mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
Merge pull request #62516 from nicksardo/expand-id
Automatic merge from submit-queue (batch tested with PRs 62060, 62516). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. [GCE] Add new formats to resource parser and self link creator **What this PR does / why we need it**: - Expands the set of parse-able strings for resource IDs, while also simplifying the code. Note that these are acceptable values for some fields in GCP API. - global/networks/my-network - regions/us-central1/subnetworks/my-sub - zones/us-central1-a/instances/my-hacker-instance - Fixes the SelfLink function to return links for regions and zones: - https://www.googleapis.com/compute/v1/projects/proj4/regions/us-central1 - Generates helper functions to create a ResourceID for each resource - Generates a unit test that ensures all links can be generated and all generated links can be parsed. - Fixes an ILB test which creates a malformed URL. **Special notes for your reviewer**: /assign rramkumar1 **Release note**: ```release-note NONE ```
This commit is contained in:
commit
c968d99ee5
@ -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}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
})
|
||||
}
|
||||
|
@ -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/<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>
|
||||
@ -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))
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)},
|
||||
)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user