// get the attributes from the cron trigger var attributes cronAttributes if err = mapstructure.Decode(cronTrigger.Attributes, &attributes); err != nil { return nil, errors.Wrap(err, "Failed to decode cron trigger attributes") } // populate schedule if attributes.Interval != "" { spec.Schedule = fmt.Sprintf("@every %s", attributes.Interval) } else { spec.Schedule, err = lc.normalizeCronTriggerScheduleInput(attributes.Schedule) if err != nil { return nil, errors.Wrap(err, "Failed to normalize cron schedule") } } // generate a string containing all the headers with --header flag as prefix, to be used by curl later headersAsCurlArg := "" for headerKey := range attributes.Event.Headers { headerValue := attributes.Event.GetHeaderString(headerKey) headersAsCurlArg = fmt.Sprintf("%s --header \"%s: %s\"", headersAsCurlArg, headerKey, headerValue) } // add default headers headersAsCurlArg = fmt.Sprintf("%s --header \"%s: %s\" --header \"%s: %s\"", headersAsCurlArg, headers.InvokeTrigger, "cron", headers.TargetName, function.Name, ) functionAddress, err := lc.getCronTriggerInvocationURL(resources, function.Namespace) if err != nil { return nil, errors.Wrap(err, "Failed to get cron trigger invocation URL") } // generate the curl command to be run by the CronJob to invoke the function // invoke the function (retry for 10 seconds) curlCommand := fmt.Sprintf("curl --silent %s %s --retry 10 --retry-delay 1 --retry-max-time 10 --retry-connrefused", headersAsCurlArg, functionAddress) if attributes.Event.Body != "" { eventBody := attributes.Event.Body // if a body exists - dump it into a file, and pass this file as argument (done to support JSON body) eventBodyFilePath := "/tmp/eventbody.out" eventBodyCurlArg := fmt.Sprintf("--data '@%s'", eventBodyFilePath) // try compact as JSON (will fail if it's not a valid JSON) eventBodyAsCompactedJSON := bytes.NewBuffer([]byte{}) if err := json.Compact(eventBodyAsCompactedJSON, []byte(eventBody)); err == nil { // set the compacted JSON as event body eventBody = eventBodyAsCompactedJSON.String() } curlCommand = fmt.Sprintf("echo %s > %s && %s %s", strconv.Quote(eventBody), eventBodyFilePath, curlCommand, eventBodyCurlArg) } // get cron job retries until failing a job (default=2) jobBackoffLimit := attributes.JobBackoffLimit if jobBackoffLimit == 0 { jobBackoffLimit = 2 } spec.JobTemplate = batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ BackoffLimit: &jobBackoffLimit, Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ Containers: []v1.Container{ { Name: "function-invocator", Image: common.GetEnvOrDefaultString( "NUCLIO_CONTROLLER_CRON_TRIGGER_CRON_JOB_IMAGE_NAME", "gcr.io/iguazio/curlimages/curl:7.81.0"), Args: []string{"/bin/sh", "-c", curlCommand}, ImagePullPolicy: v1.PullPolicy(common.GetEnvOrDefaultString("NUCLIO_CONTROLLER_CRON_TRIGGER_CRON_JOB_IMAGE_PULL_POLICY", "IfNotPresent")), }, }, RestartPolicy: v1.RestartPolicyNever, NodeSelector: function.Status.EnrichedNodeSelector, NodeName: function.Spec.NodeName, Affinity: function.Spec.Affinity, PriorityClassName: function.Spec.PriorityClassName, }, }, }, }