Merge pull request #50 from summerwind/runner-validation-webhook
Add validation webhooks
This commit is contained in:
		
						commit
						390f2a62d9
					
				
							
								
								
									
										10
									
								
								README.md
								
								
								
								
							
							
						
						
									
										10
									
								
								README.md
								
								
								
								
							|  | @ -6,11 +6,15 @@ This controller operates self-hosted runners for GitHub Actions on your Kubernet | ||||||
| 
 | 
 | ||||||
| [GitHub Actions](https://github.com/features/actions) is a very useful tool for automating development. GitHub Actions jobs are run in the cloud by default, but you may want to run your jobs in your environment. [Self-hosted runner](https://github.com/actions/runner) can be used for such use cases, but requires the provisioning and configuration of a virtual machine instance. Instead if you already have a Kubernetes cluster, it makes more sense to run the self-hosted runner on top of it. | [GitHub Actions](https://github.com/features/actions) is a very useful tool for automating development. GitHub Actions jobs are run in the cloud by default, but you may want to run your jobs in your environment. [Self-hosted runner](https://github.com/actions/runner) can be used for such use cases, but requires the provisioning and configuration of a virtual machine instance. Instead if you already have a Kubernetes cluster, it makes more sense to run the self-hosted runner on top of it. | ||||||
| 
 | 
 | ||||||
| *actions-runner-controller* makes that possible. Just create a *Runner* resource on your Kubernetes, and it will run and operate the self-hosted runner for the specified repository. Combined with Kubernetes RBAC, you can also build simple Self-hosted runners as a Service. | **actions-runner-controller** makes that possible. Just create a *Runner* resource on your Kubernetes, and it will run and operate the self-hosted runner for the specified repository. Combined with Kubernetes RBAC, you can also build simple Self-hosted runners as a Service. | ||||||
| 
 | 
 | ||||||
| ## Installation | ## Installation | ||||||
| 
 | 
 | ||||||
| First, install *actions-runner-controller* with a manifest file. This will create *actions-runner-system* namespace in your Kubernetes and deploy the required resources. | actions-runner-controller uses [cert-manager](https://cert-manager.io/docs/installation/kubernetes/) for certificate management of Admission Webhook. Make sure you have already installed cert-manager before you install. The installation instructions for cert-manager can be found below. | ||||||
|  | 
 | ||||||
|  | - [Installing cert-manager on Kubernetes](https://cert-manager.io/docs/installation/kubernetes/) | ||||||
|  | 
 | ||||||
|  | Install the custom resource and actions-runner-controller itself. This will create actions-runner-system namespace in your Kubernetes and deploy the required resources. | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| $ kubectl apply -f https://github.com/summerwind/actions-runner-controller/releases/latest/download/actions-runner-controller.yaml | $ kubectl apply -f https://github.com/summerwind/actions-runner-controller/releases/latest/download/actions-runner-controller.yaml | ||||||
|  | @ -18,7 +22,7 @@ $ kubectl apply -f https://github.com/summerwind/actions-runner-controller/relea | ||||||
| 
 | 
 | ||||||
| ## Setting up authentication with GitHub API | ## Setting up authentication with GitHub API | ||||||
| 
 | 
 | ||||||
| There are two ways for _actions-runner-controller_ to authenticate with the the GitHub API: | There are two ways for actions-runner-controller to authenticate with the the GitHub API: | ||||||
| 
 | 
 | ||||||
| 1. Using GitHub App. | 1. Using GitHub App. | ||||||
| 2. Using Personal Access Token. | 2. Using Personal Access Token. | ||||||
|  |  | ||||||
|  | @ -17,6 +17,8 @@ limitations under the License. | ||||||
| package v1alpha1 | package v1alpha1 | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"errors" | ||||||
|  | 
 | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| ) | ) | ||||||
|  | @ -75,6 +77,19 @@ type RunnerSpec struct { | ||||||
| 	TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` | 	TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // ValidateRepository validates repository field.
 | ||||||
|  | func (rs *RunnerSpec) ValidateRepository() error { | ||||||
|  | 	// Organization and repository are both exclusive.
 | ||||||
|  | 	if len(rs.Organization) == 0 && len(rs.Repository) == 0 { | ||||||
|  | 		return errors.New("Spec needs organization or repository") | ||||||
|  | 	} | ||||||
|  | 	if len(rs.Organization) > 0 && len(rs.Repository) > 0 { | ||||||
|  | 		return errors.New("Spec cannot have both organization and repository") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // RunnerStatus defines the observed state of Runner
 | // RunnerStatus defines the observed state of Runner
 | ||||||
| type RunnerStatus struct { | type RunnerStatus struct { | ||||||
| 	Registration RunnerStatusRegistration `json:"registration"` | 	Registration RunnerStatusRegistration `json:"registration"` | ||||||
|  |  | ||||||
|  | @ -0,0 +1,84 @@ | ||||||
|  | /* | ||||||
|  | Copyright 2020 The actions-runner-controller 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 ( | ||||||
|  | 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||||
|  | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
|  | 	"k8s.io/apimachinery/pkg/util/validation/field" | ||||||
|  | 	ctrl "sigs.k8s.io/controller-runtime" | ||||||
|  | 	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" | ||||||
|  | 	"sigs.k8s.io/controller-runtime/pkg/webhook" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // log is for logging in this package.
 | ||||||
|  | var runnerLog = logf.Log.WithName("runner-resource") | ||||||
|  | 
 | ||||||
|  | func (r *Runner) SetupWebhookWithManager(mgr ctrl.Manager) error { | ||||||
|  | 	return ctrl.NewWebhookManagedBy(mgr). | ||||||
|  | 		For(r). | ||||||
|  | 		Complete() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runner,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runners,versions=v1alpha1,name=mutate.runner.actions.summerwind.dev
 | ||||||
|  | 
 | ||||||
|  | var _ webhook.Defaulter = &Runner{} | ||||||
|  | 
 | ||||||
|  | // Default implements webhook.Defaulter so a webhook will be registered for the type
 | ||||||
|  | func (r *Runner) Default() { | ||||||
|  | 	// Nothing to do.
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runner,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runners,versions=v1alpha1,name=validate.runner.actions.summerwind.dev
 | ||||||
|  | 
 | ||||||
|  | var _ webhook.Validator = &Runner{} | ||||||
|  | 
 | ||||||
|  | // ValidateCreate implements webhook.Validator so a webhook will be registered for the type
 | ||||||
|  | func (r *Runner) ValidateCreate() error { | ||||||
|  | 	runnerLog.Info("validate resource to be created", "name", r.Name) | ||||||
|  | 	return r.Validate() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
 | ||||||
|  | func (r *Runner) ValidateUpdate(old runtime.Object) error { | ||||||
|  | 	runnerLog.Info("validate resource to be updated", "name", r.Name) | ||||||
|  | 	return r.Validate() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
 | ||||||
|  | func (r *Runner) ValidateDelete() error { | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Validate validates resource spec.
 | ||||||
|  | func (r *Runner) Validate() error { | ||||||
|  | 	var ( | ||||||
|  | 		errList field.ErrorList | ||||||
|  | 		err     error | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	err = r.Spec.ValidateRepository() | ||||||
|  | 	if err != nil { | ||||||
|  | 		errList = append(errList, field.Invalid(field.NewPath("spec", "repository"), r.Spec.Repository, err.Error())) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(errList) > 0 { | ||||||
|  | 		return apierrors.NewInvalid(r.GroupVersionKind().GroupKind(), r.Name, errList) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -0,0 +1,84 @@ | ||||||
|  | /* | ||||||
|  | Copyright 2020 The actions-runner-controller 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 ( | ||||||
|  | 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||||
|  | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
|  | 	"k8s.io/apimachinery/pkg/util/validation/field" | ||||||
|  | 	ctrl "sigs.k8s.io/controller-runtime" | ||||||
|  | 	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" | ||||||
|  | 	"sigs.k8s.io/controller-runtime/pkg/webhook" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // log is for logging in this package.
 | ||||||
|  | var runenrDeploymentLog = logf.Log.WithName("runnerdeployment-resource") | ||||||
|  | 
 | ||||||
|  | func (r *RunnerDeployment) SetupWebhookWithManager(mgr ctrl.Manager) error { | ||||||
|  | 	return ctrl.NewWebhookManagedBy(mgr). | ||||||
|  | 		For(r). | ||||||
|  | 		Complete() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runnerdeployment,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerdeployments,versions=v1alpha1,name=mutate.runnerdeployment.actions.summerwind.dev
 | ||||||
|  | 
 | ||||||
|  | var _ webhook.Defaulter = &RunnerDeployment{} | ||||||
|  | 
 | ||||||
|  | // Default implements webhook.Defaulter so a webhook will be registered for the type
 | ||||||
|  | func (r *RunnerDeployment) Default() { | ||||||
|  | 	// Nothing to do.
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runnerdeployment,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerdeployments,versions=v1alpha1,name=validate.runnerdeployment.actions.summerwind.dev
 | ||||||
|  | 
 | ||||||
|  | var _ webhook.Validator = &RunnerDeployment{} | ||||||
|  | 
 | ||||||
|  | // ValidateCreate implements webhook.Validator so a webhook will be registered for the type
 | ||||||
|  | func (r *RunnerDeployment) ValidateCreate() error { | ||||||
|  | 	runenrDeploymentLog.Info("validate resource to be created", "name", r.Name) | ||||||
|  | 	return r.Validate() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
 | ||||||
|  | func (r *RunnerDeployment) ValidateUpdate(old runtime.Object) error { | ||||||
|  | 	runenrDeploymentLog.Info("validate resource to be updated", "name", r.Name) | ||||||
|  | 	return r.Validate() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
 | ||||||
|  | func (r *RunnerDeployment) ValidateDelete() error { | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Validate validates resource spec.
 | ||||||
|  | func (r *RunnerDeployment) Validate() error { | ||||||
|  | 	var ( | ||||||
|  | 		errList field.ErrorList | ||||||
|  | 		err     error | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	err = r.Spec.Template.Spec.ValidateRepository() | ||||||
|  | 	if err != nil { | ||||||
|  | 		errList = append(errList, field.Invalid(field.NewPath("spec", "template", "spec", "repository"), r.Spec.Template.Spec.Repository, err.Error())) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(errList) > 0 { | ||||||
|  | 		return apierrors.NewInvalid(r.GroupVersionKind().GroupKind(), r.Name, errList) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -0,0 +1,84 @@ | ||||||
|  | /* | ||||||
|  | Copyright 2020 The actions-runner-controller 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 ( | ||||||
|  | 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||||
|  | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
|  | 	"k8s.io/apimachinery/pkg/util/validation/field" | ||||||
|  | 	ctrl "sigs.k8s.io/controller-runtime" | ||||||
|  | 	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" | ||||||
|  | 	"sigs.k8s.io/controller-runtime/pkg/webhook" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // log is for logging in this package.
 | ||||||
|  | var runnerReplicaSetLog = logf.Log.WithName("runnerreplicaset-resource") | ||||||
|  | 
 | ||||||
|  | func (r *RunnerReplicaSet) SetupWebhookWithManager(mgr ctrl.Manager) error { | ||||||
|  | 	return ctrl.NewWebhookManagedBy(mgr). | ||||||
|  | 		For(r). | ||||||
|  | 		Complete() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runnerreplicaset,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerreplicasets,versions=v1alpha1,name=mutate.runnerreplicaset.actions.summerwind.dev
 | ||||||
|  | 
 | ||||||
|  | var _ webhook.Defaulter = &RunnerReplicaSet{} | ||||||
|  | 
 | ||||||
|  | // Default implements webhook.Defaulter so a webhook will be registered for the type
 | ||||||
|  | func (r *RunnerReplicaSet) Default() { | ||||||
|  | 	// Nothing to do.
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runnerreplicaset,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerreplicasets,versions=v1alpha1,name=validate.runnerreplicaset.actions.summerwind.dev
 | ||||||
|  | 
 | ||||||
|  | var _ webhook.Validator = &RunnerReplicaSet{} | ||||||
|  | 
 | ||||||
|  | // ValidateCreate implements webhook.Validator so a webhook will be registered for the type
 | ||||||
|  | func (r *RunnerReplicaSet) ValidateCreate() error { | ||||||
|  | 	runnerReplicaSetLog.Info("validate resource to be created", "name", r.Name) | ||||||
|  | 	return r.Validate() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
 | ||||||
|  | func (r *RunnerReplicaSet) ValidateUpdate(old runtime.Object) error { | ||||||
|  | 	runnerReplicaSetLog.Info("validate resource to be updated", "name", r.Name) | ||||||
|  | 	return r.Validate() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
 | ||||||
|  | func (r *RunnerReplicaSet) ValidateDelete() error { | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Validate validates resource spec.
 | ||||||
|  | func (r *RunnerReplicaSet) Validate() error { | ||||||
|  | 	var ( | ||||||
|  | 		errList field.ErrorList | ||||||
|  | 		err     error | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	err = r.Spec.Template.Spec.ValidateRepository() | ||||||
|  | 	if err != nil { | ||||||
|  | 		errList = append(errList, field.Invalid(field.NewPath("spec", "template", "spec", "repository"), r.Spec.Template.Spec.Repository, err.Error())) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(errList) > 0 { | ||||||
|  | 		return apierrors.NewInvalid(r.GroupVersionKind().GroupKind(), r.Name, errList) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -22,7 +22,7 @@ package v1alpha1 | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"k8s.io/api/core/v1" | 	"k8s.io/api/core/v1" | ||||||
| 	runtime "k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // 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.
 | ||||||
|  |  | ||||||
|  | @ -17,9 +17,9 @@ bases: | ||||||
| - ../rbac | - ../rbac | ||||||
| - ../manager | - ../manager | ||||||
| # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in crd/kustomization.yaml | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in crd/kustomization.yaml | ||||||
| #- ../webhook | - ../webhook | ||||||
| # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. | ||||||
| #- ../certmanager | - ../certmanager | ||||||
| # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.  | # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.  | ||||||
| #- ../prometheus | #- ../prometheus | ||||||
| 
 | 
 | ||||||
|  | @ -36,39 +36,39 @@ patchesStrategicMerge: | ||||||
| #- manager_prometheus_metrics_patch.yaml | #- manager_prometheus_metrics_patch.yaml | ||||||
| 
 | 
 | ||||||
| # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in crd/kustomization.yaml | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in crd/kustomization.yaml | ||||||
| #- manager_webhook_patch.yaml | - manager_webhook_patch.yaml | ||||||
| 
 | 
 | ||||||
| # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. | ||||||
| # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. | # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. | ||||||
| # 'CERTMANAGER' needs to be enabled to use ca injection | # 'CERTMANAGER' needs to be enabled to use ca injection | ||||||
| #- webhookcainjection_patch.yaml | - webhookcainjection_patch.yaml | ||||||
| 
 | 
 | ||||||
| # the following config is for teaching kustomize how to do var substitution | # the following config is for teaching kustomize how to do var substitution | ||||||
| vars: | vars: | ||||||
| # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. | ||||||
| #- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR | - name: CERTIFICATE_NAMESPACE # namespace of the certificate CR | ||||||
| #  objref: |   objref: | ||||||
| #    kind: Certificate |     kind: Certificate | ||||||
| #    group: cert-manager.io |     group: cert-manager.io | ||||||
| #    version: v1alpha2 |     version: v1alpha2 | ||||||
| #    name: serving-cert # this name should match the one in certificate.yaml |     name: serving-cert # this name should match the one in certificate.yaml | ||||||
| #  fieldref: |   fieldref: | ||||||
| #    fieldpath: metadata.namespace |     fieldpath: metadata.namespace | ||||||
| #- name: CERTIFICATE_NAME | - name: CERTIFICATE_NAME | ||||||
| #  objref: |   objref: | ||||||
| #    kind: Certificate |     kind: Certificate | ||||||
| #    group: cert-manager.io |     group: cert-manager.io | ||||||
| #    version: v1alpha2 |     version: v1alpha2 | ||||||
| #    name: serving-cert # this name should match the one in certificate.yaml |     name: serving-cert # this name should match the one in certificate.yaml | ||||||
| #- name: SERVICE_NAMESPACE # namespace of the service | - name: SERVICE_NAMESPACE # namespace of the service | ||||||
| #  objref: |   objref: | ||||||
| #    kind: Service |     kind: Service | ||||||
| #    version: v1 |     version: v1 | ||||||
| #    name: webhook-service |     name: webhook-service | ||||||
| #  fieldref: |   fieldref: | ||||||
| #    fieldpath: metadata.namespace |     fieldpath: metadata.namespace | ||||||
| #- name: SERVICE_NAME | - name: SERVICE_NAME | ||||||
| #  objref: |   objref: | ||||||
| #    kind: Service |     kind: Service | ||||||
| #    version: v1 |     version: v1 | ||||||
| #    name: webhook-service |     name: webhook-service | ||||||
|  |  | ||||||
|  | @ -0,0 +1,124 @@ | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | apiVersion: admissionregistration.k8s.io/v1beta1 | ||||||
|  | kind: MutatingWebhookConfiguration | ||||||
|  | metadata: | ||||||
|  |   creationTimestamp: null | ||||||
|  |   name: mutating-webhook-configuration | ||||||
|  | webhooks: | ||||||
|  | - clientConfig: | ||||||
|  |     caBundle: Cg== | ||||||
|  |     service: | ||||||
|  |       name: webhook-service | ||||||
|  |       namespace: system | ||||||
|  |       path: /mutate-actions-summerwind-dev-v1alpha1-runner | ||||||
|  |   failurePolicy: Fail | ||||||
|  |   name: mutate.runner.actions.summerwind.dev | ||||||
|  |   rules: | ||||||
|  |   - apiGroups: | ||||||
|  |     - actions.summerwind.dev | ||||||
|  |     apiVersions: | ||||||
|  |     - v1alpha1 | ||||||
|  |     operations: | ||||||
|  |     - CREATE | ||||||
|  |     - UPDATE | ||||||
|  |     resources: | ||||||
|  |     - runners | ||||||
|  | - clientConfig: | ||||||
|  |     caBundle: Cg== | ||||||
|  |     service: | ||||||
|  |       name: webhook-service | ||||||
|  |       namespace: system | ||||||
|  |       path: /mutate-actions-summerwind-dev-v1alpha1-runnerdeployment | ||||||
|  |   failurePolicy: Fail | ||||||
|  |   name: mutate.runnerdeployment.actions.summerwind.dev | ||||||
|  |   rules: | ||||||
|  |   - apiGroups: | ||||||
|  |     - actions.summerwind.dev | ||||||
|  |     apiVersions: | ||||||
|  |     - v1alpha1 | ||||||
|  |     operations: | ||||||
|  |     - CREATE | ||||||
|  |     - UPDATE | ||||||
|  |     resources: | ||||||
|  |     - runnerdeployments | ||||||
|  | - clientConfig: | ||||||
|  |     caBundle: Cg== | ||||||
|  |     service: | ||||||
|  |       name: webhook-service | ||||||
|  |       namespace: system | ||||||
|  |       path: /mutate-actions-summerwind-dev-v1alpha1-runnerreplicaset | ||||||
|  |   failurePolicy: Fail | ||||||
|  |   name: mutate.runnerreplicaset.actions.summerwind.dev | ||||||
|  |   rules: | ||||||
|  |   - apiGroups: | ||||||
|  |     - actions.summerwind.dev | ||||||
|  |     apiVersions: | ||||||
|  |     - v1alpha1 | ||||||
|  |     operations: | ||||||
|  |     - CREATE | ||||||
|  |     - UPDATE | ||||||
|  |     resources: | ||||||
|  |     - runnerreplicasets | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | apiVersion: admissionregistration.k8s.io/v1beta1 | ||||||
|  | kind: ValidatingWebhookConfiguration | ||||||
|  | metadata: | ||||||
|  |   creationTimestamp: null | ||||||
|  |   name: validating-webhook-configuration | ||||||
|  | webhooks: | ||||||
|  | - clientConfig: | ||||||
|  |     caBundle: Cg== | ||||||
|  |     service: | ||||||
|  |       name: webhook-service | ||||||
|  |       namespace: system | ||||||
|  |       path: /validate-actions-summerwind-dev-v1alpha1-runner | ||||||
|  |   failurePolicy: Fail | ||||||
|  |   name: validate.runner.actions.summerwind.dev | ||||||
|  |   rules: | ||||||
|  |   - apiGroups: | ||||||
|  |     - actions.summerwind.dev | ||||||
|  |     apiVersions: | ||||||
|  |     - v1alpha1 | ||||||
|  |     operations: | ||||||
|  |     - CREATE | ||||||
|  |     - UPDATE | ||||||
|  |     resources: | ||||||
|  |     - runners | ||||||
|  | - clientConfig: | ||||||
|  |     caBundle: Cg== | ||||||
|  |     service: | ||||||
|  |       name: webhook-service | ||||||
|  |       namespace: system | ||||||
|  |       path: /validate-actions-summerwind-dev-v1alpha1-runnerdeployment | ||||||
|  |   failurePolicy: Fail | ||||||
|  |   name: validate.runnerdeployment.actions.summerwind.dev | ||||||
|  |   rules: | ||||||
|  |   - apiGroups: | ||||||
|  |     - actions.summerwind.dev | ||||||
|  |     apiVersions: | ||||||
|  |     - v1alpha1 | ||||||
|  |     operations: | ||||||
|  |     - CREATE | ||||||
|  |     - UPDATE | ||||||
|  |     resources: | ||||||
|  |     - runnerdeployments | ||||||
|  | - clientConfig: | ||||||
|  |     caBundle: Cg== | ||||||
|  |     service: | ||||||
|  |       name: webhook-service | ||||||
|  |       namespace: system | ||||||
|  |       path: /validate-actions-summerwind-dev-v1alpha1-runnerreplicaset | ||||||
|  |   failurePolicy: Fail | ||||||
|  |   name: validate.runnerreplicaset.actions.summerwind.dev | ||||||
|  |   rules: | ||||||
|  |   - apiGroups: | ||||||
|  |     - actions.summerwind.dev | ||||||
|  |     apiVersions: | ||||||
|  |     - v1alpha1 | ||||||
|  |     operations: | ||||||
|  |     - CREATE | ||||||
|  |     - UPDATE | ||||||
|  |     resources: | ||||||
|  |     - runnerreplicasets | ||||||
|  | @ -66,7 +66,7 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { | ||||||
| 		return ctrl.Result{}, client.IgnoreNotFound(err) | 		return ctrl.Result{}, client.IgnoreNotFound(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err := validateRunnerSpec(&runner.Spec) | 	err := runner.Validate() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Info("Failed to validate runner spec", "error", err.Error()) | 		log.Info("Failed to validate runner spec", "error", err.Error()) | ||||||
| 		return ctrl.Result{}, nil | 		return ctrl.Result{}, nil | ||||||
|  | @ -449,15 +449,3 @@ func removeFinalizer(finalizers []string) ([]string, bool) { | ||||||
| 
 | 
 | ||||||
| 	return result, removed | 	return result, removed | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // organization & repository are both exclusive - however this cannot be checked with kubebuilder
 |  | ||||||
| // therefore have an additional check here to log an error in case spec is invalid
 |  | ||||||
| func validateRunnerSpec(spec *v1alpha1.RunnerSpec) error { |  | ||||||
| 	if len(spec.Organization) == 0 && len(spec.Repository) == 0 { |  | ||||||
| 		return fmt.Errorf("RunnerSpec needs organization or repository") |  | ||||||
| 	} |  | ||||||
| 	if len(spec.Organization) > 0 && len(spec.Repository) > 0 { |  | ||||||
| 		return fmt.Errorf("RunnerSpec cannot have both organization and repository") |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								main.go
								
								
								
								
							
							
						
						
									
										13
									
								
								main.go
								
								
								
								
							|  | @ -174,6 +174,19 @@ func main() { | ||||||
| 		setupLog.Error(err, "unable to create controller", "controller", "RunnerDeployment") | 		setupLog.Error(err, "unable to create controller", "controller", "RunnerDeployment") | ||||||
| 		os.Exit(1) | 		os.Exit(1) | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if err = (&actionsv1alpha1.Runner{}).SetupWebhookWithManager(mgr); err != nil { | ||||||
|  | 		setupLog.Error(err, "unable to create webhook", "webhook", "Runner") | ||||||
|  | 		os.Exit(1) | ||||||
|  | 	} | ||||||
|  | 	if err = (&actionsv1alpha1.RunnerDeployment{}).SetupWebhookWithManager(mgr); err != nil { | ||||||
|  | 		setupLog.Error(err, "unable to create webhook", "webhook", "RunnerDeployment") | ||||||
|  | 		os.Exit(1) | ||||||
|  | 	} | ||||||
|  | 	if err = (&actionsv1alpha1.RunnerReplicaSet{}).SetupWebhookWithManager(mgr); err != nil { | ||||||
|  | 		setupLog.Error(err, "unable to create webhook", "webhook", "RunnerReplicaSet") | ||||||
|  | 		os.Exit(1) | ||||||
|  | 	} | ||||||
| 	// +kubebuilder:scaffold:builder
 | 	// +kubebuilder:scaffold:builder
 | ||||||
| 
 | 
 | ||||||
| 	setupLog.Info("starting manager") | 	setupLog.Info("starting manager") | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue