Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRD Support - Backend #3843

Merged
merged 24 commits into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
57baba9
Installed k8s.io/apiextensions-apiserver
eloyekunle May 30, 2019
2cb7246
implement crd list - GetCustomResourceDefinitionList
eloyekunle May 31, 2019
07d6a61
add method to fetch API extensions client to client manager
eloyekunle Jun 3, 2019
c84b4e7
implement verber for custom resource definitions
eloyekunle Jun 3, 2019
61b26cb
update fakeClient with new client manager methods
eloyekunle Jun 3, 2019
d856fca
add tests for APIExtensionsClient
eloyekunle Jun 3, 2019
761f8f5
add events source file
eloyekunle Jun 3, 2019
3229d5c
add events test source file
eloyekunle Jun 3, 2019
57fd027
implement objects list endpoint
eloyekunle Jun 5, 2019
e9278c6
replace '.Raw' with '.Into' in objects list
eloyekunle Jun 5, 2019
367352c
implement getCustomResourceObjectDetail
eloyekunle Jun 6, 2019
ae8c43c
replace kdErrors with errors
eloyekunle Jun 6, 2019
2608687
fix conflicts
eloyekunle Jun 6, 2019
f39e0e0
implement get crd detail
eloyekunle Jun 8, 2019
3b84eb9
implement get events for custom resource object
eloyekunle Jun 8, 2019
47f091a
add version to CustomResourceDefinition type
eloyekunle Jun 8, 2019
dbe02ef
add (failing) test for detail fetch
eloyekunle Jun 8, 2019
15b412b
add tests for cr objects events
eloyekunle Jun 9, 2019
d9a09cb
remove unused import
eloyekunle Jun 20, 2019
e9440f6
update dependencies
eloyekunle Jul 1, 2019
3f061f4
rename customresourcedefinition to crd
eloyekunle Jul 1, 2019
b1a3934
removed vendor dir
eloyekunle Jul 2, 2019
792ae45
update deps, remove object tests
eloyekunle Jul 2, 2019
2bd40ec
order imports
eloyekunle Jul 2, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 6 additions & 18 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,28 @@ require (
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
github.com/emicklei/go-restful v2.9.6+incompatible
github.com/evanphx/json-patch v4.1.0+incompatible // indirect
github.com/gogo/protobuf v1.2.0 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
github.com/googleapis/gnostic v0.2.0 // indirect
github.com/gorilla/websocket v1.4.0 // indirect
github.com/igm/sockjs-go v2.0.1+incompatible // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/json-iterator/go v1.1.5 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/onsi/ginkgo v1.8.0 // indirect
github.com/onsi/gomega v1.5.0 // indirect
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
github.com/prometheus/client_golang v0.9.2
github.com/prometheus/common v0.0.0-20181218105931-67670fe90761 // indirect
github.com/prometheus/procfs v0.0.0-20190102135031-14fa7590c24d // indirect
github.com/spf13/pflag v1.0.3
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc // indirect
golang.org/x/net v0.0.0-20181220203305-927f97764cc3
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 // indirect
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598 // indirect
golang.org/x/text v0.3.0
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
golang.org/x/text v0.3.2
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect
google.golang.org/appengine v1.4.0 // indirect
gopkg.in/igm/sockjs-go.v2 v2.0.0
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/square/go-jose.v2 v2.2.2
gopkg.in/yaml.v2 v2.2.2
k8s.io/api v0.0.0-20190313235455-40a48860b5ab
k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1
k8s.io/api v0.0.0-20190627205229-acea843d18eb
k8s.io/apiextensions-apiserver v0.0.0-20190629010545-2d36bfd0ff86
k8s.io/apimachinery v0.0.0-20190629005116-7ae370969693
k8s.io/client-go v11.0.0+incompatible
k8s.io/heapster v1.5.4
k8s.io/kube-openapi v0.0.0-20181114233023-0317810137be // indirect
k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a // indirect
sigs.k8s.io/yaml v1.1.0 // indirect
)
222 changes: 200 additions & 22 deletions go.sum

Large diffs are not rendered by default.

111 changes: 57 additions & 54 deletions src/app/backend/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,29 +110,30 @@ type ResourceKind string

// List of all resource kinds supported by the UI.
const (
ResourceKindConfigMap = "configmap"
ResourceKindDaemonSet = "daemonset"
ResourceKindDeployment = "deployment"
ResourceKindEvent = "event"
ResourceKindHorizontalPodAutoscaler = "horizontalpodautoscaler"
ResourceKindIngress = "ingress"
ResourceKindJob = "job"
ResourceKindCronJob = "cronjob"
ResourceKindLimitRange = "limitrange"
ResourceKindNamespace = "namespace"
ResourceKindNode = "node"
ResourceKindPersistentVolumeClaim = "persistentvolumeclaim"
ResourceKindPersistentVolume = "persistentvolume"
ResourceKindPod = "pod"
ResourceKindReplicaSet = "replicaset"
ResourceKindReplicationController = "replicationcontroller"
ResourceKindResourceQuota = "resourcequota"
ResourceKindSecret = "secret"
ResourceKindService = "service"
ResourceKindStatefulSet = "statefulset"
ResourceKindStorageClass = "storageclass"
ResourceKindClusterRole = "clusterrole"
ResourceKindEndpoint = "endpoint"
ResourceKindConfigMap = "configmap"
ResourceKindDaemonSet = "daemonset"
ResourceKindDeployment = "deployment"
ResourceKindEvent = "event"
ResourceKindHorizontalPodAutoscaler = "horizontalpodautoscaler"
ResourceKindIngress = "ingress"
ResourceKindJob = "job"
ResourceKindCronJob = "cronjob"
ResourceKindLimitRange = "limitrange"
ResourceKindNamespace = "namespace"
ResourceKindNode = "node"
ResourceKindPersistentVolumeClaim = "persistentvolumeclaim"
ResourceKindPersistentVolume = "persistentvolume"
ResourceKindCustomResourceDefinition = "customresourcedefinition"
ResourceKindPod = "pod"
ResourceKindReplicaSet = "replicaset"
ResourceKindReplicationController = "replicationcontroller"
ResourceKindResourceQuota = "resourcequota"
ResourceKindSecret = "secret"
ResourceKindService = "service"
ResourceKindStatefulSet = "statefulset"
ResourceKindStorageClass = "storageclass"
ResourceKindClusterRole = "clusterrole"
ResourceKindEndpoint = "endpoint"
)

// ClientType represents type of client that is used to perform generic operations on resources.
Expand All @@ -142,14 +143,15 @@ type ClientType string

// List of client types supported by the UI.
const (
ClientTypeDefault = "restclient"
ClientTypeExtensionClient = "extensionclient"
ClientTypeAppsClient = "appsclient"
ClientTypeBatchClient = "batchclient"
ClientTypeBetaBatchClient = "betabatchclient"
ClientTypeAutoscalingClient = "autoscalingclient"
ClientTypeStorageClient = "storageclient"
ClientTypeRbacClient = "rbacclient"
ClientTypeDefault = "restclient"
ClientTypeExtensionClient = "extensionclient"
ClientTypeAppsClient = "appsclient"
ClientTypeBatchClient = "batchclient"
ClientTypeBetaBatchClient = "betabatchclient"
ClientTypeAutoscalingClient = "autoscalingclient"
ClientTypeStorageClient = "storageclient"
ClientTypeRbacClient = "rbacclient"
ClientTypeAPIExtensionsClient = "apiextensionsclient"
)

// Mapping from resource kind to K8s apiserver API path. This is mostly pluralization, because
Expand All @@ -163,29 +165,30 @@ var KindToAPIMapping = map[string]struct {
// Is this object global scoped (not below a namespace).
Namespaced bool
}{
ResourceKindConfigMap: {"configmaps", ClientTypeDefault, true},
ResourceKindDaemonSet: {"daemonsets", ClientTypeExtensionClient, true},
ResourceKindDeployment: {"deployments", ClientTypeExtensionClient, true},
ResourceKindEvent: {"events", ClientTypeDefault, true},
ResourceKindHorizontalPodAutoscaler: {"horizontalpodautoscalers", ClientTypeAutoscalingClient, true},
ResourceKindIngress: {"ingresses", ClientTypeExtensionClient, true},
ResourceKindJob: {"jobs", ClientTypeBatchClient, true},
ResourceKindCronJob: {"cronjobs", ClientTypeBetaBatchClient, true},
ResourceKindLimitRange: {"limitrange", ClientTypeDefault, true},
ResourceKindNamespace: {"namespaces", ClientTypeDefault, false},
ResourceKindNode: {"nodes", ClientTypeDefault, false},
ResourceKindPersistentVolumeClaim: {"persistentvolumeclaims", ClientTypeDefault, true},
ResourceKindPersistentVolume: {"persistentvolumes", ClientTypeDefault, false},
ResourceKindPod: {"pods", ClientTypeDefault, true},
ResourceKindReplicaSet: {"replicasets", ClientTypeExtensionClient, true},
ResourceKindReplicationController: {"replicationcontrollers", ClientTypeDefault, true},
ResourceKindResourceQuota: {"resourcequotas", ClientTypeDefault, true},
ResourceKindSecret: {"secrets", ClientTypeDefault, true},
ResourceKindService: {"services", ClientTypeDefault, true},
ResourceKindStatefulSet: {"statefulsets", ClientTypeAppsClient, true},
ResourceKindStorageClass: {"storageclasses", ClientTypeStorageClient, false},
ResourceKindEndpoint: {"endpoints", ClientTypeDefault, true},
ResourceKindClusterRole: {"clusterroles", ClientTypeRbacClient, false},
ResourceKindConfigMap: {"configmaps", ClientTypeDefault, true},
ResourceKindDaemonSet: {"daemonsets", ClientTypeExtensionClient, true},
ResourceKindDeployment: {"deployments", ClientTypeExtensionClient, true},
ResourceKindEvent: {"events", ClientTypeDefault, true},
ResourceKindHorizontalPodAutoscaler: {"horizontalpodautoscalers", ClientTypeAutoscalingClient, true},
ResourceKindIngress: {"ingresses", ClientTypeExtensionClient, true},
ResourceKindJob: {"jobs", ClientTypeBatchClient, true},
ResourceKindCronJob: {"cronjobs", ClientTypeBetaBatchClient, true},
ResourceKindLimitRange: {"limitrange", ClientTypeDefault, true},
ResourceKindNamespace: {"namespaces", ClientTypeDefault, false},
ResourceKindNode: {"nodes", ClientTypeDefault, false},
ResourceKindPersistentVolumeClaim: {"persistentvolumeclaims", ClientTypeDefault, true},
ResourceKindPersistentVolume: {"persistentvolumes", ClientTypeDefault, false},
ResourceKindCustomResourceDefinition: {"customresourcedefinitions", ClientTypeAPIExtensionsClient, false},
ResourceKindPod: {"pods", ClientTypeDefault, true},
ResourceKindReplicaSet: {"replicasets", ClientTypeExtensionClient, true},
ResourceKindReplicationController: {"replicationcontrollers", ClientTypeDefault, true},
ResourceKindResourceQuota: {"resourcequotas", ClientTypeDefault, true},
ResourceKindSecret: {"secrets", ClientTypeDefault, true},
ResourceKindService: {"services", ClientTypeDefault, true},
ResourceKindStatefulSet: {"statefulsets", ClientTypeAppsClient, true},
ResourceKindStorageClass: {"storageclasses", ClientTypeStorageClient, false},
ResourceKindEndpoint: {"endpoints", ClientTypeDefault, true},
ResourceKindClusterRole: {"clusterroles", ClientTypeRbacClient, false},
}

// IsSelectorMatching returns true when an object with the given selector targets the same
Expand Down
11 changes: 10 additions & 1 deletion src/app/backend/auth/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/kubernetes/dashboard/src/app/backend/errors"

v1 "k8s.io/api/authorization/v1"
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
Expand All @@ -46,10 +47,18 @@ func (self *fakeClientManager) Client(req *restful.Request) (kubernetes.Interfac
return nil, nil
}

func (self *fakeClientManager) APIExtensionsClient(req *restful.Request) (apiextensionsclientset.Interface, error) {
return nil, nil
}

func (self *fakeClientManager) InsecureClient() kubernetes.Interface {
return nil
}

func (self *fakeClientManager) InsecureAPIExtensionsClient() apiextensionsclientset.Interface {
return nil
}

func (self *fakeClientManager) SetTokenManager(manager authApi.TokenManager) {}

func (self *fakeClientManager) Config(req *restful.Request) (*rest.Config, error) {
Expand All @@ -70,7 +79,7 @@ func (self *fakeClientManager) HasAccess(authInfo api.AuthInfo) error {

func (self *fakeClientManager) VerberClient(req *restful.Request) (clientapi.ResourceVerber, error) {
return client.NewResourceVerber(nil, nil, nil, nil, nil,
nil, nil, nil), nil
nil, nil, nil, nil), nil
}

func (self *fakeClientManager) CanI(req *restful.Request, ssar *v1.SelfSubjectAccessReview) bool {
Expand Down
5 changes: 4 additions & 1 deletion src/app/backend/client/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
package api

import (
restful "github.com/emicklei/go-restful"
"github.com/emicklei/go-restful"
authApi "github.com/kubernetes/dashboard/src/app/backend/auth/api"
v1 "k8s.io/api/authorization/v1"
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
Expand All @@ -38,6 +39,8 @@ const (
type ClientManager interface {
Client(req *restful.Request) (kubernetes.Interface, error)
InsecureClient() kubernetes.Interface
APIExtensionsClient(req *restful.Request) (apiextensionsclientset.Interface, error)
InsecureAPIExtensionsClient() apiextensionsclientset.Interface
CanI(req *restful.Request, ssar *v1.SelfSubjectAccessReview) bool
Config(req *restful.Request) (*rest.Config, error)
ClientCmdConfig(req *restful.Request) (clientcmd.ClientConfig, error)
Expand Down
72 changes: 62 additions & 10 deletions src/app/backend/client/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import (
"log"
"strings"

restful "github.com/emicklei/go-restful"
"github.com/emicklei/go-restful"
v1 "k8s.io/api/authorization/v1"
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
Expand Down Expand Up @@ -67,6 +68,9 @@ type clientManager struct {
inClusterConfig *rest.Config
// Responsible for decrypting tokens coming in request header. Used for authentication.
tokenManager authApi.TokenManager
// API Extensions client created without providing auth info. It uses permissions granted to
// service account used by dashboard or kubeconfig file if it was passed during dashboard init.
insecureAPIExtensionsClient apiextensionsclientset.Interface
// Kubernetes client created without providing auth info. It uses permissions granted to
// service account used by dashboard or kubeconfig file if it was passed during dashboard init.
insecureClient kubernetes.Interface
Expand All @@ -91,6 +95,21 @@ func (self *clientManager) Client(req *restful.Request) (kubernetes.Interface, e
return self.InsecureClient(), nil
}

// APIExtensionsClient returns an API Extensions client. In case dashboard login is enabled and
// option to skip login page is disabled only secure client will be returned, otherwise insecure
// client will be used.
func (self *clientManager) APIExtensionsClient(req *restful.Request) (apiextensionsclientset.Interface, error) {
if req == nil {
return nil, errors.NewBadRequest("request can not be nil!")
}

if self.isSecureModeEnabled(req) {
return self.secureAPIExtensionsClient(req)
}

return self.InsecureAPIExtensionsClient(), nil
}

// Config returns a rest config. In case dashboard login is enabled and option to skip
// login page is disabled only secure config will be returned, otherwise insecure config will be
// used.
Expand All @@ -113,6 +132,13 @@ func (self *clientManager) InsecureClient() kubernetes.Interface {
return self.insecureClient
}

// InsecureAPIExtensionsClient returns API Extensions client that was created without providing
// auth info. It uses permissions granted to service account used by dashboard or kubeconfig file
// if it was passed during dashboard init.
func (self *clientManager) InsecureAPIExtensionsClient() apiextensionsclientset.Interface {
return self.insecureAPIExtensionsClient
}

// InsecureConfig returns kubernetes client config that used privileges of dashboard service account
// or kubeconfig file if it was passed during dashboard init.
func (self *clientManager) InsecureConfig() *rest.Config {
Expand Down Expand Up @@ -188,15 +214,20 @@ func (self *clientManager) HasAccess(authInfo api.AuthInfo) error {

// VerberClient returns new verber client based on authentication information extracted from request
func (self *clientManager) VerberClient(req *restful.Request) (clientapi.ResourceVerber, error) {
client, err := self.Client(req)
k8sClient, err := self.Client(req)
if err != nil {
return nil, err
}

apiextensionsclient, err := self.APIExtensionsClient(req)
if err != nil {
return nil, err
}

return NewResourceVerber(client.CoreV1().RESTClient(),
client.ExtensionsV1beta1().RESTClient(), client.AppsV1().RESTClient(),
client.BatchV1().RESTClient(), client.BatchV1beta1().RESTClient(), client.AutoscalingV1().RESTClient(),
client.StorageV1().RESTClient(), client.RbacV1().RESTClient()), nil
return NewResourceVerber(k8sClient.CoreV1().RESTClient(),
k8sClient.ExtensionsV1beta1().RESTClient(), k8sClient.AppsV1().RESTClient(),
k8sClient.BatchV1().RESTClient(), k8sClient.BatchV1beta1().RESTClient(), k8sClient.AutoscalingV1().RESTClient(),
k8sClient.StorageV1().RESTClient(), k8sClient.RbacV1().RESTClient(), apiextensionsclient.ApiextensionsV1beta1().RESTClient()), nil
}

// SetTokenManager sets the token manager that will be used for token decryption.
Expand Down Expand Up @@ -313,6 +344,20 @@ func (self *clientManager) secureClient(req *restful.Request) (kubernetes.Interf
return client, nil
}

func (self *clientManager) secureAPIExtensionsClient(req *restful.Request) (apiextensionsclientset.Interface, error) {
cfg, err := self.secureConfig(req)
if err != nil {
return nil, err
}

client, err := apiextensionsclientset.NewForConfig(cfg)
if err != nil {
return nil, err
}

return client, nil
}

func (self *clientManager) secureConfig(req *restful.Request) (*rest.Config, error) {
cmdConfig, err := self.ClientCmdConfig(req)
if err != nil {
Expand All @@ -331,7 +376,7 @@ func (self *clientManager) secureConfig(req *restful.Request) (*rest.Config, err
// Initializes client manager
func (self *clientManager) init() {
self.initInClusterConfig()
self.initInsecureClient()
self.initInsecureClients()
self.initCSRFKey()
}

Expand Down Expand Up @@ -367,14 +412,21 @@ func (self *clientManager) initCSRFKey() {
self.csrfKey = csrf.NewCsrfTokenManager(self.insecureClient).Token()
}

func (self *clientManager) initInsecureClient() {
// Initializes Kubernetes client and API extensions client.
func (self *clientManager) initInsecureClients() {
self.initInsecureConfig()
client, err := kubernetes.NewForConfig(self.insecureConfig)
k8sClient, err := kubernetes.NewForConfig(self.insecureConfig)
if err != nil {
panic(err)
}

apiextensionsclient, err := apiextensionsclientset.NewForConfig(self.insecureConfig)
if err != nil {
panic(err)
}

self.insecureClient = client
self.insecureClient = k8sClient
self.insecureAPIExtensionsClient = apiextensionsclient
}

func (self *clientManager) initInsecureConfig() {
Expand Down
Loading