Creates cron job

This commit is contained in:
Jean-Marc ANDRE 2020-11-27 22:44:03 +01:00
parent b86690c5a1
commit 5d83956617
8 changed files with 140 additions and 452 deletions

View File

@ -17,27 +17,13 @@ limitations under the License.
package v1alpha1
import (
corev1 "k8s.io/api/core/v1"
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.
// FunctionSpec defines the desired state of Function
type FunctionSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Foo is an example field of Function. Edit Function_types.go to remove/update
Foo string `json:"foo,omitempty"`
}
// FunctionStatus defines the observed state of Function
type FunctionStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
}
// +kubebuilder:object:root=true
// Function is the Schema for the functions API
@ -45,8 +31,7 @@ type Function struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec FunctionSpec `json:"spec,omitempty"`
Status FunctionStatus `json:"status,omitempty"`
Spec corev1.Container `json:"spec,omitempty"`
}
// +kubebuilder:object:root=true

View File

@ -23,13 +23,23 @@ import (
// 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.
type Param struct {
Name string `json:"name"`
Value string `json:"value"`
}
type Step struct {
Name string `json:"name"`
Params []Param `json:"params,omitempty"`
}
// TaskSpec defines the desired state of Task
type TaskSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Foo is an example field of Task. Edit Task_types.go to remove/update
Foo string `json:"foo,omitempty"`
Steps []Step `json:"steps"`
}
// TaskStatus defines the observed state of Task

View File

@ -1,427 +0,0 @@
// +build !ignore_autogenerated
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by controller-gen. DO NOT EDIT.
package 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 *BackupConfiguration) DeepCopyInto(out *BackupConfiguration) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupConfiguration.
func (in *BackupConfiguration) DeepCopy() *BackupConfiguration {
if in == nil {
return nil
}
out := new(BackupConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *BackupConfiguration) 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 *BackupConfigurationList) DeepCopyInto(out *BackupConfigurationList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]BackupConfiguration, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupConfigurationList.
func (in *BackupConfigurationList) DeepCopy() *BackupConfigurationList {
if in == nil {
return nil
}
out := new(BackupConfigurationList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *BackupConfigurationList) 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 *BackupConfigurationSpec) DeepCopyInto(out *BackupConfigurationSpec) {
*out = *in
out.Repository = in.Repository
if in.Suspend != nil {
in, out := &in.Suspend, &out.Suspend
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupConfigurationSpec.
func (in *BackupConfigurationSpec) DeepCopy() *BackupConfigurationSpec {
if in == nil {
return nil
}
out := new(BackupConfigurationSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BackupConfigurationStatus) DeepCopyInto(out *BackupConfigurationStatus) {
*out = *in
if in.LastBackupTime != nil {
in, out := &in.LastBackupTime, &out.LastBackupTime
*out = (*in).DeepCopy()
}
if in.Suspended != nil {
in, out := &in.Suspended, &out.Suspended
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupConfigurationStatus.
func (in *BackupConfigurationStatus) DeepCopy() *BackupConfigurationStatus {
if in == nil {
return nil
}
out := new(BackupConfigurationStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BackupSession) DeepCopyInto(out *BackupSession) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
out.Status = in.Status
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupSession.
func (in *BackupSession) DeepCopy() *BackupSession {
if in == nil {
return nil
}
out := new(BackupSession)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *BackupSession) 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 *BackupSessionList) DeepCopyInto(out *BackupSessionList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]BackupSession, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupSessionList.
func (in *BackupSessionList) DeepCopy() *BackupSessionList {
if in == nil {
return nil
}
out := new(BackupSessionList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *BackupSessionList) 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 *BackupSessionSpec) DeepCopyInto(out *BackupSessionSpec) {
*out = *in
out.Ref = in.Ref
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupSessionSpec.
func (in *BackupSessionSpec) DeepCopy() *BackupSessionSpec {
if in == nil {
return nil
}
out := new(BackupSessionSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BackupSessionStatus) DeepCopyInto(out *BackupSessionStatus) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupSessionStatus.
func (in *BackupSessionStatus) DeepCopy() *BackupSessionStatus {
if in == nil {
return nil
}
out := new(BackupSessionStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Function) DeepCopyInto(out *Function) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
out.Status = in.Status
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Function.
func (in *Function) DeepCopy() *Function {
if in == nil {
return nil
}
out := new(Function)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Function) 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 *FunctionList) DeepCopyInto(out *FunctionList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Function, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionList.
func (in *FunctionList) DeepCopy() *FunctionList {
if in == nil {
return nil
}
out := new(FunctionList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *FunctionList) 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 *FunctionSpec) DeepCopyInto(out *FunctionSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionSpec.
func (in *FunctionSpec) DeepCopy() *FunctionSpec {
if in == nil {
return nil
}
out := new(FunctionSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FunctionStatus) DeepCopyInto(out *FunctionStatus) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionStatus.
func (in *FunctionStatus) DeepCopy() *FunctionStatus {
if in == nil {
return nil
}
out := new(FunctionStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Ref) DeepCopyInto(out *Ref) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ref.
func (in *Ref) DeepCopy() *Ref {
if in == nil {
return nil
}
out := new(Ref)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Repository) DeepCopyInto(out *Repository) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Repository.
func (in *Repository) DeepCopy() *Repository {
if in == nil {
return nil
}
out := new(Repository)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Task) DeepCopyInto(out *Task) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
out.Status = in.Status
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Task.
func (in *Task) DeepCopy() *Task {
if in == nil {
return nil
}
out := new(Task)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Task) 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 *TaskList) DeepCopyInto(out *TaskList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Task, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskList.
func (in *TaskList) DeepCopy() *TaskList {
if in == nil {
return nil
}
out := new(TaskList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TaskList) 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 *TaskSpec) DeepCopyInto(out *TaskSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskSpec.
func (in *TaskSpec) DeepCopy() *TaskSpec {
if in == nil {
return nil
}
out := new(TaskSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TaskStatus) DeepCopyInto(out *TaskStatus) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskStatus.
func (in *TaskStatus) DeepCopy() *TaskStatus {
if in == nil {
return nil
}
out := new(TaskStatus)
in.DeepCopyInto(out)
return out
}

Binary file not shown.

View File

@ -6,5 +6,5 @@ metadata:
spec:
repository:
name: local-backups
task: backup-pvc
task: task-backup-pv
schedule: "*/5 * * * *"

View File

@ -1,7 +1,11 @@
apiVersion: formol.desmojim.fr/v1alpha1
kind: Function
metadata:
name: function-sample
name: function-backup-pv
namespace: backup
spec:
# Add fields here
foo: bar
name: function-backup-pv
image: desmo999r/formolcli
args:
- backup
- pvc

View File

@ -1,7 +1,9 @@
apiVersion: formol.desmojim.fr/v1alpha1
kind: Task
metadata:
name: task-sample
name: task-backup-pv
namespace: backup
spec:
# Add fields here
foo: bar
steps:
- name: function-backup-pv

View File

@ -18,6 +18,8 @@ package controllers
import (
"context"
"fmt"
"time"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/runtime"
@ -25,6 +27,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// BackupSessionReconciler reconciles a BackupSession object
@ -57,12 +62,121 @@ func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
}
log.V(1).Info("Found BackupConfiguration", "BackupConfiguration", backupConf)
var childJobs batchv1.JobList
if err := r.List(ctx, &childJobs, client.InNamespace(req.Namespace), client.MatchingFields{jobOwnerKey: backupSession.Spec.Ref.Name}); err != nil {
log.Error(err, "unable to list child jobs")
return ctrl.Result{}, err
}
var activeJobs []*batchv1.Job
var successfulJobs []*batchv1.Job
var failedJobs []*batchv1.Job
isJobFinished := func(job *batchv1.Job) (bool, batchv1.JobConditionType) {
for _, c := range job.Status.Conditions {
if (c.Type == batchv1.JobComplete || c.Type == batchv1.JobFailed) && c.Status == corev1.ConditionTrue {
return true, c.Type
}
}
return false, ""
}
for i, job := range childJobs.Items {
_, finishedType := isJobFinished(&job)
switch finishedType {
case "": // running
activeJobs = append(activeJobs, &childJobs.Items[i])
case batchv1.JobFailed:
failedJobs = append(failedJobs, &childJobs.Items[i])
case batchv1.JobComplete:
successfulJobs = append(successfulJobs, &childJobs.Items[i])
}
}
if len(activeJobs) > 0 {
log.V(0).Info("A backup job is already running. Skipping")
return ctrl.Result{}, nil
}
constructJobForBackupConfiguration := func(backupConf formolv1alpha1.BackupConfiguration) (*batchv1.Job, error) {
name := fmt.Sprintf("%s-%d", backupConf.Name, time.Now().Unix())
log.V(1).Info("constructing a new Job", "name", name)
task := &formolv1alpha1.Task{}
if err := r.Get(ctx, client.ObjectKey{
Namespace: "backup",
Name: backupConf.Spec.Task,
}, task); err != nil {
log.Error(err, "unable to get Task from BackupConfiguration")
return nil, err
}
log.V(1).Info("found task", "task", task.Name)
containers := []corev1.Container{}
for _, step := range task.Spec.Steps {
function := &formolv1alpha1.Function{}
if err := r.Get(ctx, client.ObjectKey{
Namespace: "backup",
Name: step.Name,
}, function); err != nil {
log.Error(err, "unable to get Function")
return nil, err
}
log.V(1).Info("found function", "function", function.Name)
containers = append(containers, *function.Spec.DeepCopy())
}
job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Labels: make(map[string]string),
Annotations: make(map[string]string),
Name: name,
Namespace: backupConf.Namespace,
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: containers,
RestartPolicy: corev1.RestartPolicyOnFailure,
},
},
},
}
return job, nil
}
job, err := constructJobForBackupConfiguration(backupConf)
if err != nil {
log.Error(err, "unable to construct job")
return ctrl.Result{}, nil
}
if err := r.Create(ctx, job); err != nil {
log.Error(err, "unable to create job")
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
var (
jobOwnerKey = ".metadata.controller"
apiGVStr = formolv1alpha1.GroupVersion.String()
)
func (r *BackupSessionReconciler) SetupWithManager(mgr ctrl.Manager) error {
if err := mgr.GetFieldIndexer().IndexField(&batchv1.Job{}, jobOwnerKey, func(rawObj runtime.Object) []string {
job := rawObj.(*batchv1.Job)
owner := metav1.GetControllerOf(job)
if owner == nil {
return nil
}
if owner.APIVersion != apiGVStr || owner.Kind != "BackupSession" {
return nil
}
return []string{owner.Name}
}); err != nil {
return err
}
return ctrl.NewControllerManagedBy(mgr).
For(&formolv1alpha1.BackupSession{}).
Owns(&batchv1.Job{}).
Complete(r)
}