JenkinsImage controller based on kaniko (#394)
This commit is contained in:
		
							parent
							
								
									3ecf280efa
								
							
						
					
					
						commit
						ee01c4c028
					
				
							
								
								
									
										3
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										3
									
								
								Makefile
								
								
								
								
							|  | @ -197,7 +197,7 @@ ifeq ($(KUBERNETES_PROVIDER),minikube) | ||||||
| endif | endif | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| 	@RUNNING_TESTS=1 go test -parallel=1 "./test/e2e/" -tags "$(BUILDTAGS) cgo" -v -timeout 60m -run "$(E2E_TEST_SELECTOR)" \
 | 	RUNNING_TESTS=1 go test -parallel=1 "./test/e2e/" -tags "$(BUILDTAGS) cgo" -v -timeout 60m -run "$(E2E_TEST_SELECTOR)" \
 | ||||||
| 		-root=$(CURRENT_DIRECTORY) -kubeconfig=$(HOME)/.kube/config -globalMan deploy/crds/jenkins_$(API_VERSION)_jenkins_crd.yaml \
 | 		-root=$(CURRENT_DIRECTORY) -kubeconfig=$(HOME)/.kube/config -globalMan deploy/crds/jenkins_$(API_VERSION)_jenkins_crd.yaml \
 | ||||||
| 		-namespacedMan deploy/namespace-init.yaml $(TEST_ARGS) | 		-namespacedMan deploy/namespace-init.yaml $(TEST_ARGS) | ||||||
| 
 | 
 | ||||||
|  | @ -251,6 +251,7 @@ ifeq ($(KUBERNETES_PROVIDER),crc) | ||||||
| 	oc project $(CRC_OC_PROJECT) | 	oc project $(CRC_OC_PROJECT) | ||||||
| endif | endif | ||||||
| 	kubectl apply -f deploy/crds/jenkins_$(API_VERSION)_jenkins_crd.yaml | 	kubectl apply -f deploy/crds/jenkins_$(API_VERSION)_jenkins_crd.yaml | ||||||
|  | 	kubectl apply -f deploy/crds/jenkins_$(API_VERSION)_jenkinsimage_crd.yaml | ||||||
| 	@echo "Watching '$(WATCH_NAMESPACE)' namespace" | 	@echo "Watching '$(WATCH_NAMESPACE)' namespace" | ||||||
| 	build/_output/bin/jenkins-operator $(OPERATOR_ARGS) | 	build/_output/bin/jenkins-operator $(OPERATOR_ARGS) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,6 +7,8 @@ import ( | ||||||
| 	"os" | 	"os" | ||||||
| 	"runtime" | 	"runtime" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkinsimage" | ||||||
|  | 
 | ||||||
| 	// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
 | 	// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
 | ||||||
| 	_ "k8s.io/client-go/plugin/pkg/client/auth" | 	_ "k8s.io/client-go/plugin/pkg/client/auth" | ||||||
| 
 | 
 | ||||||
|  | @ -135,6 +137,10 @@ func main() { | ||||||
| 	if err := jenkins.Add(mgr, jenkinsAPIConnectionSettings, *clientSet, *cfg, &c); err != nil { | 	if err := jenkins.Add(mgr, jenkinsAPIConnectionSettings, *clientSet, *cfg, &c); err != nil { | ||||||
| 		fatal(errors.Wrap(err, "failed to setup controllers"), *debug) | 		fatal(errors.Wrap(err, "failed to setup controllers"), *debug) | ||||||
| 	} | 	} | ||||||
|  | 	// setup JenkinsImage controller
 | ||||||
|  | 	if err = jenkinsimage.Add(mgr); err != nil { | ||||||
|  | 		fatal(errors.Wrap(err, "failed to setup controllers"), *debug) | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if err = serveCRMetrics(cfg); err != nil { | 	if err = serveCRMetrics(cfg); err != nil { | ||||||
| 		log.Log.V(log.VWarn).Info("Could not generate and serve custom resource metrics", "error", err.Error()) | 		log.Log.V(log.VWarn).Info("Could not generate and serve custom resource metrics", "error", err.Error()) | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ DOCKER_ORGANIZATION=virtuslab | ||||||
| DOCKER_REGISTRY=jenkins-operator | DOCKER_REGISTRY=jenkins-operator | ||||||
| NAMESPACE=default | NAMESPACE=default | ||||||
| API_VERSION=v1alpha2 | API_VERSION=v1alpha2 | ||||||
|  | API_VERSION_NEXT=v1alpha3 | ||||||
| ALL_IN_ONE_DEPLOY_FILE_PREFIX=all-in-one | ALL_IN_ONE_DEPLOY_FILE_PREFIX=all-in-one | ||||||
| GEN_CRD_API=gen-crd-api-reference-docs | GEN_CRD_API=gen-crd-api-reference-docs | ||||||
| IMAGE_PULL_MODE=local | IMAGE_PULL_MODE=local | ||||||
|  |  | ||||||
|  | @ -0,0 +1,85 @@ | ||||||
|  | apiVersion: apiextensions.k8s.io/v1beta1 | ||||||
|  | kind: CustomResourceDefinition | ||||||
|  | metadata: | ||||||
|  |   name: jenkinsimages.jenkins.io | ||||||
|  | spec: | ||||||
|  |   group: jenkins.io | ||||||
|  |   names: | ||||||
|  |     kind: JenkinsImage | ||||||
|  |     listKind: JenkinsImageList | ||||||
|  |     plural: jenkinsimages | ||||||
|  |     singular: jenkinsimage | ||||||
|  |   scope: Namespaced | ||||||
|  |   subresources: | ||||||
|  |     status: {} | ||||||
|  |   validation: | ||||||
|  |     openAPIV3Schema: | ||||||
|  |       description: JenkinsImage is the Schema for the jenkinsimages 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: JenkinsImageSpec defines the desired state of JenkinsImage | ||||||
|  |           properties: | ||||||
|  |             image: | ||||||
|  |               description: Defines Jenkins Plugin structure | ||||||
|  |               properties: | ||||||
|  |                 name: | ||||||
|  |                   type: string | ||||||
|  |                 version: | ||||||
|  |                   type: string | ||||||
|  |               required: | ||||||
|  |               - name | ||||||
|  |               type: object | ||||||
|  |             plugins: | ||||||
|  |               items: | ||||||
|  |                 description: Defines Jenkins Plugin structure | ||||||
|  |                 properties: | ||||||
|  |                   name: | ||||||
|  |                     type: string | ||||||
|  |                   version: | ||||||
|  |                     type: string | ||||||
|  |                 required: | ||||||
|  |                 - name | ||||||
|  |                 type: object | ||||||
|  |               type: array | ||||||
|  |           required: | ||||||
|  |           - image | ||||||
|  |           - plugins | ||||||
|  |           type: object | ||||||
|  |         status: | ||||||
|  |           description: JenkinsImageStatus defines the observed state of JenkinsImage | ||||||
|  |           properties: | ||||||
|  |             image: | ||||||
|  |               type: string | ||||||
|  |             installedPlugins: | ||||||
|  |               items: | ||||||
|  |                 description: Defines Jenkins Plugin structure | ||||||
|  |                 properties: | ||||||
|  |                   name: | ||||||
|  |                     type: string | ||||||
|  |                   version: | ||||||
|  |                     type: string | ||||||
|  |                 required: | ||||||
|  |                 - name | ||||||
|  |                 type: object | ||||||
|  |               type: array | ||||||
|  |             md5sum: | ||||||
|  |               type: string | ||||||
|  |           type: object | ||||||
|  |       type: object | ||||||
|  |   version: v1alpha2 | ||||||
|  |   versions: | ||||||
|  |   - name: v1alpha2 | ||||||
|  |     served: true | ||||||
|  |     storage: true | ||||||
|  | @ -17,3 +17,90 @@ spec: | ||||||
|     - name : v1alpha1 |     - name : v1alpha1 | ||||||
|       served: true |       served: true | ||||||
|       storage: false |       storage: false | ||||||
|  | --- | ||||||
|  | apiVersion: apiextensions.k8s.io/v1beta1 | ||||||
|  | kind: CustomResourceDefinition | ||||||
|  | metadata: | ||||||
|  |   name: jenkinsimages.jenkins.io | ||||||
|  | spec: | ||||||
|  |   group: jenkins.io | ||||||
|  |   names: | ||||||
|  |     kind: JenkinsImage | ||||||
|  |     listKind: JenkinsImageList | ||||||
|  |     plural: jenkinsimages | ||||||
|  |     singular: jenkinsimage | ||||||
|  |   scope: Namespaced | ||||||
|  |   subresources: | ||||||
|  |     status: {} | ||||||
|  |   validation: | ||||||
|  |     openAPIV3Schema: | ||||||
|  |       description: JenkinsImage is the Schema for the jenkinsimages 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: JenkinsImageSpec defines the desired state of JenkinsImage | ||||||
|  |           properties: | ||||||
|  |             image: | ||||||
|  |               description: Defines Jenkins Plugin structure | ||||||
|  |               properties: | ||||||
|  |                 name: | ||||||
|  |                   type: string | ||||||
|  |                 version: | ||||||
|  |                   type: string | ||||||
|  |               required: | ||||||
|  |                 - name | ||||||
|  |               type: object | ||||||
|  |             plugins: | ||||||
|  |               items: | ||||||
|  |                 description: Defines Jenkins Plugin structure | ||||||
|  |                 properties: | ||||||
|  |                   name: | ||||||
|  |                     type: string | ||||||
|  |                   version: | ||||||
|  |                     type: string | ||||||
|  |                 required: | ||||||
|  |                   - name | ||||||
|  |                 type: object | ||||||
|  |               type: array | ||||||
|  |           required: | ||||||
|  |             - image | ||||||
|  |             - plugins | ||||||
|  |           type: object | ||||||
|  |         status: | ||||||
|  |           description: JenkinsImageStatus defines the observed state of JenkinsImage | ||||||
|  |           properties: | ||||||
|  |             image: | ||||||
|  |               type: string | ||||||
|  |             installedPlugins: | ||||||
|  |               items: | ||||||
|  |                 description: Defines Jenkins Plugin structure | ||||||
|  |                 properties: | ||||||
|  |                   name: | ||||||
|  |                     type: string | ||||||
|  |                   version: | ||||||
|  |                     type: string | ||||||
|  |                 required: | ||||||
|  |                   - name | ||||||
|  |                 type: object | ||||||
|  |               type: array | ||||||
|  |             md5sum: | ||||||
|  |               type: string | ||||||
|  |           type: object | ||||||
|  |       type: object | ||||||
|  |   version: v1alpha2 | ||||||
|  |   versions: | ||||||
|  |     - name: v1alpha2 | ||||||
|  |       served: true | ||||||
|  |       storage: true | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,24 @@ | ||||||
|  | apiVersion: jenkins.io/v1alpha2 | ||||||
|  | kind: JenkinsImage | ||||||
|  | metadata: | ||||||
|  |   name: simple-jenkinsimage | ||||||
|  | spec: | ||||||
|  |   image: | ||||||
|  |     name: jenkins/jenkins | ||||||
|  |     tag: lts | ||||||
|  |   plugins: | ||||||
|  |   - name: kubernetes | ||||||
|  |     version: "1.15.7" | ||||||
|  |   - name: workflow-job  | ||||||
|  |     version: "2.32" | ||||||
|  |   - name: workflow-aggregator | ||||||
|  |     version: "2.6" | ||||||
|  |   - name: git | ||||||
|  |     version: "3.10.0" | ||||||
|  |   - name: job-dsl | ||||||
|  |     version: "1.74" | ||||||
|  |   - name: configuration-as-code | ||||||
|  |     version: "1.19" | ||||||
|  |   - name: kubernetes-credentials-provider | ||||||
|  |     version: "0.12.1" | ||||||
|  | 
 | ||||||
|  | @ -0,0 +1,85 @@ | ||||||
|  | apiVersion: apiextensions.k8s.io/v1beta1 | ||||||
|  | kind: CustomResourceDefinition | ||||||
|  | metadata: | ||||||
|  |   name: jenkinsimages.jenkins.io | ||||||
|  | spec: | ||||||
|  |   group: jenkins.io | ||||||
|  |   names: | ||||||
|  |     kind: JenkinsImage | ||||||
|  |     listKind: JenkinsImageList | ||||||
|  |     plural: jenkinsimages | ||||||
|  |     singular: jenkinsimage | ||||||
|  |   scope: Namespaced | ||||||
|  |   subresources: | ||||||
|  |     status: {} | ||||||
|  |   validation: | ||||||
|  |     openAPIV3Schema: | ||||||
|  |       description: JenkinsImage is the Schema for the jenkinsimages 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: JenkinsImageSpec defines the desired state of JenkinsImage | ||||||
|  |           properties: | ||||||
|  |             image: | ||||||
|  |               description: Defines Jenkins Plugin structure | ||||||
|  |               properties: | ||||||
|  |                 name: | ||||||
|  |                   type: string | ||||||
|  |                 version: | ||||||
|  |                   type: string | ||||||
|  |               required: | ||||||
|  |               - name | ||||||
|  |               type: object | ||||||
|  |             plugins: | ||||||
|  |               items: | ||||||
|  |                 description: Defines Jenkins Plugin structure | ||||||
|  |                 properties: | ||||||
|  |                   name: | ||||||
|  |                     type: string | ||||||
|  |                   version: | ||||||
|  |                     type: string | ||||||
|  |                 required: | ||||||
|  |                 - name | ||||||
|  |                 type: object | ||||||
|  |               type: array | ||||||
|  |           required: | ||||||
|  |           - image | ||||||
|  |           - plugins | ||||||
|  |           type: object | ||||||
|  |         status: | ||||||
|  |           description: JenkinsImageStatus defines the observed state of JenkinsImage | ||||||
|  |           properties: | ||||||
|  |             image: | ||||||
|  |               type: string | ||||||
|  |             installedPlugins: | ||||||
|  |               items: | ||||||
|  |                 description: Defines Jenkins Plugin structure | ||||||
|  |                 properties: | ||||||
|  |                   name: | ||||||
|  |                     type: string | ||||||
|  |                   version: | ||||||
|  |                     type: string | ||||||
|  |                 required: | ||||||
|  |                 - name | ||||||
|  |                 type: object | ||||||
|  |               type: array | ||||||
|  |             md5sum: | ||||||
|  |               type: string | ||||||
|  |           type: object | ||||||
|  |       type: object | ||||||
|  |   version: v1alpha2 | ||||||
|  |   versions: | ||||||
|  |   - name: v1alpha2 | ||||||
|  |     served: true | ||||||
|  |     storage: true | ||||||
|  | @ -0,0 +1,58 @@ | ||||||
|  | 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.
 | ||||||
|  | 
 | ||||||
|  | // JenkinsImageSpec defines the desired state of JenkinsImage
 | ||||||
|  | type JenkinsImageSpec struct { | ||||||
|  | 	BaseImage Image           `json:"image"` | ||||||
|  | 	Plugins   []JenkinsPlugin `json:"plugins"` // Plugins list
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Defines Jenkins Plugin structure
 | ||||||
|  | type JenkinsPlugin struct { | ||||||
|  | 	Name    string `json:"name"` | ||||||
|  | 	Version string `json:"version,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Defines Jenkins Plugin structure
 | ||||||
|  | type Image struct { | ||||||
|  | 	Name string `json:"name"` | ||||||
|  | 	Tag  string `json:"version,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // JenkinsImageStatus defines the observed state of JenkinsImage
 | ||||||
|  | type JenkinsImageStatus struct { | ||||||
|  | 	Image            string          `json:"image,omitempty"` | ||||||
|  | 	MD5Sum           string          `json:"md5sum,omitempty"` | ||||||
|  | 	InstalledPlugins []JenkinsPlugin `json:"installedPlugins,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | ||||||
|  | 
 | ||||||
|  | // JenkinsImage is the Schema for the jenkinsimages API
 | ||||||
|  | // +kubebuilder:subresource:status
 | ||||||
|  | // +kubebuilder:resource:path=jenkinsimages,scope=Namespaced
 | ||||||
|  | type JenkinsImage struct { | ||||||
|  | 	metav1.TypeMeta   `json:",inline"` | ||||||
|  | 	metav1.ObjectMeta `json:"metadata,omitempty"` | ||||||
|  | 	Spec              JenkinsImageSpec   `json:"spec,omitempty"` | ||||||
|  | 	Status            JenkinsImageStatus `json:"status,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | ||||||
|  | 
 | ||||||
|  | // JenkinsImageList contains a list of JenkinsImage
 | ||||||
|  | type JenkinsImageList struct { | ||||||
|  | 	metav1.TypeMeta `json:",inline"` | ||||||
|  | 	metav1.ListMeta `json:"metadata,omitempty"` | ||||||
|  | 	Items           []JenkinsImage `json:"items"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	SchemeBuilder.Register(&JenkinsImage{}, &JenkinsImageList{}) | ||||||
|  | } | ||||||
|  | @ -47,4 +47,5 @@ func JenkinsTypeMeta() metav1.TypeMeta { | ||||||
| 
 | 
 | ||||||
| func init() { | func init() { | ||||||
| 	SchemeBuilder.Register(&Jenkins{}, &JenkinsList{}) | 	SchemeBuilder.Register(&Jenkins{}, &JenkinsList{}) | ||||||
|  | 	SchemeBuilder.Register(&JenkinsImage{}, &JenkinsImageList{}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -209,6 +209,22 @@ func (in *Handler) DeepCopy() *Handler { | ||||||
| 	return out | 	return out | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||||
|  | func (in *Image) DeepCopyInto(out *Image) { | ||||||
|  | 	*out = *in | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image.
 | ||||||
|  | func (in *Image) DeepCopy() *Image { | ||||||
|  | 	if in == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	out := new(Image) | ||||||
|  | 	in.DeepCopyInto(out) | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||||
| func (in *Jenkins) DeepCopyInto(out *Jenkins) { | func (in *Jenkins) DeepCopyInto(out *Jenkins) { | ||||||
| 	*out = *in | 	*out = *in | ||||||
|  | @ -253,6 +269,110 @@ func (in *JenkinsAPISettings) DeepCopy() *JenkinsAPISettings { | ||||||
| 	return out | 	return out | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||||
|  | func (in *JenkinsImage) DeepCopyInto(out *JenkinsImage) { | ||||||
|  | 	*out = *in | ||||||
|  | 	out.TypeMeta = in.TypeMeta | ||||||
|  | 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) | ||||||
|  | 	in.Spec.DeepCopyInto(&out.Spec) | ||||||
|  | 	in.Status.DeepCopyInto(&out.Status) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsImage.
 | ||||||
|  | func (in *JenkinsImage) DeepCopy() *JenkinsImage { | ||||||
|  | 	if in == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	out := new(JenkinsImage) | ||||||
|  | 	in.DeepCopyInto(out) | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||||
|  | func (in *JenkinsImage) 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 *JenkinsImageList) DeepCopyInto(out *JenkinsImageList) { | ||||||
|  | 	*out = *in | ||||||
|  | 	out.TypeMeta = in.TypeMeta | ||||||
|  | 	in.ListMeta.DeepCopyInto(&out.ListMeta) | ||||||
|  | 	if in.Items != nil { | ||||||
|  | 		in, out := &in.Items, &out.Items | ||||||
|  | 		*out = make([]JenkinsImage, len(*in)) | ||||||
|  | 		for i := range *in { | ||||||
|  | 			(*in)[i].DeepCopyInto(&(*out)[i]) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsImageList.
 | ||||||
|  | func (in *JenkinsImageList) DeepCopy() *JenkinsImageList { | ||||||
|  | 	if in == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	out := new(JenkinsImageList) | ||||||
|  | 	in.DeepCopyInto(out) | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||||
|  | func (in *JenkinsImageList) 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 *JenkinsImageSpec) DeepCopyInto(out *JenkinsImageSpec) { | ||||||
|  | 	*out = *in | ||||||
|  | 	out.BaseImage = in.BaseImage | ||||||
|  | 	if in.Plugins != nil { | ||||||
|  | 		in, out := &in.Plugins, &out.Plugins | ||||||
|  | 		*out = make([]JenkinsPlugin, len(*in)) | ||||||
|  | 		copy(*out, *in) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsImageSpec.
 | ||||||
|  | func (in *JenkinsImageSpec) DeepCopy() *JenkinsImageSpec { | ||||||
|  | 	if in == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	out := new(JenkinsImageSpec) | ||||||
|  | 	in.DeepCopyInto(out) | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||||
|  | func (in *JenkinsImageStatus) DeepCopyInto(out *JenkinsImageStatus) { | ||||||
|  | 	*out = *in | ||||||
|  | 	if in.InstalledPlugins != nil { | ||||||
|  | 		in, out := &in.InstalledPlugins, &out.InstalledPlugins | ||||||
|  | 		*out = make([]JenkinsPlugin, len(*in)) | ||||||
|  | 		copy(*out, *in) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsImageStatus.
 | ||||||
|  | func (in *JenkinsImageStatus) DeepCopy() *JenkinsImageStatus { | ||||||
|  | 	if in == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	out := new(JenkinsImageStatus) | ||||||
|  | 	in.DeepCopyInto(out) | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||||
| func (in *JenkinsList) DeepCopyInto(out *JenkinsList) { | func (in *JenkinsList) DeepCopyInto(out *JenkinsList) { | ||||||
| 	*out = *in | 	*out = *in | ||||||
|  | @ -371,6 +491,22 @@ func (in *JenkinsMaster) DeepCopy() *JenkinsMaster { | ||||||
| 	return out | 	return out | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||||
|  | func (in *JenkinsPlugin) DeepCopyInto(out *JenkinsPlugin) { | ||||||
|  | 	*out = *in | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsPlugin.
 | ||||||
|  | func (in *JenkinsPlugin) DeepCopy() *JenkinsPlugin { | ||||||
|  | 	if in == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	out := new(JenkinsPlugin) | ||||||
|  | 	in.DeepCopyInto(out) | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||||
| func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) { | func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) { | ||||||
| 	*out = *in | 	*out = *in | ||||||
|  |  | ||||||
|  | @ -0,0 +1,128 @@ | ||||||
|  | package resources | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 
 | ||||||
|  | 	jenkinsv1alpha2 "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||||
|  | 	corev1 "k8s.io/api/core/v1" | ||||||
|  | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
|  | 	logf "sigs.k8s.io/controller-runtime/pkg/log" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	NameWithSuffixFormat         = "%s-%s" | ||||||
|  | 	PluginDefinitionFormat       = "%s:%s" | ||||||
|  | 	BuilderDockerfileArg         = "--dockerfile=/workspace/dockerfile/Dockerfile" | ||||||
|  | 	BuilderContextDirArg         = "--context=dir://workspace/" | ||||||
|  | 	BuilderPushArg               = "--no-push" | ||||||
|  | 	BuilderDigestFileArg         = "--digest-file=/dev/termination-log" | ||||||
|  | 	BuilderSuffix                = "builder" | ||||||
|  | 	DockerfileStorageSuffix      = "dockerfile-storage" | ||||||
|  | 	DockerfileNameSuffix         = "dockerfile" | ||||||
|  | 	JenkinsImageBuilderImage     = "gcr.io/kaniko-project/executor:latest" | ||||||
|  | 	JenkinsImageBuilderName      = "jenkins-image-builder" | ||||||
|  | 	JenkinsImageDefaultBaseImage = "jenkins/jenkins:lts" | ||||||
|  | 	DockerfileName               = "Dockerfile" | ||||||
|  | 	DockerfileTemplate           = `FROM %s | ||||||
|  | RUN curl -o /tmp/install-plugins.sh https://raw.githubusercontent.com/jenkinsci/docker/master/install-plugins.sh
 | ||||||
|  | RUN chmod +x /tmp/install-plugins.sh | ||||||
|  | RUN install-plugins.sh %s ` | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var log = logf.Log.WithName("controller_jenkinsimage") | ||||||
|  | 
 | ||||||
|  | // NewBuilderPod returns a busybox pod with the same name/namespace as the cr.
 | ||||||
|  | func NewBuilderPod(cr *jenkinsv1alpha2.JenkinsImage) *corev1.Pod { | ||||||
|  | 	name := fmt.Sprintf(NameWithSuffixFormat, cr.Name, BuilderSuffix) | ||||||
|  | 	args := []string{BuilderDockerfileArg, BuilderContextDirArg, BuilderPushArg, BuilderDigestFileArg} | ||||||
|  | 	volumes := getVolumes(cr) | ||||||
|  | 	volumeMounts := getVolumesMounts(cr) | ||||||
|  | 	p := &corev1.Pod{ | ||||||
|  | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 			Name:      name, | ||||||
|  | 			Namespace: cr.Namespace, | ||||||
|  | 		}, | ||||||
|  | 		Spec: corev1.PodSpec{ | ||||||
|  | 			RestartPolicy: corev1.RestartPolicyNever, | ||||||
|  | 			Containers: []corev1.Container{ | ||||||
|  | 				{ | ||||||
|  | 					Name:         JenkinsImageBuilderName, | ||||||
|  | 					Image:        JenkinsImageBuilderImage, | ||||||
|  | 					Args:         args, | ||||||
|  | 					VolumeMounts: volumeMounts, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Volumes: volumes, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	return p | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewDockerfileConfigMap returns a busybox pod with the same name/namespace as the cr.
 | ||||||
|  | func NewDockerfileConfigMap(cr *jenkinsv1alpha2.JenkinsImage) *corev1.ConfigMap { | ||||||
|  | 	dockerfileContent := fmt.Sprintf(DockerfileTemplate, getDefaultedBaseImage(cr), getPluginsList(cr)) | ||||||
|  | 	name := fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileNameSuffix) | ||||||
|  | 	data := map[string]string{DockerfileName: dockerfileContent} | ||||||
|  | 	dockerfile := &corev1.ConfigMap{ | ||||||
|  | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 			Name:      name, | ||||||
|  | 			Namespace: cr.Namespace, | ||||||
|  | 		}, | ||||||
|  | 		Data: data, | ||||||
|  | 	} | ||||||
|  | 	return dockerfile | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func getPluginsList(cr *jenkinsv1alpha2.JenkinsImage) string { | ||||||
|  | 	logger := log.WithName("jenkinsimage_getPluginsList") | ||||||
|  | 	plugins := "" | ||||||
|  | 	for _, v := range cr.Spec.Plugins { | ||||||
|  | 		plugins += fmt.Sprintf(PluginDefinitionFormat, v.Name, v.Version) + " " | ||||||
|  | 		logger.Info(fmt.Sprintf("Adding plugin %s:%s ", v.Name, v.Version)) | ||||||
|  | 	} | ||||||
|  | 	return plugins | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func getDefaultedBaseImage(cr *jenkinsv1alpha2.JenkinsImage) string { | ||||||
|  | 	if len(cr.Spec.BaseImage.Name) != 0 { | ||||||
|  | 		return cr.Spec.BaseImage.Name | ||||||
|  | 	} | ||||||
|  | 	return JenkinsImageDefaultBaseImage | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func getVolumes(cr *jenkinsv1alpha2.JenkinsImage) []corev1.Volume { | ||||||
|  | 	name := fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileStorageSuffix) | ||||||
|  | 	storage := corev1.Volume{ | ||||||
|  | 		Name: name, | ||||||
|  | 		VolumeSource: corev1.VolumeSource{ | ||||||
|  | 			EmptyDir: &corev1.EmptyDirVolumeSource{}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	name = fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileNameSuffix) | ||||||
|  | 	config := corev1.Volume{ | ||||||
|  | 		Name: name, | ||||||
|  | 		VolumeSource: corev1.VolumeSource{ | ||||||
|  | 			ConfigMap: &corev1.ConfigMapVolumeSource{ | ||||||
|  | 				LocalObjectReference: corev1.LocalObjectReference{Name: name}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	volumes := []corev1.Volume{storage, config} | ||||||
|  | 	return volumes | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func getVolumesMounts(cr *jenkinsv1alpha2.JenkinsImage) []corev1.VolumeMount { | ||||||
|  | 	name := fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileStorageSuffix) | ||||||
|  | 	storage := corev1.VolumeMount{ | ||||||
|  | 		Name:      name, | ||||||
|  | 		MountPath: "/workspace", | ||||||
|  | 	} | ||||||
|  | 	name = fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileNameSuffix) | ||||||
|  | 	config := corev1.VolumeMount{ | ||||||
|  | 		Name:      name, | ||||||
|  | 		MountPath: "/workspace/dockerfile", | ||||||
|  | 	} | ||||||
|  | 	volumeMounts := []corev1.VolumeMount{storage, config} | ||||||
|  | 	return volumeMounts | ||||||
|  | } | ||||||
|  | @ -0,0 +1,150 @@ | ||||||
|  | package jenkinsimage | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 
 | ||||||
|  | 	jenkinsv1alpha2 "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2" | ||||||
|  | 
 | ||||||
|  | 	"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources" | ||||||
|  | 
 | ||||||
|  | 	"github.com/pkg/errors" | ||||||
|  | 	corev1 "k8s.io/api/core/v1" | ||||||
|  | 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||||
|  | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
|  | 	"k8s.io/apimachinery/pkg/types" | ||||||
|  | 	"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" | ||||||
|  | 	logf "sigs.k8s.io/controller-runtime/pkg/log" | ||||||
|  | 	"sigs.k8s.io/controller-runtime/pkg/manager" | ||||||
|  | 	"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||||||
|  | 	"sigs.k8s.io/controller-runtime/pkg/source" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var log = logf.Log.WithName("controller_jenkinsimage") | ||||||
|  | 
 | ||||||
|  | // Add creates a new JenkinsImage Controller and adds it to the Manager. The Manager will set fields on the Controller
 | ||||||
|  | // and Start it when the Manager is Started.
 | ||||||
|  | func Add(mgr manager.Manager) error { | ||||||
|  | 	r := &ReconcileJenkinsImage{client: mgr.GetClient(), scheme: mgr.GetScheme()} | ||||||
|  | 	return add(mgr, r) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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("jenkinsimage-controller", mgr, controller.Options{Reconciler: r}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Watch for changes to primary resource JenkinsImage
 | ||||||
|  | 	eventHandlerForObject := &handler.EnqueueRequestForObject{} | ||||||
|  | 	src := &source.Kind{Type: &jenkinsv1alpha2.JenkinsImage{}} | ||||||
|  | 	err = c.Watch(src, eventHandlerForObject) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errors.WithStack(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Watch for changes to secondary resource Pods and requeue the owner JenkinsImage
 | ||||||
|  | 	eventHandlerForOwner := &handler.EnqueueRequestForOwner{ | ||||||
|  | 		IsController: true, | ||||||
|  | 		OwnerType:    &jenkinsv1alpha2.JenkinsImage{}, | ||||||
|  | 	} | ||||||
|  | 	err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, eventHandlerForOwner) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errors.WithStack(err) | ||||||
|  | 	} | ||||||
|  | 	// Watch for changes to secondary ConfigMap and requeue the owner JenkinsImage
 | ||||||
|  | 	err = c.Watch(&source.Kind{Type: &corev1.ConfigMap{}}, eventHandlerForOwner) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errors.WithStack(err) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // blank assignment to verify that ReconcileJenkinsImage implements reconcile.Reconciler
 | ||||||
|  | var _ reconcile.Reconciler = &ReconcileJenkinsImage{} | ||||||
|  | 
 | ||||||
|  | // ReconcileJenkinsImage reconciles a JenkinsImage object
 | ||||||
|  | type ReconcileJenkinsImage struct { | ||||||
|  | 	// This client, initialized using mgr.Client() above, is a split client
 | ||||||
|  | 	// that reads objects from the cache and writes to the apiserver
 | ||||||
|  | 	client client.Client | ||||||
|  | 	scheme *runtime.Scheme | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Reconcile reads that state of the cluster for a JenkinsImage object and makes changes based on the state read
 | ||||||
|  | // and what is in the JenkinsImage.Spec
 | ||||||
|  | // The Controller will requeue the Request to be processed again if the returned error is non-nil or
 | ||||||
|  | // Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
 | ||||||
|  | func (r *ReconcileJenkinsImage) Reconcile(request reconcile.Request) (reconcile.Result, error) { | ||||||
|  | 	reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) | ||||||
|  | 	reqLogger.Info("Reconciling JenkinsImage") | ||||||
|  | 
 | ||||||
|  | 	// Fetch the JenkinsImage instance
 | ||||||
|  | 	instance := &jenkinsv1alpha2.JenkinsImage{} | ||||||
|  | 	err := r.client.Get(context.TODO(), request.NamespacedName, instance) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if apierrors.IsNotFound(err) { | ||||||
|  | 			// Request object not found, could have been deleted after reconcile request.
 | ||||||
|  | 			// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
 | ||||||
|  | 			// Return and don't requeue
 | ||||||
|  | 			return reconcile.Result{}, nil | ||||||
|  | 		} | ||||||
|  | 		// Error reading the object - requeue the request.
 | ||||||
|  | 		return reconcile.Result{}, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Define a new ConfigMap containing the Dockerfile used to build the image
 | ||||||
|  | 	dockerfile := resources.NewDockerfileConfigMap(instance) | ||||||
|  | 	// Set JenkinsImage instance as the owner and controller
 | ||||||
|  | 	if err := controllerutil.SetControllerReference(instance, dockerfile, r.scheme); err != nil { | ||||||
|  | 		return reconcile.Result{}, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Check if this ConfigMap already exists
 | ||||||
|  | 	foundConfigMap := &corev1.ConfigMap{} | ||||||
|  | 	err = r.client.Get(context.TODO(), types.NamespacedName{Name: dockerfile.Name, Namespace: dockerfile.Namespace}, foundConfigMap) | ||||||
|  | 	if err != nil && apierrors.IsNotFound(err) { | ||||||
|  | 		reqLogger.Info("Creating a new ConfigMap", "ConfigMap.Namespace", dockerfile.Namespace, "ConfigMap.Name", dockerfile.Name) | ||||||
|  | 		err = r.client.Create(context.TODO(), dockerfile) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return reconcile.Result{}, err | ||||||
|  | 		} | ||||||
|  | 		// ConfigMap created successfully - don't requeue
 | ||||||
|  | 		return reconcile.Result{}, nil | ||||||
|  | 	} else if err != nil { | ||||||
|  | 		return reconcile.Result{}, err | ||||||
|  | 	} | ||||||
|  | 	// ConfigMap already exists - don't requeue
 | ||||||
|  | 	reqLogger.Info("Skip reconcile: ConfigMap already exists", "ConfigMap.Namespace", foundConfigMap.Namespace, "ConfigMap.Name", foundConfigMap.Name) | ||||||
|  | 
 | ||||||
|  | 	// Define a new Pod object
 | ||||||
|  | 	pod := resources.NewBuilderPod(instance) | ||||||
|  | 	// Set JenkinsImage instance as the owner and controller
 | ||||||
|  | 	if err := controllerutil.SetControllerReference(instance, pod, r.scheme); err != nil { | ||||||
|  | 		return reconcile.Result{}, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Check if this Pod already exists
 | ||||||
|  | 	foundPod := &corev1.Pod{} | ||||||
|  | 	err = r.client.Get(context.TODO(), types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, foundPod) | ||||||
|  | 	if err != nil && apierrors.IsNotFound(err) { | ||||||
|  | 		reqLogger.Info("Creating a new Pod", "Pod.Namespace", pod.Namespace, "Pod.Name", pod.Name) | ||||||
|  | 		err = r.client.Create(context.TODO(), pod) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return reconcile.Result{}, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Pod created successfully - don't requeue
 | ||||||
|  | 		return reconcile.Result{}, nil | ||||||
|  | 	} else if err != nil { | ||||||
|  | 		return reconcile.Result{}, err | ||||||
|  | 	} | ||||||
|  | 	// Pod already exists - don't requeue
 | ||||||
|  | 	reqLogger.Info("Skip reconcile: Pod already exists", "Pod.Namespace", foundPod.Namespace, "Pod.Name", foundPod.Name) | ||||||
|  | 
 | ||||||
|  | 	return reconcile.Result{}, nil | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue