<p>I have a <code>CronJob</code> that runs a process in a container in Kubernetes.</p>

<p>This process takes in a time window that is defined by a <code>--since</code> and <code>--until</code> flag.  This time window needs to be defined at container start time (when the cron is triggered) and is a function of the current time.  An example running this process would be:</p>

<pre class="lang-sh prettyprint-override"><code>$ my-process --since=$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ") --until=$(date -v +1H +"%Y-%m-%dT%H:%M:%SZ")
</code></pre>

<p>So for the example above, I would like the time window to be from 1 hour ago to 1 hour in the future.  Is there a way in Kubernetes to pass in a formatted datetime as a command argument to a process?</p>

<p>An example of what I am trying to do would be the following config:</p>

<pre><code>apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: my-process
spec:
  schedule: "*/2 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: my-process
            image: my-image
            args:
            - my-process
            - --since=$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ")
            - --until=$(date -v +1H +"%Y-%m-%dT%H:%M:%SZ")
</code></pre>

<p>When doing this, the literal string <code>"$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ")"</code> would be passed in as the <code>--since</code> flag.</p>

<p>Is something like this possible?  If so, how would I do it?</p>

northsideknight
<p>Note that in your <code>CronJob</code> you don't run <code>bash</code> or any other shell and <code>command substitution</code> is a shell feature and without one will not work. In your example only one command <code>my-process</code> is started in the container and as it is not a shell, it is unable to perform <code>command substitution</code>.</p>

<p>This one:</p>

<pre><code>$ my-process --since=$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ") --until=$(date -v +1H +"%Y-%m-%dT%H:%M:%SZ")
</code></pre>

<p>will work properly because it is started in a <code>shell</code> so it may take advantage of shell features such as mentioned <code>command substitution</code></p>

<p>One thing: <code>date -v -1H +"%Y-%m-%dT%H:%M:%SZ"</code> doesn't expand properly in <code>bash shell</code> with default <code>GNU/Linux</code> <code>date</code> implementation. Among others <code>-v</code> option is not recognized so I guess you're using it on <code>MacOSX</code> or some kind of <code>BSD</code> system. In my examples below I will use date version that works on <code>Debian</code>.</p>

<p>So for testing it on <code>GNU/Linux</code> it will be something like this:</p>

<p><code>date --date='-1 hour' +"%Y-%m-%dT%H:%M:%SZ"</code></p>

<p>For testing purpose I've tried it with simple <strong>CronJob</strong> from <a href="https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#creating-a-cron-job" rel="noreferrer">this</a> example with some modifications:</p>

<pre><code>apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: debian
            env:
            - name: FROM
              value: $(date --date="-1 hour" +"%Y-%m-%dT%H:%M:%SZ")
            - name: TILL
              value: $(date --date="+1 hour" +"%Y-%m-%dT%H:%M:%SZ")
            args:
            - /bin/sh
            - -c
            - date; echo from $(FROM) till $(TILL)
          restartPolicy: OnFailure
</code></pre>

<p>It works properly. Below you can see the result of <code>CronJob</code> execution:</p>

<pre><code>$ kubectl logs hello-1569947100-xmglq
 Tue Oct  1 16:25:11 UTC 2019
 from 2019-10-01T15:25:11Z till 2019-10-01T17:25:11Z
</code></pre>

<p>Apart from the example with use of <a href="https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#use-environment-variables-to-define-arguments" rel="noreferrer">environment variables</a> I tested it with following code:</p>

<pre><code>apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: debian
            args:
            - /bin/sh
            - -c
            - date; echo from $(date --date="-1 hour" +"%Y-%m-%dT%H:%M:%SZ") till $(date --date="+1 hour" +"%Y-%m-%dT%H:%M:%SZ")
          restartPolicy: OnFailure
</code></pre>

<p>and as you can see here <code>command substitution</code> also works properly:</p>

<pre><code>$ kubectl logs hello-1569949680-fk782
Tue Oct  1 17:08:09 UTC 2019
from 2019-10-01T16:08:09Z till 2019-10-01T18:08:09Z
</code></pre>

<p>It works properly because in both examples <strong>first</strong> we spawn <code>bash shell</code> in our container and <strong>subsequently</strong> it runs other commands as simple <code>echo</code> provided as its argument. You can use your <code>my-process</code> command instead of <code>echo</code> only you'll need to provide it in one line with all its arguments, like this:</p>

<pre><code>args:
- /bin/sh
- -c
- my-process --since=$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ") --until=$(date -v +1H +"%Y-%m-%dT%H:%M:%SZ")
</code></pre>

<p><strong>This example will not work</strong> as there is no <code>shell</code> involved. <code>echo</code> command not being a shell will not be able to perform command substitution which is a shell feature:</p>

<pre><code>apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: debian
            args:
            - /bin/echo
            - from $(date --date="-1 hour" +"%Y-%m-%dT%H:%M:%SZ") till $(date --date="+1 hour" +"%Y-%m-%dT%H:%M:%SZ")
          restartPolicy: OnFailure
</code></pre>

<p>and the results will be a literal string:</p>

<pre><code>$ kubectl logs hello-1569951180-fvghz
from $(date --date="-1 hour" +"%Y-%m-%dT%H:%M:%SZ") till $(date --date="+1 hour" +"%Y-%m-%dT%H:%M:%SZ")
</code></pre>

<p>which is similar to your case as your command, like <code>echo</code> isn't a <code>shell</code> and it cannot perform <code>command substitution</code>.</p>

<p>To sum up: The solution for that is <strong>wrapping your command as a shell argument</strong>. In first two examples <code>echo</code> command is passed along with other commands as shell argument.</p>

<p>Maybe it is visible more clearly in the following example with a bit different syntax:</p>

<pre><code>apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: debian
            command: ["/bin/sh","-c"]
            args: ["FROM=$(date --date='-1 hour' +'%Y-%m-%dT%H:%M:%SZ'); TILL=$(date --date='+1 hour' +'%Y-%m-%dT%H:%M:%SZ') ;echo from $FROM till $TILL"]
          restartPolicy: OnFailure
</code></pre>

<p><code>man bash</code> says:</p>

<blockquote>
  <p>-c        If the -c option is present, then commands are read from the first non-option argument command_string.</p>
</blockquote>

<p>so <code>command: ["/bin/sh","-c"]</code> basically means <em>run a shell and execute following commands</em> which then we pass to it using <code>args</code>. In <code>bash</code> commands should be separated with semicolon <code>;</code> so they are run independently (subsequent command is executed no matter what was the result of executing previous command/commands).</p>

<p>In the following fragment:</p>

<pre><code>args: ["FROM=$(date --date='-1 hour' +'%Y-%m-%dT%H:%M:%SZ'); TILL=$(date --date='+1 hour' +'%Y-%m-%dT%H:%M:%SZ') ;echo from $FROM till $TILL"]
</code></pre>

<p>we provide to <code>/bin/sh -c</code> three separate commands:</p>

<pre><code>FROM=$(date --date='-1 hour' +'%Y-%m-%dT%H:%M:%SZ')
</code></pre>

<p>which sets <code>FROM</code> environment variable to result of execution of <code>date --date='-1 hour' +'%Y-%m-%dT%H:%M:%SZ'</code> command,</p>

<pre><code>TILL=$(date --date='+1 hour' +'%Y-%m-%dT%H:%M:%SZ')
</code></pre>

<p>which sets <code>TILL</code> environment variable to result of execution of <code>date --date='+1 hour' +'%Y-%m-%dT%H:%M:%SZ'</code> command</p>

<p>and finally we run </p>

<pre><code>echo from $FROM till $TILL
</code></pre>

<p>which uses both variables.</p>

<p>Exactly the same can be done with any other command.</p>
