mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-29 03:51:54 +08:00
Merge pull request #3847 from ioito/feature/qx-google
add: gcp cloud support
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -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" //瑞士
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ var (
|
||||
REGIONAL_NETWORK_PROVIDERS = []string{
|
||||
CLOUD_PROVIDER_HUAWEI,
|
||||
CLOUD_PROVIDER_UCLOUD,
|
||||
CLOUD_PROVIDER_GOOGLE,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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{}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package google // import "yunion.io/x/onecloud/pkg/multicloud/google"
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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, ®ions)
|
||||
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, ®ions[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())
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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": "洛杉矶",
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package provider // import "yunion.io/x/onecloud/pkg/multicloud/google/provider"
|
||||
@@ -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",
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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, "")
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package shell // import "yunion.io/x/onecloud/pkg/multicloud/google/shell"
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user