From 8098b9195141f7bed5b81d03efc571eab001dfda Mon Sep 17 00:00:00 2001 From: Nick Sardo Date: Fri, 13 Apr 2018 09:22:48 -0700 Subject: [PATCH] Expand ability of ResourceID --- pkg/cloudprovider/providers/gce/cloud/gen.go | 144 +++++++++++++++++ .../providers/gce/cloud/gen/main.go | 119 ++++++++++++-- .../providers/gce/cloud/gen_test.go | 69 +++++++++ .../providers/gce/cloud/meta/service.go | 31 +++- .../providers/gce/cloud/utils.go | 145 ++++++++++++------ .../providers/gce/cloud/utils_test.go | 85 +++++++++- .../gce/gce_loadbalancer_internal_test.go | 2 +- 7 files changed, 528 insertions(+), 67 deletions(-) diff --git a/pkg/cloudprovider/providers/gce/cloud/gen.go b/pkg/cloudprovider/providers/gce/cloud/gen.go index 3992adca90d..fb381b7bcd2 100644 --- a/pkg/cloudprovider/providers/gce/cloud/gen.go +++ b/pkg/cloudprovider/providers/gce/cloud/gen.go @@ -13152,3 +13152,147 @@ func (g *GCEZones) List(ctx context.Context, fl *filter.F) ([]*ga.Zone, error) { return all, nil } + +// NewAddressesResourceID creates a ResourceID for the Addresses resource. +func NewAddressesResourceID(project, region, name string) *ResourceID { + key := meta.RegionalKey(name, region) + return &ResourceID{project, "addresses", key} +} + +// NewBackendServicesResourceID creates a ResourceID for the BackendServices resource. +func NewBackendServicesResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "backendServices", key} +} + +// NewDisksResourceID creates a ResourceID for the Disks resource. +func NewDisksResourceID(project, zone, name string) *ResourceID { + key := meta.ZonalKey(name, zone) + return &ResourceID{project, "disks", key} +} + +// NewFirewallsResourceID creates a ResourceID for the Firewalls resource. +func NewFirewallsResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "firewalls", key} +} + +// NewForwardingRulesResourceID creates a ResourceID for the ForwardingRules resource. +func NewForwardingRulesResourceID(project, region, name string) *ResourceID { + key := meta.RegionalKey(name, region) + return &ResourceID{project, "forwardingRules", key} +} + +// NewGlobalAddressesResourceID creates a ResourceID for the GlobalAddresses resource. +func NewGlobalAddressesResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "addresses", key} +} + +// NewGlobalForwardingRulesResourceID creates a ResourceID for the GlobalForwardingRules resource. +func NewGlobalForwardingRulesResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "forwardingRules", key} +} + +// NewHealthChecksResourceID creates a ResourceID for the HealthChecks resource. +func NewHealthChecksResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "healthChecks", key} +} + +// NewHttpHealthChecksResourceID creates a ResourceID for the HttpHealthChecks resource. +func NewHttpHealthChecksResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "httpHealthChecks", key} +} + +// NewHttpsHealthChecksResourceID creates a ResourceID for the HttpsHealthChecks resource. +func NewHttpsHealthChecksResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "httpsHealthChecks", key} +} + +// NewInstanceGroupsResourceID creates a ResourceID for the InstanceGroups resource. +func NewInstanceGroupsResourceID(project, zone, name string) *ResourceID { + key := meta.ZonalKey(name, zone) + return &ResourceID{project, "instanceGroups", key} +} + +// NewInstancesResourceID creates a ResourceID for the Instances resource. +func NewInstancesResourceID(project, zone, name string) *ResourceID { + key := meta.ZonalKey(name, zone) + return &ResourceID{project, "instances", key} +} + +// NewNetworkEndpointGroupsResourceID creates a ResourceID for the NetworkEndpointGroups resource. +func NewNetworkEndpointGroupsResourceID(project, zone, name string) *ResourceID { + key := meta.ZonalKey(name, zone) + return &ResourceID{project, "networkEndpointGroups", key} +} + +// NewProjectsResourceID creates a ResourceID for the Projects resource. +func NewProjectsResourceID(project string) *ResourceID { + var key *meta.Key + return &ResourceID{project, "projects", key} +} + +// NewRegionBackendServicesResourceID creates a ResourceID for the RegionBackendServices resource. +func NewRegionBackendServicesResourceID(project, region, name string) *ResourceID { + key := meta.RegionalKey(name, region) + return &ResourceID{project, "backendServices", key} +} + +// NewRegionDisksResourceID creates a ResourceID for the RegionDisks resource. +func NewRegionDisksResourceID(project, region, name string) *ResourceID { + key := meta.RegionalKey(name, region) + return &ResourceID{project, "disks", key} +} + +// NewRegionsResourceID creates a ResourceID for the Regions resource. +func NewRegionsResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "regions", key} +} + +// NewRoutesResourceID creates a ResourceID for the Routes resource. +func NewRoutesResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "routes", key} +} + +// NewSslCertificatesResourceID creates a ResourceID for the SslCertificates resource. +func NewSslCertificatesResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "sslCertificates", key} +} + +// NewTargetHttpProxiesResourceID creates a ResourceID for the TargetHttpProxies resource. +func NewTargetHttpProxiesResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "targetHttpProxies", key} +} + +// NewTargetHttpsProxiesResourceID creates a ResourceID for the TargetHttpsProxies resource. +func NewTargetHttpsProxiesResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "targetHttpsProxies", key} +} + +// NewTargetPoolsResourceID creates a ResourceID for the TargetPools resource. +func NewTargetPoolsResourceID(project, region, name string) *ResourceID { + key := meta.RegionalKey(name, region) + return &ResourceID{project, "targetPools", key} +} + +// NewUrlMapsResourceID creates a ResourceID for the UrlMaps resource. +func NewUrlMapsResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "urlMaps", key} +} + +// NewZonesResourceID creates a ResourceID for the Zones resource. +func NewZonesResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) + return &ResourceID{project, "zones", key} +} diff --git a/pkg/cloudprovider/providers/gce/cloud/gen/main.go b/pkg/cloudprovider/providers/gce/cloud/gen/main.go index 07aa0eb3049..47aeabe9d21 100644 --- a/pkg/cloudprovider/providers/gce/cloud/gen/main.go +++ b/pkg/cloudprovider/providers/gce/cloud/gen/main.go @@ -28,7 +28,6 @@ import ( "log" "os" "os/exec" - "sort" "text/template" "time" @@ -986,6 +985,38 @@ func (g *{{.GCEWrapType}}) {{.FcnArgs}} { } } +// genTypes generates the type wrappers. +func genResourceIDs(wr io.Writer) { + const text = ` +// New{{.Service}}ResourceID creates a ResourceID for the {{.Service}} resource. +{{- if .KeyIsProject}} +func New{{.Service}}ResourceID(project string) *ResourceID { + var key *meta.Key +{{- else}} +{{- if .KeyIsGlobal}} +func New{{.Service}}ResourceID(project, name string) *ResourceID { + key := meta.GlobalKey(name) +{{- end}} +{{- if .KeyIsRegional}} +func New{{.Service}}ResourceID(project, region, name string) *ResourceID { + key := meta.RegionalKey(name, region) +{{- end}} +{{- if .KeyIsZonal}} +func New{{.Service}}ResourceID(project, zone, name string) *ResourceID { + key := meta.ZonalKey(name, zone) +{{- end -}} +{{end}} + return &ResourceID{project, "{{.Resource}}", key} +} +` + tmpl := template.Must(template.New("resourceIDs").Parse(text)) + for _, sg := range meta.SortedServicesGroups { + if err := tmpl.Execute(wr, sg.ServiceInfo()); err != nil { + panic(err) + } + } +} + func genUnitTestHeader(wr io.Writer) { const text = `/* Copyright {{.Year}} The Kubernetes Authors. @@ -1238,20 +1269,86 @@ func Test{{.Service}}Group(t *testing.T) { } ` tmpl := template.Must(template.New("unittest").Parse(text)) - // Sort keys so the output will be stable. - var keys []string - for k := range meta.AllServicesByGroup { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - s := meta.AllServicesByGroup[k] - if err := tmpl.Execute(wr, s); err != nil { + for _, sg := range meta.SortedServicesGroups { + if err := tmpl.Execute(wr, sg); err != nil { panic(err) } } } +func genUnitTestResourceIDConversion(wr io.Writer) { + const text = ` +func TestResourceIDConversion(t *testing.T) { + t.Parallel() + + for _, id := range []*ResourceID{ + {{- range .Groups}} + {{- with .ServiceInfo}} + {{- if .KeyIsProject}} + New{{.Service}}ResourceID("my-{{.Resource}}-resource"), + {{- else}} + {{- if .KeyIsGlobal}} + New{{.Service}}ResourceID("some-project", "my-{{.Resource}}-resource"), + {{- end}} + {{- if .KeyIsRegional}} + New{{.Service}}ResourceID("some-project", "us-central1", "my-{{.Resource}}-resource"), + {{- end}} + {{- if .KeyIsZonal}} + New{{.Service}}ResourceID("some-project", "us-east1-b", "my-{{.Resource}}-resource"), + {{- end -}} + {{end -}} + {{end -}} + {{end}} + } { + t.Run(id.Resource, func(t *testing.T) { + // Test conversion to and from full URL. + fullURL := id.SelfLink(meta.VersionGA) + parsedID, err := ParseResourceURL(fullURL) + if err != nil { + t.Errorf("ParseResourceURL(%s) = _, %v, want nil", fullURL, err) + } + if !reflect.DeepEqual(id, parsedID) { + t.Errorf("SelfLink(%+v) -> ParseResourceURL(%s) = %+v, want original ID", id, fullURL, parsedID) + } + + // Test conversion to and from relative resource name. + relativeName := id.RelativeResourceName() + parsedID, err = ParseResourceURL(relativeName) + if err != nil { + t.Errorf("ParseResourceURL(%s) = _, %v, want nil", relativeName, err) + } + if !reflect.DeepEqual(id, parsedID) { + t.Errorf("RelativeResourceName(%+v) -> ParseResourceURL(%s) = %+v, want original ID", id, relativeName, parsedID) + } + + // Do not test ResourcePath for projects. + if id.Resource == "projects" { + return + } + + // Test conversion to and from resource path. + resourcePath := id.ResourcePath() + parsedID, err = ParseResourceURL(resourcePath) + if err != nil { + t.Errorf("ParseResourceURL(%s) = _, %v, want nil", resourcePath, err) + } + id.ProjectID = "" + if !reflect.DeepEqual(id, parsedID) { + t.Errorf("ResourcePath(%+v) -> ParseResourceURL(%s) = %+v, want %+v", id, resourcePath, parsedID, id) + } + }) + } +} +` + data := struct { + Groups []*meta.ServiceGroup + }{meta.SortedServicesGroups} + tmpl := template.Must(template.New("unittest-resourceIDs").Parse(text)) + if err := tmpl.Execute(wr, data); err != nil { + panic(err) + } +} + func main() { flag.Parse() @@ -1262,9 +1359,11 @@ func main() { genHeader(out) genStubs(out) genTypes(out) + genResourceIDs(out) case "test": genUnitTestHeader(out) genUnitTestServices(out) + genUnitTestResourceIDConversion(out) default: log.Fatalf("Invalid -mode: %q", flags.mode) } diff --git a/pkg/cloudprovider/providers/gce/cloud/gen_test.go b/pkg/cloudprovider/providers/gce/cloud/gen_test.go index 10d6f2aee37..178124513a3 100644 --- a/pkg/cloudprovider/providers/gce/cloud/gen_test.go +++ b/pkg/cloudprovider/providers/gce/cloud/gen_test.go @@ -1807,3 +1807,72 @@ func TestZonesGroup(t *testing.T) { // Delete not found. } + +func TestResourceIDConversion(t *testing.T) { + t.Parallel() + + for _, id := range []*ResourceID{ + NewAddressesResourceID("some-project", "us-central1", "my-addresses-resource"), + NewBackendServicesResourceID("some-project", "my-backendServices-resource"), + NewDisksResourceID("some-project", "us-east1-b", "my-disks-resource"), + NewFirewallsResourceID("some-project", "my-firewalls-resource"), + NewForwardingRulesResourceID("some-project", "us-central1", "my-forwardingRules-resource"), + NewGlobalAddressesResourceID("some-project", "my-addresses-resource"), + NewGlobalForwardingRulesResourceID("some-project", "my-forwardingRules-resource"), + NewHealthChecksResourceID("some-project", "my-healthChecks-resource"), + NewHttpHealthChecksResourceID("some-project", "my-httpHealthChecks-resource"), + NewHttpsHealthChecksResourceID("some-project", "my-httpsHealthChecks-resource"), + NewInstanceGroupsResourceID("some-project", "us-east1-b", "my-instanceGroups-resource"), + NewInstancesResourceID("some-project", "us-east1-b", "my-instances-resource"), + NewNetworkEndpointGroupsResourceID("some-project", "us-east1-b", "my-networkEndpointGroups-resource"), + NewProjectsResourceID("my-projects-resource"), + NewRegionBackendServicesResourceID("some-project", "us-central1", "my-backendServices-resource"), + NewRegionDisksResourceID("some-project", "us-central1", "my-disks-resource"), + NewRegionsResourceID("some-project", "my-regions-resource"), + NewRoutesResourceID("some-project", "my-routes-resource"), + NewSslCertificatesResourceID("some-project", "my-sslCertificates-resource"), + NewTargetHttpProxiesResourceID("some-project", "my-targetHttpProxies-resource"), + NewTargetHttpsProxiesResourceID("some-project", "my-targetHttpsProxies-resource"), + NewTargetPoolsResourceID("some-project", "us-central1", "my-targetPools-resource"), + NewUrlMapsResourceID("some-project", "my-urlMaps-resource"), + NewZonesResourceID("some-project", "my-zones-resource"), + } { + t.Run(id.Resource, func(t *testing.T) { + // Test conversion to and from full URL. + fullURL := id.SelfLink(meta.VersionGA) + parsedID, err := ParseResourceURL(fullURL) + if err != nil { + t.Errorf("ParseResourceURL(%s) = _, %v, want nil", fullURL, err) + } + if !reflect.DeepEqual(id, parsedID) { + t.Errorf("SelfLink(%+v) -> ParseResourceURL(%s) = %+v, want original ID", id, fullURL, parsedID) + } + + // Test conversion to and from relative resource name. + relativeName := id.RelativeResourceName() + parsedID, err = ParseResourceURL(relativeName) + if err != nil { + t.Errorf("ParseResourceURL(%s) = _, %v, want nil", relativeName, err) + } + if !reflect.DeepEqual(id, parsedID) { + t.Errorf("RelativeResourceName(%+v) -> ParseResourceURL(%s) = %+v, want original ID", id, relativeName, parsedID) + } + + // Do not test ResourcePath for projects. + if id.Resource == "projects" { + return + } + + // Test conversion to and from resource path. + resourcePath := id.ResourcePath() + parsedID, err = ParseResourceURL(resourcePath) + if err != nil { + t.Errorf("ParseResourceURL(%s) = _, %v, want nil", resourcePath, err) + } + id.ProjectID = "" + if !reflect.DeepEqual(id, parsedID) { + t.Errorf("ResourcePath(%+v) -> ParseResourceURL(%s) = %+v, want %+v", id, resourcePath, parsedID, id) + } + }) + } +} diff --git a/pkg/cloudprovider/providers/gce/cloud/meta/service.go b/pkg/cloudprovider/providers/gce/cloud/meta/service.go index b2ba91c8ec5..c18de2a5942 100644 --- a/pkg/cloudprovider/providers/gce/cloud/meta/service.go +++ b/pkg/cloudprovider/providers/gce/cloud/meta/service.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "reflect" + "sort" ) // ServiceInfo defines the entry for a Service that code will be generated for. @@ -159,6 +160,13 @@ 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 { @@ -220,15 +228,20 @@ type ServiceGroup struct { GA *ServiceInfo } -// Service returns any ServiceInfo object belonging to the ServiceGroup. +// 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.Service + return sg.GA case sg.Alpha != nil: - return sg.Alpha.Service + return sg.Alpha case sg.Beta != nil: - return sg.Beta.Service + return sg.Beta default: panic(errors.New("service group is empty")) } @@ -272,6 +285,16 @@ func groupServices(services []*ServiceInfo) map[string]*ServiceGroup { // 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() + }) } diff --git a/pkg/cloudprovider/providers/gce/cloud/utils.go b/pkg/cloudprovider/providers/gce/cloud/utils.go index fb258866fbb..0affadc96d2 100644 --- a/pkg/cloudprovider/providers/gce/cloud/utils.go +++ b/pkg/cloudprovider/providers/gce/cloud/utils.go @@ -25,9 +25,9 @@ import ( ) const ( - gaPrefix = "https://www.googleapis.com/compute/v1/" - alphaPrefix = "https://www.googleapis.com/compute/alpha/" - betaPrefix = "https://www.googleapis.com/compute/beta/" + 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. @@ -51,8 +51,27 @@ func (r *ResourceID) Equal(other *ResourceID) bool { 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// +// regions/// +// zones/// +// projects/ // projects//global// // projects//regions/// // projects//zones/// @@ -62,64 +81,63 @@ func (r *ResourceID) Equal(other *ResourceID) bool { func ParseResourceURL(url string) (*ResourceID, error) { errNotValid := fmt.Errorf("%q is not a valid resource URL", url) - // Remove the prefix up to ...projects/ + // 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 || parts[0] != "projects" { + if len(parts) < 2 || len(parts) > 6 { return nil, errNotValid } - ret := &ResourceID{ProjectID: parts[1]} - if len(parts) == 2 { + ret := &ResourceID{} + scopedName := parts + if parts[0] == "projects" { ret.Resource = "projects" - return ret, nil - } + ret.ProjectID = parts[1] + scopedName = parts[2:] - if len(parts) < 4 { - return nil, errNotValid - } - - if len(parts) == 4 { - switch parts[2] { - case "regions": - ret.Resource = "regions" - ret.Key = meta.GlobalKey(parts[3]) + if len(scopedName) == 0 { return ret, nil - case "zones": - ret.Resource = "zones" - ret.Key = meta.GlobalKey(parts[3]) + } + } + + 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 } - } - - switch parts[2] { - case "global": - if len(parts) != 5 { - return nil, errNotValid - } - ret.Resource = parts[3] - ret.Key = meta.GlobalKey(parts[4]) - return ret, nil - case "regions": - if len(parts) != 6 { - return nil, errNotValid - } - ret.Resource = parts[4] - ret.Key = meta.RegionalKey(parts[5], parts[3]) - return ret, nil case "zones": - if len(parts) != 6 { + 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 } - ret.Resource = parts[4] - ret.Key = meta.ZonalKey(parts[5], parts[3]) - return ret, nil } return nil, errNotValid } @@ -132,6 +150,38 @@ func copyViaJSON(dest, src interface{}) error { 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 @@ -146,13 +196,6 @@ func SelfLink(ver meta.Version, project, resource string, key *meta.Key) string prefix = "invalid-prefix" } - switch key.Type() { - case meta.Zonal: - return fmt.Sprintf("%sprojects/%s/zones/%s/%s/%s", prefix, project, key.Zone, resource, key.Name) - case meta.Regional: - return fmt.Sprintf("%sprojects/%s/regions/%s/%s/%s", prefix, project, key.Region, resource, key.Name) - case meta.Global: - return fmt.Sprintf("%sprojects/%s/%s/%s", prefix, project, resource, key.Name) - } - return "invalid-self-link" + return fmt.Sprintf("%s/%s", prefix, RelativeResourceName(project, resource, key)) + } diff --git a/pkg/cloudprovider/providers/gce/cloud/utils_test.go b/pkg/cloudprovider/providers/gce/cloud/utils_test.go index 9d2ee045190..0565638ccee 100644 --- a/pkg/cloudprovider/providers/gce/cloud/utils_test.go +++ b/pkg/cloudprovider/providers/gce/cloud/utils_test.go @@ -23,6 +23,54 @@ import ( "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() @@ -90,6 +138,18 @@ func TestParseResourceURL(t *testing.T) { "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 { @@ -112,7 +172,9 @@ func TestParseResourceURL(t *testing.T) { "/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", } { @@ -198,7 +260,28 @@ func TestSelfLink(t *testing.T) { "proj4", "urlMaps", meta.GlobalKey("key3"), - "https://www.googleapis.com/compute/v1/projects/proj4/urlMaps/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 { diff --git a/pkg/cloudprovider/providers/gce/gce_loadbalancer_internal_test.go b/pkg/cloudprovider/providers/gce/gce_loadbalancer_internal_test.go index 62bd15cc6f9..f6257a7cea4 100644 --- a/pkg/cloudprovider/providers/gce/gce_loadbalancer_internal_test.go +++ b/pkg/cloudprovider/providers/gce/gce_loadbalancer_internal_test.go @@ -321,7 +321,7 @@ func TestUpdateInternalLoadBalancerBackendServices(t *testing.T) { assert.Equal( t, bs.HealthChecks, - []string{fmt.Sprintf("%s/healthChecks/k8s-%s-node", url_base, vals.ClusterID)}, + []string{fmt.Sprintf("%s/global/healthChecks/k8s-%s-node", url_base, vals.ClusterID)}, ) }