Kaynağa Gözat

Merge pull request #3822 from codificat/cronjob-example

Merged by openshift-bot
OpenShift Bot 8 yıl önce
ebeveyn
işleme
75e79b3f87

+ 3 - 1
README_CONTAINER_IMAGE.md

@@ -38,4 +38,6 @@ Here is an example of how to run a containerized `openshift-ansible` playbook th
            -e PLAYBOOK_FILE=playbooks/certificate_expiry/default.yaml \
            -e PLAYBOOK_FILE=playbooks/certificate_expiry/default.yaml \
            openshift/openshift-ansible
            openshift/openshift-ansible
 
 
-The [playbook2image examples](https://github.com/aweiteka/playbook2image/tree/master/examples) provide additional information on how to use an image built from it like this one.
+Further usage examples are available in the [examples directory](examples/).
+
+Additional usage information for images built from `playbook2image` like this one can be found in the [playbook2image examples](https://github.com/aweiteka/playbook2image/tree/master/examples).

+ 93 - 0
examples/README.md

@@ -0,0 +1,93 @@
+# openshift-ansible usage examples
+
+The primary use of `openshift-ansible` is to install, configure and upgrade OpenShift clusters.
+
+This is typically done by direct invocation of Ansible tools like `ansible-playbook`. This use case is covered in detail in the [OpenShift advanced installation documentation](https://docs.openshift.org/latest/install_config/install/advanced_install.html)
+
+For OpenShift Container Platform there's also an installation utility that wraps `openshift-ansible`. This usage case is covered in the [Quick Installation](https://docs.openshift.com/container-platform/latest/install_config/install/quick_install.html) section of the documentation.
+
+The usage examples below cover use cases other than install/configure/upgrade.
+
+## Container image
+
+The examples below run [openshift-ansible in a container](../README_CONTAINER_IMAGE.md) to perform certificate expiration checks on an OpenShift cluster from pods running on the cluster itself.
+
+You can find more details about the certificate expiration check roles and example playbooks in [the openshift_certificate_expiry role's README](../roles/openshift_certificate_expiry/README.md).
+
+### Job to upload certificate expiration reports
+
+The example `Job` in [certificate-check-upload.yaml](certificate-check-upload.yaml) executes a [Job](https://docs.openshift.org/latest/dev_guide/jobs.html) that checks the expiration dates of the internal certificates of the cluster and uploads HTML and JSON reports to `/etc/origin/certificate_expiration_report` in the masters.
+
+This example uses the [`easy-mode-upload.yaml`](../playbooks/certificate_expiry/easy-mode-upload.yaml) example playbook, which generates reports and uploads them to the masters. The playbook can be customized via environment variables to control the length of the warning period (`CERT_EXPIRY_WARN_DAYS`) and the location in the masters where the reports are uploaded (`COPY_TO_PATH`).
+
+The job expects the inventory to be provided via the *hosts* key of a [ConfigMap](https://docs.openshift.org/latest/dev_guide/configmaps.html) named *inventory*, and the passwordless ssh key that allows connecting to the hosts to be availalbe as *ssh-privatekey* from a [Secret](https://docs.openshift.org/latest/dev_guide/secrets.html) named *sshkey*, so these are created first:
+
+    oc new-project certcheck
+    oc create configmap inventory --from-file=hosts=/etc/ansible/hosts
+    oc secrets new-sshauth sshkey --ssh-privatekey=$HOME/.ssh/id_rsa
+
+Note that `inventory`, `hosts`, `sshkey` and `ssh-privatekey` are referenced by name from the provided example Job definition. If you use different names for the objects/attributes you will have to adjust the Job accordingly.
+
+To create the Job:
+
+    oc create -f examples/certificate-check-upload.yaml
+
+### Scheduled job for certificate expiration report upload
+
+**Note**: This example uses the [ScheduledJob](https://docs.openshift.com/container-platform/3.4/dev_guide/scheduled_jobs.html) object, which has been renamed to [CronJob](https://docs.openshift.org/latest/dev_guide/cron_jobs.html) upstream and is still a Technology Preview subject to further change.
+
+The example `ScheduledJob` in [scheduled-certcheck-upload.yaml](scheduled-certcheck-upload.yaml) does the same as the `Job` example above, but it is scheduled to automatically run every first day of the month (see the `spec.schedule` value in the example).
+
+The job definition is the same and it expects the same configuration: we provide the inventory and ssh key via a ConfigMap and a Secret respectively:
+
+    oc new-project certcheck
+    oc create configmap inventory --from-file=hosts=/etc/ansible/hosts
+    oc secrets new-sshauth sshkey --ssh-privatekey=$HOME/.ssh/id_rsa
+
+And then we create the ScheduledJob:
+
+    oc create -f examples/scheduled-certcheck-upload.yaml
+
+### Job and ScheduledJob to check certificates using volumes
+
+There are two additional examples:
+
+ - A `Job` [certificate-check-volume.yaml](certificate-check-volume.yaml)
+ - A `ScheduledJob` [scheduled-certcheck-upload.yaml](scheduled-certcheck-upload.yaml)
+
+These perform the same work as the two examples above, but instead of uploading the generated reports to the masters they store them in a custom path within the container that is expected to be backed by a [PersistentVolumeClaim](https://docs.openshift.org/latest/dev_guide/persistent_volumes.html), so that the reports are actually written to storage external to the container.
+
+These examples assume that there is an existing `PersistentVolumeClaim` called `certcheck-reports` and they use the  [`html_and_json_timestamp.yaml`](../playbooks/certificate_expiry/html_and_json_timestamp.yaml) example playbook to write timestamped reports into it.
+
+You can later access the reports from another pod that mounts the same volume, or externally via direct access to the backend storage behind the matching `PersistentVolume`.
+
+To run these examples we prepare the inventory and ssh keys as in the other examples:
+
+    oc new-project certcheck
+    oc create configmap inventory --from-file=hosts=/etc/ansible/hosts
+    oc secrets new-sshauth sshkey --ssh-privatekey=$HOME/.ssh/id_rsa
+
+Additionally we allocate a `PersistentVolumeClaim` to store the reports:
+
+	oc create -f - <<PVC
+	---
+	apiVersion: v1
+	kind: PersistentVolumeClaim
+	metadata:
+	  name: certcheck-reports
+	spec:
+	  accessModes:
+		- ReadWriteOnce
+	  resources:
+		requests:
+		  storage: 1Gi
+	PVC
+
+With that we can run the `Job` once:
+
+    oc create -f examples/certificate-check-volume.yaml
+
+or schedule it to run periodically as a `ScheduledJob`:
+
+    oc create -f examples/scheduled-certcheck-volume.yaml
+

+ 47 - 0
examples/certificate-check-upload.yaml

@@ -0,0 +1,47 @@
+# An example Job to run a certificate check of OpenShift's internal
+# certificate status from within OpenShift.
+#
+# The generated reports are uploaded to a location in the master
+# hosts, using the playbook 'easy-mode-upload.yaml'.
+#
+# This example uses the openshift/openshift-ansible container image.
+# (see README_CONTAINER_IMAGE.md in the top level dir for more details).
+#
+# The following objects are xpected to be configured before the creation
+# of this Job:
+#   - A ConfigMap named 'inventory' with a key named 'hosts' that
+#     contains the the Ansible inventory file
+#   - A Secret named 'sshkey' with a key named 'ssh-privatekey
+#     that contains the ssh key to connect to the hosts
+# (see examples/README.md for more details)
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: certificate-check
+spec:
+  containers:
+  - name: openshift-ansible
+    image: openshift/openshift-ansible
+    env:
+    - name: PLAYBOOK_FILE
+      value: playbooks/certificate_expiry/easy-mode-upload.yaml
+    - name: INVENTORY_FILE
+      value: /tmp/inventory/hosts       # from configmap vol below
+    - name: ANSIBLE_PRIVATE_KEY_FILE    # from secret vol below
+      value: /opt/app-root/src/.ssh/id_rsa/ssh-privatekey
+    - name: CERT_EXPIRY_WARN_DAYS
+      value: "45"      # must be a string, don't forget the quotes
+    volumeMounts:
+    - name: sshkey
+      mountPath: /opt/app-root/src/.ssh/id_rsa
+    - name: inventory
+      mountPath: /tmp/inventory
+  volumes:
+  - name: sshkey
+    secret:
+      secretName: sshkey
+  - name: inventory
+    configMap:
+      name: inventory
+  restartPolicy: Never

+ 54 - 0
examples/certificate-check-volume.yaml

@@ -0,0 +1,54 @@
+# An example Job to run a certificate check of OpenShift's internal
+# certificate status from within OpenShift.
+#
+# The generated reports are stored in a Persistent Volume using
+# the playbook 'html_and_json_timestamp.yaml'.
+#
+# This example uses the openshift/openshift-ansible container image.
+# (see README_CONTAINER_IMAGE.md in the top level dir for more details).
+#
+# The following objects are xpected to be configured before the creation
+# of this Job:
+#   - A ConfigMap named 'inventory' with a key named 'hosts' that
+#     contains the the Ansible inventory file
+#   - A Secret named 'sshkey' with a key named 'ssh-privatekey
+#     that contains the ssh key to connect to the hosts
+#   - A PersistentVolumeClaim named 'certcheck-reports' where the
+#     generated reports are going to be stored
+# (see examples/README.md for more details)
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: certificate-check
+spec:
+  containers:
+  - name: openshift-ansible
+    image: openshift/openshift-ansible
+    env:
+    - name: PLAYBOOK_FILE
+      value: playbooks/certificate_expiry/html_and_json_timestamp.yaml
+    - name: INVENTORY_FILE
+      value: /tmp/inventory/hosts       # from configmap vol below
+    - name: ANSIBLE_PRIVATE_KEY_FILE    # from secret vol below
+      value: /opt/app-root/src/.ssh/id_rsa/ssh-privatekey
+    - name: CERT_EXPIRY_WARN_DAYS
+      value: "45"      # must be a string, don't forget the quotes
+    volumeMounts:
+    - name: sshkey
+      mountPath: /opt/app-root/src/.ssh/id_rsa
+    - name: inventory
+      mountPath: /tmp/inventory
+    - name: reports
+      mountPath: /var/lib/certcheck
+  volumes:
+  - name: sshkey
+    secret:
+      secretName: sshkey
+  - name: inventory
+    configMap:
+      name: inventory
+  - name: reports
+    persistentVolumeClaim:
+      claimName: certcheck-reports
+  restartPolicy: Never

+ 53 - 0
examples/scheduled-certcheck-upload.yaml

@@ -0,0 +1,53 @@
+# An example ScheduledJob to run a regular check of OpenShift's internal
+# certificate status.
+#
+# Each job will upload new reports to a directory in the master hosts
+#
+# The Job specification is the same as 'certificate-check-upload.yaml'
+# and the expected pre-configuration is equivalent.
+# See that Job example and examples/README.md for more details.
+#
+# NOTE: ScheduledJob has been renamed to CronJob in upstream k8s recently. At
+# some point (OpenShift 3.6+) this will have to be renamed to "kind: CronJob"
+# and once the API stabilizes the apiVersion will have to be updated too.
+---
+apiVersion: batch/v2alpha1
+kind: ScheduledJob
+metadata:
+  name: certificate-check
+  labels:
+    app: certcheck
+spec:
+  schedule: "0 0 1 * *"      # every 1st day of the month at midnight
+  jobTemplate:
+    metadata:
+      labels:
+        app: certcheck
+    spec:
+      template:
+        spec:
+          containers:
+          - name: openshift-ansible
+            image: openshift/openshift-ansible
+            env:
+            - name: PLAYBOOK_FILE
+              value: playbooks/certificate_expiry/easy-mode-upload.yaml
+            - name: INVENTORY_FILE
+              value: /tmp/inventory/hosts       # from configmap vol below
+            - name: ANSIBLE_PRIVATE_KEY_FILE    # from secret vol below
+              value: /opt/app-root/src/.ssh/id_rsa/ssh-privatekey
+            - name: CERT_EXPIRY_WARN_DAYS
+              value: "45"      # must be a string, don't forget the quotes
+            volumeMounts:
+            - name: sshkey
+              mountPath: /opt/app-root/src/.ssh/id_rsa
+            - name: inventory
+              mountPath: /tmp/inventory
+          volumes:
+          - name: sshkey
+            secret:
+              secretName: sshkey
+          - name: inventory
+            configMap:
+              name: inventory
+          restartPolicy: Never

+ 58 - 0
examples/scheduled-certcheck-volume.yaml

@@ -0,0 +1,58 @@
+# An example ScheduledJob to run a regular check of OpenShift's internal
+# certificate status.
+#
+# Each job will add a new pair of reports to the configured Persistent Volume
+#
+# The Job specification is the same as 'certificate-check-volume.yaml'
+# and the expected pre-configuration is equivalent.
+# See that Job example and examples/README.md for more details.
+#
+# NOTE: ScheduledJob has been renamed to CronJob in upstream k8s recently. At
+# some point (OpenShift 3.6+) this will have to be renamed to "kind: CronJob"
+# and once the API stabilizes the apiVersion will have to be updated too.
+---
+apiVersion: batch/v2alpha1
+kind: ScheduledJob
+metadata:
+  name: certificate-check
+  labels:
+    app: certcheck
+spec:
+  schedule: "0 0 1 * *"      # every 1st day of the month at midnight
+  jobTemplate:
+    metadata:
+      labels:
+        app: certcheck
+    spec:
+      template:
+        spec:
+          containers:
+          - name: openshift-ansible
+            image: openshift/openshift-ansible
+            env:
+            - name: PLAYBOOK_FILE
+              value: playbooks/certificate_expiry/html_and_json_timestamp.yaml
+            - name: INVENTORY_FILE
+              value: /tmp/inventory/hosts       # from configmap vol below
+            - name: ANSIBLE_PRIVATE_KEY_FILE    # from secret vol below
+              value: /opt/app-root/src/.ssh/id_rsa/ssh-privatekey
+            - name: CERT_EXPIRY_WARN_DAYS
+              value: "45"      # must be a string, don't forget the quotes
+            volumeMounts:
+            - name: sshkey
+              mountPath: /opt/app-root/src/.ssh/id_rsa
+            - name: inventory
+              mountPath: /tmp/inventory
+            - name: reports
+              mountPath: /var/lib/certcheck
+          volumes:
+          - name: sshkey
+            secret:
+              secretName: sshkey
+          - name: inventory
+            configMap:
+              name: inventory
+          - name: reports
+            persistentVolumeClaim:
+              claimName: certcheck-reports
+          restartPolicy: Never

+ 40 - 0
playbooks/certificate_expiry/easy-mode-upload.yaml

@@ -0,0 +1,40 @@
+# This example generates HTML and JSON reports and
+#
+# Copies of the generated HTML and JSON reports are uploaded to the masters,
+# which is particularly useful when this playbook is run from a container.
+#
+# All certificates (healthy or not) are included in the results
+#
+# Optional environment variables to alter the behaviour of the playbook:
+# CERT_EXPIRY_WARN_DAYS:  Length of the warning window in days (45)
+# COPY_TO_PATH: path to copy reports to in the masters (/etc/origin/certificate_expiration_report)
+---
+- name: Generate certificate expiration reports
+  hosts: nodes:masters:etcd
+  gather_facts: no
+  vars:
+    openshift_certificate_expiry_save_json_results: yes
+    openshift_certificate_expiry_generate_html_report: yes
+    openshift_certificate_expiry_show_all: yes
+    openshift_certificate_expiry_warning_days: "{{ lookup('env', 'CERT_EXPIRY_WARN_DAYS') | default('45', true) }}"
+  roles:
+    - role: openshift_certificate_expiry
+
+- name: Upload reports to master
+  hosts: masters
+  gather_facts: no
+  vars:
+    destination_path: "{{ lookup('env', 'COPY_TO_PATH') | default('/etc/origin/certificate_expiration_report', true) }}"
+    timestamp: "{{ lookup('pipe', 'date +%Y%m%d') }}"
+  tasks:
+    - name: Ensure that the target directory exists
+      file:
+        path: "{{ destination_path }}"
+        state: directory
+    - name: Copy the reports
+      copy:
+        dest: "{{ destination_path }}/{{ timestamp }}-{{ item }}"
+        src: "/tmp/{{ item }}"
+      with_items:
+        - "cert-expiry-report.html"
+        - "cert-expiry-report.json"

+ 16 - 0
playbooks/certificate_expiry/html_and_json_timestamp.yaml

@@ -0,0 +1,16 @@
+---
+# Generate timestamped HTML and JSON reports in /var/lib/certcheck
+
+- name: Check cert expirys
+  hosts: nodes:masters:etcd
+  become: yes
+  gather_facts: no
+  vars:
+    openshift_certificate_expiry_generate_html_report: yes
+    openshift_certificate_expiry_save_json_results: yes
+    openshift_certificate_expiry_show_all: yes
+    timestamp: "{{ lookup('pipe', 'date +%Y%m%d') }}"
+    openshift_certificate_expiry_html_report_path: "/var/lib/certcheck/{{ timestamp }}-cert-expiry-report.html"
+    openshift_certificate_expiry_json_results_path: "/var/lib/certcheck/{{ timestamp }}-cert-expiry-report.json"
+  roles:
+    - role: openshift_certificate_expiry

+ 117 - 16
roles/openshift_certificate_expiry/README.md

@@ -19,7 +19,6 @@ to be used with an inventory that is representative of the
 cluster. For best results run `ansible-playbook` with the `-v` option.
 cluster. For best results run `ansible-playbook` with the `-v` option.
 
 
 
 
-
 # Role Variables
 # Role Variables
 
 
 Core variables in this role:
 Core variables in this role:
@@ -51,8 +50,8 @@ How to use the Certificate Expiration Checking Role.
 
 
 Run one of the example playbooks using an inventory file
 Run one of the example playbooks using an inventory file
 representative of your existing cluster. Some example playbooks are
 representative of your existing cluster. Some example playbooks are
-included in this role, or you can read on below after this example to
-craft you own.
+included in this role, or you can [read on below for more examples](#more-example-playbooks)
+to help you craft you own.
 
 
 ```
 ```
 $ ansible-playbook -v -i HOSTS playbooks/certificate_expiry/easy-mode.yaml
 $ ansible-playbook -v -i HOSTS playbooks/certificate_expiry/easy-mode.yaml
@@ -69,11 +68,47 @@ Using the `easy-mode.yaml` playbook will produce:
 > `/usr/share/ansible/openshift-ansible/playbooks/certificate_expiry/easy-mode.yaml`
 > `/usr/share/ansible/openshift-ansible/playbooks/certificate_expiry/easy-mode.yaml`
 > instead
 > instead
 
 
+## Run from a container
+
+The example playbooks that use this role are packaged in the
+[container image for openshift-ansible](../../README_CONTAINER_IMAGE.md), so you
+can run any of them by setting the `PLAYBOOK_FILE` environment variable when
+running an openshift-ansible container.
+
+There are several [examples](../../examples/README.md) in the `examples` directory that run certificate check playbooks from a container running on OpenShift.
+
 ## More Example Playbooks
 ## More Example Playbooks
 
 
 > **Note:** These Playbooks are available to run directly out of the
 > **Note:** These Playbooks are available to run directly out of the
 > [/playbooks/certificate_expiry/](../../playbooks/certificate_expiry/) directory.
 > [/playbooks/certificate_expiry/](../../playbooks/certificate_expiry/) directory.
 
 
+### Default behavior
+
+This playbook just invokes the certificate expiration check role with default options:
+
+
+```yaml
+---
+- name: Check cert expirys
+  hosts: nodes:masters:etcd
+  become: yes
+  gather_facts: no
+  roles:
+    - role: openshift_certificate_expiry
+```
+
+**From git:**
+```
+$ ansible-playbook -v -i HOSTS playbooks/certificate_expiry/default.yaml
+```
+**From openshift-ansible-playbooks rpm:**
+```
+$ ansible-playbook -v -i HOSTS /usr/share/ansible/openshift-ansible/playbooks/certificate_expiry/default.yaml
+```
+
+> [View This Playbook](../../playbooks/certificate_expiry/default.yaml)
+
+### Easy mode
 
 
 This example playbook is great if you're just wanting to **try the
 This example playbook is great if you're just wanting to **try the
 role out**. This playbook enables HTML and JSON reports. All
 role out**. This playbook enables HTML and JSON reports. All
@@ -104,35 +139,70 @@ $ ansible-playbook -v -i HOSTS /usr/share/ansible/openshift-ansible/playbooks/ce
 
 
 > [View This Playbook](../../playbooks/certificate_expiry/easy-mode.yaml)
 > [View This Playbook](../../playbooks/certificate_expiry/easy-mode.yaml)
 
 
-***
+### Easy mode and upload reports to masters
+
+This example builds on top of [easy-mode.yaml](#easy-mode) and additionally
+uploads a copy of the generated reports to the masters, with a timestamp in the
+file names.
+
+This is specially useful when the playbook runs from within a container, because
+the reports are generated inside the container and we need a way to access them.
+Uploading a copy of the reports to the masters is one way to make it easy to
+access them. Alternatively you can use the
+[role variables](#role-variables) that control the path of the generated reports
+to point to a container volume (see the [playbook with custom paths](#generate-html-and-json-reports-in-a-custom-path) for an example).
 
 
-Default behavior:
+With the container use case in mind, this playbook allows control over some
+options via environment variables:
+
+ - `CERT_EXPIRY_WARN_DAYS`: sets `openshift_certificate_expiry_warning_days`, overriding the role's default.
+ - `COPY_TO_PATH`: path in the masters where generated reports are uploaded.
 
 
 ```yaml
 ```yaml
 ---
 ---
-- name: Check cert expirys
+- name: Generate certificate expiration reports
   hosts: nodes:masters:etcd
   hosts: nodes:masters:etcd
-  become: yes
   gather_facts: no
   gather_facts: no
+  vars:
+    openshift_certificate_expiry_save_json_results: yes
+    openshift_certificate_expiry_generate_html_report: yes
+    openshift_certificate_expiry_show_all: yes
+    openshift_certificate_expiry_warning_days: "{{ lookup('env', 'CERT_EXPIRY_WARN_DAYS') | default('45', true) }}"
   roles:
   roles:
     - role: openshift_certificate_expiry
     - role: openshift_certificate_expiry
+
+- name: Upload reports to master
+  hosts: masters
+  gather_facts: no
+  vars:
+    destination_path: "{{ lookup('env', 'COPY_TO_PATH') | default('/etc/origin/certificate_expiration_report', true) }}"
+    timestamp: "{{ lookup('pipe', 'date +%Y%m%d') }}"
+  tasks:
+    - name: Create directory in masters
+      file:
+        path: "{{ destination_path }}"
+        state: directory
+    - name: Copy the reports to the masters
+      copy:
+        dest: "{{ destination_path }}/{{ timestamp }}-{{ item }}"
+        src: "/tmp/{{ item }}"
+      with_items:
+        - "cert-expiry-report.html"
+        - "cert-expiry-report.json"
 ```
 ```
 
 
 **From git:**
 **From git:**
 ```
 ```
-$ ansible-playbook -v -i HOSTS playbooks/certificate_expiry/default.yaml
+$ ansible-playbook -v -i HOSTS playbooks/certificate_expiry/easy-mode-upload.yaml
 ```
 ```
 **From openshift-ansible-playbooks rpm:**
 **From openshift-ansible-playbooks rpm:**
 ```
 ```
-$ ansible-playbook -v -i HOSTS /usr/share/ansible/openshift-ansible/playbooks/certificate_expiry/default.yaml
+$ ansible-playbook -v -i HOSTS /usr/share/ansible/openshift-ansible/playbooks/certificate_expiry/easy-mode-upload.yaml
 ```
 ```
 
 
-> [View This Playbook](../../playbooks/certificate_expiry/default.yaml)
+> [View This Playbook](../../playbooks/certificate_expiry/easy-mode-upload.yaml)
 
 
-***
-
-
-Generate HTML and JSON artifacts in their default paths:
+### Generate HTML and JSON artifacts in their default paths
 
 
 ```yaml
 ```yaml
 ---
 ---
@@ -158,7 +228,38 @@ $ ansible-playbook -v -i HOSTS /usr/share/ansible/openshift-ansible/playbooks/ce
 
 
 > [View This Playbook](../../playbooks/certificate_expiry/html_and_json_default_paths.yaml)
 > [View This Playbook](../../playbooks/certificate_expiry/html_and_json_default_paths.yaml)
 
 
-***
+### Generate HTML and JSON reports in a custom path
+
+This example customizes the report generation path to point to a specific path (`/var/lib/certcheck`) and uses a date timestamp for the generated files. This allows you to reuse a certain location to keep multiple copies of the reports.
+
+```yaml
+---
+- name: Check cert expirys
+  hosts: nodes:masters:etcd
+  become: yes
+  gather_facts: no
+  vars:
+    openshift_certificate_expiry_generate_html_report: yes
+    openshift_certificate_expiry_save_json_results: yes
+    timestamp: "{{ lookup('pipe', 'date +%Y%m%d') }}"
+    openshift_certificate_expiry_html_report_path: "/var/lib/certcheck/{{ timestamp }}-cert-expiry-report.html"
+    openshift_certificate_expiry_json_results_path: "/var/lib/certcheck/{{ timestamp }}-cert-expiry-report.json"
+  roles:
+    - role: openshift_certificate_expiry
+```
+
+**From git:**
+```
+$ ansible-playbook -v -i HOSTS playbooks/certificate_expiry/html_and_json_timestamp.yaml
+```
+**From openshift-ansible-playbooks rpm:**
+```
+$ ansible-playbook -v -i HOSTS /usr/share/ansible/openshift-ansible/playbooks/certificate_expiry/html_and_json_timestamp.yaml
+```
+
+> [View This Playbook](../../playbooks/certificate_expiry/html_and_json_timestamp.yaml)
+
+### Long warning window
 
 
 Change the expiration warning window to 1500 days (good for testing
 Change the expiration warning window to 1500 days (good for testing
 the module out):
 the module out):
@@ -186,7 +287,7 @@ $ ansible-playbook -v -i HOSTS /usr/share/ansible/openshift-ansible/playbooks/ce
 
 
 > [View This Playbook](../../playbooks/certificate_expiry/longer_warning_period.yaml)
 > [View This Playbook](../../playbooks/certificate_expiry/longer_warning_period.yaml)
 
 
-***
+### Long warning window and JSON report
 
 
 Change the expiration warning window to 1500 days (good for testing
 Change the expiration warning window to 1500 days (good for testing
 the module out) and save the results as a JSON file:
 the module out) and save the results as a JSON file: