Repository: kubernetes/dashboard
Pull request #4496 (2019-11-01 03:45:02)

add list/detail for roleBinding and clusterRoleBinding resource
@maciaszczykm hi~marcin, could you help me review this, thanks.

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes/dashboard/pull/4496#" title="Author self-approved">zehuaiWANG</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **maciaszczykm**
You can assign the PR to them by writing `/assign @maciaszczykm` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fdashboard).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes/dashboard/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["maciaszczykm"]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/kubernetes/dashboard/pull/4496?src=pr&el=h1) Report
> Merging [#4496](https://codecov.io/gh/kubernetes/dashboard/pull/4496?src=pr&el=desc) into [master](https://codecov.io/gh/kubernetes/dashboard/commit/377842ddda5ce5a58e2d5397dffb14de9522ddb4?src=pr&el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `39.06%`.

[![Impacted file tree graph](https://codecov.io/gh/kubernetes/dashboard/pull/4496/graphs/tree.svg?width=650&token=Wj7jysJ9A5&height=150&src=pr)](https://codecov.io/gh/kubernetes/dashboard/pull/4496?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #4496      +/-   ##
==========================================
- Coverage    46.6%   46.59%   -0.02%     
==========================================
  Files         203      206       +3     
  Lines        9459     9519      +60     
  Branches      107      107              
==========================================
+ Hits         4408     4435      +27     
- Misses       4779     4811      +32     
- Partials      272      273       +1
```


| [Impacted Files](https://codecov.io/gh/kubernetes/dashboard/pull/4496?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/app/backend/resource/role/detail.go](https://codecov.io/gh/kubernetes/dashboard/pull/4496/diff?src=pr&el=tree#diff-c3JjL2FwcC9iYWNrZW5kL3Jlc291cmNlL3JvbGUvZGV0YWlsLmdv) | `0% <ø> (ø)` | :arrow_up: |
| [src/app/backend/api/types.go](https://codecov.io/gh/kubernetes/dashboard/pull/4496/diff?src=pr&el=tree#diff-c3JjL2FwcC9iYWNrZW5kL2FwaS90eXBlcy5nbw==) | `35.29% <ø> (ø)` | :arrow_up: |
| [...rc/app/backend/resource/common/resourcechannels.go](https://codecov.io/gh/kubernetes/dashboard/pull/4496/diff?src=pr&el=tree#diff-c3JjL2FwcC9iYWNrZW5kL3Jlc291cmNlL2NvbW1vbi9yZXNvdXJjZWNoYW5uZWxzLmdv) | `0% <0%> (ø)` | :arrow_up: |
| [src/app/backend/resource/role/list.go](https://codecov.io/gh/kubernetes/dashboard/pull/4496/diff?src=pr&el=tree#diff-c3JjL2FwcC9iYWNrZW5kL3Jlc291cmNlL3JvbGUvbGlzdC5nbw==) | `53.57% <0%> (ø)` | :arrow_up: |
| [src/app/backend/resource/rolebinding/detail.go](https://codecov.io/gh/kubernetes/dashboard/pull/4496/diff?src=pr&el=tree#diff-c3JjL2FwcC9iYWNrZW5kL3Jlc291cmNlL3JvbGViaW5kaW5nL2RldGFpbC5nbw==) | `0% <0%> (ø)` | |
| [src/app/backend/resource/rolebinding/common.go](https://codecov.io/gh/kubernetes/dashboard/pull/4496/diff?src=pr&el=tree#diff-c3JjL2FwcC9iYWNrZW5kL3Jlc291cmNlL3JvbGViaW5kaW5nL2NvbW1vbi5nbw==) | `50% <50%> (ø)` | |
| [src/app/backend/resource/rolebinding/list.go](https://codecov.io/gh/kubernetes/dashboard/pull/4496/diff?src=pr&el=tree#diff-c3JjL2FwcC9iYWNrZW5kL3Jlc291cmNlL3JvbGViaW5kaW5nL2xpc3QuZ28=) | `53.57% <53.57%> (ø)` | |
| [...p/backend/integration/metric/common/aggregation.go](https://codecov.io/gh/kubernetes/dashboard/pull/4496/diff?src=pr&el=tree#diff-c3JjL2FwcC9iYWNrZW5kL2ludGVncmF0aW9uL21ldHJpYy9jb21tb24vYWdncmVnYXRpb24uZ28=) | `89.09% <0%> (-1.82%)` | :arrow_down: |
| ... and [2 more](https://codecov.io/gh/kubernetes/dashboard/pull/4496/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/kubernetes/dashboard/pull/4496?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/kubernetes/dashboard/pull/4496?src=pr&el=footer). Last update [377842d...93454c8](https://codecov.io/gh/kubernetes/dashboard/pull/4496?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/package-lock.json b/package-lock.json
index a2aa4acfe..098ea9994 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2716,9 +2716,9 @@
       "dev": true
     },
     "@types/lodash": {
-      "version": "4.14.143",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.143.tgz",
-      "integrity": "sha512-SJjLJkaSVYfRTLdi5llaabRVjWHQ86McEJ0BGNzHYREtJvlnJEHlaLcZ8s7Ah091QFfOeZTtiduoUN2gTcpTng==",
+      "version": "4.14.144",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz",
+      "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==",
       "dev": true
     },
     "@types/minimatch": {
@@ -7383,9 +7383,9 @@
       }
     },
     "d3": {
-      "version": "5.10.1",
-      "resolved": "https://registry.npmjs.org/d3/-/d3-5.10.1.tgz",
-      "integrity": "sha512-6D2dphCERVIJAujrgORtT59SNTT4Eeh/If4BICTGc9FEpW2swoc8eE82os5E9s5Q7PjCykANH3c4KKQxYdOzoQ==",
+      "version": "5.12.0",
+      "resolved": "https://registry.npmjs.org/d3/-/d3-5.12.0.tgz",
+      "integrity": "sha512-flYVMoVuhPFHd9zVCe2BxIszUWqBcd5fvQGMNRmSiBrgdnh6Vlruh60RJQTouAK9xPbOB0plxMvBm4MoyODXNg==",
       "requires": {
         "d3-array": "1",
         "d3-axis": "1",
@@ -7457,9 +7457,9 @@
       "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
     },
     "d3-color": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.3.0.tgz",
-      "integrity": "sha512-NHODMBlj59xPAwl2BDiO2Mog6V+PrGRtBfWKqKRrs9MCqlSkIEb0Z/SfY7jW29ReHTDC/j+vwXhnZcXI3+3fbg=="
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz",
+      "integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg=="
     },
     "d3-contour": {
       "version": "1.3.2",
@@ -7518,9 +7518,9 @@
       }
     },
     "d3-format": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.3.2.tgz",
-      "integrity": "sha512-Z18Dprj96ExragQ0DeGi+SYPQ7pPfRMtUXtsg/ChVIKNBCzjO8XYJvRTC1usblx52lqge56V5ect+frYTQc8WQ=="
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.1.tgz",
+      "integrity": "sha512-TUswGe6hfguUX1CtKxyG2nymO+1lyThbkS1ifLX0Sr+dOQtAD5gkrffpHnx+yHNKUZ0Bmg5T4AjUQwugPDrm0g=="
     },
     "d3-geo": {
       "version": "1.11.6",
@@ -7599,14 +7599,14 @@
       }
     },
     "d3-time": {
-      "version": "1.0.11",
-      "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.11.tgz",
-      "integrity": "sha512-Z3wpvhPLW4vEScGeIMUckDW7+3hWKOQfAWg/U7PlWBnQmeKQ00gCUsTtWSYulrKNA7ta8hJ+xXc6MHrMuITwEw=="
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
+      "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
     },
     "d3-time-format": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.3.tgz",
-      "integrity": "sha512-6k0a2rZryzGm5Ihx+aFMuO1GgelgIz+7HhB4PH4OEndD5q2zGn1mDfRdNrulspOfR6JXkb2sThhDK41CSK85QA==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.2.1.tgz",
+      "integrity": "sha512-VA6WqORO1+H1SvSzgl2oT0z3niANh3opa8Cencpen1LFthw/bEX71R/DgjPlWw78J4UHmD0jCPP1W0HpwMkhjg==",
       "requires": {
         "d3-time": "1"
       }
diff --git a/package.json b/package.json
index 9c07bc6b5..2dff70a01 100644
--- a/package.json
+++ b/package.json
@@ -112,7 +112,7 @@
     "ace-builds": "1.4.7",
     "c3": "0.7.10",
     "core-js": "3.3.3",
-    "d3": "5.10.1",
+    "d3": "5.12.0",
     "file-saver": "2.0.2",
     "hammerjs": "2.0.8",
     "highlight.js": "^9.15.8",
@@ -140,7 +140,7 @@
     "@types/jasmine": "3.4.4",
     "@types/jasminewd2": "2.0.8",
     "@types/js-yaml": "3.12.1",
-    "@types/lodash": "4.14.143",
+    "@types/lodash": "4.14.144",
     "@types/node": "12.12.1",
     "babel": "6.23.0",
     "babel-preset-env": "1.7.0",
diff --git a/src/app/backend/api/types.go b/src/app/backend/api/types.go
index cffe5a809..566142439 100644
--- a/src/app/backend/api/types.go
+++ b/src/app/backend/api/types.go
@@ -137,7 +137,9 @@ const (
 	ResourceKindStatefulSet              = "statefulset"
 	ResourceKindStorageClass             = "storageclass"
 	ResourceKindClusterRole              = "clusterrole"
+	ResourceKindClusterRoleBinding       = "clusterrolebinding"
 	ResourceKindRole                     = "role"
+	ResourceKindRoleBinding              = "rolebinding"
 	ResourceKindPlugin                   = "plugin"
 	ResourceKindEndpoint                 = "endpoint"
 )
diff --git a/src/app/backend/handler/apihandler.go b/src/app/backend/handler/apihandler.go
index 4c537d823..aa71cc679 100644
--- a/src/app/backend/handler/apihandler.go
+++ b/src/app/backend/handler/apihandler.go
@@ -32,6 +32,7 @@ import (
 	"github.com/kubernetes/dashboard/src/app/backend/errors"
 	"github.com/kubernetes/dashboard/src/app/backend/integration"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/clusterrole"
+	"github.com/kubernetes/dashboard/src/app/backend/resource/clusterrolebinding"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/common"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/configmap"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/container"
@@ -54,6 +55,7 @@ import (
 	"github.com/kubernetes/dashboard/src/app/backend/resource/replicaset"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/replicationcontroller"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/role"
+	"github.com/kubernetes/dashboard/src/app/backend/resource/rolebinding"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/secret"
 	resourceService "github.com/kubernetes/dashboard/src/app/backend/resource/service"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/statefulset"
@@ -517,6 +519,15 @@ func CreateHTTPAPIHandler(iManager integration.IntegrationManager, cManager clie
 			To(apiHandler.handleGetClusterRoleDetail).
 			Writes(clusterrole.ClusterRoleDetail{}))
 
+	apiV1Ws.Route(
+		apiV1Ws.GET("/clusterrolebinding").
+			To(apiHandler.handleGetClusterRoleBindingList).
+			Writes(clusterrolebinding.ClusterRoleBindingList{}))
+	apiV1Ws.Route(
+		apiV1Ws.GET("/clusterrolebinding/{name}").
+			To(apiHandler.handleGetClusterRoleBindingDetail).
+			Writes(clusterrolebinding.ClusterRoleBindingDetail{}))
+
 	apiV1Ws.Route(
 		apiV1Ws.GET("/role/{namespace}").
 			To(apiHandler.handleGetRoleList).
@@ -526,6 +537,15 @@ func CreateHTTPAPIHandler(iManager integration.IntegrationManager, cManager clie
 			To(apiHandler.handleGetRoleDetail).
 			Writes(role.RoleDetail{}))
 
+	apiV1Ws.Route(
+		apiV1Ws.GET("/rolebinding/{namespace}").
+			To(apiHandler.handleGetRoleBindingList).
+			Writes(rolebinding.RoleBindingList{}))
+	apiV1Ws.Route(
+		apiV1Ws.GET("/rolebinding/{namespace}/{name}").
+			To(apiHandler.handleGetRoleBindingDetail).
+			Writes(rolebinding.RoleBindingDetail{}))
+
 	apiV1Ws.Route(
 		apiV1Ws.GET("/persistentvolume").
 			To(apiHandler.handleGetPersistentVolumeList).
@@ -644,6 +664,38 @@ func (apiHandler *APIHandler) handleGetClusterRoleDetail(request *restful.Reques
 	response.WriteHeaderAndEntity(http.StatusOK, result)
 }
 
+func (apiHandler *APIHandler) handleGetClusterRoleBindingList(request *restful.Request, response *restful.Response) {
+	k8sClient, err := apiHandler.cManager.Client(request)
+	if err != nil {
+		errors.HandleInternalError(response, err)
+		return
+	}
+
+	dataSelect := parser.ParseDataSelectPathParameter(request)
+	result, err := clusterrolebinding.GetClusterRoleBindingList(k8sClient, dataSelect)
+	if err != nil {
+		errors.HandleInternalError(response, err)
+		return
+	}
+	response.WriteHeaderAndEntity(http.StatusOK, result)
+}
+
+func (apiHandler *APIHandler) handleGetClusterRoleBindingDetail(request *restful.Request, response *restful.Response) {
+	k8sClient, err := apiHandler.cManager.Client(request)
+	if err != nil {
+		errors.HandleInternalError(response, err)
+		return
+	}
+
+	name := request.PathParameter("name")
+	result, err := clusterrolebinding.GetClusterRoleBindingDetail(k8sClient, name)
+	if err != nil {
+		errors.HandleInternalError(response, err)
+		return
+	}
+	response.WriteHeaderAndEntity(http.StatusOK, result)
+}
+
 func (apiHandler *APIHandler) handleGetRoleList(request *restful.Request, response *restful.Response) {
 	k8sClient, err := apiHandler.cManager.Client(request)
 	if err != nil {
@@ -678,6 +730,40 @@ func (apiHandler *APIHandler) handleGetRoleDetail(request *restful.Request, resp
 	response.WriteHeaderAndEntity(http.StatusOK, result)
 }
 
+func (apiHandler *APIHandler) handleGetRoleBindingList(request *restful.Request, response *restful.Response) {
+	k8sClient, err := apiHandler.cManager.Client(request)
+	if err != nil {
+		errors.HandleInternalError(response, err)
+		return
+	}
+
+	namespace := parseNamespacePathParameter(request)
+	dataSelect := parser.ParseDataSelectPathParameter(request)
+	result, err := rolebinding.GetRoleBindingList(k8sClient, namespace, dataSelect)
+	if err != nil {
+		errors.HandleInternalError(response, err)
+		return
+	}
+	response.WriteHeaderAndEntity(http.StatusOK, result)
+}
+
+func (apiHandler *APIHandler) handleGetRoleBindingDetail(request *restful.Request, response *restful.Response) {
+	k8sClient, err := apiHandler.cManager.Client(request)
+	if err != nil {
+		errors.HandleInternalError(response, err)
+		return
+	}
+
+	namespace := request.PathParameter("namespace")
+	name := request.PathParameter("name")
+	result, err := rolebinding.GetRoleBindingDetail(k8sClient, namespace, name)
+	if err != nil {
+		errors.HandleInternalError(response, err)
+		return
+	}
+	response.WriteHeaderAndEntity(http.StatusOK, result)
+}
+
 func (apiHandler *APIHandler) handleGetCsrfToken(request *restful.Request, response *restful.Response) {
 	action := request.PathParameter("action")
 	token := xsrftoken.Generate(apiHandler.cManager.CSRFKey(), "none", action)
diff --git a/src/app/backend/resource/clusterrolebinding/common.go b/src/app/backend/resource/clusterrolebinding/common.go
new file mode 100644
index 000000000..da94ce6f5
--- /dev/null
+++ b/src/app/backend/resource/clusterrolebinding/common.go
@@ -0,0 +1,53 @@
+// 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 clusterrolebinding
+
+import (
+	"github.com/kubernetes/dashboard/src/app/backend/resource/dataselect"
+)
+
+// The code below allows to perform complex data section on []ClusterRoleBinding
+
+type ClusterRoleBindingCell ClusterRoleBinding
+
+func (self ClusterRoleBindingCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue {
+	switch name {
+	case dataselect.NameProperty:
+		return dataselect.StdComparableString(self.ObjectMeta.Name)
+	case dataselect.CreationTimestampProperty:
+		return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time)
+	case dataselect.NamespaceProperty:
+		return dataselect.StdComparableString(self.ObjectMeta.Namespace)
+	default:
+		// if name is not supported then just return a constant dummy value, sort will have no effect.
+		return nil
+	}
+}
+
+func toCells(std []ClusterRoleBinding) []dataselect.DataCell {
+	cells := make([]dataselect.DataCell, len(std))
+	for i := range std {
+		cells[i] = ClusterRoleBindingCell(std[i])
+	}
+	return cells
+}
+
+func fromCells(cells []dataselect.DataCell) []ClusterRoleBinding {
+	std := make([]ClusterRoleBinding, len(cells))
+	for i := range std {
+		std[i] = ClusterRoleBinding(cells[i].(ClusterRoleBindingCell))
+	}
+	return std
+}
diff --git a/src/app/backend/resource/clusterrolebinding/detail.go b/src/app/backend/resource/clusterrolebinding/detail.go
new file mode 100644
index 000000000..4eb5bf81c
--- /dev/null
+++ b/src/app/backend/resource/clusterrolebinding/detail.go
@@ -0,0 +1,54 @@
+// 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 clusterrolebinding
+
+import (
+	rbac "k8s.io/api/rbac/v1"
+	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	k8sClient "k8s.io/client-go/kubernetes"
+)
+
+// ClusterRoleBindingDetail contains ClusterRoleBinding details.
+type ClusterRoleBindingDetail struct {
+	// Extends list item structure.
+	ClusterRoleBinding `json:",inline"`
+
+	Subjects []rbac.Subject `json:"subjects,omitempty" protobuf:"bytes,2,rep,name=subjects"`
+
+	RoleRef rbac.RoleRef `json:"roleRef" protobuf:"bytes,3,opt,name=roleRef"`
+
+	// List of non-critical errors, that occurred during resource retrieval.
+	Errors []error `json:"errors"`
+}
+
+// GetClusterRoleBindingDetail gets ClusterRoleBinding details.
+func GetClusterRoleBindingDetail(client k8sClient.Interface, name string) (*ClusterRoleBindingDetail, error) {
+	rawObject, err := client.RbacV1().ClusterRoleBindings().Get(name, metaV1.GetOptions{})
+	if err != nil {
+		return nil, err
+	}
+
+	cr := toClusterRoleBindingDetail(*rawObject)
+	return &cr, nil
+}
+
+func toClusterRoleBindingDetail(cr rbac.ClusterRoleBinding) ClusterRoleBindingDetail {
+	return ClusterRoleBindingDetail{
+		ClusterRoleBinding: toClusterRoleBinding(cr),
+		Subjects:           cr.Subjects,
+		RoleRef:            cr.RoleRef,
+		Errors:             []error{},
+	}
+}
diff --git a/src/app/backend/resource/clusterrolebinding/list.go b/src/app/backend/resource/clusterrolebinding/list.go
new file mode 100644
index 000000000..db65e1904
--- /dev/null
+++ b/src/app/backend/resource/clusterrolebinding/list.go
@@ -0,0 +1,89 @@
+// 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 clusterrolebinding
+
+import (
+	"log"
+
+	"github.com/kubernetes/dashboard/src/app/backend/api"
+	"github.com/kubernetes/dashboard/src/app/backend/errors"
+	"github.com/kubernetes/dashboard/src/app/backend/resource/common"
+	"github.com/kubernetes/dashboard/src/app/backend/resource/dataselect"
+	rbac "k8s.io/api/rbac/v1"
+	"k8s.io/client-go/kubernetes"
+)
+
+// ClusterRoleBindingList contains a list of clusterRoleBindings in the cluster.
+type ClusterRoleBindingList struct {
+	ListMeta api.ListMeta         `json:"listMeta"`
+	Items    []ClusterRoleBinding `json:"items"`
+
+	// List of non-critical errors, that occurred during resource retrieval.
+	Errors []error `json:"errors"`
+}
+
+// ClusterRoleBindingList is a presentation layer view of Kubernetes clusterRoleBindingList. This means it is clusterRoleBindingList plus additional
+// augmented data we can get from other sources.
+type ClusterRoleBinding struct {
+	ObjectMeta api.ObjectMeta `json:"objectMeta"`
+	TypeMeta   api.TypeMeta   `json:"typeMeta"`
+}
+
+// GetClusterRoleBindingList returns a list of all ClusterRoleBindings in the cluster.
+func GetClusterRoleBindingList(client kubernetes.Interface, dsQuery *dataselect.DataSelectQuery) (*ClusterRoleBindingList, error) {
+	log.Print("Getting list of all clusterRoleBindings in the cluster")
+	channels := &common.ResourceChannels{
+		ClusterRoleBindingList: common.GetClusterRoleBindingListChannel(client, 1),
+	}
+
+	return GetClusterRoleBindingListFromChannels(channels, dsQuery)
+}
+
+// GetClusterRoleBindingListFromChannels returns a list of all ClusterRoleBindings in the cluster
+// reading required resource list once from the channels.
+func GetClusterRoleBindingListFromChannels(channels *common.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*ClusterRoleBindingList, error) {
+	clusterRoleBindings := <-channels.ClusterRoleBindingList.List
+	err := <-channels.ClusterRoleBindingList.Error
+	nonCriticalErrors, criticalError := errors.HandleError(err)
+	if criticalError != nil {
+		return nil, criticalError
+	}
+	clusterRoleBindingList := toClusterRoleBindingList(clusterRoleBindings.Items, nonCriticalErrors, dsQuery)
+	return clusterRoleBindingList, nil
+}
+
+func toClusterRoleBinding(clusterRoleBinding rbac.ClusterRoleBinding) ClusterRoleBinding {
+	return ClusterRoleBinding{
+		ObjectMeta: api.NewObjectMeta(clusterRoleBinding.ObjectMeta),
+		TypeMeta:   api.NewTypeMeta(api.ResourceKindClusterRoleBinding),
+	}
+}
+
+func toClusterRoleBindingList(clusterRoleBindings []rbac.ClusterRoleBinding, nonCriticalErrors []error, dsQuery *dataselect.DataSelectQuery) *ClusterRoleBindingList {
+	result := &ClusterRoleBindingList{
+		ListMeta: api.ListMeta{TotalItems: len(clusterRoleBindings)},
+		Errors:   nonCriticalErrors,
+	}
+
+	items := make([]ClusterRoleBinding, 0)
+	for _, item := range clusterRoleBindings {
+		items = append(items, toClusterRoleBinding(item))
+	}
+
+	clusterRoleBindingCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(items), dsQuery)
+	result.ListMeta = api.ListMeta{TotalItems: filteredTotal}
+	result.Items = fromCells(clusterRoleBindingCells)
+	return result
+}
diff --git a/src/app/backend/resource/common/resourcechannels.go b/src/app/backend/resource/common/resourcechannels.go
index ec7209cce..78bc5781b 100644
--- a/src/app/backend/resource/common/resourcechannels.go
+++ b/src/app/backend/resource/common/resourcechannels.go
@@ -740,14 +740,14 @@ type RoleBindingListChannel struct {
 
 // GetRoleBindingListChannel returns a pair of channels to a RoleBinding list for a namespace and errors that
 // both must be read numReads times.
-func GetRoleBindingListChannel(client client.Interface, numReads int) RoleBindingListChannel {
+func GetRoleBindingListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) RoleBindingListChannel {
 	channel := RoleBindingListChannel{
 		List:  make(chan *rbac.RoleBindingList, numReads),
 		Error: make(chan error, numReads),
 	}
 
 	go func() {
-		list, err := client.RbacV1().RoleBindings("").List(api.ListEverything)
+		list, err := client.RbacV1().RoleBindings(nsQuery.ToRequestParam()).List(api.ListEverything)
 		for i := 0; i < numReads; i++ {
 			channel.List <- list
 			channel.Error <- err
diff --git a/src/app/backend/resource/role/detail.go b/src/app/backend/resource/role/detail.go
index 69433bb7b..9d5bbac5f 100644
--- a/src/app/backend/resource/role/detail.go
+++ b/src/app/backend/resource/role/detail.go
@@ -20,7 +20,7 @@ import (
 	k8sClient "k8s.io/client-go/kubernetes"
 )
 
-// RoleDetail contains Cron Job details.
+// RoleDetail contains Role details.
 type RoleDetail struct {
 	// Extends list item structure.
 	Role `json:",inline"`
diff --git a/src/app/backend/resource/role/list.go b/src/app/backend/resource/role/list.go
index e98e7f5f6..0473c6d0a 100644
--- a/src/app/backend/resource/role/list.go
+++ b/src/app/backend/resource/role/list.go
@@ -60,8 +60,8 @@ func GetRoleListFromChannels(channels *common.ResourceChannels, dsQuery *datasel
 	if criticalError != nil {
 		return nil, criticalError
 	}
-	deploymentList := toRoleList(roles.Items, nonCriticalErrors, dsQuery)
-	return deploymentList, nil
+	roleList := toRoleList(roles.Items, nonCriticalErrors, dsQuery)
+	return roleList, nil
 }
 
 func toRole(role rbac.Role) Role {
diff --git a/src/app/backend/resource/rolebinding/common.go b/src/app/backend/resource/rolebinding/common.go
new file mode 100644
index 000000000..9fa92d05b
--- /dev/null
+++ b/src/app/backend/resource/rolebinding/common.go
@@ -0,0 +1,53 @@
+// 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 rolebinding
+
+import (
+	"github.com/kubernetes/dashboard/src/app/backend/resource/dataselect"
+)
+
+// The code below allows to perform complex data section on []RoleBinding
+
+type RoleBindingCell RoleBinding
+
+func (self RoleBindingCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue {
+	switch name {
+	case dataselect.NameProperty:
+		return dataselect.StdComparableString(self.ObjectMeta.Name)
+	case dataselect.CreationTimestampProperty:
+		return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time)
+	case dataselect.NamespaceProperty:
+		return dataselect.StdComparableString(self.ObjectMeta.Namespace)
+	default:
+		// if name is not supported then just return a constant dummy value, sort will have no effect.
+		return nil
+	}
+}
+
+func toCells(std []RoleBinding) []dataselect.DataCell {
+	cells := make([]dataselect.DataCell, len(std))
+	for i := range std {
+		cells[i] = RoleBindingCell(std[i])
+	}
+	return cells
+}
+
+func fromCells(cells []dataselect.DataCell) []RoleBinding {
+	std := make([]RoleBinding, len(cells))
+	for i := range std {
+		std[i] = RoleBinding(cells[i].(RoleBindingCell))
+	}
+	return std
+}
diff --git a/src/app/backend/resource/rolebinding/detail.go b/src/app/backend/resource/rolebinding/detail.go
new file mode 100644
index 000000000..ae534cad2
--- /dev/null
+++ b/src/app/backend/resource/rolebinding/detail.go
@@ -0,0 +1,54 @@
+// 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 rolebinding
+
+import (
+	rbac "k8s.io/api/rbac/v1"
+	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	k8sClient "k8s.io/client-go/kubernetes"
+)
+
+// RoleBindingDetail contains RoleBinding details.
+type RoleBindingDetail struct {
+	// Extends list item structure.
+	RoleBinding `json:",inline"`
+
+	Subjects []rbac.Subject `json:"subjects,omitempty" protobuf:"bytes,2,rep,name=subjects"`
+
+	RoleRef rbac.RoleRef `json:"roleRef" protobuf:"bytes,3,opt,name=roleRef"`
+
+	// List of non-critical errors, that occurred during resource retrieval.
+	Errors []error `json:"errors"`
+}
+
+// GetRoleBindingDetail gets RoleBinding details.
+func GetRoleBindingDetail(client k8sClient.Interface, namespace, name string) (*RoleBindingDetail, error) {
+	rawObject, err := client.RbacV1().RoleBindings(namespace).Get(name, metaV1.GetOptions{})
+	if err != nil {
+		return nil, err
+	}
+
+	cr := toRoleBindingDetail(*rawObject)
+	return &cr, nil
+}
+
+func toRoleBindingDetail(cr rbac.RoleBinding) RoleBindingDetail {
+	return RoleBindingDetail{
+		RoleBinding: toRoleBinding(cr),
+		Subjects:    cr.Subjects,
+		RoleRef:     cr.RoleRef,
+		Errors:      []error{},
+	}
+}
diff --git a/src/app/backend/resource/rolebinding/list.go b/src/app/backend/resource/rolebinding/list.go
new file mode 100644
index 000000000..729dadb67
--- /dev/null
+++ b/src/app/backend/resource/rolebinding/list.go
@@ -0,0 +1,89 @@
+// 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 rolebinding
+
+import (
+	"log"
+
+	"github.com/kubernetes/dashboard/src/app/backend/api"
+	"github.com/kubernetes/dashboard/src/app/backend/errors"
+	"github.com/kubernetes/dashboard/src/app/backend/resource/common"
+	"github.com/kubernetes/dashboard/src/app/backend/resource/dataselect"
+	rbac "k8s.io/api/rbac/v1"
+	"k8s.io/client-go/kubernetes"
+)
+
+// RoleBindingList contains a list of roleBindings in the cluster.
+type RoleBindingList struct {
+	ListMeta api.ListMeta  `json:"listMeta"`
+	Items    []RoleBinding `json:"items"`
+
+	// List of non-critical errors, that occurred during resource retrieval.
+	Errors []error `json:"errors"`
+}
+
+// RoleBinding is a presentation layer view of Kubernetes roleBinding. This means it is roleBinding plus additional
+// augmented data we can get from other sources.
+type RoleBinding struct {
+	ObjectMeta api.ObjectMeta `json:"objectMeta"`
+	TypeMeta   api.TypeMeta   `json:"typeMeta"`
+}
+
+// GetRoleBindingList returns a list of all RoleBindings in the cluster.
+func GetRoleBindingList(client kubernetes.Interface, nsQuery *common.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*RoleBindingList, error) {
+	log.Print("Getting list of all roleBindings in the cluster")
+	channels := &common.ResourceChannels{
+		RoleBindingList: common.GetRoleBindingListChannel(client, nsQuery, 1),
+	}
+
+	return GetRoleBindingListFromChannels(channels, dsQuery)
+}
+
+// GetRoleBindingListFromChannels returns a list of all RoleBindings in the cluster
+// reading required resource list once from the channels.
+func GetRoleBindingListFromChannels(channels *common.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*RoleBindingList, error) {
+	roleBindings := <-channels.RoleBindingList.List
+	err := <-channels.RoleBindingList.Error
+	nonCriticalErrors, criticalError := errors.HandleError(err)
+	if criticalError != nil {
+		return nil, criticalError
+	}
+	roleBindingList := toRoleBindingList(roleBindings.Items, nonCriticalErrors, dsQuery)
+	return roleBindingList, nil
+}
+
+func toRoleBinding(roleBinding rbac.RoleBinding) RoleBinding {
+	return RoleBinding{
+		ObjectMeta: api.NewObjectMeta(roleBinding.ObjectMeta),
+		TypeMeta:   api.NewTypeMeta(api.ResourceKindRoleBinding),
+	}
+}
+
+func toRoleBindingList(roleBindings []rbac.RoleBinding, nonCriticalErrors []error, dsQuery *dataselect.DataSelectQuery) *RoleBindingList {
+	result := &RoleBindingList{
+		ListMeta: api.ListMeta{TotalItems: len(roleBindings)},
+		Errors:   nonCriticalErrors,
+	}
+
+	items := make([]RoleBinding, 0)
+	for _, item := range roleBindings {
+		items = append(items, toRoleBinding(item))
+	}
+
+	roleBindingCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(items), dsQuery)
+	result.ListMeta = api.ListMeta{TotalItems: filteredTotal}
+	result.Items = fromCells(roleBindingCells)
+	return result
+}


Test patch:
diff --git a/src/app/backend/integration/metric/heapster/client_test.go b/src/app/backend/integration/metric/heapster/client_test.go
index 4618919a4..a89c89ae1 100644
--- a/src/app/backend/integration/metric/heapster/client_test.go
+++ b/src/app/backend/integration/metric/heapster/client_test.go
@@ -295,16 +295,16 @@ func TestDownloadMetric(t *testing.T) {
 			t.Errorf("Test Case: %s. Failed to get metrics - %s", testCase.Info, err)
 			return
 		}
-		num_req := fakeHeapsterClient.GetNumberOfRequestsMade()
+		numReq := fakeHeapsterClient.GetNumberOfRequestsMade()
 
 		if !reflect.DeepEqual(metrics[0].DataPoints, testCase.ExpectedDataPoints) {
 			t.Errorf("Test Case: %s. Received incorrect data points. Got %v, expected %v.",
 				testCase.Info, metrics[0].DataPoints, testCase.ExpectedDataPoints)
 		}
 
-		if testCase.ExpectedNumRequests != num_req {
+		if testCase.ExpectedNumRequests != numReq {
 			t.Errorf("Test Case: %s. Selector performed unexpected number of requests to the heapster server. Performed %d, expected %d",
-				testCase.Info, num_req, testCase.ExpectedNumRequests)
+				testCase.Info, numReq, testCase.ExpectedNumRequests)
 		}
 	}
 }
@@ -433,10 +433,10 @@ func TestDownloadMetrics(t *testing.T) {
 			t.Errorf("Test Case: %s. Received incorrect data points. Got %v, expected %v.",
 				testCase.Info, receivedDataPoints, testCase.ExpectedDataPoints)
 		}
-		num_req := fakeHeapsterClient.GetNumberOfRequestsMade()
-		if testCase.ExpectedNumRequests != num_req {
+		numReq := fakeHeapsterClient.GetNumberOfRequestsMade()
+		if testCase.ExpectedNumRequests != numReq {
 			t.Errorf("Test Case: %s. Selector performed unexpected number of requests to the heapster server. Performed %d, expected %d",
-				testCase.Info, num_req, testCase.ExpectedNumRequests)
+				testCase.Info, numReq, testCase.ExpectedNumRequests)
 		}
 	}
 }
diff --git a/src/app/backend/integration/metric/sidecar/client_test.go b/src/app/backend/integration/metric/sidecar/client_test.go
index 45981e5a2..eda26f4ea 100644
--- a/src/app/backend/integration/metric/sidecar/client_test.go
+++ b/src/app/backend/integration/metric/sidecar/client_test.go
@@ -297,16 +297,16 @@ func TestDownloadMetric(t *testing.T) {
 			t.Errorf("Test Case: %s. Failed to get metrics - %s", testCase.Info, err)
 			return
 		}
-		num_req := fakeSidecarClient.GetNumberOfRequestsMade()
+		numReq := fakeSidecarClient.GetNumberOfRequestsMade()
 
 		if !reflect.DeepEqual(metrics[0].DataPoints, testCase.ExpectedDataPoints) {
 			t.Errorf("Test Case: %s. Received incorrect data points. Got %v, expected %v.",
 				testCase.Info, metrics[0].DataPoints, testCase.ExpectedDataPoints)
 		}
 
-		if testCase.ExpectedNumRequests != num_req {
+		if testCase.ExpectedNumRequests != numReq {
 			t.Errorf("Test Case: %s. Selector performed unexpected number of requests to the sidecar server. Performed %d, expected %d",
-				testCase.Info, num_req, testCase.ExpectedNumRequests)
+				testCase.Info, numReq, testCase.ExpectedNumRequests)
 		}
 	}
 }
@@ -435,10 +435,10 @@ func TestDownloadMetrics(t *testing.T) {
 			t.Errorf("Test Case: %s. Received incorrect data points. Got %v, expected %v.",
 				testCase.Info, receivedDataPoints, testCase.ExpectedDataPoints)
 		}
-		num_req := fakeSidecarClient.GetNumberOfRequestsMade()
-		if testCase.ExpectedNumRequests != num_req {
+		numReq := fakeSidecarClient.GetNumberOfRequestsMade()
+		if testCase.ExpectedNumRequests != numReq {
 			t.Errorf("Test Case: %s. Selector performed unexpected number of requests to the sidecar server. Performed %d, expected %d",
-				testCase.Info, num_req, testCase.ExpectedNumRequests)
+				testCase.Info, numReq, testCase.ExpectedNumRequests)
 		}
 	}
 }
diff --git a/src/app/backend/resource/clusterrolebinding/list_test.go b/src/app/backend/resource/clusterrolebinding/list_test.go
new file mode 100644
index 000000000..b51cdb150
--- /dev/null
+++ b/src/app/backend/resource/clusterrolebinding/list_test.go
@@ -0,0 +1,65 @@
+// 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 clusterrolebinding
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/kubernetes/dashboard/src/app/backend/api"
+	"github.com/kubernetes/dashboard/src/app/backend/resource/dataselect"
+	rbac "k8s.io/api/rbac/v1"
+	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestToRbacClusterRoleBindingLists(t *testing.T) {
+	cases := []struct {
+		ClusterRoleBindings []rbac.ClusterRoleBinding
+		expected            *ClusterRoleBindingList
+	}{
+		{nil, &ClusterRoleBindingList{Items: []ClusterRoleBinding{}}},
+		{
+			[]rbac.ClusterRoleBinding{
+				{
+					ObjectMeta: metaV1.ObjectMeta{Name: "clusterRoleBinding"},
+					Subjects: []rbac.Subject{{
+						Kind:     "User",
+						Name:     "dashboard",
+						APIGroup: "rbac.authorization.k8s.io",
+					}},
+					RoleRef: rbac.RoleRef{
+						APIGroup: "Role",
+						Kind:     "pod-reader",
+						Name:     "rbac.authorization.k8s.io",
+					},
+				},
+			},
+			&ClusterRoleBindingList{
+				ListMeta: api.ListMeta{TotalItems: 1},
+				Items: []ClusterRoleBinding{{
+					ObjectMeta: api.ObjectMeta{Name: "clusterRoleBinding", Namespace: ""},
+					TypeMeta:   api.TypeMeta{Kind: api.ResourceKindClusterRoleBinding},
+				}},
+			},
+		},
+	}
+	for _, c := range cases {
+		actual := toClusterRoleBindingList(c.ClusterRoleBindings, nil, dataselect.NoDataSelect)
+		if !reflect.DeepEqual(actual, c.expected) {
+			t.Errorf("toRbacRoleLists(%#v) == \n%#v\nexpected \n%#v\n",
+				c.ClusterRoleBindings, actual, c.expected)
+		}
+	}
+}
diff --git a/src/app/backend/resource/rolebinding/list_test.go b/src/app/backend/resource/rolebinding/list_test.go
new file mode 100644
index 000000000..daeb4c4f9
--- /dev/null
+++ b/src/app/backend/resource/rolebinding/list_test.go
@@ -0,0 +1,65 @@
+// 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 rolebinding
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/kubernetes/dashboard/src/app/backend/api"
+	"github.com/kubernetes/dashboard/src/app/backend/resource/dataselect"
+	rbac "k8s.io/api/rbac/v1"
+	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestToRbacRoleBindingLists(t *testing.T) {
+	cases := []struct {
+		RoleBindings []rbac.RoleBinding
+		expected     *RoleBindingList
+	}{
+		{nil, &RoleBindingList{Items: []RoleBinding{}}},
+		{
+			[]rbac.RoleBinding{
+				{
+					ObjectMeta: metaV1.ObjectMeta{Name: "rolebinding"},
+					Subjects: []rbac.Subject{{
+						Kind:     "User",
+						Name:     "dashboard",
+						APIGroup: "rbac.authorization.k8s.io",
+					}},
+					RoleRef: rbac.RoleRef{
+						APIGroup: "Role",
+						Kind:     "pod-reader",
+						Name:     "rbac.authorization.k8s.io",
+					},
+				},
+			},
+			&RoleBindingList{
+				ListMeta: api.ListMeta{TotalItems: 1},
+				Items: []RoleBinding{{
+					ObjectMeta: api.ObjectMeta{Name: "rolebinding", Namespace: ""},
+					TypeMeta:   api.TypeMeta{Kind: api.ResourceKindRoleBinding},
+				}},
+			},
+		},
+	}
+	for _, c := range cases {
+		actual := toRoleBindingList(c.RoleBindings, nil, dataselect.NoDataSelect)
+		if !reflect.DeepEqual(actual, c.expected) {
+			t.Errorf("toRbacRoleLists(%#v) == \n%#v\nexpected \n%#v\n",
+				c.RoleBindings, actual, c.expected)
+		}
+	}
+}