From 3525fc5507366adda1265feee9123c734f574647 Mon Sep 17 00:00:00 2001 From: hongming Date: Mon, 20 Jul 2020 17:12:48 +0800 Subject: [PATCH] add federatednamespaces tenant API Signed-off-by: hongming --- hack/generate_client.sh | 2 +- pkg/apis/types/v1beta1/doc.go | 20 ++ pkg/apis/types/v1beta1/register.go | 48 ++++ pkg/apis/types/v1beta1/types.go | 86 +++++++ .../types/v1beta1/zz_generated.deepcopy.go | 225 ++++++++++++++++++ pkg/apiserver/apiserver.go | 5 + pkg/client/clientset/versioned/clientset.go | 14 ++ .../versioned/fake/clientset_generated.go | 7 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/register.go | 2 + .../versioned/typed/types/v1beta1/doc.go | 20 ++ .../versioned/typed/types/v1beta1/fake/doc.go | 20 ++ .../v1beta1/fake/fake_federatednamespace.go | 120 ++++++++++ .../types/v1beta1/fake/fake_types_client.go | 40 ++++ .../typed/types/v1beta1/federatednamespace.go | 164 +++++++++++++ .../types/v1beta1/generated_expansion.go | 21 ++ .../typed/types/v1beta1/types_client.go | 89 +++++++ .../informers/externalversions/factory.go | 6 + .../informers/externalversions/generic.go | 5 + .../externalversions/types/interface.go | 46 ++++ .../types/v1beta1/federatednamespace.go | 88 +++++++ .../types/v1beta1/interface.go | 45 ++++ .../types/v1beta1/expansion_generated.go | 23 ++ .../types/v1beta1/federatednamespace.go | 65 +++++ pkg/kapis/tenant/v1alpha2/handler.go | 23 ++ pkg/kapis/tenant/v1alpha2/register.go | 13 + .../federatednamespace/federatednamespaces.go | 73 ++++++ .../federatednamespaces_test.go | 17 ++ .../resources/v1alpha3/resource/resource.go | 5 + pkg/models/tenant/tenant.go | 81 +++++++ 30 files changed, 1374 insertions(+), 1 deletion(-) create mode 100644 pkg/apis/types/v1beta1/doc.go create mode 100644 pkg/apis/types/v1beta1/register.go create mode 100644 pkg/apis/types/v1beta1/types.go create mode 100644 pkg/apis/types/v1beta1/zz_generated.deepcopy.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta1/doc.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta1/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta1/fake/fake_federatednamespace.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta1/fake/fake_types_client.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta1/federatednamespace.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta1/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/types/v1beta1/types_client.go create mode 100644 pkg/client/informers/externalversions/types/interface.go create mode 100644 pkg/client/informers/externalversions/types/v1beta1/federatednamespace.go create mode 100644 pkg/client/informers/externalversions/types/v1beta1/interface.go create mode 100644 pkg/client/listers/types/v1beta1/expansion_generated.go create mode 100644 pkg/client/listers/types/v1beta1/federatednamespace.go create mode 100644 pkg/models/resources/v1alpha3/federatednamespace/federatednamespaces.go create mode 100644 pkg/models/resources/v1alpha3/federatednamespace/federatednamespaces_test.go diff --git a/hack/generate_client.sh b/hack/generate_client.sh index cc157212c..94ae37d3f 100755 --- a/hack/generate_client.sh +++ b/hack/generate_client.sh @@ -2,7 +2,7 @@ set -e -GV="network:v1alpha1 servicemesh:v1alpha2 tenant:v1alpha1 tenant:v1alpha2 devops:v1alpha1 iam:v1alpha2 devops:v1alpha3 cluster:v1alpha1 storage:v1alpha1 auditing:v1alpha1" +GV="network:v1alpha1 servicemesh:v1alpha2 tenant:v1alpha1 tenant:v1alpha2 devops:v1alpha1 iam:v1alpha2 devops:v1alpha3 cluster:v1alpha1 storage:v1alpha1 auditing:v1alpha1 types:v1beta1" rm -rf ./pkg/client ./hack/generate_group.sh "client,lister,informer" kubesphere.io/kubesphere/pkg/client kubesphere.io/kubesphere/pkg/apis "$GV" --output-base=./ -h "$PWD/hack/boilerplate.go.txt" diff --git a/pkg/apis/types/v1beta1/doc.go b/pkg/apis/types/v1beta1/doc.go new file mode 100644 index 000000000..3b35fcc94 --- /dev/null +++ b/pkg/apis/types/v1beta1/doc.go @@ -0,0 +1,20 @@ +/* +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. +*/ + +// +k8s:deepcopy-gen=package,register +// +k8s:defaulter-gen=TypeMeta +// +groupName=types.kubefed.io +package v1beta1 diff --git a/pkg/apis/types/v1beta1/register.go b/pkg/apis/types/v1beta1/register.go new file mode 100644 index 000000000..289ae7364 --- /dev/null +++ b/pkg/apis/types/v1beta1/register.go @@ -0,0 +1,48 @@ +/* +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. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:defaulter-gen=TypeMeta +// +groupName=types.kubefed.io +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "types.kubefed.io", Version: "v1beta1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + + // AddToScheme is required by pkg/client/... + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource is required by pkg/client/listers/... +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +func init() { + SchemeBuilder.Register(&FederatedNamespace{}, &FederatedNamespaceList{}) +} diff --git a/pkg/apis/types/v1beta1/types.go b/pkg/apis/types/v1beta1/types.go new file mode 100644 index 000000000..80dd20c61 --- /dev/null +++ b/pkg/apis/types/v1beta1/types.go @@ -0,0 +1,86 @@ +/* + + 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 v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +const ( + ResourcesPluralFedNamespace = "federatednamespaces" + ResourcesSingularFedNamespace = "federatednamespace" + FedNamespaceKind = "FederatedNamespace" +) + +type Placement struct { + Clusters []Cluster `json:"clusters,omitempty"` + ClusterSelector *ClusterSelector `json:"clusterSelector,omitempty"` +} + +type ClusterSelector struct { + MatchLabels map[string]string `json:"matchLabels,omitempty"` +} + +type Cluster struct { + Name string `json:"name"` +} + +type Override struct { + ClusterName string `json:"clusterName"` + ClusterOverrides []ClusterOverride `json:"clusterOverrides"` +} + +type ClusterOverride struct { + Path string `json:"path"` + Op string `json:"op,omitempty"` + Value runtime.RawExtension `json:"value"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:nonNamespaced +type FederatedNamespace struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec FederatedNamespaceSpec `json:"spec"` +} + +type FederatedNamespaceSpec struct { + Template NamespaceTemplate `json:"template"` + Placement Placement `json:"placement"` + Overrides []Override `json:"overrides,omitempty"` +} + +type NamespaceTemplate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec corev1.NamespaceSpec `json:"spec,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:nonNamespaced + +// FederatedNamespaceList contains a list of federatednamespacelists +type FederatedNamespaceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []FederatedNamespace `json:"items"` +} diff --git a/pkg/apis/types/v1beta1/zz_generated.deepcopy.go b/pkg/apis/types/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 000000000..99bec5968 --- /dev/null +++ b/pkg/apis/types/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,225 @@ +// +build !ignore_autogenerated + +/* +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. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Cluster) DeepCopyInto(out *Cluster) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. +func (in *Cluster) DeepCopy() *Cluster { + if in == nil { + return nil + } + out := new(Cluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterOverride) DeepCopyInto(out *ClusterOverride) { + *out = *in + in.Value.DeepCopyInto(&out.Value) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterOverride. +func (in *ClusterOverride) DeepCopy() *ClusterOverride { + if in == nil { + return nil + } + out := new(ClusterOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterSelector) DeepCopyInto(out *ClusterSelector) { + *out = *in + if in.MatchLabels != nil { + in, out := &in.MatchLabels, &out.MatchLabels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSelector. +func (in *ClusterSelector) DeepCopy() *ClusterSelector { + if in == nil { + return nil + } + out := new(ClusterSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FederatedNamespace) DeepCopyInto(out *FederatedNamespace) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNamespace. +func (in *FederatedNamespace) DeepCopy() *FederatedNamespace { + if in == nil { + return nil + } + out := new(FederatedNamespace) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNamespace) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FederatedNamespaceList) DeepCopyInto(out *FederatedNamespaceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]FederatedNamespace, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNamespaceList. +func (in *FederatedNamespaceList) DeepCopy() *FederatedNamespaceList { + if in == nil { + return nil + } + out := new(FederatedNamespaceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FederatedNamespaceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FederatedNamespaceSpec) DeepCopyInto(out *FederatedNamespaceSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) + in.Placement.DeepCopyInto(&out.Placement) + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = make([]Override, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNamespaceSpec. +func (in *FederatedNamespaceSpec) DeepCopy() *FederatedNamespaceSpec { + if in == nil { + return nil + } + out := new(FederatedNamespaceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NamespaceTemplate) DeepCopyInto(out *NamespaceTemplate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespaceTemplate. +func (in *NamespaceTemplate) DeepCopy() *NamespaceTemplate { + if in == nil { + return nil + } + out := new(NamespaceTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Override) DeepCopyInto(out *Override) { + *out = *in + if in.ClusterOverrides != nil { + in, out := &in.ClusterOverrides, &out.ClusterOverrides + *out = make([]ClusterOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Override. +func (in *Override) DeepCopy() *Override { + if in == nil { + return nil + } + out := new(Override) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Placement) DeepCopyInto(out *Placement) { + *out = *in + if in.Clusters != nil { + in, out := &in.Clusters, &out.Clusters + *out = make([]Cluster, len(*in)) + copy(*out, *in) + } + if in.ClusterSelector != nil { + in, out := &in.ClusterSelector, &out.ClusterSelector + *out = new(ClusterSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Placement. +func (in *Placement) DeepCopy() *Placement { + if in == nil { + return nil + } + out := new(Placement) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 9a7cb507e..9547fe5f3 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -30,6 +30,7 @@ import ( clusterv1alpha1 "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" + typesv1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" audit "kubesphere.io/kubesphere/pkg/apiserver/auditing" "kubesphere.io/kubesphere/pkg/apiserver/authentication/authenticators/basic" "kubesphere.io/kubesphere/pkg/apiserver/authentication/authenticators/jwttoken" @@ -400,6 +401,10 @@ func (s *APIServer) waitForResourceSync(stopCh <-chan struct{}) error { ksGVRs = append(ksGVRs, servicemeshGVRs...) } + if s.Config.MultiClusterOptions.Enable { + ksGVRs = append(ksGVRs, typesv1beta1.SchemeGroupVersion.WithResource(typesv1beta1.ResourcesPluralFedNamespace)) + } + for _, gvr := range ksGVRs { if !isResourceExists(gvr) { klog.Warningf("resource %s not exists in the cluster", gvr) diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 58337e535..41ad7eb4c 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -34,6 +34,7 @@ import ( storagev1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/storage/v1alpha1" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/tenant/v1alpha2" + typesv1beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta1" ) type Interface interface { @@ -48,6 +49,7 @@ type Interface interface { StorageV1alpha1() storagev1alpha1.StorageV1alpha1Interface TenantV1alpha1() tenantv1alpha1.TenantV1alpha1Interface TenantV1alpha2() tenantv1alpha2.TenantV1alpha2Interface + TypesV1beta1() typesv1beta1.TypesV1beta1Interface } // Clientset contains the clients for groups. Each group has exactly one @@ -64,6 +66,7 @@ type Clientset struct { storageV1alpha1 *storagev1alpha1.StorageV1alpha1Client tenantV1alpha1 *tenantv1alpha1.TenantV1alpha1Client tenantV1alpha2 *tenantv1alpha2.TenantV1alpha2Client + typesV1beta1 *typesv1beta1.TypesV1beta1Client } // AuditingV1alpha1 retrieves the AuditingV1alpha1Client @@ -116,6 +119,11 @@ func (c *Clientset) TenantV1alpha2() tenantv1alpha2.TenantV1alpha2Interface { return c.tenantV1alpha2 } +// TypesV1beta1 retrieves the TypesV1beta1Client +func (c *Clientset) TypesV1beta1() typesv1beta1.TypesV1beta1Interface { + return c.typesV1beta1 +} + // Discovery retrieves the DiscoveryClient func (c *Clientset) Discovery() discovery.DiscoveryInterface { if c == nil { @@ -177,6 +185,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.typesV1beta1, err = typesv1beta1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) if err != nil { @@ -199,6 +211,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { cs.storageV1alpha1 = storagev1alpha1.NewForConfigOrDie(c) cs.tenantV1alpha1 = tenantv1alpha1.NewForConfigOrDie(c) cs.tenantV1alpha2 = tenantv1alpha2.NewForConfigOrDie(c) + cs.typesV1beta1 = typesv1beta1.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) return &cs @@ -217,6 +230,7 @@ func New(c rest.Interface) *Clientset { cs.storageV1alpha1 = storagev1alpha1.New(c) cs.tenantV1alpha1 = tenantv1alpha1.New(c) cs.tenantV1alpha2 = tenantv1alpha2.New(c) + cs.typesV1beta1 = typesv1beta1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 0331db2c5..8a8f43774 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -45,6 +45,8 @@ import ( faketenantv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/tenant/v1alpha1/fake" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/tenant/v1alpha2" faketenantv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/tenant/v1alpha2/fake" + typesv1beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta1" + faketypesv1beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta1/fake" ) // NewSimpleClientset returns a clientset that will respond with the provided objects. @@ -143,3 +145,8 @@ func (c *Clientset) TenantV1alpha1() tenantv1alpha1.TenantV1alpha1Interface { func (c *Clientset) TenantV1alpha2() tenantv1alpha2.TenantV1alpha2Interface { return &faketenantv1alpha2.FakeTenantV1alpha2{Fake: &c.Fake} } + +// TypesV1beta1 retrieves the TypesV1beta1Client +func (c *Clientset) TypesV1beta1() typesv1beta1.TypesV1beta1Interface { + return &faketypesv1beta1.FakeTypesV1beta1{Fake: &c.Fake} +} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index fff9dcf05..f749e88d6 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -34,6 +34,7 @@ import ( storagev1alpha1 "kubesphere.io/kubesphere/pkg/apis/storage/v1alpha1" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2" + typesv1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" ) var scheme = runtime.NewScheme() @@ -50,6 +51,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ storagev1alpha1.AddToScheme, tenantv1alpha1.AddToScheme, tenantv1alpha2.AddToScheme, + typesv1beta1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 2328c7a5e..c0b5d6837 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -34,6 +34,7 @@ import ( storagev1alpha1 "kubesphere.io/kubesphere/pkg/apis/storage/v1alpha1" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2" + typesv1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" ) var Scheme = runtime.NewScheme() @@ -50,6 +51,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ storagev1alpha1.AddToScheme, tenantv1alpha1.AddToScheme, tenantv1alpha2.AddToScheme, + typesv1beta1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/client/clientset/versioned/typed/types/v1beta1/doc.go b/pkg/client/clientset/versioned/typed/types/v1beta1/doc.go new file mode 100644 index 000000000..69dd56d12 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta1/doc.go @@ -0,0 +1,20 @@ +/* +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1beta1 diff --git a/pkg/client/clientset/versioned/typed/types/v1beta1/fake/doc.go b/pkg/client/clientset/versioned/typed/types/v1beta1/fake/doc.go new file mode 100644 index 000000000..7e36dbca8 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta1/fake/doc.go @@ -0,0 +1,20 @@ +/* +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/types/v1beta1/fake/fake_federatednamespace.go b/pkg/client/clientset/versioned/typed/types/v1beta1/fake/fake_federatednamespace.go new file mode 100644 index 000000000..eb570a196 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta1/fake/fake_federatednamespace.go @@ -0,0 +1,120 @@ +/* +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. +*/ + +// 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" + v1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" +) + +// FakeFederatedNamespaces implements FederatedNamespaceInterface +type FakeFederatedNamespaces struct { + Fake *FakeTypesV1beta1 +} + +var federatednamespacesResource = schema.GroupVersionResource{Group: "types.kubefed.io", Version: "v1beta1", Resource: "federatednamespaces"} + +var federatednamespacesKind = schema.GroupVersionKind{Group: "types.kubefed.io", Version: "v1beta1", Kind: "FederatedNamespace"} + +// Get takes name of the federatedNamespace, and returns the corresponding federatedNamespace object, and an error if there is any. +func (c *FakeFederatedNamespaces) Get(name string, options v1.GetOptions) (result *v1beta1.FederatedNamespace, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(federatednamespacesResource, name), &v1beta1.FederatedNamespace{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FederatedNamespace), err +} + +// List takes label and field selectors, and returns the list of FederatedNamespaces that match those selectors. +func (c *FakeFederatedNamespaces) List(opts v1.ListOptions) (result *v1beta1.FederatedNamespaceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(federatednamespacesResource, federatednamespacesKind, opts), &v1beta1.FederatedNamespaceList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.FederatedNamespaceList{ListMeta: obj.(*v1beta1.FederatedNamespaceList).ListMeta} + for _, item := range obj.(*v1beta1.FederatedNamespaceList).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 federatedNamespaces. +func (c *FakeFederatedNamespaces) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(federatednamespacesResource, opts)) +} + +// Create takes the representation of a federatedNamespace and creates it. Returns the server's representation of the federatedNamespace, and an error, if there is any. +func (c *FakeFederatedNamespaces) Create(federatedNamespace *v1beta1.FederatedNamespace) (result *v1beta1.FederatedNamespace, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(federatednamespacesResource, federatedNamespace), &v1beta1.FederatedNamespace{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FederatedNamespace), err +} + +// Update takes the representation of a federatedNamespace and updates it. Returns the server's representation of the federatedNamespace, and an error, if there is any. +func (c *FakeFederatedNamespaces) Update(federatedNamespace *v1beta1.FederatedNamespace) (result *v1beta1.FederatedNamespace, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(federatednamespacesResource, federatedNamespace), &v1beta1.FederatedNamespace{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FederatedNamespace), err +} + +// Delete takes name of the federatedNamespace and deletes it. Returns an error if one occurs. +func (c *FakeFederatedNamespaces) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(federatednamespacesResource, name), &v1beta1.FederatedNamespace{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeFederatedNamespaces) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(federatednamespacesResource, listOptions) + + _, err := c.Fake.Invokes(action, &v1beta1.FederatedNamespaceList{}) + return err +} + +// Patch applies the patch and returns the patched federatedNamespace. +func (c *FakeFederatedNamespaces) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.FederatedNamespace, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(federatednamespacesResource, name, pt, data, subresources...), &v1beta1.FederatedNamespace{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.FederatedNamespace), err +} diff --git a/pkg/client/clientset/versioned/typed/types/v1beta1/fake/fake_types_client.go b/pkg/client/clientset/versioned/typed/types/v1beta1/fake/fake_types_client.go new file mode 100644 index 000000000..ff952e916 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta1/fake/fake_types_client.go @@ -0,0 +1,40 @@ +/* +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1beta1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/types/v1beta1" +) + +type FakeTypesV1beta1 struct { + *testing.Fake +} + +func (c *FakeTypesV1beta1) FederatedNamespaces() v1beta1.FederatedNamespaceInterface { + return &FakeFederatedNamespaces{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeTypesV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/types/v1beta1/federatednamespace.go b/pkg/client/clientset/versioned/typed/types/v1beta1/federatednamespace.go new file mode 100644 index 000000000..c08a73587 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta1/federatednamespace.go @@ -0,0 +1,164 @@ +/* +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +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" + v1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// FederatedNamespacesGetter has a method to return a FederatedNamespaceInterface. +// A group's client should implement this interface. +type FederatedNamespacesGetter interface { + FederatedNamespaces() FederatedNamespaceInterface +} + +// FederatedNamespaceInterface has methods to work with FederatedNamespace resources. +type FederatedNamespaceInterface interface { + Create(*v1beta1.FederatedNamespace) (*v1beta1.FederatedNamespace, error) + Update(*v1beta1.FederatedNamespace) (*v1beta1.FederatedNamespace, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.FederatedNamespace, error) + List(opts v1.ListOptions) (*v1beta1.FederatedNamespaceList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.FederatedNamespace, err error) + FederatedNamespaceExpansion +} + +// federatedNamespaces implements FederatedNamespaceInterface +type federatedNamespaces struct { + client rest.Interface +} + +// newFederatedNamespaces returns a FederatedNamespaces +func newFederatedNamespaces(c *TypesV1beta1Client) *federatedNamespaces { + return &federatedNamespaces{ + client: c.RESTClient(), + } +} + +// Get takes name of the federatedNamespace, and returns the corresponding federatedNamespace object, and an error if there is any. +func (c *federatedNamespaces) Get(name string, options v1.GetOptions) (result *v1beta1.FederatedNamespace, err error) { + result = &v1beta1.FederatedNamespace{} + err = c.client.Get(). + Resource("federatednamespaces"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of FederatedNamespaces that match those selectors. +func (c *federatedNamespaces) List(opts v1.ListOptions) (result *v1beta1.FederatedNamespaceList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.FederatedNamespaceList{} + err = c.client.Get(). + Resource("federatednamespaces"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested federatedNamespaces. +func (c *federatedNamespaces) 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("federatednamespaces"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a federatedNamespace and creates it. Returns the server's representation of the federatedNamespace, and an error, if there is any. +func (c *federatedNamespaces) Create(federatedNamespace *v1beta1.FederatedNamespace) (result *v1beta1.FederatedNamespace, err error) { + result = &v1beta1.FederatedNamespace{} + err = c.client.Post(). + Resource("federatednamespaces"). + Body(federatedNamespace). + Do(). + Into(result) + return +} + +// Update takes the representation of a federatedNamespace and updates it. Returns the server's representation of the federatedNamespace, and an error, if there is any. +func (c *federatedNamespaces) Update(federatedNamespace *v1beta1.FederatedNamespace) (result *v1beta1.FederatedNamespace, err error) { + result = &v1beta1.FederatedNamespace{} + err = c.client.Put(). + Resource("federatednamespaces"). + Name(federatedNamespace.Name). + Body(federatedNamespace). + Do(). + Into(result) + return +} + +// Delete takes name of the federatedNamespace and deletes it. Returns an error if one occurs. +func (c *federatedNamespaces) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Resource("federatednamespaces"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *federatedNamespaces) 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("federatednamespaces"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched federatedNamespace. +func (c *federatedNamespaces) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.FederatedNamespace, err error) { + result = &v1beta1.FederatedNamespace{} + err = c.client.Patch(pt). + Resource("federatednamespaces"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/types/v1beta1/generated_expansion.go b/pkg/client/clientset/versioned/typed/types/v1beta1/generated_expansion.go new file mode 100644 index 000000000..0ddde915c --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +type FederatedNamespaceExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/types/v1beta1/types_client.go b/pkg/client/clientset/versioned/typed/types/v1beta1/types_client.go new file mode 100644 index 000000000..f053bb6f3 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/types/v1beta1/types_client.go @@ -0,0 +1,89 @@ +/* +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + rest "k8s.io/client-go/rest" + v1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +type TypesV1beta1Interface interface { + RESTClient() rest.Interface + FederatedNamespacesGetter +} + +// TypesV1beta1Client is used to interact with features provided by the types.kubefed.io group. +type TypesV1beta1Client struct { + restClient rest.Interface +} + +func (c *TypesV1beta1Client) FederatedNamespaces() FederatedNamespaceInterface { + return newFederatedNamespaces(c) +} + +// NewForConfig creates a new TypesV1beta1Client for the given config. +func NewForConfig(c *rest.Config) (*TypesV1beta1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &TypesV1beta1Client{client}, nil +} + +// NewForConfigOrDie creates a new TypesV1beta1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *TypesV1beta1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new TypesV1beta1Client for the given RESTClient. +func New(c rest.Interface) *TypesV1beta1Client { + return &TypesV1beta1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1beta1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *TypesV1beta1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 704195cb6..dc54b8950 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -37,6 +37,7 @@ import ( servicemesh "kubesphere.io/kubesphere/pkg/client/informers/externalversions/servicemesh" storage "kubesphere.io/kubesphere/pkg/client/informers/externalversions/storage" tenant "kubesphere.io/kubesphere/pkg/client/informers/externalversions/tenant" + types "kubesphere.io/kubesphere/pkg/client/informers/externalversions/types" ) // SharedInformerOption defines the functional option type for SharedInformerFactory. @@ -187,6 +188,7 @@ type SharedInformerFactory interface { Servicemesh() servicemesh.Interface Storage() storage.Interface Tenant() tenant.Interface + Types() types.Interface } func (f *sharedInformerFactory) Auditing() auditing.Interface { @@ -220,3 +222,7 @@ func (f *sharedInformerFactory) Storage() storage.Interface { func (f *sharedInformerFactory) Tenant() tenant.Interface { return tenant.New(f, f.namespace, f.tweakListOptions) } + +func (f *sharedInformerFactory) Types() types.Interface { + return types.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 9f4b99c93..129124001 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -33,6 +33,7 @@ import ( storagev1alpha1 "kubesphere.io/kubesphere/pkg/apis/storage/v1alpha1" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2" + v1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" ) // GenericInformer is type of SharedIndexInformer which will locate and delegate to other @@ -125,6 +126,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case tenantv1alpha2.SchemeGroupVersion.WithResource("workspacetemplates"): return &genericInformer{resource: resource.GroupResource(), informer: f.Tenant().V1alpha2().WorkspaceTemplates().Informer()}, nil + // Group=types.kubefed.io, Version=v1beta1 + case v1beta1.SchemeGroupVersion.WithResource("federatednamespaces"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Types().V1beta1().FederatedNamespaces().Informer()}, nil + } return nil, fmt.Errorf("no informer found for %v", resource) diff --git a/pkg/client/informers/externalversions/types/interface.go b/pkg/client/informers/externalversions/types/interface.go new file mode 100644 index 000000000..4fa20e66a --- /dev/null +++ b/pkg/client/informers/externalversions/types/interface.go @@ -0,0 +1,46 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package types + +import ( + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1beta1 "kubesphere.io/kubesphere/pkg/client/informers/externalversions/types/v1beta1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1beta1 provides access to shared informers for resources in V1beta1. + V1beta1() v1beta1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1beta1 returns a new v1beta1.Interface. +func (g *group) V1beta1() v1beta1.Interface { + return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/types/v1beta1/federatednamespace.go b/pkg/client/informers/externalversions/types/v1beta1/federatednamespace.go new file mode 100644 index 000000000..7deb70a36 --- /dev/null +++ b/pkg/client/informers/externalversions/types/v1beta1/federatednamespace.go @@ -0,0 +1,88 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +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" + typesv1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1beta1 "kubesphere.io/kubesphere/pkg/client/listers/types/v1beta1" +) + +// FederatedNamespaceInformer provides access to a shared informer and lister for +// FederatedNamespaces. +type FederatedNamespaceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.FederatedNamespaceLister +} + +type federatedNamespaceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewFederatedNamespaceInformer constructs a new informer for FederatedNamespace 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 NewFederatedNamespaceInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredFederatedNamespaceInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredFederatedNamespaceInformer constructs a new informer for FederatedNamespace 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 NewFilteredFederatedNamespaceInformer(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.TypesV1beta1().FederatedNamespaces().List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.TypesV1beta1().FederatedNamespaces().Watch(options) + }, + }, + &typesv1beta1.FederatedNamespace{}, + resyncPeriod, + indexers, + ) +} + +func (f *federatedNamespaceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredFederatedNamespaceInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *federatedNamespaceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&typesv1beta1.FederatedNamespace{}, f.defaultInformer) +} + +func (f *federatedNamespaceInformer) Lister() v1beta1.FederatedNamespaceLister { + return v1beta1.NewFederatedNamespaceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/types/v1beta1/interface.go b/pkg/client/informers/externalversions/types/v1beta1/interface.go new file mode 100644 index 000000000..f04600705 --- /dev/null +++ b/pkg/client/informers/externalversions/types/v1beta1/interface.go @@ -0,0 +1,45 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // FederatedNamespaces returns a FederatedNamespaceInformer. + FederatedNamespaces() FederatedNamespaceInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// FederatedNamespaces returns a FederatedNamespaceInformer. +func (v *version) FederatedNamespaces() FederatedNamespaceInformer { + return &federatedNamespaceInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/listers/types/v1beta1/expansion_generated.go b/pkg/client/listers/types/v1beta1/expansion_generated.go new file mode 100644 index 000000000..cc1997a0c --- /dev/null +++ b/pkg/client/listers/types/v1beta1/expansion_generated.go @@ -0,0 +1,23 @@ +/* +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +// FederatedNamespaceListerExpansion allows custom methods to be added to +// FederatedNamespaceLister. +type FederatedNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/types/v1beta1/federatednamespace.go b/pkg/client/listers/types/v1beta1/federatednamespace.go new file mode 100644 index 000000000..b0967fcd9 --- /dev/null +++ b/pkg/client/listers/types/v1beta1/federatednamespace.go @@ -0,0 +1,65 @@ +/* +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" +) + +// FederatedNamespaceLister helps list FederatedNamespaces. +type FederatedNamespaceLister interface { + // List lists all FederatedNamespaces in the indexer. + List(selector labels.Selector) (ret []*v1beta1.FederatedNamespace, err error) + // Get retrieves the FederatedNamespace from the index for a given name. + Get(name string) (*v1beta1.FederatedNamespace, error) + FederatedNamespaceListerExpansion +} + +// federatedNamespaceLister implements the FederatedNamespaceLister interface. +type federatedNamespaceLister struct { + indexer cache.Indexer +} + +// NewFederatedNamespaceLister returns a new FederatedNamespaceLister. +func NewFederatedNamespaceLister(indexer cache.Indexer) FederatedNamespaceLister { + return &federatedNamespaceLister{indexer: indexer} +} + +// List lists all FederatedNamespaces in the indexer. +func (s *federatedNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.FederatedNamespace, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.FederatedNamespace)) + }) + return ret, err +} + +// Get retrieves the FederatedNamespace from the index for a given name. +func (s *federatedNamespaceLister) Get(name string) (*v1beta1.FederatedNamespace, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("federatednamespace"), name) + } + return obj.(*v1beta1.FederatedNamespace), nil +} diff --git a/pkg/kapis/tenant/v1alpha2/handler.go b/pkg/kapis/tenant/v1alpha2/handler.go index 527ba2e7e..9ba583a92 100644 --- a/pkg/kapis/tenant/v1alpha2/handler.go +++ b/pkg/kapis/tenant/v1alpha2/handler.go @@ -55,6 +55,29 @@ func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Respo resp.WriteEntity(result) } +func (h *tenantHandler) ListFederatedNamespaces(req *restful.Request, resp *restful.Response) { + user, ok := request.UserFrom(req.Request.Context()) + queryParam := query.ParseQueryParameter(req) + + if !ok { + err := fmt.Errorf("cannot obtain user info") + klog.Errorln(err) + api.HandleForbidden(resp, nil, err) + return + } + + workspace := req.PathParameter("workspace") + + result, err := h.tenant.ListFederatedNamespaces(user, workspace, queryParam) + + if err != nil { + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteEntity(result) +} + func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Response) { user, ok := request.UserFrom(req.Request.Context()) queryParam := query.ParseQueryParameter(req) diff --git a/pkg/kapis/tenant/v1alpha2/register.go b/pkg/kapis/tenant/v1alpha2/register.go index 6bd3ce454..13ad037d3 100644 --- a/pkg/kapis/tenant/v1alpha2/register.go +++ b/pkg/kapis/tenant/v1alpha2/register.go @@ -27,6 +27,7 @@ import ( eventsv1alpha1 "kubesphere.io/kubesphere/pkg/api/events/v1alpha1" loggingv1alpha2 "kubesphere.io/kubesphere/pkg/api/logging/v1alpha2" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2" + typesv1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" "kubesphere.io/kubesphere/pkg/apiserver/runtime" kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned" "kubesphere.io/kubesphere/pkg/constants" @@ -106,6 +107,18 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8s Doc("List the namespaces for the current user"). Returns(http.StatusOK, api.StatusOK, []corev1.Namespace{}). Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) + ws.Route(ws.GET("/federatednamespaces"). + To(handler.ListFederatedNamespaces). + Param(ws.PathParameter("workspace", "workspace name")). + Doc("List the federated namespaces for the current user"). + Returns(http.StatusOK, api.StatusOK, []typesv1beta1.FederatedNamespace{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) + ws.Route(ws.GET("/workspaces/{workspace}/federatednamespaces"). + To(handler.ListFederatedNamespaces). + Param(ws.PathParameter("workspace", "workspace name")). + Doc("List the federated namespaces of the specified workspace for the current user"). + Returns(http.StatusOK, api.StatusOK, []typesv1beta1.FederatedNamespace{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag})) ws.Route(ws.GET("/workspaces/{workspace}/namespaces"). To(handler.ListNamespaces). Param(ws.PathParameter("workspace", "workspace name")). diff --git a/pkg/models/resources/v1alpha3/federatednamespace/federatednamespaces.go b/pkg/models/resources/v1alpha3/federatednamespace/federatednamespaces.go new file mode 100644 index 000000000..157bbaa27 --- /dev/null +++ b/pkg/models/resources/v1alpha3/federatednamespace/federatednamespaces.go @@ -0,0 +1,73 @@ +/* +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 federatednamespace + +import ( + "k8s.io/apimachinery/pkg/runtime" + "kubesphere.io/kubesphere/pkg/api" + typesv1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" +) + +type federatedNamespacesGetter struct { + informers informers.SharedInformerFactory +} + +func New(informers informers.SharedInformerFactory) v1alpha3.Interface { + return &federatedNamespacesGetter{informers: informers} +} + +func (n federatedNamespacesGetter) Get(_, name string) (runtime.Object, error) { + return n.informers.Types().V1beta1().FederatedNamespaces().Lister().Get(name) +} + +func (n federatedNamespacesGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + ns, err := n.informers.Types().V1beta1().FederatedNamespaces().Lister().List(query.Selector()) + if err != nil { + return nil, err + } + + var result []runtime.Object + for _, item := range ns { + result = append(result, item) + } + + return v1alpha3.DefaultList(result, query, n.compare, n.filter), nil +} + +func (n federatedNamespacesGetter) filter(item runtime.Object, filter query.Filter) bool { + namespace, ok := item.(*typesv1beta1.FederatedNamespace) + if !ok { + return false + } + return v1alpha3.DefaultObjectMetaFilter(namespace.ObjectMeta, filter) +} + +func (n federatedNamespacesGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + leftNs, ok := left.(*typesv1beta1.FederatedNamespace) + if !ok { + return false + } + + rightNs, ok := right.(*typesv1beta1.FederatedNamespace) + if !ok { + return true + } + return v1alpha3.DefaultObjectMetaCompare(leftNs.ObjectMeta, rightNs.ObjectMeta, field) +} diff --git a/pkg/models/resources/v1alpha3/federatednamespace/federatednamespaces_test.go b/pkg/models/resources/v1alpha3/federatednamespace/federatednamespaces_test.go new file mode 100644 index 000000000..842d4bc7f --- /dev/null +++ b/pkg/models/resources/v1alpha3/federatednamespace/federatednamespaces_test.go @@ -0,0 +1,17 @@ +/* +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 federatednamespace diff --git a/pkg/models/resources/v1alpha3/resource/resource.go b/pkg/models/resources/v1alpha3/resource/resource.go index 9a84c8c8b..25c429087 100644 --- a/pkg/models/resources/v1alpha3/resource/resource.go +++ b/pkg/models/resources/v1alpha3/resource/resource.go @@ -27,6 +27,7 @@ import ( iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2" + typesv1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" "kubesphere.io/kubesphere/pkg/apiserver/query" "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" @@ -39,6 +40,7 @@ import ( "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/daemonset" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/deployment" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/devops" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/federatednamespace" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/globalrole" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/globalrolebinding" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/namespace" @@ -93,6 +95,9 @@ func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter { getters[snapshotv1beta1.SchemeGroupVersion.WithResource("volumesnapshots")] = volumesnapshot.New(factory.SnapshotSharedInformerFactory()) getters[schema.GroupVersionResource{Group: "cluster.kubesphere.io", Version: "v1alpha1", Resource: "clusters"}] = cluster.New(factory.KubeSphereSharedInformerFactory()) getters[schema.GroupVersionResource{Group: "apiextensions.k8s.io", Version: "v1", Resource: "customresourcedefinitions"}] = customresourcedefinition.New(factory.ApiExtensionSharedInformerFactory()) + + getters[typesv1beta1.SchemeGroupVersion.WithResource(typesv1beta1.ResourcesPluralFedNamespace)] = federatednamespace.New(factory.KubeSphereSharedInformerFactory()) + return &ResourceGetter{ getters: getters, } diff --git a/pkg/models/tenant/tenant.go b/pkg/models/tenant/tenant.go index 3f95e5327..29327dfb3 100644 --- a/pkg/models/tenant/tenant.go +++ b/pkg/models/tenant/tenant.go @@ -36,6 +36,7 @@ import ( clusterv1alpha1 "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2" + typesv1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" "kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer" "kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizerfactory" "kubesphere.io/kubesphere/pkg/apiserver/query" @@ -59,6 +60,7 @@ import ( type Interface interface { ListWorkspaces(user user.Info, query *query.Query) (*api.ListResult, error) ListNamespaces(user user.Info, workspace string, query *query.Query) (*api.ListResult, error) + ListFederatedNamespaces(info user.Info, workspace string, param *query.Query) (*api.ListResult, error) CreateNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error) CreateWorkspace(workspace *tenantv1alpha2.WorkspaceTemplate) (*tenantv1alpha2.WorkspaceTemplate, error) DeleteWorkspace(workspace string) error @@ -171,6 +173,85 @@ func (t *tenantOperator) ListWorkspaces(user user.Info, queryParam *query.Query) return result, nil } +func (t *tenantOperator) ListFederatedNamespaces(user user.Info, workspace string, queryParam *query.Query) (*api.ListResult, error) { + nsScope := request.ClusterScope + if workspace != "" { + nsScope = request.WorkspaceScope + } + + listNS := authorizer.AttributesRecord{ + User: user, + Verb: "list", + Workspace: workspace, + Resource: "namespaces", + ResourceRequest: true, + ResourceScope: nsScope, + } + + decision, _, err := t.authorizer.Authorize(listNS) + + if err != nil { + klog.Error(err) + return nil, err + } + + if decision == authorizer.DecisionAllow { + + if workspace != "" { + queryParam.Filters[query.FieldLabel] = query.Value(fmt.Sprintf("%s=%s", tenantv1alpha1.WorkspaceLabel, workspace)) + } + + result, err := t.resourceGetter.List(typesv1beta1.ResourcesPluralFedNamespace, "", queryParam) + + if err != nil { + klog.Error(err) + return nil, err + } + + return result, nil + } + + roleBindings, err := t.am.ListRoleBindings(user.GetName(), "") + + if err != nil { + klog.Error(err) + return nil, err + } + + namespaces := make([]runtime.Object, 0) + + for _, roleBinding := range roleBindings { + namespace, err := t.resourceGetter.Get(typesv1beta1.ResourcesPluralFedNamespace, roleBinding.Namespace, roleBinding.Namespace) + + if err != nil { + klog.Error(err) + return nil, err + } + + // skip if not controlled by the specified workspace + if ns := namespace.(*typesv1beta1.FederatedNamespace); workspace != "" && ns.Labels[tenantv1alpha1.WorkspaceLabel] != workspace { + continue + } + + if !contains(namespaces, namespace) { + namespaces = append(namespaces, namespace) + } + } + + result := resources.DefaultList(namespaces, queryParam, func(left runtime.Object, right runtime.Object, field query.Field) bool { + return resources.DefaultObjectMetaCompare(left.(*corev1.Namespace).ObjectMeta, right.(*corev1.Namespace).ObjectMeta, field) + }, func(object runtime.Object, filter query.Filter) bool { + namespace := object.(*typesv1beta1.FederatedNamespace).ObjectMeta + if workspace != "" { + if workspaceLabel, ok := namespace.Labels[tenantv1alpha1.WorkspaceLabel]; !ok || workspaceLabel != workspace { + return false + } + } + return resources.DefaultObjectMetaFilter(namespace, filter) + }) + return result, nil +} + func (t *tenantOperator) ListNamespaces(user user.Info, workspace string, queryParam *query.Query) (*api.ListResult, error) { nsScope := request.ClusterScope if workspace != "" {