rebase master

This commit is contained in:
ioito
2019-05-09 20:57:21 +08:00
parent 746a7d424e
commit ff2cca8611
82 changed files with 2247 additions and 717 deletions
Generated
-4
View File
@@ -1799,11 +1799,7 @@
"utils",
]
pruneopts = "UT"
<<<<<<< HEAD
revision = "740ce1e70d2417c195f669bbddf8ade8ec967419"
=======
revision = "91e7c6f49631cea6aa6b65d6d3e9e779f13ebc1e"
>>>>>>> 细化存储信息
[[projects]]
branch = "master"
+1 -1
View File
@@ -47,7 +47,7 @@ func init() {
type CloudregionCityListOptions struct {
Manager string `help:"List objects belonging to the cloud provider"`
Account string `help:"List objects belonging to the cloud account"`
Provider string `help:"List objects from the provider" choices:"VMware|Aliyun|Qcloud|Azure|Aws|Huawei|Openstack"`
Provider string `help:"List objects from the provider" choices:"VMware|Aliyun|Qcloud|Azure|Aws|Huawei|Openstack|Ucloud|ZStack"`
City string `help:"List regions in the specified city"`
PublicCloud *bool `help:"List objects belonging to public cloud" json:"public_cloud"`
+14 -2
View File
@@ -47,7 +47,9 @@ func init() {
MANAGER string `help:"cloud provider"`
REGION string `help:"cloud region in which EIP is allocated"`
NAME string `help:"name of the EIP"`
BW int `help:"Bandwidth in Mbps"`
Bandwidth int `help:"Bandwidth in Mbps"`
Ip string `help:"IP address of the EIP"`
Network string `help:"Network of the EIP"`
ChargeType string `help:"bandwidth charge type, either traffic or bandwidth" choices:"traffic|bandwidth"`
}
R(&EipCreateOptions{}, "eip-create", "Create an EIP", func(s *mcclient.ClientSession, args *EipCreateOptions) error {
@@ -55,12 +57,22 @@ func init() {
params.Add(jsonutils.NewString(args.MANAGER), "manager")
params.Add(jsonutils.NewString(args.REGION), "region")
params.Add(jsonutils.NewString(args.NAME), "name")
params.Add(jsonutils.NewInt(int64(args.BW)), "bandwidth")
if args.Bandwidth != 0 {
params.Add(jsonutils.NewInt(int64(args.Bandwidth)), "bandwidth")
}
if len(args.ChargeType) > 0 {
params.Add(jsonutils.NewString(args.ChargeType), "charge_type")
}
if len(args.Network) > 0 {
params.Add(jsonutils.NewString(args.Network), "network")
}
if len(args.Ip) > 0 {
params.Add(jsonutils.NewString(args.Ip), "ip")
}
result, err := modules.Elasticips.Create(s, params)
if err != nil {
return err
+7 -7
View File
@@ -234,16 +234,16 @@ func init() {
})
type NetworkCreateOptions2 struct {
Wire string `help:"ID or Name of wire in which the network is created"`
Vpc string `help:"ID or Name of vpc in which the network is created"`
Zone string `help:"ID or Name of zone in which the network is created"`
NETWORK string `help:"Name of new network"`
PREFIX string `help:"Start of IPv4 address range"`
Desc string `help:"Description" metavar:"DESCRIPTION"`
Wire string `help:"ID or Name of wire in which the network is created"`
Vpc string `help:"ID or Name of vpc in which the network is created"`
Zone string `help:"ID or Name of zone in which the network is created"`
NAME string `help:"Name of new network"`
PREFIX string `help:"Start of IPv4 address range"`
Desc string `help:"Description" metavar:"DESCRIPTION"`
}
R(&NetworkCreateOptions2{}, "network-create2", "Create a virtual network", func(s *mcclient.ClientSession, args *NetworkCreateOptions2) error {
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(args.NETWORK), "name")
params.Add(jsonutils.NewString(args.NAME), "name")
params.Add(jsonutils.NewString(args.PREFIX), "guest_ip_prefix")
if len(args.Desc) > 0 {
params.Add(jsonutils.NewString(args.Desc), "description")
+1 -1
View File
@@ -150,7 +150,7 @@ func init() {
})
type ServerSkuSpecsListOptions struct {
Provider string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Qcloud|Azure|Aws|Huawei|Openstack|Ucloud" json:"provider"`
Provider string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Qcloud|Azure|Aws|Huawei|Openstack|Ucloud|ZStack" json:"provider"`
PublicCloud *bool `help:"List objects belonging to public cloud" json:"public_cloud"`
Zone string `help:"zone Id or name"`
PostpaidStatus *string `help:"skus available status for postpaid instance" choices:"available|soldout"`
+2 -2
View File
@@ -22,8 +22,8 @@ import (
)
type GeneralUsageOptions struct {
HostType []string `help:"Host types" choices:"hypervisor|baremetal|esxi|xen|kubelet|hyperv|aliyun|azure|aws|huawei|qcloud"`
Provider []string `help:"Provider" choices:"VMware|Aliyun|Azure|Aws|Qcloud|Huawei"`
HostType []string `help:"Host types" choices:"hypervisor|baremetal|esxi|xen|kubelet|hyperv|aliyun|azure|aws|huawei|qcloud|openstack|ucloud|zstack"`
Provider []string `help:"Provider" choices:"VMware|Aliyun|Azure|Aws|Qcloud|Huawei|OpenStack|Ucloud|ZStack"`
Project string
}
+1
View File
@@ -59,6 +59,7 @@ var (
CLOUD_PROVIDER_HUAWEI,
CLOUD_PROVIDER_OPENSTACK,
CLOUD_PROVIDER_UCLOUD,
CLOUD_PROVIDER_ZSTACK,
}
)
+3 -2
View File
@@ -191,8 +191,9 @@ var HOSTTYPE_HYPERVISOR = map[string]string{
}
const (
VM_AWS_DEFAULT_LOGIN_USER = "ec2user"
VM_AZURE_DEFAULT_LOGIN_USER = "toor"
VM_AWS_DEFAULT_LOGIN_USER = "ec2user"
VM_AZURE_DEFAULT_LOGIN_USER = "toor"
VM_ZSTACK_DEFAULT_LOGIN_USER = "root"
VM_METADATA_APP_TAGS = "app_tags"
VM_METADATA_CREATE_PARAMS = "create_params"
+1
View File
@@ -87,6 +87,7 @@ var HOST_TYPES = []string{
HOST_TYPE_QCLOUD,
HOST_TYPE_HUAWEI,
HOST_TYPE_OPENSTACK,
HOST_TYPE_UCLOUD,
HOST_TYPE_ZSTACK,
}
+2 -4
View File
@@ -66,9 +66,7 @@ const (
// Zstack storage type
STORAGE_ZSTACK_LOCAL_STORAGE = "localstorage"
STORAGE_ZSTACK_ROOT = "root"
STORAGE_ZSTACK_DATA = "data"
STORAGE_ZSTACK_IMAGECACHE = "imagecache"
STORAGE_ZSTACK_CEPH = "ceph"
)
const (
@@ -100,7 +98,7 @@ var (
STORAGE_HUAWEI_SSD, STORAGE_HUAWEI_SAS, STORAGE_HUAWEI_SATA,
STORAGE_OPENSTACK_ISCSI, STORAGE_UCLOUD_CLOUD_NORMAL, STORAGE_UCLOUD_CLOUD_SSD,
STORAGE_UCLOUD_LOCAL_NORMAL, STORAGE_UCLOUD_LOCAL_SSD, STORAGE_UCLOUD_EXCLUSIVE_LOCAL_DISK,
STORAGE_ZSTACK_LOCAL_STORAGE, STORAGE_ZSTACK_ROOT, STORAGE_ZSTACK_DATA, STORAGE_ZSTACK_IMAGECACHE,
STORAGE_ZSTACK_LOCAL_STORAGE, STORAGE_ZSTACK_CEPH,
}
STORAGE_LIMITED_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS, STORAGE_RBD, STORAGE_NFS}
+10
View File
@@ -0,0 +1,10 @@
package cloudprovider
type SEip struct {
Name string
BandwidthMbps int
ChargeType string
BGPType string
NetworkExternalId string
IP string
}
+1 -1
View File
@@ -82,7 +82,7 @@ func (region *SFakeOnPremiseRegion) CreateIVpc(name string, desc string, cidr st
return nil, ErrNotSupported
}
func (region *SFakeOnPremiseRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (ICloudEIP, error) {
func (region *SFakeOnPremiseRegion) CreateEIP(eip *SEip) (ICloudEIP, error) {
return nil, ErrNotSupported
}
+2 -1
View File
@@ -67,7 +67,7 @@ type ICloudRegion interface {
SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error)
CreateIVpc(name string, desc string, cidr string) (ICloudVpc, error)
CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (ICloudEIP, error)
CreateEIP(eip *SEip) (ICloudEIP, error)
GetISnapshots() ([]ICloudSnapshot, error)
GetISnapshotById(snapshotId string) (ICloudSnapshot, error)
@@ -275,6 +275,7 @@ type ICloudEIP interface {
GetIpAddr() string
GetMode() string
GetINetworkId() string
GetAssociationType() string
GetAssociationExternalId() string
+1 -1
View File
@@ -20,7 +20,7 @@ import (
)
type CloudSyncOptions struct {
Provider string `help:"Public cloud provider" choices:"Aliyun|Azure|Aws|Qcloud"`
Provider string `help:"Public cloud provider" choices:"Aliyun|Azure|Aws|Qcloud|OpenStack|Ucloud|Huawei|ZStack"`
Environment string `help:"environment of public cloud"`
Cloudregion string `help:"region of public cloud"`
Zone string `help:"availability zone of public cloud"`
+5
View File
@@ -27,6 +27,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/billing"
)
@@ -120,6 +121,10 @@ func (self *SBaseGuestDriver) GetChangeConfigStatus() ([]string, error) {
return []string{}, fmt.Errorf("This Guest driver dose not implement GetChangeConfigStatus")
}
func (self *SBaseGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return httperrors.NewInputParameterError("Not Implement ValidateCreateEip")
}
func (self *SBaseGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error {
return fmt.Errorf("This Guest driver dose not implement ValidateResizeDisk")
}
+5
View File
@@ -27,6 +27,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/compute/options"
"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/httputils"
@@ -104,6 +105,10 @@ func (self *SESXiGuestDriver) GetDeployStatus() ([]string, error) {
return []string{api.VM_READY}, nil
}
func (self *SESXiGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return httperrors.NewInputParameterError("%s not support create eip", self.GetHypervisor())
}
func (self *SESXiGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error {
if !utils.IsInStringArray(guest.Status, []string{api.VM_READY}) {
return fmt.Errorf("Cannot resize disk when guest in status %s", guest.Status)
@@ -165,6 +165,10 @@ func (self *SManagedVirtualizedGuestDriver) ValidateCreateData(ctx context.Conte
return input, nil
}
func (self *SManagedVirtualizedGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return nil
}
func (self *SManagedVirtualizedGuestDriver) RequestDetachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId())
}
+8
View File
@@ -17,6 +17,7 @@ package guestdrivers
import (
"context"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/compute/options"
@@ -90,6 +91,10 @@ func (self *SOpenStackGuestDriver) GetDeployStatus() ([]string, error) {
return []string{api.VM_RUNNING}, nil
}
func (self *SOpenStackGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return httperrors.NewInputParameterError("%s not support create eip, it only support bind eip", self.GetHypervisor())
}
func (self *SOpenStackGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
var err error
input, err = self.SManagedVirtualizedGuestDriver.ValidateCreateData(ctx, userCred, input)
@@ -99,6 +104,9 @@ func (self *SOpenStackGuestDriver) ValidateCreateData(ctx context.Context, userC
if len(input.Networks) >= 2 {
return nil, httperrors.NewInputParameterError("cannot support more than 1 nic")
}
if len(input.Eip) > 0 || input.EipBw > 0 {
return nil, httperrors.NewUnsupportOperationError("%s not support create virtual machine with eip", self.GetHypervisor())
}
return input, nil
}
+21 -5
View File
@@ -18,6 +18,7 @@ import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -42,6 +43,10 @@ func (self *SZStackGuestDriver) GetHypervisor() string {
return api.HYPERVISOR_ZSTACK
}
func (self *SZStackGuestDriver) GetProvider() string {
return api.CLOUD_PROVIDER_ZSTACK
}
func (self *SZStackGuestDriver) GetDefaultSysDiskBackend() string {
return api.STORAGE_ZSTACK_LOCAL_STORAGE
}
@@ -53,11 +58,14 @@ func (self *SZStackGuestDriver) GetMinimalSysDiskSizeGb() int {
func (self *SZStackGuestDriver) GetStorageTypes() []string {
return []string{
api.STORAGE_ZSTACK_LOCAL_STORAGE,
api.STORAGE_ZSTACK_DATA,
api.STORAGE_ZSTACK_ROOT,
api.STORAGE_ZSTACK_CEPH,
}
}
func (self *SZStackGuestDriver) GetMaxSecurityGroupCount() int {
return 1
}
func (self *SZStackGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage {
return self.chooseHostStorage(self, host, backend, storageIds)
}
@@ -86,9 +94,6 @@ func (self *SZStackGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *m
if !utils.IsInStringArray(guest.Status, []string{api.VM_READY, api.VM_RUNNING}) {
return fmt.Errorf("Cannot resize disk when guest in status %s", guest.Status)
}
if !utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_ZSTACK_LOCAL_STORAGE, api.STORAGE_ZSTACK_ROOT, api.STORAGE_ZSTACK_DATA}) {
return fmt.Errorf("Cannot resize %s disk", storage.StorageType)
}
return nil
}
@@ -96,6 +101,10 @@ func (self *SZStackGuestDriver) RequestDetachDisk(ctx context.Context, guest *mo
return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId())
}
func (self *SZStackGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return httperrors.NewInputParameterError("%s not support create eip, it only support bind eip", self.GetHypervisor())
}
func (self *SZStackGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
input, err := self.SManagedVirtualizedGuestDriver.ValidateCreateData(ctx, userCred, input)
if err != nil {
@@ -104,6 +113,9 @@ func (self *SZStackGuestDriver) ValidateCreateData(ctx context.Context, userCred
if len(input.Networks) > 2 {
return nil, httperrors.NewInputParameterError("cannot support more than 1 nic")
}
if len(input.Eip) > 0 || input.EipBw > 0 {
return nil, httperrors.NewUnsupportOperationError("%s not support create virtual machine with eip", self.GetHypervisor())
}
return input, nil
}
@@ -115,6 +127,10 @@ func (self *SZStackGuestDriver) GetGuestInitialStateAfterRebuild() string {
return api.VM_READY
}
func (self *SZStackGuestDriver) IsNeedInjectPasswordByCloudInit() bool {
return true
}
func (self *SZStackGuestDriver) GetLinuxDefaultAccount(desc cloudprovider.SManagedVMCreateConfig) string {
userName := "root"
if desc.ImageType == "system" && desc.OsType == "Windows" {
-4
View File
@@ -16,7 +16,6 @@ package hostdrivers
import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/compute/models"
@@ -41,8 +40,5 @@ func (self *SZStackHostDriver) ValidateAttachStorage(host *models.SHost, storage
}
func (self *SZStackHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error {
if utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_ZSTACK_IMAGECACHE, api.STORAGE_ZSTACK_ROOT}) {
return httperrors.NewUnsupportOperationError("Not support create %s disk", storage.StorageType)
}
return nil
}
+3 -2
View File
@@ -793,10 +793,11 @@ func syncPublicCloudProviderInfo(
// no need to lock public cloud region as cloud region for public cloud is readonly
syncRegionEips(ctx, userCred, syncResults, provider, localRegion, remoteRegion, syncRange)
// 需要先同步vpc,避免私有云eip找不到network
syncRegionVPCs(ctx, userCred, syncResults, provider, localRegion, remoteRegion, syncRange)
syncRegionEips(ctx, userCred, syncResults, provider, localRegion, remoteRegion, syncRange)
for j := 0; j < len(localZones); j += 1 {
if len(syncRange.Zone) > 0 && !utils.IsInStringArray(localZones[j].Id, syncRange.Zone) {
+23 -6
View File
@@ -19,6 +19,7 @@ import (
"database/sql"
"fmt"
"github.com/golang-plus/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/tristate"
@@ -60,14 +61,15 @@ type SElasticip struct {
SManagedResourceBase
SBillingResourceBase
Mode string `width:"32" charset:"ascii" list:"user"`
NetworkId string `width:"36" charset:"ascii" nullable:"false" get:"user" list:"user" create:"optional"`
Mode string `width:"32" charset:"ascii" list:"user"`
IpAddr string `width:"17" charset:"ascii" list:"user"`
IpAddr string `width:"17" charset:"ascii" list:"user" create:"optional"`
AssociateType string `width:"32" charset:"ascii" list:"user"`
AssociateId string `width:"256" charset:"ascii" list:"user"`
Bandwidth int `list:"user" create:"required"`
Bandwidth int `list:"user" create:"optional" default:"0"`
ChargeType string `name:"charge_type" list:"user" create:"required"`
BgpType string `list:"user" create:"optional"` // 目前只有华为云此字段是必需填写的。
@@ -362,6 +364,15 @@ func (manager *SElasticipManager) newFromCloudEip(ctx context.Context, userCred
eip.ManagerId = provider.Id
eip.CloudregionId = region.Id
eip.ChargeType = extEip.GetInternetChargeType()
if networkId := extEip.GetINetworkId(); len(networkId) > 0 {
network, err := NetworkManager.FetchByExternalId(networkId)
if err != nil {
msg := fmt.Sprintf("failed to found network by externalId %s error: %v", networkId, err)
log.Errorf(msg)
return nil, errors.New(msg)
}
eip.NetworkId = network.GetId()
}
err = manager.TableSpec().Insert(&eip)
if err != nil {
@@ -484,7 +495,7 @@ func (manager *SElasticipManager) ValidateCreateData(ctx context.Context, userCr
if len(regionStr) == 0 {
return nil, httperrors.NewMissingParameterError("region_id")
}
region, err := CloudregionManager.FetchByIdOrName(nil, regionStr)
_region, err := CloudregionManager.FetchByIdOrName(nil, regionStr)
if err != nil {
if err != sql.ErrNoRows {
return nil, httperrors.NewGeneralError(err)
@@ -492,6 +503,7 @@ func (manager *SElasticipManager) ValidateCreateData(ctx context.Context, userCr
return nil, httperrors.NewResourceNotFoundError("Region %s not found", regionStr)
}
}
region := _region.(*SCloudregion)
data.Add(jsonutils.NewString(region.GetId()), "cloudregion_id")
managerStr := jsonutils.GetAnyString(data, []string{"manager", "manager_id"})
@@ -532,13 +544,18 @@ func (manager *SElasticipManager) ValidateCreateData(ctx context.Context, userCr
return nil, httperrors.NewOutOfQuotaError("Out of eip quota: %s", err)
}
return data, nil
return region.GetDriver().ValidateCreateEipData(ctx, userCred, data)
}
func (self *SElasticip) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.SVirtualResourceBase.PostCreate(ctx, userCred, ownerProjId, query, data)
params := jsonutils.NewDict()
if data.Contains("ip") {
ip, _ := data.GetString("ip")
params.Add(jsonutils.NewString(ip), "ip")
}
eipPendingUsage := &SQuota{Eip: 1}
self.startEipAllocateTask(ctx, userCred, nil, eipPendingUsage)
self.startEipAllocateTask(ctx, userCred, params, eipPendingUsage)
}
func (self *SElasticip) startEipAllocateTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, pendingUsage quotas.IQuota) error {
+14 -6
View File
@@ -2434,16 +2434,19 @@ func (self *SGuest) AllowPerformCreateEip(ctx context.Context, userCred mcclient
}
func (self *SGuest) PerformCreateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
bw, err := data.Int("bandwidth")
if err != nil {
return nil, httperrors.NewMissingParameterError("bandwidth")
}
var bw int64
chargeType, _ := data.GetString("charge_type")
if len(chargeType) == 0 {
chargeType = api.EIP_CHARGE_TYPE_DEFAULT
}
if chargeType == api.EIP_CHARGE_TYPE_BY_BANDWIDTH {
bw, _ = data.Int("bandwidth")
if bw == 0 {
return nil, httperrors.NewMissingParameterError("bandwidth")
}
}
if len(self.ExternalId) == 0 {
return nil, httperrors.NewInvalidStatusError("Not a managed VM")
}
@@ -2452,7 +2455,7 @@ func (self *SGuest) PerformCreateEip(ctx context.Context, userCred mcclient.Toke
return nil, httperrors.NewInvalidStatusError("No host???")
}
_, err = host.GetDriver()
_, err := host.GetDriver()
if err != nil {
return nil, httperrors.NewInvalidStatusError("No valid cloud provider")
}
@@ -2462,6 +2465,11 @@ func (self *SGuest) PerformCreateEip(ctx context.Context, userCred mcclient.Toke
return nil, httperrors.NewInvalidStatusError("No cloudregion???")
}
err = self.GetDriver().ValidateCreateEip(ctx, userCred, data)
if err != nil {
return nil, err
}
eipPendingUsage := &SQuota{Eip: 1}
err = QuotaManager.CheckSetPendingQuota(ctx, userCred, userCred.GetProjectId(), eipPendingUsage)
if err != nil {
+1
View File
@@ -151,6 +151,7 @@ type IGuestDriver interface {
RequestSyncToBackup(ctx context.Context, guest *SGuest, task taskman.ITask) error
IsSupportEip() bool
ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error
NeedStopForChangeSpec(guest *SGuest) bool
+2
View File
@@ -3056,6 +3056,8 @@ func (self *SGuest) GetDeployConfigOnHost(ctx context.Context, userCred mcclient
if strings.HasSuffix(host.Name, "-classic") {
registerVpcId, externalVpcId = "classic", "classic"
}
case api.HYPERVISOR_ZSTACK:
break
default:
return nil, fmt.Errorf("Unknown guest %s hypervisor %s for sync secgroup", self.Name, self.Hypervisor)
}
+12
View File
@@ -171,6 +171,11 @@ func (self *SNetwork) GetTotalNicCount() (int, error) {
return -1, err
}
total += cnt
cnt, err = self.GetEipsCount()
if err != nil {
return -1, err
}
total += cnt
return total, nil
}
@@ -194,6 +199,10 @@ func (self *SNetwork) GetLoadbalancerIpsCount() (int, error) {
return LoadbalancernetworkManager.Query().Equals("network_id", self.Id).CountWithError()
}
func (self *SNetwork) GetEipsCount() (int, error) {
return ElasticipManager.Query().Equals("network_id", self.Id).CountWithError()
}
func (self *SNetwork) GetUsedAddresses() map[string]bool {
used := make(map[string]bool)
@@ -203,6 +212,7 @@ func (self *SNetwork) GetUsedAddresses() map[string]bool {
HostnetworkManager.Query().SubQuery(),
ReservedipManager.Query().SubQuery(),
LoadbalancernetworkManager.Query().SubQuery(),
ElasticipManager.Query().SubQuery(),
} {
q := tbl.Query(tbl.Field("ip_addr")).Equals("network_id", self.Id)
rows, err := q.Rows()
@@ -883,6 +893,8 @@ func (self *SNetwork) getMoreDetails(ctx context.Context, extra *jsonutils.JSOND
extra.Add(jsonutils.NewInt(int64(bmVnics)), "bm_vnics")
lbVnics, _ := self.GetLoadbalancerIpsCount()
extra.Add(jsonutils.NewInt(int64(lbVnics)), "lb_vnics")
eips, _ := self.GetEipsCount()
extra.Add(jsonutils.NewInt(int64(eips)), "eip_vnics")
groupVnics, _ := self.GetGroupNicsCount()
extra.Add(jsonutils.NewInt(int64(groupVnics)), "group_vnics")
reserveVnics, _ := self.GetReservedNicsCount()
+20
View File
@@ -552,6 +552,22 @@ func (net *SNetwork) purgeLoadbalancernetworks(ctx context.Context, userCred mcc
return nil
}
func (net *SNetwork) purgeEipnetworks(ctx context.Context, userCred mcclient.TokenCredential) error {
q := ElasticipManager.Query().Equals("network_id", net.Id)
eips := make([]SElasticip, 0)
err := db.FetchModelObjects(ElasticipManager, q, &eips)
if err != nil {
return err
}
for i := range eips {
err = eips[i].RealDelete(ctx, userCred)
if err != nil {
return err
}
}
return nil
}
func (net *SNetwork) purgeReservedIps(ctx context.Context, userCred mcclient.TokenCredential) error {
q := ReservedipManager.Query().Equals("network_id", net.Id)
rips := make([]SReservedip, 0)
@@ -588,6 +604,10 @@ func (net *SNetwork) purge(ctx context.Context, userCred mcclient.TokenCredentia
if err != nil {
return err
}
err = net.purgeEipnetworks(ctx, userCred)
if err != nil {
return err
}
err = net.purgeReservedIps(ctx, userCred)
if err != nil {
return err
+2
View File
@@ -73,6 +73,8 @@ type IRegionDriver interface {
RequestDeleteLoadbalancerListenerRule(ctx context.Context, userCred mcclient.TokenCredential, lbr *SLoadbalancerListenerRule, task taskman.ITask) error
ValidateCreateVpcData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error)
ValidateCreateEipData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error)
}
var regionDrivers map[string]IRegionDriver
+1 -1
View File
@@ -541,7 +541,7 @@ func providerFilter(q *sqlchemy.SQuery, provider string, public_cloud bool) *sql
q = q.Equals("provider", provider)
} else if public_cloud {
q = q.IsNotEmpty("provider")
q = q.NotIn("provider", []string{api.CLOUD_PROVIDER_OPENSTACK})
q = q.NotIn("provider", []string{api.CLOUD_PROVIDER_OPENSTACK, api.CLOUD_PROVIDER_ZSTACK})
} else {
q = q.Filter(sqlchemy.OR(
sqlchemy.IsNull(q.Field("provider")),
+6
View File
@@ -18,6 +18,8 @@ import (
"context"
"fmt"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
@@ -304,3 +306,7 @@ func (self *SKVMRegionDriver) RequestDeleteLoadbalancerListenerRule(ctx context.
func (self *SKVMRegionDriver) ValidateCreateVpcData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return data, nil
}
func (self *SKVMRegionDriver) ValidateCreateEipData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return nil, httperrors.NewNotImplementedError("Not Implement EIP")
}
@@ -828,3 +828,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestDeleteLoadbalancerListene
func (self *SManagedVirtualizationRegionDriver) ValidateCreateVpcData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return data, nil
}
func (self *SManagedVirtualizationRegionDriver) ValidateCreateEipData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return data, nil
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package regiondrivers
import (
"context"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SZStackRegionDriver struct {
SManagedVirtualizationRegionDriver
}
func init() {
driver := SZStackRegionDriver{}
models.RegisterRegionDriver(&driver)
}
func (self *SZStackRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_ZSTACK
}
func (self *SZStackRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return nil, httperrors.NewNotImplementedError("%s does not currently support creating loadbalancer", self.GetProvider())
}
func (self *SZStackRegionDriver) ValidateCreateLoadbalancerAclData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return nil, httperrors.NewNotImplementedError("%s does not currently support creating loadbalancer acl", self.GetProvider())
}
func (self *SZStackRegionDriver) ValidateCreateLoadbalancerCertificateData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return nil, httperrors.NewNotImplementedError("%s does not currently support creating loadbalancer certificate", self.GetProvider())
}
func (self *SZStackRegionDriver) ValidateCreateEipData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
networkV := validators.NewModelIdOrNameValidator("network", "network", "")
err := networkV.Validate(data)
if err != nil {
return nil, err
}
network := networkV.Model.(*models.SNetwork)
vpc := network.GetVpc()
if vpc == nil {
return nil, httperrors.NewInputParameterError("failed to found vpc for network %s(%s)", network.Name, network.Id)
}
region, err := vpc.GetRegion()
if err != nil {
return nil, err
}
if region.GetDriver().GetProvider() != self.GetProvider() {
return nil, httperrors.NewUnsupportOperationError("network %s(%s) does not belong to %s", network.Name, network.Id, self.GetProvider())
}
return data, nil
}
+48 -1
View File
@@ -18,11 +18,14 @@ import (
"context"
"fmt"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
@@ -79,7 +82,51 @@ func (self *EipAllocateTask) OnInit(ctx context.Context, obj db.IStandaloneModel
return
}
extEip, err := iregion.CreateEIP(eip.Name, eip.Bandwidth, eip.ChargeType, eip.BgpType)
args := &cloudprovider.SEip{
Name: eip.Name,
BandwidthMbps: eip.Bandwidth,
ChargeType: eip.ChargeType,
BGPType: eip.BgpType,
IP: eip.IpAddr,
}
if len(eip.NetworkId) > 0 {
_network, err := models.NetworkManager.FetchById(eip.NetworkId)
if err != nil {
msg := fmt.Sprintf("failed to found network %s error: %v", eip.NetworkId, err)
self.onFailed(ctx, eip, msg)
return
}
network := _network.(*models.SNetwork)
ip, _ := self.GetParams().GetString("ip")
if len(ip) > 0 {
lockman.LockObject(ctx, network)
defer lockman.ReleaseObject(ctx, network)
addrTable := network.GetUsedAddresses()
ipAddr, err := network.GetFreeIP(ctx, self.UserCred, addrTable, nil, ip, models.IPAllocationNone, false)
if err != nil {
self.onFailed(ctx, eip, err.Error())
return
}
if ipAddr != ip {
msg := fmt.Sprintf("candidate ip %s is occupoed!", ip)
self.onFailed(ctx, eip, msg)
return
}
_, err = db.Update(eip, func() error {
eip.IpAddr = ipAddr
return nil
})
if err != nil {
self.onFailed(ctx, eip, err.Error())
return
}
}
args.NetworkExternalId = network.ExternalId
}
extEip, err := iregion.CreateEIP(args)
if err != nil {
msg := fmt.Sprintf("create eip fail %s", err)
eip.SetStatus(self.UserCred, api.EIP_STATUS_ALLOCATE_FAIL, msg)
+1 -1
View File
@@ -207,7 +207,7 @@ type BaseListOptions struct {
Manager string `help:"List objects belonging to the cloud provider" json:"manager,omitempty"`
Account string `help:"List objects belonging to the cloud account" json:"account,omitempty"`
Provider string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Qcloud|Azure|Aws|Huawei|Openstack|Ucloud" json:"provider,omitempty"`
Provider string `help:"List objects from the provider" choices:"OneCloud|VMware|Aliyun|Qcloud|Azure|Aws|Huawei|Openstack|Ucloud|ZStack" json:"provider,omitempty"`
Brand string `help:"List objects belonging to a special brand"`
CloudEnv string `help:"Cloud environment" choices:"public|private|onpremise|private_or_onpremise" json:"cloud_env,omitempty"`
PublicCloud *bool `help:"List objects belonging to public cloud" json:"public_cloud"`
+2 -2
View File
@@ -39,7 +39,7 @@ type ServerListOptions struct {
Gpu *bool `help:"Show gpu servers"`
Secgroup string `help:"Secgroup ID or Name"`
AdminSecgroup string `help:"AdminSecgroup ID or Name"`
Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun|azure|aws|huawei|ucloud"`
Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun|azure|aws|huawei|ucloud|zstack"`
Region string `help:"Show servers in cloudregion"`
WithEip *bool `help:"Show Servers with EIP"`
WithoutEip *bool `help:"Show Servers without EIP"`
@@ -126,7 +126,7 @@ type ServerConfigs struct {
Host string `help:"Preferred host where virtual server should be created" json:"prefer_host"`
BackupHost string `help:"Perfered host where virtual backup server should be created"`
Hypervisor string `help:"Hypervisor type" choices:"kvm|esxi|baremetal|container|aliyun|azure|qcloud|aws|huawei|openstack|ucloud"`
Hypervisor string `help:"Hypervisor type" choices:"kvm|esxi|baremetal|container|aliyun|azure|qcloud|aws|huawei|openstack|ucloud|zstack"`
ResourceType string `help:"Resource type" choices:"shared|prepaid|dedicated"`
Backup bool `help:"Create server with backup server"`
+7 -4
View File
@@ -182,6 +182,10 @@ func (self *SEipAddress) GetBandwidth() int {
return self.Bandwidth
}
func (self *SEipAddress) GetINetworkId() string {
return ""
}
func (self *SEipAddress) GetInternetChargeType() string {
switch self.InternetChargeType {
case InternetChargeByTraffic:
@@ -282,16 +286,15 @@ func (region *SRegion) AllocateEIP(bwMbps int, chargeType TInternetChargeType) (
return region.GetEip(eipId)
}
func (region *SRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (cloudprovider.ICloudEIP, error) {
func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
var ctype TInternetChargeType
switch chargeType {
switch eip.ChargeType {
case api.EIP_CHARGE_TYPE_BY_TRAFFIC:
ctype = InternetChargeByTraffic
case api.EIP_CHARGE_TYPE_BY_BANDWIDTH:
ctype = InternetChargeByBandwidth
}
eip, err := region.AllocateEIP(bwMbps, ctype)
return eip, err
return region.AllocateEIP(eip.BandwidthMbps, ctype)
}
func (region *SRegion) DeallocateEIP(eipId string) error {
+7 -3
View File
@@ -124,6 +124,10 @@ func (self *SEipAddress) GetBandwidth() int {
return self.Bandwidth
}
func (self *SEipAddress) GetINetworkId() string {
return ""
}
func (self *SEipAddress) GetInternetChargeType() string {
// todo : implement me
return api.EIP_CHARGE_TYPE_BY_TRAFFIC
@@ -250,14 +254,14 @@ func (self *SRegion) AllocateEIP(domainType string) (*SEipAddress, error) {
return self.GetEip(*eip.AllocationId)
}
func (self *SRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (cloudprovider.ICloudEIP, error) {
func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
// todo: aws 不支持指定bwMbps, chargeType
log.Debugf("CreateEip: aws not support specific params name/bwMbps/chargeType.")
ieip, err := self.AllocateEIP("vpc")
if err == nil && len(name) > 0 {
if err == nil && len(eip.Name) > 0 {
eipId := ieip.GetId()
k := "Name"
nameTag := &ec2.Tag{Key: &k, Value: &name}
nameTag := &ec2.Tag{Key: &k, Value: &eip.Name}
params := &ec2.CreateTagsInput{}
params.SetResources([]*string{&eipId})
params.SetTags([]*ec2.Tag{nameTag})
+4
View File
@@ -77,6 +77,10 @@ func (self *SClassicEipAddress) GetBandwidth() int {
return 0
}
func (self *SClassicEipAddress) GetINetworkId() string {
return ""
}
func (self *SClassicEipAddress) GetGlobalId() string {
return strings.ToLower(self.ID)
}
+6 -2
View File
@@ -77,8 +77,8 @@ func (region *SRegion) AllocateEIP(eipName string) (*SEipAddress, error) {
return &eip, cloudprovider.WaitStatus(&eip, api.EIP_STATUS_READY, 10*time.Second, 300*time.Second)
}
func (region *SRegion) CreateEIP(eipName string, bwMbps int, chargeType string, bgpType string) (cloudprovider.ICloudEIP, error) {
return region.AllocateEIP(eipName)
func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
return region.AllocateEIP(eip.Name)
}
func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) {
@@ -199,6 +199,10 @@ func (self *SEipAddress) GetBandwidth() int {
return 0
}
func (self *SEipAddress) GetINetworkId() string {
return ""
}
func (self *SEipAddress) GetGlobalId() string {
return strings.ToLower(self.ID)
}
+1 -1
View File
@@ -297,7 +297,7 @@ func ParseJSONResponse(resp *http.Response, err error, debug bool) (http.Header,
if ce.Code == 0 {
ce.Code = resp.StatusCode
}
if edetail := jsonutils.GetAnyString(jrbody2, []string{"message", "detail", "error_msg"}); len(edetail) > 0 {
if edetail := jsonutils.GetAnyString(jrbody2, []string{"message", "detail", "details", "error_msg"}); len(edetail) > 0 {
ce.Details = edetail
}
if eclass := jsonutils.GetAnyString(jrbody2, []string{"title", "type", "error_code"}); len(eclass) > 0 {
+4
View File
@@ -178,6 +178,10 @@ func (self *SEipAddress) GetBandwidth() int {
return int(self.BandwidthSize) // Mb
}
func (self *SEipAddress) GetINetworkId() string {
return ""
}
func (self *SEipAddress) GetInternetChargeType() string {
// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090603.html
bandwidth, err := self.region.GetEipBandwidth(self.BandwidthID)
+11 -11
View File
@@ -379,9 +379,9 @@ func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudpro
// 华东-上海二:5_sbgp
// 华北-北京一:5_bgp、5_sbgp
// 亚太-香港:5_bgp
func (self *SRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (cloudprovider.ICloudEIP, error) {
func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
var ctype TInternetChargeType
switch chargeType {
switch eip.ChargeType {
case api.EIP_CHARGE_TYPE_BY_TRAFFIC:
ctype = InternetChargeByTraffic
case api.EIP_CHARGE_TYPE_BY_BANDWIDTH:
@@ -389,27 +389,27 @@ func (self *SRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpTy
}
// todo: 如何避免hardcode。集成到cloudmeta服务中?
if len(bgpType) == 0 {
if len(eip.BGPType) == 0 {
switch self.GetId() {
case "cn-north-1", "cn-east-2", "cn-south-1":
bgpType = "5_sbgp"
eip.BGPType = "5_sbgp"
case "cn-northeast-1":
bgpType = "5_telcom"
eip.BGPType = "5_telcom"
case "cn-north-4", "ap-southeast-1", "ap-southeast-2", "eu-west-0":
bgpType = "5_bgp"
eip.BGPType = "5_bgp"
default:
bgpType = "5_bgp"
eip.BGPType = "5_bgp"
}
}
eip, err := self.AllocateEIP(name, bwMbps, ctype, bgpType)
eip.region = self
ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType)
ieip.region = self
if err != nil {
return nil, err
}
err = cloudprovider.WaitStatus(eip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second)
return eip, err
err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second)
return ieip, err
}
func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
+1 -1
View File
@@ -402,7 +402,7 @@ func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
return nil, cloudprovider.ErrNotSupported
}
func (region *SRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (cloudprovider.ICloudEIP, error) {
func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
return nil, cloudprovider.ErrNotSupported
}
+7 -3
View File
@@ -161,6 +161,10 @@ func (self *SEipAddress) GetBandwidth() int {
return 0
}
func (self *SEipAddress) GetINetworkId() string {
return ""
}
func (self *SEipAddress) GetBillingType() string {
return billing_api.BILLING_TYPE_POSTPAID
}
@@ -292,15 +296,15 @@ func (region *SRegion) AllocateEIP(name string, bwMbps int, chargeType TInternet
return nil, cloudprovider.ErrNotFound
}
func (region *SRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (cloudprovider.ICloudEIP, error) {
func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
var ctype TInternetChargeType
switch chargeType {
switch eip.ChargeType {
case api.EIP_CHARGE_TYPE_BY_TRAFFIC:
ctype = InternetChargeByTraffic
case api.EIP_CHARGE_TYPE_BY_BANDWIDTH:
ctype = InternetChargeByBandwidth
}
return region.AllocateEIP(name, bwMbps, ctype)
return region.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype)
}
func (region *SRegion) DeallocateEIP(eipId string) error {
+12 -8
View File
@@ -177,6 +177,10 @@ func (self *SEip) GetBandwidth() int {
return self.BandwidthMb
}
func (self *SEip) GetINetworkId() string {
return ""
}
// 弹性IP的计费模式, 枚举值为: "Bandwidth", 带宽计费; "Traffic", 流量计费; "ShareBandwidth",共享带宽模式. 默认为 "Bandwidth".
func (self *SEip) GetInternetChargeType() string {
switch self.PayMode {
@@ -207,21 +211,21 @@ func (self *SEip) ChangeBandwidth(bw int) error {
// https://docs.ucloud.cn/api/unet-api/allocate_eip
// 增加共享带宽模式ShareBandwidth
func (self *SRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (cloudprovider.ICloudEIP, error) {
if len(bgpType) == 0 {
func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
if len(eip.BGPType) == 0 {
if strings.HasPrefix(self.GetId(), "cn-") {
bgpType = "Bgp"
eip.BGPType = "Bgp"
} else {
bgpType = "International"
eip.BGPType = "International"
}
}
params := NewUcloudParams()
params.Set("OperatorName", bgpType)
params.Set("Bandwidth", bwMbps)
params.Set("Name", name)
params.Set("OperatorName", eip.BGPType)
params.Set("Bandwidth", eip.BandwidthMbps)
params.Set("Name", eip.Name)
var payMode string
switch chargeType {
switch eip.ChargeType {
case api.EIP_CHARGE_TYPE_BY_TRAFFIC:
payMode = "Traffic"
case api.EIP_CHARGE_TYPE_BY_BANDWIDTH:
+7 -1
View File
@@ -15,6 +15,7 @@
package shell
import (
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/shellutils"
"yunion.io/x/onecloud/pkg/util/ucloud"
)
@@ -37,7 +38,12 @@ func init() {
BGP string `help:"bgp type" choices:"Bgp|International"`
}
shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *ucloud.SRegion, args *EipAllocateOptions) error {
eip, err := cli.CreateEIP(args.NAME, args.BW, ucloud.EIP_CHARGE_TYPE_BY_TRAFFIC, args.BGP)
option := cloudprovider.SEip{
Name: args.NAME,
BandwidthMbps: args.BW,
BGPType: args.BGP,
}
eip, err := cli.CreateEIP(&option)
if err != nil {
return err
}
+14
View File
@@ -0,0 +1,14 @@
package zstack
type SConfiguration struct {
Name string
Category string
Description string
DefaultValue string
Value string
}
func (region *SRegion) GetConfigrations() ([]SConfiguration, error) {
configrations := []SConfiguration{}
return configrations, region.client.listAll("global-configurations", []string{}, &configrations)
}
+41 -40
View File
@@ -15,7 +15,7 @@ import (
type SDisk struct {
localStorage *SLocalStorage
cephStorage *SCephStorage
storage *SStorage
region *SRegion
ZStackBasic
@@ -24,7 +24,7 @@ type SDisk struct {
DiskOfferingUUID string `json:"diskOfferingUuid"`
RootImageUUID string `json:"rootImageUuid"`
InstallPath string `json:"installPath"`
Type string `json:"Type"`
Type string `json:"type"`
Format string `json:"format"`
Size int `json:"size"`
ActualSize int `json:"actualSize"`
@@ -36,36 +36,38 @@ type SDisk struct {
}
func (region *SRegion) GetDisk(diskId string) (*SDisk, error) {
disks, err := region.GetDisks("", []string{diskId}, "")
if err != nil {
return nil, err
}
if len(disks) == 1 {
if disks[0].UUID == diskId {
return &disks[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(disks) == 0 || len(diskId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
disk := &SDisk{region: region}
return disk, region.client.getResource("volumes", diskId, disk)
}
func (region *SRegion) GetDiskWithStorage(diskId string) (*SDisk, error) {
disk, err := region.GetDisk(diskId)
if err != nil {
log.Errorf("Get Disk %s error: %v", diskId, err)
return nil, err
}
disk.region = region
storage, err := region.GetPrimaryStorage(disk.PrimaryStorageUUID)
storage, err := region.GetStorage(disk.PrimaryStorageUUID)
if err != nil {
log.Errorf("Get primary storage %s error: %v", disk.PrimaryStorageUUID, err)
return nil, err
}
switch storage.Type {
case StorageTypeLocal:
if len(disk.VMInstanceUUID) > 0 {
instance, err := region.GetInstance(disk.VMInstanceUUID)
if err != nil {
return nil, err
}
hostId := instance.LastHostUUID
if len(hostId) == 0 {
hostId = instance.HostUUID
}
disk.localStorage = &SLocalStorage{region: region, primaryStorageID: storage.UUID, HostUUID: hostId}
return disk, nil
}
tags, err := region.GetSysTags("", "VolumeVO", disk.UUID, "")
if err != nil {
log.Errorf("get disk tag error: %v", err)
return nil, err
}
for i := 0; i < len(tags); i++ {
@@ -84,23 +86,8 @@ func (region *SRegion) GetDiskWithStorage(diskId string) (*SDisk, error) {
}
return nil, cloudprovider.ErrNotFound
case StorageTypeCeph:
storage, err := region.GetPrimaryStorage(disk.PrimaryStorageUUID)
if err != nil {
return nil, err
}
for i := 0; i < len(storage.Pools); i++ {
if strings.Contains(disk.InstallPath, storage.Pools[i].PoolName) {
zone, err := region.GetZone(storage.ZoneUUID)
if err != nil {
return nil, err
}
cephStorage := storage.Pools[i]
cephStorage.zone = zone
disk.cephStorage = &cephStorage
return disk, nil
}
}
return nil, fmt.Errorf("failed to found ceph storage for disk %s", disk.Name)
disk.storage = storage
return disk, nil
default:
return nil, fmt.Errorf("Unsupport StorageType %s", storage.Type)
}
@@ -156,8 +143,8 @@ func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) {
if disk.localStorage != nil {
return disk.localStorage, nil
}
if disk.cephStorage != nil {
return disk.cephStorage, nil
if disk.storage != nil {
return disk.storage, nil
}
return nil, cloudprovider.ErrNotFound
}
@@ -167,7 +154,10 @@ func (disk *SDisk) GetStatus() string {
case "Ready":
return api.DISK_READY
case "NotInstantiated":
return api.DISK_READY
//数据云盘特有的状态。在这个连接状态中,数据云盘只存在于数据库的表记录中。NotInstantiated状态的数据云盘可以挂载到任何类型虚拟机管理程序管理的云主机上;当挂载到云主机上后,数据云盘的hypervisorType域会存储云主机对应的虚拟机管理程序类型,在主存储上被实例化为虚拟机管理程序类型的实际二进制文件,同时连接状态会改为就绪(Ready);在这之后,这些数据云盘就只能被重新挂载到相同类型虚拟机管理程序管理的云主机上了。
return api.DISK_INIT
case "Creating":
return api.DISK_ALLOCATING
default:
log.Errorf("Unknown disk %s(%s) status %s", disk.Name, disk.UUID, disk.Status)
return api.DISK_UNKNOWN
@@ -258,12 +248,23 @@ func (region *SRegion) CreateDisk(name string, storageId string, hostId string,
params["systemTags"] = []string{"ceph::pool::" + poolName}
}
resp, err := region.client.post("volumes/data", jsonutils.Marshal(params))
disk := &SDisk{}
if err != nil {
return nil, err
}
disk := &SDisk{region: region}
return disk, resp.Unmarshal(disk, "inventory")
}
func (region *SRegion) DeleteDisk(diskId string) error {
return region.client.delete("volumes", diskId, "Enforcing")
err := region.client.delete("volumes", diskId, "Enforcing")
if err != nil {
return err
}
params := map[string]interface{}{
"expungeDataVolume": jsonutils.NewDict(),
}
_, err = region.client.put("volumes", diskId, jsonutils.Marshal(params))
return err
}
func (region *SRegion) ResizeDisk(diskId string, sizeMb int64) error {
+52 -22
View File
@@ -1,6 +1,7 @@
package zstack
import (
"fmt"
"time"
"yunion.io/x/jsonutils"
@@ -22,20 +23,8 @@ type SEipAddress struct {
}
func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) {
eips, err := region.GetEips(eipId, "")
if err != nil {
return nil, err
}
if len(eips) == 1 {
if eips[0].UUID == eipId {
return &eips[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(eips) == 0 || len(eipId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
eip := &SEipAddress{region: region}
return eip, region.client.getResource("eips", eipId, eip)
}
func (region *SRegion) GetEips(eipId, instanceId string) ([]SEipAddress, error) {
@@ -104,17 +93,13 @@ func (eip *SEipAddress) GetAssociationType() string {
func (eip *SEipAddress) GetAssociationExternalId() string {
if len(eip.VMNicUUID) > 0 {
instances, err := eip.region.GetInstances("", "", eip.VMNicUUID)
if err != nil && len(instances) == 1 {
if err == nil && len(instances) == 1 {
return instances[0].UUID
}
}
return ""
}
func (eip *SEipAddress) GetManagerId() string {
return eip.region.client.providerID
}
func (eip *SEipAddress) GetBillingType() string {
return ""
}
@@ -128,23 +113,31 @@ func (eip *SEipAddress) GetExpiredAt() time.Time {
}
func (eip *SEipAddress) Delete() error {
return cloudprovider.ErrNotImplemented
return eip.region.DeleteVirtualIP(eip.VipUUID)
}
func (eip *SEipAddress) GetBandwidth() int {
return 0
}
func (eip *SEipAddress) GetINetworkId() string {
vip, err := eip.region.GetVirtualIP(eip.VipUUID)
if err == nil {
return eip.region.GetNetworkId(vip)
}
return ""
}
func (eip *SEipAddress) GetInternetChargeType() string {
return api.EIP_CHARGE_TYPE_BY_TRAFFIC
}
func (eip *SEipAddress) Associate(instanceId string) error {
return cloudprovider.ErrNotImplemented
return eip.region.AssociateEip(instanceId, eip.UUID)
}
func (eip *SEipAddress) Dissociate() error {
return cloudprovider.ErrNotImplemented
return eip.region.DisassociateEip(eip.UUID)
}
func (eip *SEipAddress) ChangeBandwidth(bw int) error {
@@ -154,3 +147,40 @@ func (eip *SEipAddress) ChangeBandwidth(bw int) error {
func (eip *SEipAddress) GetProjectId() string {
return ""
}
func (region *SRegion) CreateEip(name string, vipId string, desc string) (*SEipAddress, error) {
params := map[string]map[string]string{
"params": {
"name": name,
"description": desc,
"vipUuid": vipId,
},
}
eip := &SEipAddress{region: region}
resp, err := region.client.post("eips", jsonutils.Marshal(params))
if err != nil {
return nil, err
}
return eip, resp.Unmarshal(eip, "inventory")
}
func (region *SRegion) AssociateEip(instanceId, eipId string) error {
instance, err := region.GetInstance(instanceId)
if err != nil {
return err
}
if len(instance.VMNics) == 0 {
return fmt.Errorf("instance %s does not have any nic", instance.Name)
}
resource := fmt.Sprintf("eips/%s/vm-instances/nics/%s", eipId, instance.VMNics[0].UUID)
params := map[string]interface{}{
"params": jsonutils.NewDict(),
}
_, err = region.client.post(resource, jsonutils.Marshal(params))
return err
}
func (region *SRegion) DisassociateEip(eipId string) error {
resource := fmt.Sprintf("eips/%s/vm-instances/nics", eipId)
return region.client.delete(resource, "", "")
}
+199 -26
View File
@@ -1,7 +1,12 @@
package zstack
import (
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -28,6 +33,35 @@ type SHost struct {
ZStackTime
}
func (region *SRegion) GetHosts(zoneId string, hostId string) ([]SHost, error) {
hosts := []SHost{}
params := []string{}
if len(zoneId) > 0 {
params = append(params, "q=zone.uuid="+zoneId)
}
if len(hostId) > 0 {
params = append(params, "q=uuid="+hostId)
}
if SkipEsxi {
params = append(params, "q=hypervisorType!=ESX")
}
return hosts, region.client.listAll("hosts", params, &hosts)
}
func (region *SRegion) GetHost(hostId string) (*SHost, error) {
host := &SHost{}
err := region.client.getResource("hosts", hostId, host)
if err != nil {
return nil, err
}
zone, err := region.GetZone(host.ZoneUUID)
if err != nil {
return nil, err
}
host.zone = zone
return host, nil
}
func (host *SHost) GetMetadata() *jsonutils.JSONDict {
return nil
}
@@ -45,25 +79,21 @@ func (host *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) {
}
func (host *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
primaryStorages, err := host.zone.region.GetPrimaryStorages(host.zone.UUID, host.ClusterUUID, "")
storages, err := host.zone.region.GetStorages(host.zone.UUID, host.ClusterUUID, "")
if err != nil {
return nil, err
}
istorages := []cloudprovider.ICloudStorage{}
for i := 0; i < len(primaryStorages); i++ {
switch primaryStorages[i].Type {
for i := 0; i < len(storages); i++ {
switch storages[i].Type {
case StorageTypeLocal:
storages, err := host.zone.region.getILocalStorages(host.zone, primaryStorages[i].UUID, host.UUID)
localStorages, err := host.zone.region.getILocalStorages(storages[i].UUID, host.UUID)
if err != nil {
return nil, err
}
istorages = append(istorages, storages...)
istorages = append(istorages, localStorages...)
case StorageTypeCeph:
storages, err := host.zone.region.getICephStorages(host.zone, primaryStorages[i].UUID)
if err != nil {
return nil, err
}
istorages = append(istorages, storages...)
istorages = append(istorages, &storages[i])
case StorageTypeVCenter:
}
}
@@ -88,21 +118,12 @@ func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
}
func (host *SHost) GetIVMById(instanceId string) (cloudprovider.ICloudVM, error) {
instances, err := host.zone.region.GetInstances(host.UUID, instanceId, "")
instance, err := host.zone.region.GetInstance(instanceId)
if err != nil {
return nil, err
}
if len(instances) == 1 {
if instances[0].UUID == instanceId {
instances[0].host = host
return &instances[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(instances) == 0 || len(instanceId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
instance.host = host
return instance, nil
}
func (host *SHost) GetId() string {
@@ -179,7 +200,7 @@ func (host *SHost) GetMemSizeMB() int {
}
func (host *SHost) GetStorageSizeMB() int {
storages, err := host.zone.region.GetPrimaryStorages(host.zone.UUID, host.ClusterUUID, "")
storages, err := host.zone.region.GetStorages(host.zone.UUID, host.ClusterUUID, "")
if err != nil {
return 0
}
@@ -206,12 +227,164 @@ func (host *SHost) GetHostType() string {
return api.HOST_TYPE_ZSTACK
}
func (host *SHost) GetManagerId() string {
return host.zone.region.client.providerID
func (region *SRegion) cleanDisks(diskIds []string) {
for i := 0; i < len(diskIds); i++ {
err := region.DeleteDisk(diskIds[i])
if err != nil {
log.Errorf("clean disk %s error: %v", diskIds[i], err)
}
}
}
func (region *SRegion) createDataDisks(name, hostId string, storages []cloudprovider.ICloudStorage, disks []cloudprovider.SDiskInfo) ([]string, error) {
diskIds := []string{}
for i := 0; i < len(disks); i++ {
for j := 0; j < len(storages); j++ {
poolName := ""
if storages[i].GetStorageType() == disks[i].StorageType {
switch disks[i].StorageType {
case "localstorage":
poolName = ""
case "ceph":
hostId = ""
storage := storages[j].(*SStorage)
poolName, _ := storage.GetDataPoolName()
if len(poolName) == 0 {
return []string{}, fmt.Errorf("failed to found data pool for ceph storage %s", storage.Name)
}
default:
return diskIds, fmt.Errorf("not support storageType %s", disks[i].StorageType)
}
name := fmt.Sprintf("vdisk_%s_%d", name, time.Now().UnixNano())
disk, err := region.CreateDisk(name, storages[j].GetId(), hostId, poolName, disks[i].SizeGB, "")
if err != nil {
return diskIds, err
}
diskIds = append(diskIds, disk.UUID)
}
}
}
return diskIds, nil
}
func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
return nil, cloudprovider.ErrNotImplemented
storages, err := host.GetIStorages()
if err != nil {
return nil, err
}
diskIds, err := host.zone.region.createDataDisks(desc.Name, host.UUID, storages, desc.DataDisks)
if err != nil {
defer host.zone.region.cleanDisks(diskIds)
return nil, err
}
rootStorageId := ""
for i := 0; i < len(storages); i++ {
if storages[i].GetStorageType() == desc.SysDisk.StorageType {
rootStorageId = storages[i].GetId()
}
}
if len(rootStorageId) == 0 {
return nil, fmt.Errorf("failed to found appropriate storage for root disk")
}
instance, err := host.zone.region._createVM(desc, host.UUID, rootStorageId)
if err != nil {
defer host.zone.region.cleanDisks(diskIds)
return nil, err
}
for i := 0; i < len(diskIds); i++ {
err = host.zone.region.AttachDisk(instance.UUID, diskIds[i])
if err != nil {
log.Errorf("failed to attach disk %s into instance %s error: %v", diskIds[i], instance.Name, err)
}
}
err = host.zone.region.AssignSecurityGroup(instance.UUID, desc.ExternalSecgroupId)
if err != nil {
return nil, err
}
return host.GetIVMById(instance.UUID)
}
func (region *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, hostId string, rootStorageId string) (*SInstance, error) {
l3Id := strings.Split(desc.ExternalNetworkId, "/")[0]
if len(l3Id) == 0 {
return nil, fmt.Errorf("invalid networkid: %s", desc.ExternalNetworkId)
}
_, err := region.GetL3Network(l3Id)
if err != nil {
log.Errorf("failed to found l3network %s error: %v", l3Id, err)
return nil, err
}
offerings := map[string]string{}
if len(desc.InstanceType) > 0 {
offering, err := region.GetInstanceOfferingByType(desc.InstanceType)
if err != nil {
return nil, err
}
offerings[offering.Name] = offering.UUID
} else {
_offerings, err := region.GetInstanceOfferings("", "", desc.Cpu, desc.MemoryMB)
if err != nil {
return nil, err
}
for _, offering := range _offerings {
offerings[offering.Name] = offering.UUID
}
if len(offerings) == 0 {
return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB)
}
}
return region.CreateInstance(desc, l3Id, hostId, rootStorageId, offerings)
}
func (region *SRegion) CreateInstance(desc *cloudprovider.SManagedVMCreateConfig, l3Id, hostId, rootStorageId string, offerings map[string]string) (*SInstance, error) {
instance := &SInstance{}
systemTags := []string{
"cdroms::Empty::None::None",
"usbRedirect::false",
fmt.Sprintf("staticIp::%s::%s", l3Id, desc.IpAddr),
"vmConsoleMode::vnc",
"cleanTraffic::false",
}
if len(desc.UserData) > 0 {
systemTags = append(systemTags, "userdata::"+desc.UserData)
}
if len(desc.PublicKey) > 0 {
systemTags = append(systemTags, "sshkey::"+desc.PublicKey)
}
var err error
for offerName, offerId := range offerings {
params := map[string]interface{}{
"params": map[string]interface{}{
"name": desc.Name,
"description": desc.Description,
"instanceOfferingUuid": offerId,
"imageUuid": desc.ExternalImageId,
"l3NetworkUuids": []string{
l3Id,
},
"hostUuid": hostId,
"dataVolumeSystemTags": []string{},
"rootVolumeSystemTags": []string{},
"vmMachineType": "",
"tagUuids": []string{},
"defaultL3NetworkUuid": l3Id,
"primaryStorageUuidForRootVolume": rootStorageId,
"dataDiskOfferingUuids": []string{},
"systemTags": systemTags,
"vmNicConfig": []string{},
},
}
log.Debugf("Try instanceOffering : %s", offerName)
err = region.client.create("vm-instances", jsonutils.Marshal(params), instance)
if err == nil {
return instance, nil
}
log.Errorf("create %s instance failed error: %v", offerName, err)
}
if err != nil {
return nil, err
}
return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB)
}
func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
+94 -14
View File
@@ -1,12 +1,19 @@
package zstack
import (
"bytes"
"context"
"fmt"
"io"
"mime/multipart"
"net/http"
"sort"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/httputils"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
@@ -79,6 +86,8 @@ func (image *SImage) GetStatus() string {
switch image.Status {
case "Ready":
return api.CACHED_IMAGE_STATUS_READY
case "Downloading":
return api.CACHED_IMAGE_STATUS_CACHING
default:
log.Errorf("Unknown image status: %s", image.Status)
return api.CACHED_IMAGE_STATUS_CACHE_FAILED
@@ -142,20 +151,8 @@ func (image *SImage) GetCreateTime() time.Time {
}
func (region *SRegion) GetImage(imageId string) (*SImage, error) {
images, err := region.GetImages(imageId)
if err != nil {
return nil, err
}
if len(images) == 1 {
if images[0].UUID == imageId {
return &images[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(images) == 0 || len(imageId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
image := &SImage{storageCache: region.getStorageCache()}
return image, region.client.getResource("images", imageId, image)
}
func (region *SRegion) GetImages(imageId string) ([]SImage, error) {
@@ -169,3 +166,86 @@ func (region *SRegion) GetImages(imageId string) ([]SImage, error) {
}
return images, region.client.listAll("images", params, &images)
}
func (region *SRegion) GetBackupStorageUUID() ([]string, error) {
imageServers, err := region.GetImageServers("")
if err != nil {
return nil, err
}
if len(imageServers) == 0 {
return nil, fmt.Errorf("failed to found any image servers")
}
servers := ImageServers(imageServers)
sort.Sort(servers)
return []string{servers[0].UUID}, nil
}
func (region *SRegion) CreateImage(imageName, format, osType, desc string, reader io.Reader, size int64) (*SImage, error) {
backupStorageUUIDs, err := region.GetBackupStorageUUID()
if err != nil {
return nil, err
}
platform := ""
switch osType {
case "linux":
platform = "Linux"
case "windows":
platform = "Windows"
default:
platform = "Other"
}
parmas := map[string]interface{}{
"params": map[string]interface{}{
"name": imageName,
"url": fmt.Sprintf("upload://%s", imageName),
"description": desc,
"mediaType": "RootVolumeTemplate",
"system": false,
"format": format,
"platform": platform,
"backupStorageUuids": backupStorageUUIDs,
"systemTags": []string{"qemuga", "bootMode::Legacy"},
},
}
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("", imageName)
if err != nil {
return nil, err
}
if reader == nil {
return nil, fmt.Errorf("invalid reader")
}
if size == 0 {
return nil, fmt.Errorf("invalid image size")
}
_, err = io.Copy(part, reader)
if err != nil {
return nil, err
}
err = writer.Close()
if err != nil {
return nil, err
}
image := &SImage{storageCache: region.getStorageCache()}
err = region.client.create("images", jsonutils.Marshal(parmas), image)
if err != nil {
return nil, err
}
if len(image.BackupStorageRefs) < 0 {
return nil, fmt.Errorf("no InstallPath reture")
}
header := http.Header{}
header.Add("X-IMAGE-UUID", image.UUID)
header.Add("X-IMAGE-SIZE", fmt.Sprintf("%d", size))
header.Add("Content-Type", writer.FormDataContentType())
_, err = httputils.Request(httputils.GetDefaultClient(), context.Background(), "POST", image.BackupStorageRefs[0].InstallPath, header, body, false)
return image, err
}
+46
View File
@@ -0,0 +1,46 @@
package zstack
type ImageServers []SImageServer
type SImageServer struct {
ZStackBasic
Hostname string `json:"hostname"`
Username string `json:"username"`
SSHPort int `json:"sshPort"`
URL string `json:"url"`
TotalCapacity int `json:"totalCapacity"`
AvailableCapacity int `json:"availableCapacity"`
Type string `json:"type"`
State string `json:"state"`
Status string `json:"status"`
AttachedZoneUUIDs []string `json:"attachedZoneUuids"`
ZStackTime
}
func (v ImageServers) Len() int {
return len(v)
}
func (v ImageServers) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func (v ImageServers) Less(i, j int) bool {
if v[i].AvailableCapacity < v[j].AvailableCapacity {
return false
}
return true
}
func (region *SRegion) GetImageServers(zoneId string) ([]SImageServer, error) {
servers := []SImageServer{}
params := []string{"q=state=Enabled", "q=status=Connected", "q=type=ImageStoreBackupStorage"}
if SkipEsxi {
params = append(params, "q=type!=VCenter")
}
if len(zoneId) > 0 {
params = append(params, "q=zone.uuid="+zoneId)
}
return servers, region.client.listAll("backup-storage", params, &servers)
}
+267 -31
View File
@@ -11,6 +11,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/pkg/util/osprofile"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
@@ -45,20 +46,8 @@ type SInstance struct {
}
func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) {
instances, err := region.GetInstances("", instanceId, "")
if err != nil {
return nil, err
}
if len(instances) == 1 {
if instances[0].UUID == instanceId {
return &instances[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(instances) == 0 || len(instanceId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
instance := &SInstance{}
return instance, region.client.getResource("vm-instances", instanceId, instance)
}
func (region *SRegion) GetInstances(hostId string, instanceId string, nicId string) ([]SInstance, error) {
@@ -168,7 +157,31 @@ func (instance *SInstance) GetVmemSizeMB() int {
}
func (instance *SInstance) GetBootOrder() string {
return "dcn"
return instance.host.zone.region.GetBootOrder(instance.UUID)
}
func (region *SRegion) GetBootOrder(instanceId string) string {
resp, err := region.client.get("vm-instances", instanceId, "boot-orders")
if err != nil {
return "dcn"
}
orders := []string{}
err = resp.Unmarshal(&orders, "orders")
if err != nil {
return "dcn"
}
order := ""
for _, _order := range orders {
switch _order {
case "CdRom":
order += "c"
case "HardDisk":
order += "d"
default:
log.Errorf("Unknown BootOrder %s for instance %s", _order, instanceId)
}
}
return order
}
func (instance *SInstance) GetVga() string {
@@ -222,11 +235,41 @@ func (instance *SInstance) GetHypervisor() string {
}
func (instance *SInstance) StartVM(ctx context.Context) error {
return cloudprovider.ErrNotImplemented
err := instance.host.zone.region.StartVM(instance.UUID)
if err != nil {
return err
}
return cloudprovider.WaitStatus(instance, api.VM_RUNNING, 5*time.Second, 5*time.Minute)
}
func (region *SRegion) StartVM(instanceId string) error {
params := map[string]interface{}{
"startVmInstance": jsonutils.NewDict(),
}
_, err := region.client.put("vm-instances", instanceId, jsonutils.Marshal(params))
return err
}
func (instance *SInstance) StopVM(ctx context.Context, isForce bool) error {
return cloudprovider.ErrNotImplemented
err := instance.host.zone.region.StopVM(instance.UUID, isForce)
if err != nil {
return err
}
return cloudprovider.WaitStatus(instance, api.VM_READY, 5*time.Second, 5*time.Minute)
}
func (region *SRegion) StopVM(instanceId string, isForce bool) error {
option := "grace"
if isForce {
option = "cold"
}
params := map[string]interface{}{
"stopVmInstance": map[string]string{
"type": option,
},
}
_, err := region.client.put("vm-instances", instanceId, jsonutils.Marshal(params))
return err
}
func (instance *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
@@ -235,43 +278,172 @@ func (instance *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
return nil, err
}
authURL, _ := url.Parse(instance.host.zone.region.client.authURL)
url := fmt.Sprintf("%s://%s:5000/thirdparty/vnc_auto.html?host=%s&port=%d&token=%s&title=%s", info.Scheme, authURL.Host, info.Hostname, info.Port, info.Token, instance.Name)
password, _ := instance.host.zone.region.GetInstanceConsolePassword(instance.UUID)
if len(password) > 0 {
url = url + fmt.Sprintf("&password=%s", password)
}
return jsonutils.Marshal(map[string]string{
"url": fmt.Sprintf("%s://%s:5000/thirdparty/vnc_auto.html?host=%s&port=%d&token=%s&title=%s", info.Scheme, authURL.Host, info.Hostname, info.Port, info.Token, instance.Name),
"url": url,
"protocol": "zstack",
"instance_id": instance.UUID,
}), nil
}
func (instance *SInstance) UpdateVM(ctx context.Context, name string) error {
return cloudprovider.ErrNotImplemented
params := map[string]interface{}{
"updateVmInstance": map[string]string{
"name": name,
},
}
return instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params))
}
func (region *SRegion) UpdateVM(instanceId string, params jsonutils.JSONObject) error {
_, err := region.client.put("vm-instances", instanceId, params)
return err
}
func (instance *SInstance) DeployVM(ctx context.Context, name string, password string, publicKey string, deleteKeypair bool, description string) error {
return cloudprovider.ErrNotImplemented
if instance.Name != name || instance.Description != description {
params := map[string]interface{}{
"updateVmInstance": map[string]string{
"name": name,
"description": description,
},
}
err := instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params))
if err != nil {
return err
}
}
if len(password) > 0 {
params := map[string]interface{}{
"changeVmPassword": map[string]string{
"account": api.VM_ZSTACK_DEFAULT_LOGIN_USER,
"password": password,
},
}
err := instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params))
if err != nil {
return err
}
}
if len(publicKey) > 0 {
params := map[string]interface{}{
"setVmSshKey": map[string]string{
"SshKey": publicKey,
},
}
err := instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params))
if err != nil {
return err
}
}
if deleteKeypair {
err := instance.host.zone.region.client.delete("vm-instances", fmt.Sprintf("%s/ssh-keys", instance.UUID), "")
if err != nil {
return err
}
}
return nil
}
func (instance *SInstance) RebuildRoot(ctx context.Context, imageId string, passwd string, publicKey string, sysSizeGB int) (string, error) {
return "", cloudprovider.ErrNotImplemented
return instance.host.zone.region.RebuildRoot(instance.UUID, imageId, sysSizeGB)
}
func (region *SRegion) RebuildRoot(instanceId, imageId string, sysSizeGB int) (string, error) {
params := map[string]interface{}{
"changeVmImage": map[string]string{
"imageUuid": imageId,
},
}
instance := &SInstance{}
resp, err := region.client.put("vm-instances", instanceId, jsonutils.Marshal(params))
if err != nil {
return "", err
}
err = resp.Unmarshal(instance, "inventory")
if err != nil {
return "", err
}
disk, err := region.GetDisk(instance.RootVolumeUUID)
if err != nil {
return "", err
}
if sysSizeGB > disk.GetDiskSizeMB()*1024 {
return instance.RootVolumeUUID, region.ResizeDisk(disk.UUID, int64(sysSizeGB)*1024)
}
return instance.RootVolumeUUID, nil
}
func (instance *SInstance) ChangeConfig(ctx context.Context, ncpu int, vmem int) error {
return cloudprovider.ErrNotImplemented
offerings, err := instance.host.zone.region.GetInstanceOfferings("", "", ncpu, vmem)
if err != nil {
return err
}
for _, offering := range offerings {
log.Debugf("try instance offering %s(%s) ...", offering.Name, offering.UUID)
err := instance.host.zone.region.ChangeConfig(instance.UUID, offering.UUID)
if err != nil {
log.Errorf("failed to change config for instance %s(%s) error: %v", instance.Name, instance.UUID, err)
} else {
return nil
}
}
return fmt.Errorf("Failed to change vm config, specification not supported")
}
func (instance *SInstance) ChangeConfig2(ctx context.Context, instanceType string) error {
return cloudprovider.ErrNotImplemented
offering, err := instance.host.zone.region.GetInstanceOfferingByType(instanceType)
if err != nil {
return err
}
return instance.host.zone.region.ChangeConfig(instance.UUID, offering.UUID)
}
func (region *SRegion) ChangeConfig(instanceId, offeringId string) error {
params := map[string]interface{}{
"changeInstanceOffering": map[string]string{
"instanceOfferingUuid": offeringId,
},
}
return region.UpdateVM(instanceId, jsonutils.Marshal(params))
}
func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error {
return cloudprovider.ErrNotImplemented
return instance.host.zone.region.AttachDisk(instance.UUID, diskId)
}
func (region *SRegion) AttachDisk(instanceId string, diskId string) error {
_, err := region.client.post(fmt.Sprintf("volumes/%s/vm-instances/%s", diskId, instanceId), jsonutils.NewDict())
return err
}
func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error {
return cloudprovider.ErrNotImplemented
return instance.host.zone.region.DetachDisk(instance.UUID, diskId)
}
func (region *SRegion) DetachDisk(instanceId, diskId string) error {
url := fmt.Sprintf("volumes/%s/vm-instances?vmUuid=%s", diskId, instanceId)
return region.client.delete(url, "", "")
}
func (instance *SInstance) DeleteVM(ctx context.Context) error {
return cloudprovider.ErrNotImplemented
return instance.host.zone.region.DeleteVM(instance.UUID)
}
func (region *SRegion) DeleteVM(instanceId string) error {
err := region.client.delete("vm-instances", instanceId, "Enforcing")
if err != nil {
return err
}
params := map[string]interface{}{
"expungeVmInstance": jsonutils.NewDict(),
}
_, err = region.client.put("vm-instances", instanceId, jsonutils.Marshal(params))
return err
}
func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
@@ -289,11 +461,75 @@ func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
}
func (instance *SInstance) AssignSecurityGroup(secgroupId string) error {
return cloudprovider.ErrNotImplemented
return instance.host.zone.region.AssignSecurityGroup(instance.UUID, secgroupId)
}
func (instance *SInstance) SetSecurityGroups(secgroupIds []string) error {
return cloudprovider.ErrNotImplemented
currentIds, err := instance.GetSecurityGroupIds()
if err != nil {
return err
}
for _, id := range currentIds {
if !utils.IsInStringArray(id, secgroupIds) {
err := instance.host.zone.region.RevokeSecurityGroup(instance.UUID, id)
if err != nil {
return err
}
}
}
for _, id := range secgroupIds {
if !utils.IsInStringArray(id, currentIds) {
err := instance.host.zone.region.AssignSecurityGroup(instance.UUID, id)
if err != nil {
return err
}
}
}
return nil
}
func (region *SRegion) AssignSecurityGroup(instanceId, secgroupId string) error {
instance, err := region.GetInstance(instanceId)
if err != nil {
return err
}
secgroup, err := region.GetSecurityGroup(secgroupId)
if err != nil {
return err
}
if len(instance.VMNics) > 0 {
if !utils.IsInStringArray(instance.VMNics[0].L3NetworkUUID, secgroup.AttachedL3NetworkUUIDs) {
resource := fmt.Sprintf("security-groups/%s/l3-networks/%s", secgroupId, instance.VMNics[0].L3NetworkUUID)
_, err := region.client.post(resource, jsonutils.NewDict())
if err != nil {
return err
}
}
params := map[string]interface{}{
"params": map[string]interface{}{
"vmNicUuids": []string{instance.VMNics[0].UUID},
},
}
resource := fmt.Sprintf("security-groups/%s/vm-instances/nics", secgroupId)
_, err = region.client.post(resource, jsonutils.Marshal(params))
return err
}
return nil
}
func (region *SRegion) RevokeSecurityGroup(instanceId, secgroupId string) error {
instance, err := region.GetInstance(instanceId)
if err != nil {
return err
}
for _, nic := range instance.VMNics {
resource := fmt.Sprintf("security-groups/%s/vm-instances/nics?vmNicUuids=%s", secgroupId, nic.UUID)
err := region.client.delete(resource, "", "")
if err != nil {
return err
}
}
return nil
}
func (instance *SInstance) GetBillingType() string {
@@ -309,15 +545,15 @@ func (instance *SInstance) GetExpiredAt() time.Time {
}
func (instance *SInstance) UpdateUserData(userData string) error {
return cloudprovider.ErrNotImplemented
return cloudprovider.ErrNotSupported
}
func (instance *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error {
return cloudprovider.ErrNotImplemented
return cloudprovider.ErrNotSupported
}
func (instance *SInstance) Renew(bc billing.SBillingCycle) error {
return cloudprovider.ErrNotImplemented
return cloudprovider.ErrNotSupported
}
func (instance *SInstance) GetProjectId() string {
+2 -9
View File
@@ -1,8 +1,6 @@
package zstack
import (
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -43,14 +41,9 @@ func (nic *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork {
log.Errorf("failed to found networks for nic %v error: %v", jsonutils.Marshal(nic).String(), err)
return nil
}
ip, err := netutils.NewIPV4Addr(nic.IP)
if err != nil {
log.Errorf("Invalid ip address %s error: %v", nic.IP, err)
return nil
}
for i := 0; i < len(networks); i++ {
if networks[i].GetIPRange().Contains(ip) {
l3Network, err := nic.instance.host.zone.region.GetL3Network(nic.instance.host.zone.UUID, "", networks[i].L3NetworkUUID)
if networks[i].Contains(nic.IP) {
l3Network, err := nic.instance.host.zone.region.GetL3Network(networks[i].L3NetworkUUID)
if err != nil {
log.Errorf("failed to found l3Network for network %v error: %v", jsonutils.Marshal(networks[i]).String(), err)
return nil
+62 -17
View File
@@ -1,6 +1,8 @@
package zstack
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/pkg/util/netutils"
@@ -54,21 +56,9 @@ func (region *SRegion) GetNetwork(zoneId, wireId, l3Id, networkId string) (*SNet
return nil, cloudprovider.ErrDuplicateId
}
func (region *SRegion) GetL3Network(zoneId string, wireId string, l3Id string) (*SL3Network, error) {
l3Networks, err := region.GetL3Networks(zoneId, wireId, l3Id)
if err != nil {
return nil, err
}
if len(l3Networks) == 1 {
if l3Networks[0].UUID == l3Id {
return &l3Networks[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(l3Networks) == 0 || len(l3Id) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
func (region *SRegion) GetL3Network(l3Id string) (*SL3Network, error) {
l3network := &SL3Network{}
return l3network, region.client.getResource("l3-networks", l3Id, l3network)
}
func (region *SRegion) GetL3Networks(zoneId string, wireId string, l3Id string) ([]SL3Network, error) {
@@ -115,7 +105,7 @@ func (network *SNetwork) GetName() string {
}
func (network *SNetwork) GetGlobalId() string {
return network.UUID
return fmt.Sprintf("%s/%s", network.L3NetworkUUID, network.UUID)
}
func (network *SNetwork) IsEmulated() bool {
@@ -131,7 +121,18 @@ func (network *SNetwork) Delete() error {
}
func (region *SRegion) DeleteNetwork(networkId string) error {
return cloudprovider.ErrNotImplemented
network, err := region.GetNetwork("", "", "", networkId)
if err != nil {
return err
}
l3, err := region.GetL3Network(network.L3NetworkUUID)
if err != nil {
return err
}
if len(l3.Networks) == 1 {
return region.client.delete("l3-networks", l3.UUID, "")
}
return region.client.delete("l3-networks/ip-ranges", networkId, "")
}
func (network *SNetwork) GetIWire() cloudprovider.ICloudWire {
@@ -160,6 +161,14 @@ func (network *SNetwork) GetIPRange() netutils.IPV4AddrRange {
return netutils.NewIPV4AddrRange(start, end)
}
func (network *SNetwork) Contains(ipAddr string) bool {
ip, err := netutils.NewIPV4Addr(ipAddr)
if err != nil {
return false
}
return network.GetIPRange().Contains(ip)
}
func (network *SNetwork) GetIpMask() int8 {
return int8(network.PrefixLen)
}
@@ -184,3 +193,39 @@ func (network *SNetwork) Refresh() error {
func (network *SNetwork) GetProjectId() string {
return ""
}
func (region *SRegion) CreateNetwork(name string, cidr string, wireId string, desc string) (*SNetwork, error) {
params := map[string]interface{}{
"params": map[string]interface{}{
"name": name,
"type": "L3BasicNetwork",
"l2NetworkUuid": wireId,
"category": "Private",
"system": false,
},
}
l3 := &SL3Network{}
resp, err := region.client.post("l3-networks", jsonutils.Marshal(params))
if err != nil {
return nil, err
}
err = resp.Unmarshal(l3, "inventory")
if err != nil {
return nil, err
}
region.AttachServiceForl3Network(l3.UUID, []string{"Flat", "SecurityGroup"})
params = map[string]interface{}{
"params": map[string]interface{}{
"name": name,
"networkCidr": cidr,
},
}
resource := fmt.Sprintf("l3-networks/%s/ip-ranges/by-cidr", l3.UUID)
resp, err = region.client.post(resource, jsonutils.Marshal(params))
if err != nil {
region.client.delete("l3-networks", l3.UUID, "")
return nil, err
}
network := &SNetwork{}
return network, resp.Unmarshal(network, "inventory")
}
+117
View File
@@ -0,0 +1,117 @@
package zstack
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
)
type SNetworkService struct {
IPsec []string `json:"IPsec"`
VRouterRoute []string `json:"VRouterRoute"`
VipQos []string `json:"VipQos"`
DNS []string `json:"DNS"`
SNAT []string `json:"SNAT"`
LoadBalancer []string `json:"LoadBalancer"`
Userdata []string `json:"Userdata"`
SecurityGroup []string `json:"SecurityGroup"`
Eip []string `json:"Eip"`
DHCP []string `json:"DHCP"`
CentralizedDNS []string `json:"CentralizedDNS"`
HostRoute []string `json:"HostRoute"`
PortForwarding []string `json:"PortForwarding"`
}
type SNetworkServiceProvider struct {
ZStackBasic
ZStackTime
Type string `json:"type"`
NetworkServiceTypes []string `json:"networkServiceTypes"`
AttachedL2NetworkUUIDs []string `json:"attachedL2NetworkUuids"`
}
type SNetworkServiceRef struct {
L3NetworkUUID string `json:"l3NetworkUuid"`
NetworkServiceProviderUUID string `json:"networkServiceProviderUuid"`
NetworkServiceType string `json:"networkServiceType"`
}
func (region *SRegion) GetNetworkServices() (*SNetworkService, error) {
service := &SNetworkService{}
resp, err := region.client.get("network-services/types", "", "")
if err != nil {
return nil, err
}
return service, resp.Unmarshal(service, "types")
}
func (region *SRegion) GetNetworkServiceProviders(Type string) ([]SNetworkServiceProvider, error) {
providers := []SNetworkServiceProvider{}
params := []string{}
if len(Type) > 0 {
params = append(params, "q=type="+Type)
}
return providers, region.client.listAll("network-services/providers", params, &providers)
}
func (region *SRegion) GetNetworkServiceRef(l3Id string, Type string) ([]SNetworkServiceRef, error) {
refs := []SNetworkServiceRef{}
params := []string{}
if len(l3Id) > 0 {
params = append(params, "q=l3NetworkUuid="+l3Id)
}
if len(Type) > 0 {
params = append(params, "q=networkServiceType="+Type)
}
return refs, region.client.listAll("l3-networks/network-services/refs", params, &refs)
}
func (region *SRegion) AttachServiceForl3Network(l3Id string, services []string) error {
networkServices := map[string][]string{}
refs, err := region.GetNetworkServiceRef(l3Id, "")
if err != nil {
return err
}
currentServices := []string{}
for i := 0; i < len(refs); i++ {
currentServices = append(currentServices, refs[i].NetworkServiceType)
}
for _, service := range services {
networkServiceProviders, err := region.GetNetworkServiceProviders(service)
if err != nil || len(networkServiceProviders) == 0 {
msg := fmt.Sprintf("failed to find network services %s error: %v", service, err)
log.Errorln(msg)
return fmt.Errorf(msg)
}
attachServices := []string{}
for i := 0; i < len(networkServiceProviders[0].NetworkServiceTypes); i++ {
if !utils.IsInStringArray(networkServiceProviders[0].NetworkServiceTypes[i], currentServices) {
attachServices = append(attachServices, networkServiceProviders[0].NetworkServiceTypes[i])
}
}
if len(attachServices) > 0 {
networkServices[networkServiceProviders[0].UUID] = attachServices
}
}
if len(networkServices) == 0 {
return nil
}
params := map[string]interface{}{
"params": map[string]interface{}{
"networkServices": networkServices,
},
}
resource := fmt.Sprintf("l3-networks/%s/network-services", l3Id)
_, err = region.client.post(resource, jsonutils.Marshal(params))
if err != nil {
log.Errorf("failed to attach network services %s to l3network %s error: %v", services, l3Id, err)
}
return err
}
func (region *SRegion) RemoveNetworkService(l3Id string, service string) error {
return region.client.delete("l3-networks", fmt.Sprintf("%s/network-services?networkServices=%s", l3Id, service), "")
}
+23 -11
View File
@@ -1,8 +1,9 @@
package zstack
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudprovider"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
@@ -22,28 +23,39 @@ type SInstanceOffering struct {
}
func (region *SRegion) GetInstanceOffering(offerId string) (*SInstanceOffering, error) {
offerings, err := region.GetInstanceOfferings(offerId)
offer := &SInstanceOffering{region: region}
return offer, region.client.getResource("instance-offerings", offerId, offer)
}
func (region *SRegion) GetInstanceOfferingByType(instanceType string) (*SInstanceOffering, error) {
offerings, err := region.GetInstanceOfferings("", instanceType, 0, 0)
if err != nil {
return nil, err
}
if len(offerings) == 1 {
if offerings[0].UUID == offerId {
return &offerings[0], nil
}
return nil, cloudprovider.ErrNotFound
return &offerings[0], nil
}
if len(offerings) == 0 || len(offerId) == 0 {
return nil, cloudprovider.ErrNotFound
if len(offerings) == 0 {
return nil, fmt.Errorf("instanceType %s not found", instanceType)
}
return nil, cloudprovider.ErrDuplicateId
return nil, fmt.Errorf("duplicate instanceType %s", instanceType)
}
func (region *SRegion) GetInstanceOfferings(offerId string) ([]SInstanceOffering, error) {
func (region *SRegion) GetInstanceOfferings(offerId string, name string, cpu int, memorySizeMb int) ([]SInstanceOffering, error) {
offerings := []SInstanceOffering{}
params := []string{"q=type=UserVM"}
params := []string{"q=type=UserVM", "q=state=Enabled"}
if len(offerId) > 0 {
params = append(params, "q=uuid="+offerId)
}
if len(name) > 0 {
params = append(params, "q=name="+name)
}
if cpu != 0 {
params = append(params, fmt.Sprintf("q=cpuNum=%d", cpu))
}
if memorySizeMb != 0 {
params = append(params, fmt.Sprintf("q=memorySize=%d", memorySizeMb*1024*1024))
}
if err := region.client.listAll("instance-offerings", params, &offerings); err != nil {
return nil, err
}
+46 -21
View File
@@ -2,6 +2,7 @@ package zstack
import (
"fmt"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -35,11 +36,11 @@ func (region *SRegion) GetId() string {
}
func (region *SRegion) GetName() string {
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ZSTACK, region.Name)
return region.client.providerName
}
func (region *SRegion) GetGlobalId() string {
return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_ZSTACK, region.Name)
return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_ZSTACK, region.client.providerID)
}
func (region *SRegion) IsEmulated() bool {
@@ -64,7 +65,7 @@ func (region *SRegion) Refresh() error {
}
func (region *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
return region.GetHost("", id)
return region.GetHost(id)
}
func (region *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
@@ -114,6 +115,10 @@ func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache,
return []cloudprovider.ICloudStoragecache{region.storageCache}, nil
}
func (region *SRegion) getStorageCache() *SStoragecache {
return &SStoragecache{region: region}
}
func (region *SRegion) GetIVpcById(vpcId string) (cloudprovider.ICloudVpc, error) {
return &SVpc{region: region}, nil
}
@@ -132,20 +137,8 @@ func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error)
}
func (region *SRegion) GetZone(zoneId string) (*SZone, error) {
zones, err := region.GetZones(zoneId)
if err != nil {
return nil, err
}
if len(zones) == 1 {
if zones[0].UUID == zoneId {
return &zones[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(zones) == 0 || len(zoneId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
zone := &SZone{region: region}
return zone, region.client.getResource("zones", zoneId, zone)
}
func (region *SRegion) GetZones(zoneId string) ([]SZone, error) {
@@ -206,8 +199,23 @@ func (region *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudp
return nil, cloudprovider.ErrNotSupported
}
func (region *SRegion) CreateEIP(name string, bwMbps int, chargeType string, bgpType string) (cloudprovider.ICloudEIP, error) {
return nil, cloudprovider.ErrNotImplemented
func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
if len(eip.NetworkExternalId) == 0 {
return nil, fmt.Errorf("networkId cannot be empty")
}
networkInfo := strings.Split(eip.NetworkExternalId, "/")
if len(networkInfo) != 2 {
return nil, fmt.Errorf("invalid network externalId, it should be `l3networId/networkId` format")
}
_, err := region.GetL3Network(networkInfo[0])
if err != nil {
return nil, err
}
vip, err := region.CreateVirtualIP(eip.Name, "", eip.IP, networkInfo[0])
if err != nil {
return nil, err
}
return region.CreateEip(eip.Name, vip.UUID, "")
}
func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
@@ -284,7 +292,7 @@ func (region *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloud
}
func (region *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
offerings, err := region.GetInstanceOfferings("")
offerings, err := region.GetInstanceOfferings("", "", 0, 0)
if err != nil {
return nil, err
}
@@ -296,5 +304,22 @@ func (region *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error)
}
func (region *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
return "", cloudprovider.ErrNotImplemented
if len(secgroupId) > 0 {
_, err := region.GetSecurityGroup(secgroupId)
if err != nil {
if err == cloudprovider.ErrNotFound {
secgroupId = ""
} else {
return "", err
}
}
}
if len(secgroupId) == 0 {
secgroup, err := region.CreateSecurityGroup(name, desc)
if err != nil {
return "", err
}
secgroupId = secgroup.UUID
}
return secgroupId, region.syncSecgroupRules(secgroupId, rules)
}
+185 -32
View File
@@ -1,11 +1,11 @@
package zstack
import (
"fmt"
"net"
"sort"
"strings"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/pkg/util/secrules"
@@ -25,6 +25,28 @@ type SSecurityGroupRule struct {
ZStackTime
}
type SSecurityGroupRuleSet []SSecurityGroupRule
func (v SSecurityGroupRuleSet) Len() int {
return len(v)
}
func (v SSecurityGroupRuleSet) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func (v SSecurityGroupRuleSet) Less(i, j int) bool {
rule, err := v[i].toRule()
if err != nil {
return false
}
_rule, err := v[j].toRule()
if err != nil {
return false
}
return strings.Compare(rule.String(), _rule.String()) <= 0
}
type SSecurityGroup struct {
region *SRegion
@@ -38,20 +60,8 @@ type SSecurityGroup struct {
}
func (region *SRegion) GetSecurityGroup(secgroupId string) (*SSecurityGroup, error) {
secgroups, err := region.GetSecurityGroups(secgroupId, "")
if err != nil {
return nil, err
}
if len(secgroups) == 1 {
if secgroups[0].UUID == secgroupId {
return &secgroups[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(secgroups) == 0 || len(secgroupId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
secgroup := &SSecurityGroup{region: region}
return secgroup, region.client.getResource("security-groups", secgroupId, secgroup)
}
func (region *SRegion) GetSecurityGroups(secgroupId string, instanceId string) ([]SSecurityGroup, error) {
@@ -94,33 +104,44 @@ func (self *SSecurityGroup) GetDescription() string {
return self.Description
}
func (rule *SSecurityGroupRule) toRule() (*secrules.SecurityRule, error) {
r := &secrules.SecurityRule{
Direction: secrules.DIR_IN,
Action: secrules.SecurityRuleAllow,
Priority: 1,
Protocol: secrules.PROTO_ANY,
PortStart: rule.StartPort,
PortEnd: rule.EndPort,
}
_, ipNet, err := net.ParseCIDR(rule.AllowedCIDR)
if err != nil {
return nil, err
}
r.IPNet = ipNet
if rule.Type == "Egress" {
r.Direction = secrules.DIR_OUT
}
if rule.Protocol != "ALL" {
r.Protocol = strings.ToLower(rule.Protocol)
}
return r, nil
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := []secrules.SecurityRule{}
priority := 100
outRuleCount := 0
for i := 0; i < len(self.Rules); i++ {
if self.Rules[i].IPVersion == 4 {
rule := secrules.SecurityRule{
Direction: secrules.DIR_IN,
Action: secrules.SecurityRuleAllow,
Priority: priority,
Protocol: secrules.PROTO_ANY,
PortStart: self.Rules[i].StartPort,
PortEnd: self.Rules[i].EndPort,
}
_, ipNet, err := net.ParseCIDR(self.Rules[i].AllowedCIDR)
rule, err := self.Rules[i].toRule()
if err != nil {
return nil, err
}
rule.IPNet = ipNet
if self.Rules[i].Type == "Egress" {
rule.Direction = secrules.DIR_OUT
if rule.Direction == secrules.DIR_OUT {
outRuleCount++
}
if self.Rules[i].Protocol != "ALL" {
rule.Protocol = strings.ToLower(self.Rules[i].Protocol)
}
rules = append(rules, rule)
rule.Priority = priority
rules = append(rules, *rule)
priority--
}
}
@@ -155,3 +176,135 @@ func (self *SSecurityGroup) Refresh() error {
func (self *SSecurityGroup) GetProjectId() string {
return ""
}
func (region *SRegion) AddSecurityGroupRule(secgroupId string, rules []secrules.SecurityRule) error {
ruleParam := []map[string]interface{}{}
for _, rule := range rules {
Type := "Ingress"
if rule.Direction == secrules.DIR_OUT {
Type = "Egress"
}
protocol := "ALL"
if rule.Protocol != secrules.PROTO_ANY {
protocol = strings.ToUpper(rule.Protocol)
}
if rule.Protocol == secrules.PROTO_ICMP {
rule.PortStart = -1
rule.PortEnd = -1
rule.Ports = []int{}
}
if len(rule.Ports) > 0 {
for _, port := range rule.Ports {
ruleParam = append(ruleParam, map[string]interface{}{
"type": Type,
"startPort": port,
"endPort": port,
"protocol": protocol,
"allowedCidr": rule.IPNet.String(),
})
}
} else {
ruleParam = append(ruleParam, map[string]interface{}{
"type": Type,
"startPort": rule.PortStart,
"endPort": rule.PortEnd,
"protocol": protocol,
"allowedCidr": rule.IPNet.String(),
})
}
}
if len(ruleParam) > 0 {
params := map[string]interface{}{
"parms": map[string]interface{}{
"rules": ruleParam,
},
}
return region.client.create(fmt.Sprintf("security-groups/%s/rules", secgroupId), jsonutils.Marshal(params), nil)
}
return nil
}
func (region *SRegion) DeleteSecurityGroupRules(ruleIds []string) error {
resource := fmt.Sprintf("security-groups/rules?ruleUuids=%s", strings.Join(ruleIds, ","))
return region.client.delete(resource, "", "")
}
func (region *SRegion) CreateSecurityGroup(name, desc string) (*SSecurityGroup, error) {
secgroup := &SSecurityGroup{}
params := map[string]map[string]string{
"params": {
"name": name,
"description": desc,
},
}
return secgroup, region.client.create("security-groups", jsonutils.Marshal(params), secgroup)
}
func (region *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error {
secgroup, err := region.GetSecurityGroup(secgroupId)
if err != nil {
return err
}
inRules, outRules := secrules.SecurityRuleSet{}, secrules.SecurityRuleSet{}
for i := 0; i < len(rules); i++ {
if rules[i].Direction == secrules.DIR_IN {
inRules = append(inRules, rules[i])
} else {
outRules = append(outRules, rules[i])
}
}
if len(outRules) > 0 {
rule := secrules.MustParseSecurityRule("out:allow any")
outRules = append(outRules, *rule)
}
rules = inRules.AllowList()
rules = append(rules, outRules.AllowList()...)
for i := 0; i < len(rules); i++ {
rules[i].Priority = 1
}
sort.Sort(secrules.SecurityRuleSet(rules))
sort.Sort(SSecurityGroupRuleSet(secgroup.Rules))
delRuleIds := []string{}
addRules := []secrules.SecurityRule{}
i, j := 0, 0
for i < len(rules) || j < len(secgroup.Rules) {
if i < len(rules) && j < len(secgroup.Rules) {
_rule, err := secgroup.Rules[j].toRule()
if err != nil {
return err
}
_ruleStr := _rule.String()
ruleStr := rules[i].String()
cmp := strings.Compare(_ruleStr, ruleStr)
if cmp == 0 {
i++
j++
} else if cmp > 0 {
delRuleIds = append(delRuleIds, secgroup.Rules[j].UUID)
j++
} else {
addRules = append(addRules, rules[i])
i++
}
} else if i >= len(rules) {
delRuleIds = append(delRuleIds, secgroup.Rules[j].UUID)
j++
} else if j >= len(secgroup.Rules) {
addRules = append(addRules, rules[i])
i++
}
}
if len(delRuleIds) > 0 {
err = region.DeleteSecurityGroupRules(delRuleIds)
if err != nil {
return err
}
}
return region.AddSecurityGroupRule(secgroupId, addRules)
}
+19
View File
@@ -0,0 +1,19 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/shellutils"
"yunion.io/x/onecloud/pkg/util/zstack"
)
func init() {
type ConfigrationListOptions struct {
}
shellutils.R(&ConfigrationListOptions{}, "configration-list", "List configration", func(cli *zstack.SRegion, args *ConfigrationListOptions) error {
configrations, err := cli.GetConfigrations()
if err != nil {
return err
}
printList(configrations, len(configrations), 0, 0, []string{})
return nil
})
}
+17 -8
View File
@@ -20,6 +20,23 @@ func init() {
return nil
})
type DiskIdOptions struct {
ID string
}
shellutils.R(&DiskIdOptions{}, "disk-show", "Show disk", func(cli *zstack.SRegion, args *DiskIdOptions) error {
disk, err := cli.GetDisk(args.ID)
if err != nil {
return err
}
printObject(disk)
return nil
})
shellutils.R(&DiskIdOptions{}, "disk-delete", "Delete disk", func(cli *zstack.SRegion, args *DiskIdOptions) error {
return cli.DeleteDisk(args.ID)
})
type DiskCreateOptions struct {
NAME string
Description string
@@ -38,14 +55,6 @@ func init() {
return nil
})
type DiskDelete struct {
ID string
}
shellutils.R(&DiskDelete{}, "disk-delete", "Delete disk", func(cli *zstack.SRegion, args *DiskDelete) error {
return cli.DeleteDisk(args.ID)
})
type DiskResize struct {
ID string
SIZEGB int64
+27
View File
@@ -1,6 +1,8 @@
package shell
import (
"os"
"yunion.io/x/onecloud/pkg/util/shellutils"
"yunion.io/x/onecloud/pkg/util/zstack"
)
@@ -18,4 +20,29 @@ func init() {
return nil
})
type ImageCreateOptions struct {
FILE string
FORMAT string `choices:"qcow2|raw|iso"`
PLATFORM string `choices:"Linux|Windows|Other"`
Desc string
}
shellutils.R(&ImageCreateOptions{}, "image-create", "Create image", func(cli *zstack.SRegion, args *ImageCreateOptions) error {
f, err := os.Open(args.FILE)
if err != nil {
return err
}
defer f.Close()
finfo, err := f.Stat()
if err != nil {
return err
}
image, err := cli.CreateImage(args.FILE, args.FORMAT, args.PLATFORM, args.Desc, f, finfo.Size())
if err != nil {
return err
}
printObject(image)
return nil
})
}
+21
View File
@@ -0,0 +1,21 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/shellutils"
"yunion.io/x/onecloud/pkg/util/zstack"
)
func init() {
type ImageServerListOptions struct {
ZoneId string
}
shellutils.R(&ImageServerListOptions{}, "image-server-list", "List image servers", func(cli *zstack.SRegion, args *ImageServerListOptions) error {
servers, err := cli.GetImageServers(args.ZoneId)
if err != nil {
return err
}
printList(servers, 0, 0, 0, []string{})
return nil
})
}
+35
View File
@@ -26,6 +26,10 @@ func init() {
ID string
}
shellutils.R(&InstanceOperation{}, "instance-delete", "Delete instance", func(cli *zstack.SRegion, args *InstanceOperation) error {
return cli.DeleteVM(args.ID)
})
shellutils.R(&InstanceOperation{}, "instance-console-password", "Show instance console password", func(cli *zstack.SRegion, args *InstanceOperation) error {
password, err := cli.GetInstanceConsolePassword(args.ID)
if err != nil {
@@ -44,4 +48,35 @@ func init() {
return nil
})
shellutils.R(&InstanceOperation{}, "instance-start", "Start instance", func(cli *zstack.SRegion, args *InstanceOperation) error {
return cli.StartVM(args.ID)
})
shellutils.R(&InstanceOperation{}, "instance-boot-order", "Show instance boot order", func(cli *zstack.SRegion, args *InstanceOperation) error {
fmt.Println(cli.GetBootOrder(args.ID))
return nil
})
type InstanceStopOption struct {
ID string
IsForce bool
}
shellutils.R(&InstanceStopOption{}, "instance-stop", "Start instance", func(cli *zstack.SRegion, args *InstanceStopOption) error {
return cli.StopVM(args.ID, args.IsForce)
})
type InstanceSecgroupOption struct {
ID string
SECGRPID string
}
shellutils.R(&InstanceSecgroupOption{}, "instance-assign-secgroup", "Assign secgroup for a instance", func(cli *zstack.SRegion, args *InstanceSecgroupOption) error {
return cli.AssignSecurityGroup(args.ID, args.SECGRPID)
})
shellutils.R(&InstanceSecgroupOption{}, "instance-revoke-secgroup", "Assign secgroup for a instance", func(cli *zstack.SRegion, args *InstanceSecgroupOption) error {
return cli.RevokeSecurityGroup(args.ID, args.SECGRPID)
})
}
@@ -0,0 +1,23 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/shellutils"
"yunion.io/x/onecloud/pkg/util/zstack"
)
func init() {
type InstanceOfferingListOptions struct {
OfferId string
Name string
Cpu int
MemoryMb int
}
shellutils.R(&InstanceOfferingListOptions{}, "instance-offering-list", "List instance offerings", func(cli *zstack.SRegion, args *InstanceOfferingListOptions) error {
offerings, err := cli.GetInstanceOfferings(args.OfferId, args.Name, args.Cpu, args.MemoryMb)
if err != nil {
return err
}
printList(offerings, len(offerings), 0, 0, []string{})
return nil
})
}
+98
View File
@@ -20,4 +20,102 @@ func init() {
printList(networks, len(networks), 0, 0, []string{})
return nil
})
type NetworkDeleteOptions struct {
ID string
}
shellutils.R(&NetworkDeleteOptions{}, "network-delete", "Delete network", func(cli *zstack.SRegion, args *NetworkDeleteOptions) error {
return cli.DeleteNetwork(args.ID)
})
type NetworkCreateOptions struct {
NAME string
Desc string
WIRE string
CIDR string
}
shellutils.R(&NetworkCreateOptions{}, "network-create", "Create network", func(cli *zstack.SRegion, args *NetworkCreateOptions) error {
network, err := cli.CreateNetwork(args.NAME, args.CIDR, args.WIRE, args.Desc)
if err != nil {
return err
}
printObject(network)
return nil
})
type L3NetworkListOptions struct {
ZoneId string
WireId string
Id string
}
shellutils.R(&L3NetworkListOptions{}, "l3network-list", "List networks", func(cli *zstack.SRegion, args *L3NetworkListOptions) error {
l3networks, err := cli.GetL3Networks(args.ZoneId, args.WireId, args.Id)
if err != nil {
return err
}
printList(l3networks, len(l3networks), 0, 0, []string{})
return nil
})
type NetworkServicesOptions struct {
}
shellutils.R(&NetworkServicesOptions{}, "network-service-list", "List network services", func(cli *zstack.SRegion, args *NetworkServicesOptions) error {
service, err := cli.GetNetworkServices()
if err != nil {
return err
}
printObject(service)
return nil
})
type NetworkServiceProviderOptions struct {
Type string
}
shellutils.R(&NetworkServiceProviderOptions{}, "network-service-provider-list", "List network service providers", func(cli *zstack.SRegion, args *NetworkServiceProviderOptions) error {
providers, err := cli.GetNetworkServiceProviders(args.Type)
if err != nil {
return err
}
printList(providers, len(providers), 0, 0, []string{})
return nil
})
type NetworkServiceAttachOptions struct {
Services []string
ID string
}
shellutils.R(&NetworkServiceAttachOptions{}, "network-service-attach", "Attach network service to l3network", func(cli *zstack.SRegion, args *NetworkServiceAttachOptions) error {
cli.AttachServiceForl3Network(args.ID, args.Services)
return nil
})
type NetworkServiceRefOptions struct {
L3Id string
Type string
}
shellutils.R(&NetworkServiceRefOptions{}, "network-service-ref", "List network service ref", func(cli *zstack.SRegion, args *NetworkServiceRefOptions) error {
refs, err := cli.GetNetworkServiceRef(args.L3Id, args.Type)
if err != nil {
return err
}
printList(refs, len(refs), 0, 0, []string{})
return nil
})
type NetworkServiceRemoveOptions struct {
L3ID string
SERVICE string `choices:"Userdata|DHCP|VipQos|HostRoute|Eip|SecurityGroup|DNS|SNAT"`
}
shellutils.R(&NetworkServiceRemoveOptions{}, "remove-network-service", "Remove l3network service", func(cli *zstack.SRegion, args *NetworkServiceRemoveOptions) error {
return cli.RemoveNetworkService(args.L3ID, args.SERVICE)
})
}
-20
View File
@@ -1,20 +0,0 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/shellutils"
"yunion.io/x/onecloud/pkg/util/zstack"
)
func init() {
type OfferingListOptions struct {
OfferId string
}
shellutils.R(&OfferingListOptions{}, "offering-list", "List instance offerings", func(cli *zstack.SRegion, args *OfferingListOptions) error {
offerings, err := cli.GetInstanceOfferings(args.OfferId)
if err != nil {
return err
}
printList(offerings, len(offerings), 0, 0, []string{})
return nil
})
}
+2 -2
View File
@@ -11,8 +11,8 @@ func init() {
ClusterId string
Id string
}
shellutils.R(&StorageListOptions{}, "primary-storage-list", "List storages", func(cli *zstack.SRegion, args *StorageListOptions) error {
storages, err := cli.GetPrimaryStorages(args.ZoneId, args.ClusterId, args.Id)
shellutils.R(&StorageListOptions{}, "storage-list", "List storages", func(cli *zstack.SRegion, args *StorageListOptions) error {
storages, err := cli.GetStorages(args.ZoneId, args.ClusterId, args.Id)
if err != nil {
return err
}
+37
View File
@@ -0,0 +1,37 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/shellutils"
"yunion.io/x/onecloud/pkg/util/zstack"
)
func init() {
type VipListOptions struct {
VipId string
}
shellutils.R(&VipListOptions{}, "vip-list", "List vips", func(cli *zstack.SRegion, args *VipListOptions) error {
vips, err := cli.GetVirtualIPs(args.VipId)
if err != nil {
return err
}
printList(vips, 0, 0, 0, []string{})
return nil
})
type VipCreateOptions struct {
NAME string
Desc string
Ip string
L3ID string
}
shellutils.R(&VipCreateOptions{}, "vip-create", "Create vip", func(cli *zstack.SRegion, args *VipCreateOptions) error {
vip, err := cli.CreateVirtualIP(args.NAME, args.Desc, args.Ip, args.L3ID)
if err != nil {
return err
}
printObject(vip)
return nil
})
}
+2 -15
View File
@@ -5,7 +5,6 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
@@ -76,20 +75,8 @@ func (snapshot *SSnapshot) IsEmulated() bool {
}
func (region *SRegion) GetSnapshot(snapshotId string) (*SSnapshot, error) {
snapshots, err := region.GetSnapshots(snapshotId, "")
if err != nil {
return nil, err
}
if len(snapshots) == 1 {
if snapshots[0].UUID == snapshotId {
return &snapshots[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(snapshots) == 0 || len(snapshotId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
snapshot := &SSnapshot{region: region}
return snapshot, region.client.getResource("volume-snapshots", snapshotId, snapshot)
}
func (region *SRegion) GetSnapshots(snapshotId string, diskId string) ([]SSnapshot, error) {
+225 -12
View File
@@ -1,35 +1,248 @@
package zstack
import (
"fmt"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type TStorageType string
type TCephPoolType string
const (
StorageTypeCeph = TStorageType("Ceph")
StorageTypeLocal = TStorageType("LocalStorage")
StorageTypeVCenter = TStorageType("VCenter")
CephPoolTypeData = TCephPoolType("Data")
CephPoolTypeRoot = TCephPoolType("Root")
CephPoolTypeImageCache = TCephPoolType("ImageCache")
)
type SPool struct {
UUID string `json:"uuid"`
PrimaryStorageUUID string `json:"primaryStorageUuid"`
PoolName string `json:"poolName"`
Type TCephPoolType `json:"type"`
AvailableCapacity int64 `json:"availableCapacity"`
UsedCapacity int64 `json:"usedCapacity"`
ReplicatedSize int64 `json:"replicatedSize"`
TotalCapacity int64 `json:"totalCapacity"`
ZStackTime
}
type SStorage struct {
region *SRegion
ZStackBasic
VCenterUUID string `json:"VCenterUuid"`
Datastore string `json:"datastore"`
ZoneUUID string `json:"zoneUuid"`
URL string `json:"url"`
TotalCapacity int64 `json:"totalCapacity"`
AvailableCapacity int `json:"availableCapacity"`
TotalPhysicalCapacity int `json:"totalPhysicalCapacity"`
AvailablePhysicalCapacity int `json:"availablePhysicalCapacity"`
Type TStorageType `json:"type"`
State string `json:"state"`
Status string `json:"status"`
MountPath string `json:"mountPath"`
AttachedClusterUUIDs []string `json:"attachedClusterUuids"`
Pools []SPool `json:"pools"`
ZStackTime
}
func (region *SRegion) getIStorages(zondId string) ([]cloudprovider.ICloudStorage, error) {
primaryStorages, err := region.GetPrimaryStorages(zondId, "", "")
primaryStorages, err := region.GetStorages(zondId, "", "")
if err != nil {
return nil, err
}
istorage := []cloudprovider.ICloudStorage{}
for _, primaryStorage := range primaryStorages {
zone, err := region.GetZone(primaryStorage.ZoneUUID)
if err != nil {
return nil, err
}
for i := 0; i < len(primaryStorages); i++ {
primaryStorage := primaryStorages[i]
switch primaryStorage.Type {
case StorageTypeLocal:
ilocalStorages, err := region.getILocalStorages(zone, primaryStorage.UUID, "")
ilocalStorages, err := region.getILocalStorages(primaryStorage.UUID, "")
if err != nil {
return nil, err
}
istorage = append(istorage, ilocalStorages...)
case StorageTypeCeph:
icephStorage, err := region.getICephStorages(zone, primaryStorage.UUID)
if err != nil {
return nil, err
}
istorage = append(istorage, icephStorage...)
primaryStorage.region = region
istorage = append(istorage, &primaryStorage)
case StorageTypeVCenter:
}
}
return istorage, nil
}
func (region *SRegion) GetStorage(storageId string) (*SStorage, error) {
if len(storageId) == 0 {
return nil, cloudprovider.ErrNotFound
}
storages, err := region.GetStorages("", "", storageId)
if err != nil {
return nil, err
}
if len(storages) == 1 && storages[0].UUID == storageId {
storages[0].region = region
return &storages[0], nil
}
if len(storages) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
}
func (region *SRegion) GetStorages(zoneId, clusterId, storageId string) ([]SStorage, error) {
storages := []SStorage{}
params := []string{}
if len(zoneId) > 0 {
params = append(params, "q=zone.uuid="+zoneId)
}
if len(clusterId) > 0 {
params = append(params, "q=cluster.uuid="+clusterId)
}
if SkipEsxi {
params = append(params, "q=type!=VCenter")
}
if len(storageId) > 0 {
params = append(params, "q=uuid="+storageId)
}
return storages, region.client.listAll("primary-storage", params, &storages)
}
func (storage *SStorage) GetStatus() string {
if storage.Status == "Connected" {
return api.STORAGE_ONLINE
}
return api.STORAGE_OFFLINE
}
func (storage *SStorage) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (storage *SStorage) GetId() string {
return storage.UUID
}
func (storage *SStorage) GetName() string {
return storage.Name
}
func (storage *SStorage) GetGlobalId() string {
return storage.GetId()
}
func (storage *SStorage) IsEmulated() bool {
return false
}
func (storage *SStorage) GetIZone() cloudprovider.ICloudZone {
zone, err := storage.region.GetZone(storage.ZoneUUID)
if err != nil {
log.Errorf("failed to find zone for storage %s(%s)", storage.Name, storage.UUID)
return nil
}
return zone
}
func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
disks, err := storage.region.GetDisks(storage.UUID, []string{}, "")
if err != nil {
return nil, err
}
idisks := []cloudprovider.ICloudDisk{}
for i := 0; i < len(disks); i++ {
disks[i].storage = storage
disks[i].region = storage.region
idisks = append(idisks, &disks[i])
}
return idisks, nil
}
func (storage *SStorage) GetStorageType() string {
return strings.ToLower(string(storage.Type))
}
func (storage *SStorage) GetMediumType() string {
return api.DISK_TYPE_ROTATE
}
func (storage *SStorage) GetCapacityMB() int64 {
return storage.TotalCapacity / 1024 / 1024
}
func (storage *SStorage) GetStorageConf() jsonutils.JSONObject {
conf := jsonutils.NewDict()
return conf
}
func (storage *SStorage) Refresh() error {
// do nothing
return nil
}
func (storage *SStorage) GetEnabled() bool {
return true
}
func (storage *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache {
storage.region.GetIStoragecaches()
return storage.region.storageCache
}
func (storage *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) {
poolName, err := storage.GetDataPoolName()
if err != nil {
return nil, err
}
disk, err := storage.region.CreateDisk(name, storage.UUID, "", poolName, sizeGb, desc)
if err != nil {
return nil, err
}
disk.storage = storage
return disk, nil
}
func (storage *SStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) {
disk, err := storage.region.GetDisk(diskId)
if err != nil {
return nil, err
}
if disk.PrimaryStorageUUID != storage.UUID {
return nil, cloudprovider.ErrNotFound
}
disk.region = storage.region
disk.storage = storage
return disk, nil
}
func (storage *SStorage) GetMountPoint() string {
poolName, _ := storage.GetDataPoolName()
if len(poolName) > 0 {
return fmt.Sprintf("ceph://%s", poolName)
}
return ""
}
func (storage *SStorage) IsSysDiskStore() bool {
return true
}
func (storage *SStorage) GetDataPoolName() (string, error) {
for _, pool := range storage.Pools {
if pool.Type == CephPoolTypeData {
return pool.PoolName, nil
}
}
return "", fmt.Errorf("failed to found storage %s(%s) data pool name", storage.Name, storage.UUID)
}
-172
View File
@@ -1,172 +0,0 @@
package zstack
import (
"fmt"
"strings"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type TCephPoolType string
const (
CephPoolTypeData = TCephPoolType("Data")
CephPoolTypeRoot = TCephPoolType("Root")
CephPoolTypeImageCache = TCephPoolType("ImageCache")
)
type SCephStorage struct {
zone *SZone
UUID string `json:"uuid"`
PrimaryStorageUUID string `json:"primaryStorageUuid"`
PoolName string `json:"poolName"`
Type TCephPoolType `json:"type"`
AvailableCapacity int64 `json:"availableCapacity"`
UsedCapacity int64 `json:"usedCapacity"`
ReplicatedSize int64 `json:"replicatedSize"`
TotalCapacity int64 `json:"totalCapacity"`
ZStackTime
}
func (region *SRegion) getICephStorages(zone *SZone, storageId string) ([]cloudprovider.ICloudStorage, error) {
storage, err := region.GetPrimaryStorage(storageId)
if err != nil {
return nil, err
}
istorages := []cloudprovider.ICloudStorage{}
for i := 0; i < len(storage.Pools); i++ {
storage.Pools[i].zone = zone
istorages = append(istorages, &storage.Pools[i])
}
return istorages, nil
}
func (storage *SCephStorage) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (storage *SCephStorage) GetId() string {
return fmt.Sprintf("%s/%s", storage.PrimaryStorageUUID, storage.UUID)
}
func (storage *SCephStorage) GetName() string {
primaryStorage, err := storage.zone.region.GetPrimaryStorage(storage.PrimaryStorageUUID)
if err != nil {
return "Unknown"
}
return fmt.Sprintf("%s/%s", primaryStorage.Name, storage.PoolName)
}
func (storage *SCephStorage) GetGlobalId() string {
return storage.GetId()
}
func (storage *SCephStorage) IsEmulated() bool {
return false
}
func (storage *SCephStorage) GetIZone() cloudprovider.ICloudZone {
return storage.zone
}
func (storage *SCephStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
if storage.Type == CephPoolTypeImageCache {
return []cloudprovider.ICloudDisk{}, nil
}
disks, err := storage.zone.region.GetDisks(storage.PrimaryStorageUUID, []string{}, string(storage.Type))
if err != nil {
return nil, err
}
idisks := []cloudprovider.ICloudDisk{}
for i := 0; i < len(disks); i++ {
disks[i].cephStorage = storage
disks[i].region = storage.zone.region
idisks = append(idisks, &disks[i])
}
return idisks, nil
}
func (storage *SCephStorage) GetStorageType() string {
return strings.ToLower(string(storage.Type))
}
func (storage *SCephStorage) GetMediumType() string {
return api.DISK_TYPE_ROTATE
}
func (storage *SCephStorage) GetCapacityMB() int64 {
return storage.TotalCapacity / 1024 / 1024
}
func (storage *SCephStorage) GetStorageConf() jsonutils.JSONObject {
conf := jsonutils.NewDict()
return conf
}
func (storage *SCephStorage) GetManagerId() string {
return storage.zone.region.client.providerID
}
func (storage *SCephStorage) GetStatus() string {
primaryStorage, err := storage.zone.region.GetPrimaryStorage(storage.PrimaryStorageUUID)
if err != nil {
return api.STORAGE_OFFLINE
}
return primaryStorage.GetStatus()
}
func (storage *SCephStorage) Refresh() error {
// do nothing
return nil
}
func (storage *SCephStorage) GetEnabled() bool {
return true
}
func (storage *SCephStorage) GetIStoragecache() cloudprovider.ICloudStoragecache {
storage.zone.region.GetIStoragecaches()
return storage.zone.region.storageCache
}
func (storage *SCephStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) {
if storage.Type == CephPoolTypeData {
disk, err := storage.zone.region.CreateDisk(name, storage.PrimaryStorageUUID, "", storage.PoolName, sizeGb, desc)
if err != nil {
return nil, err
}
disk.cephStorage = storage
return disk, nil
}
return nil, cloudprovider.ErrNotSupported
}
func (storage *SCephStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) {
disks, err := storage.zone.region.GetDisks(storage.PrimaryStorageUUID, []string{diskId}, storage.PoolName)
if err != nil {
return nil, err
}
if len(disks) == 1 {
if disks[0].UUID == diskId {
disks[0].region = storage.zone.region
disks[0].cephStorage = storage
return &disks[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(disks) == 0 || len(diskId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
}
func (storage *SCephStorage) GetMountPoint() string {
return "ceph://" + storage.PoolName
}
func (storage *SCephStorage) IsSysDiskStore() bool {
return storage.Type == CephPoolTypeRoot
}
+34 -32
View File
@@ -5,12 +5,13 @@ import (
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SLocalStorage struct {
zone *SZone
region *SRegion
primaryStorageID string
HostUUID string `json:"hostUuid"`
@@ -48,19 +49,19 @@ func (region *SRegion) GetLocalStorages(storageId string, hostId string) ([]SLoc
return nil, err
}
for i := 0; i < len(localStorage); i++ {
localStorage[i].region = region
localStorage[i].primaryStorageID = storageId
}
return localStorage, nil
}
func (region *SRegion) getILocalStorages(zone *SZone, storageId, hostId string) ([]cloudprovider.ICloudStorage, error) {
func (region *SRegion) getILocalStorages(storageId, hostId string) ([]cloudprovider.ICloudStorage, error) {
storages, err := region.GetLocalStorages(storageId, hostId)
if err != nil {
return nil, err
}
istorage := []cloudprovider.ICloudStorage{}
for i := 0; i < len(storages); i++ {
storages[i].zone = zone
istorage = append(istorage, &storages[i])
}
return istorage, nil
@@ -71,15 +72,15 @@ func (storage *SLocalStorage) GetMetadata() *jsonutils.JSONDict {
}
func (storage *SLocalStorage) GetId() string {
return fmt.Sprintf("%s/%s", storage.primaryStorageID, storage.HostUUID)
return storage.primaryStorageID
}
func (storage *SLocalStorage) GetName() string {
primaryStorage, err := storage.zone.region.GetPrimaryStorage(storage.primaryStorageID)
primaryStorage, err := storage.region.GetStorage(storage.primaryStorageID)
if err != nil {
return "Unknown"
}
host, err := storage.zone.region.GetHost(storage.zone.UUID, storage.HostUUID)
host, err := storage.region.GetHost(storage.HostUUID)
if err != nil {
return "Unknown"
}
@@ -87,7 +88,7 @@ func (storage *SLocalStorage) GetName() string {
}
func (storage *SLocalStorage) GetGlobalId() string {
return storage.GetId()
return fmt.Sprintf("%s/%s", storage.primaryStorageID, storage.HostUUID)
}
func (storage *SLocalStorage) IsEmulated() bool {
@@ -95,11 +96,20 @@ func (storage *SLocalStorage) IsEmulated() bool {
}
func (storage *SLocalStorage) GetIZone() cloudprovider.ICloudZone {
return storage.zone
host, err := storage.region.GetHost(storage.HostUUID)
if err != nil {
log.Errorf("failed get host info %s error: %v", storage.HostUUID, err)
return nil
}
zone, err := storage.region.GetZone(host.ZoneUUID)
if err != nil {
log.Errorf("failed get zone info %s error: %v", host.ZoneUUID, err)
}
return zone
}
func (storage *SLocalStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
tags, err := storage.zone.region.GetSysTags("", "VolumeVO", "", "localStorage::hostUuid::"+storage.HostUUID)
tags, err := storage.region.GetSysTags("", "VolumeVO", "", "localStorage::hostUuid::"+storage.HostUUID)
if err != nil {
return nil, err
}
@@ -107,14 +117,17 @@ func (storage *SLocalStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
for i := 0; i < len(tags); i++ {
diskIds = append(diskIds, tags[i].ResourceUUID)
}
disks, err := storage.zone.region.GetDisks(storage.primaryStorageID, diskIds, "")
idisks := []cloudprovider.ICloudDisk{}
if len(diskIds) == 0 {
return idisks, nil
}
disks, err := storage.region.GetDisks(storage.primaryStorageID, diskIds, "")
if err != nil {
return nil, err
}
idisks := []cloudprovider.ICloudDisk{}
for i := 0; i < len(disks); i++ {
disks[i].localStorage = storage
disks[i].region = storage.zone.region
disks[i].region = storage.region
idisks = append(idisks, &disks[i])
}
return idisks, nil
@@ -137,12 +150,8 @@ func (storage *SLocalStorage) GetStorageConf() jsonutils.JSONObject {
return conf
}
func (storage *SLocalStorage) GetManagerId() string {
return storage.zone.region.client.providerID
}
func (storage *SLocalStorage) GetStatus() string {
primaryStorage, err := storage.zone.region.GetPrimaryStorage(storage.primaryStorageID)
primaryStorage, err := storage.region.GetStorage(storage.primaryStorageID)
if err != nil {
return api.STORAGE_OFFLINE
}
@@ -159,12 +168,12 @@ func (storage *SLocalStorage) GetEnabled() bool {
}
func (storage *SLocalStorage) GetIStoragecache() cloudprovider.ICloudStoragecache {
storage.zone.region.GetIStoragecaches()
return storage.zone.region.storageCache
storage.region.GetIStoragecaches()
return storage.region.storageCache
}
func (storage *SLocalStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) {
disk, err := storage.zone.region.CreateDisk(name, storage.primaryStorageID, storage.HostUUID, "", sizeGb, desc)
disk, err := storage.region.CreateDisk(name, storage.primaryStorageID, storage.HostUUID, "", sizeGb, desc)
if err != nil {
return nil, err
}
@@ -173,23 +182,16 @@ func (storage *SLocalStorage) CreateIDisk(name string, sizeGb int, desc string)
}
func (storage *SLocalStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) {
tags, err := storage.zone.region.GetSysTags("", "VolumeVO", diskId, "localStorage::hostUuid::"+storage.HostUUID)
disk, err := storage.region.GetDisk(diskId)
if err != nil {
return nil, err
}
if len(tags) == 1 {
disk, err := storage.zone.region.GetDisk(diskId)
if err != nil {
return nil, err
}
disk.localStorage = storage
disk.region = storage.zone.region
return disk, nil
}
if len(tags) == 0 || len(diskId) == 0 {
if disk.PrimaryStorageUUID != storage.primaryStorageID {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
disk.localStorage = storage
disk.region = storage.region
return disk, nil
}
func (storage *SLocalStorage) GetMountPoint() string {
-79
View File
@@ -1,79 +0,0 @@
package zstack
import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type TStorageType string
const (
StorageTypeCeph = TStorageType("Ceph")
StorageTypeLocal = TStorageType("LocalStorage")
StorageTypeVCenter = TStorageType("VCenter")
)
type SPrimaryStorage struct {
zone *SZone
ZStackBasic
VCenterUUID string `json:"VCenterUuid"`
Datastore string `json:"datastore"`
ZoneUUID string `json:"zoneUuid"`
URL string `json:"url"`
TotalCapacity int64 `json:"totalCapacity"`
AvailableCapacity int `json:"availableCapacity"`
TotalPhysicalCapacity int `json:"totalPhysicalCapacity"`
AvailablePhysicalCapacity int `json:"availablePhysicalCapacity"`
Type TStorageType `json:"type"`
State string `json:"state"`
Status string `json:"status"`
MountPath string `json:"mountPath"`
AttachedClusterUUIDs []string `json:"attachedClusterUuids"`
Pools []SCephStorage `json:"pools"`
ZStackTime
}
func (region *SRegion) GetPrimaryStorage(storageId string) (*SPrimaryStorage, error) {
storages, err := region.GetPrimaryStorages("", "", storageId)
if err != nil {
return nil, err
}
if len(storages) == 1 {
if storages[0].UUID == storageId {
return &storages[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(storages) == 0 || len(storageId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
}
func (region *SRegion) GetPrimaryStorages(zoneId, clusterId, storageId string) ([]SPrimaryStorage, error) {
storages := []SPrimaryStorage{}
params := []string{}
if len(zoneId) > 0 {
params = append(params, "q=zone.uuid="+zoneId)
}
if len(clusterId) > 0 {
params = append(params, "q=cluster.uuid="+clusterId)
}
if SkipEsxi {
params = append(params, "q=type!=VCenter")
}
if len(storageId) > 0 {
params = append(params, "q=uuid="+storageId)
}
return storages, region.client.listAll("primary-storage", params, &storages)
}
func (storage *SPrimaryStorage) GetStatus() string {
if storage.Status == "Connected" {
return api.STORAGE_ONLINE
}
return api.STORAGE_OFFLINE
}
+46 -6
View File
@@ -3,10 +3,17 @@ package zstack
import (
"context"
"fmt"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/image/options"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/util/qemuimg"
)
type SStoragecache struct {
@@ -41,10 +48,6 @@ func (scache *SStoragecache) IsEmulated() bool {
return false
}
func (scache *SStoragecache) GetManagerId() string {
return scache.region.client.providerID
}
func (scache *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) {
images, err := scache.region.GetImages("")
if err != nil {
@@ -71,8 +74,45 @@ func (scache *SStoragecache) GetPath() string {
return ""
}
func (scache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist, osVersion string, extId string, isForce bool) (string, error) {
return "", cloudprovider.ErrNotImplemented
func (scache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, isForce bool) (string, error) {
if len(image.ExternalId) > 0 {
log.Debugf("UploadImage: Image external ID exists %s", image.ExternalId)
img, err := scache.region.GetImage(image.ExternalId)
if err != nil {
log.Errorf("GetImageStatus error %s", err)
}
status := img.GetStatus()
if api.CACHED_IMAGE_STATUS_READY == status && !isForce {
return image.ExternalId, nil
}
log.Debugf("image %s status %s", image.ExternalId, status)
} else {
log.Debugf("UploadImage: no external ID")
}
return scache.uploadImage(ctx, userCred, image, isForce)
}
func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, isForce bool) (string, error) {
s := auth.GetAdminSession(ctx, options.Options.Region, "")
meta, reader, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false)
if err != nil {
return "", err
}
log.Infof("meta data %s", meta)
size, _ := meta.Int("size")
img, err := self.region.CreateImage(image.ImageName, string(qemuimg.QCOW2), image.OsType, "", reader, size)
if err != nil {
return "", err
}
err = cloudprovider.WaitStatus(img, api.CACHED_IMAGE_STATUS_READY, time.Second*5, time.Minute*5)
if err != nil {
log.Errorf("waitting for image %s(%s) status ready timeout", img.Name, img.UUID)
}
return img.UUID, err
}
func (scache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) {
+70
View File
@@ -0,0 +1,70 @@
package zstack
import (
"fmt"
"yunion.io/x/jsonutils"
)
type SVirtualIP struct {
ZStackBasic
IPRangeUUID string `json:"ipRangeUuid"`
L3NetworkUUID string `json:"l3NetworkUuid"`
IP string `json:"ip"`
State string `json:"state"`
Gateway string `json:"gateway"`
Netmask string `json:"netmask"`
PrefixLen int `json:"prefixLen"`
ServiceProvider string `json:"serviceProvider"`
PeerL3NetworkUuids []string `json:"peerL3NetworkUuids"`
UseFor string `json:"useFor"`
UsedIPUUID string `json:"usedIpUuid"`
ZStackTime
}
func (region *SRegion) GetVirtualIP(vipId string) (*SVirtualIP, error) {
vip := &SVirtualIP{}
return vip, region.client.getResource("vips", vipId, vip)
}
func (region *SRegion) GetNetworkId(vip *SVirtualIP) string {
networks, err := region.GetNetworks("", "", vip.L3NetworkUUID, "")
if err == nil {
for _, network := range networks {
if network.Contains(vip.IP) {
return fmt.Sprintf("%s/%s", vip.L3NetworkUUID, network.UUID)
}
}
}
return ""
}
func (region *SRegion) GetVirtualIPs(vipId string) ([]SVirtualIP, error) {
vips := []SVirtualIP{}
params := []string{}
if len(vipId) > 0 {
params = append(params, "q=uuid="+vipId)
}
return vips, region.client.listAll("vips", params, &vips)
}
func (region *SRegion) CreateVirtualIP(name, desc, ip string, l3Id string) (*SVirtualIP, error) {
vip := SVirtualIP{}
params := map[string]map[string]string{
"params": {
"name": name,
"description": desc,
"requiredIp": ip,
"l3NetworkUuid": l3Id,
},
}
resp, err := region.client.post("vips", jsonutils.Marshal(params))
if err != nil {
return nil, err
}
return &vip, resp.Unmarshal(&vip, "inventory")
}
func (region *SRegion) DeleteVirtualIP(vipId string) error {
return region.client.delete("vips", vipId, "")
}
+1 -5
View File
@@ -24,7 +24,7 @@ func (vpc *SVpc) GetId() string {
}
func (vpc *SVpc) GetName() string {
return DEFAULT_VPC_NAME
return fmt.Sprintf("%s-VPC", vpc.region.client.providerName)
}
func (vpc *SVpc) GetGlobalId() string {
@@ -95,10 +95,6 @@ func (vpc *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
return nil, cloudprovider.ErrNotSupported
}
func (vpc *SVpc) GetManagerId() string {
return vpc.region.client.providerID
}
func (vpc *SVpc) Delete() error {
return nil
}
+19 -16
View File
@@ -1,6 +1,7 @@
package zstack
import (
"fmt"
"strings"
"yunion.io/x/jsonutils"
@@ -22,20 +23,8 @@ type SWire struct {
}
func (region *SRegion) GetWire(wireId string) (*SWire, error) {
wires, err := region.GetWires("", wireId, "")
if err != nil {
return nil, err
}
if len(wires) == 1 {
if wires[0].UUID == wireId {
return &wires[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(wires) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
wire := &SWire{vpc: region.GetVpc()}
return wire, region.client.getResource("l2-networks", wireId, wire)
}
func (region *SRegion) GetWires(zoneId string, wireId string, clusterId string) ([]SWire, error) {
@@ -121,9 +110,23 @@ func (wire *SWire) GetBandwidth() int {
}
func (wire *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
return nil, cloudprovider.ErrNotImplemented
network, err := wire.vpc.region.CreateNetwork(name, cidr, wire.UUID, desc)
if err != nil {
return nil, err
}
network.wire = wire
return network, nil
}
func (wire *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) {
return nil, cloudprovider.ErrNotImplemented
idInfo := strings.Split(netid, "/")
if len(idInfo) == 2 {
network, err := wire.vpc.region.GetNetwork(wire.ZoneUUID, wire.UUID, idInfo[0], idInfo[1])
if err != nil {
return nil, err
}
network.wire = wire
return network, nil
}
return nil, fmt.Errorf("invalid netid %s", netid)
}
+4 -33
View File
@@ -85,43 +85,14 @@ func (zone *SZone) GetIStorageById(storageId string) (cloudprovider.ICloudStorag
return nil, cloudprovider.ErrNotFound
}
func (region *SRegion) GetHosts(zoneId string, hostId string) ([]SHost, error) {
hosts := []SHost{}
params := []string{}
if len(zoneId) > 0 {
params = append(params, "q=zone.uuid="+zoneId)
}
if len(hostId) > 0 {
params = append(params, "q=uuid="+hostId)
}
if SkipEsxi {
params = append(params, "q=hypervisorType!=ESX")
}
return hosts, region.client.listAll("hosts", params, &hosts)
}
func (region *SRegion) GetHost(zoneId string, hostId string) (*SHost, error) {
hosts, err := region.GetHosts(zoneId, hostId)
if err != nil {
return nil, err
}
if len(hosts) == 1 {
if hosts[0].UUID == hostId {
return &hosts[0], nil
}
return nil, cloudprovider.ErrNotFound
}
if len(hosts) == 0 || len(hostId) == 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, cloudprovider.ErrDuplicateId
}
func (zone *SZone) GetIHostById(hostId string) (cloudprovider.ICloudHost, error) {
host, err := zone.region.GetHost(zone.UUID, hostId)
host, err := zone.region.GetHost(hostId)
if err != nil {
return nil, err
}
if host.ZoneUUID != zone.UUID {
return nil, cloudprovider.ErrNotFound
}
host.zone = zone
return host, nil
}
+49 -1
View File
@@ -141,6 +141,9 @@ func (cli *SZStackClient) _list(resource string, start int, limit int, params []
}
func (cli *SZStackClient) getDeleteURL(resource, resourceId, deleteMode string) string {
if len(resourceId) == 0 {
return cli.authURL + fmt.Sprintf("/zstack/%s/%s", ZSTACK_API_VERSION, resource)
}
url := cli.authURL + fmt.Sprintf("/zstack/%s/%s/%s", ZSTACK_API_VERSION, resource, resourceId)
if len(deleteMode) > 0 {
url += "?deleteMode=" + deleteMode
@@ -171,6 +174,12 @@ func (cli *SZStackClient) _delete(resource, resourceId, deleteMode string) (json
}
func (cli *SZStackClient) getURL(resource, resourceId, spec string) string {
if len(resourceId) == 0 {
return cli.authURL + fmt.Sprintf("/zstack/%s/%s", ZSTACK_API_VERSION, resource)
}
if len(spec) == 0 {
return cli.authURL + fmt.Sprintf("/zstack/%s/%s/%s", ZSTACK_API_VERSION, resource, resourceId)
}
return cli.authURL + fmt.Sprintf("/zstack/%s/%s/%s/%s", ZSTACK_API_VERSION, resource, resourceId, spec)
}
@@ -199,6 +208,27 @@ func (cli *SZStackClient) _put(resource, resourceId string, params jsonutils.JSO
return resp, nil
}
func (cli *SZStackClient) getResource(resource, resourceId string, retval interface{}) error {
if len(resourceId) == 0 {
return cloudprovider.ErrNotFound
}
resp, err := cli._get(resource, resourceId, "")
if err != nil {
return err
}
inventories, err := resp.GetArray("inventories")
if err != nil {
return err
}
if len(inventories) == 1 {
return inventories[0].Unmarshal(retval)
}
if len(inventories) == 0 {
return cloudprovider.ErrNotFound
}
return cloudprovider.ErrDuplicateId
}
func (cli *SZStackClient) get(resource, resourceId string, spec string) (jsonutils.JSONObject, error) {
return cli._get(resource, resourceId, spec)
}
@@ -210,7 +240,25 @@ func (cli *SZStackClient) _get(resource, resourceId string, spec string) (jsonut
header.Add("Authorization", "OAuth "+cli.sessionID)
requestURL := cli.getURL(resource, resourceId, spec)
_, resp, err := httputils.JSONRequest(client, context.Background(), "GET", requestURL, header, nil, cli.debug)
return resp, err
if err != nil {
return nil, err
}
if resp.Contains("location") {
location, _ := resp.GetString("location")
return cli.wait(client, header, "get", requestURL, jsonutils.NewDict(), location)
}
return resp, nil
}
func (cli *SZStackClient) create(resource string, params jsonutils.JSONObject, retval interface{}) error {
resp, err := cli._post(resource, params)
if err != nil {
return err
}
if retval == nil {
return nil
}
return resp.Unmarshal(retval, "inventory")
}
func (cli *SZStackClient) post(resource string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
-4
View File
@@ -12,7 +12,3 @@ type ZStackBasic struct {
Name string `json:"name"`
Description string `json:"description"`
}
const (
DEFAULT_VPC_NAME = "ZStackVPC"
)
+2 -1
View File
@@ -31,6 +31,7 @@ const (
SPICE = "spice"
WMKS = "wmks"
VMRC = "vmrc"
ZSTACK = "zstack"
)
type RemoteConsoleInfo struct {
@@ -108,7 +109,7 @@ func (info *RemoteConsoleInfo) GetConnectParams() (string, error) {
return info.getAliyunURL()
case QCLOUD:
return info.getQcloudURL()
case OPENSTACK, VMRC:
case OPENSTACK, VMRC, ZSTACK:
return info.Url, nil
default:
return "", fmt.Errorf("Can't convert protocol %s to connect params", info.Protocol)