Browse code

make all alias correctly

deads2k authored on 2016/02/27 05:14:40
Showing 6 changed files
... ...
@@ -31,16 +31,6 @@ var originTypes map[unversioned.GroupVersionKind]bool
31 31
 // but that is not onerous
32 32
 var originTypesLock sync.Once
33 33
 
34
-// UserResources are the resource names that apply to the primary, user facing resources used by
35
-// client tools. They are in deletion-first order - dependent resources should be last.
36
-var UserResources = []string{
37
-	"buildConfigs", "builds",
38
-	"imageStreams",
39
-	"deploymentConfigs", "replicationControllers",
40
-	"routes", "services",
41
-	"pods",
42
-}
43
-
44 34
 // OriginKind returns true if OpenShift owns the GroupVersionKind.
45 35
 func OriginKind(gvk unversioned.GroupVersionKind) bool {
46 36
 	return getOrCreateOriginKinds()[gvk]
47 37
new file mode 100644
... ...
@@ -0,0 +1,73 @@
0
+package client
1
+
2
+import (
3
+	"net/url"
4
+
5
+	"k8s.io/kubernetes/pkg/api/errors"
6
+	"k8s.io/kubernetes/pkg/api/unversioned"
7
+	kclient "k8s.io/kubernetes/pkg/client/unversioned"
8
+)
9
+
10
+// DiscoveryClient implements the functions that dicovery server-supported API groups,
11
+// versions and resources.
12
+type DiscoveryClient struct {
13
+	*kclient.DiscoveryClient
14
+}
15
+
16
+// ServerResourcesForGroupVersion returns the supported resources for a group and version.
17
+func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (resources *unversioned.APIResourceList, err error) {
18
+	// we don't expose this version
19
+	if groupVersion == "v1beta3" {
20
+		return &unversioned.APIResourceList{}, nil
21
+	}
22
+
23
+	parentList, err := d.DiscoveryClient.ServerResourcesForGroupVersion(groupVersion)
24
+	if err != nil {
25
+		return parentList, err
26
+	}
27
+
28
+	if groupVersion != "v1" {
29
+		return parentList, nil
30
+	}
31
+
32
+	// we request v1, we must combine the parent list with the list from /oapi
33
+
34
+	url := url.URL{}
35
+	url.Path = "/oapi/" + groupVersion
36
+	originResources := &unversioned.APIResourceList{}
37
+	err = d.Get().AbsPath(url.String()).Do().Into(originResources)
38
+	if err != nil {
39
+		// ignore 403 or 404 error to be compatible with an v1.0 server.
40
+		if groupVersion == "v1" && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
41
+			return parentList, nil
42
+		} else {
43
+			return nil, err
44
+		}
45
+	}
46
+
47
+	parentList.APIResources = append(parentList.APIResources, originResources.APIResources...)
48
+	return parentList, nil
49
+}
50
+
51
+// ServerResources returns the supported resources for all groups and versions.
52
+func (d *DiscoveryClient) ServerResources() (map[string]*unversioned.APIResourceList, error) {
53
+	apiGroups, err := d.ServerGroups()
54
+	if err != nil {
55
+		return nil, err
56
+	}
57
+	groupVersions := kclient.ExtractGroupVersions(apiGroups)
58
+	result := map[string]*unversioned.APIResourceList{}
59
+	for _, groupVersion := range groupVersions {
60
+		resources, err := d.ServerResourcesForGroupVersion(groupVersion)
61
+		if err != nil {
62
+			return nil, err
63
+		}
64
+		result[groupVersion] = resources
65
+	}
66
+	return result, nil
67
+}
68
+
69
+// New creates a new DiscoveryClient for the given RESTClient.
70
+func NewDiscoveryClient(c *kclient.RESTClient) *DiscoveryClient {
71
+	return &DiscoveryClient{kclient.NewDiscoveryClient(c)}
72
+}
... ...
@@ -167,7 +167,6 @@ func NewFactory(clientConfig kclientcmd.ClientConfig) *Factory {
167 167
 		}
168 168
 		restMapper = meta.MultiRESTMapper(append(restMapper, groupMeta.RESTMapper))
169 169
 	}
170
-	mapper := ShortcutExpander{RESTMapper: kubectl.ShortcutExpander{RESTMapper: restMapper}}
171 170
 
172 171
 	clients := &clientCache{
173 172
 		clients: make(map[string]*client.Client),
... ...
@@ -182,16 +181,30 @@ func NewFactory(clientConfig kclientcmd.ClientConfig) *Factory {
182 182
 	}
183 183
 
184 184
 	w.Object = func() (meta.RESTMapper, runtime.ObjectTyper) {
185
+
186
+		defaultMapper := ShortcutExpander{RESTMapper: kubectl.ShortcutExpander{RESTMapper: restMapper}}
187
+		defaultTyper := api.Scheme
188
+
185 189
 		// Output using whatever version was negotiated in the client cache. The
186 190
 		// version we decode with may not be the same as what the server requires.
187
-		if cfg, err := clients.ClientConfigForVersion(nil); err == nil {
188
-			cmdApiVersion := unversioned.GroupVersion{}
189
-			if cfg.GroupVersion != nil {
190
-				cmdApiVersion = *cfg.GroupVersion
191
-			}
192
-			return kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}}, api.Scheme
191
+		cfg, err := clients.ClientConfigForVersion(nil)
192
+		if err != nil {
193
+			return defaultMapper, defaultTyper
194
+		}
195
+
196
+		cmdApiVersion := unversioned.GroupVersion{}
197
+		if cfg.GroupVersion != nil {
198
+			cmdApiVersion = *cfg.GroupVersion
193 199
 		}
194
-		return mapper, api.Scheme
200
+
201
+		// at this point we've negotiated and can get the client
202
+		oclient, err := clients.ClientForVersion(nil)
203
+		if err != nil {
204
+			return defaultMapper, defaultTyper
205
+		}
206
+
207
+		mapper := NewShortcutExpander(client.NewDiscoveryClient(oclient.RESTClient), kubectl.ShortcutExpander{RESTMapper: restMapper})
208
+		return kubectl.OutputVersionMapper{RESTMapper: mapper, OutputVersions: []unversioned.GroupVersion{cmdApiVersion}}, api.Scheme
195 209
 	}
196 210
 
197 211
 	kClientForMapping := w.Factory.ClientForMapping
... ...
@@ -581,76 +594,6 @@ func (f *Factory) OriginSwaggerSchema(client *kclient.RESTClient, version unvers
581 581
 	return &schema, nil
582 582
 }
583 583
 
584
-// ShortcutExpander is a RESTMapper that can be used for OpenShift resources.   It expands the resource first, then invokes the wrapped
585
-type ShortcutExpander struct {
586
-	RESTMapper meta.RESTMapper
587
-}
588
-
589
-var _ meta.RESTMapper = &ShortcutExpander{}
590
-
591
-func (e ShortcutExpander) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) {
592
-	return e.RESTMapper.KindFor(expandResourceShortcut(resource))
593
-}
594
-
595
-func (e ShortcutExpander) KindsFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionKind, error) {
596
-	return e.RESTMapper.KindsFor(expandResourceShortcut(resource))
597
-}
598
-
599
-func (e ShortcutExpander) ResourcesFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) {
600
-	return e.RESTMapper.ResourcesFor(expandResourceShortcut(resource))
601
-}
602
-
603
-func (e ShortcutExpander) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) {
604
-	return e.RESTMapper.ResourceFor(expandResourceShortcut(resource))
605
-}
606
-
607
-func (e ShortcutExpander) ResourceIsValid(resource unversioned.GroupVersionResource) bool {
608
-	return e.RESTMapper.ResourceIsValid(expandResourceShortcut(resource))
609
-}
610
-
611
-func (e ShortcutExpander) ResourceSingularizer(resource string) (string, error) {
612
-	return e.RESTMapper.ResourceSingularizer(expandResourceShortcut(unversioned.GroupVersionResource{Resource: resource}).Resource)
613
-}
614
-
615
-func (e ShortcutExpander) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
616
-	return e.RESTMapper.RESTMapping(gk, versions...)
617
-}
618
-
619
-// AliasesForResource returns whether a resource has an alias or not
620
-func (e ShortcutExpander) AliasesForResource(resource string) ([]string, bool) {
621
-	aliases := map[string][]string{
622
-		"all": latest.UserResources,
623
-	}
624
-
625
-	if res, ok := aliases[resource]; ok {
626
-		return res, true
627
-	}
628
-	return e.RESTMapper.AliasesForResource(expandResourceShortcut(unversioned.GroupVersionResource{Resource: resource}).Resource)
629
-}
630
-
631
-// shortForms is the list of short names to their expanded names
632
-var shortForms = map[string]string{
633
-	"dc":      "deploymentconfigs",
634
-	"bc":      "buildconfigs",
635
-	"is":      "imagestreams",
636
-	"istag":   "imagestreamtags",
637
-	"isimage": "imagestreamimages",
638
-	"sa":      "serviceaccounts",
639
-	"pv":      "persistentvolumes",
640
-	"pvc":     "persistentvolumeclaims",
641
-}
642
-
643
-// expandResourceShortcut will return the expanded version of resource
644
-// (something that a pkg/api/meta.RESTMapper can understand), if it is
645
-// indeed a shortcut. Otherwise, will return resource unmodified.
646
-func expandResourceShortcut(resource unversioned.GroupVersionResource) unversioned.GroupVersionResource {
647
-	if expanded, ok := shortForms[resource.Resource]; ok {
648
-		resource.Resource = expanded
649
-		return resource
650
-	}
651
-	return resource
652
-}
653
-
654 584
 // clientCache caches previously loaded clients for reuse. This is largely
655 585
 // copied from upstream (because of typing) but reuses the negotiation logic.
656 586
 // TODO: Consolidate this entire concept with upstream's ClientCache.
657 587
new file mode 100644
... ...
@@ -0,0 +1,126 @@
0
+package clientcmd
1
+
2
+import (
3
+	"k8s.io/kubernetes/pkg/api/meta"
4
+	"k8s.io/kubernetes/pkg/api/unversioned"
5
+	kclient "k8s.io/kubernetes/pkg/client/unversioned"
6
+)
7
+
8
+// ShortcutExpander is a RESTMapper that can be used for OpenShift resources.   It expands the resource first, then invokes the wrapped
9
+type ShortcutExpander struct {
10
+	RESTMapper meta.RESTMapper
11
+
12
+	All []string
13
+}
14
+
15
+var _ meta.RESTMapper = &ShortcutExpander{}
16
+
17
+func NewShortcutExpander(discoveryClient kclient.DiscoveryInterface, delegate meta.RESTMapper) ShortcutExpander {
18
+	defaultMapper := ShortcutExpander{RESTMapper: delegate}
19
+
20
+	// this assumes that legacy kube versions and legacy origin versions are the same, probably fair
21
+	apiResources, err := discoveryClient.ServerResources()
22
+	if err != nil {
23
+		return defaultMapper
24
+	}
25
+
26
+	availableResources := []unversioned.GroupVersionResource{}
27
+	for groupVersionString, resourceList := range apiResources {
28
+		currVersion, err := unversioned.ParseGroupVersion(groupVersionString)
29
+		if err != nil {
30
+			return defaultMapper
31
+		}
32
+
33
+		for _, resource := range resourceList.APIResources {
34
+			availableResources = append(availableResources, currVersion.WithResource(resource.Name))
35
+		}
36
+	}
37
+
38
+	availableAll := []string{}
39
+	for _, requestedResource := range userResources {
40
+		for _, availableResource := range availableResources {
41
+			if requestedResource == availableResource.Resource {
42
+				availableAll = append(availableAll, requestedResource)
43
+				break
44
+			}
45
+		}
46
+	}
47
+
48
+	return ShortcutExpander{All: availableAll, RESTMapper: delegate}
49
+}
50
+
51
+func (e ShortcutExpander) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) {
52
+	return e.RESTMapper.KindFor(expandResourceShortcut(resource))
53
+}
54
+
55
+func (e ShortcutExpander) KindsFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionKind, error) {
56
+	return e.RESTMapper.KindsFor(expandResourceShortcut(resource))
57
+}
58
+
59
+func (e ShortcutExpander) ResourcesFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) {
60
+	return e.RESTMapper.ResourcesFor(expandResourceShortcut(resource))
61
+}
62
+
63
+func (e ShortcutExpander) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) {
64
+	return e.RESTMapper.ResourceFor(expandResourceShortcut(resource))
65
+}
66
+
67
+func (e ShortcutExpander) ResourceIsValid(resource unversioned.GroupVersionResource) bool {
68
+	return e.RESTMapper.ResourceIsValid(expandResourceShortcut(resource))
69
+}
70
+
71
+func (e ShortcutExpander) ResourceSingularizer(resource string) (string, error) {
72
+	return e.RESTMapper.ResourceSingularizer(expandResourceShortcut(unversioned.GroupVersionResource{Resource: resource}).Resource)
73
+}
74
+
75
+func (e ShortcutExpander) RESTMapping(gk unversioned.GroupKind, versions ...string) (*meta.RESTMapping, error) {
76
+	return e.RESTMapper.RESTMapping(gk, versions...)
77
+}
78
+
79
+// userResources are the resource names that apply to the primary, user facing resources used by
80
+// client tools. They are in deletion-first order - dependent resources should be last.
81
+var userResources = []string{
82
+	"buildconfigs", "builds",
83
+	"imagestreams",
84
+	"deploymentconfigs", "replicationcontrollers",
85
+	"routes", "services",
86
+	"pods",
87
+}
88
+
89
+// AliasesForResource returns whether a resource has an alias or not
90
+func (e ShortcutExpander) AliasesForResource(resource string) ([]string, bool) {
91
+	aliases := map[string][]string{
92
+		"all": userResources,
93
+	}
94
+	if len(e.All) != 0 {
95
+		aliases["all"] = e.All
96
+	}
97
+
98
+	if res, ok := aliases[resource]; ok {
99
+		return res, true
100
+	}
101
+	return e.RESTMapper.AliasesForResource(expandResourceShortcut(unversioned.GroupVersionResource{Resource: resource}).Resource)
102
+}
103
+
104
+// shortForms is the list of short names to their expanded names
105
+var shortForms = map[string]string{
106
+	"dc":      "deploymentconfigs",
107
+	"bc":      "buildconfigs",
108
+	"is":      "imagestreams",
109
+	"istag":   "imagestreamtags",
110
+	"isimage": "imagestreamimages",
111
+	"sa":      "serviceaccounts",
112
+	"pv":      "persistentvolumes",
113
+	"pvc":     "persistentvolumeclaims",
114
+}
115
+
116
+// expandResourceShortcut will return the expanded version of resource
117
+// (something that a pkg/api/meta.RESTMapper can understand), if it is
118
+// indeed a shortcut. Otherwise, will return resource unmodified.
119
+func expandResourceShortcut(resource unversioned.GroupVersionResource) unversioned.GroupVersionResource {
120
+	if expanded, ok := shortForms[resource.Resource]; ok {
121
+		resource.Resource = expanded
122
+		return resource
123
+	}
124
+	return resource
125
+}
... ...
@@ -22,6 +22,7 @@ os::log::install_errexit
22 22
 
23 23
 os::cmd::expect_success_and_text 'oc types' 'Deployment Configuration'
24 24
 os::cmd::expect_failure_and_text 'oc get' 'deploymentconfig'
25
+os::cmd::expect_success_and_text 'oc get all --loglevel=6' 'buildconfigs'
25 26
 os::cmd::expect_success_and_text 'oc explain pods' 'Pod is a collection of containers that can run on a host'
26 27
 os::cmd::expect_success_and_text 'oc explain pods.spec' 'SecurityContext holds pod-level security attributes'
27 28
 os::cmd::expect_success_and_text 'oc explain deploymentconfig' 'a desired deployment state'
28 29
new file mode 100644
... ...
@@ -0,0 +1,60 @@
0
+// +build integration
1
+
2
+package integration
3
+
4
+import (
5
+	"testing"
6
+
7
+	"k8s.io/kubernetes/pkg/util/sets"
8
+
9
+	"github.com/openshift/origin/pkg/client"
10
+	configapi "github.com/openshift/origin/pkg/cmd/server/api"
11
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
12
+	testutil "github.com/openshift/origin/test/util"
13
+	testserver "github.com/openshift/origin/test/util/server"
14
+)
15
+
16
+func TestFullExpansion(t *testing.T) {
17
+	testutil.RequireEtcd(t)
18
+	_, clusterAdminKubeConfig, err := testserver.StartTestMasterAPI()
19
+	if err != nil {
20
+		t.Fatalf("unexpected error: %v", err)
21
+	}
22
+
23
+	clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig)
24
+	if err != nil {
25
+		t.Fatalf("unexpected error: %v", err)
26
+	}
27
+
28
+	mapper := clientcmd.NewShortcutExpander(client.NewDiscoveryClient(clusterAdminClient.RESTClient), nil)
29
+
30
+	if !sets.NewString(mapper.All...).Has("buildconfigs") {
31
+		t.Errorf("expected buildconfigs, got: %v", mapper.All)
32
+	}
33
+}
34
+
35
+func TestExpansionWithoutBuilds(t *testing.T) {
36
+	testutil.RequireEtcd(t)
37
+
38
+	masterConfig, err := testserver.DefaultMasterOptions()
39
+	if err != nil {
40
+		t.Fatalf("unexpected error: %v", err)
41
+	}
42
+
43
+	masterConfig.DisabledFeatures = configapi.AtomicDisabledFeatures
44
+	clusterAdminKubeConfig, err := testserver.StartConfiguredMasterAPI(masterConfig)
45
+	if err != nil {
46
+		t.Fatalf("unexpected error: %v", err)
47
+	}
48
+
49
+	clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig)
50
+	if err != nil {
51
+		t.Fatalf("unexpected error: %v", err)
52
+	}
53
+
54
+	mapper := clientcmd.NewShortcutExpander(client.NewDiscoveryClient(clusterAdminClient.RESTClient), nil)
55
+
56
+	if sets.NewString(mapper.All...).Has("buildconfigs") {
57
+		t.Errorf("expected no buildconfigs, got: %v", mapper.All)
58
+	}
59
+}