Merge pull request #3847 from ioito/feature/qx-google

add: gcp cloud support
This commit is contained in:
yunion-ci-robot
2019-11-27 12:04:28 +08:00
committed by GitHub
103 changed files with 7676 additions and 34 deletions
+24
View File
@@ -16,6 +16,7 @@ package shell
import (
"fmt"
"io/ioutil"
"yunion.io/x/jsonutils"
@@ -117,6 +118,29 @@ func init() {
return nil
})
R(&options.SGoogleCloudAccountCreateOptions{}, "cloud-account-create-google", "Create a Google cloud account", func(s *mcclient.ClientSession, args *options.SGoogleCloudAccountCreateOptions) error {
params := jsonutils.Marshal(args)
params.(*jsonutils.JSONDict).Add(jsonutils.NewString("Google"), "provider")
data, err := ioutil.ReadFile(args.GoogleJsonFile)
if err != nil {
return err
}
authParams, err := jsonutils.Parse(data)
if err != nil {
return err
}
err = jsonutils.Update(params, authParams)
if err != nil {
return err
}
result, err := modules.Cloudaccounts.Create(s, params)
if err != nil {
return err
}
printObject(result)
return nil
})
R(&options.SAWSCloudAccountCreateOptions{}, "cloud-account-create-aws", "Create an AWS cloud account", func(s *mcclient.ClientSession, args *options.SAWSCloudAccountCreateOptions) error {
params := jsonutils.Marshal(args).(*jsonutils.JSONDict)
options := jsonutils.NewDict()
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
func init() {
type GlobalNetworkListOptions struct {
options.BaseListOptions
}
R(&GlobalNetworkListOptions{}, "global-network-list", "List global networks", func(s *mcclient.ClientSession, args *GlobalNetworkListOptions) error {
params, err := options.ListStructToParams(args)
if err != nil {
return err
}
result, err := modules.GlobalNetworks.List(s, params)
if err != nil {
return err
}
printList(result, modules.GlobalNetworks.GetColumns(s))
return nil
})
type GlobalNetworkShowOptions struct {
ID string `help:"ID or Name of globalnetwork"`
}
R(&GlobalNetworkShowOptions{}, "global-network-show", "Show details of a global network", func(s *mcclient.ClientSession, args *GlobalNetworkShowOptions) error {
result, err := modules.GlobalNetworks.GetById(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
}
+147
View File
@@ -0,0 +1,147 @@
// 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 main
import (
"fmt"
"os"
"yunion.io/x/log"
"yunion.io/x/structarg"
"yunion.io/x/onecloud/pkg/multicloud/google"
_ "yunion.io/x/onecloud/pkg/multicloud/google/shell"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
type BaseOptions struct {
Debug bool `help:"debug mode"`
Help bool `help:"Show help"`
ClientEmail string `help:"Client email" default:"$GOOGLE_CLIENT_EMAIL"`
ProjectID string `help:"Project ID" default:"$GOOGLE_PROJECT_ID"`
PrivateKeyID string `help:"Private Key ID" default:"$GOOGLE_PRIVATE_KEY_ID"`
PrivateKey string `help:"Private Key" default:"$GOOGLE_PRIVATE_KEY"`
RegionID string `help:"RegionID" default:"$GOOGLE_REGION"`
SUBCOMMAND string `help:"googlecli subcommand" subcommand:"true"`
}
func getSubcommandParser() (*structarg.ArgumentParser, error) {
parse, e := structarg.NewArgumentParser(&BaseOptions{},
"googlecli",
"Command-line interface to google API.",
`See "googlecli help COMMAND" for help on a specific command.`)
if e != nil {
return nil, e
}
subcmd := parse.GetSubcommand()
if subcmd == nil {
return nil, fmt.Errorf("No subcommand argument.")
}
type HelpOptions struct {
SUBCOMMAND string `help:"sub-command name"`
}
shellutils.R(&HelpOptions{}, "help", "Show help of a subcommand", func(args *HelpOptions) error {
helpstr, e := subcmd.SubHelpString(args.SUBCOMMAND)
if e != nil {
return e
} else {
fmt.Print(helpstr)
return nil
}
})
for _, v := range shellutils.CommandTable {
_, e := subcmd.AddSubParser(v.Options, v.Command, v.Desc, v.Callback)
if e != nil {
return nil, e
}
}
return parse, nil
}
func showErrorAndExit(e error) {
log.Errorf("%s", e)
os.Exit(1)
}
func newClient(options *BaseOptions) (*google.SRegion, error) {
if len(options.ClientEmail) == 0 {
return nil, fmt.Errorf("Missing ClientEmail")
}
if len(options.PrivateKeyID) == 0 {
return nil, fmt.Errorf("Missing PrivateKeyID")
}
if len(options.PrivateKey) == 0 {
return nil, fmt.Errorf("Missing PrivateKey")
}
if len(options.ProjectID) == 0 {
return nil, fmt.Errorf("Missing ProjectID")
}
cli, err := google.NewGoogleClient("", "", options.ProjectID, options.ClientEmail, options.PrivateKeyID, options.PrivateKey, options.Debug)
if err != nil {
return nil, err
}
region := cli.GetRegion(options.RegionID)
if region == nil {
return nil, fmt.Errorf("No such region %s", options.RegionID)
}
return region, nil
}
func main() {
parser, e := getSubcommandParser()
if e != nil {
showErrorAndExit(e)
}
e = parser.ParseArgs(os.Args[1:], false)
options := parser.Options().(*BaseOptions)
if options.Help {
fmt.Print(parser.HelpString())
return
}
subcmd := parser.GetSubcommand()
subparser := subcmd.GetSubParser()
if e != nil {
if subparser != nil {
fmt.Print(subparser.Usage())
} else {
fmt.Print(parser.Usage())
}
showErrorAndExit(e)
return
}
suboptions := subparser.Options()
if options.SUBCOMMAND == "help" {
e = subcmd.Invoke(suboptions)
} else {
var region *google.SRegion
region, e = newClient(options)
if e != nil {
showErrorAndExit(e)
}
e = subcmd.Invoke(region, suboptions)
}
if e != nil {
showErrorAndExit(e)
}
}
+1
View File
@@ -115,6 +115,7 @@ require (
go.uber.org/atomic v1.4.0 // indirect
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc
golang.org/x/net v0.0.0-20191007182048-72f939374954
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421
golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/sys v0.0.0-20191008105621-543471e840be
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20191008142428-8d021180e987
+5
View File
@@ -45,6 +45,11 @@ type CloudaccountCredentialInput struct {
AppId string //Qcloud
SecretId string //Qcloud
SecretKey string //Qcloud
ClientEmail string //Google
ProjectId string //Google
PrivateKeyId string //Google
PrivateKey string //Google
}
type CloudaccountCreateInput struct {
+2
View File
@@ -39,6 +39,7 @@ const (
CLOUD_PROVIDER_OPENSTACK = "OpenStack"
CLOUD_PROVIDER_UCLOUD = "Ucloud"
CLOUD_PROVIDER_ZSTACK = "ZStack"
CLOUD_PROVIDER_GOOGLE = "Google"
CLOUD_PROVIDER_GENERICS3 = "S3"
CLOUD_PROVIDER_CEPH = "Ceph"
@@ -82,6 +83,7 @@ var (
CLOUD_PROVIDER_OPENSTACK,
CLOUD_PROVIDER_UCLOUD,
CLOUD_PROVIDER_ZSTACK,
CLOUD_PROVIDER_GOOGLE,
}
)
+27 -14
View File
@@ -31,6 +31,7 @@ const (
CITY_HONG_KONG = "Hongkong" //香港
CITY_NING_XIA = "Ningxia" //宁夏
CITY_GUANG_ZHOU = "Guangzhou" //广州
CITY_TAI_WAN = "Taiwan" //台湾
CITY_GUI_YANG = "Guiyang" //贵阳
CITY_TAIPEI = "Taipei" //台北市
CITY_KAOHSIUNG = "Kaohsiung" //高雄市
@@ -49,6 +50,15 @@ const (
CITY_YARRALUMLA = "Yarralumla" //亚拉伦拉
CITY_MELBOURNE = "Melbourne" //墨尔本
//芬兰
CITY_FINLAND = "Finland"
//比利时
CITY_BELGIUM = "Belgium" //比利时
//瑞士
CITY_ZURICH = "Zurich" //苏黎世
// 马来西亚
CITY_KUALA_LUMPUR = "Kuala Lumpur" //吉隆坡
@@ -61,20 +71,21 @@ const (
CITY_MAHARASHTRA = "Maharashtra" //马哈拉施特拉邦
// 美国
CITY_VIRGINIA = "Virginia" //弗吉尼亚
CITY_SILICONVALLEY = "Siliconvalley" //硅谷
CITY_OHIO = "Ohio" //俄亥俄州
CITY_N_VIRGINIA = "N. Virginia" //北弗吉尼亚
CITY_N_CALIFORNIA = "N. California" //北加州
CITY_OREGON = "Oregon" //俄勒冈州
CITY_LOS_ANGELES = "Los Angeles" //洛杉矶
CITY_SAN_FRANCISCO = "San Francisco" //旧金山
CITY_UTAH = "Utah" //犹他州
CITY_WASHINGTON = "Washington" //华盛顿
CITY_TEXAS = "Texas" //德克萨斯
CITY_CHICAGO = "Chicago" //芝加哥
CITY_IOWA = "Iowa" //爱荷华
CITY_US_GOV_WEST = "us-gov-west" //???
CITY_VIRGINIA = "Virginia" //弗吉尼亚
CITY_SILICONVALLEY = "Siliconvalley" //硅谷
CITY_OHIO = "Ohio" //俄亥俄州
CITY_N_VIRGINIA = "N. Virginia" //北弗吉尼亚
CITY_N_CALIFORNIA = "N. California" //北加州
CITY_OREGON = "Oregon" //俄勒冈州
CITY_LOS_ANGELES = "Los Angeles" //洛杉矶
CITY_SAN_FRANCISCO = "San Francisco" //旧金山
CITY_UTAH = "Utah" //犹他州
CITY_WASHINGTON = "Washington" //华盛顿
CITY_TEXAS = "Texas" //德克萨斯
CITY_CHICAGO = "Chicago" //芝加哥
CITY_IOWA = "Iowa" //爱荷华
CITY_US_GOV_WEST = "us-gov-west" //???
CITY_SOUTH_CAROLINA = "South Carolina" //南卡罗来纳州
// 英国
CITY_LONDON = "London" //伦敦
@@ -95,6 +106,7 @@ const (
CITY_CANADA_CENTRAL = "Canada Central" //加拿大中部
CITY_QUEBEC = "Quebec" //魁北克市
CITY_TORONTO = "Toronto" //多伦多
CITY_MONTREAL = "Montreal" //蒙特利尔
// 爱尔兰
CITY_IRELAND = "Ireland" //爱尔兰
@@ -154,4 +166,5 @@ const (
COUNTRY_CODE_RU = "RU" //俄罗斯
COUNTRY_CODE_NG = "NG" //尼日利亚
COUNTRY_CODE_VN = "VN" //越南
COUNTRY_CODE_CH = "CH" //瑞士
)
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package compute
const (
GLOBAL_NETWORK_STATUS_AVAILABLE = "available"
GLOBAL_NETWORK_STATUS_UNKNOWN = "unknown"
)
+5
View File
@@ -140,6 +140,7 @@ const (
HYPERVISOR_OPENSTACK = "openstack"
HYPERVISOR_UCLOUD = "ucloud"
HYPERVISOR_ZSTACK = "zstack"
HYPERVISOR_GOOGLE = "google"
// HYPERVISOR_DEFAULT = HYPERVISOR_KVM
HYPERVISOR_DEFAULT = HYPERVISOR_KVM
@@ -161,6 +162,7 @@ var HYPERVISORS = []string{
HYPERVISOR_OPENSTACK,
HYPERVISOR_UCLOUD,
HYPERVISOR_ZSTACK,
HYPERVISOR_GOOGLE,
}
var ONECLOUD_HYPERVISORS = []string{
@@ -176,6 +178,7 @@ var PUBLIC_CLOUD_HYPERVISORS = []string{
HYPERVISOR_QCLOUD,
HYPERVISOR_HUAWEI,
HYPERVISOR_UCLOUD,
HYPERVISOR_GOOGLE,
}
var PRIVATE_CLOUD_HYPERVISORS = []string{
@@ -198,6 +201,7 @@ var HYPERVISOR_HOSTTYPE = map[string]string{
HYPERVISOR_OPENSTACK: HOST_TYPE_OPENSTACK,
HYPERVISOR_UCLOUD: HOST_TYPE_UCLOUD,
HYPERVISOR_ZSTACK: HOST_TYPE_ZSTACK,
HYPERVISOR_GOOGLE: HOST_TYPE_GOOGLE,
}
var HOSTTYPE_HYPERVISOR = map[string]string{
@@ -213,6 +217,7 @@ var HOSTTYPE_HYPERVISOR = map[string]string{
HOST_TYPE_OPENSTACK: HYPERVISOR_OPENSTACK,
HOST_TYPE_UCLOUD: HYPERVISOR_UCLOUD,
HOST_TYPE_ZSTACK: HYPERVISOR_ZSTACK,
HOST_TYPE_GOOGLE: HYPERVISOR_GOOGLE,
}
const (
+1
View File
@@ -31,6 +31,7 @@ const (
HOST_TYPE_OPENSTACK = "openstack"
HOST_TYPE_UCLOUD = "ucloud"
HOST_TYPE_ZSTACK = "zstack"
HOST_TYPE_GOOGLE = "google"
HOST_TYPE_DEFAULT = HOST_TYPE_HYPERVISOR
+1
View File
@@ -56,6 +56,7 @@ var (
REGIONAL_NETWORK_PROVIDERS = []string{
CLOUD_PROVIDER_HUAWEI,
CLOUD_PROVIDER_UCLOUD,
CLOUD_PROVIDER_GOOGLE,
}
)
+5
View File
@@ -70,6 +70,11 @@ const (
// Zstack storage type
STORAGE_ZSTACK_LOCAL_STORAGE = "localstorage"
STORAGE_ZSTACK_CEPH = "ceph"
// Google storage type
STORAGE_GOOGLE_LOCAL_STORAGE = "local-storage" //本地SSD暂存盘 (最多8个)
STORAGE_GOOGLE_PD_STANDARD = "pd-standard" //标准永久性磁盘
STORAGE_GOOGLE_PD_SSD = "pd-ssd" //SSD永久性磁盘
)
const (
+3
View File
@@ -73,6 +73,9 @@ type ICloudProvider interface {
GetIProjects() ([]ICloudProject, error)
GetIRegionById(id string) (ICloudRegion, error)
GetIGlobalnetworks() ([]ICloudGlobalnetwork, error)
GetIGlobalnetworkById(id string) (ICloudGlobalnetwork, error)
GetOnPremiseIRegion() (ICloudRegion, error)
GetBalance() (float64, string, error)
+5
View File
@@ -427,6 +427,7 @@ type ICloudVpc interface {
GetIWireById(wireId string) (ICloudWire, error)
GetINatGateways() ([]ICloudNatGateway, error)
GetIGlobalNetworkId() string
}
type ICloudWire interface {
@@ -930,3 +931,7 @@ type ICloudEvent interface {
GetCreatedAt() time.Time
}
type ICloudGlobalnetwork interface {
ICloudResource
}
+52
View File
@@ -0,0 +1,52 @@
// 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 guestdrivers
import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SGoogleGuestDriver struct {
SManagedVirtualizedGuestDriver
}
func init() {
driver := SGoogleGuestDriver{}
models.RegisterGuestDriver(&driver)
}
func (self *SGoogleGuestDriver) GetQuotaPlatformID() []string {
return []string{
api.CLOUD_ENV_PUBLIC_CLOUD,
api.CLOUD_PROVIDER_GOOGLE,
}
}
func (self *SGoogleGuestDriver) GetHypervisor() string {
return api.HYPERVISOR_GOOGLE
}
func (self *SGoogleGuestDriver) GetProvider() string {
return api.CLOUD_PROVIDER_GOOGLE
}
func (self *SGoogleGuestDriver) GetDefaultSysDiskBackend() string {
return api.STORAGE_GOOGLE_PD_STANDARD
}
func (self *SGoogleGuestDriver) GetMinimalSysDiskSizeGb() int {
return 10
}
+8 -2
View File
@@ -301,7 +301,10 @@ func (self *SManagedVirtualizedGuestDriver) RequestDeployGuestOnHost(ctx context
return errors.Wrap(err, "vpc.GetRegion")
}
vpcId := region.GetDriver().GetSecurityGroupVpcId(ctx, task.GetUserCred(), region, host, vpc, false)
vpcId, err := region.GetDriver().GetSecurityGroupVpcId(ctx, task.GetUserCred(), region, host, vpc, false)
if err != nil {
return errors.Wrap(err, "GetSecurityGroupVpcId")
}
secgroups := guest.GetSecgroups()
for i, secgroup := range secgroups {
@@ -912,7 +915,10 @@ func (self *SManagedVirtualizedGuestDriver) RequestSyncSecgroupsOnHost(ctx conte
region := host.GetRegion()
vpcId := region.GetDriver().GetSecurityGroupVpcId(ctx, task.GetUserCred(), region, host, vpc, false)
vpcId, err := region.GetDriver().GetSecurityGroupVpcId(ctx, task.GetUserCred(), region, host, vpc, false)
if err != nil {
return errors.Wrap(err, "GetSecurityGroupVpcId")
}
secgroups := guest.GetSecgroups()
externalIds := []string{}
+37
View File
@@ -0,0 +1,37 @@
// 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 hostdrivers
import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SGoogleHostDriver struct {
SManagedVirtualizationHostDriver
}
func init() {
driver := SGoogleHostDriver{}
models.RegisterHostDriver(&driver)
}
func (self *SGoogleHostDriver) GetHostType() string {
return api.HOST_TYPE_GOOGLE
}
func (self *SGoogleHostDriver) GetHypervisor() string {
return api.HYPERVISOR_GOOGLE
}
+5 -1
View File
@@ -81,7 +81,7 @@ type SCloudaccount struct {
AccessUrl string `width:"64" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
Account string `width:"128" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"` // Column(VARCHAR(64, charset='ascii'), nullable=False)
Secret string `width:"256" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"` // Column(VARCHAR(256, charset='ascii'), nullable=False)
Secret string `length:"0" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"` // Google需要秘钥认证,需要此字段比较长
// BalanceKey string `width:"256" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
@@ -1440,6 +1440,10 @@ func (account *SCloudaccount) syncAccountStatus(ctx context.Context, userCred mc
log.Errorf("syncCloudproviderRegion fail %s", err)
return err
}
err = providers[i].syncCloudproviderGlobalnetworks(ctx, userCred)
if err != nil {
log.Errorf("failed to sync cloudprovider globalnetwork for %s %s error: %v", providers[i].Provider, providers[i].Name, err)
}
}
}
return nil
+7 -3
View File
@@ -356,9 +356,10 @@ func (self *SCloudproviderregion) DoSync(ctx context.Context, userCred mcclient.
if localRegion.isManaged() {
remoteRegion, err := driver.GetIRegionById(localRegion.ExternalId)
if err == nil {
err = syncPublicCloudProviderInfo(ctx, userCred, syncResults, provider, driver, localRegion, remoteRegion, &syncRange)
if err != nil {
return errors.Wrap(err, "GetIRegionById")
}
err = syncPublicCloudProviderInfo(ctx, userCred, syncResults, provider, driver, localRegion, remoteRegion, &syncRange)
} else {
err = syncOnPremiseCloudProviderInfo(ctx, userCred, syncResults, provider, driver, &syncRange)
}
@@ -384,7 +385,10 @@ func (self *SCloudproviderregion) getSyncTaskKey() string {
func (self *SCloudproviderregion) submitSyncTask(userCred mcclient.TokenCredential, syncRange SSyncRange, waitChan chan bool) {
self.markStartSync(userCred)
RunSyncCloudproviderRegionTask(self.getSyncTaskKey(), func() {
self.DoSync(context.Background(), userCred, syncRange)
err := self.DoSync(context.Background(), userCred, syncRange)
if err != nil {
log.Errorf("DoSync faild %v", err)
}
if waitChan != nil {
waitChan <- true
}
+21 -1
View File
@@ -77,7 +77,7 @@ type SCloudprovider struct {
AccessUrl string `width:"64" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
Account string `width:"128" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"` // Column(VARCHAR(64, charset='ascii'), nullable=False)
Secret string `width:"256" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"` // Column(VARCHAR(256, charset='ascii'), nullable=False)
Secret string `length:"0" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"` // Google需要秘钥认证,需要此字段比较长
CloudaccountId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"`
@@ -1085,6 +1085,25 @@ func (provider *SCloudprovider) markProviderConnected(ctx context.Context, userC
return provider.ClearSchedDescCache()
}
func (provider *SCloudprovider) syncCloudproviderGlobalnetworks(ctx context.Context, userCred mcclient.TokenCredential) error {
driver, err := provider.GetProvider()
if err != nil {
return err
}
if !driver.GetFactory().IsOnPremise() {
globalnetworks, err := driver.GetIGlobalnetworks()
if err != nil {
return errors.Wrap(err, "GetIGlobalnetworks")
}
result := GlobalNetworkManager.SyncGlobalnetworks(ctx, userCred, provider, globalnetworks)
if result.IsError() {
log.Errorf("syncGlobalnetworks fail %s", result.Result())
}
return nil
}
return nil
}
func (provider *SCloudprovider) prepareCloudproviderRegions(ctx context.Context, userCred mcclient.TokenCredential) ([]SCloudproviderregion, error) {
driver, err := provider.GetProvider()
if err != nil {
@@ -1181,6 +1200,7 @@ func (self *SCloudprovider) RealDelete(ctx context.Context, userCred mcclient.To
DBInstanceBackupManager,
ElasticcacheManager,
VpcManager,
GlobalNetworkManager,
ElasticipManager,
NetworkInterfaceManager,
CloudproviderRegionManager,
+233
View File
@@ -0,0 +1,233 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package models
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SGlobalNetworkManager struct {
db.SEnabledStatusStandaloneResourceBaseManager
}
var GlobalNetworkManager *SGlobalNetworkManager
func init() {
GlobalNetworkManager = &SGlobalNetworkManager{
SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
SGlobalNetwork{},
"globalnetworks_tbl",
"globalnetwork",
"globalnetworks",
),
}
GlobalNetworkManager.SetVirtualObject(GlobalNetworkManager)
}
type SGlobalNetwork struct {
db.SEnabledStatusStandaloneResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
Provider string `width:"64" charset:"ascii" list:"user"`
}
func (manager *SGlobalNetworkManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
//current not support create
return false
}
func (self *SGlobalNetwork) ValidateDeleteCondition(ctx context.Context) error {
return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx)
}
func (self *SGlobalNetwork) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
return self.SEnabledStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query)
}
func (self *SGlobalNetwork) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
return self.SEnabledStatusStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query)
}
func (manager *SGlobalNetworkManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data)
}
func (self *SGlobalNetwork) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return self.SEnabledStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data)
}
func (self *SGlobalNetwork) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
log.Infof("SGlobalNetwork delete do nothing")
self.SetStatus(userCred, api.NETWORK_STATUS_START_DELETE, "")
return nil
}
func (self *SGlobalNetwork) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
if len(self.ExternalId) > 0 {
return self.StartDeleteGlobalNetworkTask(ctx, userCred)
}
return self.RealDelete(ctx, userCred)
}
func (self *SGlobalNetwork) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
db.OpsLog.LogEvent(self, db.ACT_DELOCATE, self.GetShortDesc(ctx), userCred)
self.SetStatus(userCred, api.NETWORK_STATUS_DELETED, "real delete")
return self.SEnabledStatusStandaloneResourceBase.Delete(ctx, userCred)
}
func (self *SGlobalNetwork) StartDeleteGlobalNetworkTask(ctx context.Context, userCred mcclient.TokenCredential) error {
task, err := taskman.TaskManager.NewTask(ctx, "GlobalNetworkDeleteTask", self, userCred, nil, "", "", nil)
if err != nil {
return errors.Wrapf(err, "NewTask")
}
task.ScheduleRun(nil)
return nil
}
func (manager *SGlobalNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
return manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
}
func (self *SGlobalNetwork) ValidateUpdateCondition(ctx context.Context) error {
return self.SEnabledStatusStandaloneResourceBase.ValidateUpdateCondition(ctx)
}
func (manager *SGlobalNetworkManager) GetGlobalNetworksByManagerId(id string) ([]SGlobalNetwork, error) {
q := manager.Query().Equals("manager_id", id)
q = q.Filter(sqlchemy.NOT(sqlchemy.IsNullOrEmpty(q.Field("external_id"))))
globalnetworks := []SGlobalNetwork{}
err := db.FetchModelObjects(manager, q, &globalnetworks)
if err != nil {
return nil, err
}
return globalnetworks, nil
}
func (self *SGlobalNetwork) GetGlobalNetworkVpcs() ([]SGlobalnetworkVpc, error) {
gnvs := []SGlobalnetworkVpc{}
q := GlobalnetworkVpcManager.Query().Equals("globalnetwork_id", self.Id)
err := db.FetchModelObjects(GlobalnetworkVpcManager, q, &gnvs)
if err != nil {
return nil, err
}
return gnvs, nil
}
func (manager *SGlobalNetworkManager) SyncGlobalnetworks(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, exts []cloudprovider.ICloudGlobalnetwork) compare.SyncResult {
lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred))
defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred))
result := compare.SyncResult{}
dbNetworks, err := manager.GetGlobalNetworksByManagerId(provider.Id)
if err != nil {
result.Error(err)
return result
}
removed := make([]SGlobalNetwork, 0)
commondb := make([]SGlobalNetwork, 0)
commonext := make([]cloudprovider.ICloudGlobalnetwork, 0)
added := make([]cloudprovider.ICloudGlobalnetwork, 0)
err = compare.CompareSets(dbNetworks, exts, &removed, &commondb, &commonext, &added)
if err != nil {
result.Error(errors.Wrap(err, "CompareSets"))
return result
}
for i := 0; i < len(removed); i += 1 {
err = removed[i].syncRemoveGlobalnetwork(ctx, userCred)
if err != nil {
result.DeleteError(err)
continue
}
result.Delete()
}
for i := 0; i < len(commondb); i += 1 {
// update
err = commondb[i].syncWithCloudGlobalnetwork(ctx, userCred, provider, commonext[i])
if err != nil {
result.UpdateError(err)
continue
}
result.Update()
}
for i := 0; i < len(added); i += 1 {
err := manager.newFromCloudGlobalnetwork(ctx, userCred, provider, added[i])
if err != nil {
result.AddError(err)
continue
}
result.Add()
}
return result
}
func (self *SGlobalNetwork) syncWithCloudGlobalnetwork(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudGlobalnetwork) error {
diff, err := db.UpdateWithLock(ctx, self, func() error {
self.Status = ext.GetStatus()
return nil
})
if err != nil {
return errors.Wrap(err, "UpdateWithLock")
}
db.OpsLog.LogSyncUpdate(self, diff, userCred)
return nil
}
func (self *SGlobalNetwork) syncRemoveGlobalnetwork(ctx context.Context, userCred mcclient.TokenCredential) error {
err := self.ValidateDeleteCondition(ctx)
if err != nil {
return err
}
return self.RealDelete(ctx, userCred)
}
func (manager *SGlobalNetworkManager) newFromCloudGlobalnetwork(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudGlobalnetwork) error {
network := SGlobalNetwork{}
network.SetModelManager(manager, &network)
newName, err := db.GenerateName(manager, nil, ext.GetName())
if err != nil {
return errors.Wrap(err, "GenerateName")
}
network.ExternalId = ext.GetGlobalId()
network.Name = newName
network.Status = ext.GetStatus()
network.Enabled = true
network.ManagerId = provider.Id
network.Provider = provider.Provider
err = manager.TableSpec().Insert(&network)
if err != nil {
return errors.Wrap(err, "Insert")
}
db.OpsLog.LogEvent(&network, db.ACT_CREATE, network.GetShortDesc(ctx), userCred)
return nil
}
+130
View File
@@ -0,0 +1,130 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package models
import (
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SGlobalnetworkVpcManager struct {
db.SJointResourceBaseManager
}
var GlobalnetworkVpcManager *SGlobalnetworkVpcManager
func init() {
db.InitManager(func() {
GlobalnetworkVpcManager = &SGlobalnetworkVpcManager{
SJointResourceBaseManager: db.NewJointResourceBaseManager(
SGlobalnetworkVpc{},
"globalnetworkvpcs_tbl",
"globalnetworkvpc",
"globalnetworkvpcs",
GlobalNetworkManager,
VpcManager,
),
}
GlobalnetworkVpcManager.SetVirtualObject(GlobalnetworkVpcManager)
})
}
type SGlobalnetworkVpc struct {
db.SJointResourceBase
GlobalnetworkId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
}
func (manager *SGlobalnetworkVpcManager) GetMasterFieldName() string {
return "globalnetwork_id"
}
func (manager *SGlobalnetworkVpcManager) GetSlaveFieldName() string {
return "vpc_id"
}
func (joint *SGlobalnetworkVpc) Master() db.IStandaloneModel {
return db.JointMaster(joint)
}
func (joint *SGlobalnetworkVpc) Slave() db.IStandaloneModel {
return db.JointSlave(joint)
}
func (manager *SGlobalnetworkVpcManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsAdminAllowList(userCred, manager)
}
func (manager *SGlobalnetworkVpcManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowCreate(userCred, manager)
}
func (manager *SGlobalnetworkVpcManager) AllowListDescendent(ctx context.Context, userCred mcclient.TokenCredential, model db.IStandaloneModel, query jsonutils.JSONObject) bool {
return db.IsAdminAllowList(userCred, manager)
}
func (manager *SGlobalnetworkVpcManager) AllowAttach(ctx context.Context, userCred mcclient.TokenCredential, master db.IStandaloneModel, slave db.IStandaloneModel) bool {
return db.IsAdminAllowCreate(userCred, manager)
}
func (self *SGlobalnetworkVpc) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsAdminAllowGet(userCred, self)
}
func (self *SGlobalnetworkVpc) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
return db.IsAdminAllowUpdate(userCred, self)
}
func (self *SGlobalnetworkVpc) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return db.IsAdminAllowDelete(userCred, self)
}
func (self *SGlobalnetworkVpc) Detach(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DetachJoint(ctx, userCred, self)
}
func (self *SGlobalnetworkVpc) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
return self.SJointResourceBase.GetCustomizeColumns(ctx, userCred, query)
}
func (self *SGlobalnetworkVpc) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
return self.SJointResourceBase.GetExtraDetails(ctx, userCred, query)
}
func (manager *SGlobalnetworkVpcManager) NewGlobalnetworkVpc(vpc *SVpc, globalnetwork *SGlobalNetwork) error {
q := manager.Query().Equals("vpc_id", vpc.Id).Equals("globalnetwork_id", globalnetwork.Id)
count, err := q.CountWithError()
if err != nil {
return errors.Wrap(err, "CountWithError")
}
if count > 1 {
return sqlchemy.ErrDuplicateEntry
}
if count == 1 {
return nil
}
gv := &SGlobalnetworkVpc{}
gv.SetModelManager(manager, gv)
gv.VpcId = vpc.Id
gv.GlobalnetworkId = globalnetwork.Id
return manager.TableSpec().Insert(gv)
}
+53
View File
@@ -1620,3 +1620,56 @@ func (manager *SSecurityGroupCacheManager) purgeAll(ctx context.Context, userCre
}
return nil
}
func (gnv *SGlobalnetworkVpc) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, gnv)
defer lockman.ReleaseObject(ctx, gnv)
return gnv.Delete(ctx, userCred)
}
func (gn *SGlobalNetwork) purgeGlobalNetworkVpcs(ctx context.Context, userCred mcclient.TokenCredential) error {
globalnetworkVpcs, err := gn.GetGlobalNetworkVpcs()
if err != nil {
return errors.Wrap(err, "gn.GetGlobalNetworkVpcs")
}
for i := range globalnetworkVpcs {
err = globalnetworkVpcs[i].purge(ctx, userCred)
if err != nil {
return errors.Wrap(err, "globalnetworkVpcs[i].purge")
}
}
return nil
}
func (gn *SGlobalNetwork) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, gn)
defer lockman.ReleaseObject(ctx, gn)
err := gn.purgeGlobalNetworkVpcs(ctx, userCred)
if err != nil {
return errors.Wrap(err, "gn.purgeGlobalNetworkVpcs")
}
err = gn.ValidateDeleteCondition(ctx)
if err != nil {
return errors.Wrapf(err, "globalnetwork %s(%s)", gn.Name, gn.Id)
}
return gn.RealDelete(ctx, userCred)
}
func (manager *SGlobalNetworkManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
globalnetworks := []SGlobalNetwork{}
err := fetchByManagerId(manager, providerId, &globalnetworks)
if err != nil {
return err
}
for i := range globalnetworks {
err := globalnetworks[i].purge(ctx, userCred)
if err != nil {
return err
}
}
return nil
}
+2 -1
View File
@@ -117,8 +117,9 @@ type IRegionDriver interface {
RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *SVpc, secgroup *SSecurityGroup) (string, error)
IsSupportClassicSecurityGroup() bool
IsSecurityGroupBelongVpc() bool
IsSecurityGroupBelongGlobalNetwork() bool //安全组子账号范围内可用
GetDefaultSecurityGroupVpcId() string
GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, host *SHost, vpc *SVpc, classic bool) string
GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *SCloudregion, host *SHost, vpc *SVpc, classic bool) (string, error)
ValidateCreateDBInstanceData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input *api.SDBInstanceCreateInput, skus []SDBInstanceSku, network *SNetwork) (*api.SDBInstanceCreateInput, error)
ValidateCreateDBInstanceAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *SDBInstance, input *api.SDBInstanceAccountCreateInput) (*api.SDBInstanceAccountCreateInput, error)
+13 -2
View File
@@ -223,10 +223,21 @@ func (manager *SSecurityGroupCacheManager) SyncSecurityGroupCaches(ctx context.C
}
vpcId := ""
if region.GetDriver().IsSecurityGroupBelongVpc() {
if region.GetDriver().IsSecurityGroupBelongGlobalNetwork() { //globalnetwork没有region属性
vpcId, err = region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, false)
if err != nil {
syncResult.Error(errors.Wrap(err, "GetSecurityGroupVpcId"))
return localSecgroups, remoteSecgroups, syncResult
}
region = nil
} else if region.GetDriver().IsSecurityGroupBelongVpc() {
vpcId = vpc.ExternalId
} else if region.GetDriver().IsSupportClassicSecurityGroup() && len(secgroups) > 0 {
vpcId = region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, secgroups[0].GetVpcId() == "classic")
vpcId, err = region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, secgroups[0].GetVpcId() == "classic")
if err != nil {
syncResult.Error(errors.Wrap(err, "GetSecurityGroupVpcId"))
return localSecgroups, remoteSecgroups, syncResult
}
} else {
vpcId = region.GetDriver().GetDefaultSecurityGroupVpcId()
}
+46
View File
@@ -347,6 +347,13 @@ func (manager *SVpcManager) SyncVPCs(ctx context.Context, userCred mcclient.Toke
remoteVPCs = append(remoteVPCs, commonext[i])
syncResult.Update()
}
globalnetworkId := commonext[i].GetIGlobalNetworkId()
if len(globalnetworkId) > 0 {
err := commondb[i].checkAndSetGlobalNetwork(globalnetworkId)
if err != nil {
log.Errorf("failed to set globalnetwork for %s error: %v", globalnetworkId, err)
}
}
}
for i := 0; i < len(added); i += 1 {
new, err := manager.newFromCloudVpc(ctx, userCred, added[i], provider, region)
@@ -358,6 +365,13 @@ func (manager *SVpcManager) SyncVPCs(ctx context.Context, userCred mcclient.Toke
remoteVPCs = append(remoteVPCs, added[i])
syncResult.Add()
}
globalnetworkId := added[i].GetIGlobalNetworkId()
if len(globalnetworkId) > 0 {
err := new.checkAndSetGlobalNetwork(globalnetworkId)
if err != nil {
log.Errorf("failed to set globalnetwork for %s error: %v", globalnetworkId, err)
}
}
}
return localVPCs, remoteVPCs, syncResult
@@ -400,6 +414,14 @@ func (self *SVpc) SyncWithCloudVpc(ctx context.Context, userCred mcclient.TokenC
return nil
}
func (vpc *SVpc) checkAndSetGlobalNetwork(globalnetworkId string) error {
globalnetwork, err := db.FetchByExternalId(GlobalNetworkManager, globalnetworkId)
if err != nil {
return errors.Wrap(err, "FetchByExternalId")
}
return GlobalnetworkVpcManager.NewGlobalnetworkVpc(vpc, globalnetwork.(*SGlobalNetwork))
}
func (manager *SVpcManager) newFromCloudVpc(ctx context.Context, userCred mcclient.TokenCredential, extVPC cloudprovider.ICloudVpc, provider *SCloudprovider, region *SCloudregion) (*SVpc, error) {
vpc := SVpc{}
vpc.SetModelManager(manager, &vpc)
@@ -787,3 +809,27 @@ func (vpc *SVpc) StartVpcSyncstatusTask(ctx context.Context, userCred mcclient.T
task.ScheduleRun(nil)
return nil
}
func (vpc *SVpc) GetGlobalNetwork() (*SGlobalNetwork, error) {
gv := GlobalnetworkVpcManager.Query().SubQuery()
q := GlobalNetworkManager.Query()
q.Join(gv, sqlchemy.Equals(q.Field("id"), gv.Field("globalnetwork_id")))
q = q.Filter(sqlchemy.Equals(gv.Field("vpc_id"), vpc.Id))
count, err := q.CountWithError()
if err != nil {
return nil, errors.Wrap(err, "CountWithError")
}
if count > 1 {
return nil, sqlchemy.ErrDuplicateEntry
}
if count == 0 {
return nil, sql.ErrNoRows
}
globalnetwork := &SGlobalNetwork{}
globalnetwork.SetModelManager(GlobalNetworkManager, globalnetwork)
err = q.First(globalnetwork)
if err != nil {
return nil, errors.Wrap(err, "First")
}
return globalnetwork, nil
}
+6 -2
View File
@@ -215,12 +215,16 @@ func (self *SBaseRegionDriver) IsSecurityGroupBelongVpc() bool {
return false
}
func (self *SBaseRegionDriver) IsSecurityGroupBelongGlobalNetwork() bool {
return false
}
func (self *SBaseRegionDriver) GetDefaultSecurityGroupVpcId() string {
return api.NORMAL_VPC_ID
}
func (self *SBaseRegionDriver) GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, host *models.SHost, vpc *models.SVpc, classic bool) string {
return ""
func (self *SBaseRegionDriver) GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, host *models.SHost, vpc *models.SVpc, classic bool) (string, error) {
return "", cloudprovider.ErrNotImplemented
}
func (self *SBaseRegionDriver) RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *models.SVpc, secgroup *models.SSecurityGroup) (string, error) {
+37
View File
@@ -0,0 +1,37 @@
// 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 (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SGoogleRegionDriver struct {
SManagedVirtualizationRegionDriver
}
func init() {
driver := SGoogleRegionDriver{}
models.RegisterRegionDriver(&driver)
}
func (self *SGoogleRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_GOOGLE
}
func (self *SGoogleRegionDriver) IsSecurityGroupBelongGlobalNetwork() bool {
return true
}
+19 -7
View File
@@ -1384,13 +1384,19 @@ func (self *SManagedVirtualizationRegionDriver) BindIPToNatgatewayRollback(ctx c
return nil
}
func (self *SManagedVirtualizationRegionDriver) GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, host *models.SHost, vpc *models.SVpc, classic bool) string {
if region.GetDriver().IsSupportClassicSecurityGroup() && (classic || (host != nil && strings.HasSuffix(host.Name, "-classic"))) {
return "classic"
func (self *SManagedVirtualizationRegionDriver) GetSecurityGroupVpcId(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, host *models.SHost, vpc *models.SVpc, classic bool) (string, error) {
if region.GetDriver().IsSecurityGroupBelongGlobalNetwork() {
globalnetwork, err := vpc.GetGlobalNetwork()
if err != nil {
return "", errors.Wrap(err, "vpc.GetGlobalNetwork")
}
return globalnetwork.ExternalId, nil
} else if region.GetDriver().IsSupportClassicSecurityGroup() && (classic || (host != nil && strings.HasSuffix(host.Name, "-classic"))) {
return "classic", nil
} else if region.GetDriver().IsSecurityGroupBelongVpc() {
return vpc.ExternalId
return vpc.ExternalId, nil
}
return region.GetDriver().GetDefaultSecurityGroupVpcId()
return region.GetDriver().GetDefaultSecurityGroupVpcId(), nil
}
func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, vpcId string, vpc *models.SVpc, secgroup *models.SSecurityGroup) (string, error) {
@@ -1473,7 +1479,10 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncSecurityGroup(ctx con
func (self *SManagedVirtualizationRegionDriver) RequestCacheSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential, region *models.SCloudregion, vpc *models.SVpc, secgroup *models.SSecurityGroup, classic bool, task taskman.ITask) error {
vpcId := region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, classic)
vpcId, err := region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, classic)
if err != nil {
return errors.Wrap(err, "GetSecurityGroupVpcId")
}
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
_, err := self.RequestSyncSecurityGroup(ctx, userCred, vpcId, vpc, secgroup)
return nil, err
@@ -1533,7 +1542,10 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstance(ctx cont
secgroup, _ := dbinstance.GetSecgroup()
if secgroup != nil {
vpcId := region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, false)
vpcId, err := region.GetDriver().GetSecurityGroupVpcId(ctx, userCred, region, nil, vpc, false)
if err != nil {
return nil, errors.Wrap(err, "GetSecurityGroupVpcId")
}
desc.SecgroupId, err = region.GetDriver().RequestSyncSecurityGroup(ctx, userCred, vpcId, vpc, secgroup)
if err != nil {
return nil, errors.Wrap(err, "SyncSecurityGroup")
+2
View File
@@ -136,6 +136,7 @@ func InitHandlers(app *appsrv.Application) {
models.ElasticcacheParameterManager,
models.ElasticcacheBackupManager,
models.ElasticcacheSkuManager,
models.GlobalNetworkManager,
} {
db.RegisterModelManager(manager)
handler := db.NewModelHandler(manager)
@@ -160,6 +161,7 @@ func InitHandlers(app *appsrv.Application) {
models.NetworkinterfacenetworkManager,
models.SnapshotPolicyDiskManager,
models.InstanceSnapshotJointManager,
models.GlobalnetworkVpcManager,
} {
db.RegisterModelManager(manager)
handler := db.NewJointModelHandler(manager)
@@ -0,0 +1,35 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package modules
import (
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
)
type GlobalNetworkManager struct {
modulebase.ResourceManager
}
var (
GlobalNetworks GlobalNetworkManager
)
func init() {
GlobalNetworks = GlobalNetworkManager{NewComputeManager("globalnetwork", "globalnetworks",
[]string{},
[]string{"ID", "Name", "Description"})}
registerCompute(&GlobalNetworks)
}
@@ -0,0 +1,33 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package modules
import "yunion.io/x/onecloud/pkg/mcclient/modulebase"
var (
GlobalnetworkVpcs modulebase.JointResourceManager
)
func init() {
GlobalnetworkVpcs = NewJointComputeManager(
"globalnetworkvpc",
"globalnetworkvpcs",
[]string{"Globalnetwork_Id", "Globalnetwork",
"Vpc_Id", "Vpc"},
[]string{},
&GlobalNetworks,
&Vpcs)
registerCompute(&GlobalnetworkVpcs)
}
+5
View File
@@ -105,6 +105,11 @@ type SQcloudCloudAccountCreateOptions struct {
SQcloudCredential
}
type SGoogleCloudAccountCreateOptions struct {
SCloudAccountCreateBaseOptions
GoogleJsonFile string `help:"Google auth json file" positional:"true"`
}
type SAWSCloudAccountCreateOptions struct {
SCloudAccountCreateBaseOptions
SAccessKeyCredentialWithEnvironment
@@ -121,6 +121,14 @@ func (self *SAliyunProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (cli *SAliyunProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (cli *SAliyunProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SAliyunProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(extId)
}
+8
View File
@@ -114,6 +114,14 @@ func (self *SAwsProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (self *SAwsProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (self *SAwsProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SAwsProvider) GetSysInfo() (jsonutils.JSONObject, error) {
regions := self.client.GetIRegions()
info := jsonutils.NewDict()
@@ -166,6 +166,14 @@ func (self *SAzureProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (cli *SAzureProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (cli *SAzureProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SAzureProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(id)
}
+8
View File
@@ -166,6 +166,14 @@ func (self *SESXiProvider) GetIRegions() []cloudprovider.ICloudRegion {
return nil
}
func (cli *SESXiProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (cli *SESXiProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SESXiProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
return nil, cloudprovider.ErrNotSupported
}
+228
View File
@@ -0,0 +1,228 @@
// 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 google
import (
"context"
"fmt"
"time"
"yunion.io/x/jsonutils"
billing "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SDisk struct {
storage *SStorage
Id string
CreationTimestamp time.Time
Name string
SizeGB int
Zone string
Status string
SelfLink string
Type string
SourceImage string
LastAttachTimestamp time.Time
LastDetachTimestamp time.Time
LabelFingerprint string
PhysicalBlockSizeBytes string
ResourcePolicies []string
Kind string
autoDelete bool
boot bool
index int
}
func (region *SRegion) GetDisks(zone string, storageType string, maxResults int, pageToken string) ([]SDisk, error) {
disks := []SDisk{}
if len(zone) == 0 {
return nil, fmt.Errorf("zone params can not be empty")
}
params := map[string]string{}
if len(storageType) > 0 {
params["filter"] = fmt.Sprintf(`type="%s/zones/%s/diskTypes/%s"`, region.GetUrlPrefixWithProjectId(), zone, storageType)
}
return disks, region.List(fmt.Sprintf("zones/%s/disks", zone), params, maxResults, pageToken, &disks)
}
func (region *SRegion) GetDisk(id string) (*SDisk, error) {
disk := &SDisk{}
return disk, region.Get(id, disk)
}
func (disk *SDisk) GetId() string {
return disk.SelfLink
}
func (disk *SDisk) GetGlobalId() string {
return getGlobalId(disk.SelfLink)
}
func (disk *SDisk) GetName() string {
return disk.Name
}
func (disk *SDisk) GetStatus() string {
switch disk.Status {
case "READY":
return api.DISK_READY
case "CREATING":
return api.DISK_ALLOCATING
case "RESTORING":
return api.DISK_RESET
case "FAILED":
return api.DISK_ALLOC_FAILED
case "DELETING":
return api.DISK_DEALLOC
default:
return api.DISK_UNKNOWN
}
}
func (disk *SDisk) IsEmulated() bool {
return false
}
func (disk *SDisk) Refresh() error {
_disk, err := disk.storage.zone.region.GetDisk(disk.SelfLink)
if err != nil {
return err
}
return jsonutils.Update(disk, _disk)
}
func (disk *SDisk) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) {
return disk.storage, nil
}
func (disk *SDisk) GetIStorageId() string {
return disk.storage.GetGlobalId()
}
func (disk *SDisk) GetDiskFormat() string {
return ""
}
func (disk *SDisk) GetDiskSizeMB() int {
return disk.SizeGB * 1024
}
func (disk *SDisk) GetIsAutoDelete() bool {
return disk.autoDelete
}
func (disk *SDisk) GetTemplateId() string {
return disk.SourceImage
}
func (disk *SDisk) GetDiskType() string {
if disk.index == 0 || disk.boot {
return api.DISK_TYPE_SYS
}
return api.DISK_TYPE_DATA
}
func (disk *SDisk) GetFsFormat() string {
return ""
}
func (disk *SDisk) GetIsNonPersistent() bool {
return false
}
func (disk *SDisk) GetDriver() string {
return "scsi"
}
func (disk *SDisk) GetCacheMode() string {
return "none"
}
func (disk *SDisk) GetMountpoint() string {
return ""
}
func (disk *SDisk) GetAccessPath() string {
return ""
}
func (disk *SDisk) Delete(ctx context.Context) error {
return cloudprovider.ErrNotImplemented
}
func (disk *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (disk *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
snapshots, err := disk.storage.zone.region.GetSnapshots(disk.SelfLink, 0, "")
if err != nil {
return nil, err
}
isnapshots := []cloudprovider.ICloudSnapshot{}
for i := range snapshots {
snapshots[i].region = disk.storage.zone.region
isnapshots = append(isnapshots, &snapshots[i])
}
return isnapshots, nil
}
func (disk *SDisk) GetISnapshot(id string) (cloudprovider.ICloudSnapshot, error) {
return disk.storage.zone.region.GetSnapshot(id)
}
func (disk *SDisk) GetExtSnapshotPolicyIds() ([]string, error) {
result := []string{}
for _, policy := range disk.ResourcePolicies {
result = append(result, getGlobalId(policy))
}
return result, nil
}
func (disk *SDisk) Resize(ctx context.Context, newSizeMB int64) error {
return cloudprovider.ErrNotImplemented
}
func (disk *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) {
return "", cloudprovider.ErrNotImplemented
}
func (disk *SDisk) Rebuild(ctx context.Context) error {
return cloudprovider.ErrNotImplemented
}
func (disk *SDisk) GetBillingType() string {
return billing.BILLING_TYPE_POSTPAID
}
func (disk *SDisk) GetCreatedAt() time.Time {
return disk.CreationTimestamp
}
func (disk *SDisk) GetExpiredAt() time.Time {
return time.Time{}
}
func (disk *SDisk) GetProjectId() string {
return disk.storage.zone.region.GetProjectId()
}
+1
View File
@@ -0,0 +1 @@
package google // import "yunion.io/x/onecloud/pkg/multicloud/google"
+173
View File
@@ -0,0 +1,173 @@
// 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 google
import (
"fmt"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
billing "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SAddress struct {
region *SRegion
Id string
CreationTimestamp time.Time
Name string
Description string
Address string
Status string
Region string
Users []string
SelfLink string
NetworkTier string
AddressType string
Kind string
}
func (region *SRegion) GetEips(address string, maxResults int, pageToken string) ([]SAddress, error) {
eips := []SAddress{}
params := map[string]string{}
if len(address) > 0 {
params["filter"] = fmt.Sprintf(`address="%s"`, address)
}
resource := fmt.Sprintf("regions/%s/addresses", region.Name)
return eips, region.List(resource, params, maxResults, pageToken, &eips)
}
func (region *SRegion) GetEip(id string) (*SAddress, error) {
eip := &SAddress{region: region}
return eip, region.Get(id, eip)
}
func (addr *SAddress) GetId() string {
return addr.SelfLink
}
func (addr *SAddress) GetName() string {
return addr.Name
}
func (addr *SAddress) GetGlobalId() string {
return getGlobalId(addr.SelfLink)
}
func (addr *SAddress) GetStatus() string {
switch addr.Status {
case "RESERVING":
return api.EIP_STATUS_ASSOCIATE
case "RESERVED":
return api.EIP_STATUS_READY
case "IN_USE":
return api.EIP_STATUS_READY
default:
log.Errorf("Unknown eip status: %s", addr.Status)
return api.EIP_STATUS_UNKNOWN
}
}
func (addr *SAddress) GetProjectId() string {
return addr.region.GetProjectId()
}
func (addr *SAddress) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (addr *SAddress) IsEmulated() bool {
if addr.Id == addr.SelfLink {
return true
}
return false
}
func (addr *SAddress) GetCreatedAt() time.Time {
return addr.CreationTimestamp
}
func (addr *SAddress) GetExpiredAt() time.Time {
return time.Time{}
}
func (addr *SAddress) GetBillingType() string {
return billing.BILLING_TYPE_POSTPAID
}
func (addr *SAddress) Refresh() error {
if addr.IsEmulated() {
return nil
}
_addr, err := addr.region.GetEip(addr.SelfLink)
if err != nil {
return err
}
return jsonutils.Update(addr, _addr)
}
func (addr *SAddress) GetIpAddr() string {
return addr.Address
}
func (addr *SAddress) GetMode() string {
if addr.IsEmulated() {
return api.EIP_MODE_INSTANCE_PUBLICIP
}
return api.EIP_MODE_STANDALONE_EIP
}
func (addr *SAddress) GetINetworkId() string {
return ""
}
func (addr *SAddress) GetAssociationType() string {
return api.EIP_ASSOCIATE_TYPE_SERVER
}
func (addr *SAddress) GetAssociationExternalId() string {
if len(addr.Users) > 0 {
return getGlobalId(addr.Users[0])
}
return ""
}
func (addr *SAddress) GetBandwidth() int {
return 0
}
func (addr *SAddress) GetInternetChargeType() string {
return api.EIP_CHARGE_TYPE_BY_TRAFFIC
}
func (addr *SAddress) Delete() error {
return cloudprovider.ErrNotImplemented
}
func (addr *SAddress) Associate(instanceId string) error {
return cloudprovider.ErrNotImplemented
}
func (addr *SAddress) Dissociate() error {
return cloudprovider.ErrNotImplemented
}
func (addr *SAddress) ChangeBandwidth(bw int) error {
return cloudprovider.ErrNotImplemented
}
+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 google
import (
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
type SGlobalNetwork struct {
Id string
//CreationTimestamp time.Time
Name string
Description string
SelfLink string
AutoCreateSubnetworks bool
Subnetworks []string
RoutingConfig map[string]string
Kind string
}
func (cli *SGoogleClient) GetGlobalNetwork(id string) (*SGlobalNetwork, error) {
net := &SGlobalNetwork{}
return net, cli.get(id, net)
}
func (cli *SGoogleClient) GetGlobalNetworks(maxResults int, pageToken string) ([]SGlobalNetwork, error) {
networks := []SGlobalNetwork{}
params := map[string]string{}
resource := "global/networks"
return networks, cli.list(resource, params, maxResults, pageToken, &networks)
}
func (net *SGlobalNetwork) GetId() string {
return net.SelfLink
}
func (net *SGlobalNetwork) GetGlobalId() string {
return getGlobalId(net.SelfLink)
}
func (net *SGlobalNetwork) GetName() string {
return net.Name
}
func (net *SGlobalNetwork) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (net *SGlobalNetwork) GetStatus() string {
return api.GLOBAL_NETWORK_STATUS_AVAILABLE
}
func (net *SGlobalNetwork) IsEmulated() bool {
return false
}
func (net *SGlobalNetwork) Refresh() error {
return nil
}
+318
View File
@@ -0,0 +1,318 @@
// 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 google
import (
"context"
"fmt"
"net/http"
"net/url"
"strings"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"golang.org/x/oauth2/jwt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/httputils"
)
const (
CLOUD_PROVIDER_GOOGLE = api.CLOUD_PROVIDER_GOOGLE
CLOUD_PROVIDER_GOOGLE_CN = "谷歌云"
GOOGLE_DEFAULT_REGION = "asia-east1"
GOOGLE_API_VERSION = "v1"
)
type SGoogleClient struct {
providerId string
providerName string
projectId string
privateKey string
privateKeyId string
clientEmail string
iregions []cloudprovider.ICloudRegion
images []SImage
snapshots map[string][]SSnapshot
globalnetworks []SGlobalNetwork
resourcepolices []SResourcePolicy
client *http.Client
Debug bool
}
func NewGoogleClient(providerId string, providerName string, projectId, clientEmail, privateKeyId, privateKey string, isDebug bool) (*SGoogleClient, error) {
client := SGoogleClient{
providerId: providerId,
providerName: providerName,
projectId: projectId,
privateKey: strings.Replace(privateKey, "\\n", "\n", -1),
privateKeyId: privateKeyId,
clientEmail: clientEmail,
Debug: isDebug,
}
conf := &jwt.Config{
Email: clientEmail,
PrivateKeyID: privateKeyId,
PrivateKey: []byte(client.privateKey),
Scopes: []string{
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/compute.readonly",
"https://www.googleapis.com/auth/cloud-platform.read-only",
"https://www.googleapis.com/auth/cloudplatformprojects",
"https://www.googleapis.com/auth/cloudplatformprojects.readonly",
},
TokenURL: google.JWTTokenURL,
}
client.client = conf.Client(oauth2.NoContext)
return &client, client.fetchRegions()
}
func (self *SGoogleClient) GetAccountId() string {
return self.clientEmail
}
func (self *SGoogleClient) fetchRegions() error {
regions := []SRegion{}
err := self.listAll("regions", nil, &regions)
if err != nil {
return err
}
self.iregions = []cloudprovider.ICloudRegion{}
for i := 0; i < len(regions); i++ {
regions[i].client = self
self.iregions = append(self.iregions, &regions[i])
}
return nil
}
func (self *SGoogleClient) get(id string, retval interface{}) error {
if !strings.HasPrefix(id, getUrlPrefix()) {
id = getUrlPrefix() + id
}
data, err := jsonRequest(self.client, "GET", id, nil, self.Debug)
if err != nil {
if strings.Index(err.Error(), "not found") > 0 {
return cloudprovider.ErrNotFound
}
return errors.Wrap(err, "JSONRequest")
}
err = data.Unmarshal(retval)
if err != nil {
return errors.Wrap(err, "Unmarshal")
}
return nil
}
func (self *SGoogleClient) listAll(resource string, params map[string]string, retval interface{}) error {
var (
items *jsonutils.JSONArray = jsonutils.NewArray()
_items []jsonutils.JSONObject = []jsonutils.JSONObject{}
maxResults int = 500
nextPageToken string = ""
err error = nil
)
for {
_items, nextPageToken, err = self._listAll(resource, params, maxResults, nextPageToken)
if err != nil {
return errors.Wrapf(err, `_listAll("%s")`, resource)
}
items.Add(_items...)
if len(nextPageToken) == 0 || len(_items) == 0 {
break
}
}
return items.Unmarshal(retval)
}
func (self *SGoogleClient) _listAll(resource string, params map[string]string, maxResults int, pageToken string) ([]jsonutils.JSONObject, string, error) {
if params == nil {
params = map[string]string{}
}
params["maxResults"] = fmt.Sprintf("%d", maxResults)
params["pageToken"] = pageToken
data, err := self._list(resource, params)
if err != nil {
return nil, "", err
}
items := []jsonutils.JSONObject{}
if data.Contains("items") {
items, err = data.GetArray("items")
if err != nil {
return nil, "", errors.Wrap(err, "data.GetArray")
}
}
nextPageToken, _ := data.GetString("nextPageToken")
return items, nextPageToken, nil
}
func (self *SGoogleClient) list(resource string, params map[string]string, maxResults int, pageToken string, retval interface{}) error {
if maxResults == 0 && len(pageToken) == 0 {
return self.listAll(resource, params, retval)
}
params["maxResults"] = fmt.Sprintf("%d", maxResults)
params["pageToken"] = pageToken
data, err := self._list(resource, params)
if err != nil {
return errors.Wrapf(err, "_list(%s)", resource)
}
if data.Contains("items") {
err := data.Unmarshal(retval, "items")
if err != nil {
return errors.Wrap(err, "data.Unmarshal")
}
}
return nil
}
func jsonRequest(client *http.Client, method httputils.THttpMethod, url string, body jsonutils.JSONObject, debug bool) (jsonutils.JSONObject, error) {
_, data, err := httputils.JSONRequest(client, context.Background(), method, url, nil, body, debug)
if err != nil {
if strings.Index(err.Error(), "not found") > 0 {
return nil, cloudprovider.ErrNotFound
}
return nil, errors.Wrap(err, "JSONRequest")
}
return data, nil
}
func (self *SGoogleClient) _list(resource string, params map[string]string) (jsonutils.JSONObject, error) {
baseUrl := fmt.Sprintf("%s%s/%s", getUrlPrefix(), self.projectId, resource)
values := url.Values{}
for k, v := range params {
values.Set(k, v)
}
if len(values) > 0 {
baseUrl = fmt.Sprintf("%s?%s", baseUrl, values.Encode())
}
return jsonRequest(self.client, "GET", baseUrl, nil, self.Debug)
}
func (self *SGoogleClient) GetRegion(regionId string) *SRegion {
if len(regionId) == 0 {
regionId = GOOGLE_DEFAULT_REGION
}
for i := 0; i < len(self.iregions); i++ {
if self.iregions[i].GetId() == regionId {
return self.iregions[i].(*SRegion)
}
}
return nil
}
func (client *SGoogleClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
projects, err := client.GetProjects()
if err != nil {
return nil, errors.Wrap(err, "GetProjects")
}
accounts := []cloudprovider.SSubAccount{}
for _, project := range projects {
subAccount := cloudprovider.SSubAccount{}
subAccount.Name = client.providerName
subAccount.Account = fmt.Sprintf("%s/%s", project.ProjectId, client.clientEmail)
if project.LifecycleState == "ACTIVE" {
subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL
} else {
subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_ARREARS
}
accounts = append(accounts, subAccount)
}
return accounts, nil
}
func (self *SGoogleClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
for i := 0; i < len(self.iregions); i++ {
if self.iregions[i].GetGlobalId() == id {
return self.iregions[i].(*SRegion), nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SGoogleClient) GetIRegions() []cloudprovider.ICloudRegion {
return self.iregions
}
func (self *SGoogleClient) fetchGlobalNetwork() ([]SGlobalNetwork, error) {
if len(self.globalnetworks) > 0 {
return self.globalnetworks, nil
}
globalnetworks, err := self.GetGlobalNetworks(0, "")
if err != nil {
return nil, err
}
self.globalnetworks = globalnetworks
return globalnetworks, nil
}
func (cli *SGoogleClient) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
networks, err := cli.fetchGlobalNetwork()
if err != nil {
return nil, errors.Wrap(err, "fetchGlobalNetwork")
}
inetworks := []cloudprovider.ICloudGlobalnetwork{}
for i := range networks {
inetworks = append(inetworks, &networks[i])
}
return inetworks, nil
}
func (cli *SGoogleClient) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
network, err := cli.GetGlobalNetwork(id)
if err != nil {
return nil, err
}
return network, nil
}
func (self *SGoogleClient) GetRegions() []SRegion {
regions := make([]SRegion, len(self.iregions))
for i := 0; i < len(regions); i++ {
region := self.iregions[i].(*SRegion)
regions[i] = *region
}
return regions
}
func (self *SGoogleClient) GetIProjects() ([]cloudprovider.ICloudProject, error) {
projects, err := self.GetProjects()
if err != nil {
return nil, err
}
iprojects := []cloudprovider.ICloudProject{}
for i := range projects {
iprojects = append(iprojects, &projects[i])
}
return iprojects, nil
}
func getUrlPrefix() string {
return fmt.Sprintf("https://www.googleapis.com/compute/%s/projects/", GOOGLE_API_VERSION)
}
func getGlobalId(id string) string {
return strings.TrimPrefix(id, getUrlPrefix())
}
+187
View File
@@ -0,0 +1,187 @@
// 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 google
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SHost struct {
multicloud.SHostBase
zone *SZone
}
func (self *SHost) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (host *SHost) GetId() string {
return getGlobalId(host.zone.GetId())
}
func (host *SHost) GetGlobalId() string {
return host.GetId()
}
func (host *SHost) GetName() string {
return fmt.Sprintf("%s-%s", host.zone.region.client.providerName, host.zone.GetName())
}
func (host *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
return host.zone.GetIStorages()
}
func (host *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
return host.zone.GetIStorageById(id)
}
func (host *SHost) IsEmulated() bool {
return false
}
func (host *SHost) GetStatus() string {
return api.HOST_STATUS_RUNNING
}
func (host *SHost) Refresh() error {
return nil
}
func (host *SHost) GetHostStatus() string {
return api.HOST_ONLINE
}
func (host *SHost) GetEnabled() bool {
return true
}
func (host *SHost) GetAccessIp() string {
return ""
}
func (host *SHost) GetAccessMac() string {
return ""
}
func (host *SHost) GetSysInfo() jsonutils.JSONObject {
info := jsonutils.NewDict()
info.Add(jsonutils.NewString(CLOUD_PROVIDER_GOOGLE), "manufacture")
return info
}
func (host *SHost) GetSN() string {
return ""
}
func (host *SHost) GetCpuCount() int {
return 0
}
func (host *SHost) GetNodeCount() int8 {
return 0
}
func (host *SHost) GetCpuDesc() string {
return ""
}
func (host *SHost) GetCpuMhz() int {
return 0
}
func (host *SHost) GetMemSizeMB() int {
return 0
}
func (host *SHost) GetStorageSizeMB() int {
return 0
}
func (host *SHost) GetStorageType() string {
return api.DISK_TYPE_HYBRID
}
func (host *SHost) GetHostType() string {
return api.HOST_TYPE_GOOGLE
}
func (host *SHost) GetWire() *SWire {
vpc := &SVpc{region: host.zone.region}
return &SWire{vpc: vpc}
}
func (host *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) {
ivpcs, err := host.zone.region.GetIVpcs()
if err != nil {
return nil, errors.Wrap(err, "region.GetIVpcs")
}
iwires := []cloudprovider.ICloudWire{}
for i := range ivpcs {
_iwires, err := ivpcs[i].GetIWires()
if err != nil {
return nil, errors.Wrap(err, "ivpcs[i].GetIWires")
}
iwires = append(iwires, _iwires...)
}
return iwires, nil
}
func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
instances, err := host.zone.region.GetInstances(host.zone.Name, 0, "")
if err != nil {
return nil, err
}
iVMs := []cloudprovider.ICloudVM{}
for i := range instances {
instances[i].host = host
iVMs = append(iVMs, &instances[i])
}
return iVMs, nil
}
func (host *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
instance, err := host.zone.region.GetInstance(id)
if err != nil {
return nil, err
}
if instance.Zone != host.zone.SelfLink {
return nil, cloudprovider.ErrNotFound
}
return instance, nil
}
func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
return nil, cloudprovider.ErrNotSupported
}
func (host *SHost) GetIsMaintenance() bool {
return false
}
func (host *SHost) GetVersion() string {
return GOOGLE_API_VERSION
}
+228
View File
@@ -0,0 +1,228 @@
// 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 google
import (
"context"
"strings"
"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/util/imagetools"
)
type GuestOsFeature struct {
Type string
}
type SDeprecated struct {
State string
Replacement string
Deprecated bool
}
type SImage struct {
storagecache *SStoragecache
Id string
CreationTimestamp time.Time
Name string
Description string
SourceType string
RawDisk map[string]string
Deprecated SDeprecated
Status string
ArchiveSizeBytes int64
DiskSizeGb int
Licenses []string
Family string
SelfLink string
LabelFingerprint string
GuestOsFeatures []GuestOsFeature
LicenseCodes []string
StorageLocations []string
Kind string
}
func (region *SRegion) SetProjectId(id string) {
region.client.projectId = id
}
func (region *SRegion) GetAllAvailableImages() ([]SImage, error) {
images := []SImage{}
projectId := region.client.projectId
for _, project := range []string{
"centos-cloud",
"ubuntu-os-cloud",
"windows-cloud",
"windows-sql-cloud",
"suse-cloud",
"suse-sap-cloud",
"rhel-cloud",
"rhel-sap-cloud",
"cos-cloud",
"coreos-cloud",
"debian-cloud",
projectId,
} {
_images, err := region.GetImages(project, 0, "")
if err != nil {
return nil, err
}
for _, image := range _images {
if image.Deprecated.State == "" {
images = append(images, image)
}
}
}
return images, nil
}
func (region *SRegion) GetImages(project string, maxResults int, pageToken string) ([]SImage, error) {
images := []SImage{}
resource := "global/images"
params := map[string]string{}
if len(project) > 0 {
region.SetProjectId(project)
}
return images, region.List(resource, params, maxResults, pageToken, &images)
}
func (region *SRegion) GetImage(id string) (*SImage, error) {
image := &SImage{}
return image, region.Get(id, image)
}
func (image *SImage) GetId() string {
return image.SelfLink
}
func (image *SImage) GetGlobalId() string {
return getGlobalId(image.SelfLink)
}
func (image *SImage) GetName() string {
return image.Name
}
func (image *SImage) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (image *SImage) GetMinRamSizeMb() int {
return 0
}
func (image *SImage) GetStatus() string {
switch image.Status {
case "READY":
return api.CACHED_IMAGE_STATUS_READY
case "FAILED":
return api.CACHED_IMAGE_STATUS_CACHE_FAILED
case "PENDING":
return api.CACHED_IMAGE_STATUS_SAVING
default:
log.Errorf("Unknown image status: %s", image.Status)
return api.CACHED_IMAGE_STATUS_CACHE_FAILED
}
}
func (image *SImage) GetImageStatus() string {
switch image.Status {
case "READY":
return cloudprovider.IMAGE_STATUS_ACTIVE
case "FAILED":
return cloudprovider.IMAGE_STATUS_KILLED
case "PENDING":
return cloudprovider.IMAGE_STATUS_QUEUED
default:
return cloudprovider.IMAGE_STATUS_KILLED
}
}
func (image *SImage) Refresh() error {
_image, err := image.storagecache.region.GetImage(image.SelfLink)
if err != nil {
return err
}
return jsonutils.Update(image, _image)
}
func (image *SImage) GetImageType() string {
if strings.Index(image.SelfLink, image.storagecache.region.GetProjectId()) >= 0 {
return cloudprovider.CachedImageTypeCustomized
}
return cloudprovider.CachedImageTypeSystem
}
func (image *SImage) GetSizeByte() int64 {
return image.ArchiveSizeBytes
}
func (image *SImage) GetOsType() string {
return imagetools.NormalizeImageInfo(image.Name, "", "", "", "").OsType
}
func (image *SImage) GetOsDist() string {
return imagetools.NormalizeImageInfo(image.Name, "", "", "", "").OsDistro
}
func (image *SImage) GetOsVersion() string {
return imagetools.NormalizeImageInfo(image.Name, "", "", "", "").OsVersion
}
func (image *SImage) GetOsArch() string {
return imagetools.NormalizeImageInfo(image.Name, "", "", "", "").OsArch
}
func (image *SImage) GetMinOsDiskSizeGb() int {
return image.DiskSizeGb
}
func (image *SImage) GetCreatedAt() time.Time {
return image.CreationTimestamp
}
func (image *SImage) GetImageFormat() string {
return "vhd"
}
func (image *SImage) IsEmulated() bool {
return false
}
func (image *SImage) Delete(ctx context.Context) error {
return cloudprovider.ErrNotImplemented
}
func (image *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache {
return image.storagecache
}
func (region *SRegion) fetchImages() ([]SImage, error) {
if len(region.client.images) > 0 {
return region.client.images, nil
}
images, err := region.GetAllAvailableImages()
if err != nil {
return nil, err
}
region.client.images = images
return images, nil
}
+409
View File
@@ -0,0 +1,409 @@
// 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 google
import (
"context"
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/osprofile"
"yunion.io/x/pkg/utils"
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
"yunion.io/x/onecloud/pkg/util/billing"
"yunion.io/x/onecloud/pkg/util/imagetools"
)
type AccessConfig struct {
Type string
Name string
NatIP string
NetworkTier string
Kind string
}
type InstanceDisk struct {
Type string
Mode string
Source string
DeviceName string
Index int
Boot bool
AutoDelete bool
Licenses []string
Interface string
GuestOsFeatures []GuestOsFeature
Kind string
}
type ServiceAccount struct {
Email string
scopes []string
}
type SInstanceTag struct {
Items []string
Fingerprint string
}
type SInstance struct {
multicloud.SInstanceBase
host *SHost
Id string
CreationTimestamp time.Time
Name string
Description string
Tags SInstanceTag
MachineType string
Status string
Zone string
CanIpForward bool
NetworkInterfaces []SNetworkInterface
Disks []InstanceDisk
Metadata map[string]string
ServiceAccounts []ServiceAccount
SelfLink string
Scheduling map[string]interface{}
CpuPlatform string
LabelFingerprint string
StartRestricted bool
DeletionProtection bool
Kind string
guestCpus int
memoryMb int
machineType string
}
func (region *SRegion) GetInstances(zone string, maxResults int, pageToken string) ([]SInstance, error) {
instances := []SInstance{}
params := map[string]string{}
if len(zone) == 0 {
return nil, fmt.Errorf("zone params can not be empty")
}
resource := fmt.Sprintf("zones/%s/instances", zone)
return instances, region.List(resource, params, maxResults, pageToken, &instances)
}
func (region *SRegion) GetInstance(id string) (*SInstance, error) {
instance := &SInstance{}
return instance, region.Get(id, instance)
}
func (instance *SInstance) GetId() string {
return instance.SelfLink
}
func (instnace *SInstance) GetGlobalId() string {
return getGlobalId(instnace.SelfLink)
}
func (instance *SInstance) GetName() string {
return instance.Name
}
func (instnace *SInstance) IsEmulated() bool {
return false
}
func (instance *SInstance) fetchMachineType() error {
if instance.guestCpus > 0 || instance.memoryMb > 0 || len(instance.machineType) > 0 {
return nil
}
machinetype, err := instance.host.zone.region.GetMachineType(instance.MachineType)
if err != nil {
return err
}
instance.guestCpus = machinetype.GuestCpus
instance.memoryMb = machinetype.MemoryMb
instance.machineType = machinetype.Name
return nil
}
func (instance *SInstance) Refresh() error {
_instance, err := instance.host.zone.region.GetInstance(instance.SelfLink)
if err != nil {
return err
}
return jsonutils.Update(instance, _instance)
}
//PROVISIONING, STAGING, RUNNING, STOPPING, STOPPED, SUSPENDING, SUSPENDED, and TERMINATED.
func (instance *SInstance) GetStatus() string {
switch instance.Status {
case "PROVISIONING":
return api.VM_DEPLOYING
case "STAGING":
return api.VM_STARTING
case "RUNNING":
return api.VM_RUNNING
case "STOPPING":
return api.VM_STOPPING
case "STOPPED":
return api.VM_READY
case "SUSPENDING":
return api.VM_SUSPENDING
case "SUSPENDED":
return api.VM_SUSPEND
case "TERMINATED":
return api.VM_DELETING
default:
return api.VM_UNKNOWN
}
}
func (instance *SInstance) GetBillingType() string {
return billing_api.BILLING_TYPE_POSTPAID
}
func (instance *SInstance) GetCreatedAt() time.Time {
return instance.CreationTimestamp
}
func (instance *SInstance) GetExpiredAt() time.Time {
return time.Time{}
}
func (instance *SInstance) GetProjectId() string {
return instance.host.zone.region.GetProjectId()
}
func (instance *SInstance) GetIHost() cloudprovider.ICloudHost {
return instance.host
}
func (instance *SInstance) GetIHostId() string {
return instance.host.GetGlobalId()
}
func (instance *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
idisks := []cloudprovider.ICloudDisk{}
for _, disk := range instance.Disks {
disk, err := instance.host.zone.region.GetDisk(disk.Source)
if err != nil {
return nil, errors.Wrap(err, "GetDisk")
}
storage, err := instance.host.zone.region.GetStorage(disk.Type)
if err != nil {
return nil, errors.Wrap(err, "GetStorage")
}
storage.zone = instance.host.zone
disk.storage = storage
idisks = append(idisks, disk)
}
return idisks, nil
}
func (instance *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
nics := []cloudprovider.ICloudNic{}
for i := range instance.NetworkInterfaces {
instance.NetworkInterfaces[i].instance = instance
nics = append(nics, &instance.NetworkInterfaces[i])
}
return nics, nil
}
func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
for _, networkinterface := range instance.NetworkInterfaces {
for _, conf := range networkinterface.AccessConfigs {
if len(conf.NatIP) > 0 {
eips, err := instance.host.zone.region.GetEips(conf.NatIP, 0, "")
if err != nil {
return nil, errors.Wrapf(err, "region.GetEip(%s)", conf.NatIP)
}
if len(eips) == 1 {
return &eips[0], nil
}
eip := &SAddress{
region: instance.host.zone.region,
SelfLink: instance.SelfLink,
Id: instance.SelfLink,
Address: conf.NatIP,
}
return eip, nil
}
}
}
return nil, nil
}
func (instance *SInstance) GetVcpuCount() int {
instance.fetchMachineType()
return instance.guestCpus
}
func (instance *SInstance) GetVmemSizeMB() int {
instance.fetchMachineType()
return instance.memoryMb
}
func (instance *SInstance) GetBootOrder() string {
return "cdn"
}
func (instance *SInstance) GetVga() string {
return "std"
}
func (instance *SInstance) GetVdi() string {
return "vnc"
}
func (instance *SInstance) GetOSType() string {
for _, disk := range instance.Disks {
if disk.Index == 0 {
for _, license := range disk.Licenses {
if strings.Index(strings.ToLower(license), "windows") < 0 {
return osprofile.OS_TYPE_LINUX
} else {
return osprofile.OS_TYPE_WINDOWS
}
}
}
}
return osprofile.OS_TYPE_LINUX
}
func (instance *SInstance) GetOSName() string {
for _, disk := range instance.Disks {
if disk.Index == 0 {
for _, license := range disk.Licenses {
return imagetools.NormalizeImageInfo(license, "", "", "", "").OsDistro
}
}
}
return ""
}
func (instance *SInstance) GetBios() string {
return "BIOS"
}
func (instance *SInstance) GetMachine() string {
return "pc"
}
func (instance *SInstance) GetInstanceType() string {
instance.fetchMachineType()
return instance.machineType
}
func (instance *SInstance) AssignSecurityGroup(id string) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) GetSecurityGroupIds() ([]string, error) {
secgroupIds := []string{}
isecgroups := []cloudprovider.ICloudSecurityGroup{}
for _, networkinterface := range instance.NetworkInterfaces {
globalnetwork, err := instance.host.zone.region.client.GetGlobalNetwork(networkinterface.Network)
if err != nil {
return nil, errors.Wrap(err, "GetGlobalNetwork")
}
vpc := &SVpc{globalnetwork: globalnetwork, region: instance.host.zone.region}
_isecgroups, err := vpc.GetISecurityGroups()
if err != nil {
return nil, errors.Wrap(err, "vpc.GetISecurityGroups")
}
isecgroups = append(isecgroups, _isecgroups...)
for _, isecgroup := range _isecgroups {
if len(instance.ServiceAccounts) > 0 && isecgroup.GetName() == instance.ServiceAccounts[0].Email {
secgroupIds = append(secgroupIds, isecgroup.GetGlobalId())
}
if isecgroup.GetName() == globalnetwork.GetName() {
secgroupIds = append(secgroupIds, isecgroup.GetGlobalId())
}
}
}
if len(instance.NetworkInterfaces) == 1 {
for _, secgroup := range isecgroups {
if utils.IsInStringArray(secgroup.GetName(), instance.Tags.Items) {
secgroupIds = append(secgroupIds, secgroup.GetGlobalId())
}
}
}
return secgroupIds, nil
}
func (instance *SInstance) SetSecurityGroups(ids []string) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) GetHypervisor() string {
return api.HYPERVISOR_GOOGLE
}
func (instance *SInstance) StartVM(ctx context.Context) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) StopVM(ctx context.Context, isForce bool) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) DeleteVM(ctx context.Context) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) UpdateVM(ctx context.Context, name string) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) UpdateUserData(userData string) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) RebuildRoot(ctx context.Context, imageId string, passwd string, publicKey string, sysSizeGB int) (string, error) {
return "", cloudprovider.ErrNotImplemented
}
func (instance *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, driver string) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) Renew(bc billing.SBillingCycle) error {
return cloudprovider.ErrNotImplemented
}
func (instance *SInstance) GetError() error {
return nil
}
+58
View File
@@ -0,0 +1,58 @@
// 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 google
import (
"yunion.io/x/log"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SNetworkInterface struct {
instance *SInstance
Network string
Subnetwork string
NetworkIP string
Name string
AccessConfigs []AccessConfig
Fingerprint string
Kind string
}
func (nic *SNetworkInterface) GetIP() string {
return nic.NetworkIP
}
func (nic *SNetworkInterface) GetMAC() string {
ip, _ := netutils.NewIPV4Addr(nic.NetworkIP)
return ip.ToMac("00:16:")
}
func (nic *SNetworkInterface) GetDriver() string {
return "virtio"
}
func (nic *SNetworkInterface) GetINetwork() cloudprovider.ICloudNetwork {
network, err := nic.instance.host.zone.region.GetNetwork(nic.Subnetwork)
if err != nil {
log.Errorf("failed to found network(%s) for nic error: %v", nic.Subnetwork, err)
return nil
}
wire := nic.instance.host.GetWire()
network.wire = wire
return network
}
@@ -0,0 +1,70 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google
import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{
"asia-east1": {Latitude: 25.0443, Longitude: 121.509, City: api.CITY_TAI_WAN, CountryCode: api.COUNTRY_CODE_CN},
"asia-east2": {Latitude: 22.396427, Longitude: 114.109497, City: api.CITY_HONG_KONG, CountryCode: api.COUNTRY_CODE_CN},
"asia-northeast1": {Latitude: 35.709026, Longitude: 139.731995, City: api.CITY_TOKYO, CountryCode: api.COUNTRY_CODE_JP},
"asia-northeast2": {Latitude: 34.6937378, Longitude: 135.5021651, City: api.CITY_OSAKA, CountryCode: api.COUNTRY_CODE_JP},
"asia-south1": {Latitude: 19.075983, Longitude: 72.877655, City: api.CITY_MUMBAI, CountryCode: api.COUNTRY_CODE_IN},
"asia-southeast1": {Latitude: 1.352083, Longitude: 103.819839, City: api.CITY_SINGAPORE, CountryCode: api.COUNTRY_CODE_SG},
"australia-southeast1": {Latitude: -33.8688197, Longitude: 151.2092955, City: api.CITY_SYDNEY, CountryCode: api.COUNTRY_CODE_AU},
"europe-north1": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_FINLAND, CountryCode: api.COUNTRY_CODE_CN},
"europe-west1": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BELGIUM, CountryCode: api.COUNTRY_CODE_CN},
"europe-west2": {Latitude: 51.507351, Longitude: -0.127758, City: api.CITY_LONDON, CountryCode: api.COUNTRY_CODE_GB},
"europe-west3": {Latitude: 51.165691, Longitude: 10.451526, City: api.CITY_FRANKFURT, CountryCode: api.COUNTRY_CODE_DE},
"europe-west4": {Latitude: 52.2076831, Longitude: 4.1585786, City: api.CITY_HOLLAND, CountryCode: api.COUNTRY_CODE_NL},
"europe-west6": {Latitude: 47.3774497, Longitude: 8.5016958, City: api.CITY_ZURICH, CountryCode: api.COUNTRY_CODE_CH},
"northamerica-northeast1": {Latitude: 45.5580206, Longitude: -73.8003414, City: api.CITY_MONTREAL, CountryCode: api.COUNTRY_CODE_CA},
"southamerica-east1": {Latitude: -23.5505199, Longitude: -46.6333094, City: api.CITY_SAO_PAULO, CountryCode: api.COUNTRY_CODE_BR},
"us-central1": {Latitude: 41.9328655, Longitude: -94.5106809, City: api.CITY_IOWA, CountryCode: api.COUNTRY_CODE_US},
"us-east1": {Latitude: 33.6194409, Longitude: -82.0475635, City: api.CITY_SOUTH_CAROLINA, CountryCode: api.COUNTRY_CODE_US},
"us-east4": {Latitude: 37.4315734, Longitude: -78.6568942, City: api.CITY_N_VIRGINIA, CountryCode: api.COUNTRY_CODE_US},
"us-west1": {Latitude: 43.8041334, Longitude: -120.5542012, City: api.CITY_OREGON, CountryCode: api.COUNTRY_CODE_US},
"us-west2": {Latitude: 34.0522342, Longitude: -118.2436849, City: api.CITY_LOS_ANGELES, CountryCode: api.COUNTRY_CODE_US},
}
var RegionNames = map[string]string{
"asia-east1": "台湾",
"asia-east2": "香港",
"asia-northeast1": "东京",
"asia-northeast2": "大阪",
"asia-south1": "孟买",
"asia-southeast1": "新加坡",
"australia-southeast1": "悉尼",
"europe-north1": "芬兰",
"europe-west1": "比利时",
"europe-west2": "伦敦",
"europe-west3": "法兰克福",
"europe-west4": "荷兰",
"europe-west6": "苏黎世",
"northamerica-northeast1": "蒙特利尔",
"southamerica-east1": "圣保罗",
"us-central1": "艾奥瓦",
"us-east1": "南卡罗来纳州",
"us-east4": "北弗吉尼亚",
"us-west1": "俄勒冈州",
"us-west2": "洛杉矶",
}
+57
View File
@@ -0,0 +1,57 @@
// 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 google
import (
"fmt"
"time"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SMachineType struct {
Id string
CreationTimestamp time.Time
Name string
Description string
GuestCpus int
MemoryMb int
ImageSpaceGb int
MaximumPersistentDisks int
MaximumPersistentDisksSizeGb int
Zone string
SelfLink string
IsSharedCpu bool
Kind string
}
func (region *SRegion) GetMachineTypes(zone string, maxResults int, pageToken string) ([]SMachineType, error) {
machines := []SMachineType{}
params := map[string]string{}
if len(zone) == 0 {
return nil, cloudprovider.ErrNotFound
}
resource := fmt.Sprintf("zones/%s/machineTypes", zone)
return machines, region.List(resource, params, maxResults, pageToken, &machines)
}
func (region *SRegion) GetMachineType(id string) (*SMachineType, error) {
machine := &SMachineType{}
err := region.client.get(id, machine)
if err != nil {
return nil, err
}
return machine, nil
}
+144
View File
@@ -0,0 +1,144 @@
// 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 google
import (
"fmt"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/util/netutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
type SNetwork struct {
wire *SWire
Id string
CreationTimestamp time.Time
Name string
Network string
IpCidrRange string
Region string
GatewayAddress string
SelfLink string
Status string
AvailableCpuPlatforms []string
PrivateIpGoogleAccess bool
Fingerprint string
Purpose string
Kind string
}
func (region *SRegion) GetNetworks(network string, maxResults int, pageToken string) ([]SNetwork, error) {
networks := []SNetwork{}
params := map[string]string{}
if len(network) > 0 {
params["filter"] = fmt.Sprintf(`network="%s"`, network)
}
resource := fmt.Sprintf("regions/%s/subnetworks", region.Name)
return networks, region.List(resource, params, maxResults, pageToken, &networks)
}
func (region *SRegion) GetNetwork(id string) (*SNetwork, error) {
network := &SNetwork{}
return network, region.Get(id, network)
}
func (network *SNetwork) GetId() string {
return network.SelfLink
}
func (network *SNetwork) GetName() string {
return network.Name
}
func (network *SNetwork) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (network *SNetwork) GetProjectId() string {
return network.wire.vpc.region.GetProjectId()
}
func (network *SNetwork) Refresh() error {
_network, err := network.wire.vpc.region.GetNetwork(network.SelfLink)
if err != nil {
return err
}
return jsonutils.Update(network, _network)
}
func (network *SNetwork) IsEmulated() bool {
return false
}
func (network *SNetwork) GetStatus() string {
return api.NETWORK_INTERFACE_STATUS_AVAILABLE
}
func (network *SNetwork) GetGlobalId() string {
return getGlobalId(network.SelfLink)
}
func (network *SNetwork) Delete() error {
return cloudprovider.ErrNotImplemented
}
func (network *SNetwork) GetAllocTimeoutSeconds() int {
return 300
}
func (network *SNetwork) GetIWire() cloudprovider.ICloudWire {
return network.wire
}
func (network *SNetwork) GetIpStart() string {
pref, _ := netutils.NewIPV4Prefix(network.IpCidrRange)
startIp := pref.Address.NetAddr(pref.MaskLen) // 0
startIp = startIp.StepUp() // 1
return startIp.String()
}
func (network *SNetwork) GetIpEnd() string {
pref, _ := netutils.NewIPV4Prefix(network.IpCidrRange)
endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255
endIp = endIp.StepDown() // 254
return endIp.String()
}
func (network *SNetwork) GetIpMask() int8 {
pref, _ := netutils.NewIPV4Prefix(network.IpCidrRange)
return pref.MaskLen
}
func (network *SNetwork) GetGateway() string {
return network.GatewayAddress
}
func (network *SNetwork) GetServerType() string {
return api.NETWORK_TYPE_GUEST
}
func (network *SNetwork) GetIsPublic() bool {
return true
}
func (network *SNetwork) GetPublicScope() rbacutils.TRbacScope {
return rbacutils.ScopeDomain
}
+94
View File
@@ -0,0 +1,94 @@
// 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 google
import (
"fmt"
"time"
"github.com/pkg/errors"
"yunion.io/x/jsonutils"
)
type SProject struct {
Name string
CreateTime time.Time
LifecycleState string
ProjectId string
ProjectNumber string
}
func (cli *SGoogleClient) GetProject(id string) (*SProject, error) {
project := &SProject{}
return project, cli.get(id, project)
}
func (cli *SGoogleClient) GetProjects() ([]SProject, error) {
baseUrl := "https://cloudresourcemanager.googleapis.com/v1/projects"
nextPageToken := ""
result := []SProject{}
for {
url := baseUrl
if len(nextPageToken) > 0 {
url = fmt.Sprintf("%s?pageToken=%s", baseUrl, nextPageToken)
}
data, err := jsonRequest(cli.client, "GET", url, nil, cli.Debug)
if err != nil {
return nil, errors.Wrap(err, "JSONRequest")
}
_result := []SProject{}
if data.Contains("projects") {
err = data.Unmarshal(&_result, "projects")
if err != nil {
return nil, errors.Wrap(err, "data.Unmarshal")
}
}
result = append(result, _result...)
nextPageToken, _ = data.GetString("nextPageToken")
if len(nextPageToken) == 0 || len(_result) == 0 {
break
}
}
return result, nil
}
func (p *SProject) GetName() string {
return p.Name
}
func (p *SProject) GetId() string {
return p.ProjectId
}
func (p *SProject) GetGlobalId() string {
return p.ProjectId
}
func (p *SProject) GetStatus() string {
return ""
}
func (p *SProject) Refresh() error {
return nil
}
func (p *SProject) IsEmulated() bool {
return false
}
func (p *SProject) GetMetadata() *jsonutils.JSONDict {
return nil
}
+1
View File
@@ -0,0 +1 @@
package provider // import "yunion.io/x/onecloud/pkg/multicloud/google/provider"
+191
View File
@@ -0,0 +1,191 @@
// 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 provider
import (
"context"
"fmt"
"strings"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/multicloud/google"
)
type SGoogleProviderFactory struct {
cloudprovider.SPublicCloudBaseProviderFactor
}
func (self *SGoogleProviderFactory) GetId() string {
return google.CLOUD_PROVIDER_GOOGLE
}
func (self *SGoogleProviderFactory) GetName() string {
return google.CLOUD_PROVIDER_GOOGLE_CN
}
func (self *SGoogleProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error {
return nil
}
func (self *SGoogleProviderFactory) IsSupportPrepaidResources() bool {
return true
}
func (self *SGoogleProviderFactory) NeedSyncSkuFromCloud() bool {
return false
}
func (self *SGoogleProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input *api.CloudaccountCreateInput) error {
for key, value := range map[string]string{
"client_email": input.ClientEmail,
"project_id": input.ProjectId,
"private_key_id": input.PrivateKeyId,
"private_key": input.PrivateKey,
} {
if len(value) == 0 {
return httperrors.NewMissingParameterError(key)
}
}
input.Account = fmt.Sprintf("%s/%s", input.ProjectId, input.ClientEmail)
input.Secret = fmt.Sprintf("%s/%s", input.PrivateKeyId, input.PrivateKey)
return nil
}
func (self *SGoogleProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input *api.CloudaccountCredentialInput, cloudaccount string) (*cloudprovider.SCloudaccount, error) {
projectID, clientEmail := "", ""
accountInfo := strings.Split(cloudaccount, "/")
if len(accountInfo) == 2 {
projectID, clientEmail = accountInfo[0], accountInfo[1]
}
for key, value := range map[string]string{
"private_key_id": input.PrivateKeyId,
"private_key": input.PrivateKey,
} {
if len(value) == 0 {
return nil, httperrors.NewMissingParameterError(key)
}
}
if len(input.ClientEmail) == 0 {
input.ClientEmail = clientEmail
}
if len(input.ProjectId) == 0 {
input.ProjectId = projectID
}
account := &cloudprovider.SCloudaccount{
Account: fmt.Sprintf("%s/%s", input.ProjectId, input.ClientEmail),
Secret: fmt.Sprintf("%s/%s", input.PrivateKeyId, input.PrivateKey),
}
return account, nil
}
func (self *SGoogleProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) {
privateKeyID, privateKey := "", ""
privateKeyInfo := strings.Split(secret, "/")
if len(privateKeyInfo) < 2 {
return nil, fmt.Errorf("Missing privateKeyID or privateKey for google cloud")
}
privateKeyID = privateKeyInfo[0]
privateKey = strings.Join(privateKeyInfo[1:], "/")
projectID, clientEmail := "", ""
accountInfo := strings.Split(account, "/")
if len(accountInfo) < 2 {
return nil, fmt.Errorf("Invalid projectID or client email for google cloud %s", account)
}
projectID, clientEmail = accountInfo[0], accountInfo[1]
client, err := google.NewGoogleClient(providerId, providerName, projectID, clientEmail, privateKeyID, privateKey, false)
if err != nil {
return nil, err
}
return &SGoogleProvider{
SBaseProvider: cloudprovider.NewBaseProvider(self),
client: client,
}, nil
}
func (self *SGoogleProviderFactory) GetClientRC(url, account, secret string) (map[string]string, error) {
return map[string]string{
"ALIYUN_ACCESS_KEY": account,
"ALIYUN_SECRET": secret,
"ALIYUN_REGION": google.GOOGLE_DEFAULT_REGION,
}, nil
}
func init() {
factory := SGoogleProviderFactory{}
cloudprovider.RegisterFactory(&factory)
}
type SGoogleProvider struct {
cloudprovider.SBaseProvider
client *google.SGoogleClient
}
func (self *SGoogleProvider) GetSysInfo() (jsonutils.JSONObject, error) {
regions := self.client.GetIRegions()
info := jsonutils.NewDict()
info.Add(jsonutils.NewInt(int64(len(regions))), "region_count")
info.Add(jsonutils.NewString(google.GOOGLE_API_VERSION), "api_version")
return info, nil
}
func (self *SGoogleProvider) GetVersion() string {
return google.GOOGLE_API_VERSION
}
func (self *SGoogleProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
return self.client.GetSubAccounts()
}
func (self *SGoogleProvider) GetAccountId() string {
return self.client.GetAccountId()
}
func (self *SGoogleProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (self *SGoogleProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return self.client.GetIGlobalnetworks()
}
func (self *SGoogleProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return self.client.GetIGlobalnetworkById(id)
}
func (self *SGoogleProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(extId)
}
func (self *SGoogleProvider) GetBalance() (float64, string, error) {
return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported
}
func (self *SGoogleProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
return self.client.GetIProjects()
}
func (self *SGoogleProvider) GetStorageClasses(regionId string) []string {
return []string{
"Standard", "IA", "Archive",
}
}
+300
View File
@@ -0,0 +1,300 @@
// 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 google
import (
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SRegion struct {
cloudprovider.SFakeOnPremiseRegion
multicloud.SRegion
multicloud.SNoObjectStorageRegion
client *SGoogleClient
Description string
ID string
Kind string
Name string
Status string
SelfLink string
CreationTimestamp time.Time
}
func (region *SRegion) GetClient() *SGoogleClient {
return region.client
}
func (region *SRegion) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (region *SRegion) GetName() string {
if name, ok := RegionNames[region.Name]; ok {
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_GOOGLE_CN, name)
}
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_GOOGLE_CN, region.Name)
}
func (region *SRegion) GetId() string {
return region.Name
}
func (region *SRegion) GetGlobalId() string {
return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_GOOGLE, region.Name)
}
func (region *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
if geoInfo, ok := LatitudeAndLongitude[region.Name]; ok {
return geoInfo
}
return cloudprovider.SGeographicInfo{}
}
func (region *SRegion) GetProvider() string {
return CLOUD_PROVIDER_GOOGLE
}
func (region *SRegion) GetStatus() string {
if region.Status == "UP" {
return api.CLOUD_REGION_STATUS_INSERVER
}
return api.CLOUD_REGION_STATUS_OUTOFSERVICE
}
func (region *SRegion) IsEmulated() bool {
return false
}
func (region *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
zones, err := region.GetZones(region.Name, 0, "")
if err != nil {
return nil, err
}
izones := []cloudprovider.ICloudZone{}
for i := 0; i < len(zones); i++ {
zones[i].region = region
izones = append(izones, &zones[i])
}
return izones, nil
}
func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
zones, err := region.GetIZones()
if err != nil {
return nil, err
}
for i := range zones {
if zones[i].GetGlobalId() == id {
return zones[i], nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (region *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
globalnetworks, err := region.client.fetchGlobalNetwork()
if err != nil {
return nil, errors.Wrap(err, "fetchGlobalNetwork")
}
substr := fmt.Sprintf("regions/%s/subnetworks", region.Name)
ivpcs := []cloudprovider.ICloudVpc{}
for i := range globalnetworks {
for _, subnet := range globalnetworks[i].Subnetworks {
if strings.Index(subnet, substr) >= 0 {
vpc := SVpc{region: region, globalnetwork: &globalnetworks[i]}
ivpcs = append(ivpcs, &vpc)
}
}
}
return ivpcs, nil
}
func (region *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
ivpcs, err := region.GetIVpcs()
if err != nil {
return nil, err
}
for i := range ivpcs {
if ivpcs[i].GetGlobalId() == id {
return ivpcs[i], nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (region *SRegion) GetUrlPrefixWithProjectId() string {
return getUrlPrefix() + region.GetProjectId()
}
func (region *SRegion) GetProjectId() string {
return region.client.projectId
}
func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
eips, err := region.GetEips("", 0, "")
if err != nil {
return nil, err
}
ieips := []cloudprovider.ICloudEIP{}
for i := range eips {
eips[i].region = region
ieips = append(ieips, &eips[i])
}
return ieips, nil
}
func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
ivm, err := region.GetInstance(id)
if err != nil {
return nil, err
}
return ivm, nil
}
func (region *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
disk, err := region.GetDisk(id)
if err != nil {
return nil, err
}
return disk, nil
}
func (region *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) {
eip, err := region.GetEip(id)
if err != nil {
return nil, err
}
return eip, nil
}
func (region *SRegion) fetchSnapshots() error {
if len(region.client.snapshots) > 0 {
return nil
}
region.client.snapshots = map[string][]SSnapshot{}
snapshots, err := region.GetSnapshots("", 0, "")
if err != nil {
return err
}
regionNames := []string{}
for _, region := range region.client.iregions {
regionNames = append(regionNames, region.GetId())
}
for _, snapshot := range snapshots {
for _, location := range snapshot.StorageLocations {
_regionName := ""
if utils.IsInStringArray(location, regionNames) {
_regionName = location
} else {
for _, regionName := range regionNames {
if strings.HasPrefix(regionName, location) {
_regionName = regionName
break
}
}
}
if len(_regionName) > 0 {
if _, ok := region.client.snapshots[_regionName]; !ok {
region.client.snapshots[_regionName] = []SSnapshot{}
}
region.client.snapshots[_regionName] = append(region.client.snapshots[_regionName], snapshot)
break
}
}
}
return nil
}
func (region *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
region.fetchSnapshots()
isnapshots := []cloudprovider.ICloudSnapshot{}
if snapshots, ok := region.client.snapshots[region.Name]; ok {
for i := range snapshots {
snapshots[i].region = region
isnapshots = append(isnapshots, &snapshots[i])
}
}
return isnapshots, nil
}
func (region *SRegion) GetISnapshotById(id string) (cloudprovider.ICloudSnapshot, error) {
snapshot, err := region.GetSnapshot(id)
if err != nil {
return nil, err
}
return snapshot, nil
}
func (region *SRegion) ListAll(resource string, params map[string]string, retval interface{}) error {
return region.client.listAll(resource, params, retval)
}
func (region *SRegion) List(resource string, params map[string]string, maxResults int, pageToken string, retval interface{}) error {
return region.client.list(resource, params, maxResults, pageToken, retval)
}
func (region *SRegion) Get(id string, retval interface{}) error {
return region.client.get(id, retval)
}
func (region *SRegion) fetchResourcePolicies() ([]SResourcePolicy, error) {
if len(region.client.resourcepolices) > 0 {
return region.client.resourcepolices, nil
}
policies, err := region.GetResourcePolicies(0, "")
if err != nil {
return nil, err
}
region.client.resourcepolices = policies
return policies, nil
}
func (region *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) {
policies, err := region.fetchResourcePolicies()
if err != nil {
return nil, err
}
ipolicies := []cloudprovider.ICloudSnapshotPolicy{}
for i := range policies {
policies[i].region = region
if strings.Contains(region.Name, policies[i].SnapshotSchedulePolicy.SnapshotProperties.StorageLocations[0]) {
ipolicies = append(ipolicies, &policies[i])
}
}
return ipolicies, nil
}
func (region *SRegion) GetISnapshotPolicyById(id string) (cloudprovider.ICloudSnapshotPolicy, error) {
policy, err := region.GetResourcePolicy(id)
if err != nil {
return nil, err
}
if !strings.Contains(region.Name, policy.SnapshotSchedulePolicy.SnapshotProperties.StorageLocations[0]) {
return nil, cloudprovider.ErrNotFound
}
return policy, nil
}
+53
View File
@@ -0,0 +1,53 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google
import (
"fmt"
"time"
)
type SRegionDisk struct {
storage *SStorage
Id string
CreationTimestamp time.Time
Name string
SizeGB int
Zone string
Status string
SelfLink string
Type string
LastAttachTimestamp time.Time
LastDetachTimestamp time.Time
LabelFingerprint string
PhysicalBlockSizeBytes string
Kind string
}
func (region *SRegion) GetRegionDisks(storageType string, maxResults int, pageToken string) ([]SRegionDisk, error) {
disks := []SRegionDisk{}
params := map[string]string{}
if len(storageType) > 0 {
params["filter"] = fmt.Sprintf(`type="%s/regions/%s/diskTypes/%s"`, region.GetUrlPrefixWithProjectId(), region.Name, storageType)
}
resource := fmt.Sprintf("regions/%s/disks", region.Name)
return disks, region.List(resource, params, maxResults, pageToken, &disks)
}
func (region *SRegion) GetRegionDisk(id string) (*SRegionDisk, error) {
disk := &SRegionDisk{}
return disk, region.Get(id, disk)
}
+45
View File
@@ -0,0 +1,45 @@
// 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 google
import (
"fmt"
"time"
)
type SRegionStorage struct {
region *SRegion
CreationTimestamp time.Time
Name string
Description string
ValidDiskSize string
Zone string
SelfLink string
DefaultDiskSizeGb string
Kind string
}
func (region *SRegion) GetRegionStorages(maxResults int, pageToken string) ([]SRegionStorage, error) {
storages := []SRegionStorage{}
resource := fmt.Sprintf("regions/%s/diskTypes", region.Name)
params := map[string]string{}
return storages, region.List(resource, params, maxResults, pageToken, &storages)
}
func (region *SRegion) GetRegionStorage(id string) (*SRegionStorage, error) {
storage := &SRegionStorage{region: region}
return storage, region.Get(id, storage)
}
+177
View File
@@ -0,0 +1,177 @@
// 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 google
import (
"fmt"
"strconv"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
type SDailySchedule struct {
DaysInCycle int
StartTime string
Duration string
}
type SDayOfWeek struct {
Day string
StartTime string
Duration string
}
type SHourlySchedule struct {
HoursInCycle int
StartTime string
Duration string
}
type SWeeklySchedule struct {
DayOfWeeks []SDayOfWeek
}
type SSchedule struct {
WeeklySchedule SWeeklySchedule
DailySchedule SDailySchedule
HourlySchedule SHourlySchedule
}
type SRetentionPolicy struct {
MaxRetentionDays int
OnSourceDiskDelete string
}
type SSnapshotProperties struct {
StorageLocations []string
GuestFlush bool
}
type SSnapshotSchedulePolicy struct {
Schedule SSchedule
RetentionPolicy SRetentionPolicy
SnapshotProperties SSnapshotProperties
}
type SResourcePolicy struct {
region *SRegion
Id string
CreationTimestamp time.Time
SelfLink string
Region string
Name string
Status string
Kind string
SnapshotSchedulePolicy SSnapshotSchedulePolicy `json:"snapshotSchedulePolicy"`
}
func (region *SRegion) GetResourcePolicies(maxResults int, pageToken string) ([]SResourcePolicy, error) {
policies := []SResourcePolicy{}
resource := fmt.Sprintf("regions/%s/resourcePolicies", region.Name)
params := map[string]string{}
return policies, region.List(resource, params, maxResults, pageToken, &policies)
}
func (region *SRegion) GetResourcePolicy(id string) (*SResourcePolicy, error) {
policy := &SResourcePolicy{region: region}
return policy, region.Get(id, policy)
}
func (policy *SResourcePolicy) GetId() string {
return getGlobalId(policy.SelfLink)
}
func (policy *SResourcePolicy) GetGlobalId() string {
return policy.GetId()
}
func (policy *SResourcePolicy) GetName() string {
return policy.Name
}
func (policy *SResourcePolicy) GetStatus() string {
switch policy.Status {
case "READY":
return api.SNAPSHOT_POLICY_READY
default:
log.Errorf("unknown policy status %s", policy.Status)
return api.SNAPSHOT_POLICY_UNKNOWN
}
}
func (policy *SResourcePolicy) Refresh() error {
_policy, err := policy.region.GetResourcePolicy(policy.SelfLink)
if err != nil {
return err
}
return jsonutils.Update(policy, _policy)
}
func (policy *SResourcePolicy) IsEmulated() bool {
return false
}
func (policy *SResourcePolicy) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (policy *SResourcePolicy) GetProjectId() string {
return policy.region.GetProjectId()
}
func (policy *SResourcePolicy) GetRetentionDays() int {
return policy.SnapshotSchedulePolicy.RetentionPolicy.MaxRetentionDays
}
func (policy *SResourcePolicy) GetRepeatWeekdays() ([]int, error) {
result := []int{1, 2, 3, 4, 5, 6, 7}
if len(policy.SnapshotSchedulePolicy.Schedule.WeeklySchedule.DayOfWeeks) > 0 {
return nil, fmt.Errorf("current not support dayOfWeeks")
}
if policy.SnapshotSchedulePolicy.Schedule.HourlySchedule.HoursInCycle != 0 {
return nil, fmt.Errorf("current not support hourlySchedule")
}
return result, nil
}
func (policy *SResourcePolicy) GetTimePoints() ([]int, error) {
result := []int{}
if len(policy.SnapshotSchedulePolicy.Schedule.DailySchedule.StartTime) == 0 {
return nil, fmt.Errorf("current only support dailySchedule")
}
if startInfo := strings.Split(policy.SnapshotSchedulePolicy.Schedule.DailySchedule.StartTime, ":"); len(startInfo) >= 2 {
point, err := strconv.Atoi(startInfo[0])
if err != nil {
return nil, errors.Wrapf(err, "convert %s", policy.SnapshotSchedulePolicy.Schedule.DailySchedule.StartTime)
}
result = append(result, point)
if startInfo[1] != "00" {
result = append(result, point+1)
}
}
return result, nil
}
func (policy *SResourcePolicy) IsActivated() bool {
return true
}
+302
View File
@@ -0,0 +1,302 @@
// 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 google
import (
"fmt"
"net"
"sort"
"strconv"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/pkg/util/secrules"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SFirewallAction struct {
IPProtocol string
Ports []string
}
type SFirewall struct {
Id string
CreationTimestamp time.Time
Name string
Description string
Network string
Priority int
SourceRanges []string
TargetServiceAccounts []string
TargetTags []string
Allowed []SFirewallAction
Denied []SFirewallAction
Direction string
Disabled bool
SelfLink string
Kind string
}
type FirewallSet []SFirewall
func (f FirewallSet) Len() int {
return len(f)
}
func (f FirewallSet) Swap(i, j int) {
f[i], f[j] = f[j], f[i]
}
func (f FirewallSet) Less(i, j int) bool {
if f[i].Priority != f[j].Priority {
return f[i].Priority < f[j].Priority
}
return len(f[i].Allowed) < len(f[j].Allowed)
}
type SSecurityGroup struct {
vpc *SVpc
ServiceAccount string
Tag string
}
func (region *SRegion) GetFirewalls(network string, maxResults int, pageToken string) ([]SFirewall, error) {
firewalls := []SFirewall{}
params := map[string]string{"filter": "disabled = false"}
resource := "global/firewalls"
return firewalls, region.List(resource, params, maxResults, pageToken, &firewalls)
}
func (region *SRegion) GetFirewall(id string) (*SFirewall, error) {
firewall := &SFirewall{}
return firewall, region.Get(id, firewall)
}
func (firewall *SFirewall) _toRules(action secrules.TSecurityRuleAction) ([]secrules.SecurityRule, error) {
rules := []secrules.SecurityRule{}
list := firewall.Allowed
if action == secrules.SecurityRuleDeny {
list = firewall.Denied
}
for _, allow := range list {
rule := secrules.SecurityRule{
Action: action,
Direction: secrules.DIR_IN,
Description: firewall.Description,
Priority: firewall.Priority,
}
if firewall.Direction == "EGRESS" {
rule.Direction = secrules.DIR_OUT
}
switch allow.IPProtocol {
case "tcp", "udp", "icmp":
rule.Protocol = allow.IPProtocol
case "all":
rule.Protocol = secrules.PROTO_ANY
default:
return nil, fmt.Errorf("unsupport protocol %s", allow.IPProtocol)
}
for _, sourceRange := range firewall.SourceRanges {
if regutils.MatchCIDR(sourceRange) {
_, rule.IPNet, _ = net.ParseCIDR(sourceRange)
} else {
rule.IPNet = &net.IPNet{
IP: net.ParseIP(sourceRange),
Mask: net.CIDRMask(32, 32),
}
}
ports := []int{}
for _, port := range allow.Ports {
if strings.Index(port, "-") > 0 {
err := rule.ParsePorts(port)
if err != nil {
return nil, errors.Wrapf(err, "Parse port %s", port)
}
rules = append(rules, rule)
} else {
_port, err := strconv.Atoi(port)
if err != nil {
return nil, errors.Wrapf(err, "Atio port %s", port)
}
ports = append(ports, _port)
}
}
if len(ports) > 0 {
rule.Ports = ports
rule.PortStart = -1
rule.PortEnd = -1
rules = append(rules, rule)
}
}
}
return rules, nil
}
func (firewall *SFirewall) toRules() ([]secrules.SecurityRule, error) {
rules := []secrules.SecurityRule{}
_rules, err := firewall._toRules(secrules.SecurityRuleAllow)
if err != nil {
return nil, err
}
rules = append(rules, _rules...)
_rules, err = firewall._toRules(secrules.SecurityRuleDeny)
if err != nil {
return nil, err
}
rules = append(rules, _rules...)
return rules, nil
}
func (secgroup *SSecurityGroup) GetId() string {
return secgroup.vpc.globalnetwork.GetGlobalId()
}
func (secgroup *SSecurityGroup) GetGlobalId() string {
if len(secgroup.Tag) > 0 {
return fmt.Sprintf("%s/%s", secgroup.GetId(), secgroup.Tag)
}
if len(secgroup.ServiceAccount) > 0 {
return fmt.Sprintf("%s/%s", secgroup.GetId(), secgroup.ServiceAccount)
}
return secgroup.GetId()
}
func (secgroup *SSecurityGroup) GetDescription() string {
return ""
}
func (secgroup *SSecurityGroup) GetName() string {
if len(secgroup.Tag) > 0 {
return secgroup.Tag
}
if len(secgroup.ServiceAccount) > 0 {
return secgroup.ServiceAccount
}
return secgroup.vpc.globalnetwork.GetName()
}
func (secgroup *SSecurityGroup) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (secgroup *SSecurityGroup) GetStatus() string {
return ""
}
func (secgroup *SSecurityGroup) IsEmulated() bool {
return false
}
func (secgroup *SSecurityGroup) Refresh() error {
return nil
}
func (secgroup *SSecurityGroup) Delete() error {
return nil
}
func (secgroup *SSecurityGroup) GetProjectId() string {
return ""
}
func (secgroup *SSecurityGroup) GetVpcId() string {
return secgroup.vpc.GetGlobalId()
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
_firewalls, err := self.vpc.region.GetFirewalls(self.vpc.globalnetwork.SelfLink, 0, "")
if err != nil {
return nil, err
}
firewalls := []SFirewall{}
for _, firewall := range _firewalls {
if len(self.Tag) > 0 && utils.IsInStringArray(self.Tag, firewall.TargetTags) {
firewalls = append(firewalls, firewall)
} else if len(self.ServiceAccount) > 0 && utils.IsInStringArray(self.ServiceAccount, firewall.TargetServiceAccounts) {
firewalls = append(firewalls, firewall)
} else {
if len(self.Tag) == 0 && len(self.ServiceAccount) == 0 && len(firewall.TargetServiceAccounts) == 0 && len(firewall.TargetTags) == 0 {
firewalls = append(firewalls, firewall)
}
}
}
sort.Sort(FirewallSet(firewalls))
rules := []secrules.SecurityRule{}
priority := 100
for _, firewall := range firewalls {
firewall.Priority = priority
if priority > 2 {
priority--
}
_rules, err := firewall.toRules()
if err != nil {
return nil, err
}
rules = append(rules, _rules...)
}
return rules, nil
}
func (secgroup *SSecurityGroup) SyncRules(rules []secrules.SecurityRule) error {
return cloudprovider.ErrNotImplemented
}
func (region *SRegion) GetISecurityGroupById(id string) (cloudprovider.ICloudSecurityGroup, error) {
vpcs, err := region.GetIVpcs()
if err != nil {
return nil, errors.Wrap(err, "GetIVpcs")
}
for _, vpc := range vpcs {
secgroups, err := vpc.GetISecurityGroups()
if err != nil {
return nil, errors.Wrap(err, "GetISecurityGroups")
}
for _, secgroup := range secgroups {
if secgroup.GetGlobalId() == id {
return secgroup, nil
}
}
}
return nil, cloudprovider.ErrNotFound
}
func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudprovider.ICloudSecurityGroup, error) {
ivpc, err := region.GetIVpcById(vpcId)
if err != nil {
return nil, err
}
secgroups, err := ivpc.GetISecurityGroups()
if err != nil {
return nil, errors.Wrap(err, "ivpc.GetISecurityGroups")
}
for _, secgroup := range secgroups {
if secgroup.GetName() == name {
return secgroup, nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
return region.GetISecurityGroupByName(conf.VpcId, "")
}
+76
View File
@@ -0,0 +1,76 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type DiskListOptions struct {
ZONE string
StorageType string
MaxResults int
PageToken string
}
shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *google.SRegion, args *DiskListOptions) error {
disks, err := cli.GetDisks(args.ZONE, args.StorageType, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(disks, 0, 0, 0, nil)
return nil
})
type DiskShowOptions struct {
ID string
}
shellutils.R(&DiskShowOptions{}, "disk-show", "Show disk", func(cli *google.SRegion, args *DiskShowOptions) error {
disk, err := cli.GetDisk(args.ID)
if err != nil {
return err
}
printObject(disk)
return nil
})
type RegionDiskListOptions struct {
StorageType string
MaxResults int
PageToken string
}
shellutils.R(&RegionDiskListOptions{}, "region-disk-list", "List region disks", func(cli *google.SRegion, args *RegionDiskListOptions) error {
disks, err := cli.GetRegionDisks(args.StorageType, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(disks, 0, 0, 0, nil)
return nil
})
type RegionDiskShowOptions struct {
ID string
}
shellutils.R(&RegionDiskShowOptions{}, "region-disk-show", "Show region disk", func(cli *google.SRegion, args *RegionDiskShowOptions) error {
disk, err := cli.GetRegionDisk(args.ID)
if err != nil {
return err
}
printObject(disk)
return nil
})
}
+1
View File
@@ -0,0 +1 @@
package shell // import "yunion.io/x/onecloud/pkg/multicloud/google/shell"
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type EipListOptions struct {
Address string
MaxResults int
PageToken string
}
shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *google.SRegion, args *EipListOptions) error {
eips, err := cli.GetEips(args.Address, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(eips, 0, 0, 0, nil)
return nil
})
type EipShowOptions struct {
ID string
}
shellutils.R(&EipShowOptions{}, "eip-show", "Show eip", func(cli *google.SRegion, args *EipShowOptions) error {
eip, err := cli.GetEip(args.ID)
if err != nil {
return err
}
printObject(eip)
return nil
})
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type FirewallListOptions struct {
Network string
MaxResults int
PageToken string
}
shellutils.R(&FirewallListOptions{}, "firewall-list", "List firewalls", func(cli *google.SRegion, args *FirewallListOptions) error {
firewalls, err := cli.GetFirewalls(args.Network, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(firewalls, 0, 0, 0, nil)
return nil
})
type FirewallShowOptions struct {
ID string
}
shellutils.R(&FirewallShowOptions{}, "firewall-show", "Show firewall", func(cli *google.SRegion, args *FirewallShowOptions) error {
firewall, err := cli.GetFirewall(args.ID)
if err != nil {
return err
}
printObject(firewall)
return nil
})
}
@@ -0,0 +1,48 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type GlobalNetworkListOptions struct {
MaxResults int
PageToken string
}
shellutils.R(&GlobalNetworkListOptions{}, "global-network-list", "List globalnetworks", func(cli *google.SRegion, args *GlobalNetworkListOptions) error {
globalnetworks, err := cli.GetClient().GetGlobalNetworks(args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(globalnetworks, 0, 0, 0, nil)
return nil
})
type GlobalNetworkShowOptions struct {
ID string
}
shellutils.R(&GlobalNetworkShowOptions{}, "global-network-show", "Show globalnetwork", func(cli *google.SRegion, args *GlobalNetworkShowOptions) error {
globalnetwork, err := cli.GetClient().GetGlobalNetwork(args.ID)
if err != nil {
return err
}
printObject(globalnetwork)
return nil
})
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type ImageListOptions struct {
Project string
MaxResults int
PageToken string
}
shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *google.SRegion, args *ImageListOptions) error {
images, err := cli.GetImages(args.Project, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(images, 0, 0, 0, nil)
return nil
})
type ImageShowOptions struct {
ID string
}
shellutils.R(&ImageShowOptions{}, "image-show", "Show image", func(cli *google.SRegion, args *ImageShowOptions) error {
image, err := cli.GetImage(args.ID)
if err != nil {
return err
}
printObject(image)
return nil
})
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type InstanceListOptions struct {
ZONE string
MaxResults int
PageToken string
}
shellutils.R(&InstanceListOptions{}, "instance-list", "List instances", func(cli *google.SRegion, args *InstanceListOptions) error {
instances, err := cli.GetInstances(args.ZONE, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(instances, 0, 0, 0, nil)
return nil
})
type InstanceShowOptions struct {
ID string
}
shellutils.R(&InstanceShowOptions{}, "instance-show", "Show instance", func(cli *google.SRegion, args *InstanceShowOptions) error {
instance, err := cli.GetInstance(args.ID)
if err != nil {
return err
}
printObject(instance)
return nil
})
}
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type MachineTypeListOptions struct {
ZONE string
MaxResults int
PageToken string
}
shellutils.R(&MachineTypeListOptions{}, "machine-type-list", "List machinetypes", func(cli *google.SRegion, args *MachineTypeListOptions) error {
machinetypes, err := cli.GetMachineTypes(args.ZONE, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(machinetypes, 0, 0, 0, nil)
return nil
})
type MachineTypeShowOptions struct {
ID string
}
shellutils.R(&MachineTypeShowOptions{}, "machine-type-show", "Show machinetype", func(cli *google.SRegion, args *MachineTypeShowOptions) error {
machinetype, err := cli.GetMachineType(args.ID)
if err != nil {
return err
}
printObject(machinetype)
return nil
})
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type NetworkListOptions struct {
Network string
MaxResults int
PageToken string
}
shellutils.R(&NetworkListOptions{}, "network-list", "List networks", func(cli *google.SRegion, args *NetworkListOptions) error {
networks, err := cli.GetNetworks(args.Network, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(networks, 0, 0, 0, nil)
return nil
})
type NetworkShowOptions struct {
ID string
}
shellutils.R(&NetworkShowOptions{}, "network-show", "Show network", func(cli *google.SRegion, args *NetworkShowOptions) error {
network, err := cli.GetNetwork(args.ID)
if err != nil {
return err
}
printObject(network)
return nil
})
}
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import "yunion.io/x/onecloud/pkg/util/printutils"
func printList(data interface{}, total, offset, limit int, columns []string) {
printutils.PrintInterfaceList(data, total, offset, limit, columns)
}
func printObject(obj interface{}) {
printutils.PrintInterfaceObject(obj)
}
+35
View File
@@ -0,0 +1,35 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type ProjectListOptions struct {
MaxResults int
PageToken string
}
shellutils.R(&ProjectListOptions{}, "project-list", "List projects", func(cli *google.SRegion, args *ProjectListOptions) error {
projects, err := cli.GetClient().GetProjects()
if err != nil {
return err
}
printList(projects, 0, 0, 0, nil)
return nil
})
}
+30
View File
@@ -0,0 +1,30 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type RegionListOptions struct {
}
shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *google.SRegion, args *RegionListOptions) error {
regions := cli.GetClient().GetRegions()
printList(regions, 0, 0, 0, nil)
return nil
})
}
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type ResourcePolicyListOptions struct {
Disk string
MaxResults int
PageToken string
}
shellutils.R(&ResourcePolicyListOptions{}, "resource-policy-list", "List resourcepolicys", func(cli *google.SRegion, args *ResourcePolicyListOptions) error {
resourcepolicys, err := cli.GetResourcePolicies(args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(resourcepolicys, 0, 0, 0, nil)
return nil
})
type ResourcePolicyShowOptions struct {
ID string
}
shellutils.R(&ResourcePolicyShowOptions{}, "resource-policy-show", "Show resourcepolicy", func(cli *google.SRegion, args *ResourcePolicyShowOptions) error {
resourcepolicy, err := cli.GetResourcePolicy(args.ID)
if err != nil {
return err
}
printObject(resourcepolicy)
return nil
})
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type SnapshotListOptions struct {
Disk string
MaxResults int
PageToken string
}
shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshots", func(cli *google.SRegion, args *SnapshotListOptions) error {
snapshots, err := cli.GetSnapshots(args.Disk, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(snapshots, 0, 0, 0, nil)
return nil
})
type SnapshotShowOptions struct {
ID string
}
shellutils.R(&SnapshotShowOptions{}, "snapshot-show", "Show snapshot", func(cli *google.SRegion, args *SnapshotShowOptions) error {
snapshot, err := cli.GetSnapshot(args.ID)
if err != nil {
return err
}
printObject(snapshot)
return nil
})
}
+74
View File
@@ -0,0 +1,74 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type StorageListOptions struct {
ZONE string
MaxResults int
PageToken string
}
shellutils.R(&StorageListOptions{}, "storage-list", "List storages", func(cli *google.SRegion, args *StorageListOptions) error {
storages, err := cli.GetStorages(args.ZONE, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(storages, 0, 0, 0, nil)
return nil
})
type StorageShowOptions struct {
ID string
}
shellutils.R(&StorageShowOptions{}, "storage-show", "Show storage", func(cli *google.SRegion, args *StorageShowOptions) error {
storage, err := cli.GetStorage(args.ID)
if err != nil {
return err
}
printObject(storage)
return nil
})
type RegionStorageListOptions struct {
MaxResults int
PageToken string
}
shellutils.R(&RegionStorageListOptions{}, "region-storage-list", "List region storages", func(cli *google.SRegion, args *RegionStorageListOptions) error {
storages, err := cli.GetRegionStorages(args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(storages, 0, 0, 0, nil)
return nil
})
type RegionStorageShowOptions struct {
ID string
}
shellutils.R(&RegionStorageShowOptions{}, "region-storage-show", "Show region storage", func(cli *google.SRegion, args *RegionStorageShowOptions) error {
storage, err := cli.GetRegionStorage(args.ID)
if err != nil {
return err
}
printObject(storage)
return nil
})
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/multicloud/google"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type ZoneListOptions struct {
RegionId string
MaxResults int
PageToken string
}
shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *google.SRegion, args *ZoneListOptions) error {
zones, err := cli.GetZones(args.RegionId, args.MaxResults, args.PageToken)
if err != nil {
return err
}
printList(zones, 0, 0, 0, nil)
return nil
})
type ZoneShowOptions struct {
ID string
}
shellutils.R(&ZoneShowOptions{}, "zone-show", "Show zones", func(cli *google.SRegion, args *ZoneShowOptions) error {
zone, err := cli.GetZone(args.ID)
if err != nil {
return err
}
printObject(zone)
return nil
})
}
+127
View File
@@ -0,0 +1,127 @@
// 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 google
import (
"fmt"
"time"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SSnapshot struct {
region *SRegion
Id string
CreationTimestamp time.Time
Name string
Status string
SourceDisk string
SourceDiskId string
DiskSizeGb int32
StorageBytes int
StorageBytesStatus string
Licenses []string
SelfLink string
LabelFingerprint string
LicenseCodes []string
StorageLocations []string
Kind string
}
func (region *SRegion) GetSnapshots(disk string, maxResults int, pageToken string) ([]SSnapshot, error) {
snapshots := []SSnapshot{}
params := map[string]string{}
if len(disk) > 0 {
params["filter"] = fmt.Sprintf(`sourceDisk="%s"`, disk)
}
resource := "global/snapshots"
return snapshots, region.List(resource, params, maxResults, pageToken, &snapshots)
}
func (region *SRegion) GetSnapshot(id string) (*SSnapshot, error) {
snapshot := &SSnapshot{region: region}
return snapshot, region.Get(id, snapshot)
}
func (snapshot *SSnapshot) GetId() string {
return snapshot.SelfLink
}
func (snapshot *SSnapshot) GetGlobalId() string {
return getGlobalId(snapshot.SelfLink)
}
func (snapshot *SSnapshot) GetName() string {
return snapshot.Name
}
//CREATING, DELETING, FAILED, READY, or UPLOADING
func (snapshot *SSnapshot) GetStatus() string {
switch snapshot.Status {
case "CREATING":
return api.SNAPSHOT_CREATING
case "DELETING":
return api.SNAPSHOT_DELETING
case "FAILED":
return api.SNAPSHOT_UNKNOWN
case "READY", "UPLOADING":
return api.SNAPSHOT_READY
default:
return api.SNAPSHOT_UNKNOWN
}
}
func (snapshot *SSnapshot) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (snapshot *SSnapshot) IsEmulated() bool {
return false
}
func (snapshot *SSnapshot) Refresh() error {
_snapshot, err := snapshot.region.GetSnapshot(snapshot.SelfLink)
if err != nil {
return err
}
return jsonutils.Update(snapshot, _snapshot)
}
func (snapshot *SSnapshot) GetSizeMb() int32 {
return snapshot.DiskSizeGb * 1024
}
func (snapshot *SSnapshot) GetDiskId() string {
return snapshot.SourceDisk
}
func (snapshot *SSnapshot) GetDiskType() string {
if len(snapshot.Licenses) > 0 {
return api.DISK_TYPE_SYS
}
return api.DISK_TYPE_DATA
}
func (snapshot *SSnapshot) Delete() error {
return cloudprovider.ErrNotImplemented
}
func (snapshot *SSnapshot) GetProjectId() string {
return snapshot.region.GetProjectId()
}
+145
View File
@@ -0,0 +1,145 @@
// 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 google
import (
"fmt"
"time"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SStorage struct {
zone *SZone
CreationTimestamp time.Time
Name string
Description string
ValidDiskSize string
Zone string
SelfLink string
DefaultDiskSizeGb string
Kind string
}
func (region *SRegion) GetStorages(zone string, maxResults int, pageToken string) ([]SStorage, error) {
storages := []SStorage{}
if len(zone) == 0 {
return nil, fmt.Errorf("zone params can not be empty")
}
resource := fmt.Sprintf("zones/%s/diskTypes", zone)
params := map[string]string{}
return storages, region.List(resource, params, maxResults, pageToken, &storages)
}
func (region *SRegion) GetStorage(id string) (*SStorage, error) {
storage := &SStorage{}
return storage, region.Get(id, storage)
}
func (storage *SStorage) GetId() string {
return getGlobalId(storage.SelfLink)
}
func (storage *SStorage) GetGlobalId() string {
return storage.GetId()
}
func (storage *SStorage) GetName() string {
return storage.Description
}
func (storage *SStorage) GetStatus() string {
return api.STORAGE_ONLINE
}
func (storage *SStorage) IsEmulated() bool {
return true
}
func (storage *SStorage) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (storage *SStorage) Refresh() error {
_storage, err := storage.zone.region.GetStorage(storage.SelfLink)
if err != nil {
return err
}
return jsonutils.Update(storage, _storage)
}
func (storage *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache {
return storage.zone.region.getStoragecache()
}
func (storage *SStorage) GetIZone() cloudprovider.ICloudZone {
return storage.zone
}
func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
disks, err := storage.zone.region.GetDisks(storage.zone.Name, storage.Name, 0, "")
if err != nil {
return nil, err
}
idisks := []cloudprovider.ICloudDisk{}
for i := range disks {
disks[i].storage = storage
idisks = append(idisks, &disks[i])
}
return idisks, nil
}
func (storage *SStorage) GetStorageType() string {
return storage.Name
}
func (storage *SStorage) GetMediumType() string {
return api.DISK_TYPE_SSD
}
func (storage *SStorage) GetCapacityMB() int64 {
return 0
}
func (storage *SStorage) GetStorageConf() jsonutils.JSONObject {
return jsonutils.Marshal(map[string]string{
"ValidDiskSize": storage.ValidDiskSize,
"DefaultDiskSizeGb": storage.DefaultDiskSizeGb,
})
}
func (storage *SStorage) GetEnabled() bool {
return true
}
func (storage *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
return nil, cloudprovider.ErrNotFound
}
func (storage *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (storage *SStorage) GetMountPoint() string {
return ""
}
func (storage *SStorage) IsSysDiskStore() bool {
return storage.Name != api.STORAGE_GOOGLE_LOCAL_STORAGE
}
+123
View File
@@ -0,0 +1,123 @@
// 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 google
import (
"context"
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SStoragecache struct {
region *SRegion
iimages []cloudprovider.ICloudImage
}
func (cache *SStoragecache) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (cache *SStoragecache) GetId() string {
return fmt.Sprintf("%s-%s", cache.region.client.providerId, cache.region.GetId())
}
func (cache *SStoragecache) GetName() string {
return fmt.Sprintf("%s-%s", cache.region.client.providerName, cache.region.GetId())
}
func (cache *SStoragecache) GetStatus() string {
return "available"
}
func (cache *SStoragecache) Refresh() error {
return nil
}
func (cache *SStoragecache) GetGlobalId() string {
return fmt.Sprintf("%s-%s", cache.region.client.providerId, cache.region.GetGlobalId())
}
func (cache *SStoragecache) IsEmulated() bool {
return true
}
func (cache *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) {
images, err := cache.region.fetchImages()
if err != nil {
return nil, err
}
iimages := []cloudprovider.ICloudImage{}
for i := range images {
images[i].storagecache = cache
iimages = append(iimages, &images[i])
}
return iimages, nil
}
func (cache *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) {
image, err := cache.region.GetImage(extId)
if err != nil {
return nil, err
}
return image, nil
}
func (cache *SStoragecache) GetPath() string {
return ""
}
func (cache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, isForce bool) (string, error) {
return "", cloudprovider.ErrNotImplemented
}
func (cache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (cache *SRegion) CheckBucket(bucketName string) (*oss.Bucket, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (cache *SRegion) CreateImage(snapshoutId, imageName, imageDesc string) (string, error) {
return "", cloudprovider.ErrNotImplemented
}
func (cache *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) {
cache := &SStoragecache{region: region}
return []cloudprovider.ICloudStoragecache{cache}, nil
}
func (region *SRegion) getStoragecache() cloudprovider.ICloudStoragecache {
return &SStoragecache{region: region}
}
func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) {
cache := region.getStoragecache()
if id == cache.GetGlobalId() {
return cache, nil
}
return nil, cloudprovider.ErrNotFound
}
+122
View File
@@ -0,0 +1,122 @@
// 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 google
import (
"fmt"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
type SVpc struct {
multicloud.SVpc
globalnetwork *SGlobalNetwork
region *SRegion
}
func (vpc *SVpc) GetName() string {
return fmt.Sprintf("%s(%s)", vpc.globalnetwork.Name, vpc.region.Name)
}
func (vpc *SVpc) GetId() string {
return getGlobalId(vpc.globalnetwork.SelfLink)
}
func (vpc *SVpc) GetGlobalId() string {
return vpc.GetId()
}
func (vpc *SVpc) Refresh() error {
return nil
}
func (vpc *SVpc) GetStatus() string {
return api.VPC_STATUS_AVAILABLE
}
func (vpc *SVpc) Delete() error {
return cloudprovider.ErrNotSupported
}
func (vpc *SVpc) GetCidrBlock() string {
return ""
}
func (vpc *SVpc) GetIGlobalNetworkId() string {
return vpc.globalnetwork.GetGlobalId()
}
func (vpc *SVpc) IsEmulated() bool {
return false
}
func (vpc *SVpc) GetIsDefault() bool {
return false
}
func (vpc *SVpc) GetRegion() cloudprovider.ICloudRegion {
return vpc.region
}
func (vpc *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (vpc *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) {
firewalls, err := vpc.region.GetFirewalls(vpc.globalnetwork.SelfLink, 0, "")
if err != nil {
return nil, errors.Wrap(err, "GetFirewalls")
}
isecgroups := []cloudprovider.ICloudSecurityGroup{}
tags := []string{}
allInstance := false
for _, firewall := range firewalls {
if len(firewall.TargetServiceAccounts) > 0 {
secgroup := &SSecurityGroup{vpc: vpc, ServiceAccount: firewall.TargetServiceAccounts[0]}
isecgroups = append(isecgroups, secgroup)
} else if len(firewall.TargetTags) > 0 && !utils.IsInStringArray(firewall.TargetTags[0], tags) {
secgroup := &SSecurityGroup{vpc: vpc, Tag: firewall.TargetTags[0]}
tags = append(tags, firewall.TargetTags[0])
isecgroups = append(isecgroups, secgroup)
} else if !allInstance {
secgroup := &SSecurityGroup{vpc: vpc}
isecgroups = append(isecgroups, secgroup)
allInstance = true
}
}
return isecgroups, nil
}
func (vpc *SVpc) getWire() *SWire {
return &SWire{vpc: vpc}
}
func (vpc *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) {
wire := vpc.getWire()
return []cloudprovider.ICloudWire{wire}, nil
}
func (vpc *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) {
if id != vpc.getWire().GetGlobalId() {
return nil, cloudprovider.ErrNotFound
}
return &SWire{vpc: vpc}, nil
}
+96
View File
@@ -0,0 +1,96 @@
// 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 google
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SWire struct {
vpc *SVpc
}
func (wire *SWire) GetId() string {
return wire.vpc.GetGlobalId()
}
func (wire *SWire) GetGlobalId() string {
return fmt.Sprintf("%s-%s", getGlobalId(wire.GetId()), wire.vpc.region.Name)
}
func (wire *SWire) GetName() string {
return wire.vpc.GetName()
}
func (wire *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (wire *SWire) GetIVpc() cloudprovider.ICloudVpc {
return wire.vpc
}
func (wire *SWire) GetIZone() cloudprovider.ICloudZone {
return nil
}
func (wire *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) {
networks, err := wire.vpc.region.GetNetworks(wire.vpc.globalnetwork.SelfLink, 0, "")
if err != nil {
return nil, err
}
inetworks := []cloudprovider.ICloudNetwork{}
for i := range networks {
networks[i].wire = wire
inetworks = append(inetworks, &networks[i])
}
return inetworks, nil
}
func (wire *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) {
network, err := wire.vpc.region.GetNetwork(id)
if err != nil {
return nil, err
}
if network.Network != wire.vpc.globalnetwork.SelfLink {
return nil, cloudprovider.ErrNotFound
}
network.wire = wire
return network, nil
}
func (wire *SWire) GetBandwidth() int {
return 0
}
func (wire *SWire) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (wire *SWire) GetStatus() string {
return "available"
}
func (wire *SWire) IsEmulated() bool {
return false
}
func (wire *SWire) Refresh() error {
return nil
}
+125
View File
@@ -0,0 +1,125 @@
// 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 google
import (
"fmt"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SZone struct {
region *SRegion
Description string
ID string
Kind string
Name string
Region string
SelfLink string
AvailableCpuPlatforms []string
Status string
}
func (region *SRegion) GetZone(id string) (*SZone, error) {
zone := &SZone{}
return zone, region.Get(id, zone)
}
func (region *SRegion) GetZones(regionId string, maxResults int, pageToken string) ([]SZone, error) {
zones := []SZone{}
params := map[string]string{}
if len(regionId) > 0 {
params["filter"] = fmt.Sprintf(`region="%s/regions/%s"`, region.GetUrlPrefixWithProjectId(), regionId)
}
resource := "zones"
return zones, region.List(resource, params, maxResults, pageToken, &zones)
}
func (zone *SZone) GetName() string {
return zone.Name
}
func (zone *SZone) GetGlobalId() string {
return zone.GetId()
}
func (zone *SZone) GetId() string {
return fmt.Sprintf("%s/%s", zone.region.GetGlobalId(), zone.Name)
}
func (zone *SZone) GetIHostById(hostId string) (cloudprovider.ICloudHost, error) {
if hostId != zone.getHost().GetGlobalId() {
return nil, cloudprovider.ErrNotFound
}
return &SHost{zone: zone}, nil
}
func (zone *SZone) getHost() *SHost {
return &SHost{zone: zone}
}
func (zone *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) {
host := zone.getHost()
return []cloudprovider.ICloudHost{host}, nil
}
func (zone *SZone) GetIRegion() cloudprovider.ICloudRegion {
return zone.region
}
func (zone *SZone) GetIStorageById(storageId string) (cloudprovider.ICloudStorage, error) {
storage, err := zone.region.GetStorage(storageId)
if err != nil {
return nil, err
}
storage.zone = zone
return storage, nil
}
func (zone *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
storages, err := zone.region.GetStorages(zone.Name, 0, "")
if err != nil {
return nil, err
}
istorages := []cloudprovider.ICloudStorage{}
for i := range storages {
storages[i].zone = zone
istorages = append(istorages, &storages[i])
}
return istorages, nil
}
func (zone *SZone) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (zone *SZone) IsEmulated() bool {
return true
}
func (zone *SZone) Refresh() error {
return nil
}
func (zone *SZone) GetStatus() string {
if zone.Status == "UP" {
return api.ZONE_ENABLE
}
return api.ZONE_SOLDOUT
}
@@ -145,6 +145,14 @@ func (self *SHuaweiProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (cli *SHuaweiProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (cli *SHuaweiProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SHuaweiProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(extId)
}
+2 -1
View File
@@ -20,7 +20,8 @@ import (
_ "yunion.io/x/onecloud/pkg/multicloud/aliyun/provider"
_ "yunion.io/x/onecloud/pkg/multicloud/aws/provider"
_ "yunion.io/x/onecloud/pkg/multicloud/azure/provider"
_ "yunion.io/x/onecloud/pkg/multicloud/esxi/provider" // private clouds
_ "yunion.io/x/onecloud/pkg/multicloud/esxi/provider" // private clouds
_ "yunion.io/x/onecloud/pkg/multicloud/google/provider" // public clouds
_ "yunion.io/x/onecloud/pkg/multicloud/huawei/provider"
_ "yunion.io/x/onecloud/pkg/multicloud/objectstore/ceph/provider"
_ "yunion.io/x/onecloud/pkg/multicloud/objectstore/provider"
@@ -114,6 +114,14 @@ func (self *SObjectStoreProvider) GetIRegions() []cloudprovider.ICloudRegion {
return nil
}
func (self *SObjectStoreProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (self *SObjectStoreProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SObjectStoreProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
return nil, cloudprovider.ErrNotSupported
}
@@ -170,6 +170,14 @@ func (self *SOpenStackProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (self *SOpenStackProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (self *SOpenStackProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SOpenStackProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(extId)
}
@@ -161,6 +161,14 @@ func (self *SQcloudProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (client *SQcloudProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (client *SQcloudProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SQcloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(id)
}
+40
View File
@@ -23,6 +23,46 @@ import (
type SRegion struct{}
func (r *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
return nil, fmt.Errorf("Not Implement GetIDiskById")
}
func (r *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
return nil, fmt.Errorf("Not Implement GetIHostById")
}
func (r *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) {
return nil, fmt.Errorf("Not Implement GetIHosts")
}
func (r *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
return nil, fmt.Errorf("Not Implement GetISnapshotById")
}
func (r *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
return nil, fmt.Errorf("Not Implement GetISnapshots")
}
func (r *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
return nil, fmt.Errorf("Not Implement GetIStorageById")
}
func (r *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) {
return nil, fmt.Errorf("Not Implement GetIStoragecacheById")
}
func (r *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) {
return nil, fmt.Errorf("Not Implement GetIStoragecaches")
}
func (r *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
return nil, fmt.Errorf("Not Implement GetIStorages")
}
func (r *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
return nil, fmt.Errorf("Not Implement GetIVMById")
}
func (r *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput) (string, error) {
return "", fmt.Errorf("CreateSnapshotPolicy not implement")
}
@@ -149,6 +149,14 @@ func (self *SUcloudProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (cli *SUcloudProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (cli *SUcloudProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SUcloudProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(extId)
}
+4
View File
@@ -27,3 +27,7 @@ type SVpc struct {
func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) {
return nil, fmt.Errorf("Not Implemented GetNatGateways")
}
func (self *SVpc) GetIGlobalNetworkId() string {
return ""
}
@@ -124,6 +124,14 @@ func (self *SZStackProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (cli *SZStackProvider) GetIGlobalnetworks() ([]cloudprovider.ICloudGlobalnetwork, error) {
return []cloudprovider.ICloudGlobalnetwork{}, nil
}
func (cli *SZStackProvider) GetIGlobalnetworkById(id string) (cloudprovider.ICloudGlobalnetwork, error) {
return nil, cloudprovider.ErrNotFound
}
func (self *SZStackProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(extId)
}
+15
View File
@@ -0,0 +1,15 @@
# This is the official list of cloud authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as:
# Name or Organization <email address>
# The email address is not required for organizations.
Filippo Valsorda <hi@filippo.io>
Google Inc.
Ingo Oeser <nightlyone@googlemail.com>
Palm Stone Games, Inc.
Paweł Knap <pawelknap88@gmail.com>
Péter Szilágyi <peterke@gmail.com>
Tyler Treat <ttreat31@gmail.com>
+40
View File
@@ -0,0 +1,40 @@
# People who have agreed to one of the CLAs and can contribute patches.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# https://developers.google.com/open-source/cla/individual
# https://developers.google.com/open-source/cla/corporate
#
# Names should be added to this file as:
# Name <email address>
# Keep the list alphabetically sorted.
Alexis Hunt <lexer@google.com>
Andreas Litt <andreas.litt@gmail.com>
Andrew Gerrand <adg@golang.org>
Brad Fitzpatrick <bradfitz@golang.org>
Burcu Dogan <jbd@google.com>
Dave Day <djd@golang.org>
David Sansome <me@davidsansome.com>
David Symonds <dsymonds@golang.org>
Filippo Valsorda <hi@filippo.io>
Glenn Lewis <gmlewis@google.com>
Ingo Oeser <nightlyone@googlemail.com>
James Hall <james.hall@shopify.com>
Johan Euphrosine <proppy@google.com>
Jonathan Amsterdam <jba@google.com>
Kunpei Sakai <namusyaka@gmail.com>
Luna Duclos <luna.duclos@palmstonegames.com>
Magnus Hiie <magnus.hiie@gmail.com>
Mario Castro <mariocaster@gmail.com>
Michael McGreevy <mcgreevy@golang.org>
Omar Jarjur <ojarjur@google.com>
Paweł Knap <pawelknap88@gmail.com>
Péter Szilágyi <peterke@gmail.com>
Sarah Adams <shadams@google.com>
Thanatat Tamtan <acoshift@gmail.com>
Toby Burress <kurin@google.com>
Tuo Shan <shantuo@google.com>
Tyler Treat <ttreat31@gmail.com>
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+513
View File
@@ -0,0 +1,513 @@
// Copyright 2014 Google LLC
//
// 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 metadata provides access to Google Compute Engine (GCE)
// metadata and API service accounts.
//
// This package is a wrapper around the GCE metadata service,
// as documented at https://developers.google.com/compute/docs/metadata.
package metadata // import "cloud.google.com/go/compute/metadata"
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"runtime"
"strings"
"sync"
"time"
)
const (
// metadataIP is the documented metadata server IP address.
metadataIP = "169.254.169.254"
// metadataHostEnv is the environment variable specifying the
// GCE metadata hostname. If empty, the default value of
// metadataIP ("169.254.169.254") is used instead.
// This is variable name is not defined by any spec, as far as
// I know; it was made up for the Go package.
metadataHostEnv = "GCE_METADATA_HOST"
userAgent = "gcloud-golang/0.1"
)
type cachedValue struct {
k string
trim bool
mu sync.Mutex
v string
}
var (
projID = &cachedValue{k: "project/project-id", trim: true}
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
instID = &cachedValue{k: "instance/id", trim: true}
)
var (
defaultClient = &Client{hc: &http.Client{
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: 2 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
ResponseHeaderTimeout: 2 * time.Second,
},
}}
subscribeClient = &Client{hc: &http.Client{
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: 2 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
},
}}
)
// NotDefinedError is returned when requested metadata is not defined.
//
// The underlying string is the suffix after "/computeMetadata/v1/".
//
// This error is not returned if the value is defined to be the empty
// string.
type NotDefinedError string
func (suffix NotDefinedError) Error() string {
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
}
func (c *cachedValue) get(cl *Client) (v string, err error) {
defer c.mu.Unlock()
c.mu.Lock()
if c.v != "" {
return c.v, nil
}
if c.trim {
v, err = cl.getTrimmed(c.k)
} else {
v, err = cl.Get(c.k)
}
if err == nil {
c.v = v
}
return
}
var (
onGCEOnce sync.Once
onGCE bool
)
// OnGCE reports whether this process is running on Google Compute Engine.
func OnGCE() bool {
onGCEOnce.Do(initOnGCE)
return onGCE
}
func initOnGCE() {
onGCE = testOnGCE()
}
func testOnGCE() bool {
// The user explicitly said they're on GCE, so trust them.
if os.Getenv(metadataHostEnv) != "" {
return true
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
resc := make(chan bool, 2)
// Try two strategies in parallel.
// See https://github.com/googleapis/google-cloud-go/issues/194
go func() {
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
req.Header.Set("User-Agent", userAgent)
res, err := defaultClient.hc.Do(req.WithContext(ctx))
if err != nil {
resc <- false
return
}
defer res.Body.Close()
resc <- res.Header.Get("Metadata-Flavor") == "Google"
}()
go func() {
addrs, err := net.LookupHost("metadata.google.internal")
if err != nil || len(addrs) == 0 {
resc <- false
return
}
resc <- strsContains(addrs, metadataIP)
}()
tryHarder := systemInfoSuggestsGCE()
if tryHarder {
res := <-resc
if res {
// The first strategy succeeded, so let's use it.
return true
}
// Wait for either the DNS or metadata server probe to
// contradict the other one and say we are running on
// GCE. Give it a lot of time to do so, since the system
// info already suggests we're running on a GCE BIOS.
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
select {
case res = <-resc:
return res
case <-timer.C:
// Too slow. Who knows what this system is.
return false
}
}
// There's no hint from the system info that we're running on
// GCE, so use the first probe's result as truth, whether it's
// true or false. The goal here is to optimize for speed for
// users who are NOT running on GCE. We can't assume that
// either a DNS lookup or an HTTP request to a blackholed IP
// address is fast. Worst case this should return when the
// metaClient's Transport.ResponseHeaderTimeout or
// Transport.Dial.Timeout fires (in two seconds).
return <-resc
}
// systemInfoSuggestsGCE reports whether the local system (without
// doing network requests) suggests that we're running on GCE. If this
// returns true, testOnGCE tries a bit harder to reach its metadata
// server.
func systemInfoSuggestsGCE() bool {
if runtime.GOOS != "linux" {
// We don't have any non-Linux clues available, at least yet.
return false
}
slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
name := strings.TrimSpace(string(slurp))
return name == "Google" || name == "Google Compute Engine"
}
// Subscribe calls Client.Subscribe on a client designed for subscribing (one with no
// ResponseHeaderTimeout).
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
return subscribeClient.Subscribe(suffix, fn)
}
// Get calls Client.Get on the default client.
func Get(suffix string) (string, error) { return defaultClient.Get(suffix) }
// ProjectID returns the current instance's project ID string.
func ProjectID() (string, error) { return defaultClient.ProjectID() }
// NumericProjectID returns the current instance's numeric project ID.
func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() }
// InternalIP returns the instance's primary internal IP address.
func InternalIP() (string, error) { return defaultClient.InternalIP() }
// ExternalIP returns the instance's primary external (public) IP address.
func ExternalIP() (string, error) { return defaultClient.ExternalIP() }
// Hostname returns the instance's hostname. This will be of the form
// "<instanceID>.c.<projID>.internal".
func Hostname() (string, error) { return defaultClient.Hostname() }
// InstanceTags returns the list of user-defined instance tags,
// assigned when initially creating a GCE instance.
func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() }
// InstanceID returns the current VM's numeric instance ID.
func InstanceID() (string, error) { return defaultClient.InstanceID() }
// InstanceName returns the current VM's instance ID string.
func InstanceName() (string, error) { return defaultClient.InstanceName() }
// Zone returns the current VM's zone, such as "us-central1-b".
func Zone() (string, error) { return defaultClient.Zone() }
// InstanceAttributes calls Client.InstanceAttributes on the default client.
func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() }
// ProjectAttributes calls Client.ProjectAttributes on the default client.
func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() }
// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client.
func InstanceAttributeValue(attr string) (string, error) {
return defaultClient.InstanceAttributeValue(attr)
}
// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client.
func ProjectAttributeValue(attr string) (string, error) {
return defaultClient.ProjectAttributeValue(attr)
}
// Scopes calls Client.Scopes on the default client.
func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) }
func strsContains(ss []string, s string) bool {
for _, v := range ss {
if v == s {
return true
}
}
return false
}
// A Client provides metadata.
type Client struct {
hc *http.Client
}
// NewClient returns a Client that can be used to fetch metadata. All HTTP requests
// will use the given http.Client instead of the default client.
func NewClient(c *http.Client) *Client {
return &Client{hc: c}
}
// getETag returns a value from the metadata service as well as the associated ETag.
// This func is otherwise equivalent to Get.
func (c *Client) getETag(suffix string) (value, etag string, err error) {
// Using a fixed IP makes it very difficult to spoof the metadata service in
// a container, which is an important use-case for local testing of cloud
// deployments. To enable spoofing of the metadata service, the environment
// variable GCE_METADATA_HOST is first inspected to decide where metadata
// requests shall go.
host := os.Getenv(metadataHostEnv)
if host == "" {
// Using 169.254.169.254 instead of "metadata" here because Go
// binaries built with the "netgo" tag and without cgo won't
// know the search suffix for "metadata" is
// ".google.internal", and this IP address is documented as
// being stable anyway.
host = metadataIP
}
u := "http://" + host + "/computeMetadata/v1/" + suffix
req, _ := http.NewRequest("GET", u, nil)
req.Header.Set("Metadata-Flavor", "Google")
req.Header.Set("User-Agent", userAgent)
res, err := c.hc.Do(req)
if err != nil {
return "", "", err
}
defer res.Body.Close()
if res.StatusCode == http.StatusNotFound {
return "", "", NotDefinedError(suffix)
}
all, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", "", err
}
if res.StatusCode != 200 {
return "", "", &Error{Code: res.StatusCode, Message: string(all)}
}
return string(all), res.Header.Get("Etag"), nil
}
// Get returns a value from the metadata service.
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
//
// If the GCE_METADATA_HOST environment variable is not defined, a default of
// 169.254.169.254 will be used instead.
//
// If the requested metadata is not defined, the returned error will
// be of type NotDefinedError.
func (c *Client) Get(suffix string) (string, error) {
val, _, err := c.getETag(suffix)
return val, err
}
func (c *Client) getTrimmed(suffix string) (s string, err error) {
s, err = c.Get(suffix)
s = strings.TrimSpace(s)
return
}
func (c *Client) lines(suffix string) ([]string, error) {
j, err := c.Get(suffix)
if err != nil {
return nil, err
}
s := strings.Split(strings.TrimSpace(j), "\n")
for i := range s {
s[i] = strings.TrimSpace(s[i])
}
return s, nil
}
// ProjectID returns the current instance's project ID string.
func (c *Client) ProjectID() (string, error) { return projID.get(c) }
// NumericProjectID returns the current instance's numeric project ID.
func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) }
// InstanceID returns the current VM's numeric instance ID.
func (c *Client) InstanceID() (string, error) { return instID.get(c) }
// InternalIP returns the instance's primary internal IP address.
func (c *Client) InternalIP() (string, error) {
return c.getTrimmed("instance/network-interfaces/0/ip")
}
// ExternalIP returns the instance's primary external (public) IP address.
func (c *Client) ExternalIP() (string, error) {
return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
}
// Hostname returns the instance's hostname. This will be of the form
// "<instanceID>.c.<projID>.internal".
func (c *Client) Hostname() (string, error) {
return c.getTrimmed("instance/hostname")
}
// InstanceTags returns the list of user-defined instance tags,
// assigned when initially creating a GCE instance.
func (c *Client) InstanceTags() ([]string, error) {
var s []string
j, err := c.Get("instance/tags")
if err != nil {
return nil, err
}
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
return nil, err
}
return s, nil
}
// InstanceName returns the current VM's instance ID string.
func (c *Client) InstanceName() (string, error) {
host, err := c.Hostname()
if err != nil {
return "", err
}
return strings.Split(host, ".")[0], nil
}
// Zone returns the current VM's zone, such as "us-central1-b".
func (c *Client) Zone() (string, error) {
zone, err := c.getTrimmed("instance/zone")
// zone is of the form "projects/<projNum>/zones/<zoneName>".
if err != nil {
return "", err
}
return zone[strings.LastIndex(zone, "/")+1:], nil
}
// InstanceAttributes returns the list of user-defined attributes,
// assigned when initially creating a GCE VM instance. The value of an
// attribute can be obtained with InstanceAttributeValue.
func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") }
// ProjectAttributes returns the list of user-defined attributes
// applying to the project as a whole, not just this VM. The value of
// an attribute can be obtained with ProjectAttributeValue.
func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") }
// InstanceAttributeValue returns the value of the provided VM
// instance attribute.
//
// If the requested attribute is not defined, the returned error will
// be of type NotDefinedError.
//
// InstanceAttributeValue may return ("", nil) if the attribute was
// defined to be the empty string.
func (c *Client) InstanceAttributeValue(attr string) (string, error) {
return c.Get("instance/attributes/" + attr)
}
// ProjectAttributeValue returns the value of the provided
// project attribute.
//
// If the requested attribute is not defined, the returned error will
// be of type NotDefinedError.
//
// ProjectAttributeValue may return ("", nil) if the attribute was
// defined to be the empty string.
func (c *Client) ProjectAttributeValue(attr string) (string, error) {
return c.Get("project/attributes/" + attr)
}
// Scopes returns the service account scopes for the given account.
// The account may be empty or the string "default" to use the instance's
// main account.
func (c *Client) Scopes(serviceAccount string) ([]string, error) {
if serviceAccount == "" {
serviceAccount = "default"
}
return c.lines("instance/service-accounts/" + serviceAccount + "/scopes")
}
// Subscribe subscribes to a value from the metadata service.
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
// The suffix may contain query parameters.
//
// Subscribe calls fn with the latest metadata value indicated by the provided
// suffix. If the metadata value is deleted, fn is called with the empty string
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
// is deleted. Subscribe returns the error value returned from the last call to
// fn, which may be nil when ok == false.
func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
const failedSubscribeSleep = time.Second * 5
// First check to see if the metadata value exists at all.
val, lastETag, err := c.getETag(suffix)
if err != nil {
return err
}
if err := fn(val, true); err != nil {
return err
}
ok := true
if strings.ContainsRune(suffix, '?') {
suffix += "&wait_for_change=true&last_etag="
} else {
suffix += "?wait_for_change=true&last_etag="
}
for {
val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag))
if err != nil {
if _, deleted := err.(NotDefinedError); !deleted {
time.Sleep(failedSubscribeSleep)
continue // Retry on other errors.
}
ok = false
}
lastETag = etag
if err := fn(val, ok); err != nil || !ok {
return err
}
}
}
// Error contains an error response from the server.
type Error struct {
// Code is the HTTP response status code.
Code int
// Message is the server response message.
Message string
}
func (e *Error) Error() string {
return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
}
+38
View File
@@ -0,0 +1,38 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package google
import (
"context"
"time"
"golang.org/x/oauth2"
)
// Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
// Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
var appengineAppIDFunc func(c context.Context) string
// AppEngineTokenSource returns a token source that fetches tokens from either
// the current application's service account or from the metadata server,
// depending on the App Engine environment. See below for environment-specific
// details. If you are implementing a 3-legged OAuth 2.0 flow on App Engine that
// involves user accounts, see oauth2.Config instead.
//
// First generation App Engine runtimes (<= Go 1.9):
// AppEngineTokenSource returns a token source that fetches tokens issued to the
// current App Engine application's service account. The provided context must have
// come from appengine.NewContext.
//
// Second generation App Engine runtimes (>= Go 1.11) and App Engine flexible:
// AppEngineTokenSource is DEPRECATED on second generation runtimes and on the
// flexible environment. It delegates to ComputeTokenSource, and the provided
// context and scopes are not used. Please use DefaultTokenSource (or ComputeTokenSource,
// which DefaultTokenSource will use in this case) instead.
func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
return appEngineTokenSource(ctx, scope...)
}
+77
View File
@@ -0,0 +1,77 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appengine
// This file applies to App Engine first generation runtimes (<= Go 1.9).
package google
import (
"context"
"sort"
"strings"
"sync"
"golang.org/x/oauth2"
"google.golang.org/appengine"
)
func init() {
appengineTokenFunc = appengine.AccessToken
appengineAppIDFunc = appengine.AppID
}
// See comment on AppEngineTokenSource in appengine.go.
func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
scopes := append([]string{}, scope...)
sort.Strings(scopes)
return &gaeTokenSource{
ctx: ctx,
scopes: scopes,
key: strings.Join(scopes, " "),
}
}
// aeTokens helps the fetched tokens to be reused until their expiration.
var (
aeTokensMu sync.Mutex
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
)
type tokenLock struct {
mu sync.Mutex // guards t; held while fetching or updating t
t *oauth2.Token
}
type gaeTokenSource struct {
ctx context.Context
scopes []string
key string // to aeTokens map; space-separated scopes
}
func (ts *gaeTokenSource) Token() (*oauth2.Token, error) {
aeTokensMu.Lock()
tok, ok := aeTokens[ts.key]
if !ok {
tok = &tokenLock{}
aeTokens[ts.key] = tok
}
aeTokensMu.Unlock()
tok.mu.Lock()
defer tok.mu.Unlock()
if tok.t.Valid() {
return tok.t, nil
}
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
if err != nil {
return nil, err
}
tok.t = &oauth2.Token{
AccessToken: access,
Expiry: exp,
}
return tok.t, nil
}
+27
View File
@@ -0,0 +1,27 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !appengine
// This file applies to App Engine second generation runtimes (>= Go 1.11) and App Engine flexible.
package google
import (
"context"
"log"
"sync"
"golang.org/x/oauth2"
)
var logOnce sync.Once // only spam about deprecation once
// See comment on AppEngineTokenSource in appengine.go.
func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
logOnce.Do(func() {
log.Print("google: AppEngineTokenSource is deprecated on App Engine standard second generation runtimes (>= Go 1.11) and App Engine flexible. Please use DefaultTokenSource or ComputeTokenSource.")
})
return ComputeTokenSource("")
}
+155
View File
@@ -0,0 +1,155 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package google
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"runtime"
"cloud.google.com/go/compute/metadata"
"golang.org/x/oauth2"
)
// Credentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type Credentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// DefaultCredentials is the old name of Credentials.
//
// Deprecated: use Credentials instead.
type DefaultCredentials = Credentials
// DefaultClient returns an HTTP Client that uses the
// DefaultTokenSource to obtain authentication credentials.
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
ts, err := DefaultTokenSource(ctx, scope...)
if err != nil {
return nil, err
}
return oauth2.NewClient(ctx, ts), nil
}
// DefaultTokenSource returns the token source for
// "Application Default Credentials".
// It is a shortcut for FindDefaultCredentials(ctx, scope).TokenSource.
func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
creds, err := FindDefaultCredentials(ctx, scope...)
if err != nil {
return nil, err
}
return creds.TokenSource, nil
}
// FindDefaultCredentials searches for "Application Default Credentials".
//
// It looks for credentials in the following places,
// preferring the first location found:
//
// 1. A JSON file whose path is specified by the
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
// 2. A JSON file in a location known to the gcloud command-line tool.
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
// 3. On Google App Engine standard first generation runtimes (<= Go 1.9) it uses
// the appengine.AccessToken function.
// 4. On Google Compute Engine, Google App Engine standard second generation runtimes
// (>= Go 1.11), and Google App Engine flexible environment, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) {
// First, try the environment variable.
const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
if filename := os.Getenv(envVar); filename != "" {
creds, err := readCredentialsFile(ctx, filename, scopes)
if err != nil {
return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
}
return creds, nil
}
// Second, try a well-known file.
filename := wellKnownFile()
if creds, err := readCredentialsFile(ctx, filename, scopes); err == nil {
return creds, nil
} else if !os.IsNotExist(err) {
return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
}
// Third, if we're on a Google App Engine standard first generation runtime (<= Go 1.9)
// use those credentials. App Engine standard second generation runtimes (>= Go 1.11)
// and App Engine flexible use ComputeTokenSource and the metadata server.
if appengineTokenFunc != nil {
return &DefaultCredentials{
ProjectID: appengineAppIDFunc(ctx),
TokenSource: AppEngineTokenSource(ctx, scopes...),
}, nil
}
// Fourth, if we're on Google Compute Engine, an App Engine standard second generation runtime,
// or App Engine flexible, use the metadata server.
if metadata.OnGCE() {
id, _ := metadata.ProjectID()
return &DefaultCredentials{
ProjectID: id,
TokenSource: ComputeTokenSource(""),
}, nil
}
// None are found; return helpful error.
const url = "https://developers.google.com/accounts/docs/application-default-credentials"
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
}
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
var f credentialsFile
if err := json.Unmarshal(jsonData, &f); err != nil {
return nil, err
}
ts, err := f.tokenSource(ctx, append([]string(nil), scopes...))
if err != nil {
return nil, err
}
return &DefaultCredentials{
ProjectID: f.ProjectID,
TokenSource: ts,
JSON: jsonData,
}, nil
}
func wellKnownFile() string {
const f = "application_default_credentials.json"
if runtime.GOOS == "windows" {
return filepath.Join(os.Getenv("APPDATA"), "gcloud", f)
}
return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f)
}
func readCredentialsFile(ctx context.Context, filename string, scopes []string) (*DefaultCredentials, error) {
b, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return CredentialsFromJSON(ctx, b, scopes...)
}
+40
View File
@@ -0,0 +1,40 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package google provides support for making OAuth2 authorized and authenticated
// HTTP requests to Google APIs. It supports the Web server flow, client-side
// credentials, service accounts, Google Compute Engine service accounts, and Google
// App Engine service accounts.
//
// A brief overview of the package follows. For more information, please read
// https://developers.google.com/accounts/docs/OAuth2
// and
// https://developers.google.com/accounts/docs/application-default-credentials.
//
// OAuth2 Configs
//
// Two functions in this package return golang.org/x/oauth2.Config values from Google credential
// data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON,
// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or
// create an http.Client.
//
//
// Credentials
//
// The Credentials type represents Google credentials, including Application Default
// Credentials.
//
// Use FindDefaultCredentials to obtain Application Default Credentials.
// FindDefaultCredentials looks in some well-known places for a credentials file, and
// will call AppEngineTokenSource or ComputeTokenSource as needed.
//
// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials,
// then use the credentials to construct an http.Client or an oauth2.TokenSource.
//
// Use CredentialsFromJSON to obtain credentials from either of the two JSON formats
// described in OAuth2 Configs, above. The TokenSource in the returned value is the
// same as the one obtained from the oauth2.Config returned from ConfigFromJSON or
// JWTConfigFromJSON, but the Credentials may contain additional information
// that is useful is some circumstances.
package google // import "golang.org/x/oauth2/google"
+193
View File
@@ -0,0 +1,193 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package google
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"cloud.google.com/go/compute/metadata"
"golang.org/x/oauth2"
"golang.org/x/oauth2/jwt"
)
// Endpoint is Google's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://oauth2.googleapis.com/token",
AuthStyle: oauth2.AuthStyleInParams,
}
// JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.
const JWTTokenURL = "https://oauth2.googleapis.com/token"
// ConfigFromJSON uses a Google Developers Console client_credentials.json
// file to construct a config.
// client_credentials.json can be downloaded from
// https://console.developers.google.com, under "Credentials". Download the Web
// application credentials in the JSON format and provide the contents of the
// file as jsonKey.
func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
type cred struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
RedirectURIs []string `json:"redirect_uris"`
AuthURI string `json:"auth_uri"`
TokenURI string `json:"token_uri"`
}
var j struct {
Web *cred `json:"web"`
Installed *cred `json:"installed"`
}
if err := json.Unmarshal(jsonKey, &j); err != nil {
return nil, err
}
var c *cred
switch {
case j.Web != nil:
c = j.Web
case j.Installed != nil:
c = j.Installed
default:
return nil, fmt.Errorf("oauth2/google: no credentials found")
}
if len(c.RedirectURIs) < 1 {
return nil, errors.New("oauth2/google: missing redirect URL in the client_credentials.json")
}
return &oauth2.Config{
ClientID: c.ClientID,
ClientSecret: c.ClientSecret,
RedirectURL: c.RedirectURIs[0],
Scopes: scope,
Endpoint: oauth2.Endpoint{
AuthURL: c.AuthURI,
TokenURL: c.TokenURI,
},
}, nil
}
// JWTConfigFromJSON uses a Google Developers service account JSON key file to read
// the credentials that authorize and authenticate the requests.
// Create a service account on "Credentials" for your project at
// https://console.developers.google.com to download a JSON key file.
func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
var f credentialsFile
if err := json.Unmarshal(jsonKey, &f); err != nil {
return nil, err
}
if f.Type != serviceAccountKey {
return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey)
}
scope = append([]string(nil), scope...) // copy
return f.jwtConfig(scope), nil
}
// JSON key file types.
const (
serviceAccountKey = "service_account"
userCredentialsKey = "authorized_user"
)
// credentialsFile is the unmarshalled representation of a credentials file.
type credentialsFile struct {
Type string `json:"type"` // serviceAccountKey or userCredentialsKey
// Service Account fields
ClientEmail string `json:"client_email"`
PrivateKeyID string `json:"private_key_id"`
PrivateKey string `json:"private_key"`
TokenURL string `json:"token_uri"`
ProjectID string `json:"project_id"`
// User Credential fields
// (These typically come from gcloud auth.)
ClientSecret string `json:"client_secret"`
ClientID string `json:"client_id"`
RefreshToken string `json:"refresh_token"`
}
func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config {
cfg := &jwt.Config{
Email: f.ClientEmail,
PrivateKey: []byte(f.PrivateKey),
PrivateKeyID: f.PrivateKeyID,
Scopes: scopes,
TokenURL: f.TokenURL,
}
if cfg.TokenURL == "" {
cfg.TokenURL = JWTTokenURL
}
return cfg
}
func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oauth2.TokenSource, error) {
switch f.Type {
case serviceAccountKey:
cfg := f.jwtConfig(scopes)
return cfg.TokenSource(ctx), nil
case userCredentialsKey:
cfg := &oauth2.Config{
ClientID: f.ClientID,
ClientSecret: f.ClientSecret,
Scopes: scopes,
Endpoint: Endpoint,
}
tok := &oauth2.Token{RefreshToken: f.RefreshToken}
return cfg.TokenSource(ctx, tok), nil
case "":
return nil, errors.New("missing 'type' field in credentials")
default:
return nil, fmt.Errorf("unknown credential type: %q", f.Type)
}
}
// ComputeTokenSource returns a token source that fetches access tokens
// from Google Compute Engine (GCE)'s metadata server. It's only valid to use
// this token source if your program is running on a GCE instance.
// If no account is specified, "default" is used.
// Further information about retrieving access tokens from the GCE metadata
// server can be found at https://cloud.google.com/compute/docs/authentication.
func ComputeTokenSource(account string) oauth2.TokenSource {
return oauth2.ReuseTokenSource(nil, computeSource{account: account})
}
type computeSource struct {
account string
}
func (cs computeSource) Token() (*oauth2.Token, error) {
if !metadata.OnGCE() {
return nil, errors.New("oauth2/google: can't get a token from the metadata service; not running on GCE")
}
acct := cs.account
if acct == "" {
acct = "default"
}
tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token")
if err != nil {
return nil, err
}
var res struct {
AccessToken string `json:"access_token"`
ExpiresInSec int `json:"expires_in"`
TokenType string `json:"token_type"`
}
err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res)
if err != nil {
return nil, fmt.Errorf("oauth2/google: invalid token JSON from metadata: %v", err)
}
if res.ExpiresInSec == 0 || res.AccessToken == "" {
return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata")
}
return &oauth2.Token{
AccessToken: res.AccessToken,
TokenType: res.TokenType,
Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
}, nil
}
+74
View File
@@ -0,0 +1,74 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package google
import (
"crypto/rsa"
"fmt"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/internal"
"golang.org/x/oauth2/jws"
)
// JWTAccessTokenSourceFromJSON uses a Google Developers service account JSON
// key file to read the credentials that authorize and authenticate the
// requests, and returns a TokenSource that does not use any OAuth2 flow but
// instead creates a JWT and sends that as the access token.
// The audience is typically a URL that specifies the scope of the credentials.
//
// Note that this is not a standard OAuth flow, but rather an
// optimization supported by a few Google services.
// Unless you know otherwise, you should use JWTConfigFromJSON instead.
func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.TokenSource, error) {
cfg, err := JWTConfigFromJSON(jsonKey)
if err != nil {
return nil, fmt.Errorf("google: could not parse JSON key: %v", err)
}
pk, err := internal.ParseKey(cfg.PrivateKey)
if err != nil {
return nil, fmt.Errorf("google: could not parse key: %v", err)
}
ts := &jwtAccessTokenSource{
email: cfg.Email,
audience: audience,
pk: pk,
pkID: cfg.PrivateKeyID,
}
tok, err := ts.Token()
if err != nil {
return nil, err
}
return oauth2.ReuseTokenSource(tok, ts), nil
}
type jwtAccessTokenSource struct {
email, audience string
pk *rsa.PrivateKey
pkID string
}
func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
iat := time.Now()
exp := iat.Add(time.Hour)
cs := &jws.ClaimSet{
Iss: ts.email,
Sub: ts.email,
Aud: ts.audience,
Iat: iat.Unix(),
Exp: exp.Unix(),
}
hdr := &jws.Header{
Algorithm: "RS256",
Typ: "JWT",
KeyID: string(ts.pkID),
}
msg, err := jws.Encode(hdr, cs, ts.pk)
if err != nil {
return nil, fmt.Errorf("google: could not encode JWT: %v", err)
}
return &oauth2.Token{AccessToken: msg, TokenType: "Bearer", Expiry: exp}, nil
}
+201
View File
@@ -0,0 +1,201 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package google
import (
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
"time"
"golang.org/x/oauth2"
)
type sdkCredentials struct {
Data []struct {
Credential struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
TokenExpiry *time.Time `json:"token_expiry"`
} `json:"credential"`
Key struct {
Account string `json:"account"`
Scope string `json:"scope"`
} `json:"key"`
}
}
// An SDKConfig provides access to tokens from an account already
// authorized via the Google Cloud SDK.
type SDKConfig struct {
conf oauth2.Config
initialToken *oauth2.Token
}
// NewSDKConfig creates an SDKConfig for the given Google Cloud SDK
// account. If account is empty, the account currently active in
// Google Cloud SDK properties is used.
// Google Cloud SDK credentials must be created by running `gcloud auth`
// before using this function.
// The Google Cloud SDK is available at https://cloud.google.com/sdk/.
func NewSDKConfig(account string) (*SDKConfig, error) {
configPath, err := sdkConfigPath()
if err != nil {
return nil, fmt.Errorf("oauth2/google: error getting SDK config path: %v", err)
}
credentialsPath := filepath.Join(configPath, "credentials")
f, err := os.Open(credentialsPath)
if err != nil {
return nil, fmt.Errorf("oauth2/google: failed to load SDK credentials: %v", err)
}
defer f.Close()
var c sdkCredentials
if err := json.NewDecoder(f).Decode(&c); err != nil {
return nil, fmt.Errorf("oauth2/google: failed to decode SDK credentials from %q: %v", credentialsPath, err)
}
if len(c.Data) == 0 {
return nil, fmt.Errorf("oauth2/google: no credentials found in %q, run `gcloud auth login` to create one", credentialsPath)
}
if account == "" {
propertiesPath := filepath.Join(configPath, "properties")
f, err := os.Open(propertiesPath)
if err != nil {
return nil, fmt.Errorf("oauth2/google: failed to load SDK properties: %v", err)
}
defer f.Close()
ini, err := parseINI(f)
if err != nil {
return nil, fmt.Errorf("oauth2/google: failed to parse SDK properties %q: %v", propertiesPath, err)
}
core, ok := ini["core"]
if !ok {
return nil, fmt.Errorf("oauth2/google: failed to find [core] section in %v", ini)
}
active, ok := core["account"]
if !ok {
return nil, fmt.Errorf("oauth2/google: failed to find %q attribute in %v", "account", core)
}
account = active
}
for _, d := range c.Data {
if account == "" || d.Key.Account == account {
if d.Credential.AccessToken == "" && d.Credential.RefreshToken == "" {
return nil, fmt.Errorf("oauth2/google: no token available for account %q", account)
}
var expiry time.Time
if d.Credential.TokenExpiry != nil {
expiry = *d.Credential.TokenExpiry
}
return &SDKConfig{
conf: oauth2.Config{
ClientID: d.Credential.ClientID,
ClientSecret: d.Credential.ClientSecret,
Scopes: strings.Split(d.Key.Scope, " "),
Endpoint: Endpoint,
RedirectURL: "oob",
},
initialToken: &oauth2.Token{
AccessToken: d.Credential.AccessToken,
RefreshToken: d.Credential.RefreshToken,
Expiry: expiry,
},
}, nil
}
}
return nil, fmt.Errorf("oauth2/google: no such credentials for account %q", account)
}
// Client returns an HTTP client using Google Cloud SDK credentials to
// authorize requests. The token will auto-refresh as necessary. The
// underlying http.RoundTripper will be obtained using the provided
// context. The returned client and its Transport should not be
// modified.
func (c *SDKConfig) Client(ctx context.Context) *http.Client {
return &http.Client{
Transport: &oauth2.Transport{
Source: c.TokenSource(ctx),
},
}
}
// TokenSource returns an oauth2.TokenSource that retrieve tokens from
// Google Cloud SDK credentials using the provided context.
// It will returns the current access token stored in the credentials,
// and refresh it when it expires, but it won't update the credentials
// with the new access token.
func (c *SDKConfig) TokenSource(ctx context.Context) oauth2.TokenSource {
return c.conf.TokenSource(ctx, c.initialToken)
}
// Scopes are the OAuth 2.0 scopes the current account is authorized for.
func (c *SDKConfig) Scopes() []string {
return c.conf.Scopes
}
func parseINI(ini io.Reader) (map[string]map[string]string, error) {
result := map[string]map[string]string{
"": {}, // root section
}
scanner := bufio.NewScanner(ini)
currentSection := ""
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, ";") {
// comment.
continue
}
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
currentSection = strings.TrimSpace(line[1 : len(line)-1])
result[currentSection] = map[string]string{}
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) == 2 && parts[0] != "" {
result[currentSection][strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("error scanning ini: %v", err)
}
return result, nil
}
// sdkConfigPath tries to guess where the gcloud config is located.
// It can be overridden during tests.
var sdkConfigPath = func() (string, error) {
if runtime.GOOS == "windows" {
return filepath.Join(os.Getenv("APPDATA"), "gcloud"), nil
}
homeDir := guessUnixHomeDir()
if homeDir == "" {
return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty")
}
return filepath.Join(homeDir, ".config", "gcloud"), nil
}
func guessUnixHomeDir() string {
// Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
if v := os.Getenv("HOME"); v != "" {
return v
}
// Else, fall back to user.Current:
if u, err := user.Current(); err == nil {
return u.HomeDir
}
return ""
}

Some files were not shown because too many files have changed in this diff Show More