From 54fc52c0e3d35c9802b57398423079fd63fc6dac Mon Sep 17 00:00:00 2001 From: hongming Date: Sat, 28 Mar 2020 17:55:31 +0800 Subject: [PATCH] add user crd Signed-off-by: hongming --- config/crds/iam.kubesphere.io_users.yaml | 114 ++++++++ config/samples/iam_v1alpha2_user.yaml | 9 + hack/generate_client.sh | 2 +- pkg/apis/addtoscheme_iam_v1alpha2.go | 26 ++ pkg/apis/iam/group.go | 18 ++ pkg/apis/iam/v1alpha2/doc.go | 23 ++ pkg/apis/iam/v1alpha2/register.go | 46 ++++ pkg/apis/iam/v1alpha2/user_types.go | 132 ++++++++++ pkg/apis/iam/v1alpha2/user_types_test.go | 56 ++++ pkg/apis/iam/v1alpha2/v1alpha2_suite_test.go | 55 ++++ .../iam/v1alpha2/zz_generated.deepcopy.go | 147 +++++++++++ pkg/apiserver/apiserver.go | 2 +- 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/iam/v1alpha2/doc.go | 20 ++ .../versioned/typed/iam/v1alpha2/fake/doc.go | 20 ++ .../iam/v1alpha2/fake/fake_iam_client.go | 40 +++ .../typed/iam/v1alpha2/fake/fake_user.go | 131 ++++++++++ .../typed/iam/v1alpha2/generated_expansion.go | 21 ++ .../typed/iam/v1alpha2/iam_client.go | 89 +++++++ .../versioned/typed/iam/v1alpha2/user.go | 180 +++++++++++++ .../informers/externalversions/factory.go | 6 + .../informers/externalversions/generic.go | 11 +- .../externalversions/iam/interface.go | 46 ++++ .../iam/v1alpha2/interface.go | 45 ++++ .../externalversions/iam/v1alpha2/user.go | 88 +++++++ .../iam/v1alpha2/expansion_generated.go | 23 ++ pkg/client/listers/iam/v1alpha2/user.go | 65 +++++ pkg/controller/user/user_controller.go | 228 ++++++++++++++++ pkg/controller/user/user_controller_test.go | 245 ++++++++++++++++++ pkg/models/registries/image.go | 2 +- pkg/simple/client/cache/simple_cache.go | 2 +- pkg/simple/client/devops/jenkins/build.go | 2 +- pkg/simple/client/mysql/options.go | 2 +- 36 files changed, 1912 insertions(+), 9 deletions(-) create mode 100644 config/crds/iam.kubesphere.io_users.yaml create mode 100644 config/samples/iam_v1alpha2_user.yaml create mode 100644 pkg/apis/addtoscheme_iam_v1alpha2.go create mode 100644 pkg/apis/iam/group.go create mode 100644 pkg/apis/iam/v1alpha2/doc.go create mode 100644 pkg/apis/iam/v1alpha2/register.go create mode 100644 pkg/apis/iam/v1alpha2/user_types.go create mode 100644 pkg/apis/iam/v1alpha2/user_types_test.go create mode 100644 pkg/apis/iam/v1alpha2/v1alpha2_suite_test.go create mode 100644 pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/doc.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_iam_client.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_user.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/iam_client.go create mode 100644 pkg/client/clientset/versioned/typed/iam/v1alpha2/user.go create mode 100644 pkg/client/informers/externalversions/iam/interface.go create mode 100644 pkg/client/informers/externalversions/iam/v1alpha2/interface.go create mode 100644 pkg/client/informers/externalversions/iam/v1alpha2/user.go create mode 100644 pkg/client/listers/iam/v1alpha2/expansion_generated.go create mode 100644 pkg/client/listers/iam/v1alpha2/user.go create mode 100644 pkg/controller/user/user_controller.go create mode 100644 pkg/controller/user/user_controller_test.go diff --git a/config/crds/iam.kubesphere.io_users.yaml b/config/crds/iam.kubesphere.io_users.yaml new file mode 100644 index 00000000..9b1fde0e --- /dev/null +++ b/config/crds/iam.kubesphere.io_users.yaml @@ -0,0 +1,114 @@ + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + creationTimestamp: null + name: users.iam.kubesphere.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.email + name: Email + type: string + group: iam.kubesphere.io + names: + categories: + - iam + kind: User + listKind: UserList + plural: users + singular: user + scope: Cluster + subresources: {} + validation: + openAPIV3Schema: + description: User is the Schema for the users API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + 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 + metadata: + type: object + spec: + description: UserSpec defines the desired state of User + properties: + description: + description: Description of the user. + type: string + displayName: + type: string + email: + description: Unique email address. + type: string + finalizers: + description: Finalizers is an opaque list of values that must be empty + to permanently remove object from storage. + items: + type: string + type: array + groups: + items: + type: string + type: array + lang: + description: The preferred written or spoken language for the user. + type: string + password: + type: string + required: + - email + - password + type: object + status: + description: UserStatus defines the observed state of User + properties: + conditions: + description: Represents the latest available observations of a namespace's + current state. + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of namespace controller condition. + type: string + required: + - status + - type + type: object + type: array + phase: + description: Phase is the phase of the user. + type: string + type: object + required: + - spec + type: object + version: v1alpha2 + versions: + - name: v1alpha2 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/samples/iam_v1alpha2_user.yaml b/config/samples/iam_v1alpha2_user.yaml new file mode 100644 index 00000000..6820fd74 --- /dev/null +++ b/config/samples/iam_v1alpha2_user.yaml @@ -0,0 +1,9 @@ +apiVersion: iam.kubesphere.io/v1alpha2 +kind: User +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: user-sample +spec: + # Add fields here + foo: bar diff --git a/hack/generate_client.sh b/hack/generate_client.sh index 9d094b8b..7bbaba58 100755 --- a/hack/generate_client.sh +++ b/hack/generate_client.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -GV="network:v1alpha1 servicemesh:v1alpha2 tenant:v1alpha1 devops:v1alpha1" +GV="network:v1alpha1 servicemesh:v1alpha2 tenant:v1alpha1 devops:v1alpha1 iam:v1alpha2" 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/addtoscheme_iam_v1alpha2.go b/pkg/apis/addtoscheme_iam_v1alpha2.go new file mode 100644 index 00000000..3f2a962a --- /dev/null +++ b/pkg/apis/addtoscheme_iam_v1alpha2.go @@ -0,0 +1,26 @@ +/* +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 apis + +import ( + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, iamv1alpha2.SchemeBuilder.AddToScheme) +} diff --git a/pkg/apis/iam/group.go b/pkg/apis/iam/group.go new file mode 100644 index 00000000..cd47ea56 --- /dev/null +++ b/pkg/apis/iam/group.go @@ -0,0 +1,18 @@ +/* +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 iam contains iam API versions +package iam diff --git a/pkg/apis/iam/v1alpha2/doc.go b/pkg/apis/iam/v1alpha2/doc.go new file mode 100644 index 00000000..5ddef225 --- /dev/null +++ b/pkg/apis/iam/v1alpha2/doc.go @@ -0,0 +1,23 @@ +/* +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 v1alpha2 contains API Schema definitions for the iam v1alpha2 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=kubesphere.io/kubesphere/pkg/apis/iam +// +k8s:defaulter-gen=TypeMeta +// +groupName=iam.kubesphere.io +package v1alpha2 diff --git a/pkg/apis/iam/v1alpha2/register.go b/pkg/apis/iam/v1alpha2/register.go new file mode 100644 index 00000000..373dcf12 --- /dev/null +++ b/pkg/apis/iam/v1alpha2/register.go @@ -0,0 +1,46 @@ +/* +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. + +// Package v1alpha2 contains API Schema definitions for the iam v1alpha2 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=kubesphere.io/kubesphere/pkg/apis/iam +// +k8s:defaulter-gen=TypeMeta +// +groupName=iam.kubesphere.io +package v1alpha2 + +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: "iam.kubesphere.io", Version: "v1alpha2"} + + // 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() +} diff --git a/pkg/apis/iam/v1alpha2/user_types.go b/pkg/apis/iam/v1alpha2/user_types.go new file mode 100644 index 00000000..9158f6ed --- /dev/null +++ b/pkg/apis/iam/v1alpha2/user_types.go @@ -0,0 +1,132 @@ +/* +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 v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// User is the Schema for the users API +// +k8s:openapi-gen=true +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:nonNamespaced +// +kubebuilder:printcolumn:name="Email",type="string",JSONPath=".spec.email" +// +kubebuilder:resource:categories="iam",scope="Cluster" +type User struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec UserSpec `json:"spec"` + // +optional + Status UserStatus `json:"status,omitempty"` +} + +type FinalizerName string + +// UserSpec defines the desired state of User +type UserSpec struct { + // Unique email address. + Email string `json:"email"` + // The preferred written or spoken language for the user. + // +optional + Lang string `json:"lang,omitempty"` + // Description of the user. + // +optional + Description string `json:"description,omitempty"` + // +optional + DisplayName string `json:"displayName,omitempty"` + // +optional + Groups []string `json:"groups,omitempty"` + EncryptedPassword string `json:"password"` + + // Finalizers is an opaque list of values that must be empty to permanently remove object from storage. + // +optional + Finalizers []FinalizerName `json:"finalizers,omitempty"` +} + +type UserPhase string + +// These are the valid phases of a user. +const ( + // UserActive means the user is available. + UserActive UserPhase = "Active" + // UserDisabled means the user is disabled. + UserDisabled UserPhase = "Disabled" +) + +// UserStatus defines the observed state of User +type UserStatus struct { + // Phase is the phase of the user. + // +optional + Phase UserPhase `json:"phase,omitempty" protobuf:"bytes,1,opt,name=phase,casttype=UserPhase"` + + // Represents the latest available observations of a namespace's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + Conditions []UserCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,2,rep,name=conditions"` +} + +type UserCondition struct { + // Type of namespace controller condition. + Type UserConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=NamespaceConditionType"` + // Status of the condition, one of True, False, Unknown. + Status ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=ConditionStatus"` + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,4,opt,name=lastTransitionTime"` + // +optional + Reason string `json:"reason,omitempty" protobuf:"bytes,5,opt,name=reason"` + // +optional + Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"` +} + +type UserConditionType string + +// These are valid conditions of a user. +const ( + // UserLoginFailure contains information about user login. + UserLoginFailure UserConditionType = "UserLoginFailure" +) + +type ConditionStatus string + +// These are valid condition statuses. "ConditionTrue" means a resource is in the condition. +// "ConditionFalse" means a resource is not in the condition. "ConditionUnknown" means kubernetes +// can't decide if a resource is in the condition or not. In the future, we could add other +// intermediate conditions, e.g. ConditionDegraded. +const ( + ConditionTrue ConditionStatus = "True" + ConditionFalse ConditionStatus = "False" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:nonNamespaced + +// UserList contains a list of User +type UserList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []User `json:"items"` +} + +func init() { + SchemeBuilder.Register(&User{}, &UserList{}) +} diff --git a/pkg/apis/iam/v1alpha2/user_types_test.go b/pkg/apis/iam/v1alpha2/user_types_test.go new file mode 100644 index 00000000..2146c1a8 --- /dev/null +++ b/pkg/apis/iam/v1alpha2/user_types_test.go @@ -0,0 +1,56 @@ +/* +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 v1alpha2 + +import ( + "testing" + + "github.com/onsi/gomega" + "golang.org/x/net/context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +func TestStorageUser(t *testing.T) { + key := types.NamespacedName{ + Name: "foo", + } + created := &User{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }} + g := gomega.NewGomegaWithT(t) + + // Test Create + fetched := &User{} + g.Expect(c.Create(context.TODO(), created)).To(gomega.Succeed()) + + g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.Succeed()) + g.Expect(fetched).To(gomega.Equal(created)) + + // Test Updating the Labels + updated := fetched.DeepCopy() + updated.Labels = map[string]string{"hello": "world"} + g.Expect(c.Update(context.TODO(), updated)).To(gomega.Succeed()) + + g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.Succeed()) + g.Expect(fetched).To(gomega.Equal(updated)) + + // Test Delete + g.Expect(c.Delete(context.TODO(), fetched)).To(gomega.Succeed()) + g.Expect(c.Get(context.TODO(), key, fetched)).ToNot(gomega.Succeed()) +} diff --git a/pkg/apis/iam/v1alpha2/v1alpha2_suite_test.go b/pkg/apis/iam/v1alpha2/v1alpha2_suite_test.go new file mode 100644 index 00000000..17192bd5 --- /dev/null +++ b/pkg/apis/iam/v1alpha2/v1alpha2_suite_test.go @@ -0,0 +1,55 @@ +/* +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 v1alpha2 + +import ( + "log" + "os" + "path/filepath" + "testing" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" +) + +var cfg *rest.Config +var c client.Client + +func TestMain(m *testing.M) { + t := &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "config", "crds")}, + } + + err := SchemeBuilder.AddToScheme(scheme.Scheme) + if err != nil { + log.Fatal(err) + } + + if cfg, err = t.Start(); err != nil { + log.Fatal(err) + } + + if c, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}); err != nil { + log.Fatal(err) + } + + code := m.Run() + t.Stop() + os.Exit(code) +} diff --git a/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go new file mode 100644 index 00000000..a7056368 --- /dev/null +++ b/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go @@ -0,0 +1,147 @@ +// +build !ignore_autogenerated + +/* +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 controller-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// 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 + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *User) 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 *UserCondition) DeepCopyInto(out *UserCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserCondition. +func (in *UserCondition) DeepCopy() *UserCondition { + if in == nil { + return nil + } + out := new(UserCondition) + 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 + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]User, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserList. +func (in *UserList) DeepCopy() *UserList { + if in == nil { + return nil + } + out := new(UserList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *UserList) 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 *UserSpec) DeepCopyInto(out *UserSpec) { + *out = *in + if in.Groups != nil { + in, out := &in.Groups, &out.Groups + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Finalizers != nil { + in, out := &in.Finalizers, &out.Finalizers + *out = make([]FinalizerName, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserSpec. +func (in *UserSpec) DeepCopy() *UserSpec { + if in == nil { + return nil + } + out := new(UserSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserStatus) DeepCopyInto(out *UserStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]UserCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserStatus. +func (in *UserStatus) DeepCopy() *UserStatus { + if in == nil { + return nil + } + out := new(UserStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 87ae92da..f8a02f1d 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -28,7 +28,7 @@ import ( iamv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2" loggingv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/logging/v1alpha2" monitoringv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha2" - oauth "kubesphere.io/kubesphere/pkg/kapis/oauth" + "kubesphere.io/kubesphere/pkg/kapis/oauth" openpitrixv1 "kubesphere.io/kubesphere/pkg/kapis/openpitrix/v1" operationsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/operations/v1alpha2" resourcesv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha2" diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index cdf28675..937b8444 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -25,6 +25,7 @@ import ( rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/devops/v1alpha1" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/iam/v1alpha2" networkv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/network/v1alpha1" servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/servicemesh/v1alpha2" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/tenant/v1alpha1" @@ -33,6 +34,7 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface DevopsV1alpha1() devopsv1alpha1.DevopsV1alpha1Interface + IamV1alpha2() iamv1alpha2.IamV1alpha2Interface NetworkV1alpha1() networkv1alpha1.NetworkV1alpha1Interface ServicemeshV1alpha2() servicemeshv1alpha2.ServicemeshV1alpha2Interface TenantV1alpha1() tenantv1alpha1.TenantV1alpha1Interface @@ -43,6 +45,7 @@ type Interface interface { type Clientset struct { *discovery.DiscoveryClient devopsV1alpha1 *devopsv1alpha1.DevopsV1alpha1Client + iamV1alpha2 *iamv1alpha2.IamV1alpha2Client networkV1alpha1 *networkv1alpha1.NetworkV1alpha1Client servicemeshV1alpha2 *servicemeshv1alpha2.ServicemeshV1alpha2Client tenantV1alpha1 *tenantv1alpha1.TenantV1alpha1Client @@ -53,6 +56,11 @@ func (c *Clientset) DevopsV1alpha1() devopsv1alpha1.DevopsV1alpha1Interface { return c.devopsV1alpha1 } +// IamV1alpha2 retrieves the IamV1alpha2Client +func (c *Clientset) IamV1alpha2() iamv1alpha2.IamV1alpha2Interface { + return c.iamV1alpha2 +} + // NetworkV1alpha1 retrieves the NetworkV1alpha1Client func (c *Clientset) NetworkV1alpha1() networkv1alpha1.NetworkV1alpha1Interface { return c.networkV1alpha1 @@ -93,6 +101,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.iamV1alpha2, err = iamv1alpha2.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.networkV1alpha1, err = networkv1alpha1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -118,6 +130,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset cs.devopsV1alpha1 = devopsv1alpha1.NewForConfigOrDie(c) + cs.iamV1alpha2 = iamv1alpha2.NewForConfigOrDie(c) cs.networkV1alpha1 = networkv1alpha1.NewForConfigOrDie(c) cs.servicemeshV1alpha2 = servicemeshv1alpha2.NewForConfigOrDie(c) cs.tenantV1alpha1 = tenantv1alpha1.NewForConfigOrDie(c) @@ -130,6 +143,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { func New(c rest.Interface) *Clientset { var cs Clientset cs.devopsV1alpha1 = devopsv1alpha1.New(c) + cs.iamV1alpha2 = iamv1alpha2.New(c) cs.networkV1alpha1 = networkv1alpha1.New(c) cs.servicemeshV1alpha2 = servicemeshv1alpha2.New(c) cs.tenantV1alpha1 = tenantv1alpha1.New(c) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 2eb0a0a0..1d5746b9 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -27,6 +27,8 @@ import ( clientset "kubesphere.io/kubesphere/pkg/client/clientset/versioned" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/devops/v1alpha1" fakedevopsv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/devops/v1alpha1/fake" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/iam/v1alpha2" + fakeiamv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake" networkv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/network/v1alpha1" fakenetworkv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/network/v1alpha1/fake" servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/servicemesh/v1alpha2" @@ -87,6 +89,11 @@ func (c *Clientset) DevopsV1alpha1() devopsv1alpha1.DevopsV1alpha1Interface { return &fakedevopsv1alpha1.FakeDevopsV1alpha1{Fake: &c.Fake} } +// IamV1alpha2 retrieves the IamV1alpha2Client +func (c *Clientset) IamV1alpha2() iamv1alpha2.IamV1alpha2Interface { + return &fakeiamv1alpha2.FakeIamV1alpha2{Fake: &c.Fake} +} + // NetworkV1alpha1 retrieves the NetworkV1alpha1Client func (c *Clientset) NetworkV1alpha1() networkv1alpha1.NetworkV1alpha1Interface { return &fakenetworkv1alpha1.FakeNetworkV1alpha1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 36f2e736..cd0dc609 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -25,6 +25,7 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" networkv1alpha1 "kubesphere.io/kubesphere/pkg/apis/network/v1alpha1" servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" @@ -35,6 +36,7 @@ var codecs = serializer.NewCodecFactory(scheme) var parameterCodec = runtime.NewParameterCodec(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ devopsv1alpha1.AddToScheme, + iamv1alpha2.AddToScheme, networkv1alpha1.AddToScheme, servicemeshv1alpha2.AddToScheme, tenantv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 30434c54..728d5b82 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -25,6 +25,7 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" networkv1alpha1 "kubesphere.io/kubesphere/pkg/apis/network/v1alpha1" servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" @@ -35,6 +36,7 @@ var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ devopsv1alpha1.AddToScheme, + iamv1alpha2.AddToScheme, networkv1alpha1.AddToScheme, servicemeshv1alpha2.AddToScheme, tenantv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/doc.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/doc.go new file mode 100644 index 00000000..02d20203 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha2 diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/doc.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/doc.go new file mode 100644 index 00000000..329c98fb --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/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. +*/ + +// 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/iam/v1alpha2/fake/fake_iam_client.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_iam_client.go new file mode 100644 index 00000000..93b004ea --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_iam_client.go @@ -0,0 +1,40 @@ +/* +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 ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1alpha2 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/iam/v1alpha2" +) + +type FakeIamV1alpha2 struct { + *testing.Fake +} + +func (c *FakeIamV1alpha2) Users() v1alpha2.UserInterface { + return &FakeUsers{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeIamV1alpha2) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_user.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_user.go new file mode 100644 index 00000000..f8a50771 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/fake/fake_user.go @@ -0,0 +1,131 @@ +/* +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" +) + +// FakeUsers implements UserInterface +type FakeUsers struct { + Fake *FakeIamV1alpha2 +} + +var usersResource = schema.GroupVersionResource{Group: "iam.kubesphere.io", Version: "v1alpha2", Resource: "users"} + +var usersKind = schema.GroupVersionKind{Group: "iam.kubesphere.io", Version: "v1alpha2", Kind: "User"} + +// Get takes name of the user, and returns the corresponding user object, and an error if there is any. +func (c *FakeUsers) Get(name string, options v1.GetOptions) (result *v1alpha2.User, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(usersResource, name), &v1alpha2.User{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.User), err +} + +// List takes label and field selectors, and returns the list of Users that match those selectors. +func (c *FakeUsers) List(opts v1.ListOptions) (result *v1alpha2.UserList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(usersResource, usersKind, opts), &v1alpha2.UserList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha2.UserList{ListMeta: obj.(*v1alpha2.UserList).ListMeta} + for _, item := range obj.(*v1alpha2.UserList).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 users. +func (c *FakeUsers) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(usersResource, opts)) +} + +// Create takes the representation of a user and creates it. Returns the server's representation of the user, and an error, if there is any. +func (c *FakeUsers) Create(user *v1alpha2.User) (result *v1alpha2.User, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(usersResource, user), &v1alpha2.User{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.User), err +} + +// Update takes the representation of a user and updates it. Returns the server's representation of the user, and an error, if there is any. +func (c *FakeUsers) Update(user *v1alpha2.User) (result *v1alpha2.User, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(usersResource, user), &v1alpha2.User{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.User), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeUsers) UpdateStatus(user *v1alpha2.User) (*v1alpha2.User, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(usersResource, "status", user), &v1alpha2.User{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.User), err +} + +// Delete takes name of the user and deletes it. Returns an error if one occurs. +func (c *FakeUsers) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(usersResource, name), &v1alpha2.User{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeUsers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(usersResource, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha2.UserList{}) + return err +} + +// Patch applies the patch and returns the patched user. +func (c *FakeUsers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.User, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(usersResource, name, pt, data, subresources...), &v1alpha2.User{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.User), 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 new file mode 100644 index 00000000..6a63cac5 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/generated_expansion.go @@ -0,0 +1,21 @@ +/* +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 + +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 new file mode 100644 index 00000000..a18e2b5a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/iam_client.go @@ -0,0 +1,89 @@ +/* +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 ( + rest "k8s.io/client-go/rest" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +type IamV1alpha2Interface interface { + RESTClient() rest.Interface + UsersGetter +} + +// IamV1alpha2Client is used to interact with features provided by the iam.kubesphere.io group. +type IamV1alpha2Client struct { + restClient rest.Interface +} + +func (c *IamV1alpha2Client) Users() UserInterface { + return newUsers(c) +} + +// NewForConfig creates a new IamV1alpha2Client for the given config. +func NewForConfig(c *rest.Config) (*IamV1alpha2Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &IamV1alpha2Client{client}, nil +} + +// NewForConfigOrDie creates a new IamV1alpha2Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *IamV1alpha2Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new IamV1alpha2Client for the given RESTClient. +func New(c rest.Interface) *IamV1alpha2Client { + return &IamV1alpha2Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha2.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 *IamV1alpha2Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/iam/v1alpha2/user.go b/pkg/client/clientset/versioned/typed/iam/v1alpha2/user.go new file mode 100644 index 00000000..ea25d4ac --- /dev/null +++ b/pkg/client/clientset/versioned/typed/iam/v1alpha2/user.go @@ -0,0 +1,180 @@ +/* +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" +) + +// UsersGetter has a method to return a UserInterface. +// A group's client should implement this interface. +type UsersGetter interface { + Users() UserInterface +} + +// UserInterface has methods to work with User resources. +type UserInterface interface { + Create(*v1alpha2.User) (*v1alpha2.User, error) + Update(*v1alpha2.User) (*v1alpha2.User, error) + UpdateStatus(*v1alpha2.User) (*v1alpha2.User, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha2.User, error) + List(opts v1.ListOptions) (*v1alpha2.UserList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.User, err error) + UserExpansion +} + +// users implements UserInterface +type users struct { + client rest.Interface +} + +// newUsers returns a Users +func newUsers(c *IamV1alpha2Client) *users { + return &users{ + client: c.RESTClient(), + } +} + +// Get takes name of the user, and returns the corresponding user object, and an error if there is any. +func (c *users) Get(name string, options v1.GetOptions) (result *v1alpha2.User, err error) { + result = &v1alpha2.User{} + err = c.client.Get(). + Resource("users"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Users that match those selectors. +func (c *users) List(opts v1.ListOptions) (result *v1alpha2.UserList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha2.UserList{} + err = c.client.Get(). + Resource("users"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested users. +func (c *users) 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("users"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a user and creates it. Returns the server's representation of the user, and an error, if there is any. +func (c *users) Create(user *v1alpha2.User) (result *v1alpha2.User, err error) { + result = &v1alpha2.User{} + err = c.client.Post(). + Resource("users"). + Body(user). + Do(). + Into(result) + return +} + +// Update takes the representation of a user and updates it. Returns the server's representation of the user, and an error, if there is any. +func (c *users) Update(user *v1alpha2.User) (result *v1alpha2.User, err error) { + result = &v1alpha2.User{} + err = c.client.Put(). + Resource("users"). + Name(user.Name). + Body(user). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *users) UpdateStatus(user *v1alpha2.User) (result *v1alpha2.User, err error) { + result = &v1alpha2.User{} + err = c.client.Put(). + Resource("users"). + Name(user.Name). + SubResource("status"). + Body(user). + Do(). + Into(result) + return +} + +// Delete takes name of the user and deletes it. Returns an error if one occurs. +func (c *users) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Resource("users"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *users) 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("users"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched user. +func (c *users) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.User, err error) { + result = &v1alpha2.User{} + err = c.client.Patch(pt). + Resource("users"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 8134dd6e..d75bcfcf 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -29,6 +29,7 @@ import ( cache "k8s.io/client-go/tools/cache" versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" devops "kubesphere.io/kubesphere/pkg/client/informers/externalversions/devops" + iam "kubesphere.io/kubesphere/pkg/client/informers/externalversions/iam" internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" network "kubesphere.io/kubesphere/pkg/client/informers/externalversions/network" servicemesh "kubesphere.io/kubesphere/pkg/client/informers/externalversions/servicemesh" @@ -176,6 +177,7 @@ type SharedInformerFactory interface { WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool Devops() devops.Interface + Iam() iam.Interface Network() network.Interface Servicemesh() servicemesh.Interface Tenant() tenant.Interface @@ -185,6 +187,10 @@ func (f *sharedInformerFactory) Devops() devops.Interface { return devops.New(f, f.namespace, f.tweakListOptions) } +func (f *sharedInformerFactory) Iam() iam.Interface { + return iam.New(f, f.namespace, f.tweakListOptions) +} + func (f *sharedInformerFactory) Network() network.Interface { return network.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index b4763dd3..36ab98cd 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -24,8 +24,9 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" + v1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" networkv1alpha1 "kubesphere.io/kubesphere/pkg/apis/network/v1alpha1" - v1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2" + servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" ) @@ -65,6 +66,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha1.SchemeGroupVersion.WithResource("s2iruns"): return &genericInformer{resource: resource.GroupResource(), informer: f.Devops().V1alpha1().S2iRuns().Informer()}, nil + // Group=iam.kubesphere.io, Version=v1alpha2 + case v1alpha2.SchemeGroupVersion.WithResource("users"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Iam().V1alpha2().Users().Informer()}, nil + // Group=network.kubesphere.io, Version=v1alpha1 case networkv1alpha1.SchemeGroupVersion.WithResource("namespacenetworkpolicies"): return &genericInformer{resource: resource.GroupResource(), informer: f.Network().V1alpha1().NamespaceNetworkPolicies().Informer()}, nil @@ -72,9 +77,9 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Network().V1alpha1().WorkspaceNetworkPolicies().Informer()}, nil // Group=servicemesh.kubesphere.io, Version=v1alpha2 - case v1alpha2.SchemeGroupVersion.WithResource("servicepolicies"): + case servicemeshv1alpha2.SchemeGroupVersion.WithResource("servicepolicies"): return &genericInformer{resource: resource.GroupResource(), informer: f.Servicemesh().V1alpha2().ServicePolicies().Informer()}, nil - case v1alpha2.SchemeGroupVersion.WithResource("strategies"): + case servicemeshv1alpha2.SchemeGroupVersion.WithResource("strategies"): return &genericInformer{resource: resource.GroupResource(), informer: f.Servicemesh().V1alpha2().Strategies().Informer()}, nil // Group=tenant.kubesphere.io, Version=v1alpha1 diff --git a/pkg/client/informers/externalversions/iam/interface.go b/pkg/client/informers/externalversions/iam/interface.go new file mode 100644 index 00000000..544e94cd --- /dev/null +++ b/pkg/client/informers/externalversions/iam/interface.go @@ -0,0 +1,46 @@ +/* +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 iam + +import ( + v1alpha2 "kubesphere.io/kubesphere/pkg/client/informers/externalversions/iam/v1alpha2" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha2 provides access to shared informers for resources in V1alpha2. + V1alpha2() v1alpha2.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} +} + +// V1alpha2 returns a new v1alpha2.Interface. +func (g *group) V1alpha2() v1alpha2.Interface { + return v1alpha2.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/iam/v1alpha2/interface.go b/pkg/client/informers/externalversions/iam/v1alpha2/interface.go new file mode 100644 index 00000000..f75006b7 --- /dev/null +++ b/pkg/client/informers/externalversions/iam/v1alpha2/interface.go @@ -0,0 +1,45 @@ +/* +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 ( + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Users returns a UserInformer. + Users() UserInformer +} + +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} +} + +// 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/user.go b/pkg/client/informers/externalversions/iam/v1alpha2/user.go new file mode 100644 index 00000000..c2cfb157 --- /dev/null +++ b/pkg/client/informers/externalversions/iam/v1alpha2/user.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" +) + +// UserInformer provides access to a shared informer and lister for +// Users. +type UserInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha2.UserLister +} + +type userInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewUserInformer constructs a new informer for User 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 NewUserInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredUserInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredUserInformer constructs a new informer for User 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 NewFilteredUserInformer(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().Users().List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.IamV1alpha2().Users().Watch(options) + }, + }, + &iamv1alpha2.User{}, + resyncPeriod, + indexers, + ) +} + +func (f *userInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredUserInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *userInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&iamv1alpha2.User{}, f.defaultInformer) +} + +func (f *userInformer) Lister() v1alpha2.UserLister { + return v1alpha2.NewUserLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/listers/iam/v1alpha2/expansion_generated.go b/pkg/client/listers/iam/v1alpha2/expansion_generated.go new file mode 100644 index 00000000..b75d2871 --- /dev/null +++ b/pkg/client/listers/iam/v1alpha2/expansion_generated.go @@ -0,0 +1,23 @@ +/* +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 + +// UserListerExpansion allows custom methods to be added to +// UserLister. +type UserListerExpansion interface{} diff --git a/pkg/client/listers/iam/v1alpha2/user.go b/pkg/client/listers/iam/v1alpha2/user.go new file mode 100644 index 00000000..99090df7 --- /dev/null +++ b/pkg/client/listers/iam/v1alpha2/user.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" +) + +// UserLister helps list Users. +type UserLister interface { + // List lists all Users in the indexer. + List(selector labels.Selector) (ret []*v1alpha2.User, err error) + // Get retrieves the User from the index for a given name. + Get(name string) (*v1alpha2.User, error) + UserListerExpansion +} + +// userLister implements the UserLister interface. +type userLister struct { + indexer cache.Indexer +} + +// NewUserLister returns a new UserLister. +func NewUserLister(indexer cache.Indexer) UserLister { + return &userLister{indexer: indexer} +} + +// List lists all Users in the indexer. +func (s *userLister) List(selector labels.Selector) (ret []*v1alpha2.User, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.User)) + }) + return ret, err +} + +// Get retrieves the User from the index for a given name. +func (s *userLister) Get(name string) (*v1alpha2.User, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha2.Resource("user"), name) + } + return obj.(*v1alpha2.User), nil +} diff --git a/pkg/controller/user/user_controller.go b/pkg/controller/user/user_controller.go new file mode 100644 index 00000000..c31117be --- /dev/null +++ b/pkg/controller/user/user_controller.go @@ -0,0 +1,228 @@ +/* +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 user + +import ( + "fmt" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/record" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + kubesphereclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + kubespherescheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" + userinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/iam/v1alpha2" + userlister "kubesphere.io/kubesphere/pkg/client/listers/iam/v1alpha2" + "time" +) + +const ( + // SuccessSynced is used as part of the Event 'reason' when a Foo is synced + successSynced = "Synced" + // is synced successfully + messageResourceSynced = "User synced successfully" + controllerName = "user-controller" +) + +type Controller struct { + kubeClientset kubernetes.Interface + kubesphereClientset kubesphereclient.Interface + + userInformer userinformer.UserInformer + userLister userlister.UserLister + userSynced cache.InformerSynced + // workqueue is a rate limited work queue. This is used to queue work to be + // processed instead of performing it as soon as a change happens. This + // means we can ensure we only process a fixed amount of resources at a + // time, and makes it easy to ensure we are never processing the same item + // simultaneously in two different workers. + workqueue workqueue.RateLimitingInterface + // recorder is an event recorder for recording Event resources to the + // Kubernetes API. + recorder record.EventRecorder +} + +func NewController(kubeclientset kubernetes.Interface, + kubesphereklientset kubesphereclient.Interface, + userInformer userinformer.UserInformer) *Controller { + + // Create event broadcaster + // Add sample-controller types to the default Kubernetes Scheme so Events can be + // logged for sample-controller types. + + utilruntime.Must(kubespherescheme.AddToScheme(scheme.Scheme)) + klog.V(4).Info("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + eventBroadcaster.StartLogging(klog.Infof) + eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")}) + recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerName}) + ctl := &Controller{ + kubeClientset: kubeclientset, + kubesphereClientset: kubesphereklientset, + userInformer: userInformer, + userLister: userInformer.Lister(), + userSynced: userInformer.Informer().HasSynced, + workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Users"), + recorder: recorder, + } + klog.Info("Setting up event handlers") + userInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: ctl.enqueueUser, + UpdateFunc: func(old, new interface{}) { + ctl.enqueueUser(new) + }, + DeleteFunc: ctl.enqueueUser, + }) + return ctl +} + +func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { + defer utilruntime.HandleCrash() + defer c.workqueue.ShutDown() + + //init client + + // Start the informer factories to begin populating the informer caches + klog.Info("Starting User controller") + + // Wait for the caches to be synced before starting workers + klog.Info("Waiting for informer caches to sync") + if ok := cache.WaitForCacheSync(stopCh, c.userSynced); !ok { + return fmt.Errorf("failed to wait for caches to sync") + } + + klog.Info("Starting workers") + // Launch two workers to process Foo resources + for i := 0; i < threadiness; i++ { + go wait.Until(c.runWorker, time.Second, stopCh) + } + + klog.Info("Started workers") + <-stopCh + klog.Info("Shutting down workers") + return nil +} + +func (c *Controller) enqueueUser(obj interface{}) { + var key string + var err error + if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil { + utilruntime.HandleError(err) + return + } + c.workqueue.Add(key) +} + +func (c *Controller) runWorker() { + for c.processNextWorkItem() { + } +} + +func (c *Controller) processNextWorkItem() bool { + obj, shutdown := c.workqueue.Get() + + if shutdown { + return false + } + + // We wrap this block in a func so we can defer c.workqueue.Done. + err := func(obj interface{}) error { + // We call Done here so the workqueue knows we have finished + // processing this item. We also must remember to call Forget if we + // do not want this work item being re-queued. For example, we do + // not call Forget if a transient error occurs, instead the item is + // put back on the workqueue and attempted again after a back-off + // period. + defer c.workqueue.Done(obj) + var key string + var ok bool + // We expect strings to come off the workqueue. These are of the + // form namespace/name. We do this as the delayed nature of the + // workqueue means the items in the informer cache may actually be + // more up to date that when the item was initially put onto the + // workqueue. + if key, ok = obj.(string); !ok { + // As the item in the workqueue is actually invalid, we call + // Forget here else we'd go into a loop of attempting to + // process a work item that is invalid. + c.workqueue.Forget(obj) + utilruntime.HandleError(fmt.Errorf("expected string in workqueue but got %#v", obj)) + return nil + } + // Run the reconcile, passing it the namespace/name string of the + // Foo resource to be synced. + if err := c.reconcile(key); err != nil { + // Put the item back on the workqueue to handle any transient errors. + c.workqueue.AddRateLimited(key) + return fmt.Errorf("error syncing '%s': %s, requeuing", key, err.Error()) + } + // Finally, if no error occurs we Forget this item so it does not + // get queued again until another change happens. + c.workqueue.Forget(obj) + klog.Info("Successfully synced", "key", key) + return nil + }(obj) + + if err != nil { + utilruntime.HandleError(err) + return true + } + + return true +} + +// syncHandler compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the Foo resource +// with the current status of the resource. +func (c *Controller) reconcile(key string) error { + + // Get the user with this name + user, err := c.userLister.Get(key) + if err != nil { + // The user may no longer exist, in which case we stop + // processing. + if errors.IsNotFound(err) { + utilruntime.HandleError(fmt.Errorf("user '%s' in work queue no longer exists", key)) + return nil + } + + return err + } + + err = c.updateUserStatus(user) + if err != nil { + return err + } + + c.recorder.Event(user, corev1.EventTypeNormal, successSynced, messageResourceSynced) + return nil +} + +func (c *Controller) updateUserStatus(user *iamv1alpha2.User) error { + + userCopy := user.DeepCopy() + userCopy.Status.Phase = iamv1alpha2.UserActive + _, err := c.kubesphereClientset.IamV1alpha2().Users().Update(userCopy) + return err +} diff --git a/pkg/controller/user/user_controller_test.go b/pkg/controller/user/user_controller_test.go new file mode 100644 index 00000000..bf364b9e --- /dev/null +++ b/pkg/controller/user/user_controller_test.go @@ -0,0 +1,245 @@ +/* +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 user + +import ( + "fmt" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/diff" + kubeinformers "k8s.io/client-go/informers" + k8sfake "k8s.io/client-go/kubernetes/fake" + core "k8s.io/client-go/testing" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/record" + iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" + informers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "reflect" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var ( + alwaysReady = func() bool { return true } + noResyncPeriodFunc = func() time.Duration { return 0 } +) + +type fixture struct { + t *testing.T + + client *fake.Clientset + kubeclient *k8sfake.Clientset + // Objects to put in the store. + userLister []*iamv1alpha2.User + // Actions expected to happen on the client. + kubeactions []core.Action + actions []core.Action + // Objects from here preloaded into NewSimpleFake. + kubeobjects []runtime.Object + objects []runtime.Object +} + +func newFixture(t *testing.T) *fixture { + f := &fixture{} + f.t = t + f.objects = []runtime.Object{} + f.kubeobjects = []runtime.Object{} + return f +} + +func newUser(name string) *iamv1alpha2.User { + return &iamv1alpha2.User{ + TypeMeta: metav1.TypeMeta{APIVersion: iamv1alpha2.SchemeGroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: iamv1alpha2.UserSpec{ + Email: fmt.Sprintf("%s@kubesphere.io", name), + Lang: "zh-CN", + Description: "fake user", + }, + } +} + +func (f *fixture) newController() (*Controller, informers.SharedInformerFactory, kubeinformers.SharedInformerFactory) { + f.client = fake.NewSimpleClientset(f.objects...) + f.kubeclient = k8sfake.NewSimpleClientset(f.kubeobjects...) + + i := informers.NewSharedInformerFactory(f.client, noResyncPeriodFunc()) + k8sI := kubeinformers.NewSharedInformerFactory(f.kubeclient, noResyncPeriodFunc()) + + for _, user := range f.userLister { + err := i.Iam().V1alpha2().Users().Informer().GetIndexer().Add(user) + if err != nil { + f.t.Errorf("add user:%s", err) + } + } + + c := NewController(f.kubeclient, f.client, i.Iam().V1alpha2().Users()) + c.userSynced = alwaysReady + c.recorder = &record.FakeRecorder{} + + return c, i, k8sI +} + +func (f *fixture) run(userName string) { + f.runController(userName, true, false) +} + +func (f *fixture) runExpectError(userName string) { + f.runController(userName, true, true) +} + +func (f *fixture) runController(user string, startInformers bool, expectError bool) { + c, i, k8sI := f.newController() + if startInformers { + stopCh := make(chan struct{}) + defer close(stopCh) + i.Start(stopCh) + k8sI.Start(stopCh) + } + + err := c.reconcile(user) + if !expectError && err != nil { + f.t.Errorf("error syncing user: %v", err) + } else if expectError && err == nil { + f.t.Error("expected error syncing user, got nil") + } + + actions := filterInformerActions(f.client.Actions()) + for i, action := range actions { + if len(f.actions) < i+1 { + f.t.Errorf("%d unexpected actions: %+v", len(actions)-len(f.actions), actions[i:]) + break + } + + expectedAction := f.actions[i] + checkAction(expectedAction, action, f.t) + } + + if len(f.actions) > len(actions) { + f.t.Errorf("%d additional expected actions:%+v", len(f.actions)-len(actions), f.actions[len(actions):]) + } + + k8sActions := filterInformerActions(f.kubeclient.Actions()) + for i, action := range k8sActions { + if len(f.kubeactions) < i+1 { + f.t.Errorf("%d unexpected actions: %+v", len(k8sActions)-len(f.kubeactions), k8sActions[i:]) + break + } + + expectedAction := f.kubeactions[i] + checkAction(expectedAction, action, f.t) + } + + if len(f.kubeactions) > len(k8sActions) { + f.t.Errorf("%d additional expected actions:%+v", len(f.kubeactions)-len(k8sActions), f.kubeactions[len(k8sActions):]) + } +} + +// checkAction verifies that expected and actual actions are equal and both have +// same attached resources +func checkAction(expected, actual core.Action, t *testing.T) { + if !(expected.Matches(actual.GetVerb(), actual.GetResource().Resource) && actual.GetSubresource() == expected.GetSubresource()) { + t.Errorf("Expected\n\t%#v\ngot\n\t%#v", expected, actual) + return + } + + if reflect.TypeOf(actual) != reflect.TypeOf(expected) { + t.Errorf("Action has wrong type. Expected: %t. Got: %t", expected, actual) + return + } + + switch a := actual.(type) { + case core.CreateActionImpl: + e, _ := expected.(core.CreateActionImpl) + expObject := e.GetObject() + object := a.GetObject() + + if !reflect.DeepEqual(expObject, object) { + t.Errorf("Action %s %s has wrong object\nDiff:\n %s", + a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expObject, object)) + } + case core.UpdateActionImpl: + e, _ := expected.(core.UpdateActionImpl) + expObject := e.GetObject() + object := a.GetObject() + + if !reflect.DeepEqual(expObject, object) { + t.Errorf("Action %s %s has wrong object\nDiff:\n %s", + a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expObject, object)) + } + case core.PatchActionImpl: + e, _ := expected.(core.PatchActionImpl) + expPatch := e.GetPatch() + patch := a.GetPatch() + + if !reflect.DeepEqual(expPatch, patch) { + t.Errorf("Action %s %s has wrong patch\nDiff:\n %s", + a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expPatch, patch)) + } + default: + t.Errorf("Uncaptured Action %s %s, you should explicitly add a case to capture it", + actual.GetVerb(), actual.GetResource().Resource) + } +} + +// filterInformerActions filters list and watch actions for testing resources. +// Since list and watch don't change resource state we can filter it to lower +// nose level in our tests. +func filterInformerActions(actions []core.Action) []core.Action { + var ret []core.Action + for _, action := range actions { + if action.Matches("list", "users") || + action.Matches("watch", "users") { + continue + } + ret = append(ret, action) + } + + return ret +} + +func (f *fixture) expectUpdateUserStatusAction(user *iamv1alpha2.User) { + expect := user.DeepCopy() + expect.Status.Phase = iamv1alpha2.UserActive + action := core.NewUpdateAction(schema.GroupVersionResource{Resource: "users"}, "", expect) + f.actions = append(f.actions, action) +} + +func getKey(user *iamv1alpha2.User, t *testing.T) string { + key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(user) + if err != nil { + t.Errorf("Unexpected error getting key for user %v: %v", user.Name, err) + return "" + } + return key +} + +func TestDoNothing(t *testing.T) { + f := newFixture(t) + user := newUser("test") + + f.userLister = append(f.userLister, user) + f.objects = append(f.objects, user) + + f.expectUpdateUserStatusAction(user) + f.run(getKey(user, t)) +} diff --git a/pkg/models/registries/image.go b/pkg/models/registries/image.go index 1d5f725b..71caa444 100644 --- a/pkg/models/registries/image.go +++ b/pkg/models/registries/image.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/docker/distribution/reference" - digest "github.com/opencontainers/go-digest" + "github.com/opencontainers/go-digest" ) // Image holds information about an image. diff --git a/pkg/simple/client/cache/simple_cache.go b/pkg/simple/client/cache/simple_cache.go index be0a6d9d..55dc5442 100644 --- a/pkg/simple/client/cache/simple_cache.go +++ b/pkg/simple/client/cache/simple_cache.go @@ -34,7 +34,7 @@ func (s *simpleCache) Keys(pattern string) ([]string, error) { return nil, err } var keys []string - for k, _ := range s.store { + for k := range s.store { if re.MatchString(k) { keys = append(keys, k) } diff --git a/pkg/simple/client/devops/jenkins/build.go b/pkg/simple/client/devops/jenkins/build.go index 43f81a19..b2b4e9a6 100644 --- a/pkg/simple/client/devops/jenkins/build.go +++ b/pkg/simple/client/devops/jenkins/build.go @@ -339,7 +339,7 @@ func (b *Build) GetRevisionBranch() string { } func (b *Build) IsGood() bool { - return (!b.IsRunning() && b.Raw.Result == STATUS_SUCCESS) + return !b.IsRunning() && b.Raw.Result == STATUS_SUCCESS } func (b *Build) IsRunning() bool { diff --git a/pkg/simple/client/mysql/options.go b/pkg/simple/client/mysql/options.go index dc0d545d..e17b2730 100644 --- a/pkg/simple/client/mysql/options.go +++ b/pkg/simple/client/mysql/options.go @@ -2,7 +2,7 @@ package mysql import ( "github.com/spf13/pflag" - reflectutils "kubesphere.io/kubesphere/pkg/utils/reflectutils" + "kubesphere.io/kubesphere/pkg/utils/reflectutils" "time" ) -- GitLab