mirror of https://github.com/k3s-io/k3s
Removing cloud directory
parent
b97092ca8f
commit
7f8dae1abc
|
@ -1,67 +0,0 @@
|
||||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = [
|
|
||||||
"constants.go",
|
|
||||||
"context.go",
|
|
||||||
"doc.go",
|
|
||||||
"gce_projects.go",
|
|
||||||
"gen.go",
|
|
||||||
"op.go",
|
|
||||||
"project.go",
|
|
||||||
"ratelimit.go",
|
|
||||||
"service.go",
|
|
||||||
"utils.go",
|
|
||||||
],
|
|
||||||
importpath = "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud",
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
deps = [
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/filter:go_default_library",
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/meta:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v0.alpha:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v0.beta:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v1:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/googleapi:go_default_library",
|
|
||||||
"//vendor/k8s.io/klog:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
go_test(
|
|
||||||
name = "go_default_test",
|
|
||||||
srcs = [
|
|
||||||
"gen_test.go",
|
|
||||||
"mock_test.go",
|
|
||||||
"ratelimit_test.go",
|
|
||||||
"service_test.go",
|
|
||||||
"utils_test.go",
|
|
||||||
],
|
|
||||||
embed = [":go_default_library"],
|
|
||||||
deps = [
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/filter:go_default_library",
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/meta:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v0.alpha:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v0.beta:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v1:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [
|
|
||||||
":package-srcs",
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/filter:all-srcs",
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/gen:all-srcs",
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/meta:all-srcs",
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/mock:all-srcs",
|
|
||||||
],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NetworkTier represents the Network Service Tier used by a resource
|
|
||||||
type NetworkTier string
|
|
||||||
|
|
||||||
// LbScheme represents the possible types of load balancers
|
|
||||||
type LbScheme string
|
|
||||||
|
|
||||||
const (
|
|
||||||
NetworkTierStandard NetworkTier = "Standard"
|
|
||||||
NetworkTierPremium NetworkTier = "Premium"
|
|
||||||
NetworkTierDefault NetworkTier = NetworkTierPremium
|
|
||||||
|
|
||||||
SchemeExternal LbScheme = "EXTERNAL"
|
|
||||||
SchemeInternal LbScheme = "INTERNAL"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ToGCEValue converts NetworkTier to a string that we can populate the
|
|
||||||
// NetworkTier field of GCE objects, including ForwardingRules and Addresses.
|
|
||||||
func (n NetworkTier) ToGCEValue() string {
|
|
||||||
return strings.ToUpper(string(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetworkTierGCEValueToType converts the value of the NetworkTier field of a
|
|
||||||
// GCE object to the NetworkTier type.
|
|
||||||
func NetworkTierGCEValueToType(s string) NetworkTier {
|
|
||||||
switch s {
|
|
||||||
case NetworkTierStandard.ToGCEValue():
|
|
||||||
return NetworkTierStandard
|
|
||||||
case NetworkTierPremium.ToGCEValue():
|
|
||||||
return NetworkTierPremium
|
|
||||||
default:
|
|
||||||
return NetworkTier(s)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultCallTimeout = 1 * time.Hour
|
|
||||||
)
|
|
||||||
|
|
||||||
// ContextWithCallTimeout returns a context with a default timeout, used for generated client calls.
|
|
||||||
func ContextWithCallTimeout() (context.Context, context.CancelFunc) {
|
|
||||||
return context.WithTimeout(context.Background(), defaultCallTimeout)
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud implements a more golang friendly interface to the GCE compute
|
|
||||||
// API. The code in this package is generated automatically via the generator
|
|
||||||
// implemented in "gen/main.go". The code generator creates the basic CRUD
|
|
||||||
// actions for the given resource: "Insert", "Get", "List" and "Delete".
|
|
||||||
// Additional methods by customizing the ServiceInfo object (see below).
|
|
||||||
// Generated code includes a full mock of the GCE compute API.
|
|
||||||
//
|
|
||||||
// Usage
|
|
||||||
//
|
|
||||||
// The root of the GCE compute API is the interface "Cloud". Code written using
|
|
||||||
// Cloud can be used against the actual implementation "GCE" or "MockGCE".
|
|
||||||
//
|
|
||||||
// func foo(cloud Cloud) {
|
|
||||||
// igs, err := cloud.InstanceGroups().List(ctx, "us-central1-b", filter.None)
|
|
||||||
// ...
|
|
||||||
// }
|
|
||||||
// // Run foo against the actual cloud.
|
|
||||||
// foo(NewGCE(&Service{...}))
|
|
||||||
// // Run foo with a mock.
|
|
||||||
// foo(NewMockGCE())
|
|
||||||
//
|
|
||||||
// Rate limiting and routing
|
|
||||||
//
|
|
||||||
// The generated code allows for custom policies for operation rate limiting
|
|
||||||
// and GCE project routing. See RateLimiter and ProjectRouter for more details.
|
|
||||||
//
|
|
||||||
// Mocks
|
|
||||||
//
|
|
||||||
// Mocks are automatically generated for each type implementing basic logic for
|
|
||||||
// resource manipulation. This eliminates the boilerplate required to mock GCE
|
|
||||||
// functionality. Each method will also have a corresponding "xxxHook"
|
|
||||||
// function generated in the mock structure where unit test code can hook the
|
|
||||||
// execution of the method.
|
|
||||||
//
|
|
||||||
// Mocks for different versions of the same service will share the same set of
|
|
||||||
// objects, i.e. an alpha object will be visible with beta and GA methods.
|
|
||||||
// Note that translation is done with JSON serialization between the API versions.
|
|
||||||
//
|
|
||||||
// Changing service code generation
|
|
||||||
//
|
|
||||||
// The list of services to generate is contained in "meta/meta.go". To add a
|
|
||||||
// service, add an entry to the list "meta.AllServices". An example entry:
|
|
||||||
//
|
|
||||||
// &ServiceInfo{
|
|
||||||
// Object: "InstanceGroup", // Name of the object type.
|
|
||||||
// Service: "InstanceGroups", // Name of the service.
|
|
||||||
// Resource: "instanceGroups", // Lowercase resource name (as appears in the URL).
|
|
||||||
// version: meta.VersionAlpha, // API version (one entry per version is needed).
|
|
||||||
// keyType: Zonal, // What kind of resource this is.
|
|
||||||
// serviceType: reflect.TypeOf(&alpha.InstanceGroupsService{}), // Associated golang type.
|
|
||||||
// additionalMethods: []string{ // Additional methods to generate code for.
|
|
||||||
// "SetNamedPorts",
|
|
||||||
// },
|
|
||||||
// options: <options> // Or'd ("|") together.
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Read-only objects
|
|
||||||
//
|
|
||||||
// Services such as Regions and Zones do not allow for mutations. Specify
|
|
||||||
// "ReadOnly" in ServiceInfo.options to omit the mutation methods.
|
|
||||||
//
|
|
||||||
// Adding custom methods
|
|
||||||
//
|
|
||||||
// Some methods that may not be properly handled by the generated code. To enable
|
|
||||||
// addition of custom code to the generated mocks, set the "CustomOps" option
|
|
||||||
// in "meta.ServiceInfo" entry. This will make the generated service interface
|
|
||||||
// embed a "<ServiceName>Ops" interface. This interface MUST be written by hand
|
|
||||||
// and contain the custom method logic. Corresponding methods must be added to
|
|
||||||
// the corresponding Mockxxx and GCExxx struct types.
|
|
||||||
//
|
|
||||||
// // In "meta/meta.go":
|
|
||||||
// &ServiceInfo{
|
|
||||||
// Object: "InstanceGroup",
|
|
||||||
// ...
|
|
||||||
// options: CustomOps,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // In the generated code "gen.go":
|
|
||||||
// type InstanceGroups interface {
|
|
||||||
// InstanceGroupsOps // Added by CustomOps option.
|
|
||||||
// ...
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // In hand written file:
|
|
||||||
// type InstanceGroupsOps interface {
|
|
||||||
// MyMethod()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func (mock *MockInstanceGroups) MyMethod() {
|
|
||||||
// // Custom mock implementation.
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func (gce *GCEInstanceGroups) MyMethod() {
|
|
||||||
// // Custom implementation.
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Update generated codes
|
|
||||||
//
|
|
||||||
// Run hack/update-cloudprovider-gce.sh to update the generated codes.
|
|
||||||
//
|
|
||||||
package cloud
|
|
|
@ -1,29 +0,0 @@
|
||||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = ["filter.go"],
|
|
||||||
importpath = "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/filter",
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
deps = ["//vendor/k8s.io/klog:go_default_library"],
|
|
||||||
)
|
|
||||||
|
|
||||||
go_test(
|
|
||||||
name = "go_default_test",
|
|
||||||
srcs = ["filter_test.go"],
|
|
||||||
embed = [":go_default_library"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [":package-srcs"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
|
@ -1,303 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 filter encapsulates the filter argument to compute API calls.
|
|
||||||
//
|
|
||||||
// // List all global addresses (no filter).
|
|
||||||
// c.GlobalAddresses().List(ctx, filter.None)
|
|
||||||
//
|
|
||||||
// // List global addresses filtering for name matching "abc.*".
|
|
||||||
// c.GlobalAddresses().List(ctx, filter.Regexp("name", "abc.*"))
|
|
||||||
//
|
|
||||||
// // List on multiple conditions.
|
|
||||||
// f := filter.Regexp("name", "homer.*").AndNotRegexp("name", "homers")
|
|
||||||
// c.GlobalAddresses().List(ctx, f)
|
|
||||||
package filter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/klog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// None indicates that the List result set should not be filter (i.e.
|
|
||||||
// return all values).
|
|
||||||
None *F
|
|
||||||
)
|
|
||||||
|
|
||||||
// Regexp returns a filter for fieldName matches regexp v.
|
|
||||||
func Regexp(fieldName, v string) *F {
|
|
||||||
return (&F{}).AndRegexp(fieldName, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotRegexp returns a filter for fieldName not matches regexp v.
|
|
||||||
func NotRegexp(fieldName, v string) *F {
|
|
||||||
return (&F{}).AndNotRegexp(fieldName, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EqualInt returns a filter for fieldName ~ v.
|
|
||||||
func EqualInt(fieldName string, v int) *F {
|
|
||||||
return (&F{}).AndEqualInt(fieldName, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotEqualInt returns a filter for fieldName != v.
|
|
||||||
func NotEqualInt(fieldName string, v int) *F {
|
|
||||||
return (&F{}).AndNotEqualInt(fieldName, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EqualBool returns a filter for fieldName == v.
|
|
||||||
func EqualBool(fieldName string, v bool) *F {
|
|
||||||
return (&F{}).AndEqualBool(fieldName, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotEqualBool returns a filter for fieldName != v.
|
|
||||||
func NotEqualBool(fieldName string, v bool) *F {
|
|
||||||
return (&F{}).AndNotEqualBool(fieldName, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// F is a filter to be used with List() operations.
|
|
||||||
//
|
|
||||||
// From the compute API description:
|
|
||||||
//
|
|
||||||
// Sets a filter {expression} for filtering listed resources. Your {expression}
|
|
||||||
// must be in the format: field_name comparison_string literal_string.
|
|
||||||
//
|
|
||||||
// The field_name is the name of the field you want to compare. Only atomic field
|
|
||||||
// types are supported (string, number, boolean). The comparison_string must be
|
|
||||||
// either eq (equals) or ne (not equals). The literal_string is the string value
|
|
||||||
// to filter to. The literal value must be valid for the type of field you are
|
|
||||||
// filtering by (string, number, boolean). For string fields, the literal value is
|
|
||||||
// interpreted as a regular expression using RE2 syntax. The literal value must
|
|
||||||
// match the entire field.
|
|
||||||
//
|
|
||||||
// For example, to filter for instances that do not have a name of
|
|
||||||
// example-instance, you would use name ne example-instance.
|
|
||||||
//
|
|
||||||
// You can filter on nested fields. For example, you could filter on instances
|
|
||||||
// that have set the scheduling.automaticRestart field to true. Use filtering on
|
|
||||||
// nested fields to take advantage of labels to organize and search for results
|
|
||||||
// based on label values.
|
|
||||||
//
|
|
||||||
// To filter on multiple expressions, provide each separate expression within
|
|
||||||
// parentheses. For example, (scheduling.automaticRestart eq true)
|
|
||||||
// (zone eq us-central1-f). Multiple expressions are treated as AND expressions,
|
|
||||||
// meaning that resources must match all expressions to pass the filters.
|
|
||||||
type F struct {
|
|
||||||
predicates []filterPredicate
|
|
||||||
}
|
|
||||||
|
|
||||||
// And joins two filters together.
|
|
||||||
func (fl *F) And(rest *F) *F {
|
|
||||||
fl.predicates = append(fl.predicates, rest.predicates...)
|
|
||||||
return fl
|
|
||||||
}
|
|
||||||
|
|
||||||
// AndRegexp adds a field match string predicate.
|
|
||||||
func (fl *F) AndRegexp(fieldName, v string) *F {
|
|
||||||
fl.predicates = append(fl.predicates, filterPredicate{fieldName: fieldName, op: equals, s: &v})
|
|
||||||
return fl
|
|
||||||
}
|
|
||||||
|
|
||||||
// AndNotRegexp adds a field not match string predicate.
|
|
||||||
func (fl *F) AndNotRegexp(fieldName, v string) *F {
|
|
||||||
fl.predicates = append(fl.predicates, filterPredicate{fieldName: fieldName, op: notEquals, s: &v})
|
|
||||||
return fl
|
|
||||||
}
|
|
||||||
|
|
||||||
// AndEqualInt adds a field == int predicate.
|
|
||||||
func (fl *F) AndEqualInt(fieldName string, v int) *F {
|
|
||||||
fl.predicates = append(fl.predicates, filterPredicate{fieldName: fieldName, op: equals, i: &v})
|
|
||||||
return fl
|
|
||||||
}
|
|
||||||
|
|
||||||
// AndNotEqualInt adds a field != int predicate.
|
|
||||||
func (fl *F) AndNotEqualInt(fieldName string, v int) *F {
|
|
||||||
fl.predicates = append(fl.predicates, filterPredicate{fieldName: fieldName, op: notEquals, i: &v})
|
|
||||||
return fl
|
|
||||||
}
|
|
||||||
|
|
||||||
// AndEqualBool adds a field == bool predicate.
|
|
||||||
func (fl *F) AndEqualBool(fieldName string, v bool) *F {
|
|
||||||
fl.predicates = append(fl.predicates, filterPredicate{fieldName: fieldName, op: equals, b: &v})
|
|
||||||
return fl
|
|
||||||
}
|
|
||||||
|
|
||||||
// AndNotEqualBool adds a field != bool predicate.
|
|
||||||
func (fl *F) AndNotEqualBool(fieldName string, v bool) *F {
|
|
||||||
fl.predicates = append(fl.predicates, filterPredicate{fieldName: fieldName, op: notEquals, b: &v})
|
|
||||||
return fl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fl *F) String() string {
|
|
||||||
if len(fl.predicates) == 1 {
|
|
||||||
return fl.predicates[0].String()
|
|
||||||
}
|
|
||||||
|
|
||||||
var pl []string
|
|
||||||
for _, p := range fl.predicates {
|
|
||||||
pl = append(pl, "("+p.String()+")")
|
|
||||||
}
|
|
||||||
return strings.Join(pl, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match returns true if the F as specifies matches the given object. This
|
|
||||||
// is used by the Mock implementations to perform filtering and SHOULD NOT be
|
|
||||||
// used in production code as it is not well-tested to be equivalent to the
|
|
||||||
// actual compute API.
|
|
||||||
func (fl *F) Match(obj interface{}) bool {
|
|
||||||
if fl == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, p := range fl.predicates {
|
|
||||||
if !p.match(obj) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
type filterOp int
|
|
||||||
|
|
||||||
const (
|
|
||||||
equals filterOp = iota
|
|
||||||
notEquals filterOp = iota
|
|
||||||
)
|
|
||||||
|
|
||||||
// filterPredicate is an individual predicate for a fieldName and value.
|
|
||||||
type filterPredicate struct {
|
|
||||||
fieldName string
|
|
||||||
|
|
||||||
op filterOp
|
|
||||||
s *string
|
|
||||||
i *int
|
|
||||||
b *bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fp *filterPredicate) String() string {
|
|
||||||
var op string
|
|
||||||
switch fp.op {
|
|
||||||
case equals:
|
|
||||||
op = "eq"
|
|
||||||
case notEquals:
|
|
||||||
op = "ne"
|
|
||||||
default:
|
|
||||||
op = "invalidOp"
|
|
||||||
}
|
|
||||||
|
|
||||||
var value string
|
|
||||||
switch {
|
|
||||||
case fp.s != nil:
|
|
||||||
// There does not seem to be any sort of escaping as specified in the
|
|
||||||
// document. This means it's possible to create malformed expressions.
|
|
||||||
value = *fp.s
|
|
||||||
case fp.i != nil:
|
|
||||||
value = fmt.Sprintf("%d", *fp.i)
|
|
||||||
case fp.b != nil:
|
|
||||||
value = fmt.Sprintf("%t", *fp.b)
|
|
||||||
default:
|
|
||||||
value = "invalidValue"
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s %s %s", fp.fieldName, op, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fp *filterPredicate) match(o interface{}) bool {
|
|
||||||
v, err := extractValue(fp.fieldName, o)
|
|
||||||
klog.V(6).Infof("extractValue(%q, %#v) = %v, %v", fp.fieldName, o, v, err)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var match bool
|
|
||||||
switch x := v.(type) {
|
|
||||||
case string:
|
|
||||||
if fp.s == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
re, err := regexp.Compile(*fp.s)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("Match regexp %q is invalid: %v", *fp.s, err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
match = re.Match([]byte(x))
|
|
||||||
case int:
|
|
||||||
if fp.i == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
match = x == *fp.i
|
|
||||||
case bool:
|
|
||||||
if fp.b == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
match = x == *fp.b
|
|
||||||
}
|
|
||||||
|
|
||||||
switch fp.op {
|
|
||||||
case equals:
|
|
||||||
return match
|
|
||||||
case notEquals:
|
|
||||||
return !match
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// snakeToCamelCase converts from "names_like_this" to "NamesLikeThis" to
|
|
||||||
// interoperate between proto and Golang naming conventions.
|
|
||||||
func snakeToCamelCase(s string) string {
|
|
||||||
parts := strings.Split(s, "_")
|
|
||||||
var ret string
|
|
||||||
for _, x := range parts {
|
|
||||||
ret += strings.Title(x)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractValue returns the value of the field named by path in object o if it exists.
|
|
||||||
func extractValue(path string, o interface{}) (interface{}, error) {
|
|
||||||
parts := strings.Split(path, ".")
|
|
||||||
for _, f := range parts {
|
|
||||||
v := reflect.ValueOf(o)
|
|
||||||
// Dereference Ptr to handle *struct.
|
|
||||||
if v.Kind() == reflect.Ptr {
|
|
||||||
if v.IsNil() {
|
|
||||||
return nil, errors.New("field is nil")
|
|
||||||
}
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
if v.Kind() != reflect.Struct {
|
|
||||||
return nil, fmt.Errorf("cannot get field from non-struct (%T)", o)
|
|
||||||
}
|
|
||||||
v = v.FieldByName(snakeToCamelCase(f))
|
|
||||||
if !v.IsValid() {
|
|
||||||
return nil, fmt.Errorf("cannot get field %q as it is not a valid field in %T", f, o)
|
|
||||||
}
|
|
||||||
if !v.CanInterface() {
|
|
||||||
return nil, fmt.Errorf("cannot get field %q in obj of type %T", f, o)
|
|
||||||
}
|
|
||||||
o = v.Interface()
|
|
||||||
}
|
|
||||||
switch o.(type) {
|
|
||||||
case string, int, bool:
|
|
||||||
return o, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("unhandled object of type %T", o)
|
|
||||||
}
|
|
|
@ -1,176 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 filter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFilterToString(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
f *F
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{Regexp("field1", "abc"), `field1 eq abc`},
|
|
||||||
{NotRegexp("field1", "abc"), `field1 ne abc`},
|
|
||||||
{EqualInt("field1", 13), "field1 eq 13"},
|
|
||||||
{NotEqualInt("field1", 13), "field1 ne 13"},
|
|
||||||
{EqualBool("field1", true), "field1 eq true"},
|
|
||||||
{NotEqualBool("field1", true), "field1 ne true"},
|
|
||||||
{Regexp("field1", "abc").AndRegexp("field2", "def"), `(field1 eq abc) (field2 eq def)`},
|
|
||||||
{Regexp("field1", "abc").AndNotEqualInt("field2", 17), `(field1 eq abc) (field2 ne 17)`},
|
|
||||||
{Regexp("field1", "abc").And(EqualInt("field2", 17)), `(field1 eq abc) (field2 eq 17)`},
|
|
||||||
} {
|
|
||||||
if tc.f.String() != tc.want {
|
|
||||||
t.Errorf("filter %#v String() = %q, want %q", tc.f, tc.f.String(), tc.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFilterMatch(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
type inner struct {
|
|
||||||
X string
|
|
||||||
}
|
|
||||||
type S struct {
|
|
||||||
S string
|
|
||||||
I int
|
|
||||||
B bool
|
|
||||||
Unhandled struct{}
|
|
||||||
NestedField *inner
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
f *F
|
|
||||||
o interface{}
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{f: None, o: &S{}, want: true},
|
|
||||||
{f: Regexp("s", "abc"), o: &S{}},
|
|
||||||
{f: EqualInt("i", 10), o: &S{}},
|
|
||||||
{f: EqualBool("b", true), o: &S{}},
|
|
||||||
{f: NotRegexp("s", "abc"), o: &S{}, want: true},
|
|
||||||
{f: NotEqualInt("i", 10), o: &S{}, want: true},
|
|
||||||
{f: NotEqualBool("b", true), o: &S{}, want: true},
|
|
||||||
{f: Regexp("s", "abc").AndEqualBool("b", true), o: &S{}},
|
|
||||||
{f: Regexp("s", "abc"), o: &S{S: "abc"}, want: true},
|
|
||||||
{f: Regexp("s", "a.*"), o: &S{S: "abc"}, want: true},
|
|
||||||
{f: Regexp("s", "a((("), o: &S{S: "abc"}},
|
|
||||||
{f: NotRegexp("s", "abc"), o: &S{S: "abc"}},
|
|
||||||
{f: EqualInt("i", 10), o: &S{I: 11}},
|
|
||||||
{f: EqualInt("i", 10), o: &S{I: 10}, want: true},
|
|
||||||
{f: Regexp("s", "abc").AndEqualBool("b", true), o: &S{S: "abc"}},
|
|
||||||
{f: Regexp("s", "abcd").AndEqualBool("b", true), o: &S{S: "abc"}},
|
|
||||||
{f: Regexp("s", "abc").AndEqualBool("b", true), o: &S{S: "abc", B: true}, want: true},
|
|
||||||
{f: Regexp("s", "abc").And(EqualBool("b", true)), o: &S{S: "abc", B: true}, want: true},
|
|
||||||
{f: Regexp("unhandled", "xyz"), o: &S{}},
|
|
||||||
{f: Regexp("nested_field.x", "xyz"), o: &S{}},
|
|
||||||
{f: Regexp("nested_field.x", "xyz"), o: &S{NestedField: &inner{"xyz"}}, want: true},
|
|
||||||
{f: NotRegexp("nested_field.x", "xyz"), o: &S{NestedField: &inner{"xyz"}}},
|
|
||||||
{f: Regexp("nested_field.y", "xyz"), o: &S{NestedField: &inner{"xyz"}}},
|
|
||||||
{f: Regexp("nested_field", "xyz"), o: &S{NestedField: &inner{"xyz"}}},
|
|
||||||
} {
|
|
||||||
got := tc.f.Match(tc.o)
|
|
||||||
if got != tc.want {
|
|
||||||
t.Errorf("%v: Match(%+v) = %v, want %v", tc.f, tc.o, got, tc.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFilterSnakeToCamelCase(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
s string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{"", ""},
|
|
||||||
{"abc", "Abc"},
|
|
||||||
{"_foo", "Foo"},
|
|
||||||
{"a_b_c", "ABC"},
|
|
||||||
{"a_BC_def", "ABCDef"},
|
|
||||||
{"a_Bc_def", "ABcDef"},
|
|
||||||
} {
|
|
||||||
got := snakeToCamelCase(tc.s)
|
|
||||||
if got != tc.want {
|
|
||||||
t.Errorf("snakeToCamelCase(%q) = %q, want %q", tc.s, got, tc.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFilterExtractValue(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
type nest2 struct {
|
|
||||||
Y string
|
|
||||||
}
|
|
||||||
type nest struct {
|
|
||||||
X string
|
|
||||||
Nest2 nest2
|
|
||||||
}
|
|
||||||
st := &struct {
|
|
||||||
S string
|
|
||||||
I int
|
|
||||||
F bool
|
|
||||||
Nest nest
|
|
||||||
NestPtr *nest
|
|
||||||
|
|
||||||
Unhandled float64
|
|
||||||
}{
|
|
||||||
"abc",
|
|
||||||
13,
|
|
||||||
true,
|
|
||||||
nest{"xyz", nest2{"zzz"}},
|
|
||||||
&nest{"yyy", nest2{}},
|
|
||||||
0.0,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
path string
|
|
||||||
o interface{}
|
|
||||||
want interface{}
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{path: "s", o: st, want: "abc"},
|
|
||||||
{path: "i", o: st, want: 13},
|
|
||||||
{path: "f", o: st, want: true},
|
|
||||||
{path: "nest.x", o: st, want: "xyz"},
|
|
||||||
{path: "nest_ptr.x", o: st, want: "yyy"},
|
|
||||||
// Error cases.
|
|
||||||
{path: "", o: st, wantErr: true},
|
|
||||||
{path: "no_such_field", o: st, wantErr: true},
|
|
||||||
{path: "s.invalid_type", o: st, wantErr: true},
|
|
||||||
{path: "unhandled", o: st, wantErr: true},
|
|
||||||
{path: "nest.x", o: &struct{ Nest *nest }{}, wantErr: true},
|
|
||||||
} {
|
|
||||||
o, err := extractValue(tc.path, tc.o)
|
|
||||||
gotErr := err != nil
|
|
||||||
if gotErr != tc.wantErr {
|
|
||||||
t.Errorf("extractValue(%v, %+v) = %v, %v; gotErr = %v, tc.wantErr = %v", tc.path, tc.o, o, err, gotErr, tc.wantErr)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(o, tc.want) {
|
|
||||||
t.Errorf("extractValue(%v, %+v) = %v, nil; want %v, nil", tc.path, tc.o, o, tc.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
compute "google.golang.org/api/compute/v1"
|
|
||||||
"google.golang.org/api/googleapi"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProjectsOps is the manually implemented methods for the Projects service.
|
|
||||||
type ProjectsOps interface {
|
|
||||||
Get(ctx context.Context, projectID string) (*compute.Project, error)
|
|
||||||
SetCommonInstanceMetadata(ctx context.Context, projectID string, m *compute.Metadata) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockProjectOpsState is stored in the mock.X field.
|
|
||||||
type MockProjectOpsState struct {
|
|
||||||
metadata map[string]*compute.Metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a project by projectID.
|
|
||||||
func (m *MockProjects) Get(ctx context.Context, projectID string) (*compute.Project, error) {
|
|
||||||
m.Lock.Lock()
|
|
||||||
defer m.Lock.Unlock()
|
|
||||||
|
|
||||||
if p, ok := m.Objects[*meta.GlobalKey(projectID)]; ok {
|
|
||||||
return p.ToGA(), nil
|
|
||||||
}
|
|
||||||
return nil, &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("MockProjects %v not found", projectID),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a project by projectID.
|
|
||||||
func (g *GCEProjects) Get(ctx context.Context, projectID string) (*compute.Project, error) {
|
|
||||||
rk := &RateLimitKey{
|
|
||||||
ProjectID: projectID,
|
|
||||||
Operation: "Get",
|
|
||||||
Version: meta.Version("ga"),
|
|
||||||
Service: "Projects",
|
|
||||||
}
|
|
||||||
if err := g.s.RateLimiter.Accept(ctx, rk); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
call := g.s.GA.Projects.Get(projectID)
|
|
||||||
call.Context(ctx)
|
|
||||||
return call.Do()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCommonInstanceMetadata for a given project.
|
|
||||||
func (m *MockProjects) SetCommonInstanceMetadata(ctx context.Context, projectID string, meta *compute.Metadata) error {
|
|
||||||
if m.X == nil {
|
|
||||||
m.X = &MockProjectOpsState{metadata: map[string]*compute.Metadata{}}
|
|
||||||
}
|
|
||||||
state := m.X.(*MockProjectOpsState)
|
|
||||||
state.metadata[projectID] = meta
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCommonInstanceMetadata for a given project.
|
|
||||||
func (g *GCEProjects) SetCommonInstanceMetadata(ctx context.Context, projectID string, m *compute.Metadata) error {
|
|
||||||
rk := &RateLimitKey{
|
|
||||||
ProjectID: projectID,
|
|
||||||
Operation: "SetCommonInstanceMetadata",
|
|
||||||
Version: meta.Version("ga"),
|
|
||||||
Service: "Projects",
|
|
||||||
}
|
|
||||||
if err := g.s.RateLimiter.Accept(ctx, rk); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
call := g.s.GA.Projects.SetCommonInstanceMetadata(projectID, m)
|
|
||||||
call.Context(ctx)
|
|
||||||
|
|
||||||
op, err := call.Do()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return g.s.WaitForCompletion(ctx, op)
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,29 +0,0 @@
|
||||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = ["main.go"],
|
|
||||||
importpath = "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/gen",
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
deps = ["//pkg/cloudprovider/providers/gce/cloud/meta:go_default_library"],
|
|
||||||
)
|
|
||||||
|
|
||||||
go_binary(
|
|
||||||
name = "gen",
|
|
||||||
embed = [":go_default_library"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [":package-srcs"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,39 +0,0 @@
|
||||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = [
|
|
||||||
"doc.go",
|
|
||||||
"key.go",
|
|
||||||
"meta.go",
|
|
||||||
"method.go",
|
|
||||||
"service.go",
|
|
||||||
],
|
|
||||||
importpath = "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta",
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
deps = [
|
|
||||||
"//vendor/google.golang.org/api/compute/v0.alpha:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v0.beta:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v1:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
go_test(
|
|
||||||
name = "go_default_test",
|
|
||||||
srcs = ["key_test.go"],
|
|
||||||
embed = [":go_default_library"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [":package-srcs"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 meta contains the meta description of the GCE cloud types to
|
|
||||||
// generate code for.
|
|
||||||
package meta
|
|
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 meta
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Key for a GCP resource.
|
|
||||||
type Key struct {
|
|
||||||
Name string
|
|
||||||
Zone string
|
|
||||||
Region string
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyType is the type of the key.
|
|
||||||
type KeyType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Zonal key type.
|
|
||||||
Zonal = "zonal"
|
|
||||||
// Regional key type.
|
|
||||||
Regional = "regional"
|
|
||||||
// Global key type.
|
|
||||||
Global = "global"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// locationRegexp is the format of regions/zone names in GCE.
|
|
||||||
locationRegexp = regexp.MustCompile("^[a-z](?:[-a-z0-9]+)?$")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ZonalKey returns the key for a zonal resource.
|
|
||||||
func ZonalKey(name, zone string) *Key {
|
|
||||||
return &Key{name, zone, ""}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegionalKey returns the key for a regional resource.
|
|
||||||
func RegionalKey(name, region string) *Key {
|
|
||||||
return &Key{name, "", region}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalKey returns the key for a global resource.
|
|
||||||
func GlobalKey(name string) *Key {
|
|
||||||
return &Key{name, "", ""}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the type of the key.
|
|
||||||
func (k *Key) Type() KeyType {
|
|
||||||
switch {
|
|
||||||
case k.Zone != "":
|
|
||||||
return Zonal
|
|
||||||
case k.Region != "":
|
|
||||||
return Regional
|
|
||||||
default:
|
|
||||||
return Global
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of the key.
|
|
||||||
func (k Key) String() string {
|
|
||||||
switch k.Type() {
|
|
||||||
case Zonal:
|
|
||||||
return fmt.Sprintf("Key{%q, zone: %q}", k.Name, k.Zone)
|
|
||||||
case Regional:
|
|
||||||
return fmt.Sprintf("Key{%q, region: %q}", k.Name, k.Region)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("Key{%q}", k.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Valid is true if the key is valid.
|
|
||||||
func (k *Key) Valid() bool {
|
|
||||||
if k.Zone != "" && k.Region != "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case k.Region != "":
|
|
||||||
return locationRegexp.Match([]byte(k.Region))
|
|
||||||
case k.Zone != "":
|
|
||||||
return locationRegexp.Match([]byte(k.Zone))
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeysToMap creates a map[Key]bool from a list of keys.
|
|
||||||
func KeysToMap(keys ...Key) map[Key]bool {
|
|
||||||
ret := map[Key]bool{}
|
|
||||||
for _, k := range keys {
|
|
||||||
ret[k] = true
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 meta
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestKeyType(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
key *Key
|
|
||||||
want KeyType
|
|
||||||
}{
|
|
||||||
{GlobalKey("abc"), Global},
|
|
||||||
{ZonalKey("abc", "us-central1-b"), Zonal},
|
|
||||||
{RegionalKey("abc", "us-central1"), Regional},
|
|
||||||
} {
|
|
||||||
if tc.key.Type() != tc.want {
|
|
||||||
t.Errorf("key.Type() == %v, want %v", tc.key.Type(), tc.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeyString(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, k := range []*Key{
|
|
||||||
GlobalKey("abc"),
|
|
||||||
RegionalKey("abc", "us-central1"),
|
|
||||||
ZonalKey("abc", "us-central1-b"),
|
|
||||||
} {
|
|
||||||
if k.String() == "" {
|
|
||||||
t.Errorf(`k.String() = "", want non-empty`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeyValid(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
region := "us-central1"
|
|
||||||
zone := "us-central1-b"
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
key *Key
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{GlobalKey("abc"), true},
|
|
||||||
{RegionalKey("abc", region), true},
|
|
||||||
{ZonalKey("abc", zone), true},
|
|
||||||
{RegionalKey("abc", "/invalid/"), false},
|
|
||||||
{ZonalKey("abc", "/invalid/"), false},
|
|
||||||
{&Key{"abc", zone, region}, false},
|
|
||||||
} {
|
|
||||||
got := tc.key.Valid()
|
|
||||||
if got != tc.want {
|
|
||||||
t.Errorf("key %+v; key.Valid() = %v, want %v", tc.key, got, tc.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,440 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 meta
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
alpha "google.golang.org/api/compute/v0.alpha"
|
|
||||||
beta "google.golang.org/api/compute/v0.beta"
|
|
||||||
ga "google.golang.org/api/compute/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Version of the API (ga, alpha, beta).
|
|
||||||
type Version string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// NoGet prevents the Get() method from being generated.
|
|
||||||
NoGet = 1 << iota
|
|
||||||
// NoList prevents the List() method from being generated.
|
|
||||||
NoList = 1 << iota
|
|
||||||
// NoDelete prevents the Delete() method from being generated.
|
|
||||||
NoDelete = 1 << iota
|
|
||||||
// NoInsert prevents the Insert() method from being generated.
|
|
||||||
NoInsert = 1 << iota
|
|
||||||
// CustomOps specifies that an empty interface xxxOps will be generated to
|
|
||||||
// enable custom method calls to be attached to the generated service
|
|
||||||
// interface.
|
|
||||||
CustomOps = 1 << iota
|
|
||||||
// AggregatedList will generated a method for AggregatedList().
|
|
||||||
AggregatedList = 1 << iota
|
|
||||||
|
|
||||||
// ReadOnly specifies that the given resource is read-only and should not
|
|
||||||
// have insert() or delete() methods generated for the wrapper.
|
|
||||||
ReadOnly = NoDelete | NoInsert
|
|
||||||
|
|
||||||
// VersionGA is the API version in compute.v1.
|
|
||||||
VersionGA Version = "ga"
|
|
||||||
// VersionAlpha is the API version in computer.v0.alpha.
|
|
||||||
VersionAlpha Version = "alpha"
|
|
||||||
// VersionBeta is the API version in computer.v0.beta.
|
|
||||||
VersionBeta Version = "beta"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AllVersions is a list of all versions of the GCE API.
|
|
||||||
var AllVersions = []Version{
|
|
||||||
VersionGA,
|
|
||||||
VersionAlpha,
|
|
||||||
VersionBeta,
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllServices are a list of all the services to generate code for. Keep
|
|
||||||
// this list in lexiographical order by object type.
|
|
||||||
var AllServices = []*ServiceInfo{
|
|
||||||
{
|
|
||||||
Object: "Address",
|
|
||||||
Service: "Addresses",
|
|
||||||
Resource: "addresses",
|
|
||||||
keyType: Regional,
|
|
||||||
serviceType: reflect.TypeOf(&ga.AddressesService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Address",
|
|
||||||
Service: "Addresses",
|
|
||||||
Resource: "addresses",
|
|
||||||
version: VersionAlpha,
|
|
||||||
keyType: Regional,
|
|
||||||
serviceType: reflect.TypeOf(&alpha.AddressesService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Address",
|
|
||||||
Service: "Addresses",
|
|
||||||
Resource: "addresses",
|
|
||||||
version: VersionBeta,
|
|
||||||
keyType: Regional,
|
|
||||||
serviceType: reflect.TypeOf(&beta.AddressesService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Address",
|
|
||||||
Service: "GlobalAddresses",
|
|
||||||
Resource: "addresses",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.GlobalAddressesService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "BackendService",
|
|
||||||
Service: "BackendServices",
|
|
||||||
Resource: "backendServices",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.BackendServicesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"GetHealth",
|
|
||||||
"Patch",
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "BackendService",
|
|
||||||
Service: "BackendServices",
|
|
||||||
Resource: "backendServices",
|
|
||||||
version: VersionBeta,
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&beta.BackendServicesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Update",
|
|
||||||
"SetSecurityPolicy",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "BackendService",
|
|
||||||
Service: "BackendServices",
|
|
||||||
Resource: "backendServices",
|
|
||||||
version: VersionAlpha,
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&alpha.BackendServicesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Update",
|
|
||||||
"SetSecurityPolicy",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "BackendService",
|
|
||||||
Service: "RegionBackendServices",
|
|
||||||
Resource: "backendServices",
|
|
||||||
version: VersionGA,
|
|
||||||
keyType: Regional,
|
|
||||||
serviceType: reflect.TypeOf(&ga.RegionBackendServicesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"GetHealth",
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "BackendService",
|
|
||||||
Service: "RegionBackendServices",
|
|
||||||
Resource: "backendServices",
|
|
||||||
version: VersionAlpha,
|
|
||||||
keyType: Regional,
|
|
||||||
serviceType: reflect.TypeOf(&alpha.RegionBackendServicesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"GetHealth",
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Disk",
|
|
||||||
Service: "Disks",
|
|
||||||
Resource: "disks",
|
|
||||||
keyType: Zonal,
|
|
||||||
serviceType: reflect.TypeOf(&ga.DisksService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Resize",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Disk",
|
|
||||||
Service: "RegionDisks",
|
|
||||||
Resource: "disks",
|
|
||||||
version: VersionGA,
|
|
||||||
keyType: Regional,
|
|
||||||
serviceType: reflect.TypeOf(&ga.RegionDisksService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Resize",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Firewall",
|
|
||||||
Service: "Firewalls",
|
|
||||||
Resource: "firewalls",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.FirewallsService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "ForwardingRule",
|
|
||||||
Service: "ForwardingRules",
|
|
||||||
Resource: "forwardingRules",
|
|
||||||
keyType: Regional,
|
|
||||||
serviceType: reflect.TypeOf(&ga.ForwardingRulesService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "ForwardingRule",
|
|
||||||
Service: "ForwardingRules",
|
|
||||||
Resource: "forwardingRules",
|
|
||||||
version: VersionAlpha,
|
|
||||||
keyType: Regional,
|
|
||||||
serviceType: reflect.TypeOf(&alpha.ForwardingRulesService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "ForwardingRule",
|
|
||||||
Service: "GlobalForwardingRules",
|
|
||||||
Resource: "forwardingRules",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.GlobalForwardingRulesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"SetTarget",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "HealthCheck",
|
|
||||||
Service: "HealthChecks",
|
|
||||||
Resource: "healthChecks",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.HealthChecksService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "HealthCheck",
|
|
||||||
Service: "HealthChecks",
|
|
||||||
Resource: "healthChecks",
|
|
||||||
version: VersionBeta,
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&beta.HealthChecksService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "HealthCheck",
|
|
||||||
Service: "HealthChecks",
|
|
||||||
Resource: "healthChecks",
|
|
||||||
version: VersionAlpha,
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&alpha.HealthChecksService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "HttpHealthCheck",
|
|
||||||
Service: "HttpHealthChecks",
|
|
||||||
Resource: "httpHealthChecks",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.HttpHealthChecksService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "HttpsHealthCheck",
|
|
||||||
Service: "HttpsHealthChecks",
|
|
||||||
Resource: "httpsHealthChecks",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.HttpsHealthChecksService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "InstanceGroup",
|
|
||||||
Service: "InstanceGroups",
|
|
||||||
Resource: "instanceGroups",
|
|
||||||
keyType: Zonal,
|
|
||||||
serviceType: reflect.TypeOf(&ga.InstanceGroupsService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"AddInstances",
|
|
||||||
"ListInstances",
|
|
||||||
"RemoveInstances",
|
|
||||||
"SetNamedPorts",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Instance",
|
|
||||||
Service: "Instances",
|
|
||||||
Resource: "instances",
|
|
||||||
keyType: Zonal,
|
|
||||||
serviceType: reflect.TypeOf(&ga.InstancesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"AttachDisk",
|
|
||||||
"DetachDisk",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Instance",
|
|
||||||
Service: "Instances",
|
|
||||||
Resource: "instances",
|
|
||||||
version: VersionBeta,
|
|
||||||
keyType: Zonal,
|
|
||||||
serviceType: reflect.TypeOf(&beta.InstancesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"AttachDisk",
|
|
||||||
"DetachDisk",
|
|
||||||
"UpdateNetworkInterface",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Instance",
|
|
||||||
Service: "Instances",
|
|
||||||
Resource: "instances",
|
|
||||||
version: VersionAlpha,
|
|
||||||
keyType: Zonal,
|
|
||||||
serviceType: reflect.TypeOf(&alpha.InstancesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"AttachDisk",
|
|
||||||
"DetachDisk",
|
|
||||||
"UpdateNetworkInterface",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "NetworkEndpointGroup",
|
|
||||||
Service: "NetworkEndpointGroups",
|
|
||||||
Resource: "networkEndpointGroups",
|
|
||||||
version: VersionAlpha,
|
|
||||||
keyType: Zonal,
|
|
||||||
serviceType: reflect.TypeOf(&alpha.NetworkEndpointGroupsService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"AttachNetworkEndpoints",
|
|
||||||
"DetachNetworkEndpoints",
|
|
||||||
"ListNetworkEndpoints",
|
|
||||||
},
|
|
||||||
options: AggregatedList,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "NetworkEndpointGroup",
|
|
||||||
Service: "NetworkEndpointGroups",
|
|
||||||
Resource: "networkEndpointGroups",
|
|
||||||
version: VersionBeta,
|
|
||||||
keyType: Zonal,
|
|
||||||
serviceType: reflect.TypeOf(&beta.NetworkEndpointGroupsService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"AttachNetworkEndpoints",
|
|
||||||
"DetachNetworkEndpoints",
|
|
||||||
"ListNetworkEndpoints",
|
|
||||||
},
|
|
||||||
options: AggregatedList,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Project",
|
|
||||||
Service: "Projects",
|
|
||||||
Resource: "projects",
|
|
||||||
keyType: Global,
|
|
||||||
// Generate only the stub with no methods.
|
|
||||||
options: NoGet | NoList | NoInsert | NoDelete | CustomOps,
|
|
||||||
serviceType: reflect.TypeOf(&ga.ProjectsService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Region",
|
|
||||||
Service: "Regions",
|
|
||||||
Resource: "regions",
|
|
||||||
keyType: Global,
|
|
||||||
options: ReadOnly,
|
|
||||||
serviceType: reflect.TypeOf(&ga.RegionsService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Route",
|
|
||||||
Service: "Routes",
|
|
||||||
Resource: "routes",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.RoutesService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "SecurityPolicy",
|
|
||||||
Service: "SecurityPolicies",
|
|
||||||
Resource: "securityPolicies",
|
|
||||||
version: VersionBeta,
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&beta.SecurityPoliciesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"AddRule",
|
|
||||||
"GetRule",
|
|
||||||
"Patch",
|
|
||||||
"PatchRule",
|
|
||||||
"RemoveRule",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "SslCertificate",
|
|
||||||
Service: "SslCertificates",
|
|
||||||
Resource: "sslCertificates",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.SslCertificatesService{}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "TargetHttpProxy",
|
|
||||||
Service: "TargetHttpProxies",
|
|
||||||
Resource: "targetHttpProxies",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.TargetHttpProxiesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"SetUrlMap",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "TargetHttpsProxy",
|
|
||||||
Service: "TargetHttpsProxies",
|
|
||||||
Resource: "targetHttpsProxies",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.TargetHttpsProxiesService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"SetSslCertificates",
|
|
||||||
"SetUrlMap",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "TargetPool",
|
|
||||||
Service: "TargetPools",
|
|
||||||
Resource: "targetPools",
|
|
||||||
keyType: Regional,
|
|
||||||
serviceType: reflect.TypeOf(&ga.TargetPoolsService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"AddInstance",
|
|
||||||
"RemoveInstance",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "UrlMap",
|
|
||||||
Service: "UrlMaps",
|
|
||||||
Resource: "urlMaps",
|
|
||||||
keyType: Global,
|
|
||||||
serviceType: reflect.TypeOf(&ga.UrlMapsService{}),
|
|
||||||
additionalMethods: []string{
|
|
||||||
"Update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Object: "Zone",
|
|
||||||
Service: "Zones",
|
|
||||||
Resource: "zones",
|
|
||||||
keyType: Global,
|
|
||||||
options: ReadOnly,
|
|
||||||
serviceType: reflect.TypeOf(&ga.ZonesService{}),
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,337 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 meta
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newArg(t reflect.Type) *arg {
|
|
||||||
ret := &arg{}
|
|
||||||
|
|
||||||
// Dereference the pointer types to get at the underlying concrete type.
|
|
||||||
Loop:
|
|
||||||
for {
|
|
||||||
switch t.Kind() {
|
|
||||||
case reflect.Ptr:
|
|
||||||
ret.numPtr++
|
|
||||||
t = t.Elem()
|
|
||||||
default:
|
|
||||||
ret.pkg = t.PkgPath()
|
|
||||||
ret.typeName += t.Name()
|
|
||||||
break Loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
type arg struct {
|
|
||||||
pkg, typeName string
|
|
||||||
numPtr int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *arg) normalizedPkg() string {
|
|
||||||
if a.pkg == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip the repo.../vendor/ prefix from the package path if present.
|
|
||||||
parts := strings.Split(a.pkg, "/")
|
|
||||||
// Remove vendor prefix.
|
|
||||||
for i := 0; i < len(parts); i++ {
|
|
||||||
if parts[i] == "vendor" {
|
|
||||||
parts = parts[i+1:]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch strings.Join(parts, "/") {
|
|
||||||
case "google.golang.org/api/compute/v1":
|
|
||||||
return "ga."
|
|
||||||
case "google.golang.org/api/compute/v0.alpha":
|
|
||||||
return "alpha."
|
|
||||||
case "google.golang.org/api/compute/v0.beta":
|
|
||||||
return "beta."
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unhandled package %q", a.pkg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *arg) String() string {
|
|
||||||
var ret string
|
|
||||||
for i := 0; i < a.numPtr; i++ {
|
|
||||||
ret += "*"
|
|
||||||
}
|
|
||||||
ret += a.normalizedPkg()
|
|
||||||
ret += a.typeName
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// newMethod returns a newly initialized method.
|
|
||||||
func newMethod(s *ServiceInfo, m reflect.Method) *Method {
|
|
||||||
ret := &Method{
|
|
||||||
ServiceInfo: s,
|
|
||||||
m: m,
|
|
||||||
kind: MethodOperation,
|
|
||||||
ReturnType: "",
|
|
||||||
}
|
|
||||||
ret.init()
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// MethodKind is the type of method that we are generated code for.
|
|
||||||
type MethodKind int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// MethodOperation is a long running method that returns an operation.
|
|
||||||
MethodOperation MethodKind = iota
|
|
||||||
// MethodGet is a method that immediately returns some data.
|
|
||||||
MethodGet MethodKind = iota
|
|
||||||
// MethodPaged is a method that returns a paged set of data.
|
|
||||||
MethodPaged MethodKind = iota
|
|
||||||
)
|
|
||||||
|
|
||||||
// Method is used to generate the calling code for non-standard methods.
|
|
||||||
type Method struct {
|
|
||||||
*ServiceInfo
|
|
||||||
m reflect.Method
|
|
||||||
|
|
||||||
kind MethodKind
|
|
||||||
// ReturnType is the return type for the method.
|
|
||||||
ReturnType string
|
|
||||||
// ItemType is the type of the individual elements returns from a
|
|
||||||
// Pages() call. This is only applicable for MethodPaged kind.
|
|
||||||
ItemType string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOperation is true if the method is an Operation.
|
|
||||||
func (m *Method) IsOperation() bool {
|
|
||||||
return m.kind == MethodOperation
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPaged is true if the method paged.
|
|
||||||
func (m *Method) IsPaged() bool {
|
|
||||||
return m.kind == MethodPaged
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsGet is true if the method simple get.
|
|
||||||
func (m *Method) IsGet() bool {
|
|
||||||
return m.kind == MethodGet
|
|
||||||
}
|
|
||||||
|
|
||||||
// argsSkip is the number of arguments to skip when generating the
|
|
||||||
// synthesized method.
|
|
||||||
func (m *Method) argsSkip() int {
|
|
||||||
switch m.keyType {
|
|
||||||
case Zonal:
|
|
||||||
return 4
|
|
||||||
case Regional:
|
|
||||||
return 4
|
|
||||||
case Global:
|
|
||||||
return 3
|
|
||||||
}
|
|
||||||
panic(fmt.Errorf("invalid KeyType %v", m.keyType))
|
|
||||||
}
|
|
||||||
|
|
||||||
// args return a list of arguments to the method, skipping the first skip
|
|
||||||
// elements. If nameArgs is true, then the arguments will include a generated
|
|
||||||
// parameter name (arg<N>). prefix will be added to the parameters.
|
|
||||||
func (m *Method) args(skip int, nameArgs bool, prefix []string) []string {
|
|
||||||
var args []*arg
|
|
||||||
fType := m.m.Func.Type()
|
|
||||||
for i := 0; i < fType.NumIn(); i++ {
|
|
||||||
t := fType.In(i)
|
|
||||||
args = append(args, newArg(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
var a []string
|
|
||||||
for i := skip; i < fType.NumIn(); i++ {
|
|
||||||
if nameArgs {
|
|
||||||
a = append(a, fmt.Sprintf("arg%d %s", i-skip, args[i]))
|
|
||||||
} else {
|
|
||||||
a = append(a, args[i].String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return append(prefix, a...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// init the method. This performs some rudimentary static checking as well as
|
|
||||||
// determines the kind of method by looking at the shape (method signature) of
|
|
||||||
// the object.
|
|
||||||
func (m *Method) init() {
|
|
||||||
fType := m.m.Func.Type()
|
|
||||||
if fType.NumIn() < m.argsSkip() {
|
|
||||||
err := fmt.Errorf("method %q.%q, arity = %d which is less than required (< %d)",
|
|
||||||
m.Service, m.Name(), fType.NumIn(), m.argsSkip())
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
// Skipped args should all be string (they will be projectID, zone, region etc).
|
|
||||||
for i := 1; i < m.argsSkip(); i++ {
|
|
||||||
if fType.In(i).Kind() != reflect.String {
|
|
||||||
panic(fmt.Errorf("method %q.%q: skipped args can only be strings", m.Service, m.Name()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Return of the method must return a single value of type *xxxCall.
|
|
||||||
if fType.NumOut() != 1 || fType.Out(0).Kind() != reflect.Ptr || !strings.HasSuffix(fType.Out(0).Elem().Name(), "Call") {
|
|
||||||
panic(fmt.Errorf("method %q.%q: generator only supports methods returning an *xxxCall object",
|
|
||||||
m.Service, m.Name()))
|
|
||||||
}
|
|
||||||
returnType := fType.Out(0)
|
|
||||||
returnTypeName := fType.Out(0).Elem().Name()
|
|
||||||
// xxxCall must have a Do() method.
|
|
||||||
doMethod, ok := returnType.MethodByName("Do")
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Errorf("method %q.%q: return type %q does not have a Do() method",
|
|
||||||
m.Service, m.Name(), returnTypeName))
|
|
||||||
}
|
|
||||||
_, hasPages := returnType.MethodByName("Pages")
|
|
||||||
// Do() method must return (*T, error).
|
|
||||||
switch doMethod.Func.Type().NumOut() {
|
|
||||||
case 2:
|
|
||||||
out0 := doMethod.Func.Type().Out(0)
|
|
||||||
if out0.Kind() != reflect.Ptr {
|
|
||||||
panic(fmt.Errorf("method %q.%q: return type %q of Do() = S, _; S must be pointer type (%v)",
|
|
||||||
m.Service, m.Name(), returnTypeName, out0))
|
|
||||||
}
|
|
||||||
m.ReturnType = out0.Elem().Name()
|
|
||||||
switch {
|
|
||||||
case out0.Elem().Name() == "Operation":
|
|
||||||
m.kind = MethodOperation
|
|
||||||
case hasPages:
|
|
||||||
m.kind = MethodPaged
|
|
||||||
// Pages() returns a xxxList that has the actual list
|
|
||||||
// of objects in the xxxList.Items field.
|
|
||||||
listType := out0.Elem()
|
|
||||||
itemsField, ok := listType.FieldByName("Items")
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Errorf("method %q.%q: paged return type %q does not have a .Items field", m.Service, m.Name(), listType.Name()))
|
|
||||||
}
|
|
||||||
// itemsField will be a []*ItemType. Dereference to
|
|
||||||
// extract the ItemType.
|
|
||||||
itemsType := itemsField.Type
|
|
||||||
if itemsType.Kind() != reflect.Slice && itemsType.Elem().Kind() != reflect.Ptr {
|
|
||||||
panic(fmt.Errorf("method %q.%q: paged return type %q.Items is not an array of pointers", m.Service, m.Name(), listType.Name()))
|
|
||||||
}
|
|
||||||
m.ItemType = itemsType.Elem().Elem().Name()
|
|
||||||
default:
|
|
||||||
m.kind = MethodGet
|
|
||||||
}
|
|
||||||
// Second argument must be "error".
|
|
||||||
if doMethod.Func.Type().Out(1).Name() != "error" {
|
|
||||||
panic(fmt.Errorf("method %q.%q: return type %q of Do() = S, T; T must be 'error'",
|
|
||||||
m.Service, m.Name(), returnTypeName))
|
|
||||||
}
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("method %q.%q: %q Do() return type is not handled by the generator",
|
|
||||||
m.Service, m.Name(), returnTypeName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name is the name of the method.
|
|
||||||
func (m *Method) Name() string {
|
|
||||||
return m.m.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallArgs is a list of comma separated "argN" used for calling the method.
|
|
||||||
// For example, if the method has two additional arguments, this will return
|
|
||||||
// "arg0, arg1".
|
|
||||||
func (m *Method) CallArgs() string {
|
|
||||||
var args []string
|
|
||||||
for i := m.argsSkip(); i < m.m.Func.Type().NumIn(); i++ {
|
|
||||||
args = append(args, fmt.Sprintf("arg%d", i-m.argsSkip()))
|
|
||||||
}
|
|
||||||
if len(args) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(", %s", strings.Join(args, ", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockHookName is the name of the hook function in the mock.
|
|
||||||
func (m *Method) MockHookName() string {
|
|
||||||
return m.m.Name + "Hook"
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockHook is the definition of the hook function.
|
|
||||||
func (m *Method) MockHook() string {
|
|
||||||
args := m.args(m.argsSkip(), false, []string{
|
|
||||||
"context.Context",
|
|
||||||
"*meta.Key",
|
|
||||||
})
|
|
||||||
if m.kind == MethodPaged {
|
|
||||||
args = append(args, "*filter.F")
|
|
||||||
}
|
|
||||||
|
|
||||||
args = append(args, fmt.Sprintf("*%s", m.MockWrapType()))
|
|
||||||
|
|
||||||
switch m.kind {
|
|
||||||
case MethodOperation:
|
|
||||||
return fmt.Sprintf("%v func(%v) error", m.MockHookName(), strings.Join(args, ", "))
|
|
||||||
case MethodGet:
|
|
||||||
return fmt.Sprintf("%v func(%v) (*%v.%v, error)", m.MockHookName(), strings.Join(args, ", "), m.Version(), m.ReturnType)
|
|
||||||
case MethodPaged:
|
|
||||||
return fmt.Sprintf("%v func(%v) ([]*%v.%v, error)", m.MockHookName(), strings.Join(args, ", "), m.Version(), m.ItemType)
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("invalid method kind: %v", m.kind))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FcnArgs is the function signature for the definition of the method.
|
|
||||||
func (m *Method) FcnArgs() string {
|
|
||||||
args := m.args(m.argsSkip(), true, []string{
|
|
||||||
"ctx context.Context",
|
|
||||||
"key *meta.Key",
|
|
||||||
})
|
|
||||||
if m.kind == MethodPaged {
|
|
||||||
args = append(args, "fl *filter.F")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch m.kind {
|
|
||||||
case MethodOperation:
|
|
||||||
return fmt.Sprintf("%v(%v) error", m.m.Name, strings.Join(args, ", "))
|
|
||||||
case MethodGet:
|
|
||||||
return fmt.Sprintf("%v(%v) (*%v.%v, error)", m.m.Name, strings.Join(args, ", "), m.Version(), m.ReturnType)
|
|
||||||
case MethodPaged:
|
|
||||||
return fmt.Sprintf("%v(%v) ([]*%v.%v, error)", m.m.Name, strings.Join(args, ", "), m.Version(), m.ItemType)
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("invalid method kind: %v", m.kind))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// InterfaceFunc is the function declaration of the method in the interface.
|
|
||||||
func (m *Method) InterfaceFunc() string {
|
|
||||||
args := []string{
|
|
||||||
"context.Context",
|
|
||||||
"*meta.Key",
|
|
||||||
}
|
|
||||||
args = m.args(m.argsSkip(), false, args)
|
|
||||||
if m.kind == MethodPaged {
|
|
||||||
args = append(args, "*filter.F")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch m.kind {
|
|
||||||
case MethodOperation:
|
|
||||||
return fmt.Sprintf("%v(%v) error", m.m.Name, strings.Join(args, ", "))
|
|
||||||
case MethodGet:
|
|
||||||
return fmt.Sprintf("%v(%v) (*%v.%v, error)", m.m.Name, strings.Join(args, ", "), m.Version(), m.ReturnType)
|
|
||||||
case MethodPaged:
|
|
||||||
return fmt.Sprintf("%v(%v) ([]*%v.%v, error)", m.m.Name, strings.Join(args, ", "), m.Version(), m.ItemType)
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("invalid method kind: %v", m.kind))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,300 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 meta
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ServiceInfo defines the entry for a Service that code will be generated for.
|
|
||||||
type ServiceInfo struct {
|
|
||||||
// Object is the Go name of the object type that the service deals
|
|
||||||
// with. Example: "ForwardingRule".
|
|
||||||
Object string
|
|
||||||
// Service is the Go name of the service struct i.e. where the methods
|
|
||||||
// are defined. Examples: "GlobalForwardingRules".
|
|
||||||
Service string
|
|
||||||
// Resource is the plural noun of the resource in the compute API URL (e.g.
|
|
||||||
// "forwardingRules").
|
|
||||||
Resource string
|
|
||||||
// version if unspecified will be assumed to be VersionGA.
|
|
||||||
version Version
|
|
||||||
keyType KeyType
|
|
||||||
serviceType reflect.Type
|
|
||||||
|
|
||||||
additionalMethods []string
|
|
||||||
options int
|
|
||||||
aggregatedListField string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version returns the version of the Service, defaulting to GA if APIVersion
|
|
||||||
// is empty.
|
|
||||||
func (i *ServiceInfo) Version() Version {
|
|
||||||
if i.version == "" {
|
|
||||||
return VersionGA
|
|
||||||
}
|
|
||||||
return i.version
|
|
||||||
}
|
|
||||||
|
|
||||||
// VersionTitle returns the capitalized golang CamelCase name for the version.
|
|
||||||
func (i *ServiceInfo) VersionTitle() string {
|
|
||||||
switch i.Version() {
|
|
||||||
case VersionGA:
|
|
||||||
return "GA"
|
|
||||||
case VersionAlpha:
|
|
||||||
return "Alpha"
|
|
||||||
case VersionBeta:
|
|
||||||
return "Beta"
|
|
||||||
}
|
|
||||||
panic(fmt.Errorf("invalid version %q", i.Version()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// WrapType is the name of the wrapper service type.
|
|
||||||
func (i *ServiceInfo) WrapType() string {
|
|
||||||
switch i.Version() {
|
|
||||||
case VersionGA:
|
|
||||||
return i.Service
|
|
||||||
case VersionAlpha:
|
|
||||||
return "Alpha" + i.Service
|
|
||||||
case VersionBeta:
|
|
||||||
return "Beta" + i.Service
|
|
||||||
}
|
|
||||||
return "Invalid"
|
|
||||||
}
|
|
||||||
|
|
||||||
// WrapTypeOps is the name of the additional operations type.
|
|
||||||
func (i *ServiceInfo) WrapTypeOps() string {
|
|
||||||
return i.WrapType() + "Ops"
|
|
||||||
}
|
|
||||||
|
|
||||||
// FQObjectType is fully qualified name of the object (e.g. compute.Instance).
|
|
||||||
func (i *ServiceInfo) FQObjectType() string {
|
|
||||||
return fmt.Sprintf("%v.%v", i.Version(), i.Object)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObjectListType is the compute List type for the object (contains Items field).
|
|
||||||
func (i *ServiceInfo) ObjectListType() string {
|
|
||||||
return fmt.Sprintf("%v.%vList", i.Version(), i.Object)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ObjectAggregatedListType is the compute List type for the object (contains Items field).
|
|
||||||
func (i *ServiceInfo) ObjectAggregatedListType() string {
|
|
||||||
return fmt.Sprintf("%v.%vAggregatedList", i.Version(), i.Object)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockWrapType is the name of the concrete mock for this type.
|
|
||||||
func (i *ServiceInfo) MockWrapType() string {
|
|
||||||
return "Mock" + i.WrapType()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockField is the name of the field in the mock struct.
|
|
||||||
func (i *ServiceInfo) MockField() string {
|
|
||||||
return "Mock" + i.WrapType()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GCEWrapType is the name of the GCE wrapper type.
|
|
||||||
func (i *ServiceInfo) GCEWrapType() string {
|
|
||||||
return "GCE" + i.WrapType()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Field is the name of the GCE struct.
|
|
||||||
func (i *ServiceInfo) Field() string {
|
|
||||||
return "gce" + i.WrapType()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Methods returns a list of additional methods to generate code for.
|
|
||||||
func (i *ServiceInfo) Methods() []*Method {
|
|
||||||
methods := map[string]bool{}
|
|
||||||
for _, m := range i.additionalMethods {
|
|
||||||
methods[m] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
var ret []*Method
|
|
||||||
for j := 0; j < i.serviceType.NumMethod(); j++ {
|
|
||||||
m := i.serviceType.Method(j)
|
|
||||||
if _, ok := methods[m.Name]; !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ret = append(ret, newMethod(i, m))
|
|
||||||
methods[m.Name] = false
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, b := range methods {
|
|
||||||
if b {
|
|
||||||
panic(fmt.Errorf("method %q was not found in service %q", k, i.Service))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyIsGlobal is true if the key is global.
|
|
||||||
func (i *ServiceInfo) KeyIsGlobal() bool {
|
|
||||||
return i.keyType == Global
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyIsRegional is true if the key is regional.
|
|
||||||
func (i *ServiceInfo) KeyIsRegional() bool {
|
|
||||||
return i.keyType == Regional
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyIsZonal is true if the key is zonal.
|
|
||||||
func (i *ServiceInfo) KeyIsZonal() bool {
|
|
||||||
return i.keyType == Zonal
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyIsProject is true if the key represents the project resource.
|
|
||||||
func (i *ServiceInfo) KeyIsProject() bool {
|
|
||||||
// Projects are a special resource for ResourceId because there is no 'key' value. This func
|
|
||||||
// is used by the generator to not accept a key parameter.
|
|
||||||
return i.Service == "Projects"
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeKey returns the call used to create the appropriate key type.
|
|
||||||
func (i *ServiceInfo) MakeKey(name, location string) string {
|
|
||||||
switch i.keyType {
|
|
||||||
case Global:
|
|
||||||
return fmt.Sprintf("GlobalKey(%q)", name)
|
|
||||||
case Regional:
|
|
||||||
return fmt.Sprintf("RegionalKey(%q, %q)", name, location)
|
|
||||||
case Zonal:
|
|
||||||
return fmt.Sprintf("ZonalKey(%q, %q)", name, location)
|
|
||||||
}
|
|
||||||
return "Invalid"
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateGet is true if the method is to be generated.
|
|
||||||
func (i *ServiceInfo) GenerateGet() bool {
|
|
||||||
return i.options&NoGet == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateList is true if the method is to be generated.
|
|
||||||
func (i *ServiceInfo) GenerateList() bool {
|
|
||||||
return i.options&NoList == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateDelete is true if the method is to be generated.
|
|
||||||
func (i *ServiceInfo) GenerateDelete() bool {
|
|
||||||
return i.options&NoDelete == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateInsert is true if the method is to be generated.
|
|
||||||
func (i *ServiceInfo) GenerateInsert() bool {
|
|
||||||
return i.options&NoInsert == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateCustomOps is true if we should generated a xxxOps interface for
|
|
||||||
// adding additional methods to the generated interface.
|
|
||||||
func (i *ServiceInfo) GenerateCustomOps() bool {
|
|
||||||
return i.options&CustomOps != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// AggregatedList is true if the method is to be generated.
|
|
||||||
func (i *ServiceInfo) AggregatedList() bool {
|
|
||||||
return i.options&AggregatedList != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// AggregatedListField is the name of the field used for the aggregated list
|
|
||||||
// call. This is typically the same as the name of the service, but can be
|
|
||||||
// customized by setting the aggregatedListField field.
|
|
||||||
func (i *ServiceInfo) AggregatedListField() string {
|
|
||||||
if i.aggregatedListField == "" {
|
|
||||||
return i.Service
|
|
||||||
}
|
|
||||||
return i.aggregatedListField
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceGroup is a grouping of the same service but at different API versions.
|
|
||||||
type ServiceGroup struct {
|
|
||||||
Alpha *ServiceInfo
|
|
||||||
Beta *ServiceInfo
|
|
||||||
GA *ServiceInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// Service returns any ServiceInfo string belonging to the ServiceGroup.
|
|
||||||
func (sg *ServiceGroup) Service() string {
|
|
||||||
return sg.ServiceInfo().Service
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceInfo returns any ServiceInfo object belonging to the ServiceGroup.
|
|
||||||
func (sg *ServiceGroup) ServiceInfo() *ServiceInfo {
|
|
||||||
switch {
|
|
||||||
case sg.GA != nil:
|
|
||||||
return sg.GA
|
|
||||||
case sg.Alpha != nil:
|
|
||||||
return sg.Alpha
|
|
||||||
case sg.Beta != nil:
|
|
||||||
return sg.Beta
|
|
||||||
default:
|
|
||||||
panic(errors.New("service group is empty"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasGA returns true if this object has a GA representation.
|
|
||||||
func (sg *ServiceGroup) HasGA() bool {
|
|
||||||
return sg.GA != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasAlpha returns true if this object has a Alpha representation.
|
|
||||||
func (sg *ServiceGroup) HasAlpha() bool {
|
|
||||||
return sg.Alpha != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasBeta returns true if this object has a Beta representation.
|
|
||||||
func (sg *ServiceGroup) HasBeta() bool {
|
|
||||||
return sg.Beta != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// groupServices together by version.
|
|
||||||
func groupServices(services []*ServiceInfo) map[string]*ServiceGroup {
|
|
||||||
ret := map[string]*ServiceGroup{}
|
|
||||||
for _, si := range services {
|
|
||||||
if _, ok := ret[si.Service]; !ok {
|
|
||||||
ret[si.Service] = &ServiceGroup{}
|
|
||||||
}
|
|
||||||
group := ret[si.Service]
|
|
||||||
switch si.Version() {
|
|
||||||
case VersionAlpha:
|
|
||||||
group.Alpha = si
|
|
||||||
case VersionBeta:
|
|
||||||
group.Beta = si
|
|
||||||
case VersionGA:
|
|
||||||
group.GA = si
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllServicesByGroup is a map of service name to ServicesGroup.
|
|
||||||
var AllServicesByGroup map[string]*ServiceGroup
|
|
||||||
|
|
||||||
// SortedServicesGroups is a slice of Servicegroup sorted by Service name.
|
|
||||||
var SortedServicesGroups []*ServiceGroup
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
AllServicesByGroup = groupServices(AllServices)
|
|
||||||
|
|
||||||
for _, sg := range AllServicesByGroup {
|
|
||||||
SortedServicesGroups = append(SortedServicesGroups, sg)
|
|
||||||
}
|
|
||||||
sort.Slice(SortedServicesGroups, func(i, j int) bool {
|
|
||||||
return SortedServicesGroups[i].Service() < SortedServicesGroups[j].Service()
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = ["mock.go"],
|
|
||||||
importpath = "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/mock",
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
deps = [
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud:go_default_library",
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/filter:go_default_library",
|
|
||||||
"//pkg/cloudprovider/providers/gce/cloud/meta:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v0.alpha:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v0.beta:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/compute/v1:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/googleapi:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [":package-srcs"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
|
@ -1,640 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 mock encapsulates mocks for testing GCE provider functionality.
|
|
||||||
// These methods are used to override the mock objects' methods in order to
|
|
||||||
// intercept the standard processing and to add custom logic for test purposes.
|
|
||||||
//
|
|
||||||
// // Example usage:
|
|
||||||
// cloud := cloud.NewMockGCE()
|
|
||||||
// cloud.MockTargetPools.AddInstanceHook = mock.AddInstanceHook
|
|
||||||
package mock
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
alpha "google.golang.org/api/compute/v0.alpha"
|
|
||||||
beta "google.golang.org/api/compute/v0.beta"
|
|
||||||
ga "google.golang.org/api/compute/v1"
|
|
||||||
"google.golang.org/api/googleapi"
|
|
||||||
cloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/filter"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// InUseError is a shared variable with error code StatusBadRequest for error verification.
|
|
||||||
InUseError = &googleapi.Error{Code: http.StatusBadRequest, Message: "It's being used by god."}
|
|
||||||
// InternalServerError is shared variable with error code StatusInternalServerError for error verification.
|
|
||||||
InternalServerError = &googleapi.Error{Code: http.StatusInternalServerError}
|
|
||||||
// UnauthorizedErr wraps a Google API error with code StatusForbidden.
|
|
||||||
UnauthorizedErr = &googleapi.Error{Code: http.StatusForbidden}
|
|
||||||
)
|
|
||||||
|
|
||||||
// gceObject is an abstraction of all GCE API object in go client
|
|
||||||
type gceObject interface {
|
|
||||||
MarshalJSON() ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddInstanceHook mocks adding a Instance to MockTargetPools
|
|
||||||
func AddInstanceHook(ctx context.Context, key *meta.Key, req *ga.TargetPoolsAddInstanceRequest, m *cloud.MockTargetPools) error {
|
|
||||||
pool, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in TargetPools", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, instance := range req.Instances {
|
|
||||||
pool.Instances = append(pool.Instances, instance.Instance)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveInstanceHook mocks removing a Instance from MockTargetPools
|
|
||||||
func RemoveInstanceHook(ctx context.Context, key *meta.Key, req *ga.TargetPoolsRemoveInstanceRequest, m *cloud.MockTargetPools) error {
|
|
||||||
pool, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in TargetPools", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, instanceToRemove := range req.Instances {
|
|
||||||
for i, instance := range pool.Instances {
|
|
||||||
if instanceToRemove.Instance == instance {
|
|
||||||
// Delete instance from pool.Instances without preserving order
|
|
||||||
pool.Instances[i] = pool.Instances[len(pool.Instances)-1]
|
|
||||||
pool.Instances = pool.Instances[:len(pool.Instances)-1]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertAndInsertAlphaForwardingRule(key *meta.Key, obj gceObject, mRules map[meta.Key]*cloud.MockForwardingRulesObj, version meta.Version, projectID string) (bool, error) {
|
|
||||||
if !key.Valid() {
|
|
||||||
return true, fmt.Errorf("invalid GCE key (%+v)", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := mRules[*key]; ok {
|
|
||||||
err := &googleapi.Error{
|
|
||||||
Code: http.StatusConflict,
|
|
||||||
Message: fmt.Sprintf("MockForwardingRule %v exists", key),
|
|
||||||
}
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
enc, err := obj.MarshalJSON()
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
var fwdRule alpha.ForwardingRule
|
|
||||||
if err := json.Unmarshal(enc, &fwdRule); err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
// Set the default values for the Alpha fields.
|
|
||||||
if fwdRule.NetworkTier == "" {
|
|
||||||
fwdRule.NetworkTier = cloud.NetworkTierDefault.ToGCEValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
fwdRule.Name = key.Name
|
|
||||||
if fwdRule.SelfLink == "" {
|
|
||||||
fwdRule.SelfLink = cloud.SelfLink(version, projectID, "forwardingRules", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
mRules[*key] = &cloud.MockForwardingRulesObj{Obj: fwdRule}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertFwdRuleHook mocks inserting a ForwardingRule. ForwardingRules are
|
|
||||||
// expected to default to Premium tier if no NetworkTier is specified.
|
|
||||||
func InsertFwdRuleHook(ctx context.Context, key *meta.Key, obj *ga.ForwardingRule, m *cloud.MockForwardingRules) (bool, error) {
|
|
||||||
m.Lock.Lock()
|
|
||||||
defer m.Lock.Unlock()
|
|
||||||
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionGA, "forwardingRules")
|
|
||||||
return convertAndInsertAlphaForwardingRule(key, obj, m.Objects, meta.VersionGA, projectID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertBetaFwdRuleHook mocks inserting a BetaForwardingRule.
|
|
||||||
func InsertBetaFwdRuleHook(ctx context.Context, key *meta.Key, obj *beta.ForwardingRule, m *cloud.MockForwardingRules) (bool, error) {
|
|
||||||
m.Lock.Lock()
|
|
||||||
defer m.Lock.Unlock()
|
|
||||||
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionBeta, "forwardingRules")
|
|
||||||
return convertAndInsertAlphaForwardingRule(key, obj, m.Objects, meta.VersionBeta, projectID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertAlphaFwdRuleHook mocks inserting an AlphaForwardingRule.
|
|
||||||
func InsertAlphaFwdRuleHook(ctx context.Context, key *meta.Key, obj *alpha.ForwardingRule, m *cloud.MockForwardingRules) (bool, error) {
|
|
||||||
m.Lock.Lock()
|
|
||||||
defer m.Lock.Unlock()
|
|
||||||
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionAlpha, "forwardingRules")
|
|
||||||
return convertAndInsertAlphaForwardingRule(key, obj, m.Objects, meta.VersionAlpha, projectID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddressAttributes maps from Address key to a map of Instances
|
|
||||||
type AddressAttributes struct {
|
|
||||||
IPCounter int // Used to assign Addresses with no IP a unique IP address
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertAndInsertAlphaAddress(key *meta.Key, obj gceObject, mAddrs map[meta.Key]*cloud.MockAddressesObj, version meta.Version, projectID string, addressAttrs AddressAttributes) (bool, error) {
|
|
||||||
if !key.Valid() {
|
|
||||||
return true, fmt.Errorf("invalid GCE key (%+v)", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := mAddrs[*key]; ok {
|
|
||||||
err := &googleapi.Error{
|
|
||||||
Code: http.StatusConflict,
|
|
||||||
Message: fmt.Sprintf("MockAddresses %v exists", key),
|
|
||||||
}
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
enc, err := obj.MarshalJSON()
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
var addr alpha.Address
|
|
||||||
if err := json.Unmarshal(enc, &addr); err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default address type if not present.
|
|
||||||
if addr.AddressType == "" {
|
|
||||||
addr.AddressType = string(cloud.SchemeExternal)
|
|
||||||
}
|
|
||||||
|
|
||||||
var existingAddresses []*ga.Address
|
|
||||||
for _, obj := range mAddrs {
|
|
||||||
existingAddresses = append(existingAddresses, obj.ToGA())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, existingAddr := range existingAddresses {
|
|
||||||
if addr.Address == existingAddr.Address {
|
|
||||||
msg := fmt.Sprintf("MockAddresses IP %v in use", addr.Address)
|
|
||||||
|
|
||||||
// When the IP is already in use, this call returns a StatusBadRequest
|
|
||||||
// if the address is an external address, and StatusConflict if an
|
|
||||||
// internal address. This is to be consistent with actual GCE API.
|
|
||||||
errorCode := http.StatusConflict
|
|
||||||
if addr.AddressType == string(cloud.SchemeExternal) {
|
|
||||||
errorCode = http.StatusBadRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, &googleapi.Error{Code: errorCode, Message: msg}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default values used in tests
|
|
||||||
addr.Name = key.Name
|
|
||||||
if addr.SelfLink == "" {
|
|
||||||
addr.SelfLink = cloud.SelfLink(version, projectID, "addresses", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
if addr.Address == "" {
|
|
||||||
addr.Address = fmt.Sprintf("1.2.3.%d", addressAttrs.IPCounter)
|
|
||||||
addressAttrs.IPCounter++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the default values for the Alpha fields.
|
|
||||||
if addr.NetworkTier == "" {
|
|
||||||
addr.NetworkTier = cloud.NetworkTierDefault.ToGCEValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
mAddrs[*key] = &cloud.MockAddressesObj{Obj: addr}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertAddressHook mocks inserting an Address.
|
|
||||||
func InsertAddressHook(ctx context.Context, key *meta.Key, obj *ga.Address, m *cloud.MockAddresses) (bool, error) {
|
|
||||||
m.Lock.Lock()
|
|
||||||
defer m.Lock.Unlock()
|
|
||||||
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionGA, "addresses")
|
|
||||||
return convertAndInsertAlphaAddress(key, obj, m.Objects, meta.VersionGA, projectID, m.X.(AddressAttributes))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertBetaAddressHook mocks inserting a BetaAddress.
|
|
||||||
func InsertBetaAddressHook(ctx context.Context, key *meta.Key, obj *beta.Address, m *cloud.MockAddresses) (bool, error) {
|
|
||||||
m.Lock.Lock()
|
|
||||||
defer m.Lock.Unlock()
|
|
||||||
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionBeta, "addresses")
|
|
||||||
return convertAndInsertAlphaAddress(key, obj, m.Objects, meta.VersionBeta, projectID, m.X.(AddressAttributes))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertAlphaAddressHook mocks inserting an Address. Addresses are expected to
|
|
||||||
// default to Premium tier if no NetworkTier is specified.
|
|
||||||
func InsertAlphaAddressHook(ctx context.Context, key *meta.Key, obj *alpha.Address, m *cloud.MockAlphaAddresses) (bool, error) {
|
|
||||||
m.Lock.Lock()
|
|
||||||
defer m.Lock.Unlock()
|
|
||||||
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionBeta, "addresses")
|
|
||||||
return convertAndInsertAlphaAddress(key, obj, m.Objects, meta.VersionAlpha, projectID, m.X.(AddressAttributes))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstanceGroupAttributes maps from InstanceGroup key to a map of Instances
|
|
||||||
type InstanceGroupAttributes struct {
|
|
||||||
InstanceMap map[meta.Key]map[string]*ga.InstanceWithNamedPorts
|
|
||||||
Lock *sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddInstances adds a list of Instances passed by InstanceReference
|
|
||||||
func (igAttrs *InstanceGroupAttributes) AddInstances(key *meta.Key, instanceRefs []*ga.InstanceReference) error {
|
|
||||||
igAttrs.Lock.Lock()
|
|
||||||
defer igAttrs.Lock.Unlock()
|
|
||||||
|
|
||||||
instancesWithNamedPorts, ok := igAttrs.InstanceMap[*key]
|
|
||||||
if !ok {
|
|
||||||
instancesWithNamedPorts = make(map[string]*ga.InstanceWithNamedPorts)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, instance := range instanceRefs {
|
|
||||||
iWithPort := &ga.InstanceWithNamedPorts{
|
|
||||||
Instance: instance.Instance,
|
|
||||||
}
|
|
||||||
|
|
||||||
instancesWithNamedPorts[instance.Instance] = iWithPort
|
|
||||||
}
|
|
||||||
|
|
||||||
igAttrs.InstanceMap[*key] = instancesWithNamedPorts
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveInstances removes a list of Instances passed by InstanceReference
|
|
||||||
func (igAttrs *InstanceGroupAttributes) RemoveInstances(key *meta.Key, instanceRefs []*ga.InstanceReference) error {
|
|
||||||
igAttrs.Lock.Lock()
|
|
||||||
defer igAttrs.Lock.Unlock()
|
|
||||||
|
|
||||||
instancesWithNamedPorts, ok := igAttrs.InstanceMap[*key]
|
|
||||||
if !ok {
|
|
||||||
instancesWithNamedPorts = make(map[string]*ga.InstanceWithNamedPorts)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, instanceToRemove := range instanceRefs {
|
|
||||||
if _, ok := instancesWithNamedPorts[instanceToRemove.Instance]; ok {
|
|
||||||
delete(instancesWithNamedPorts, instanceToRemove.Instance)
|
|
||||||
} else {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("%s is not a member of %s", instanceToRemove.Instance, key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
igAttrs.InstanceMap[*key] = instancesWithNamedPorts
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// List gets a list of InstanceWithNamedPorts
|
|
||||||
func (igAttrs *InstanceGroupAttributes) List(key *meta.Key) []*ga.InstanceWithNamedPorts {
|
|
||||||
igAttrs.Lock.Lock()
|
|
||||||
defer igAttrs.Lock.Unlock()
|
|
||||||
|
|
||||||
instancesWithNamedPorts, ok := igAttrs.InstanceMap[*key]
|
|
||||||
if !ok {
|
|
||||||
instancesWithNamedPorts = make(map[string]*ga.InstanceWithNamedPorts)
|
|
||||||
}
|
|
||||||
|
|
||||||
var instanceList []*ga.InstanceWithNamedPorts
|
|
||||||
for _, val := range instancesWithNamedPorts {
|
|
||||||
instanceList = append(instanceList, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
return instanceList
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddInstancesHook mocks adding instances from an InstanceGroup
|
|
||||||
func AddInstancesHook(ctx context.Context, key *meta.Key, req *ga.InstanceGroupsAddInstancesRequest, m *cloud.MockInstanceGroups) error {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in InstanceGroups", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var attrs InstanceGroupAttributes
|
|
||||||
attrs = m.X.(InstanceGroupAttributes)
|
|
||||||
attrs.AddInstances(key, req.Instances)
|
|
||||||
m.X = attrs
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListInstancesHook mocks listing instances from an InstanceGroup
|
|
||||||
func ListInstancesHook(ctx context.Context, key *meta.Key, req *ga.InstanceGroupsListInstancesRequest, filter *filter.F, m *cloud.MockInstanceGroups) ([]*ga.InstanceWithNamedPorts, error) {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in InstanceGroups", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var attrs InstanceGroupAttributes
|
|
||||||
attrs = m.X.(InstanceGroupAttributes)
|
|
||||||
instances := attrs.List(key)
|
|
||||||
|
|
||||||
return instances, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveInstancesHook mocks removing instances from an InstanceGroup
|
|
||||||
func RemoveInstancesHook(ctx context.Context, key *meta.Key, req *ga.InstanceGroupsRemoveInstancesRequest, m *cloud.MockInstanceGroups) error {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in InstanceGroups", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var attrs InstanceGroupAttributes
|
|
||||||
attrs = m.X.(InstanceGroupAttributes)
|
|
||||||
attrs.RemoveInstances(key, req.Instances)
|
|
||||||
m.X = attrs
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateFirewallHook defines the hook for updating a Firewall. It replaces the
|
|
||||||
// object with the same key in the mock with the updated object.
|
|
||||||
func UpdateFirewallHook(ctx context.Context, key *meta.Key, obj *ga.Firewall, m *cloud.MockFirewalls) error {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in Firewalls", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Name = key.Name
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, "ga", "firewalls")
|
|
||||||
obj.SelfLink = cloud.SelfLink(meta.VersionGA, projectID, "firewalls", key)
|
|
||||||
|
|
||||||
m.Objects[*key] = &cloud.MockFirewallsObj{Obj: obj}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateHealthCheckHook defines the hook for updating a HealthCheck. It
|
|
||||||
// replaces the object with the same key in the mock with the updated object.
|
|
||||||
func UpdateHealthCheckHook(ctx context.Context, key *meta.Key, obj *ga.HealthCheck, m *cloud.MockHealthChecks) error {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in HealthChecks", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Name = key.Name
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, "ga", "healthChecks")
|
|
||||||
obj.SelfLink = cloud.SelfLink(meta.VersionGA, projectID, "healthChecks", key)
|
|
||||||
|
|
||||||
m.Objects[*key] = &cloud.MockHealthChecksObj{Obj: obj}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateRegionBackendServiceHook defines the hook for updating a Region
|
|
||||||
// BackendsService. It replaces the object with the same key in the mock with
|
|
||||||
// the updated object.
|
|
||||||
func UpdateRegionBackendServiceHook(ctx context.Context, key *meta.Key, obj *ga.BackendService, m *cloud.MockRegionBackendServices) error {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in RegionBackendServices", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Name = key.Name
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, "ga", "backendServices")
|
|
||||||
obj.SelfLink = cloud.SelfLink(meta.VersionGA, projectID, "backendServices", key)
|
|
||||||
|
|
||||||
m.Objects[*key] = &cloud.MockRegionBackendServicesObj{Obj: obj}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateBackendServiceHook defines the hook for updating a BackendService.
|
|
||||||
// It replaces the object with the same key in the mock with the updated object.
|
|
||||||
func UpdateBackendServiceHook(ctx context.Context, key *meta.Key, obj *ga.BackendService, m *cloud.MockBackendServices) error {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in BackendServices", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Name = key.Name
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, "ga", "backendServices")
|
|
||||||
obj.SelfLink = cloud.SelfLink(meta.VersionGA, projectID, "backendServices", key)
|
|
||||||
|
|
||||||
m.Objects[*key] = &cloud.MockBackendServicesObj{Obj: obj}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAlphaBackendServiceHook defines the hook for updating an alpha BackendService.
|
|
||||||
// It replaces the object with the same key in the mock with the updated object.
|
|
||||||
func UpdateAlphaBackendServiceHook(ctx context.Context, key *meta.Key, obj *alpha.BackendService, m *cloud.MockAlphaBackendServices) error {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in BackendServices", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Name = key.Name
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, "alpha", "backendServices")
|
|
||||||
obj.SelfLink = cloud.SelfLink(meta.VersionAlpha, projectID, "backendServices", key)
|
|
||||||
|
|
||||||
m.Objects[*key] = &cloud.MockBackendServicesObj{Obj: obj}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateBetaBackendServiceHook defines the hook for updating an beta BackendService.
|
|
||||||
// It replaces the object with the same key in the mock with the updated object.
|
|
||||||
func UpdateBetaBackendServiceHook(ctx context.Context, key *meta.Key, obj *beta.BackendService, m *cloud.MockBetaBackendServices) error {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in BackendServices", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Name = key.Name
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, "beta", "backendServices")
|
|
||||||
obj.SelfLink = cloud.SelfLink(meta.VersionBeta, projectID, "backendServices", key)
|
|
||||||
|
|
||||||
m.Objects[*key] = &cloud.MockBackendServicesObj{Obj: obj}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateURLMapHook defines the hook for updating a UrlMap.
|
|
||||||
// It replaces the object with the same key in the mock with the updated object.
|
|
||||||
func UpdateURLMapHook(ctx context.Context, key *meta.Key, obj *ga.UrlMap, m *cloud.MockUrlMaps) error {
|
|
||||||
_, err := m.Get(ctx, key)
|
|
||||||
if err != nil {
|
|
||||||
return &googleapi.Error{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
Message: fmt.Sprintf("Key: %s was not found in UrlMaps", key.String()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Name = key.Name
|
|
||||||
projectID := m.ProjectRouter.ProjectID(ctx, "ga", "urlMaps")
|
|
||||||
obj.SelfLink = cloud.SelfLink(meta.VersionGA, projectID, "urlMaps", key)
|
|
||||||
|
|
||||||
m.Objects[*key] = &cloud.MockUrlMapsObj{Obj: obj}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertFirewallsUnauthorizedErrHook mocks firewall insertion. A forbidden error will be thrown as return.
|
|
||||||
func InsertFirewallsUnauthorizedErrHook(ctx context.Context, key *meta.Key, obj *ga.Firewall, m *cloud.MockFirewalls) (bool, error) {
|
|
||||||
return true, &googleapi.Error{Code: http.StatusForbidden}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateFirewallsUnauthorizedErrHook mocks firewall updating. A forbidden error will be thrown as return.
|
|
||||||
func UpdateFirewallsUnauthorizedErrHook(ctx context.Context, key *meta.Key, obj *ga.Firewall, m *cloud.MockFirewalls) error {
|
|
||||||
return &googleapi.Error{Code: http.StatusForbidden}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteFirewallsUnauthorizedErrHook mocks firewall deletion. A forbidden error will be thrown as return.
|
|
||||||
func DeleteFirewallsUnauthorizedErrHook(ctx context.Context, key *meta.Key, m *cloud.MockFirewalls) (bool, error) {
|
|
||||||
return true, &googleapi.Error{Code: http.StatusForbidden}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFirewallsUnauthorizedErrHook mocks firewall information retrival. A forbidden error will be thrown as return.
|
|
||||||
func GetFirewallsUnauthorizedErrHook(ctx context.Context, key *meta.Key, m *cloud.MockFirewalls) (bool, *ga.Firewall, error) {
|
|
||||||
return true, nil, &googleapi.Error{Code: http.StatusForbidden}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTargetPoolInternalErrHook mocks getting target pool. It returns a internal server error.
|
|
||||||
func GetTargetPoolInternalErrHook(ctx context.Context, key *meta.Key, m *cloud.MockTargetPools) (bool, *ga.TargetPool, error) {
|
|
||||||
return true, nil, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetForwardingRulesInternalErrHook mocks getting forwarding rules and returns an internal server error.
|
|
||||||
func GetForwardingRulesInternalErrHook(ctx context.Context, key *meta.Key, m *cloud.MockForwardingRules) (bool, *ga.ForwardingRule, error) {
|
|
||||||
return true, nil, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAddressesInternalErrHook mocks getting network address and returns an internal server error.
|
|
||||||
func GetAddressesInternalErrHook(ctx context.Context, key *meta.Key, m *cloud.MockAddresses) (bool, *ga.Address, error) {
|
|
||||||
return true, nil, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPHealthChecksInternalErrHook mocks getting http health check and returns an internal server error.
|
|
||||||
func GetHTTPHealthChecksInternalErrHook(ctx context.Context, key *meta.Key, m *cloud.MockHttpHealthChecks) (bool, *ga.HttpHealthCheck, error) {
|
|
||||||
return true, nil, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertTargetPoolsInternalErrHook mocks getting target pool and returns an internal server error.
|
|
||||||
func InsertTargetPoolsInternalErrHook(ctx context.Context, key *meta.Key, obj *ga.TargetPool, m *cloud.MockTargetPools) (bool, error) {
|
|
||||||
return true, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertForwardingRulesInternalErrHook mocks getting forwarding rule and returns an internal server error.
|
|
||||||
func InsertForwardingRulesInternalErrHook(ctx context.Context, key *meta.Key, obj *ga.ForwardingRule, m *cloud.MockForwardingRules) (bool, error) {
|
|
||||||
return true, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteAddressesNotFoundErrHook mocks deleting network address and returns a not found error.
|
|
||||||
func DeleteAddressesNotFoundErrHook(ctx context.Context, key *meta.Key, m *cloud.MockAddresses) (bool, error) {
|
|
||||||
return true, &googleapi.Error{Code: http.StatusNotFound}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteAddressesInternalErrHook mocks deleting address and returns an internal server error.
|
|
||||||
func DeleteAddressesInternalErrHook(ctx context.Context, key *meta.Key, m *cloud.MockAddresses) (bool, error) {
|
|
||||||
return true, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertAlphaBackendServiceUnauthorizedErrHook mocks inserting an alpha BackendService and returns a forbidden error.
|
|
||||||
func InsertAlphaBackendServiceUnauthorizedErrHook(ctx context.Context, key *meta.Key, obj *alpha.BackendService, m *cloud.MockAlphaBackendServices) (bool, error) {
|
|
||||||
return true, UnauthorizedErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAlphaBackendServiceUnauthorizedErrHook mocks updating an alpha BackendService and returns a forbidden error.
|
|
||||||
func UpdateAlphaBackendServiceUnauthorizedErrHook(ctx context.Context, key *meta.Key, obj *alpha.BackendService, m *cloud.MockAlphaBackendServices) error {
|
|
||||||
return UnauthorizedErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRegionBackendServicesErrHook mocks getting region backend service and returns an internal server error.
|
|
||||||
func GetRegionBackendServicesErrHook(ctx context.Context, key *meta.Key, m *cloud.MockRegionBackendServices) (bool, *ga.BackendService, error) {
|
|
||||||
return true, nil, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateRegionBackendServicesErrHook mocks updating a reegion backend service and returns an internal server error.
|
|
||||||
func UpdateRegionBackendServicesErrHook(ctx context.Context, key *meta.Key, svc *ga.BackendService, m *cloud.MockRegionBackendServices) error {
|
|
||||||
return InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRegionBackendServicesErrHook mocks deleting region backend service and returns an internal server error.
|
|
||||||
func DeleteRegionBackendServicesErrHook(ctx context.Context, key *meta.Key, m *cloud.MockRegionBackendServices) (bool, error) {
|
|
||||||
return true, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRegionBackendServicesInUseErrHook mocks deleting region backend service and returns an InUseError.
|
|
||||||
func DeleteRegionBackendServicesInUseErrHook(ctx context.Context, key *meta.Key, m *cloud.MockRegionBackendServices) (bool, error) {
|
|
||||||
return true, InUseError
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInstanceGroupInternalErrHook mocks getting instance group and returns an internal server error.
|
|
||||||
func GetInstanceGroupInternalErrHook(ctx context.Context, key *meta.Key, m *cloud.MockInstanceGroups) (bool, *ga.InstanceGroup, error) {
|
|
||||||
return true, nil, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHealthChecksInternalErrHook mocks getting health check and returns an internal server erorr.
|
|
||||||
func GetHealthChecksInternalErrHook(ctx context.Context, key *meta.Key, m *cloud.MockHealthChecks) (bool, *ga.HealthCheck, error) {
|
|
||||||
return true, nil, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteHealthChecksInternalErrHook mocks deleting health check and returns an internal server error.
|
|
||||||
func DeleteHealthChecksInternalErrHook(ctx context.Context, key *meta.Key, m *cloud.MockHealthChecks) (bool, error) {
|
|
||||||
return true, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteHealthChecksInuseErrHook mocks deleting health check and returns an in use error.
|
|
||||||
func DeleteHealthChecksInuseErrHook(ctx context.Context, key *meta.Key, m *cloud.MockHealthChecks) (bool, error) {
|
|
||||||
return true, InUseError
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteForwardingRuleErrHook mocks deleting forwarding rule and returns an internal server error.
|
|
||||||
func DeleteForwardingRuleErrHook(ctx context.Context, key *meta.Key, m *cloud.MockForwardingRules) (bool, error) {
|
|
||||||
return true, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListZonesInternalErrHook mocks listing zone and returns an internal server error.
|
|
||||||
func ListZonesInternalErrHook(ctx context.Context, fl *filter.F, m *cloud.MockZones) (bool, []*ga.Zone, error) {
|
|
||||||
return true, []*ga.Zone{}, InternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteInstanceGroupInternalErrHook mocks deleting instance group and returns an internal server error.
|
|
||||||
func DeleteInstanceGroupInternalErrHook(ctx context.Context, key *meta.Key, m *cloud.MockInstanceGroups) (bool, error) {
|
|
||||||
return true, InternalServerError
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
alpha "google.golang.org/api/compute/v0.alpha"
|
|
||||||
beta "google.golang.org/api/compute/v0.beta"
|
|
||||||
ga "google.golang.org/api/compute/v1"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/filter"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMocks(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
// This test uses Addresses, but the logic that is generated is the same for
|
|
||||||
// other basic objects.
|
|
||||||
const region = "us-central1"
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
pr := &SingleProjectRouter{"mock-project"}
|
|
||||||
mock := NewMockGCE(pr)
|
|
||||||
|
|
||||||
keyAlpha := meta.RegionalKey("key-alpha", region)
|
|
||||||
keyBeta := meta.RegionalKey("key-beta", region)
|
|
||||||
keyGA := meta.RegionalKey("key-ga", region)
|
|
||||||
key := keyAlpha
|
|
||||||
|
|
||||||
// Get not found.
|
|
||||||
if _, err := mock.AlphaAddresses().Get(ctx, key); err == nil {
|
|
||||||
t.Errorf("AlphaAddresses().Get(%v, %v) = _, nil; want error", ctx, key)
|
|
||||||
}
|
|
||||||
if _, err := mock.BetaAddresses().Get(ctx, key); err == nil {
|
|
||||||
t.Errorf("BetaAddresses().Get(%v, %v) = _, nil; want error", ctx, key)
|
|
||||||
}
|
|
||||||
if _, err := mock.Addresses().Get(ctx, key); err == nil {
|
|
||||||
t.Errorf("Addresses().Get(%v, %v) = _, nil; want error", ctx, key)
|
|
||||||
}
|
|
||||||
// Insert.
|
|
||||||
{
|
|
||||||
obj := &alpha.Address{}
|
|
||||||
if err := mock.AlphaAddresses().Insert(ctx, keyAlpha, obj); err != nil {
|
|
||||||
t.Errorf("AlphaAddresses().Insert(%v, %v, %v) = %v; want nil", ctx, key, obj, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
obj := &beta.Address{}
|
|
||||||
if err := mock.BetaAddresses().Insert(ctx, keyBeta, obj); err != nil {
|
|
||||||
t.Errorf("BetaAddresses().Insert(%v, %v, %v) = %v; want nil", ctx, key, obj, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
obj := &ga.Address{}
|
|
||||||
if err := mock.Addresses().Insert(ctx, keyGA, &ga.Address{Name: "ga"}); err != nil {
|
|
||||||
t.Errorf("Addresses().Insert(%v, %v, %v) = %v; want nil", ctx, key, obj, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Get across versions.
|
|
||||||
if obj, err := mock.AlphaAddresses().Get(ctx, key); err != nil {
|
|
||||||
t.Errorf("AlphaAddresses().Get(%v, %v) = %v, %v; want nil", ctx, key, obj, err)
|
|
||||||
}
|
|
||||||
if obj, err := mock.BetaAddresses().Get(ctx, key); err != nil {
|
|
||||||
t.Errorf("BetaAddresses().Get(%v, %v) = %v, %v; want nil", ctx, key, obj, err)
|
|
||||||
}
|
|
||||||
if obj, err := mock.Addresses().Get(ctx, key); err != nil {
|
|
||||||
t.Errorf("Addresses().Get(%v, %v) = %v, %v; want nil", ctx, key, obj, err)
|
|
||||||
}
|
|
||||||
// List across versions.
|
|
||||||
want := map[string]bool{"key-alpha": true, "key-beta": true, "key-ga": true}
|
|
||||||
{
|
|
||||||
objs, err := mock.AlphaAddresses().List(ctx, region, filter.None)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("AlphaAddresses().List(%v, %v, %v) = %v, %v; want _, nil", ctx, region, filter.None, objs, err)
|
|
||||||
} else {
|
|
||||||
got := map[string]bool{}
|
|
||||||
for _, obj := range objs {
|
|
||||||
got[obj.Name] = true
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
|
||||||
t.Errorf("AlphaAddresses().List(); got %+v, want %+v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
objs, err := mock.BetaAddresses().List(ctx, region, filter.None)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("BetaAddresses().List(%v, %v, %v) = %v, %v; want _, nil", ctx, region, filter.None, objs, err)
|
|
||||||
} else {
|
|
||||||
got := map[string]bool{}
|
|
||||||
for _, obj := range objs {
|
|
||||||
got[obj.Name] = true
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
|
||||||
t.Errorf("AlphaAddresses().List(); got %+v, want %+v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
objs, err := mock.Addresses().List(ctx, region, filter.None)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Addresses().List(%v, %v, %v) = %v, %v; want _, nil", ctx, region, filter.None, objs, err)
|
|
||||||
} else {
|
|
||||||
got := map[string]bool{}
|
|
||||||
for _, obj := range objs {
|
|
||||||
got[obj.Name] = true
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
|
||||||
t.Errorf("AlphaAddresses().List(); got %+v, want %+v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Delete across versions.
|
|
||||||
if err := mock.AlphaAddresses().Delete(ctx, keyAlpha); err != nil {
|
|
||||||
t.Errorf("AlphaAddresses().Delete(%v, %v) = %v; want nil", ctx, key, err)
|
|
||||||
}
|
|
||||||
if err := mock.BetaAddresses().Delete(ctx, keyBeta); err != nil {
|
|
||||||
t.Errorf("BetaAddresses().Delete(%v, %v) = %v; want nil", ctx, key, err)
|
|
||||||
}
|
|
||||||
if err := mock.Addresses().Delete(ctx, keyGA); err != nil {
|
|
||||||
t.Errorf("Addresses().Delete(%v, %v) = %v; want nil", ctx, key, err)
|
|
||||||
}
|
|
||||||
// Delete not found.
|
|
||||||
if err := mock.AlphaAddresses().Delete(ctx, keyAlpha); err == nil {
|
|
||||||
t.Errorf("AlphaAddresses().Delete(%v, %v) = nil; want error", ctx, key)
|
|
||||||
}
|
|
||||||
if err := mock.BetaAddresses().Delete(ctx, keyBeta); err == nil {
|
|
||||||
t.Errorf("BetaAddresses().Delete(%v, %v) = nil; want error", ctx, key)
|
|
||||||
}
|
|
||||||
if err := mock.Addresses().Delete(ctx, keyGA); err == nil {
|
|
||||||
t.Errorf("Addresses().Delete(%v, %v) = nil; want error", ctx, key)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,219 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"k8s.io/klog"
|
|
||||||
|
|
||||||
alpha "google.golang.org/api/compute/v0.alpha"
|
|
||||||
beta "google.golang.org/api/compute/v0.beta"
|
|
||||||
ga "google.golang.org/api/compute/v1"
|
|
||||||
"google.golang.org/api/googleapi"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
operationStatusDone = "DONE"
|
|
||||||
)
|
|
||||||
|
|
||||||
// operation is a GCE operation that can be watied on.
|
|
||||||
type operation interface {
|
|
||||||
// isDone queries GCE for the done status. This call can block.
|
|
||||||
isDone(ctx context.Context) (bool, error)
|
|
||||||
// error returns the resulting error of the operation. This may be nil if the operations
|
|
||||||
// was successful.
|
|
||||||
error() error
|
|
||||||
// rateLimitKey returns the rate limit key to use for the given operation.
|
|
||||||
// This rate limit will govern how fast the server will be polled for
|
|
||||||
// operation completion status.
|
|
||||||
rateLimitKey() *RateLimitKey
|
|
||||||
}
|
|
||||||
|
|
||||||
type gaOperation struct {
|
|
||||||
s *Service
|
|
||||||
projectID string
|
|
||||||
key *meta.Key
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *gaOperation) String() string {
|
|
||||||
return fmt.Sprintf("gaOperation{%q, %v}", o.projectID, o.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *gaOperation) isDone(ctx context.Context) (bool, error) {
|
|
||||||
var (
|
|
||||||
op *ga.Operation
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
switch o.key.Type() {
|
|
||||||
case meta.Regional:
|
|
||||||
op, err = o.s.GA.RegionOperations.Get(o.projectID, o.key.Region, o.key.Name).Context(ctx).Do()
|
|
||||||
klog.V(5).Infof("GA.RegionOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Region, o.key.Name, op, err, ctx)
|
|
||||||
case meta.Zonal:
|
|
||||||
op, err = o.s.GA.ZoneOperations.Get(o.projectID, o.key.Zone, o.key.Name).Context(ctx).Do()
|
|
||||||
klog.V(5).Infof("GA.ZoneOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Zone, o.key.Name, op, err, ctx)
|
|
||||||
case meta.Global:
|
|
||||||
op, err = o.s.GA.GlobalOperations.Get(o.projectID, o.key.Name).Context(ctx).Do()
|
|
||||||
klog.V(5).Infof("GA.GlobalOperations.Get(%v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Name, op, err, ctx)
|
|
||||||
default:
|
|
||||||
return false, fmt.Errorf("invalid key type: %#v", o.key)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if op == nil || op.Status != operationStatusDone {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if op.Error != nil && len(op.Error.Errors) > 0 && op.Error.Errors[0] != nil {
|
|
||||||
e := op.Error.Errors[0]
|
|
||||||
o.err = &googleapi.Error{Code: int(op.HttpErrorStatusCode), Message: fmt.Sprintf("%v - %v", e.Code, e.Message)}
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *gaOperation) rateLimitKey() *RateLimitKey {
|
|
||||||
return &RateLimitKey{
|
|
||||||
ProjectID: o.projectID,
|
|
||||||
Operation: "Get",
|
|
||||||
Service: "Operations",
|
|
||||||
Version: meta.VersionGA,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *gaOperation) error() error {
|
|
||||||
return o.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type alphaOperation struct {
|
|
||||||
s *Service
|
|
||||||
projectID string
|
|
||||||
key *meta.Key
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *alphaOperation) String() string {
|
|
||||||
return fmt.Sprintf("alphaOperation{%q, %v}", o.projectID, o.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *alphaOperation) isDone(ctx context.Context) (bool, error) {
|
|
||||||
var (
|
|
||||||
op *alpha.Operation
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
switch o.key.Type() {
|
|
||||||
case meta.Regional:
|
|
||||||
op, err = o.s.Alpha.RegionOperations.Get(o.projectID, o.key.Region, o.key.Name).Context(ctx).Do()
|
|
||||||
klog.V(5).Infof("Alpha.RegionOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Region, o.key.Name, op, err, ctx)
|
|
||||||
case meta.Zonal:
|
|
||||||
op, err = o.s.Alpha.ZoneOperations.Get(o.projectID, o.key.Zone, o.key.Name).Context(ctx).Do()
|
|
||||||
klog.V(5).Infof("Alpha.ZoneOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Zone, o.key.Name, op, err, ctx)
|
|
||||||
case meta.Global:
|
|
||||||
op, err = o.s.Alpha.GlobalOperations.Get(o.projectID, o.key.Name).Context(ctx).Do()
|
|
||||||
klog.V(5).Infof("Alpha.GlobalOperations.Get(%v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Name, op, err, ctx)
|
|
||||||
default:
|
|
||||||
return false, fmt.Errorf("invalid key type: %#v", o.key)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if op == nil || op.Status != operationStatusDone {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if op.Error != nil && len(op.Error.Errors) > 0 && op.Error.Errors[0] != nil {
|
|
||||||
e := op.Error.Errors[0]
|
|
||||||
o.err = &googleapi.Error{Code: int(op.HttpErrorStatusCode), Message: fmt.Sprintf("%v - %v", e.Code, e.Message)}
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *alphaOperation) rateLimitKey() *RateLimitKey {
|
|
||||||
return &RateLimitKey{
|
|
||||||
ProjectID: o.projectID,
|
|
||||||
Operation: "Get",
|
|
||||||
Service: "Operations",
|
|
||||||
Version: meta.VersionAlpha,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *alphaOperation) error() error {
|
|
||||||
return o.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type betaOperation struct {
|
|
||||||
s *Service
|
|
||||||
projectID string
|
|
||||||
key *meta.Key
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *betaOperation) String() string {
|
|
||||||
return fmt.Sprintf("betaOperation{%q, %v}", o.projectID, o.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *betaOperation) isDone(ctx context.Context) (bool, error) {
|
|
||||||
var (
|
|
||||||
op *beta.Operation
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
switch o.key.Type() {
|
|
||||||
case meta.Regional:
|
|
||||||
op, err = o.s.Beta.RegionOperations.Get(o.projectID, o.key.Region, o.key.Name).Context(ctx).Do()
|
|
||||||
klog.V(5).Infof("Beta.RegionOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Region, o.key.Name, op, err, ctx)
|
|
||||||
case meta.Zonal:
|
|
||||||
op, err = o.s.Beta.ZoneOperations.Get(o.projectID, o.key.Zone, o.key.Name).Context(ctx).Do()
|
|
||||||
klog.V(5).Infof("Beta.ZoneOperations.Get(%v, %v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Zone, o.key.Name, op, err, ctx)
|
|
||||||
case meta.Global:
|
|
||||||
op, err = o.s.Beta.GlobalOperations.Get(o.projectID, o.key.Name).Context(ctx).Do()
|
|
||||||
klog.V(5).Infof("Beta.GlobalOperations.Get(%v, %v) = %+v, %v; ctx = %v", o.projectID, o.key.Name, op, err, ctx)
|
|
||||||
default:
|
|
||||||
return false, fmt.Errorf("invalid key type: %#v", o.key)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if op == nil || op.Status != operationStatusDone {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if op.Error != nil && len(op.Error.Errors) > 0 && op.Error.Errors[0] != nil {
|
|
||||||
e := op.Error.Errors[0]
|
|
||||||
o.err = &googleapi.Error{Code: int(op.HttpErrorStatusCode), Message: fmt.Sprintf("%v - %v", e.Code, e.Message)}
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *betaOperation) rateLimitKey() *RateLimitKey {
|
|
||||||
return &RateLimitKey{
|
|
||||||
ProjectID: o.projectID,
|
|
||||||
Operation: "Get",
|
|
||||||
Service: "Operations",
|
|
||||||
Version: meta.VersionBeta,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *betaOperation) error() error {
|
|
||||||
return o.err
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProjectRouter routes service calls to the appropriate GCE project.
|
|
||||||
type ProjectRouter interface {
|
|
||||||
// ProjectID returns the project ID (non-numeric) to be used for a call
|
|
||||||
// to an API (version,service). Example tuples: ("ga", "ForwardingRules"),
|
|
||||||
// ("alpha", "GlobalAddresses").
|
|
||||||
//
|
|
||||||
// This allows for plumbing different service calls to the appropriate
|
|
||||||
// project, for instance, networking services to a separate project
|
|
||||||
// than instance management.
|
|
||||||
ProjectID(ctx context.Context, version meta.Version, service string) string
|
|
||||||
}
|
|
||||||
|
|
||||||
// SingleProjectRouter routes all service calls to the same project ID.
|
|
||||||
type SingleProjectRouter struct {
|
|
||||||
ID string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProjectID returns the project ID to be used for a call to the API.
|
|
||||||
func (r *SingleProjectRouter) ProjectID(ctx context.Context, version meta.Version, service string) string {
|
|
||||||
return r.ID
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RateLimitKey is a key identifying the operation to be rate limited. The rate limit
|
|
||||||
// queue will be determined based on the contents of RateKey.
|
|
||||||
type RateLimitKey struct {
|
|
||||||
// ProjectID is the non-numeric ID of the project.
|
|
||||||
ProjectID string
|
|
||||||
// Operation is the specific method being invoked (e.g. "Get", "List").
|
|
||||||
Operation string
|
|
||||||
// Version is the API version of the call.
|
|
||||||
Version meta.Version
|
|
||||||
// Service is the service being invoked (e.g. "Firewalls", "BackendServices")
|
|
||||||
Service string
|
|
||||||
}
|
|
||||||
|
|
||||||
// RateLimiter is the interface for a rate limiting policy.
|
|
||||||
type RateLimiter interface {
|
|
||||||
// Accept uses the RateLimitKey to derive a sleep time for the calling
|
|
||||||
// goroutine. This call will block until the operation is ready for
|
|
||||||
// execution.
|
|
||||||
//
|
|
||||||
// Accept returns an error if the given context ctx was canceled
|
|
||||||
// while waiting for acceptance into the queue.
|
|
||||||
Accept(ctx context.Context, key *RateLimitKey) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// acceptor is an object which blocks within Accept until a call is allowed to run.
|
|
||||||
// Accept is a behavior of the flowcontrol.RateLimiter interface.
|
|
||||||
type acceptor interface {
|
|
||||||
// Accept blocks until a call is allowed to run.
|
|
||||||
Accept()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AcceptRateLimiter wraps an Acceptor with RateLimiter parameters.
|
|
||||||
type AcceptRateLimiter struct {
|
|
||||||
// Acceptor is the underlying rate limiter.
|
|
||||||
Acceptor acceptor
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept wraps an Acceptor and blocks on Accept or context.Done(). Key is ignored.
|
|
||||||
func (rl *AcceptRateLimiter) Accept(ctx context.Context, key *RateLimitKey) error {
|
|
||||||
ch := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
rl.Acceptor.Accept()
|
|
||||||
close(ch)
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-ch:
|
|
||||||
break
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NopRateLimiter is a rate limiter that performs no rate limiting.
|
|
||||||
type NopRateLimiter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept everything immediately.
|
|
||||||
func (*NopRateLimiter) Accept(ctx context.Context, key *RateLimitKey) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MinimumRateLimiter wraps a RateLimiter and will only call its Accept until the minimum
|
|
||||||
// duration has been met or the context is cancelled.
|
|
||||||
type MinimumRateLimiter struct {
|
|
||||||
// RateLimiter is the underlying ratelimiter which is called after the mininum time is reacehd.
|
|
||||||
RateLimiter RateLimiter
|
|
||||||
// Minimum is the minimum wait time before the underlying ratelimiter is called.
|
|
||||||
Minimum time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept blocks on the minimum duration and context. Once the minimum duration is met,
|
|
||||||
// the func is blocked on the underlying ratelimiter.
|
|
||||||
func (m *MinimumRateLimiter) Accept(ctx context.Context, key *RateLimitKey) error {
|
|
||||||
select {
|
|
||||||
case <-time.After(m.Minimum):
|
|
||||||
return m.RateLimiter.Accept(ctx, key)
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FakeAcceptor struct{ accept func() }
|
|
||||||
|
|
||||||
func (f *FakeAcceptor) Accept() {
|
|
||||||
f.accept()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAcceptRateLimiter(t *testing.T) {
|
|
||||||
fa := &FakeAcceptor{accept: func() {}}
|
|
||||||
arl := &AcceptRateLimiter{fa}
|
|
||||||
err := arl.Accept(context.Background(), nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("AcceptRateLimiter.Accept() = %v, want nil", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use context that has been cancelled and expect a context error returned.
|
|
||||||
ctxCancelled, cancelled := context.WithCancel(context.Background())
|
|
||||||
cancelled()
|
|
||||||
// Verify context is cancelled by now.
|
|
||||||
<-ctxCancelled.Done()
|
|
||||||
|
|
||||||
fa.accept = func() { time.Sleep(1 * time.Second) }
|
|
||||||
err = arl.Accept(ctxCancelled, nil)
|
|
||||||
if err != ctxCancelled.Err() {
|
|
||||||
t.Errorf("AcceptRateLimiter.Accept() = %v, want %v", err, ctxCancelled.Err())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMinimumRateLimiter(t *testing.T) {
|
|
||||||
fa := &FakeAcceptor{accept: func() {}}
|
|
||||||
arl := &AcceptRateLimiter{fa}
|
|
||||||
var called bool
|
|
||||||
fa.accept = func() { called = true }
|
|
||||||
m := &MinimumRateLimiter{RateLimiter: arl, Minimum: 10 * time.Millisecond}
|
|
||||||
|
|
||||||
err := m.Accept(context.Background(), nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("MinimumRateLimiter.Accept = %v, want nil", err)
|
|
||||||
}
|
|
||||||
if !called {
|
|
||||||
t.Errorf("`called` = false, want true")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use context that has been cancelled and expect a context error returned.
|
|
||||||
ctxCancelled, cancelled := context.WithCancel(context.Background())
|
|
||||||
cancelled()
|
|
||||||
// Verify context is cancelled by now.
|
|
||||||
<-ctxCancelled.Done()
|
|
||||||
called = false
|
|
||||||
err = m.Accept(ctxCancelled, nil)
|
|
||||||
if err != ctxCancelled.Err() {
|
|
||||||
t.Errorf("AcceptRateLimiter.Accept() = %v, want %v", err, ctxCancelled.Err())
|
|
||||||
}
|
|
||||||
if called {
|
|
||||||
t.Errorf("`called` = true, want false")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"k8s.io/klog"
|
|
||||||
|
|
||||||
alpha "google.golang.org/api/compute/v0.alpha"
|
|
||||||
beta "google.golang.org/api/compute/v0.beta"
|
|
||||||
ga "google.golang.org/api/compute/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Service is the top-level adapter for all of the different compute API
|
|
||||||
// versions.
|
|
||||||
type Service struct {
|
|
||||||
GA *ga.Service
|
|
||||||
Alpha *alpha.Service
|
|
||||||
Beta *beta.Service
|
|
||||||
ProjectRouter ProjectRouter
|
|
||||||
RateLimiter RateLimiter
|
|
||||||
}
|
|
||||||
|
|
||||||
// wrapOperation wraps a GCE anyOP in a version generic operation type.
|
|
||||||
func (s *Service) wrapOperation(anyOp interface{}) (operation, error) {
|
|
||||||
switch o := anyOp.(type) {
|
|
||||||
case *ga.Operation:
|
|
||||||
r, err := ParseResourceURL(o.SelfLink)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &gaOperation{s: s, projectID: r.ProjectID, key: r.Key}, nil
|
|
||||||
case *alpha.Operation:
|
|
||||||
r, err := ParseResourceURL(o.SelfLink)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &alphaOperation{s: s, projectID: r.ProjectID, key: r.Key}, nil
|
|
||||||
case *beta.Operation:
|
|
||||||
r, err := ParseResourceURL(o.SelfLink)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &betaOperation{s: s, projectID: r.ProjectID, key: r.Key}, nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid type %T", anyOp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitForCompletion of a long running operation. This will poll the state of
|
|
||||||
// GCE for the completion status of the given operation. genericOp can be one
|
|
||||||
// of alpha, beta, ga Operation types.
|
|
||||||
func (s *Service) WaitForCompletion(ctx context.Context, genericOp interface{}) error {
|
|
||||||
op, err := s.wrapOperation(genericOp)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("wrapOperation(%+v) error: %v", genericOp, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.pollOperation(ctx, op)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pollOperation calls operations.isDone until the function comes back true or context is Done.
|
|
||||||
// If an error occurs retrieving the operation, the loop will continue until the context is done.
|
|
||||||
// This is to prevent a transient error from bubbling up to controller-level logic.
|
|
||||||
func (s *Service) pollOperation(ctx context.Context, op operation) error {
|
|
||||||
var pollCount int
|
|
||||||
for {
|
|
||||||
// Check if context has been cancelled. Note that ctx.Done() must be checked before
|
|
||||||
// returning ctx.Err().
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
klog.V(5).Infof("op.pollOperation(%v, %v) not completed, poll count = %d, ctx.Err = %v", ctx, op, pollCount, ctx.Err())
|
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
// ctx is not canceled, continue immediately
|
|
||||||
}
|
|
||||||
|
|
||||||
pollCount++
|
|
||||||
klog.V(5).Infof("op.isDone(%v) waiting; op = %v, poll count = %d", ctx, op, pollCount)
|
|
||||||
s.RateLimiter.Accept(ctx, op.rateLimitKey())
|
|
||||||
done, err := op.isDone(ctx)
|
|
||||||
if err != nil {
|
|
||||||
klog.V(5).Infof("op.isDone(%v) error; op = %v, poll count = %d, err = %v, retrying", ctx, op, pollCount, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if done {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
klog.V(5).Infof("op.isDone(%v) complete; op = %v, poll count = %d, op.err = %v", ctx, op, pollCount, op.error())
|
|
||||||
return op.error()
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPollOperation(t *testing.T) {
|
|
||||||
const totalAttempts = 10
|
|
||||||
var attempts int
|
|
||||||
fo := &fakeOperation{isDoneFunc: func(ctx context.Context) (bool, error) {
|
|
||||||
attempts++
|
|
||||||
if attempts < totalAttempts {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}}
|
|
||||||
s := Service{RateLimiter: &NopRateLimiter{}}
|
|
||||||
// Check that pollOperation will retry the operation multiple times.
|
|
||||||
err := s.pollOperation(context.Background(), fo)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("pollOperation() = %v, want nil", err)
|
|
||||||
}
|
|
||||||
if attempts != totalAttempts {
|
|
||||||
t.Errorf("`attempts` = %d, want %d", attempts, totalAttempts)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the operation's error is returned.
|
|
||||||
fo.err = fmt.Errorf("test operation failed")
|
|
||||||
err = s.pollOperation(context.Background(), fo)
|
|
||||||
if err != fo.err {
|
|
||||||
t.Errorf("pollOperation() = %v, want %v", err, fo.err)
|
|
||||||
}
|
|
||||||
fo.err = nil
|
|
||||||
|
|
||||||
fo.isDoneFunc = func(ctx context.Context) (bool, error) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
// Use context that has been cancelled and expect a context error returned.
|
|
||||||
ctxCancelled, cancelled := context.WithCancel(context.Background())
|
|
||||||
cancelled()
|
|
||||||
// Verify context is cancelled by now.
|
|
||||||
<-ctxCancelled.Done()
|
|
||||||
// Check that pollOperation returns because the context is cancelled.
|
|
||||||
err = s.pollOperation(ctxCancelled, fo)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("pollOperation() = nil, want: %v", ctxCancelled.Err())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type fakeOperation struct {
|
|
||||||
isDoneFunc func(ctx context.Context) (bool, error)
|
|
||||||
err error
|
|
||||||
rateKey *RateLimitKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fakeOperation) isDone(ctx context.Context) (bool, error) {
|
|
||||||
return f.isDoneFunc(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fakeOperation) error() error {
|
|
||||||
return f.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fakeOperation) rateLimitKey() *RateLimitKey {
|
|
||||||
return f.rateKey
|
|
||||||
}
|
|
|
@ -1,201 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
gaPrefix = "https://www.googleapis.com/compute/v1"
|
|
||||||
alphaPrefix = "https://www.googleapis.com/compute/alpha"
|
|
||||||
betaPrefix = "https://www.googleapis.com/compute/beta"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ResourceID identifies a GCE resource as parsed from compute resource URL.
|
|
||||||
type ResourceID struct {
|
|
||||||
ProjectID string
|
|
||||||
Resource string
|
|
||||||
Key *meta.Key
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal returns true if two resource IDs are equal.
|
|
||||||
func (r *ResourceID) Equal(other *ResourceID) bool {
|
|
||||||
if r.ProjectID != other.ProjectID || r.Resource != other.Resource {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if r.Key != nil && other.Key != nil {
|
|
||||||
return *r.Key == *other.Key
|
|
||||||
}
|
|
||||||
if r.Key == nil && other.Key == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// RelativeResourceName returns the relative resource name string
|
|
||||||
// representing this ResourceID.
|
|
||||||
func (r *ResourceID) RelativeResourceName() string {
|
|
||||||
return RelativeResourceName(r.ProjectID, r.Resource, r.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourcePath returns the resource path representing this ResourceID.
|
|
||||||
func (r *ResourceID) ResourcePath() string {
|
|
||||||
return ResourcePath(r.Resource, r.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ResourceID) SelfLink(ver meta.Version) string {
|
|
||||||
return SelfLink(ver, r.ProjectID, r.Resource, r.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseResourceURL parses resource URLs of the following formats:
|
|
||||||
//
|
|
||||||
// global/<res>/<name>
|
|
||||||
// regions/<region>/<res>/<name>
|
|
||||||
// zones/<zone>/<res>/<name>
|
|
||||||
// projects/<proj>
|
|
||||||
// projects/<proj>/global/<res>/<name>
|
|
||||||
// projects/<proj>/regions/<region>/<res>/<name>
|
|
||||||
// projects/<proj>/zones/<zone>/<res>/<name>
|
|
||||||
// [https://www.googleapis.com/compute/<ver>]/projects/<proj>/global/<res>/<name>
|
|
||||||
// [https://www.googleapis.com/compute/<ver>]/projects/<proj>/regions/<region>/<res>/<name>
|
|
||||||
// [https://www.googleapis.com/compute/<ver>]/projects/<proj>/zones/<zone>/<res>/<name>
|
|
||||||
func ParseResourceURL(url string) (*ResourceID, error) {
|
|
||||||
errNotValid := fmt.Errorf("%q is not a valid resource URL", url)
|
|
||||||
|
|
||||||
// Trim prefix off URL leaving "projects/..."
|
|
||||||
projectsIndex := strings.Index(url, "/projects/")
|
|
||||||
if projectsIndex >= 0 {
|
|
||||||
url = url[projectsIndex+1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(url, "/")
|
|
||||||
if len(parts) < 2 || len(parts) > 6 {
|
|
||||||
return nil, errNotValid
|
|
||||||
}
|
|
||||||
|
|
||||||
ret := &ResourceID{}
|
|
||||||
scopedName := parts
|
|
||||||
if parts[0] == "projects" {
|
|
||||||
ret.Resource = "projects"
|
|
||||||
ret.ProjectID = parts[1]
|
|
||||||
scopedName = parts[2:]
|
|
||||||
|
|
||||||
if len(scopedName) == 0 {
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch scopedName[0] {
|
|
||||||
case "global":
|
|
||||||
if len(scopedName) != 3 {
|
|
||||||
return nil, errNotValid
|
|
||||||
}
|
|
||||||
ret.Resource = scopedName[1]
|
|
||||||
ret.Key = meta.GlobalKey(scopedName[2])
|
|
||||||
return ret, nil
|
|
||||||
case "regions":
|
|
||||||
switch len(scopedName) {
|
|
||||||
case 2:
|
|
||||||
ret.Resource = "regions"
|
|
||||||
ret.Key = meta.GlobalKey(scopedName[1])
|
|
||||||
return ret, nil
|
|
||||||
case 4:
|
|
||||||
ret.Resource = scopedName[2]
|
|
||||||
ret.Key = meta.RegionalKey(scopedName[3], scopedName[1])
|
|
||||||
return ret, nil
|
|
||||||
default:
|
|
||||||
return nil, errNotValid
|
|
||||||
}
|
|
||||||
case "zones":
|
|
||||||
switch len(scopedName) {
|
|
||||||
case 2:
|
|
||||||
ret.Resource = "zones"
|
|
||||||
ret.Key = meta.GlobalKey(scopedName[1])
|
|
||||||
return ret, nil
|
|
||||||
case 4:
|
|
||||||
ret.Resource = scopedName[2]
|
|
||||||
ret.Key = meta.ZonalKey(scopedName[3], scopedName[1])
|
|
||||||
return ret, nil
|
|
||||||
default:
|
|
||||||
return nil, errNotValid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, errNotValid
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyViaJSON(dest, src interface{}) error {
|
|
||||||
bytes, err := json.Marshal(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return json.Unmarshal(bytes, dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourcePath returns the path starting from the location.
|
|
||||||
// Example: regions/us-central1/subnetworks/my-subnet
|
|
||||||
func ResourcePath(resource string, key *meta.Key) string {
|
|
||||||
switch resource {
|
|
||||||
case "zones", "regions":
|
|
||||||
return fmt.Sprintf("%s/%s", resource, key.Name)
|
|
||||||
case "projects":
|
|
||||||
return "invalid-resource"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch key.Type() {
|
|
||||||
case meta.Zonal:
|
|
||||||
return fmt.Sprintf("zones/%s/%s/%s", key.Zone, resource, key.Name)
|
|
||||||
case meta.Regional:
|
|
||||||
return fmt.Sprintf("regions/%s/%s/%s", key.Region, resource, key.Name)
|
|
||||||
case meta.Global:
|
|
||||||
return fmt.Sprintf("global/%s/%s", resource, key.Name)
|
|
||||||
}
|
|
||||||
return "invalid-key-type"
|
|
||||||
}
|
|
||||||
|
|
||||||
// RelativeResourceName returns the path starting from project.
|
|
||||||
// Example: projects/my-project/regions/us-central1/subnetworks/my-subnet
|
|
||||||
func RelativeResourceName(project, resource string, key *meta.Key) string {
|
|
||||||
switch resource {
|
|
||||||
case "projects":
|
|
||||||
return fmt.Sprintf("projects/%s", project)
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("projects/%s/%s", project, ResourcePath(resource, key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelfLink returns the self link URL for the given object.
|
|
||||||
func SelfLink(ver meta.Version, project, resource string, key *meta.Key) string {
|
|
||||||
var prefix string
|
|
||||||
switch ver {
|
|
||||||
case meta.VersionAlpha:
|
|
||||||
prefix = alphaPrefix
|
|
||||||
case meta.VersionBeta:
|
|
||||||
prefix = betaPrefix
|
|
||||||
case meta.VersionGA:
|
|
||||||
prefix = gaPrefix
|
|
||||||
default:
|
|
||||||
prefix = "invalid-prefix"
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s/%s", prefix, RelativeResourceName(project, resource, key))
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,291 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
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 cloud
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEqualResourceID(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
a *ResourceID
|
|
||||||
b *ResourceID
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
a: &ResourceID{"some-gce-project", "projects", nil},
|
|
||||||
b: &ResourceID{"some-gce-project", "projects", nil},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: &ResourceID{"", "networks", meta.GlobalKey("my-net")},
|
|
||||||
b: &ResourceID{"", "networks", meta.GlobalKey("my-net")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: &ResourceID{"some-gce-project", "projects", meta.GlobalKey("us-central1")},
|
|
||||||
b: &ResourceID{"some-gce-project", "projects", meta.GlobalKey("us-central1")},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
if !tc.a.Equal(tc.b) {
|
|
||||||
t.Errorf("%v.Equal(%v) = false, want true", tc.a, tc.b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
a *ResourceID
|
|
||||||
b *ResourceID
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
a: &ResourceID{"some-gce-project", "projects", nil},
|
|
||||||
b: &ResourceID{"some-other-project", "projects", nil},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: &ResourceID{"some-gce-project", "projects", nil},
|
|
||||||
b: &ResourceID{"some-gce-project", "projects", meta.GlobalKey("us-central1")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
a: &ResourceID{"some-gce-project", "networks", meta.GlobalKey("us-central1")},
|
|
||||||
b: &ResourceID{"some-gce-project", "projects", meta.GlobalKey("us-central1")},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
if tc.a.Equal(tc.b) {
|
|
||||||
t.Errorf("%v.Equal(%v) = true, want false", tc.a, tc.b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseResourceURL(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
in string
|
|
||||||
r *ResourceID
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/some-gce-project",
|
|
||||||
&ResourceID{"some-gce-project", "projects", nil},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/some-gce-project/regions/us-central1",
|
|
||||||
&ResourceID{"some-gce-project", "regions", meta.GlobalKey("us-central1")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/some-gce-project/zones/us-central1-b",
|
|
||||||
&ResourceID{"some-gce-project", "zones", meta.GlobalKey("us-central1-b")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/some-gce-project/global/operations/operation-1513289952196-56054460af5a0-b1dae0c3-9bbf9dbf",
|
|
||||||
&ResourceID{"some-gce-project", "operations", meta.GlobalKey("operation-1513289952196-56054460af5a0-b1dae0c3-9bbf9dbf")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"https://www.googleapis.com/compute/alpha/projects/some-gce-project/regions/us-central1/addresses/my-address",
|
|
||||||
&ResourceID{"some-gce-project", "addresses", meta.RegionalKey("my-address", "us-central1")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/some-gce-project/zones/us-central1-c/instances/instance-1",
|
|
||||||
&ResourceID{"some-gce-project", "instances", meta.ZonalKey("instance-1", "us-central1-c")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"http://localhost:3990/compute/beta/projects/some-gce-project/global/operations/operation-1513289952196-56054460af5a0-b1dae0c3-9bbf9dbf",
|
|
||||||
&ResourceID{"some-gce-project", "operations", meta.GlobalKey("operation-1513289952196-56054460af5a0-b1dae0c3-9bbf9dbf")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"http://localhost:3990/compute/alpha/projects/some-gce-project/regions/dev-central1/addresses/my-address",
|
|
||||||
&ResourceID{"some-gce-project", "addresses", meta.RegionalKey("my-address", "dev-central1")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"http://localhost:3990/compute/v1/projects/some-gce-project/zones/dev-central1-std/instances/instance-1",
|
|
||||||
&ResourceID{"some-gce-project", "instances", meta.ZonalKey("instance-1", "dev-central1-std")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"projects/some-gce-project",
|
|
||||||
&ResourceID{"some-gce-project", "projects", nil},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"projects/some-gce-project/regions/us-central1",
|
|
||||||
&ResourceID{"some-gce-project", "regions", meta.GlobalKey("us-central1")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"projects/some-gce-project/zones/us-central1-b",
|
|
||||||
&ResourceID{"some-gce-project", "zones", meta.GlobalKey("us-central1-b")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"projects/some-gce-project/global/operations/operation-1513289952196-56054460af5a0-b1dae0c3-9bbf9dbf",
|
|
||||||
&ResourceID{"some-gce-project", "operations", meta.GlobalKey("operation-1513289952196-56054460af5a0-b1dae0c3-9bbf9dbf")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"projects/some-gce-project/regions/us-central1/addresses/my-address",
|
|
||||||
&ResourceID{"some-gce-project", "addresses", meta.RegionalKey("my-address", "us-central1")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"projects/some-gce-project/zones/us-central1-c/instances/instance-1",
|
|
||||||
&ResourceID{"some-gce-project", "instances", meta.ZonalKey("instance-1", "us-central1-c")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"global/networks/my-network",
|
|
||||||
&ResourceID{"", "networks", meta.GlobalKey("my-network")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"regions/us-central1/subnetworks/my-subnet",
|
|
||||||
&ResourceID{"", "subnetworks", meta.RegionalKey("my-subnet", "us-central1")},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"zones/us-central1-c/instances/instance-1",
|
|
||||||
&ResourceID{"", "instances", meta.ZonalKey("instance-1", "us-central1-c")},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
r, err := ParseResourceURL(tc.in)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("ParseResourceURL(%q) = %+v, %v; want _, nil", tc.in, r, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !r.Equal(tc.r) {
|
|
||||||
t.Errorf("ParseResourceURL(%q) = %+v, nil; want %+v, nil", tc.in, r, tc.r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Malformed URLs.
|
|
||||||
for _, tc := range []string{
|
|
||||||
"",
|
|
||||||
"/",
|
|
||||||
"/a",
|
|
||||||
"/a/b",
|
|
||||||
"/a/b/c",
|
|
||||||
"/a/b/c/d",
|
|
||||||
"/a/b/c/d/e",
|
|
||||||
"/a/b/c/d/e/f",
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/some-gce-project/global",
|
|
||||||
"projects/some-gce-project/global",
|
|
||||||
"projects/some-gce-project/global/foo",
|
|
||||||
"projects/some-gce-project/global/foo/bar/baz",
|
|
||||||
"projects/some-gce-project/regions/us-central1/res",
|
|
||||||
"projects/some-gce-project/zones/us-central1-c/res",
|
|
||||||
"projects/some-gce-project/zones/us-central1-c/res/name/extra",
|
|
||||||
} {
|
|
||||||
r, err := ParseResourceURL(tc)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("ParseResourceURL(%q) = %+v, %v, want _, error", tc, r, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type A struct {
|
|
||||||
A, B, C string
|
|
||||||
}
|
|
||||||
|
|
||||||
type B struct {
|
|
||||||
A, B, D string
|
|
||||||
}
|
|
||||||
|
|
||||||
type E struct{}
|
|
||||||
|
|
||||||
func (*E) MarshalJSON() ([]byte, error) {
|
|
||||||
return nil, errors.New("injected error")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCopyVisJSON(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
var b B
|
|
||||||
srcA := &A{"aa", "bb", "cc"}
|
|
||||||
err := copyViaJSON(&b, srcA)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf(`copyViaJSON(&b, %+v) = %v, want nil`, srcA, err)
|
|
||||||
} else {
|
|
||||||
expectedB := B{"aa", "bb", ""}
|
|
||||||
if b != expectedB {
|
|
||||||
t.Errorf("b == %+v, want %+v", b, expectedB)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var a A
|
|
||||||
srcB := &B{"aaa", "bbb", "ccc"}
|
|
||||||
err = copyViaJSON(&a, srcB)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf(`copyViaJSON(&a, %+v) = %v, want nil`, srcB, err)
|
|
||||||
} else {
|
|
||||||
expectedA := A{"aaa", "bbb", ""}
|
|
||||||
if a != expectedA {
|
|
||||||
t.Errorf("a == %+v, want %+v", a, expectedA)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := copyViaJSON(&a, &E{}); err == nil {
|
|
||||||
t.Errorf("copyViaJSON(&a, &E{}) = nil, want error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelfLink(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
|
||||||
ver meta.Version
|
|
||||||
project string
|
|
||||||
resource string
|
|
||||||
key *meta.Key
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
meta.VersionAlpha,
|
|
||||||
"proj1",
|
|
||||||
"addresses",
|
|
||||||
meta.RegionalKey("key1", "us-central1"),
|
|
||||||
"https://www.googleapis.com/compute/alpha/projects/proj1/regions/us-central1/addresses/key1",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
meta.VersionBeta,
|
|
||||||
"proj3",
|
|
||||||
"disks",
|
|
||||||
meta.ZonalKey("key2", "us-central1-b"),
|
|
||||||
"https://www.googleapis.com/compute/beta/projects/proj3/zones/us-central1-b/disks/key2",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
meta.VersionGA,
|
|
||||||
"proj4",
|
|
||||||
"urlMaps",
|
|
||||||
meta.GlobalKey("key3"),
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/proj4/global/urlMaps/key3",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
meta.VersionGA,
|
|
||||||
"proj4",
|
|
||||||
"projects",
|
|
||||||
nil,
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/proj4",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
meta.VersionGA,
|
|
||||||
"proj4",
|
|
||||||
"regions",
|
|
||||||
meta.GlobalKey("us-central1"),
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/proj4/regions/us-central1",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
meta.VersionGA,
|
|
||||||
"proj4",
|
|
||||||
"zones",
|
|
||||||
meta.GlobalKey("us-central1-a"),
|
|
||||||
"https://www.googleapis.com/compute/v1/projects/proj4/zones/us-central1-a",
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
if link := SelfLink(tc.ver, tc.project, tc.resource, tc.key); link != tc.want {
|
|
||||||
t.Errorf("SelfLink(%v, %q, %q, %v) = %v, want %q", tc.ver, tc.project, tc.resource, tc.key, link, tc.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue