diff --git a/Makefile b/Makefile index 478adb549dfc9f316b7c403815ee83d632dde947..c62af8adfeacc9dc872ac41e2dcc3f906ece8565 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ define ALL_HELP_INFO # debugging tools like delve. endef .PHONY: all -all: test ks-apiserver ks-apigateway ks-iam controller-manager +all: test ks-apiserver ks-apigateway ks-iam controller-manager generate-apis # Build ks-apiserver binary ks-apiserver: test @@ -58,39 +58,37 @@ controller-manager: test hack/gobuild.sh cmd/controller-manager # Run go fmt against code -fmt: +fmt: generate-apis go fmt ./pkg/... ./cmd/... # Run go vet against code -vet: +vet: generate-apis go vet ./pkg/... ./cmd/... # Generate manifests e.g. CRD, RBAC etc. manifests: go run vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go all -crds: - $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./pkg/apis/network/..." output:crd:artifacts:config=config/crd/bases +crds: generate-apis + $(CONTROLLER_GEN) crd:trivialVersions=true paths="./pkg/apis/devops/..." output:crd:artifacts:config=config/crds + deploy: manifests kubectl apply -f config/crds kustomize build config/default | kubectl apply -f - -# Generate DeepCopy to implement runtime.Object -deepcopy: - ./vendor/k8s.io/code-generator/generate-groups.sh all kubesphere.io/kubesphere/pkg/client kubesphere.io/kubesphere/pkg/apis "servicemesh:v1alpha2 tenant:v1alpha1" - -generate: +generate: crds go generate ./pkg/... ./cmd/... # Generate code generate-apis: controller-gen $(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths=./pkg/apis/... + # Build the docker image docker-build: all docker build . -t ${IMG} # Run tests -test: generate fmt vet +test: generate fmt vet generate-apis go test ./pkg/... ./cmd/... -coverprofile cover.out .PHONY: clean diff --git a/config/crds/devops.kubesphere.io_s2ibinaries.yaml b/config/crds/devops.kubesphere.io_s2ibinaries.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1d3cc57ef60262fe6613316c67ce9f1e8f45d4e4 --- /dev/null +++ b/config/crds/devops.kubesphere.io_s2ibinaries.yaml @@ -0,0 +1,394 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + name: s2ibinaries.devops.kubesphere.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.fileName + name: FileName + type: string + - JSONPath: .spec.md5 + name: MD5 + type: string + - JSONPath: .spec.size + name: Size + type: string + - JSONPath: .status.phase + name: Phase + type: string + group: devops.kubesphere.io + names: + kind: S2iBinary + plural: s2ibinaries + scope: "" + subresources: {} + validation: + openAPIV3Schema: + description: S2iBinary is the Schema for the s2ibinaries 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/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/api-conventions.md#types-kinds' + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value map stored with + a resource that may be set by external tools to store and retrieve + arbitrary metadata. They are not queryable and should be preserved + when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations' + type: object + clusterName: + description: The name of the cluster which the object belongs to. This + is used to distinguish resources with same name and namespace in different + clusters. This field is not set anywhere right now and apiserver is + going to ignore it if set in create or update request. + type: string + creationTimestamp: + description: "CreationTimestamp is a timestamp representing the server + time when this object was created. It is not guaranteed to be set + in happens-before order across separate operations. Clients may not + set this value. It is represented in RFC3339 form and is in UTC. \n + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata" + format: date-time + type: string + deletionGracePeriodSeconds: + description: Number of seconds allowed for this object to gracefully + terminate before it will be removed from the system. Only set when + deletionTimestamp is also set. May only be shortened. Read-only. + format: int64 + type: integer + deletionTimestamp: + description: "DeletionTimestamp is RFC 3339 date and time at which this + resource will be deleted. This field is set by the server when a graceful + deletion is requested by the user, and is not directly settable by + a client. The resource is expected to be deleted (no longer visible + from resource lists, and not reachable by name) after the time in + this field, once the finalizers list is empty. As long as the finalizers + list contains items, deletion is blocked. Once the deletionTimestamp + is set, this value may not be unset or be set further into the future, + although it may be shortened or the resource may be deleted prior + to this time. For example, a user may request that a pod is deleted + in 30 seconds. The Kubelet will react by sending a graceful termination + signal to the containers in the pod. After that 30 seconds, the Kubelet + will send a hard termination signal (SIGKILL) to the container and + after cleanup, remove the pod from the API. In the presence of network + partitions, this object may still exist after this timestamp, until + an administrator or automated process can determine the resource is + fully terminated. If not set, graceful deletion of the object has + not been requested. \n Populated by the system when a graceful deletion + is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata" + format: date-time + type: string + finalizers: + description: Must be empty before the object is deleted from the registry. + Each entry is an identifier for the responsible component that will + remove the entry from the list. If the deletionTimestamp of the object + is non-nil, entries in this list can only be removed. + items: + type: string + type: array + generateName: + description: "GenerateName is an optional prefix, used by the server, + to generate a unique name ONLY IF the Name field has not been provided. + If this field is used, the name returned to the client will be different + than the name passed. This value will also be combined with a unique + suffix. The provided value has the same validation rules as the Name + field, and may be truncated by the length of the suffix required to + make the value unique on the server. \n If this field is specified + and the generated name exists, the server will NOT return a 409 - + instead, it will either return 201 Created or 500 with Reason ServerTimeout + indicating a unique name could not be found in the time allotted, + and the client should retry (optionally after the time indicated in + the Retry-After header). \n Applied only if Name is not specified. + More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#idempotency" + type: string + generation: + description: A sequence number representing a specific generation of + the desired state. Populated by the system. Read-only. + format: int64 + type: integer + initializers: + description: "An initializer is a controller which enforces some system + invariant at object creation time. This field is a list of initializers + that have not yet acted on this object. If nil or empty, this object + has been completely initialized. Otherwise, the object is considered + uninitialized and is hidden (in list/watch and get calls) from clients + that haven't explicitly asked to observe uninitialized objects. \n + When an object is created, the system will populate this list with + the current set of initializers. Only privileged users may set or + modify this list. Once it is empty, it may not be modified further + by any user." + properties: + pending: + description: Pending is a list of initializers that must execute + in order before this object is visible. When the last pending + initializer is removed, and no failing result is set, the initializers + struct will be set to nil and the object is considered as initialized + and visible to all clients. + items: + properties: + name: + description: name of the process that is responsible for initializing + this object. + type: string + required: + - name + type: object + type: array + result: + description: If result is set with the Failure field, the object + will be persisted to storage and then deleted, ensuring that other + clients can observe the deletion. + 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/api-conventions.md#resources' + type: string + code: + description: Suggested HTTP return code for this status, 0 if + not set. + format: int32 + type: integer + details: + description: Extended data associated with the reason. Each + reason may define its own extended details. This field is + optional and the data returned is not guaranteed to conform + to any schema except that defined by the reason type. + properties: + causes: + description: The Causes array includes more details associated + with the StatusReason failure. Not all StatusReasons may + provide detailed causes. + items: + properties: + field: + description: "The field of the resource that has caused + this error, as named by its JSON serialization. + May include dot and postfix notation for nested + attributes. Arrays are zero-indexed. Fields may + appear more than once in an array of causes due + to fields having multiple errors. Optional. \n Examples: + \ \"name\" - the field \"name\" on the current + resource \"items[0].name\" - the field \"name\" + on the first array entry in \"items\"" + type: string + message: + description: A human-readable description of the cause + of the error. This field may be presented as-is + to a reader. + type: string + reason: + description: A machine-readable description of the + cause of the error. If this value is empty there + is no information available. + type: string + type: object + type: array + group: + description: The group attribute of the resource associated + with the status StatusReason. + type: string + kind: + description: 'The kind attribute of the resource associated + with the status StatusReason. On some operations may differ + from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' + type: string + name: + description: The name attribute of the resource associated + with the status StatusReason (when there is a single name + which can be described). + type: string + retryAfterSeconds: + description: If specified, the time in seconds before the + operation should be retried. Some errors may indicate + the client must take an alternate action - for those errors + this field may indicate how long to wait before taking + the alternate action. + format: int32 + type: integer + uid: + description: 'UID of the resource. (when there is a single + resource which can be described). More info: http://kubernetes.io/docs/user-guide/identifiers#uids' + type: string + type: object + 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/api-conventions.md#types-kinds' + type: string + message: + description: A human-readable description of the status of this + operation. + type: string + metadata: + description: 'Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' + properties: + continue: + description: continue may be set if the user set a limit + on the number of items returned, and indicates that the + server has more data available. The value is opaque and + may be used to issue another request to the endpoint that + served this list to retrieve the next set of available + objects. Continuing a consistent list may not be possible + if the server configuration has changed or more than a + few minutes have passed. The resourceVersion field returned + when using this continue value will be identical to the + value in the first response, unless you have received + this token from an error message. + type: string + resourceVersion: + description: 'String that identifies the server''s internal + version of this object that can be used by clients to + determine when objects have changed. Value must be treated + as opaque by clients and passed unmodified back to the + server. Populated by the system. Read-only. More info: + https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency' + type: string + selfLink: + description: selfLink is a URL representing this object. + Populated by the system. Read-only. + type: string + type: object + reason: + description: A machine-readable description of why this operation + is in the "Failure" status. If this value is empty there is + no information available. A Reason clarifies an HTTP status + code but does not override it. + type: string + status: + description: 'Status of the operation. One of: "Success" or + "Failure". More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status' + type: string + type: object + required: + - pending + type: object + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be used to organize + and categorize (scope and select) objects. May match selectors of + replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels' + type: object + name: + description: 'Name must be unique within a namespace. Is required when + creating resources, although some resources may allow a client to + request the generation of an appropriate name automatically. Name + is primarily intended for creation idempotence and configuration definition. + Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names' + type: string + namespace: + description: "Namespace defines the space within each name must be unique. + An empty namespace is equivalent to the \"default\" namespace, but + \"default\" is the canonical representation. Not all objects are required + to be scoped to a namespace - the value of this field for those objects + will be empty. \n Must be a DNS_LABEL. Cannot be updated. More info: + http://kubernetes.io/docs/user-guide/namespaces" + type: string + ownerReferences: + description: List of objects depended by this object. If ALL objects + in the list have been deleted, this object will be garbage collected. + If this object is managed by a controller, then an entry in this list + will point to this controller, with the controller field set to true. + There cannot be more than one managing controller. + items: + properties: + apiVersion: + description: API version of the referent. + type: string + blockOwnerDeletion: + description: If true, AND if the owner has the "foregroundDeletion" + finalizer, then the owner cannot be deleted from the key-value + store until this reference is removed. Defaults to false. To + set this field, a user needs "delete" permission of the owner, + otherwise 422 (Unprocessable Entity) will be returned. + type: boolean + controller: + description: If true, this reference points to the managing controller. + type: boolean + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names' + type: string + uid: + description: 'UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids' + type: string + required: + - apiVersion + - kind + - name + - uid + type: object + type: array + resourceVersion: + description: "An opaque value that represents the internal version of + this object that can be used by clients to determine when objects + have changed. May be used for optimistic concurrency, change detection, + and the watch operation on a resource or set of resources. Clients + must treat these values as opaque and passed unmodified back to the + server. They may only be valid for a particular resource or set of + resources. \n Populated by the system. Read-only. Value must be treated + as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency" + type: string + selfLink: + description: SelfLink is a URL representing this object. Populated by + the system. Read-only. + type: string + uid: + description: "UID is the unique in time and space value for this object. + It is typically generated by the server on successful creation of + a resource and is not allowed to change on PUT operations. \n Populated + by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers#uids" + type: string + type: object + spec: + properties: + downloadURL: + description: DownloadURL in KubeSphere + type: string + fileName: + description: FileName is filename of binary + type: string + md5: + description: MD5 is Binary's MD5 Hash + type: string + size: + description: Size is the file size of file + type: string + uploadTimeStamp: + description: UploadTime is last upload time + format: date-time + type: string + type: object + status: + properties: + phase: + description: Phase is status of S2iBinary . Possible value is "Ready","UnableToDownload" + type: string + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/pkg/apis/addtoscheme_devops_v1alpha1.go b/pkg/apis/addtoscheme_devops_v1alpha1.go new file mode 100644 index 0000000000000000000000000000000000000000..8a09ff3eef9b31a2efb7a801b4a2057a07af49a5 --- /dev/null +++ b/pkg/apis/addtoscheme_devops_v1alpha1.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 ( + "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme) +} diff --git a/pkg/apis/devops/group.go b/pkg/apis/devops/group.go new file mode 100644 index 0000000000000000000000000000000000000000..829b784ea3ddd2c4593470e67c2db8537f4b78ad --- /dev/null +++ b/pkg/apis/devops/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 devops contains devops API versions +package devops diff --git a/pkg/apis/devops/v1alpha1/doc.go b/pkg/apis/devops/v1alpha1/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..0411bf7a749b9c77b94c889f304df6706936d640 --- /dev/null +++ b/pkg/apis/devops/v1alpha1/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 v1alpha1 contains API Schema definitions for the devops v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=kubesphere.io/kubesphere/pkg/apis/devops +// +k8s:defaulter-gen=TypeMeta +// +groupName=devops.kubesphere.io +package v1alpha1 diff --git a/pkg/apis/devops/v1alpha1/register.go b/pkg/apis/devops/v1alpha1/register.go new file mode 100644 index 0000000000000000000000000000000000000000..b0b72eff6b658b98c58fef17a08dc140abd9dab1 --- /dev/null +++ b/pkg/apis/devops/v1alpha1/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 v1alpha1 contains API Schema definitions for the devops v1alpha1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=kubesphere.io/kubesphere/pkg/apis/devops +// +k8s:defaulter-gen=TypeMeta +// +groupName=devops.kubesphere.io +package v1alpha1 + +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: "devops.kubesphere.io", Version: "v1alpha1"} + + // 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/devops/v1alpha1/s2ibinary_types.go b/pkg/apis/devops/v1alpha1/s2ibinary_types.go new file mode 100644 index 0000000000000000000000000000000000000000..04b1a309be763b5ddddecbc96940cb363a7f5b17 --- /dev/null +++ b/pkg/apis/devops/v1alpha1/s2ibinary_types.go @@ -0,0 +1,74 @@ +/* +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 v1alpha1 + +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. + +// S2iBinarySpec defines the desired state of S2iBinary +type S2iBinarySpec struct { + //FileName is filename of binary + FileName string `json:"fileName,omitempty"` + //MD5 is Binary's MD5 Hash + MD5 string `json:"md5,omitempty"` + //Size is the file size of file + Size string `json:"size,omitempty"` + //DownloadURL in KubeSphere + DownloadURL string `json:"downloadURL,omitempty"` + // UploadTime is last upload time + UploadTimeStamp metav1.Time `json:"uploadTimeStamp,omitempty"` +} + +// S2iBinaryStatus defines the observed state of S2iBinary +type S2iBinaryStatus struct { + //Phase is status of S2iBinary . Possible value is "Ready","UnableToDownload" + Phase string `json:"phase,omitempty"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// S2iBinary is the Schema for the s2ibinaries API +// +k8s:openapi-gen=true +// +kubebuilder:printcolumn:name="FileName",type="string",JSONPath=".spec.fileName" +// +kubebuilder:printcolumn:name="MD5",type="string",JSONPath=".spec.md5" +// +kubebuilder:printcolumn:name="Size",type="string",JSONPath=".spec.size" +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase" +type S2iBinary struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec S2iBinarySpec `json:"spec,omitempty"` + Status S2iBinaryStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// S2iBinaryList contains a list of S2iBinary +type S2iBinaryList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []S2iBinary `json:"items"` +} + +func init() { + SchemeBuilder.Register(&S2iBinary{}, &S2iBinaryList{}) +} diff --git a/pkg/apis/devops/v1alpha1/s2ibinary_types_test.go b/pkg/apis/devops/v1alpha1/s2ibinary_types_test.go new file mode 100644 index 0000000000000000000000000000000000000000..bb81d6c89ed5d81018d570aff4cb9b02c810f9b3 --- /dev/null +++ b/pkg/apis/devops/v1alpha1/s2ibinary_types_test.go @@ -0,0 +1,58 @@ +/* +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 v1alpha1 + +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 TestStorageS2iBinary(t *testing.T) { + key := types.NamespacedName{ + Name: "foo", + Namespace: "default", + } + created := &S2iBinary{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }} + g := gomega.NewGomegaWithT(t) + + // Test Create + fetched := &S2iBinary{} + g.Expect(c.Create(context.TODO(), created)).NotTo(gomega.HaveOccurred()) + + g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred()) + 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)).NotTo(gomega.HaveOccurred()) + + g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred()) + g.Expect(fetched).To(gomega.Equal(updated)) + + // Test Delete + g.Expect(c.Delete(context.TODO(), fetched)).NotTo(gomega.HaveOccurred()) + g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.HaveOccurred()) +} diff --git a/pkg/apis/devops/v1alpha1/v1alpha1_suite_test.go b/pkg/apis/devops/v1alpha1/v1alpha1_suite_test.go new file mode 100644 index 0000000000000000000000000000000000000000..2206160bea864483ecbbfa1faea3d5d6d0084ac5 --- /dev/null +++ b/pkg/apis/devops/v1alpha1/v1alpha1_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 v1alpha1 + +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/devops/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000000000000000000000000000000000000..7369fb2bd4fde4b027375904f872c179c331788b --- /dev/null +++ b/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,115 @@ +// +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. +*/ + +// autogenerated by controller-gen object, do not modify manually + +package v1alpha1 + +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 *S2iBinary) DeepCopyInto(out *S2iBinary) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBinary. +func (in *S2iBinary) DeepCopy() *S2iBinary { + if in == nil { + return nil + } + out := new(S2iBinary) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *S2iBinary) 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 *S2iBinaryList) DeepCopyInto(out *S2iBinaryList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]S2iBinary, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBinaryList. +func (in *S2iBinaryList) DeepCopy() *S2iBinaryList { + if in == nil { + return nil + } + out := new(S2iBinaryList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *S2iBinaryList) 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 *S2iBinarySpec) DeepCopyInto(out *S2iBinarySpec) { + *out = *in + in.UploadTimeStamp.DeepCopyInto(&out.UploadTimeStamp) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBinarySpec. +func (in *S2iBinarySpec) DeepCopy() *S2iBinarySpec { + if in == nil { + return nil + } + out := new(S2iBinarySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *S2iBinaryStatus) DeepCopyInto(out *S2iBinaryStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBinaryStatus. +func (in *S2iBinaryStatus) DeepCopy() *S2iBinaryStatus { + if in == nil { + return nil + } + out := new(S2iBinaryStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/network/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/network/v1alpha1/zz_generated.deepcopy.go index d01da1d0abf352f307ba26e84204db763c45cc0b..4b8b8dc3a6e8c91b50ad7bd450437a09d508ae3a 100644 --- a/pkg/apis/network/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/network/v1alpha1/zz_generated.deepcopy.go @@ -63,13 +63,6 @@ func (in *WorkspaceNetworkPolicyEgressRule) DeepCopyInto(out *WorkspaceNetworkPo (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.To != nil { - in, out := &in.To, &out.To - *out = make([]WorkspaceNetworkPolicyPeer, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceNetworkPolicyEgressRule. @@ -92,13 +85,6 @@ func (in *WorkspaceNetworkPolicyIngressRule) DeepCopyInto(out *WorkspaceNetworkP (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.From != nil { - in, out := &in.From, &out.From - *out = make([]WorkspaceNetworkPolicyPeer, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceNetworkPolicyIngressRule. @@ -172,20 +158,6 @@ func (in *WorkspaceNetworkPolicySpec) DeepCopyInto(out *WorkspaceNetworkPolicySp *out = make([]v1.PolicyType, len(*in)) copy(*out, *in) } - if in.Ingress != nil { - in, out := &in.Ingress, &out.Ingress - *out = make([]WorkspaceNetworkPolicyIngressRule, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Egress != nil { - in, out := &in.Egress, &out.Egress - *out = make([]WorkspaceNetworkPolicyEgressRule, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceNetworkPolicySpec. diff --git a/pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go index ad3e11fdbf97ed074b990d893c0fc9e43c5cace6..dbc4b47905d4cda4678ffb1e92da9a4ab9b23b95 100644 --- a/pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go @@ -126,7 +126,6 @@ func (in *ServicePolicySpec) DeepCopyInto(out *ServicePolicySpec) { *out = new(v1.LabelSelector) (*in).DeepCopyInto(*out) } - in.Template.DeepCopyInto(&out.Template) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicySpec. @@ -149,16 +148,6 @@ func (in *ServicePolicyStatus) DeepCopyInto(out *ServicePolicyStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.StartTime != nil { - in, out := &in.StartTime, &out.StartTime - *out = new(v1.Time) - (*in).DeepCopyInto(*out) - } - if in.CompletionTime != nil { - in, out := &in.CompletionTime, &out.CompletionTime - *out = new(v1.Time) - (*in).DeepCopyInto(*out) - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicyStatus. @@ -255,7 +244,6 @@ func (in *StrategySpec) DeepCopyInto(out *StrategySpec) { *out = new(v1.LabelSelector) (*in).DeepCopyInto(*out) } - in.Template.DeepCopyInto(&out.Template) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategySpec. @@ -278,16 +266,6 @@ func (in *StrategyStatus) DeepCopyInto(out *StrategyStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.StartTime != nil { - in, out := &in.StartTime, &out.StartTime - *out = new(v1.Time) - (*in).DeepCopyInto(*out) - } - if in.CompletionTime != nil { - in, out := &in.CompletionTime, &out.CompletionTime - *out = new(v1.Time) - (*in).DeepCopyInto(*out) - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyStatus. diff --git a/pkg/controller/add_s2ibinary.go b/pkg/controller/add_s2ibinary.go new file mode 100644 index 0000000000000000000000000000000000000000..a116baf1ef97385fbd7cb4f732a7c4e098016c07 --- /dev/null +++ b/pkg/controller/add_s2ibinary.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 controller + +import ( + "kubesphere.io/kubesphere/pkg/controller/s2ibinary" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, s2ibinary.Add) +} diff --git a/pkg/controller/s2ibinary/s2ibinary_controller.go b/pkg/controller/s2ibinary/s2ibinary_controller.go new file mode 100644 index 0000000000000000000000000000000000000000..d3532006de42fee39f29859d40814b2c35a55dc4 --- /dev/null +++ b/pkg/controller/s2ibinary/s2ibinary_controller.go @@ -0,0 +1,169 @@ +/* +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 s2ibinary + +import ( + "context" + "reflect" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +var log = logf.Log.WithName("controller") + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new S2iBinary Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileS2iBinary{Client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("s2ibinary-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to S2iBinary + err = c.Watch(&source.Kind{Type: &devopsv1alpha1.S2iBinary{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create + // Uncomment watch a Deployment created by S2iBinary - change this for objects you create + err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &devopsv1alpha1.S2iBinary{}, + }) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &ReconcileS2iBinary{} + +// ReconcileS2iBinary reconciles a S2iBinary object +type ReconcileS2iBinary struct { + client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a S2iBinary object and makes changes based on the state read +// and what is in the S2iBinary.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes +// a Deployment as an example +// Automatically generate RBAC rules to allow the Controller to read and write Deployments +// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=devops.kubesphere.io,resources=s2ibinaries,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=devops.kubesphere.io,resources=s2ibinaries/status,verbs=get;update;patch +func (r *ReconcileS2iBinary) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Fetch the S2iBinary instance + instance := &devopsv1alpha1.S2iBinary{} + err := r.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + // TODO(user): Change this to be the object type created by your controller + // Define the desired Deployment object + deploy := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: instance.Name + "-deployment", + Namespace: instance.Namespace, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"deployment": instance.Name + "-deployment"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"deployment": instance.Name + "-deployment"}}, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "nginx", + Image: "nginx", + }, + }, + }, + }, + }, + } + if err := controllerutil.SetControllerReference(instance, deploy, r.scheme); err != nil { + return reconcile.Result{}, err + } + + // TODO(user): Change this for the object type created by your controller + // Check if the Deployment already exists + found := &appsv1.Deployment{} + err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found) + if err != nil && errors.IsNotFound(err) { + log.Info("Creating Deployment", "namespace", deploy.Namespace, "name", deploy.Name) + err = r.Create(context.TODO(), deploy) + if err != nil { + return reconcile.Result{}, err + } + } else if err != nil { + return reconcile.Result{}, err + } + + // TODO(user): Change this for the object type created by your controller + // Update the found object and write the result back if there are any changes + if !reflect.DeepEqual(deploy.Spec, found.Spec) { + found.Spec = deploy.Spec + log.Info("Updating Deployment", "namespace", deploy.Namespace, "name", deploy.Name) + err = r.Update(context.TODO(), found) + if err != nil { + return reconcile.Result{}, err + } + } + return reconcile.Result{}, nil +} diff --git a/pkg/controller/s2ibinary/s2ibinary_controller_suite_test.go b/pkg/controller/s2ibinary/s2ibinary_controller_suite_test.go new file mode 100644 index 0000000000000000000000000000000000000000..71b5f22b6481e72f72297616fa161e561ba14c2c --- /dev/null +++ b/pkg/controller/s2ibinary/s2ibinary_controller_suite_test.go @@ -0,0 +1,75 @@ +/* +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 s2ibinary + +import ( + stdlog "log" + "os" + "path/filepath" + "sync" + "testing" + + "github.com/onsi/gomega" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "kubesphere.io/kubesphere/pkg/apis" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +var cfg *rest.Config + +func TestMain(m *testing.M) { + t := &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")}, + } + apis.AddToScheme(scheme.Scheme) + + var err error + if cfg, err = t.Start(); err != nil { + stdlog.Fatal(err) + } + + code := m.Run() + t.Stop() + os.Exit(code) +} + +// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and +// writes the request to requests after Reconcile is finished. +func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) { + requests := make(chan reconcile.Request) + fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) { + result, err := inner.Reconcile(req) + requests <- req + return result, err + }) + return fn, requests +} + +// StartTestManager adds recFn +func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) { + stop := make(chan struct{}) + wg := &sync.WaitGroup{} + go func() { + wg.Add(1) + g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred()) + wg.Done() + }() + return stop, wg +} diff --git a/pkg/controller/s2ibinary/s2ibinary_controller_test.go b/pkg/controller/s2ibinary/s2ibinary_controller_test.go new file mode 100644 index 0000000000000000000000000000000000000000..bc1fede6b4a5d969186d21213d344c912291683f --- /dev/null +++ b/pkg/controller/s2ibinary/s2ibinary_controller_test.go @@ -0,0 +1,87 @@ +/* +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 s2ibinary + +import ( + "testing" + "time" + + "github.com/onsi/gomega" + "golang.org/x/net/context" + appsv1 "k8s.io/api/apps/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +var c client.Client + +var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo", Namespace: "default"}} +var depKey = types.NamespacedName{Name: "foo-deployment", Namespace: "default"} + +const timeout = time.Second * 5 + +func TestReconcile(t *testing.T) { + g := gomega.NewGomegaWithT(t) + instance := &devopsv1alpha1.S2iBinary{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} + + // Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a + // channel when it is finished. + mgr, err := manager.New(cfg, manager.Options{}) + g.Expect(err).NotTo(gomega.HaveOccurred()) + c = mgr.GetClient() + + recFn, requests := SetupTestReconcile(newReconciler(mgr)) + g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred()) + + stopMgr, mgrStopped := StartTestManager(mgr, g) + + defer func() { + close(stopMgr) + mgrStopped.Wait() + }() + + // Create the S2iBinary object and expect the Reconcile and Deployment to be created + err = c.Create(context.TODO(), instance) + // The instance object may not be a valid object because it might be missing some required fields. + // Please modify the instance object by adding required fields and then remove the following if statement. + if apierrors.IsInvalid(err) { + t.Logf("failed to create object, got an invalid object error: %v", err) + return + } + g.Expect(err).NotTo(gomega.HaveOccurred()) + defer c.Delete(context.TODO(), instance) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) + + deploy := &appsv1.Deployment{} + g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout). + Should(gomega.Succeed()) + + // Delete the Deployment and expect Reconcile to be called for Deployment deletion + g.Expect(c.Delete(context.TODO(), deploy)).NotTo(gomega.HaveOccurred()) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) + g.Eventually(func() error { return c.Get(context.TODO(), depKey, deploy) }, timeout). + Should(gomega.Succeed()) + + // Manually delete Deployment since GC isn't enabled in the test control plane + g.Expect(c.Delete(context.TODO(), deploy)).To(gomega.Succeed()) + +}