From a3d3c8e42785fecb60e1541e537ab1f3c8aa5a00 Mon Sep 17 00:00:00 2001 From: hongming Date: Fri, 10 Apr 2020 10:16:26 +0800 Subject: [PATCH] update Signed-off-by: hongming --- cmd/controller-manager/app/server.go | 16 +- .../crds/iam.kubesphere.io_policyrules.yaml | 11 +- .../crds/iam.kubesphere.io_rolebindings.yaml | 17 +- config/crds/iam.kubesphere.io_roles.yaml | 24 +- config/samples/iam_v1alpha2_policyrule.yaml | 54 +++- config/samples/iam_v1alpha2_role.yaml | 29 +- config/samples/iam_v1alpha2_rolebinding.yaml | 14 +- go.sum | 1 + pkg/apis/iam/v1alpha2/types.go | 49 +++- .../iam/v1alpha2/zz_generated.deepcopy.go | 62 +++-- pkg/apiserver/apiserver.go | 10 +- .../authorization/authorizerfactory/opa.go | 93 ++++--- .../authorizerfactory/opa_test.go | 205 +++++++++++++- pkg/apiserver/query/field.go | 2 - .../iam/v1alpha2/fake/fake_iam_client.go | 12 + .../iam/v1alpha2/fake/fake_policyrule.go | 120 ++++++++ .../typed/iam/v1alpha2/fake/fake_role.go | 120 ++++++++ .../iam/v1alpha2/fake/fake_rolebinding.go | 120 ++++++++ .../typed/iam/v1alpha2/generated_expansion.go | 6 + .../typed/iam/v1alpha2/iam_client.go | 15 + .../typed/iam/v1alpha2/policyrule.go | 164 +++++++++++ .../versioned/typed/iam/v1alpha2/role.go | 164 +++++++++++ .../typed/iam/v1alpha2/rolebinding.go | 164 +++++++++++ .../informers/externalversions/generic.go | 6 + .../iam/v1alpha2/interface.go | 21 ++ .../iam/v1alpha2/policyrule.go | 88 ++++++ .../externalversions/iam/v1alpha2/role.go | 88 ++++++ .../iam/v1alpha2/rolebinding.go | 88 ++++++ .../iam/v1alpha2/expansion_generated.go | 12 + pkg/client/listers/iam/v1alpha2/policyrule.go | 65 +++++ pkg/client/listers/iam/v1alpha2/role.go | 65 +++++ .../listers/iam/v1alpha2/rolebinding.go | 65 +++++ pkg/controller/user/user_webhook.go | 13 +- pkg/kapis/iam/v1alpha2/handler.go | 67 ++++- pkg/kapis/iam/v1alpha2/register.go | 46 ++- pkg/kapis/tenant/v1alpha2/handler.go | 212 ++------------ pkg/kapis/tenant/v1alpha2/register.go | 79 +----- pkg/models/iam/am/am.go | 135 ++++++--- pkg/models/iam/am/fake_operator.go | 141 ---------- pkg/models/resources/v1alpha3/interface.go | 7 +- pkg/models/tenant/devops.go | 225 --------------- pkg/models/tenant/namespaces.go | 115 -------- pkg/models/tenant/tenant.go | 188 ++++++++----- pkg/models/tenant/workspaces.go | 263 ------------------ 44 files changed, 2178 insertions(+), 1283 deletions(-) create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_policyrule.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_role.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_rolebinding.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/policyrule.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/role.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/rolebinding.go create mode 100644 pkg/client/informers/externalversions/iam/v1alpha2/policyrule.go create mode 100644 pkg/client/informers/externalversions/iam/v1alpha2/role.go create mode 100644 pkg/client/informers/externalversions/iam/v1alpha2/rolebinding.go create mode 100644 pkg/client/listers/iam/v1alpha2/policyrule.go create mode 100644 pkg/client/listers/iam/v1alpha2/role.go create mode 100644 pkg/client/listers/iam/v1alpha2/rolebinding.go delete mode 100644 pkg/models/iam/am/fake_operator.go delete mode 100644 pkg/models/tenant/devops.go delete mode 100644 pkg/models/tenant/namespaces.go delete mode 100644 pkg/models/tenant/workspaces.go diff --git a/cmd/controller-manager/app/server.go b/cmd/controller-manager/app/server.go index c1eb2e079..63229e7a7 100644 --- a/cmd/controller-manager/app/server.go +++ b/cmd/controller-manager/app/server.go @@ -35,6 +35,7 @@ import ( controllerconfig "kubesphere.io/kubesphere/pkg/apiserver/config" "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" "kubesphere.io/kubesphere/pkg/controller/namespace" + "kubesphere.io/kubesphere/pkg/controller/user" "kubesphere.io/kubesphere/pkg/controller/workspace" "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/simple/client/k8s" @@ -43,6 +44,7 @@ import ( "os" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/runtime/signals" + "sigs.k8s.io/controller-runtime/pkg/webhook" ) func NewControllerManagerCommand() *cobra.Command { @@ -151,13 +153,13 @@ func Run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{}) // Start cache data after all informer is registered informerFactory.Start(stopCh) - // Setup webhooks TODO enable webhook - //klog.Info("setting up webhook server") - //hookServer := mgr.GetWebhookServer() - // - //klog.Info("registering webhooks to the webhook server") - //hookServer.Register("//mutating-encrypt-password-iam-kubesphere-io-v1alpha2-user", &webhook.Admission{Handler: &user.PasswordCipher{Client: mgr.GetClient()}}) - //hookServer.Register("/validate-email-iam-kubesphere-io-v1alpha2-user", &webhook.Admission{Handler: &user.EmailValidator{Client: mgr.GetClient()}}) + // Setup webhooks + klog.Info("setting up webhook server") + hookServer := mgr.GetWebhookServer() + + klog.Info("registering webhooks to the webhook server") + hookServer.Register("/mutating-encrypt-password-iam-kubesphere-io-v1alpha2-user", &webhook.Admission{Handler: &user.PasswordCipher{Client: mgr.GetClient()}}) + hookServer.Register("/validate-email-iam-kubesphere-io-v1alpha2-user", &webhook.Admission{Handler: &user.EmailValidator{Client: mgr.GetClient()}}) klog.V(0).Info("Starting the controllers.") if err = mgr.Start(stopCh); err != nil { diff --git a/config/crds/iam.kubesphere.io_policyrules.yaml b/config/crds/iam.kubesphere.io_policyrules.yaml index 674c97416..c0eb6ed9c 100644 --- a/config/crds/iam.kubesphere.io_policyrules.yaml +++ b/config/crds/iam.kubesphere.io_policyrules.yaml @@ -8,6 +8,10 @@ metadata: creationTimestamp: null name: policyrules.iam.kubesphere.io spec: + additionalPrinterColumns: + - JSONPath: .scope + name: Scope + type: string group: iam.kubesphere.io names: categories: @@ -17,6 +21,7 @@ spec: plural: policyrules singular: policyrule scope: Cluster + subresources: {} validation: openAPIV3Schema: properties: @@ -30,15 +35,15 @@ spec: object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string - level: - type: string metadata: type: object rego: type: string + scope: + type: string required: - - level - rego + - scope type: object version: v1alpha2 versions: diff --git a/config/crds/iam.kubesphere.io_rolebindings.yaml b/config/crds/iam.kubesphere.io_rolebindings.yaml index a5c835f40..ede871b22 100644 --- a/config/crds/iam.kubesphere.io_rolebindings.yaml +++ b/config/crds/iam.kubesphere.io_rolebindings.yaml @@ -8,6 +8,16 @@ metadata: creationTimestamp: null name: rolebindings.iam.kubesphere.io spec: + additionalPrinterColumns: + - JSONPath: .scope + name: Scope + type: string + - JSONPath: .roleRef.name + name: RoleRef + type: string + - JSONPath: .subjects[*].name + name: Subjects + type: string group: iam.kubesphere.io names: categories: @@ -17,6 +27,7 @@ spec: plural: rolebindings singular: rolebinding scope: Cluster + subresources: {} validation: openAPIV3Schema: description: RoleBinding is the Schema for the rolebindings API @@ -31,8 +42,6 @@ spec: object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string - level: - type: string metadata: type: object roleRef: @@ -53,6 +62,8 @@ spec: - kind - name type: object + scope: + type: string subjects: description: Subjects holds references to the users the role applies to. items: @@ -77,8 +88,8 @@ spec: type: object type: array required: - - level - roleRef + - scope type: object version: v1alpha2 versions: diff --git a/config/crds/iam.kubesphere.io_roles.yaml b/config/crds/iam.kubesphere.io_roles.yaml index 144333b4a..91b01e128 100644 --- a/config/crds/iam.kubesphere.io_roles.yaml +++ b/config/crds/iam.kubesphere.io_roles.yaml @@ -8,6 +8,13 @@ metadata: creationTimestamp: null name: roles.iam.kubesphere.io spec: + additionalPrinterColumns: + - JSONPath: .target.scope + name: Scope + type: string + - JSONPath: .target.name + name: Target + type: string group: iam.kubesphere.io names: categories: @@ -17,6 +24,7 @@ spec: plural: roles singular: role scope: Cluster + subresources: {} validation: openAPIV3Schema: properties: @@ -52,21 +60,19 @@ spec: - name type: object type: array - scope: + target: properties: - level: + name: + type: string + scope: type: string - scopes: - items: - type: string - type: array required: - - level - - scopes + - name + - scope type: object required: - rules - - scope + - target type: object version: v1alpha2 versions: diff --git a/config/samples/iam_v1alpha2_policyrule.yaml b/config/samples/iam_v1alpha2_policyrule.yaml index 6f2cd420b..d22ad3e5b 100644 --- a/config/samples/iam_v1alpha2_policyrule.yaml +++ b/config/samples/iam_v1alpha2_policyrule.yaml @@ -3,7 +3,53 @@ kind: PolicyRule metadata: labels: controller-tools.k8s.io: "1.0" - name: policyrule-sample -spec: - # Add fields here - foo: bar + name: always-allow +scope: Global +rego: 'package authz\ndefault allow = true' + +--- + +apiVersion: iam.kubesphere.io/v1alpha2 +kind: PolicyRule +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: always-deny +scope: Global +rego: | + package authz + default allow = false + +--- + +apiVersion: iam.kubesphere.io/v1alpha2 +kind: PolicyRule +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: cluster-manage +scope: Global +rego: | + package authz + default allow = false + allow { + input.Resource == 'clusters' + } + +--- + +apiVersion: iam.kubesphere.io/v1alpha2 +kind: PolicyRule +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: some-namespace-manage +scope: Namespace +rego: | + package authz + default allow = false + allow { + input.Resource == 'clusters' + } + + diff --git a/config/samples/iam_v1alpha2_role.yaml b/config/samples/iam_v1alpha2_role.yaml index 8c81faa95..a85cad08d 100644 --- a/config/samples/iam_v1alpha2_role.yaml +++ b/config/samples/iam_v1alpha2_role.yaml @@ -3,7 +3,28 @@ kind: Role metadata: labels: controller-tools.k8s.io: "1.0" - name: role-sample -spec: - # Add fields here - foo: bar + name: cluster-admin +target: + scope: Global + name: '' +rules: + - apiGroup: iam.kubesphere.io/v1alpha2 + kind: PolicyRule + name: always-allow + +--- + +apiVersion: iam.kubesphere.io/v1alpha2 +kind: Role +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: anonymous +target: + scope: Global + name: '' +rules: + - apiGroup: iam.kubesphere.io/v1alpha2 + kind: PolicyRule + name: always-deny + diff --git a/config/samples/iam_v1alpha2_rolebinding.yaml b/config/samples/iam_v1alpha2_rolebinding.yaml index d0c5b34e7..3caf4fa87 100644 --- a/config/samples/iam_v1alpha2_rolebinding.yaml +++ b/config/samples/iam_v1alpha2_rolebinding.yaml @@ -3,7 +3,13 @@ kind: RoleBinding metadata: labels: controller-tools.k8s.io: "1.0" - name: rolebinding-sample -spec: - # Add fields here - foo: bar + name: cluster-admin +scope: Global +roleRef: + apiGroup: iam.kubesphere.io/v1alpha2 + kind: Role + name: cluster-admin +subjects: + - apiGroup: iam.kubesphere.io/v1alpha2 + kind: User + name: admin diff --git a/go.sum b/go.sum index 6d86b60cd..d39f730cd 100644 --- a/go.sum +++ b/go.sum @@ -313,6 +313,7 @@ github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2i github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/openshift/api v0.0.0-20180801171038-322a19404e37 h1:05irGU4HK4IauGGDbsk+ZHrm1wOzMLYjMlfaiqMrBYc= github.com/openshift/api v0.0.0-20180801171038-322a19404e37/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= github.com/openshift/api v0.0.0-20200331152225-585af27e34fd h1:f4iPC9iCf1an7qEWpEFvp/swsM79vvBRsJ2twU4D30s= github.com/openshift/api v0.0.0-20200331152225-585af27e34fd/go.mod h1:RKMJ5CBnljLfnej+BJ/xnOWc3kZDvJUaIAEq2oKSPtE= diff --git a/pkg/apis/iam/v1alpha2/types.go b/pkg/apis/iam/v1alpha2/types.go index aeb6a404e..6fef890a3 100644 --- a/pkg/apis/iam/v1alpha2/types.go +++ b/pkg/apis/iam/v1alpha2/types.go @@ -21,8 +21,8 @@ import ( ) // +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:openapi-gen=true // User is the Schema for the users API @@ -125,30 +125,38 @@ type UserList struct { Items []User `json:"items"` } +// +genclient +// +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:printcolumn:name="Scope",type="string",JSONPath=".target.scope" +// +kubebuilder:printcolumn:name="Target",type="string",JSONPath=".target.name" // +kubebuilder:resource:categories="iam",scope="Cluster" type Role struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Scope Scope `json:"scope"` - Rules []RuleRef `json:"rules"` + Target Target `json:"target"` + Rules []RuleRef `json:"rules"` } -type Scope struct { - Level Level `json:"level"` - Scopes []string `json:"scopes"` +type Target struct { + Scope Scope `json:"scope"` + Name string `json:"name"` } -type Level string +type Scope string const ( - LevelGlobal Level = "Global" - LevelCluster Level = "Cluster" - LevelWorkspace Level = "Workspace" - LevelNamespace Level = "Namespace" - ScopeALL = "*" + GlobalScope Scope = "Global" + ClusterScope Scope = "Cluster" + WorkspaceScope Scope = "Workspace" + NamespaceScope Scope = "Namespace" + TargetAll = "*" + UserKind = "User" + PolicyRuleKind = "PolicyRule" + RoleKind = "Role" + RoleBindingKind = "RoleBinding" ) // RuleRef contains information that points to the role being used @@ -170,14 +178,17 @@ type RoleList struct { Items []Role `json:"items"` } +// +genclient +// +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:printcolumn:name="Scope",type="string",JSONPath=".scope" // +kubebuilder:resource:categories="iam",scope="Cluster" type PolicyRule struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Level Level `json:"level"` + Scope Scope `json:"scope"` Rego string `json:"rego"` } @@ -190,15 +201,20 @@ type PolicyRuleList struct { Items []PolicyRule `json:"items"` } +// +genclient +// +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // RoleBinding is the Schema for the rolebindings API +// +kubebuilder:printcolumn:name="Scope",type="string",JSONPath=".scope" +// +kubebuilder:printcolumn:name="RoleRef",type="string",JSONPath=".roleRef.name" +// +kubebuilder:printcolumn:name="Subjects",type="string",JSONPath=".subjects[*].name" // +kubebuilder:resource:categories="iam",scope="Cluster" type RoleBinding struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Level Level `json:"level"` + Scope Scope `json:"scope"` RoleRef RoleRef `json:"roleRef"` // Subjects holds references to the users the role applies to. // +optional @@ -234,3 +250,8 @@ type RoleBindingList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []RoleBinding `json:"items"` } + +type UserDetail struct { + *User + GlobalRole *Role `json:"globalRole"` +} diff --git a/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go index 26394de1d..8ac0e86bc 100644 --- a/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go @@ -86,7 +86,7 @@ func (in *Role) DeepCopyInto(out *Role) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Scope.DeepCopyInto(&out.Scope) + out.Target = in.Target if in.Rules != nil { in, out := &in.Rules, &out.Rules *out = make([]RuleRef, len(*in)) @@ -237,26 +237,6 @@ func (in *RuleRef) DeepCopy() *RuleRef { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Scope) DeepCopyInto(out *Scope) { - *out = *in - if in.Scopes != nil { - in, out := &in.Scopes, &out.Scopes - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Scope. -func (in *Scope) DeepCopy() *Scope { - if in == nil { - return nil - } - out := new(Scope) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Subject) DeepCopyInto(out *Subject) { *out = *in @@ -272,6 +252,21 @@ func (in *Subject) DeepCopy() *Subject { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Target) DeepCopyInto(out *Target) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Target. +func (in *Target) DeepCopy() *Target { + if in == nil { + return nil + } + out := new(Target) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *User) DeepCopyInto(out *User) { *out = *in @@ -315,6 +310,31 @@ func (in *UserCondition) DeepCopy() *UserCondition { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserDetail) DeepCopyInto(out *UserDetail) { + *out = *in + if in.User != nil { + in, out := &in.User, &out.User + *out = new(User) + (*in).DeepCopyInto(*out) + } + if in.GlobalRole != nil { + in, out := &in.GlobalRole, &out.GlobalRole + *out = new(Role) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserDetail. +func (in *UserDetail) DeepCopy() *UserDetail { + if in == nil { + return nil + } + out := new(UserDetail) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *UserList) DeepCopyInto(out *UserList) { *out = *in diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 91553bc32..415b87358 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -144,7 +144,10 @@ func (s *APIServer) installKubeSphereAPIs() { urlruntime.Must(resourcesv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.InformerFactory)) //urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.InformerFactory, s.DBClient.Database())) urlruntime.Must(terminalv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.KubernetesClient.Config())) - urlruntime.Must(iamv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.InformerFactory, s.LdapClient, s.CacheClient, s.Config.AuthenticationOptions)) + urlruntime.Must(iamv1alpha2.AddToContainer(s.container, im.NewOperator(s.KubernetesClient.KubeSphere(), + s.InformerFactory.KubeSphereSharedInformerFactory()), + am.NewAMOperator(s.KubernetesClient.KubeSphere(), s.InformerFactory.KubeSphereSharedInformerFactory()), + s.Config.AuthenticationOptions)) urlruntime.Must(oauth.AddToContainer(s.container, token.NewJwtTokenIssuer(token.DefaultIssuerName, s.Config.AuthenticationOptions, s.CacheClient), s.Config.AuthenticationOptions)) urlruntime.Must(servicemeshv1alpha2.AddToContainer(s.container)) } @@ -188,7 +191,7 @@ func (s *APIServer) buildHandlerChain() { pathAuthorizer, _ := path.NewAuthorizer(excludedPaths) // union authorizers are ordered, don't change the order here - authorizers := unionauthorizer.New(pathAuthorizer, authorizerfactory.NewOPAAuthorizer(am.NewFakeAMOperator())) + authorizers := unionauthorizer.New(pathAuthorizer, authorizerfactory.NewOPAAuthorizer(am.NewAMOperator(s.KubernetesClient.KubeSphere(), s.InformerFactory.KubeSphereSharedInformerFactory()))) handler = filters.WithAuthorization(handler, authorizers) // authenticators are unordered @@ -274,6 +277,9 @@ func (s *APIServer) waitForResourceSync(stopCh <-chan struct{}) error { ksGVRs := []schema.GroupVersionResource{ {Group: "tenant.kubesphere.io", Version: "v1alpha1", Resource: "workspaces"}, {Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "users"}, + {Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "roles"}, + {Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "rolebindings"}, + {Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "policyrules"}, {Group: "tower.kubesphere.io", Version: "v1alpha1", Resource: "agents"}, } diff --git a/pkg/apiserver/authorization/authorizerfactory/opa.go b/pkg/apiserver/authorization/authorizerfactory/opa.go index 609945477..b6ea752ba 100644 --- a/pkg/apiserver/authorization/authorizerfactory/opa.go +++ b/pkg/apiserver/authorization/authorizerfactory/opa.go @@ -21,6 +21,9 @@ package authorizerfactory import ( "context" "github.com/open-policy-agent/opa/rego" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/klog" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" "kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer" "kubesphere.io/kubesphere/pkg/models/iam/am" ) @@ -33,13 +36,16 @@ type opaAuthorizer struct { func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { // Make decisions based on the authorization policy of different levels of roles - platformRole, err := o.am.GetPlatformRole(attr.GetUser().GetName()) + globalRole, err := o.am.GetRoleOfUserInTargetScope(iamv1alpha2.GlobalScope, "", attr.GetUser().GetName()) if err != nil { + if errors.IsNotFound(err) { + return authorizer.DecisionDeny, err.Error(), nil + } return authorizer.DecisionDeny, "", err } // check platform role policy rules - if authorized, reason, err = makeDecision(platformRole, attr); authorized == authorizer.DecisionAllow { + if authorized, reason, err = o.makeDecision(globalRole, attr); authorized == authorizer.DecisionAllow { return authorized, reason, err } @@ -48,13 +54,16 @@ func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized author return authorizer.DecisionDeny, "permission undefined", nil } - clusterRole, err := o.am.GetClusterRole(attr.GetCluster(), attr.GetUser().GetName()) + clusterRole, err := o.am.GetRoleOfUserInTargetScope(iamv1alpha2.ClusterScope, attr.GetCluster(), attr.GetUser().GetName()) if err != nil { + if errors.IsNotFound(err) { + return authorizer.DecisionDeny, err.Error(), nil + } return authorizer.DecisionDeny, "", err } // check cluster role policy rules - if a, r, e := makeDecision(clusterRole, attr); a == authorizer.DecisionAllow { + if a, r, e := o.makeDecision(clusterRole, attr); a == authorizer.DecisionAllow { return a, r, e } @@ -63,13 +72,16 @@ func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized author return authorizer.DecisionDeny, "permission undefined", nil } - workspaceRole, err := o.am.GetWorkspaceRole(attr.GetWorkspace(), attr.GetUser().GetName()) + workspaceRole, err := o.am.GetRoleOfUserInTargetScope(iamv1alpha2.WorkspaceScope, attr.GetWorkspace(), attr.GetUser().GetName()) if err != nil { + if errors.IsNotFound(err) { + return authorizer.DecisionDeny, err.Error(), nil + } return authorizer.DecisionDeny, "", err } // check workspace role policy rules - if a, r, e := makeDecision(workspaceRole, attr); a == authorizer.DecisionAllow { + if a, r, e := o.makeDecision(workspaceRole, attr); a == authorizer.DecisionAllow { return a, r, e } @@ -79,12 +91,15 @@ func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized author } if attr.GetNamespace() != "" { - namespaceRole, err := o.am.GetNamespaceRole(attr.GetCluster(), attr.GetNamespace(), attr.GetUser().GetName()) + namespaceRole, err := o.am.GetRoleOfUserInTargetScope(iamv1alpha2.NamespaceScope, attr.GetNamespace(), attr.GetUser().GetName()) if err != nil { + if errors.IsNotFound(err) { + return authorizer.DecisionDeny, err.Error(), nil + } return authorizer.DecisionDeny, "", err } // check namespace role policy rules - if a, r, e := makeDecision(namespaceRole, attr); a == authorizer.DecisionAllow { + if a, r, e := o.makeDecision(namespaceRole, attr); a == authorizer.DecisionAllow { return a, r, e } } @@ -93,48 +108,36 @@ func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized author } // Make decision base on role -func makeDecision(role am.Role, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { +func (o *opaAuthorizer) makeDecision(role *iamv1alpha2.Role, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { - // Call the rego.New function to create an object that can be prepared or evaluated - // After constructing a new rego.Rego object you can call PrepareForEval() to obtain an executable query - query, err := rego.New(rego.Query("data.authz.allow"), rego.Module("authz.rego", role.GetRego())).PrepareForEval(context.Background()) + for _, ruleRef := range role.Rules { + rule, err := o.am.GetPolicyRule(ruleRef.Name) + if err != nil { + if errors.IsNotFound(err) { + continue + } + return authorizer.DecisionDeny, "", err + } + // Call the rego.New function to create an object that can be prepared or evaluated + // After constructing a new rego.Rego object you can call PrepareForEval() to obtain an executable query + query, err := rego.New(rego.Query("data.authz.allow"), rego.Module("authz.rego", rule.Rego)).PrepareForEval(context.Background()) - if err != nil { - return authorizer.DecisionDeny, "", err - } + if err != nil { + klog.Errorf("rule syntax error:%s", err) + continue + } - // data example - //{ - // "User": { - // "Name": "admin", - // "UID": "0", - // "Groups": [ - // "admin" - // ], - // "Extra": null - // }, - // "Verb": "list", - // "Cluster": "cluster1", - // "Workspace": "", - // "Namespace": "", - // "APIGroup": "", - // "APIVersion": "v1", - // "Resource": "nodes", - // "Subresource": "", - // "Name": "", - // "KubernetesRequest": true, - // "ResourceRequest": true, - // "Path": "/api/v1/nodes" - //} - // The policy decision is contained in the results returned by the Eval() call. You can inspect the decision and handle it accordingly. - results, err := query.Eval(context.Background(), rego.EvalInput(a)) + // The policy decision is contained in the results returned by the Eval() call. You can inspect the decision and handle it accordingly. + results, err := query.Eval(context.Background(), rego.EvalInput(a)) - if err != nil { - return authorizer.DecisionDeny, "", err - } + if err != nil { + klog.Errorf("rule syntax error:%s", err) + continue + } - if len(results) > 0 && results[0].Expressions[0].Value == true { - return authorizer.DecisionAllow, "", nil + if len(results) > 0 && results[0].Expressions[0].Value == true { + return authorizer.DecisionAllow, "", nil + } } return authorizer.DecisionDeny, "permission undefined", nil diff --git a/pkg/apiserver/authorization/authorizerfactory/opa_test.go b/pkg/apiserver/authorization/authorizerfactory/opa_test.go index 3781dfae8..13bbe74e8 100644 --- a/pkg/apiserver/authorization/authorizerfactory/opa_test.go +++ b/pkg/apiserver/authorization/authorizerfactory/opa_test.go @@ -19,22 +19,44 @@ package authorizerfactory import ( + "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/authentication/user" + iamvealpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" "kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" "kubesphere.io/kubesphere/pkg/models/iam/am" "testing" ) -func TestPlatformRole(t *testing.T) { - platformRoles := map[string]am.FakeRole{"admin": { - Name: "admin", - Rego: "package authz\ndefault allow = true", - }, "anonymous": { - Name: "anonymous", - Rego: "package authz\ndefault allow = false", - }, "tom": { - Name: "tom", - Rego: `package authz +func prepare() (am.AccessManagementInterface, error) { + rules := []*iamvealpha2.PolicyRule{ + { + TypeMeta: metav1.TypeMeta{ + Kind: iamvealpha2.PolicyRuleKind, + APIVersion: iamvealpha2.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: "always-allow", + }, + Rego: "package authz\ndefault allow = true", + }, { + TypeMeta: metav1.TypeMeta{ + Kind: iamvealpha2.PolicyRuleKind, + APIVersion: iamvealpha2.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "always-deny", + }, + Rego: "package authz\ndefault allow = false", + }, { + TypeMeta: metav1.TypeMeta{ + Kind: iamvealpha2.PolicyRuleKind, + APIVersion: iamvealpha2.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: "manage-cluster1-resources", + }, + Rego: `package authz default allow = false allow { resources_in_cluster1 @@ -42,11 +64,168 @@ allow { resources_in_cluster1 { input.Cluster == "cluster1" }`, - }, + }, } - operator := am.NewFakeAMOperator() - operator.Prepare(platformRoles, nil, nil, nil) + roles := []*iamvealpha2.Role{ + { + TypeMeta: metav1.TypeMeta{ + Kind: iamvealpha2.RoleKind, + APIVersion: iamvealpha2.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: "global-admin", + }, + Target: iamvealpha2.Target{ + Scope: iamvealpha2.GlobalScope, + Name: "", + }, + Rules: []iamvealpha2.RuleRef{ + { + APIGroup: iamvealpha2.SchemeGroupVersion.String(), + Kind: iamvealpha2.PolicyRuleKind, + Name: "always-allow", + }, + }, + }, + { + TypeMeta: metav1.TypeMeta{ + Kind: iamvealpha2.RoleKind, + APIVersion: iamvealpha2.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: "anonymous", + }, + Target: iamvealpha2.Target{ + Scope: iamvealpha2.GlobalScope, + Name: "", + }, + Rules: []iamvealpha2.RuleRef{ + { + APIGroup: iamvealpha2.SchemeGroupVersion.String(), + Kind: iamvealpha2.PolicyRuleKind, + Name: "always-deny", + }, + }, + }, + { + TypeMeta: metav1.TypeMeta{ + Kind: iamvealpha2.RoleKind, + APIVersion: iamvealpha2.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1-admin", + }, + Target: iamvealpha2.Target{ + Scope: iamvealpha2.GlobalScope, + Name: "", + }, + Rules: []iamvealpha2.RuleRef{ + { + APIGroup: iamvealpha2.SchemeGroupVersion.String(), + Kind: iamvealpha2.PolicyRuleKind, + Name: "manage-cluster1-resources", + }, + }, + }, + } + + roleBindings := []*iamvealpha2.RoleBinding{ + { + TypeMeta: metav1.TypeMeta{ + Kind: iamvealpha2.RoleBindingKind, + APIVersion: iamvealpha2.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: "global-admin", + }, + Scope: iamvealpha2.GlobalScope, + RoleRef: iamvealpha2.RoleRef{ + APIGroup: iamvealpha2.SchemeGroupVersion.String(), + Kind: iamvealpha2.RoleKind, + Name: "global-admin", + }, + Subjects: []iamvealpha2.Subject{ + { + Kind: iamvealpha2.UserKind, + APIGroup: iamvealpha2.SchemeGroupVersion.String(), + Name: "admin", + }, + }, + }, + { + TypeMeta: metav1.TypeMeta{ + Kind: iamvealpha2.RoleBindingKind, + APIVersion: iamvealpha2.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: "anonymous", + }, + Scope: iamvealpha2.GlobalScope, + RoleRef: iamvealpha2.RoleRef{ + APIGroup: iamvealpha2.SchemeGroupVersion.String(), + Kind: iamvealpha2.RoleKind, + Name: "anonymous", + }, + Subjects: []iamvealpha2.Subject{ + { + Kind: iamvealpha2.UserKind, + APIGroup: iamvealpha2.SchemeGroupVersion.String(), + Name: user.Anonymous, + }, + }, + }, + { + TypeMeta: metav1.TypeMeta{ + Kind: iamvealpha2.RoleBindingKind, + APIVersion: iamvealpha2.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1-admin", + }, + Scope: iamvealpha2.GlobalScope, + RoleRef: iamvealpha2.RoleRef{ + APIGroup: iamvealpha2.SchemeGroupVersion.String(), + Kind: iamvealpha2.RoleKind, + Name: "cluster1-admin", + }, + Subjects: []iamvealpha2.Subject{ + { + Kind: iamvealpha2.UserKind, + APIGroup: iamvealpha2.SchemeGroupVersion.String(), + Name: "tom", + }, + }, + }, + } + + ksClient := fake.NewSimpleClientset() + informerFactory := externalversions.NewSharedInformerFactory(ksClient, 0) + + for _, rule := range rules { + err := informerFactory.Iam().V1alpha2().PolicyRules().Informer().GetIndexer().Add(rule) + if err != nil { + return nil, fmt.Errorf("add rule:%s", err) + } + } + for _, role := range roles { + err := informerFactory.Iam().V1alpha2().Roles().Informer().GetIndexer().Add(role) + if err != nil { + return nil, fmt.Errorf("add role:%s", err) + } + } + for _, roleBinding := range roleBindings { + err := informerFactory.Iam().V1alpha2().RoleBindings().Informer().GetIndexer().Add(roleBinding) + if err != nil { + return nil, fmt.Errorf("add role binding:%s", err) + } + } + + operator := am.NewAMOperator(ksClient, informerFactory) + + return operator, nil +} + +func TestGlobalRole(t *testing.T) { + + operator, err := prepare() + if err != nil { + t.Fatal(err) + } opa := NewOPAAuthorizer(operator) diff --git a/pkg/apiserver/query/field.go b/pkg/apiserver/query/field.go index e37ec7866..0a1515072 100644 --- a/pkg/apiserver/query/field.go +++ b/pkg/apiserver/query/field.go @@ -10,7 +10,6 @@ const ( FieldLastUpdateTimestamp = "lastUpdateTimestamp" FieldLabel = "label" FieldAnnotation = "annotation" - FieldClusterName = "clusterName" FieldNamespace = "namespace" FieldStatus = "status" FieldOwnerReference = "ownerReference" @@ -29,7 +28,6 @@ var ComparableFields = []Field{ FieldUID, FieldLabel, FieldAnnotation, - FieldClusterName, FieldNamespace, FieldStatus, FieldOwnerReference, diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_iam_client.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_iam_client.go index 93b004ea7..7b8ccc866 100644 --- a/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_iam_client.go +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_iam_client.go @@ -28,6 +28,18 @@ type FakeIamV1alpha2 struct { *testing.Fake } +func (c *FakeIamV1alpha2) PolicyRules() v1alpha2.PolicyRuleInterface { + return &FakePolicyRules{c} +} + +func (c *FakeIamV1alpha2) Roles() v1alpha2.RoleInterface { + return &FakeRoles{c} +} + +func (c *FakeIamV1alpha2) RoleBindings() v1alpha2.RoleBindingInterface { + return &FakeRoleBindings{c} +} + func (c *FakeIamV1alpha2) Users() v1alpha2.UserInterface { return &FakeUsers{c} } diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_policyrule.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_policyrule.go new file mode 100644 index 000000000..b9e63645b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_policyrule.go @@ -0,0 +1,120 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" +) + +// FakePolicyRules implements PolicyRuleInterface +type FakePolicyRules struct { + Fake *FakeIamV1alpha2 +} + +var policyrulesResource = schema.GroupVersionResource{Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "policyrules"} + +var policyrulesKind = schema.GroupVersionKind{Group: "iam.kubesphere.io", Version: "v1alpha2", Kind: "PolicyRule"} + +// Get takes name of the policyRule, and returns the corresponding policyRule object, and an error if there is any. +func (c *FakePolicyRules) Get(name string, options v1.GetOptions) (result *v1alpha2.PolicyRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(policyrulesResource, name), &v1alpha2.PolicyRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.PolicyRule), err +} + +// List takes label and field selectors, and returns the list of PolicyRules that match those selectors. +func (c *FakePolicyRules) List(opts v1.ListOptions) (result *v1alpha2.PolicyRuleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(policyrulesResource, policyrulesKind, opts), &v1alpha2.PolicyRuleList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha2.PolicyRuleList{ListMeta: obj.(*v1alpha2.PolicyRuleList).ListMeta} + for _, item := range obj.(*v1alpha2.PolicyRuleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested policyRules. +func (c *FakePolicyRules) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(policyrulesResource, opts)) +} + +// Create takes the representation of a policyRule and creates it. Returns the server's representation of the policyRule, and an error, if there is any. +func (c *FakePolicyRules) Create(policyRule *v1alpha2.PolicyRule) (result *v1alpha2.PolicyRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(policyrulesResource, policyRule), &v1alpha2.PolicyRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.PolicyRule), err +} + +// Update takes the representation of a policyRule and updates it. Returns the server's representation of the policyRule, and an error, if there is any. +func (c *FakePolicyRules) Update(policyRule *v1alpha2.PolicyRule) (result *v1alpha2.PolicyRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(policyrulesResource, policyRule), &v1alpha2.PolicyRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.PolicyRule), err +} + +// Delete takes name of the policyRule and deletes it. Returns an error if one occurs. +func (c *FakePolicyRules) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(policyrulesResource, name), &v1alpha2.PolicyRule{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakePolicyRules) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(policyrulesResource, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha2.PolicyRuleList{}) + return err +} + +// Patch applies the patch and returns the patched policyRule. +func (c *FakePolicyRules) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.PolicyRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(policyrulesResource, name, pt, data, subresources...), &v1alpha2.PolicyRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.PolicyRule), err +} diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_role.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_role.go new file mode 100644 index 000000000..eef005e6d --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_role.go @@ -0,0 +1,120 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" +) + +// FakeRoles implements RoleInterface +type FakeRoles struct { + Fake *FakeIamV1alpha2 +} + +var rolesResource = schema.GroupVersionResource{Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "roles"} + +var rolesKind = schema.GroupVersionKind{Group: "iam.kubesphere.io", Version: "v1alpha2", Kind: "Role"} + +// Get takes name of the role, and returns the corresponding role object, and an error if there is any. +func (c *FakeRoles) Get(name string, options v1.GetOptions) (result *v1alpha2.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(rolesResource, name), &v1alpha2.Role{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.Role), err +} + +// List takes label and field selectors, and returns the list of Roles that match those selectors. +func (c *FakeRoles) List(opts v1.ListOptions) (result *v1alpha2.RoleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(rolesResource, rolesKind, opts), &v1alpha2.RoleList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha2.RoleList{ListMeta: obj.(*v1alpha2.RoleList).ListMeta} + for _, item := range obj.(*v1alpha2.RoleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested roles. +func (c *FakeRoles) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(rolesResource, opts)) +} + +// Create takes the representation of a role and creates it. Returns the server's representation of the role, and an error, if there is any. +func (c *FakeRoles) Create(role *v1alpha2.Role) (result *v1alpha2.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(rolesResource, role), &v1alpha2.Role{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.Role), err +} + +// Update takes the representation of a role and updates it. Returns the server's representation of the role, and an error, if there is any. +func (c *FakeRoles) Update(role *v1alpha2.Role) (result *v1alpha2.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(rolesResource, role), &v1alpha2.Role{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.Role), err +} + +// Delete takes name of the role and deletes it. Returns an error if one occurs. +func (c *FakeRoles) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(rolesResource, name), &v1alpha2.Role{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRoles) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(rolesResource, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha2.RoleList{}) + return err +} + +// Patch applies the patch and returns the patched role. +func (c *FakeRoles) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.Role, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(rolesResource, name, pt, data, subresources...), &v1alpha2.Role{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.Role), err +} diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_rolebinding.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_rolebinding.go new file mode 100644 index 000000000..55966eb01 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_rolebinding.go @@ -0,0 +1,120 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" +) + +// FakeRoleBindings implements RoleBindingInterface +type FakeRoleBindings struct { + Fake *FakeIamV1alpha2 +} + +var rolebindingsResource = schema.GroupVersionResource{Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "rolebindings"} + +var rolebindingsKind = schema.GroupVersionKind{Group: "iam.kubesphere.io", Version: "v1alpha2", Kind: "RoleBinding"} + +// Get takes name of the roleBinding, and returns the corresponding roleBinding object, and an error if there is any. +func (c *FakeRoleBindings) Get(name string, options v1.GetOptions) (result *v1alpha2.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(rolebindingsResource, name), &v1alpha2.RoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.RoleBinding), err +} + +// List takes label and field selectors, and returns the list of RoleBindings that match those selectors. +func (c *FakeRoleBindings) List(opts v1.ListOptions) (result *v1alpha2.RoleBindingList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(rolebindingsResource, rolebindingsKind, opts), &v1alpha2.RoleBindingList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha2.RoleBindingList{ListMeta: obj.(*v1alpha2.RoleBindingList).ListMeta} + for _, item := range obj.(*v1alpha2.RoleBindingList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested roleBindings. +func (c *FakeRoleBindings) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(rolebindingsResource, opts)) +} + +// Create takes the representation of a roleBinding and creates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *FakeRoleBindings) Create(roleBinding *v1alpha2.RoleBinding) (result *v1alpha2.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(rolebindingsResource, roleBinding), &v1alpha2.RoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.RoleBinding), err +} + +// Update takes the representation of a roleBinding and updates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *FakeRoleBindings) Update(roleBinding *v1alpha2.RoleBinding) (result *v1alpha2.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(rolebindingsResource, roleBinding), &v1alpha2.RoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.RoleBinding), err +} + +// Delete takes name of the roleBinding and deletes it. Returns an error if one occurs. +func (c *FakeRoleBindings) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(rolebindingsResource, name), &v1alpha2.RoleBinding{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRoleBindings) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(rolebindingsResource, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha2.RoleBindingList{}) + return err +} + +// Patch applies the patch and returns the patched roleBinding. +func (c *FakeRoleBindings) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.RoleBinding, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(rolebindingsResource, name, pt, data, subresources...), &v1alpha2.RoleBinding{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.RoleBinding), err +} diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/generated_expansion.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/generated_expansion.go index 6a63cac5a..cae484a26 100644 --- a/pkg/client/clientset/versioned/typed/iam/v1alpha2/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/generated_expansion.go @@ -18,4 +18,10 @@ limitations under the License. package v1alpha2 +type PolicyRuleExpansion interface{} + +type RoleExpansion interface{} + +type RoleBindingExpansion interface{} + type UserExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/iam_client.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/iam_client.go index a18e2b5a3..7bd5bafdf 100644 --- a/pkg/client/clientset/versioned/typed/iam/v1alpha2/iam_client.go +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/iam_client.go @@ -26,6 +26,9 @@ import ( type IamV1alpha2Interface interface { RESTClient() rest.Interface + PolicyRulesGetter + RolesGetter + RoleBindingsGetter UsersGetter } @@ -34,6 +37,18 @@ type IamV1alpha2Client struct { restClient rest.Interface } +func (c *IamV1alpha2Client) PolicyRules() PolicyRuleInterface { + return newPolicyRules(c) +} + +func (c *IamV1alpha2Client) Roles() RoleInterface { + return newRoles(c) +} + +func (c *IamV1alpha2Client) RoleBindings() RoleBindingInterface { + return newRoleBindings(c) +} + func (c *IamV1alpha2Client) Users() UserInterface { return newUsers(c) } diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/policyrule.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/policyrule.go new file mode 100644 index 000000000..61515de5a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/policyrule.go @@ -0,0 +1,164 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// PolicyRulesGetter has a method to return a PolicyRuleInterface. +// A group's client should implement this interface. +type PolicyRulesGetter interface { + PolicyRules() PolicyRuleInterface +} + +// PolicyRuleInterface has methods to work with PolicyRule resources. +type PolicyRuleInterface interface { + Create(*v1alpha2.PolicyRule) (*v1alpha2.PolicyRule, error) + Update(*v1alpha2.PolicyRule) (*v1alpha2.PolicyRule, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha2.PolicyRule, error) + List(opts v1.ListOptions) (*v1alpha2.PolicyRuleList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.PolicyRule, err error) + PolicyRuleExpansion +} + +// policyRules implements PolicyRuleInterface +type policyRules struct { + client rest.Interface +} + +// newPolicyRules returns a PolicyRules +func newPolicyRules(c *IamV1alpha2Client) *policyRules { + return &policyRules{ + client: c.RESTClient(), + } +} + +// Get takes name of the policyRule, and returns the corresponding policyRule object, and an error if there is any. +func (c *policyRules) Get(name string, options v1.GetOptions) (result *v1alpha2.PolicyRule, err error) { + result = &v1alpha2.PolicyRule{} + err = c.client.Get(). + Resource("policyrules"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of PolicyRules that match those selectors. +func (c *policyRules) List(opts v1.ListOptions) (result *v1alpha2.PolicyRuleList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha2.PolicyRuleList{} + err = c.client.Get(). + Resource("policyrules"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested policyRules. +func (c *policyRules) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("policyrules"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a policyRule and creates it. Returns the server's representation of the policyRule, and an error, if there is any. +func (c *policyRules) Create(policyRule *v1alpha2.PolicyRule) (result *v1alpha2.PolicyRule, err error) { + result = &v1alpha2.PolicyRule{} + err = c.client.Post(). + Resource("policyrules"). + Body(policyRule). + Do(). + Into(result) + return +} + +// Update takes the representation of a policyRule and updates it. Returns the server's representation of the policyRule, and an error, if there is any. +func (c *policyRules) Update(policyRule *v1alpha2.PolicyRule) (result *v1alpha2.PolicyRule, err error) { + result = &v1alpha2.PolicyRule{} + err = c.client.Put(). + Resource("policyrules"). + Name(policyRule.Name). + Body(policyRule). + Do(). + Into(result) + return +} + +// Delete takes name of the policyRule and deletes it. Returns an error if one occurs. +func (c *policyRules) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Resource("policyrules"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *policyRules) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("policyrules"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched policyRule. +func (c *policyRules) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.PolicyRule, err error) { + result = &v1alpha2.PolicyRule{} + err = c.client.Patch(pt). + Resource("policyrules"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/role.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/role.go new file mode 100644 index 000000000..35b3a84ac --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/role.go @@ -0,0 +1,164 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// RolesGetter has a method to return a RoleInterface. +// A group's client should implement this interface. +type RolesGetter interface { + Roles() RoleInterface +} + +// RoleInterface has methods to work with Role resources. +type RoleInterface interface { + Create(*v1alpha2.Role) (*v1alpha2.Role, error) + Update(*v1alpha2.Role) (*v1alpha2.Role, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha2.Role, error) + List(opts v1.ListOptions) (*v1alpha2.RoleList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.Role, err error) + RoleExpansion +} + +// roles implements RoleInterface +type roles struct { + client rest.Interface +} + +// newRoles returns a Roles +func newRoles(c *IamV1alpha2Client) *roles { + return &roles{ + client: c.RESTClient(), + } +} + +// Get takes name of the role, and returns the corresponding role object, and an error if there is any. +func (c *roles) Get(name string, options v1.GetOptions) (result *v1alpha2.Role, err error) { + result = &v1alpha2.Role{} + err = c.client.Get(). + Resource("roles"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Roles that match those selectors. +func (c *roles) List(opts v1.ListOptions) (result *v1alpha2.RoleList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha2.RoleList{} + err = c.client.Get(). + Resource("roles"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested roles. +func (c *roles) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("roles"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a role and creates it. Returns the server's representation of the role, and an error, if there is any. +func (c *roles) Create(role *v1alpha2.Role) (result *v1alpha2.Role, err error) { + result = &v1alpha2.Role{} + err = c.client.Post(). + Resource("roles"). + Body(role). + Do(). + Into(result) + return +} + +// Update takes the representation of a role and updates it. Returns the server's representation of the role, and an error, if there is any. +func (c *roles) Update(role *v1alpha2.Role) (result *v1alpha2.Role, err error) { + result = &v1alpha2.Role{} + err = c.client.Put(). + Resource("roles"). + Name(role.Name). + Body(role). + Do(). + Into(result) + return +} + +// Delete takes name of the role and deletes it. Returns an error if one occurs. +func (c *roles) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Resource("roles"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *roles) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("roles"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched role. +func (c *roles) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.Role, err error) { + result = &v1alpha2.Role{} + err = c.client.Patch(pt). + Resource("roles"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/rolebinding.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/rolebinding.go new file mode 100644 index 000000000..7dffa28a4 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/rolebinding.go @@ -0,0 +1,164 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// RoleBindingsGetter has a method to return a RoleBindingInterface. +// A group's client should implement this interface. +type RoleBindingsGetter interface { + RoleBindings() RoleBindingInterface +} + +// RoleBindingInterface has methods to work with RoleBinding resources. +type RoleBindingInterface interface { + Create(*v1alpha2.RoleBinding) (*v1alpha2.RoleBinding, error) + Update(*v1alpha2.RoleBinding) (*v1alpha2.RoleBinding, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha2.RoleBinding, error) + List(opts v1.ListOptions) (*v1alpha2.RoleBindingList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.RoleBinding, err error) + RoleBindingExpansion +} + +// roleBindings implements RoleBindingInterface +type roleBindings struct { + client rest.Interface +} + +// newRoleBindings returns a RoleBindings +func newRoleBindings(c *IamV1alpha2Client) *roleBindings { + return &roleBindings{ + client: c.RESTClient(), + } +} + +// Get takes name of the roleBinding, and returns the corresponding roleBinding object, and an error if there is any. +func (c *roleBindings) Get(name string, options v1.GetOptions) (result *v1alpha2.RoleBinding, err error) { + result = &v1alpha2.RoleBinding{} + err = c.client.Get(). + Resource("rolebindings"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of RoleBindings that match those selectors. +func (c *roleBindings) List(opts v1.ListOptions) (result *v1alpha2.RoleBindingList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha2.RoleBindingList{} + err = c.client.Get(). + Resource("rolebindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested roleBindings. +func (c *roleBindings) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("rolebindings"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a roleBinding and creates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *roleBindings) Create(roleBinding *v1alpha2.RoleBinding) (result *v1alpha2.RoleBinding, err error) { + result = &v1alpha2.RoleBinding{} + err = c.client.Post(). + Resource("rolebindings"). + Body(roleBinding). + Do(). + Into(result) + return +} + +// Update takes the representation of a roleBinding and updates it. Returns the server's representation of the roleBinding, and an error, if there is any. +func (c *roleBindings) Update(roleBinding *v1alpha2.RoleBinding) (result *v1alpha2.RoleBinding, err error) { + result = &v1alpha2.RoleBinding{} + err = c.client.Put(). + Resource("rolebindings"). + Name(roleBinding.Name). + Body(roleBinding). + Do(). + Into(result) + return +} + +// Delete takes name of the roleBinding and deletes it. Returns an error if one occurs. +func (c *roleBindings) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Resource("rolebindings"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *roleBindings) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("rolebindings"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched roleBinding. +func (c *roleBindings) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.RoleBinding, err error) { + result = &v1alpha2.RoleBinding{} + err = c.client.Patch(pt). + Resource("rolebindings"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 027a8d386..c96a3eb1e 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -68,6 +68,12 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Devops().V1alpha1().S2iRuns().Informer()}, nil // Group=iam.kubesphere.io, Version=v1alpha2 + case v1alpha2.SchemeGroupVersion.WithResource("policyrules"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Iam().V1alpha2().PolicyRules().Informer()}, nil + case v1alpha2.SchemeGroupVersion.WithResource("roles"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Iam().V1alpha2().Roles().Informer()}, nil + case v1alpha2.SchemeGroupVersion.WithResource("rolebindings"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Iam().V1alpha2().RoleBindings().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("users"): return &genericInformer{resource: resource.GroupResource(), informer: f.Iam().V1alpha2().Users().Informer()}, nil diff --git a/pkg/client/informers/externalversions/iam/v1alpha2/interface.go b/pkg/client/informers/externalversions/iam/v1alpha2/interface.go index f75006b77..674febe64 100644 --- a/pkg/client/informers/externalversions/iam/v1alpha2/interface.go +++ b/pkg/client/informers/externalversions/iam/v1alpha2/interface.go @@ -24,6 +24,12 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // PolicyRules returns a PolicyRuleInformer. + PolicyRules() PolicyRuleInformer + // Roles returns a RoleInformer. + Roles() RoleInformer + // RoleBindings returns a RoleBindingInformer. + RoleBindings() RoleBindingInformer // Users returns a UserInformer. Users() UserInformer } @@ -39,6 +45,21 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } +// PolicyRules returns a PolicyRuleInformer. +func (v *version) PolicyRules() PolicyRuleInformer { + return &policyRuleInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// Roles returns a RoleInformer. +func (v *version) Roles() RoleInformer { + return &roleInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// RoleBindings returns a RoleBindingInformer. +func (v *version) RoleBindings() RoleBindingInformer { + return &roleBindingInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + // Users returns a UserInformer. func (v *version) Users() UserInformer { return &userInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/informers/externalversions/iam/v1alpha2/policyrule.go b/pkg/client/informers/externalversions/iam/v1alpha2/policyrule.go new file mode 100644 index 000000000..c5a2fd756 --- /dev/null +++ b/pkg/client/informers/externalversions/iam/v1alpha2/policyrule.go @@ -0,0 +1,88 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1alpha2 "kubesphere.io/kubesphere/pkg/client/listers/iam/v1alpha2" +) + +// PolicyRuleInformer provides access to a shared informer and lister for +// PolicyRules. +type PolicyRuleInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha2.PolicyRuleLister +} + +type policyRuleInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewPolicyRuleInformer constructs a new informer for PolicyRule type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewPolicyRuleInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredPolicyRuleInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredPolicyRuleInformer constructs a new informer for PolicyRule type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredPolicyRuleInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.IamV1alpha2().PolicyRules().List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.IamV1alpha2().PolicyRules().Watch(options) + }, + }, + &iamv1alpha2.PolicyRule{}, + resyncPeriod, + indexers, + ) +} + +func (f *policyRuleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredPolicyRuleInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *policyRuleInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&iamv1alpha2.PolicyRule{}, f.defaultInformer) +} + +func (f *policyRuleInformer) Lister() v1alpha2.PolicyRuleLister { + return v1alpha2.NewPolicyRuleLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/iam/v1alpha2/role.go b/pkg/client/informers/externalversions/iam/v1alpha2/role.go new file mode 100644 index 000000000..af36316ed --- /dev/null +++ b/pkg/client/informers/externalversions/iam/v1alpha2/role.go @@ -0,0 +1,88 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1alpha2 "kubesphere.io/kubesphere/pkg/client/listers/iam/v1alpha2" +) + +// RoleInformer provides access to a shared informer and lister for +// Roles. +type RoleInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha2.RoleLister +} + +type roleInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewRoleInformer constructs a new informer for Role type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewRoleInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredRoleInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredRoleInformer constructs a new informer for Role type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredRoleInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.IamV1alpha2().Roles().List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.IamV1alpha2().Roles().Watch(options) + }, + }, + &iamv1alpha2.Role{}, + resyncPeriod, + indexers, + ) +} + +func (f *roleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredRoleInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *roleInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&iamv1alpha2.Role{}, f.defaultInformer) +} + +func (f *roleInformer) Lister() v1alpha2.RoleLister { + return v1alpha2.NewRoleLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/iam/v1alpha2/rolebinding.go b/pkg/client/informers/externalversions/iam/v1alpha2/rolebinding.go new file mode 100644 index 000000000..5cc80d0d2 --- /dev/null +++ b/pkg/client/informers/externalversions/iam/v1alpha2/rolebinding.go @@ -0,0 +1,88 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1alpha2 "kubesphere.io/kubesphere/pkg/client/listers/iam/v1alpha2" +) + +// RoleBindingInformer provides access to a shared informer and lister for +// RoleBindings. +type RoleBindingInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha2.RoleBindingLister +} + +type roleBindingInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewRoleBindingInformer constructs a new informer for RoleBinding type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewRoleBindingInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredRoleBindingInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredRoleBindingInformer constructs a new informer for RoleBinding type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredRoleBindingInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.IamV1alpha2().RoleBindings().List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.IamV1alpha2().RoleBindings().Watch(options) + }, + }, + &iamv1alpha2.RoleBinding{}, + resyncPeriod, + indexers, + ) +} + +func (f *roleBindingInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredRoleBindingInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *roleBindingInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&iamv1alpha2.RoleBinding{}, f.defaultInformer) +} + +func (f *roleBindingInformer) Lister() v1alpha2.RoleBindingLister { + return v1alpha2.NewRoleBindingLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/listers/iam/v1alpha2/expansion_generated.go b/pkg/client/listers/iam/v1alpha2/expansion_generated.go index b75d28714..5262c5697 100644 --- a/pkg/client/listers/iam/v1alpha2/expansion_generated.go +++ b/pkg/client/listers/iam/v1alpha2/expansion_generated.go @@ -18,6 +18,18 @@ limitations under the License. package v1alpha2 +// PolicyRuleListerExpansion allows custom methods to be added to +// PolicyRuleLister. +type PolicyRuleListerExpansion interface{} + +// RoleListerExpansion allows custom methods to be added to +// RoleLister. +type RoleListerExpansion interface{} + +// RoleBindingListerExpansion allows custom methods to be added to +// RoleBindingLister. +type RoleBindingListerExpansion interface{} + // UserListerExpansion allows custom methods to be added to // UserLister. type UserListerExpansion interface{} diff --git a/pkg/client/listers/iam/v1alpha2/policyrule.go b/pkg/client/listers/iam/v1alpha2/policyrule.go new file mode 100644 index 000000000..ec9d01ea3 --- /dev/null +++ b/pkg/client/listers/iam/v1alpha2/policyrule.go @@ -0,0 +1,65 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" +) + +// PolicyRuleLister helps list PolicyRules. +type PolicyRuleLister interface { + // List lists all PolicyRules in the indexer. + List(selector labels.Selector) (ret []*v1alpha2.PolicyRule, err error) + // Get retrieves the PolicyRule from the index for a given name. + Get(name string) (*v1alpha2.PolicyRule, error) + PolicyRuleListerExpansion +} + +// policyRuleLister implements the PolicyRuleLister interface. +type policyRuleLister struct { + indexer cache.Indexer +} + +// NewPolicyRuleLister returns a new PolicyRuleLister. +func NewPolicyRuleLister(indexer cache.Indexer) PolicyRuleLister { + return &policyRuleLister{indexer: indexer} +} + +// List lists all PolicyRules in the indexer. +func (s *policyRuleLister) List(selector labels.Selector) (ret []*v1alpha2.PolicyRule, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.PolicyRule)) + }) + return ret, err +} + +// Get retrieves the PolicyRule from the index for a given name. +func (s *policyRuleLister) Get(name string) (*v1alpha2.PolicyRule, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha2.Resource("policyrule"), name) + } + return obj.(*v1alpha2.PolicyRule), nil +} diff --git a/pkg/client/listers/iam/v1alpha2/role.go b/pkg/client/listers/iam/v1alpha2/role.go new file mode 100644 index 000000000..15dd8f053 --- /dev/null +++ b/pkg/client/listers/iam/v1alpha2/role.go @@ -0,0 +1,65 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" +) + +// RoleLister helps list Roles. +type RoleLister interface { + // List lists all Roles in the indexer. + List(selector labels.Selector) (ret []*v1alpha2.Role, err error) + // Get retrieves the Role from the index for a given name. + Get(name string) (*v1alpha2.Role, error) + RoleListerExpansion +} + +// roleLister implements the RoleLister interface. +type roleLister struct { + indexer cache.Indexer +} + +// NewRoleLister returns a new RoleLister. +func NewRoleLister(indexer cache.Indexer) RoleLister { + return &roleLister{indexer: indexer} +} + +// List lists all Roles in the indexer. +func (s *roleLister) List(selector labels.Selector) (ret []*v1alpha2.Role, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.Role)) + }) + return ret, err +} + +// Get retrieves the Role from the index for a given name. +func (s *roleLister) Get(name string) (*v1alpha2.Role, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha2.Resource("role"), name) + } + return obj.(*v1alpha2.Role), nil +} diff --git a/pkg/client/listers/iam/v1alpha2/rolebinding.go b/pkg/client/listers/iam/v1alpha2/rolebinding.go new file mode 100644 index 000000000..d3704c296 --- /dev/null +++ b/pkg/client/listers/iam/v1alpha2/rolebinding.go @@ -0,0 +1,65 @@ +/* +Copyright 2019 The KubeSphere 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" +) + +// RoleBindingLister helps list RoleBindings. +type RoleBindingLister interface { + // List lists all RoleBindings in the indexer. + List(selector labels.Selector) (ret []*v1alpha2.RoleBinding, err error) + // Get retrieves the RoleBinding from the index for a given name. + Get(name string) (*v1alpha2.RoleBinding, error) + RoleBindingListerExpansion +} + +// roleBindingLister implements the RoleBindingLister interface. +type roleBindingLister struct { + indexer cache.Indexer +} + +// NewRoleBindingLister returns a new RoleBindingLister. +func NewRoleBindingLister(indexer cache.Indexer) RoleBindingLister { + return &roleBindingLister{indexer: indexer} +} + +// List lists all RoleBindings in the indexer. +func (s *roleBindingLister) List(selector labels.Selector) (ret []*v1alpha2.RoleBinding, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.RoleBinding)) + }) + return ret, err +} + +// Get retrieves the RoleBinding from the index for a given name. +func (s *roleBindingLister) Get(name string) (*v1alpha2.RoleBinding, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha2.Resource("rolebinding"), name) + } + return obj.(*v1alpha2.RoleBinding), nil +} diff --git a/pkg/controller/user/user_webhook.go b/pkg/controller/user/user_webhook.go index 036516be5..dc8631d9f 100644 --- a/pkg/controller/user/user_webhook.go +++ b/pkg/controller/user/user_webhook.go @@ -30,6 +30,10 @@ import ( "strconv" ) +const ( + encryptedAnnotation = "iam.kubesphere.io/password-encrypted" +) + type EmailValidator struct { Client client.Client decoder *admission.Decoder @@ -51,7 +55,11 @@ func (a *EmailValidator) Handle(ctx context.Context, req admission.Request) admi allUsers := v1alpha2.UserList{} - a.Client.List(ctx, &v1alpha2.UserList{}, &client.ListOptions{}) + err = a.Client.List(ctx, &v1alpha2.UserList{}, &client.ListOptions{}) + + if err != nil { + return admission.Errored(http.StatusInternalServerError, err) + } found := emailAlreadyExist(allUsers, email) @@ -78,7 +86,7 @@ func (a *PasswordCipher) Handle(ctx context.Context, req admission.Request) admi return admission.Errored(http.StatusBadRequest, err) } - encrypted, err := strconv.ParseBool(user.Annotations["iam.kubesphere.io/password-encrypted"]) + encrypted, err := strconv.ParseBool(user.Annotations[encryptedAnnotation]) if err != nil || !encrypted { password, err := hashPassword(user.Spec.EncryptedPassword) @@ -86,6 +94,7 @@ func (a *PasswordCipher) Handle(ctx context.Context, req admission.Request) admi return admission.Errored(http.StatusInternalServerError, err) } user.Spec.EncryptedPassword = password + user.Annotations[encryptedAnnotation] = "true" } marshaledUser, err := json.Marshal(user) diff --git a/pkg/kapis/iam/v1alpha2/handler.go b/pkg/kapis/iam/v1alpha2/handler.go index 5c93193c3..37836f233 100644 --- a/pkg/kapis/iam/v1alpha2/handler.go +++ b/pkg/kapis/iam/v1alpha2/handler.go @@ -2,24 +2,24 @@ package v1alpha2 import ( "github.com/emicklei/go-restful" + "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/kubesphere/pkg/api" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options" - "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/models/iam/am" "kubesphere.io/kubesphere/pkg/models/iam/im" - "kubesphere.io/kubesphere/pkg/simple/client/cache" - "kubesphere.io/kubesphere/pkg/simple/client/k8s" - ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap" + "strings" ) type iamHandler struct { - amOperator am.AccessManagementInterface - imOperator im.IdentityManagementInterface + am am.AccessManagementInterface + im im.IdentityManagementInterface } -func newIAMHandler(k8sClient k8s.Client, factory informers.InformerFactory, ldapClient ldappool.Interface, cacheClient cache.Interface, options *authoptions.AuthenticationOptions) *iamHandler { +func newIAMHandler(im im.IdentityManagementInterface, am am.AccessManagementInterface, options *authoptions.AuthenticationOptions) *iamHandler { return &iamHandler{ - amOperator: am.NewAMOperator(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory()), - imOperator: im.NewLDAPOperator(ldapClient), + am: am, + im: im, } } @@ -36,7 +36,22 @@ func (h *iamHandler) ModifyUser(request *restful.Request, response *restful.Resp } func (h *iamHandler) DescribeUser(req *restful.Request, resp *restful.Response) { - panic("implement me") + username := req.PathParameter("user") + user, err := h.im.DescribeUser(username) + if err != nil { + api.HandleInternalError(resp, req, err) + return + } + + globalRole, err := h.am.GetRoleOfUserInTargetScope(iamv1alpha2.GlobalScope, "", username) + + if err != nil { + api.HandleInternalError(resp, req, err) + return + } + result := iamv1alpha2.UserDetail{User: user, GlobalRole: globalRole} + + resp.WriteEntity(result) } func (h *iamHandler) ListUsers(req *restful.Request, resp *restful.Response) { @@ -48,9 +63,39 @@ func (h *iamHandler) ListUserRoles(req *restful.Request, resp *restful.Response) } func (h *iamHandler) ListRoles(req *restful.Request, resp *restful.Response) { - panic("implement me") } + +func (h *iamHandler) ListRolesOfUser(req *restful.Request, resp *restful.Response) { + username := req.PathParameter("user") + + var roles []iamv1alpha2.Role + var err error + + if strings.HasSuffix(req.Request.URL.Path, "workspaceroles") { + roles, err = h.am.ListRolesOfUser(iamv1alpha2.WorkspaceScope, username) + } else if strings.HasSuffix(req.Request.URL.Path, "clusterroles") { + roles, err = h.am.ListRolesOfUser(iamv1alpha2.ClusterScope, username) + } else if strings.HasSuffix(req.Request.URL.Path, "namespaceroles") { + roles, err = h.am.ListRolesOfUser(iamv1alpha2.NamespaceScope, username) + } + + if err != nil { + api.HandleInternalError(resp, req, err) + return + } + + result := iamv1alpha2.RoleList{ + TypeMeta: v1.TypeMeta{ + Kind: "List", + APIVersion: "v1", + }, + ListMeta: v1.ListMeta{}, + Items: roles, + } + + resp.WriteEntity(result) +} func (h *iamHandler) ListClusterRoles(req *restful.Request, resp *restful.Response) { panic("implement me") } diff --git a/pkg/kapis/iam/v1alpha2/register.go b/pkg/kapis/iam/v1alpha2/register.go index 9ea21a33c..4a4fb3cfc 100644 --- a/pkg/kapis/iam/v1alpha2/register.go +++ b/pkg/kapis/iam/v1alpha2/register.go @@ -22,15 +22,14 @@ import ( "github.com/emicklei/go-restful-openapi" "k8s.io/apimachinery/pkg/runtime/schema" "kubesphere.io/kubesphere/pkg/api" + iamvealpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options" "kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/constants" - "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/models" + "kubesphere.io/kubesphere/pkg/models/iam/am" + "kubesphere.io/kubesphere/pkg/models/iam/im" "kubesphere.io/kubesphere/pkg/server/errors" - "kubesphere.io/kubesphere/pkg/simple/client/cache" - "kubesphere.io/kubesphere/pkg/simple/client/k8s" - ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap" "net/http" ) @@ -38,19 +37,38 @@ const groupName = "iam.kubesphere.io" var GroupVersion = schema.GroupVersion{Group: groupName, Version: "v1alpha2"} -func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informers.InformerFactory, ldapClient ldappool.Interface, cacheClient cache.Interface, options *authoptions.AuthenticationOptions) error { +func AddToContainer(container *restful.Container, im im.IdentityManagementInterface, am am.AccessManagementInterface, options *authoptions.AuthenticationOptions) error { ws := runtime.NewWebService(GroupVersion) - handler := newIAMHandler(k8sClient, factory, ldapClient, cacheClient, options) + handler := newIAMHandler(im, am, options) - // implemented by create CRD object. - //ws.Route(ws.POST("/users").To(handler.CreateUser)) - //ws.Route(ws.DELETE("/users/{user}")) - //ws.Route(ws.PUT("/users/{user}")) - //ws.Route(ws.GET("/users/{user}")) + ws.Route(ws.GET("/users/{user}"). + To(handler.DescribeUser). + Doc("Retrieve user details."). + Param(ws.PathParameter("user", "username")). + Returns(http.StatusOK, api.StatusOK, iamvealpha2.UserDetail{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag})) - // TODO move to resources api - //ws.Route(ws.GET("/users")) + ws.Route(ws.GET("/users/{user}/workspaceroles"). + To(handler.ListRolesOfUser). + Doc("Retrieve user roles in workspaces."). + Param(ws.PathParameter("user", "username")). + Returns(http.StatusOK, api.StatusOK, iamvealpha2.RoleList{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag})) + + ws.Route(ws.GET("/users/{user}/clusterroles"). + To(handler.ListRolesOfUser). + Doc("Retrieve user roles in clusters."). + Param(ws.PathParameter("user", "username")). + Returns(http.StatusOK, api.StatusOK, iamvealpha2.RoleList{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag})) + + ws.Route(ws.GET("/users/{user}/namespaceroles"). + To(handler.ListRolesOfUser). + Doc("Retrieve user roles in namespaces."). + Param(ws.PathParameter("user", "username")). + Returns(http.StatusOK, api.StatusOK, iamvealpha2.RoleList{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag})) ws.Route(ws.GET("/namespaces/{namespace}/roles"). To(handler.ListRoles). @@ -104,6 +122,6 @@ func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informer Returns(http.StatusOK, api.StatusOK, errors.Error{}). Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag})) - c.Add(ws) + container.Add(ws) return nil } diff --git a/pkg/kapis/tenant/v1alpha2/handler.go b/pkg/kapis/tenant/v1alpha2/handler.go index ec4385e6b..a4414329d 100644 --- a/pkg/kapis/tenant/v1alpha2/handler.go +++ b/pkg/kapis/tenant/v1alpha2/handler.go @@ -1,196 +1,38 @@ package v1alpha2 import ( + "errors" "github.com/emicklei/go-restful" - v1 "k8s.io/api/core/v1" - k8serr "k8s.io/apimachinery/pkg/api/errors" "k8s.io/klog" "kubesphere.io/kubesphere/pkg/api" - "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/apiserver/request" "kubesphere.io/kubesphere/pkg/informers" - "kubesphere.io/kubesphere/pkg/models/iam/am" - "kubesphere.io/kubesphere/pkg/models/monitoring" - "kubesphere.io/kubesphere/pkg/models/resources/v1alpha2" "kubesphere.io/kubesphere/pkg/models/tenant" - apierr "kubesphere.io/kubesphere/pkg/server/errors" - "kubesphere.io/kubesphere/pkg/server/params" "kubesphere.io/kubesphere/pkg/simple/client/k8s" - "kubesphere.io/kubesphere/pkg/simple/client/mysql" - "net/http" ) type tenantHandler struct { tenant tenant.Interface - am am.AccessManagementInterface } -func newTenantHandler(k8sClient k8s.Client, factory informers.InformerFactory, db *mysql.Database) *tenantHandler { +func newTenantHandler(k8sClient k8s.Client, factory informers.InformerFactory) *tenantHandler { return &tenantHandler{ - tenant: tenant.New(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory(), factory.KubeSphereSharedInformerFactory(), db), - am: am.NewAMOperator(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory()), + tenant: tenant.New(k8sClient, factory), } } func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Response) { - username := req.HeaderParameter(constants.UserNameHeader) - orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime) - limit, offset := params.ParsePaging(req) - reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true) - conditions, err := params.ParseConditions(req) + user, ok := request.UserFrom(req.Request.Context()) - if err != nil { + if !ok { + err := errors.New("cannot obtain user info") klog.Errorln(err) - api.HandleBadRequest(resp, nil, err) + api.HandleForbidden(resp, nil, err) return } - result, err := h.tenant.ListWorkspaces(username, conditions, orderBy, reverse, limit, offset) - - if err != nil { - api.HandleInternalError(resp, nil, err) - return - } - - resp.WriteAsJson(result) -} - -func (h *tenantHandler) DescribeWorkspace(req *restful.Request, resp *restful.Response) { - username := req.HeaderParameter(constants.UserNameHeader) - workspaceName := req.PathParameter("workspace") - - result, err := h.tenant.DescribeWorkspace(username, workspaceName) - - if err != nil { - if k8serr.IsNotFound(err) { - api.HandleNotFound(resp, nil, err) - } else { - api.HandleInternalError(resp, nil, err) - } - return - } - - resp.WriteAsJson(result) -} - -func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Response) { - workspace := req.PathParameter("workspace") - username := req.PathParameter("member") - // /workspaces/{workspace}/members/{username}/namespaces - if username == "" { - // /workspaces/{workspace}/namespaces - username = req.HeaderParameter(constants.UserNameHeader) - } - - orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime) - limit, offset := params.ParsePaging(req) - reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true) - conditions, err := params.ParseConditions(req) - - if err != nil { - api.HandleBadRequest(resp, nil, err) - return - } - - conditions.Match[constants.WorkspaceLabelKey] = workspace - - result, err := h.tenant.ListNamespaces(username, conditions, orderBy, reverse, limit, offset) - - if err != nil { - api.HandleInternalError(resp, nil, err) - return - } - - namespaces := make([]*v1.Namespace, 0) - - for _, item := range result.Items { - namespaces = append(namespaces, item.(*v1.Namespace).DeepCopy()) - } - - namespaces = monitoring.GetNamespacesWithMetrics(namespaces) - - items := make([]interface{}, 0) - - for _, item := range namespaces { - items = append(items, item) - } - - result.Items = items - - resp.WriteAsJson(result) -} - -func (h *tenantHandler) CreateNamespace(req *restful.Request, resp *restful.Response) { - workspace := req.PathParameter("workspace") - username := req.HeaderParameter(constants.UserNameHeader) - var namespace v1.Namespace - err := req.ReadEntity(&namespace) - if err != nil { - api.HandleNotFound(resp, nil, err) - return - } - - _, err = h.tenant.DescribeWorkspace("", workspace) - - if err != nil { - if k8serr.IsNotFound(err) { - api.HandleForbidden(resp, nil, err) - } else { - api.HandleInternalError(resp, nil, err) - } - return - } - - created, err := h.tenant.CreateNamespace(workspace, &namespace, username) - - if err != nil { - if k8serr.IsAlreadyExists(err) { - resp.WriteHeaderAndEntity(http.StatusConflict, err) - } else { - api.HandleInternalError(resp, nil, err) - } - return - } - resp.WriteAsJson(created) -} - -func (h *tenantHandler) DeleteNamespace(req *restful.Request, resp *restful.Response) { - workspace := req.PathParameter("workspace") - namespace := req.PathParameter("namespace") - - err := h.tenant.DeleteNamespace(workspace, namespace) - - if err != nil { - if k8serr.IsNotFound(err) { - api.HandleNotFound(resp, nil, err) - } else { - api.HandleInternalError(resp, nil, err) - } - return - } - - resp.WriteAsJson(apierr.None) -} - -func (h *tenantHandler) ListDevopsProjects(req *restful.Request, resp *restful.Response) { - - workspace := req.PathParameter("workspace") - username := req.PathParameter("member") - if username == "" { - username = req.HeaderParameter(constants.UserNameHeader) - } - orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime) - limit, offset := params.ParsePaging(req) - reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true) - conditions, err := params.ParseConditions(req) - - if err != nil { - api.HandleBadRequest(resp, nil, err) - return - } - conditions.Match["workspace"] = workspace - - result, err := h.tenant.ListDevopsProjects(username, conditions, orderBy, reverse, limit, offset) + result, err := h.tenant.ListWorkspaces(user.GetName()) if err != nil { api.HandleInternalError(resp, nil, err) @@ -200,40 +42,24 @@ func (h *tenantHandler) ListDevopsProjects(req *restful.Request, resp *restful.R resp.WriteEntity(result) } -func (h *tenantHandler) GetDevOpsProjectsCount(req *restful.Request, resp *restful.Response) { - username := req.HeaderParameter(constants.UserNameHeader) +func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Response) { + user, ok := request.UserFrom(req.Request.Context()) - result, err := h.tenant.ListDevopsProjects(username, nil, "", false, 1, 0) - if err != nil { - api.HandleInternalError(resp, nil, err) - return - } - resp.WriteEntity(struct { - Count int `json:"count"` - }{Count: result.TotalCount}) -} -func (h *tenantHandler) DeleteDevopsProject(req *restful.Request, resp *restful.Response) { - projectId := req.PathParameter("devops") - workspace := req.PathParameter("workspace") - username := req.HeaderParameter(constants.UserNameHeader) - - _, err := h.tenant.DescribeWorkspace("", workspace) - - if err != nil { - api.HandleInternalError(resp, req, err) + if !ok { + err := errors.New("cannot obtain user info") + klog.Errorln(err) + api.HandleForbidden(resp, nil, err) return } - err = h.tenant.DeleteDevOpsProject(username, projectId) + worksapceName := req.PathParameter("workspace") + + result, err := h.tenant.ListNamespaces(worksapceName, user.GetName()) if err != nil { api.HandleInternalError(resp, nil, err) return } - resp.WriteEntity(apierr.None) -} - -func (h *tenantHandler) CreateDevopsProject(req *restful.Request, resp *restful.Response) { - + resp.WriteEntity(result) } diff --git a/pkg/kapis/tenant/v1alpha2/register.go b/pkg/kapis/tenant/v1alpha2/register.go index 94b65d4d6..0124aca07 100644 --- a/pkg/kapis/tenant/v1alpha2/register.go +++ b/pkg/kapis/tenant/v1alpha2/register.go @@ -23,17 +23,11 @@ import ( "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime/schema" "kubesphere.io/kubesphere/pkg/api" - devopsv1alpha2 "kubesphere.io/kubesphere/pkg/api/devops/v1alpha2" - "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" "kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/models" - "kubesphere.io/kubesphere/pkg/server/errors" - "kubesphere.io/kubesphere/pkg/server/params" "kubesphere.io/kubesphere/pkg/simple/client/k8s" - "kubesphere.io/kubesphere/pkg/simple/client/mysql" - "net/http" ) @@ -43,95 +37,28 @@ const ( var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"} -func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informers.InformerFactory, db *mysql.Database) error { +func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informers.InformerFactory) error { ws := runtime.NewWebService(GroupVersion) - handler := newTenantHandler(k8sClient, factory, db) + handler := newTenantHandler(k8sClient, factory) ws.Route(ws.GET("/workspaces"). To(handler.ListWorkspaces). Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). Doc("List all workspaces that belongs to the current user"). Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) - ws.Route(ws.GET("/workspaces/{workspace}"). - To(handler.DescribeWorkspace). - Doc("Describe the specified workspace"). - Param(ws.PathParameter("workspace", "workspace name")). - Returns(http.StatusOK, api.StatusOK, v1alpha1.Workspace{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) ws.Route(ws.GET("/workspaces/{workspace}/namespaces"). To(handler.ListNamespaces). Param(ws.PathParameter("workspace", "workspace name")). Doc("List the namespaces of the specified workspace for the current user"). Returns(http.StatusOK, api.StatusOK, []v1.Namespace{}). Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) - ws.Route(ws.GET("/workspaces/{workspace}/members/{member}/namespaces"). + ws.Route(ws.GET("/workspaces/{workspace}/clusters"). To(handler.ListNamespaces). Param(ws.PathParameter("workspace", "workspace name")). Param(ws.PathParameter("member", "workspace member's username")). Doc("List the namespaces for the workspace member"). Returns(http.StatusOK, api.StatusOK, []v1.Namespace{}). Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) - ws.Route(ws.POST("/workspaces/{workspace}/namespaces"). - To(handler.CreateNamespace). - Param(ws.PathParameter("workspace", "workspace name")). - Doc("Create a namespace in the specified workspace"). - Returns(http.StatusOK, api.StatusOK, []v1.Namespace{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) - ws.Route(ws.DELETE("/workspaces/{workspace}/namespaces/{namespace}"). - To(handler.DeleteNamespace). - Param(ws.PathParameter("workspace", "workspace name")). - Param(ws.PathParameter("namespace", "the name of the namespace")). - Doc("Delete the specified namespace from the workspace"). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) - - ws.Route(ws.GET("/workspaces/{workspace}/devops"). - To(handler.ListDevopsProjects). - Param(ws.PathParameter("workspace", "workspace name")). - Param(ws.QueryParameter(params.PagingParam, "page"). - Required(false). - DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1")). - Param(ws.QueryParameter(params.ConditionsParam, "query conditions"). - Required(false). - DataFormat("key=%s,key~%s")). - Doc("List devops projects for the current user"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) - ws.Route(ws.GET("/workspaces/{workspace}/members/{member}/devops"). - To(handler.ListDevopsProjects). - Param(ws.PathParameter("workspace", "workspace name")). - Param(ws.PathParameter("member", "workspace member's username")). - Param(ws.QueryParameter(params.PagingParam, "page"). - Required(false). - DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1")). - Param(ws.QueryParameter(params.ConditionsParam, "query conditions"). - Required(false). - DataFormat("key=%s,key~%s")). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). - Doc("List the devops projects for the workspace member"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) - ws.Route(ws.GET("/devopscount"). - To(handler.GetDevOpsProjectsCount). - Returns(http.StatusOK, api.StatusOK, struct { - Count uint32 `json:"count"` - }{}). - Doc("Get the devops projects count for the member"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) - ws.Route(ws.POST("/workspaces/{workspace}/devops"). - To(handler.CreateDevopsProject). - Param(ws.PathParameter("workspace", "workspace name")). - Doc("Create a devops project in the specified workspace"). - Reads(devopsv1alpha2.DevOpsProject{}). - Returns(http.StatusOK, api.StatusOK, devopsv1alpha2.DevOpsProject{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) - ws.Route(ws.DELETE("/workspaces/{workspace}/devops/{devops}"). - To(handler.DeleteDevopsProject). - Param(ws.PathParameter("workspace", "workspace name")). - Param(ws.PathParameter("devops", "devops project ID")). - Doc("Delete the specified devops project from the workspace"). - Returns(http.StatusOK, api.StatusOK, devopsv1alpha2.DevOpsProject{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) c.Add(ws) return nil diff --git a/pkg/models/iam/am/am.go b/pkg/models/iam/am/am.go index 9a2da7f84..6bf840141 100644 --- a/pkg/models/iam/am/am.go +++ b/pkg/models/iam/am/am.go @@ -18,61 +18,118 @@ package am import ( - "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" - "kubesphere.io/kubesphere/pkg/models/resources/v1alpha2" - "kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/clusterrole" - "kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource" - "kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/role" -) - -const ( - ClusterRoleKind = "ClusterRole" - NamespaceAdminRoleBindName = "admin" - NamespaceViewerRoleBindName = "viewer" + "fmt" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/klog" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "net/http" ) type AccessManagementInterface interface { - GetPlatformRole(username string) (Role, error) - GetClusterRole(cluster, username string) (Role, error) - GetWorkspaceRole(workspace, username string) (Role, error) - GetNamespaceRole(cluster, namespace, username string) (Role, error) -} - -type Role interface { - GetName() string - GetRego() string + ListRolesOfUser(scope iamv1alpha2.Scope, username string) ([]iamv1alpha2.Role, error) + GetRoleOfUserInTargetScope(scope iamv1alpha2.Scope, target string, username string) (*iamv1alpha2.Role, error) + GetPolicyRule(name string) (*iamv1alpha2.PolicyRule, error) } type amOperator struct { - informers informers.SharedInformerFactory - resources resource.ResourceGetter - kubeClient kubernetes.Interface + informers informers.SharedInformerFactory + ksClient kubesphere.Interface } -func NewAMOperator(kubeClient kubernetes.Interface, informers informers.SharedInformerFactory) AccessManagementInterface { - resourceGetter := resource.ResourceGetter{} - resourceGetter.Add(v1alpha2.Role, role.NewRoleSearcher(informers)) - resourceGetter.Add(v1alpha2.ClusterRoles, clusterrole.NewClusterRoleSearcher(informers)) +func NewAMOperator(ksClient kubesphere.Interface, informers informers.SharedInformerFactory) AccessManagementInterface { return &amOperator{ - informers: informers, - resources: resourceGetter, - kubeClient: kubeClient, + informers: informers, + ksClient: ksClient, } } -func (am *amOperator) GetPlatformRole(username string) (Role, error) { - panic("implement me") +func containsUser(subjets []iamv1alpha2.Subject, username string) bool { + for _, sub := range subjets { + if sub.Kind == iamv1alpha2.UserKind && sub.Name == username { + return true + } + } + return false } -func (am *amOperator) GetClusterRole(cluster, username string) (Role, error) { - panic("implement me") +func (am *amOperator) ListRolesOfUser(scope iamv1alpha2.Scope, username string) ([]iamv1alpha2.Role, error) { + + lister := am.informers.Iam().V1alpha2().RoleBindings().Lister() + + roleBindings, err := lister.List(labels.Everything()) + + if err != nil { + klog.Error(err) + return nil, err + } + + roleBindingsInScope := filterRoleBindingByScope(roleBindings, scope) + + roles := make([]iamv1alpha2.Role, 0) + + for _, roleBinding := range roleBindingsInScope { + if containsUser(roleBinding.Subjects, username) { + role, err := am.informers. + Iam().V1alpha2().Roles().Lister().Get(roleBinding.RoleRef.Name) + + if err != nil { + if errors.IsNotFound(err) { + continue + } + return nil, err + } + + roles = append(roles, *role) + } + } + + return roles, nil } -func (am *amOperator) GetWorkspaceRole(workspace, username string) (Role, error) { - panic("implement me") +func filterRoleBindingByScope(roles []*iamv1alpha2.RoleBinding, scope iamv1alpha2.Scope) []*iamv1alpha2.RoleBinding { + result := make([]*iamv1alpha2.RoleBinding, 0) + for _, role := range roles { + if role.Scope == scope { + result = append(result, role) + } + } + return result } -func (am *amOperator) GetNamespaceRole(cluster, namespace, username string) (Role, error) { - panic("implement me") +func (am *amOperator) GetPolicyRule(name string) (*iamv1alpha2.PolicyRule, error) { + lister := am.informers.Iam().V1alpha2().PolicyRules().Lister() + return lister.Get(name) +} + +// Users can only bind one role at each level +func (am *amOperator) GetRoleOfUserInTargetScope(scope iamv1alpha2.Scope, target, username string) (*iamv1alpha2.Role, error) { + roles, err := am.ListRolesOfUser(scope, username) + if err != nil { + klog.Error(err) + return nil, err + } + for _, role := range roles { + if role.Target.Name == iamv1alpha2.TargetAll || + role.Target.Name == target { + return &role, nil + } + } + + err = &errors.StatusError{ErrStatus: metav1.Status{ + Status: metav1.StatusFailure, + Code: http.StatusNotFound, + Reason: metav1.StatusReasonNotFound, + Details: &metav1.StatusDetails{ + Group: iamv1alpha2.SchemeGroupVersion.Group, + Kind: iamv1alpha2.RoleBindingKind, + }, + Message: fmt.Sprintf("role bind not found in %s %s scope", target, scope), + }} + + klog.Error(err) + return nil, err } diff --git a/pkg/models/iam/am/fake_operator.go b/pkg/models/iam/am/fake_operator.go deleted file mode 100644 index 2d83d4133..000000000 --- a/pkg/models/iam/am/fake_operator.go +++ /dev/null @@ -1,141 +0,0 @@ -/* - * - * Copyright 2020 The KubeSphere 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 am - -import ( - "encoding/json" - "fmt" - "k8s.io/apiserver/pkg/authentication/user" - "kubesphere.io/kubesphere/pkg/simple/client/cache" -) - -type FakeRole struct { - Name string - Rego string -} -type FakeOperator struct { - cache cache.Interface -} - -func (f FakeOperator) queryFakeRole(cacheKey string) (Role, error) { - data, err := f.cache.Get(cacheKey) - if err != nil { - if err == cache.ErrNoSuchKey { - return &FakeRole{ - Name: "DenyAll", - Rego: "package authz\ndefault allow = false", - }, nil - } - return nil, err - } - var role FakeRole - err = json.Unmarshal([]byte(data), &role) - if err != nil { - return nil, err - } - return role, nil -} - -func (f FakeOperator) saveFakeRole(cacheKey string, role FakeRole) error { - data, err := json.Marshal(role) - if err != nil { - return err - } - return f.cache.Set(cacheKey, string(data), 0) -} - -func (f FakeOperator) GetPlatformRole(username string) (Role, error) { - return f.queryFakeRole(platformRoleCacheKey(username)) -} - -func (f FakeOperator) GetClusterRole(cluster, username string) (Role, error) { - return f.queryFakeRole(clusterRoleCacheKey(cluster, username)) -} - -func (f FakeOperator) GetWorkspaceRole(workspace, username string) (Role, error) { - return f.queryFakeRole(workspaceRoleCacheKey(workspace, username)) -} - -func (f FakeOperator) GetNamespaceRole(cluster, namespace, username string) (Role, error) { - return f.queryFakeRole(namespaceRoleCacheKey(cluster, namespace, username)) -} - -func (f FakeOperator) Prepare(platformRoles map[string]FakeRole, clusterRoles map[string]map[string]FakeRole, workspaceRoles map[string]map[string]FakeRole, namespaceRoles map[string]map[string]map[string]FakeRole) { - - for username, role := range platformRoles { - f.saveFakeRole(platformRoleCacheKey(username), role) - } - for cluster, roles := range clusterRoles { - for username, role := range roles { - f.saveFakeRole(clusterRoleCacheKey(cluster, username), role) - } - } - - for workspace, roles := range workspaceRoles { - for username, role := range roles { - f.saveFakeRole(workspaceRoleCacheKey(workspace, username), role) - } - } - - for cluster, nsRoles := range namespaceRoles { - for namespace, roles := range nsRoles { - for username, role := range roles { - f.saveFakeRole(namespaceRoleCacheKey(cluster, namespace, username), role) - } - } - } -} - -func namespaceRoleCacheKey(cluster, namespace, username string) string { - return fmt.Sprintf("cluster.%s.namespaces.%s.roles.%s", cluster, namespace, username) -} - -func clusterRoleCacheKey(cluster, username string) string { - return fmt.Sprintf("cluster.%s.roles.%s", cluster, username) -} -func workspaceRoleCacheKey(workspace, username string) string { - return fmt.Sprintf("workspace.%s.roles.%s", workspace, username) -} - -func platformRoleCacheKey(username string) string { - return fmt.Sprintf("platform.roles.%s", username) -} - -func (f FakeRole) GetName() string { - return f.Name -} - -func (f FakeRole) GetRego() string { - return f.Rego -} - -func NewFakeAMOperator() *FakeOperator { - operator := &FakeOperator{cache: cache.NewSimpleCache()} - operator.saveFakeRole(platformRoleCacheKey("admin"), FakeRole{ - Name: "admin", - Rego: "package authz\ndefault allow = true", - }) - operator.saveFakeRole(platformRoleCacheKey(user.Anonymous), FakeRole{ - Name: "admin", - Rego: `package authz -default allow = false -`, - }) - return operator -} diff --git a/pkg/models/resources/v1alpha3/interface.go b/pkg/models/resources/v1alpha3/interface.go index e5fd4c4aa..d639411be 100644 --- a/pkg/models/resources/v1alpha3/interface.go +++ b/pkg/models/resources/v1alpha3/interface.go @@ -46,11 +46,12 @@ func DefaultList(objects []runtime.Object, query *query.Query, compareFunc Compa return compareFunc(filtered[i], filtered[j], query.SortBy) }) - start, end := query.Pagination.GetValidPagination(len(filtered)) + total := len(filtered) + start, end := query.Pagination.GetValidPagination(total) return &api.ListResult{ - Items: objectsToInterfaces(filtered[start:end]), TotalItems: len(filtered), + Items: objectsToInterfaces(filtered[start:end]), } } @@ -101,8 +102,6 @@ func DefaultObjectMetaFilter(item metav1.ObjectMeta, filter query.Filter) bool { // /namespaces?page=1&limit=10&label=kubesphere.io/workspace:system-workspace case query.FieldLabel: return containsAnyValue(item.Labels, string(filter.Value)) - case query.FieldClusterName: - return strings.Compare(item.ClusterName, string(filter.Value)) == 0 default: return false } diff --git a/pkg/models/tenant/devops.go b/pkg/models/tenant/devops.go deleted file mode 100644 index b0cdb6b2a..000000000 --- a/pkg/models/tenant/devops.go +++ /dev/null @@ -1,225 +0,0 @@ -/* - - Copyright 2019 The KubeSphere 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 tenant - -import ( - "fmt" - "github.com/emicklei/go-restful" - "github.com/gocraft/dbr" - "k8s.io/klog" - "kubesphere.io/kubesphere/pkg/api/devops/v1alpha2" - "kubesphere.io/kubesphere/pkg/db" - "kubesphere.io/kubesphere/pkg/models" - "kubesphere.io/kubesphere/pkg/models/devops" - "kubesphere.io/kubesphere/pkg/server/params" - dsClient "kubesphere.io/kubesphere/pkg/simple/client/devops" - "kubesphere.io/kubesphere/pkg/simple/client/mysql" - "net/http" -) - -type DevOpsProjectOperator interface { - ListDevOpsProjects(workspace, username string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error) - CreateDevOpsProject(username string, workspace string, req *v1alpha2.DevOpsProject) (*v1alpha2.DevOpsProject, error) - GetDevOpsProjectsCount(username string) (uint32, error) - DeleteDevOpsProject(projectId, username string) error -} - -type devopsProjectOperator struct { - ksProjectOperator devops.ProjectOperator - db *mysql.Database - dsProject dsClient.ProjectOperator -} - -func newProjectOperator(operator devops.ProjectOperator, db *mysql.Database, client dsClient.ProjectOperator) DevOpsProjectOperator { - return &devopsProjectOperator{ - ksProjectOperator: operator, - db: db, - dsProject: client, - } -} - -func (o *devopsProjectOperator) ListDevOpsProjects(workspace, username string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error) { - - query := o.db.Select(devops.GetColumnsFromStructWithPrefix(devops.DevOpsProjectTableName, v1alpha2.DevOpsProject{})...). - From(devops.DevOpsProjectTableName) - var sqconditions []dbr.Builder - - sqconditions = append(sqconditions, db.Eq(devops.DevOpsProjectWorkSpaceColumn, workspace)) - - switch username { - case devops.KS_ADMIN: - default: - onCondition := fmt.Sprintf("%s = %s", devops.ProjectMembershipProjectIdColumn, devops.DevOpsProjectIdColumn) - query.Join(devops.ProjectMembershipTableName, onCondition) - sqconditions = append(sqconditions, db.Eq(devops.ProjectMembershipUsernameColumn, username)) - sqconditions = append(sqconditions, db.Eq( - devops.ProjectMembershipTableName+"."+devops.StatusColumn, devops.StatusActive)) - } - - sqconditions = append(sqconditions, db.Eq( - devops.DevOpsProjectTableName+"."+devops.StatusColumn, devops.StatusActive)) - if keyword := conditions.Match["keyword"]; keyword != "" { - sqconditions = append(sqconditions, db.Like(devops.DevOpsProjectNameColumn, keyword)) - } - projects := make([]*v1alpha2.DevOpsProject, 0) - - if len(sqconditions) > 0 { - query.Where(db.And(sqconditions...)) - } - switch orderBy { - case "name": - if reverse { - query.OrderDesc(devops.DevOpsProjectNameColumn) - } else { - query.OrderAsc(devops.DevOpsProjectNameColumn) - } - default: - if reverse { - query.OrderAsc(devops.DevOpsProjectCreateTimeColumn) - } else { - query.OrderDesc(devops.DevOpsProjectCreateTimeColumn) - } - - } - query.Limit(uint64(limit)) - query.Offset(uint64(offset)) - _, err := query.Load(&projects) - if err != nil { - klog.Errorf("%+v", err) - return nil, restful.NewError(http.StatusInternalServerError, err.Error()) - } - count, err := query.Count() - if err != nil { - klog.Errorf("%+v", err) - return nil, restful.NewError(http.StatusInternalServerError, err.Error()) - } - - result := make([]interface{}, 0) - for _, v := range projects { - result = append(result, v) - } - - return &models.PageableResponse{Items: result, TotalCount: int(count)}, nil -} - -func (o *devopsProjectOperator) GetDevOpsProjectsCount(username string) (uint32, error) { - - query := o.db.Select(devops.GetColumnsFromStructWithPrefix(devops.DevOpsProjectTableName, v1alpha2.DevOpsProject{})...). - From(devops.DevOpsProjectTableName) - var sqconditions []dbr.Builder - - if username != devops.KS_ADMIN { - onCondition := fmt.Sprintf("%s = %s", devops.ProjectMembershipProjectIdColumn, devops.DevOpsProjectIdColumn) - query.Join(devops.ProjectMembershipTableName, onCondition) - sqconditions = append(sqconditions, db.Eq(devops.ProjectMembershipUsernameColumn, username)) - sqconditions = append(sqconditions, db.Eq( - devops.ProjectMembershipTableName+"."+devops.StatusColumn, devops.StatusActive)) - } - - sqconditions = append(sqconditions, db.Eq( - devops.DevOpsProjectTableName+"."+devops.StatusColumn, devops.StatusActive)) - if len(sqconditions) > 0 { - query.Where(db.And(sqconditions...)) - } - count, err := query.Count() - if err != nil { - klog.Errorf("%+v", err) - return 0, restful.NewError(http.StatusInternalServerError, err.Error()) - } - return count, nil -} - -func (o *devopsProjectOperator) DeleteDevOpsProject(projectId, username string) error { - err := o.ksProjectOperator.CheckProjectUserInRole(username, projectId, []string{dsClient.ProjectOwner}) - if err != nil { - klog.Errorf("%+v", err) - return restful.NewError(http.StatusForbidden, err.Error()) - } - - err = o.dsProject.DeleteDevOpsProject(projectId) - if err != nil { - klog.Errorf("%+v", err) - return err - } - _, err = o.db.DeleteFrom(devops.ProjectMembershipTableName). - Where(db.Eq(devops.ProjectMembershipProjectIdColumn, projectId)).Exec() - if err != nil { - klog.Errorf("%+v", err) - return err - } - _, err = o.db.Update(devops.DevOpsProjectTableName). - Set(devops.StatusColumn, devops.StatusDeleted). - Where(db.Eq(devops.DevOpsProjectIdColumn, projectId)).Exec() - if err != nil { - klog.Errorf("%+v", err) - return err - } - project := &v1alpha2.DevOpsProject{} - err = o.db.Select(devops.DevOpsProjectColumns...). - From(devops.DevOpsProjectTableName). - Where(db.Eq(devops.DevOpsProjectIdColumn, projectId)). - LoadOne(project) - if err != nil { - klog.Errorf("%+v", err) - return err - } - return nil -} - -func (o *devopsProjectOperator) CreateDevOpsProject(username string, workspace string, req *v1alpha2.DevOpsProject) (*v1alpha2.DevOpsProject, error) { - - project := devops.NewDevOpsProject(req.Name, req.Description, username, req.Extra, workspace) - _, err := o.dsProject.CreateDevOpsProject(username, project) - if err != nil { - klog.Error(err) - return nil, err - } - _, err = o.db.InsertInto(devops.DevOpsProjectTableName). - Columns(devops.DevOpsProjectColumns...).Record(project).Exec() - if err != nil { - klog.Errorf("%+v", err) - return nil, restful.NewError(http.StatusInternalServerError, err.Error()) - } - - projectMembership := devops.NewDevOpsProjectMemberShip(username, project.ProjectId, dsClient.ProjectOwner, username) - _, err = o.db.InsertInto(devops.ProjectMembershipTableName). - Columns(devops.ProjectMembershipColumns...).Record(projectMembership).Exec() - if err != nil { - klog.Errorf("%+v", err) - return nil, restful.NewError(http.StatusInternalServerError, err.Error()) - } - return project, nil -} - -func (o *devopsProjectOperator) getProjectUserRole(username, projectId string) (string, error) { - if username == devops.KS_ADMIN { - return dsClient.ProjectOwner, nil - } - - membership := &dsClient.ProjectMembership{} - err := o.db.Select(devops.ProjectMembershipColumns...). - From(devops.ProjectMembershipTableName). - Where(db.And( - db.Eq(devops.ProjectMembershipUsernameColumn, username), - db.Eq(devops.ProjectMembershipProjectIdColumn, projectId))).LoadOne(membership) - if err != nil { - return "", err - } - - return membership.Role, nil -} diff --git a/pkg/models/tenant/namespaces.go b/pkg/models/tenant/namespaces.go deleted file mode 100644 index b8ea11a5c..000000000 --- a/pkg/models/tenant/namespaces.go +++ /dev/null @@ -1,115 +0,0 @@ -/* - - Copyright 2019 The KubeSphere 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 tenant - -import ( - "k8s.io/api/core/v1" - k8sinformers "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" - "kubesphere.io/kubesphere/pkg/constants" - "kubesphere.io/kubesphere/pkg/models/iam/am" - "kubesphere.io/kubesphere/pkg/models/resources/v1alpha2" - "kubesphere.io/kubesphere/pkg/server/params" - "kubesphere.io/kubesphere/pkg/utils/sliceutil" - "strings" -) - -type NamespaceInterface interface { - Search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error) - CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error) -} - -type namespaceSearcher struct { - k8s kubernetes.Interface - informers k8sinformers.SharedInformerFactory - am am.AccessManagementInterface -} - -func (s *namespaceSearcher) CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error) { - if namespace.Labels == nil { - namespace.Labels = make(map[string]string, 0) - } - if username != "" { - namespace.Annotations[constants.CreatorAnnotationKey] = username - } - - namespace.Labels[constants.WorkspaceLabelKey] = workspace - - return s.k8s.CoreV1().Namespaces().Create(namespace) -} - -func newNamespaceOperator(k8s kubernetes.Interface, informers k8sinformers.SharedInformerFactory, am am.AccessManagementInterface) NamespaceInterface { - return &namespaceSearcher{k8s: k8s, informers: informers, am: am} -} - -func (s *namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool { - for k, v := range match { - switch k { - case v1alpha2.Name: - names := strings.Split(v, "|") - if !sliceutil.HasString(names, item.Name) { - return false - } - case v1alpha2.Keyword: - if !strings.Contains(item.Name, v) && !contains(item.Labels, "", v) && !contains(item.Annotations, "", v) { - return false - } - default: - // label not exist or value not equal - if val, ok := item.Labels[k]; !ok || val != v { - return false - } - } - } - return true -} - -func (s *namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool { - - for k, v := range fuzzy { - switch k { - case v1alpha2.Name: - if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { - return false - } - default: - return false - } - } - - return true -} - -func (s *namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool { - switch orderBy { - case "createTime": - return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time) - case "name": - fallthrough - default: - return strings.Compare(a.Name, b.Name) <= 0 - } -} - -func (s *namespaceSearcher) GetNamespaces(username string) ([]*v1.Namespace, error) { - panic("implement me") -} - -func (s *namespaceSearcher) Search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error) { - panic("implement me") -} diff --git a/pkg/models/tenant/tenant.go b/pkg/models/tenant/tenant.go index dd3ace488..038967d84 100644 --- a/pkg/models/tenant/tenant.go +++ b/pkg/models/tenant/tenant.go @@ -18,97 +18,147 @@ package tenant import ( - "k8s.io/api/core/v1" - k8sinformers "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" - "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" - ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" - "kubesphere.io/kubesphere/pkg/models" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" + "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/models/iam/am" - "kubesphere.io/kubesphere/pkg/server/params" - "kubesphere.io/kubesphere/pkg/simple/client/mysql" + "kubesphere.io/kubesphere/pkg/simple/client/k8s" ) type Interface interface { - CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error) - DeleteNamespace(workspace, namespace string) error - DescribeWorkspace(username, workspace string) (*v1alpha1.Workspace, error) - ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) - ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) - ListDevopsProjects(username string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error) - CountDevOpsProjects(username string) (uint32, error) - DeleteDevOpsProject(username, projectId string) error + ListWorkspaces(username string) (*api.ListResult, error) + ListNamespaces(username, workspace string) (*api.ListResult, error) } type tenantOperator struct { - workspaces WorkspaceInterface - namespaces NamespaceInterface - am am.AccessManagementInterface - devops DevOpsProjectOperator + informers informers.InformerFactory + am am.AccessManagementInterface } -func (t *tenantOperator) CountDevOpsProjects(username string) (uint32, error) { - return t.devops.GetDevOpsProjectsCount(username) -} - -func (t *tenantOperator) DeleteDevOpsProject(username, projectId string) error { - return t.devops.DeleteDevOpsProject(projectId, username) -} - -func (t *tenantOperator) GetUserDevopsSimpleRules(username string, projectId string) (interface{}, error) { - panic("implement me") -} - -func (t *tenantOperator) ListDevopsProjects(username string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error) { - return t.devops.ListDevOpsProjects(conditions.Match["workspace"], username, conditions, orderBy, reverse, limit, offset) -} - -func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error { - return t.workspaces.DeleteNamespace(workspace, namespace) -} - -func New(client kubernetes.Interface, informers k8sinformers.SharedInformerFactory, ksinformers ksinformers.SharedInformerFactory, db *mysql.Database) Interface { - amOperator := am.NewAMOperator(client, informers) +func New(k8sClient k8s.Client, informers informers.InformerFactory) Interface { return &tenantOperator{ - workspaces: newWorkspaceOperator(client, informers, ksinformers, amOperator, db), - namespaces: newNamespaceOperator(client, informers, amOperator), - am: amOperator, + informers: informers, + am: am.NewAMOperator(k8sClient.KubeSphere(), informers.KubeSphereSharedInformerFactory()), } } -func (t *tenantOperator) CreateNamespace(workspaceName string, namespace *v1.Namespace, username string) (*v1.Namespace, error) { - return t.namespaces.CreateNamespace(workspaceName, namespace, username) -} - -func (t *tenantOperator) DescribeWorkspace(username, workspaceName string) (*v1alpha1.Workspace, error) { - workspace, err := t.workspaces.GetWorkspace(workspaceName) +func (t *tenantOperator) ListWorkspaces(username string) (*api.ListResult, error) { + workspaceRoles, err := t.am.ListRolesOfUser(iamv1alpha2.WorkspaceScope, username) if err != nil { + klog.Error(err) return nil, err } - return workspace, nil -} + workspaces := make([]*tenantv1alpha1.Workspace, 0) -func (t *tenantOperator) ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { - panic("implement me") -} + for _, role := range workspaceRoles { -func (t *tenantOperator) ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { + // all workspaces are allowed + if role.Target.Name == iamv1alpha2.TargetAll { + workspaces, err = t.informers.KubeSphereSharedInformerFactory(). + Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything()) + break + } + workspace, err := t.informers.KubeSphereSharedInformerFactory(). + Tenant().V1alpha1().Workspaces().Lister().Get(role.Target.Name) - namespaces, err := t.namespaces.Search(username, conditions, orderBy, reverse) - - if err != nil { - return nil, err - } - - // limit offset - result := make([]interface{}, 0) - for i, v := range namespaces { - if len(result) < limit && i >= offset { - result = append(result, v) + if errors.IsNotFound(err) { + klog.Warningf("workspace role: %s found but workspace not exist", role.Target) + continue + } + if err != nil { + klog.Error(err) + return nil, err + } + if !containsWorkspace(workspaces, workspace) { + workspaces = append(workspaces, workspace) } } - return &models.PageableResponse{Items: result, TotalCount: len(namespaces)}, nil + return &api.ListResult{ + TotalItems: len(workspaces), + Items: workspacesToInterfaces(workspaces), + }, nil +} + +func (t *tenantOperator) ListNamespaces(username, workspace string) (*api.ListResult, error) { + + namespaceRoles, err := t.am.ListRolesOfUser(iamv1alpha2.NamespaceScope, username) + + if err != nil { + klog.Error(err) + return nil, err + } + + namespaces := make([]*corev1.Namespace, 0) + + for _, role := range namespaceRoles { + + // all workspaces are allowed + if role.Target.Name == iamv1alpha2.TargetAll { + namespaces, err = t.informers.KubernetesSharedInformerFactory(). + Core().V1().Namespaces().Lister().List(labels.Everything()) + break + } + + namespace, err := t.informers.KubernetesSharedInformerFactory(). + Core().V1().Namespaces().Lister().Get(role.Target.Name) + + if errors.IsNotFound(err) { + klog.Warningf("workspace role: %s found but workspace not exist", role.Target) + continue + } + if err != nil { + klog.Error(err) + return nil, err + } + if !containsNamespace(namespaces, namespace) { + namespaces = append(namespaces, namespace) + } + } + + return &api.ListResult{ + TotalItems: len(namespaces), + Items: namespacesToInterfaces(namespaces), + }, nil +} + +func containsWorkspace(workspaces []*tenantv1alpha1.Workspace, workspace *tenantv1alpha1.Workspace) bool { + for _, item := range workspaces { + if item.Name == workspace.Name { + return true + } + } + return false +} + +func containsNamespace(namespaces []*corev1.Namespace, namespace *corev1.Namespace) bool { + for _, item := range namespaces { + if item.Name == namespace.Name { + return true + } + } + return false +} + +func workspacesToInterfaces(workspaces []*tenantv1alpha1.Workspace) []interface{} { + ret := make([]interface{}, len(workspaces)) + for index, v := range workspaces { + ret[index] = v + } + return ret +} + +func namespacesToInterfaces(namespaces []*corev1.Namespace) []interface{} { + ret := make([]interface{}, len(namespaces)) + for index, v := range namespaces { + ret[index] = v + } + return ret } diff --git a/pkg/models/tenant/workspaces.go b/pkg/models/tenant/workspaces.go deleted file mode 100644 index 346c5ec00..000000000 --- a/pkg/models/tenant/workspaces.go +++ /dev/null @@ -1,263 +0,0 @@ -/* - * - * Copyright 2020 The KubeSphere 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 tenant - -import ( - core "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" - iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" - "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" - "kubesphere.io/kubesphere/pkg/client/informers/externalversions" - "kubesphere.io/kubesphere/pkg/constants" - "kubesphere.io/kubesphere/pkg/db" - "kubesphere.io/kubesphere/pkg/models/devops" - "kubesphere.io/kubesphere/pkg/models/iam/am" - "kubesphere.io/kubesphere/pkg/models/resources/v1alpha2" - "kubesphere.io/kubesphere/pkg/server/params" - "kubesphere.io/kubesphere/pkg/simple/client/mysql" - "kubesphere.io/kubesphere/pkg/utils/sliceutil" - "strings" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" -) - -type InWorkspaceUser struct { - *iamv1alpha2.User - WorkspaceRole string `json:"workspaceRole"` -} - -type WorkspaceInterface interface { - GetWorkspace(workspace string) (*v1alpha1.Workspace, error) - SearchWorkspace(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error) - ListNamespaces(workspace string) ([]*core.Namespace, error) - DeleteNamespace(workspace, namespace string) error - RemoveUser(user, workspace string) error - AddUser(workspace string, user *InWorkspaceUser) error - CountDevopsProjectsInWorkspace(workspace string) (int, error) - CountUsersInWorkspace(workspace string) (int, error) - CountOrgRoles() (int, error) - CountWorkspaces() (int, error) - CountNamespacesInWorkspace(workspace string) (int, error) -} - -type workspaceOperator struct { - client kubernetes.Interface - informers informers.SharedInformerFactory - ksInformers externalversions.SharedInformerFactory - am am.AccessManagementInterface - - // TODO: use db interface instead of mysql client - // we can refactor this after rewrite devops using crd - db *mysql.Database -} - -func newWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, am am.AccessManagementInterface, db *mysql.Database) WorkspaceInterface { - return &workspaceOperator{ - client: client, - informers: informers, - ksInformers: ksinformers, - am: am, - db: db, - } -} - -func (w *workspaceOperator) ListNamespaces(workspace string) ([]*core.Namespace, error) { - namespaces, err := w.informers.Core().V1().Namespaces().Lister().List(labels.SelectorFromSet(labels.Set{constants.WorkspaceLabelKey: workspace})) - - if err != nil { - return nil, err - } - - return namespaces, nil -} - -func (w *workspaceOperator) DeleteNamespace(workspace string, namespace string) error { - ns, err := w.informers.Core().V1().Namespaces().Lister().Get(namespace) - if err != nil { - return err - } - - if ns.Labels[constants.WorkspaceLabelKey] == workspace { - deletePolicy := metav1.DeletePropagationBackground - return w.client.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy}) - } else { - return apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: "workspace"}, workspace) - } -} - -func (w *workspaceOperator) RemoveUser(workspace string, username string) error { - panic("implement me") -} - -func (w *workspaceOperator) AddUser(workspaceName string, user *InWorkspaceUser) error { - - panic("implement me") -} - -func (w *workspaceOperator) CountDevopsProjectsInWorkspace(workspaceName string) (int, error) { - query := w.db.Select(devops.DevOpsProjectIdColumn). - From(devops.DevOpsProjectTableName). - Where(db.And(db.Eq(devops.DevOpsProjectWorkSpaceColumn, workspaceName), - db.Eq(devops.StatusColumn, devops.StatusActive))) - - devOpsProjects := make([]string, 0) - - if _, err := query.Load(&devOpsProjects); err != nil { - return 0, err - } - return len(devOpsProjects), nil -} - -func (w *workspaceOperator) CountUsersInWorkspace(workspace string) (int, error) { - count, err := w.CountUsersInWorkspace(workspace) - if err != nil { - return 0, err - } - return count, nil -} - -func (w *workspaceOperator) CountOrgRoles() (int, error) { - return len(constants.WorkSpaceRoles), nil -} - -func (w *workspaceOperator) CountNamespacesInWorkspace(workspace string) (int, error) { - ns, err := w.ListNamespaces(workspace) - if err != nil { - return 0, err - } - - return len(ns), nil -} - -func (*workspaceOperator) match(match map[string]string, item *v1alpha1.Workspace) bool { - for k, v := range match { - switch k { - case v1alpha2.Name: - names := strings.Split(v, "|") - if !sliceutil.HasString(names, item.Name) { - return false - } - case v1alpha2.Keyword: - if !strings.Contains(item.Name, v) && !contains(item.Labels, "", v) && !contains(item.Annotations, "", v) { - return false - } - default: - // label not exist or value not equal - if val, ok := item.Labels[k]; !ok || val != v { - return false - } - } - } - return true -} - -func (*workspaceOperator) fuzzy(fuzzy map[string]string, item *v1alpha1.Workspace) bool { - - for k, v := range fuzzy { - switch k { - case v1alpha2.Name: - if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { - return false - } - default: - return false - } - } - - return true -} - -func (*workspaceOperator) compare(a, b *v1alpha1.Workspace, orderBy string) bool { - switch orderBy { - case v1alpha2.CreateTime: - return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time) - case v1alpha2.Name: - fallthrough - default: - return strings.Compare(a.Name, b.Name) <= 0 - } -} - -func (w *workspaceOperator) SearchWorkspace(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error) { - panic("implement me") -} - -func (w *workspaceOperator) GetWorkspace(workspaceName string) (*v1alpha1.Workspace, error) { - return w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName) -} - -func contains(m map[string]string, key, value string) bool { - for k, v := range m { - if key == "" { - if strings.Contains(k, value) || strings.Contains(v, value) { - return true - } - } else if k == key && strings.Contains(v, value) { - return true - } - } - return false -} - -/* -// TODO: move to metrics package -func GetAllProjectNums() (int, error) { - namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister() - list, err := namespaceLister.List(labels.Everything()) - if err != nil { - return 0, err - } - return len(list), nil -} - -func GetAllDevOpsProjectsNums() (int, error) { - _, err := clientset.ClientSets().Devops() - if _, notEnabled := err.(clientset.ClientSetNotEnabledError); notEnabled { - return 0, err - } - - dbconn, err := clientset.ClientSets().MySQL() - if err != nil { - return 0, err - } - - query := dbconn.Select(devops.DevOpsProjectIdColumn). - From(devops.DevOpsProjectTableName). - Where(db.Eq(devops.StatusColumn, devops.StatusActive)) - - devOpsProjects := make([]string, 0) - - if _, err := query.Load(&devOpsProjects); err != nil { - return 0, err - } - return len(devOpsProjects), nil -} -*/ - -func (w *workspaceOperator) CountWorkspaces() (int, error) { - ws, err := w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything()) - if err != nil { - return 0, err - } - - return len(ws), nil -}