From abe1cac723da26ea31f261356bdc5d9f60613f66 Mon Sep 17 00:00:00 2001
From: Alex Iribarren <Alex.Iribarren@cern.ch>
Date: Thu, 5 May 2022 10:26:42 +0200
Subject: [PATCH] Added form for launching image_ci pipelines

---
 docs/distributions/openstack.md  |  95 ++++++++++++++++++++++++++-
 docs/javascripts/testing_form.js | 107 +++++++++++++++++++++++++++++++
 docs/stylesheets/extra.css       |  67 ++++++++++++++++++-
 mkdocs.yml                       |   3 +
 4 files changed, 269 insertions(+), 3 deletions(-)
 create mode 100644 docs/javascripts/testing_form.js

diff --git a/docs/distributions/openstack.md b/docs/distributions/openstack.md
index d8f4437..a0e9bff 100644
--- a/docs/distributions/openstack.md
+++ b/docs/distributions/openstack.md
@@ -2,8 +2,99 @@
 
 ## Introduction
 
-Our group is responsbile for building and testing new OpenStack glance images for the distributions that we support.
+Our group is responsible for building and testing new OpenStack glance images for the distributions that we support.
 
-We have a scripted process, utilising koji and kickstart files which can be found here: [https://gitlab.cern.ch/linuxsupport/koji-image-build](https://gitlab.cern.ch/linuxsupport/koji-image-build).
+We have a scripted process, utilizing Koji and kickstart files which can be found here: [https://gitlab.cern.ch/linuxsupport/koji-image-build](https://gitlab.cern.ch/linuxsupport/koji-image-build).
 
 This repository takes care of running scheduled pipelines once a month to rebuild our cloud images. It has tests in place which can be also skipped if needed.
+
+## Testing
+
+Testing is carried out by a [separate pipeline](https://gitlab.cern.ch/linuxsupport/testing/image-ci) which is
+triggered automatically when images are rebuilt. It can also be run on demand to test the image or the Puppet
+and Cloud infrastructure.
+
+To make it easier for you, you can use this form to pre-fill the CI pipeline variables. Select the options
+you want, click the button at the bottom and then click "Run pipeline" at the bottom of the Gitlab page
+that will open in a new tab.
+
+<!--
+  Most of the magic happens in docs/javascripts/testing_form.js
+  If you make changes here, you'll have to make changes there too.
+-->
+<form name="image_ci" class="testing">
+  Select at least one option from each of the following three categories:
+  <div class="row">
+    <fieldset>
+      <legend>Operating System</legend>
+      <div>
+        <input type="checkbox" id="TEST_OS7" name="TEST_OS7">
+        <label for="TEST_OS7">CERN CentOS 7</label>
+      </div>
+      <div>
+        <input type="checkbox" id="TEST_OS8s" name="TEST_OS8s">
+        <label for="TEST_OS8s">CentOS Stream 8</label>
+      </div>
+      <div>
+        <input type="checkbox" id="TEST_OS9" name="TEST_OS9">
+        <label for="TEST_OS9">CentOS Stream 9</label>
+      </div>
+      <div>
+        <input type="checkbox" id="TEST_OSRH7" name="TEST_OSRH7">
+        <label for="TEST_OSRH7">RHEL 7</label>
+      </div>
+      <div>
+        <input type="checkbox" id="TEST_OSRH8" name="TEST_OSRH8">
+        <label for="TEST_OSRH8">RHEL 8</label>
+      </div>
+    </fieldset>
+
+    <fieldset>
+      <legend>Instance Type</legend>
+      <div>
+        <input type="checkbox" id="TEST_VIRTUAL" name="TEST_VIRTUAL">
+        <label for="TEST_VIRTUAL">Virtual</label>
+      </div>
+      <div>
+        <input type="checkbox" id="TEST_PHYSICAL" name="TEST_PHYSICAL">
+        <label for="TEST_PHYSICAL">Physical</label>
+      </div>
+    </fieldset>
+
+    <fieldset>
+      <legend>Configuration</legend>
+      <div>
+        <input type="checkbox" id="TEST_UNMANAGED" name="TEST_UNMANAGED">
+        <label for="TEST_UNMANAGED">Unmanaged</label>
+      </div>
+      <div>
+        <input type="checkbox" id="TEST_PUPPET" name="TEST_PUPPET">
+        <label for="TEST_PUPPET">Puppet-managed</label>
+      </div>
+    </fieldset>
+  </div>
+
+  <fieldset>
+    <legend>Advanced Settings</legend>
+    <div>
+      <label for="IMAGE">Image UUID <span class="help">(optional, if not set the latest image is tested)</span>:</label>
+      <input type="text" id="IMAGE" name="IMAGE" size="36" pattern="^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$">
+    </div>
+
+    <div>
+      <label for="FLAVOR">Physical machine flavor <span class="help">(optional, if not set all machines in the project are tested)</span>:</label>
+      <input type="text" id="FLAVOR" name="FLAVOR" size="36">
+    </div>
+
+    <div>
+      <input type="checkbox" id="DELETE_FAILURES" name="DELETE_FAILURES" checked>
+      <label for="DELETE_FAILURES">Delete machines even if tests failed</label>
+    </div>
+
+  </fieldset>
+
+  <hr />
+  <center>
+    <button type="button" name="run" onclick="runImageTests()" disabled>Run 0 tests</button>
+  </center>
+</form>
diff --git a/docs/javascripts/testing_form.js b/docs/javascripts/testing_form.js
new file mode 100644
index 0000000..b595069
--- /dev/null
+++ b/docs/javascripts/testing_form.js
@@ -0,0 +1,107 @@
+// Javascript to deal with the testing pipeline configurator in docs/distributions/openstack.md
+
+function validate() {
+    let valid = 1;
+
+    // First, let's count how many options are selected in each category
+    const OSes = [
+        document.image_ci.TEST_OS7.checked,
+        document.image_ci.TEST_OS8s.checked,
+        document.image_ci.TEST_OS9.checked,
+        document.image_ci.TEST_OSRH7.checked,
+        document.image_ci.TEST_OSRH8.checked,
+    ].filter(value => value === true).length;
+
+    const Instances = [
+        document.image_ci.TEST_VIRTUAL.checked,
+        document.image_ci.TEST_PHYSICAL.checked,
+    ].filter(value => value === true).length;
+
+    const Configs = [
+        document.image_ci.TEST_UNMANAGED.checked,
+        document.image_ci.TEST_PUPPET.checked,
+    ].filter(value => value === true).length;
+
+    // If we were given an image, we can only have one OS selected
+    if (document.image_ci.IMAGE.value !== '' && OSes !== 1) {
+        document.image_ci.IMAGE.setCustomValidity('If you specify an image, you must select <em>exactly</em> one OS to test.');
+        valid = 0;
+    } else if (document.image_ci.IMAGE.validity.patternMismatch) {
+        document.image_ci.IMAGE.setCustomValidity('The image must be specified as a UUID.');
+        valid = 0;
+    } else {
+        document.image_ci.IMAGE.setCustomValidity('');
+    }
+    document.image_ci.IMAGE.reportValidity();
+
+    // If we were given a flavor, TEST_PHYSICAL has to be selected
+    if (document.image_ci.FLAVOR.value !== '' && !document.image_ci.TEST_PHYSICAL.checked) {
+        document.image_ci.FLAVOR.setCustomValidity('If you specify a flavor, you must also enable tests of the Physical instance type.');
+        valid = 0;
+    } else {
+        document.image_ci.FLAVOR.setCustomValidity('');
+    }
+
+    // Update the total number of tests to run and enable or disable the button
+    const total = valid * OSes * Instances * Configs;
+    document.image_ci.run.textContent = `Run ${total} test` + (total === 1 ? "" : "s");
+    if (total > 0) {
+        document.image_ci.run.disabled = false;
+    } else {
+        document.image_ci.run.disabled = true;
+    }
+
+    showErrors(document.image_ci);
+}
+
+// Show validation errors next to the form elements
+function showErrors(form) {
+    var invalidFields = form.querySelectorAll( ":invalid" ),
+        errorMessages = form.querySelectorAll( ".error-message" ),
+        parent;
+
+    // Remove any existing messages
+    for ( var i = 0; i < errorMessages.length; i++ ) {
+        errorMessages[ i ].parentNode.removeChild( errorMessages[ i ] );
+    }
+
+    for ( var i = 0; i < invalidFields.length; i++ ) {
+        parent = invalidFields[ i ].parentNode;
+        parent.insertAdjacentHTML( "beforeend", "<div class='error-message'>" +
+            invalidFields[ i ].validationMessage +
+            "</div>" );
+    }
+
+    // If there are errors, give focus to the first invalid field
+    if ( invalidFields.length > 0 ) {
+        invalidFields[ 0 ].focus();
+    }
+}
+
+// Assemble the Gitlab URL and open it in a new tab
+function runImageTests() {
+    // .../pipelines/new?ref=<branch>&var[<variable_key>]=<value>&file_var[<file_key>]=<value>
+
+    // Assemble the list of variables to pass to the pipeline
+    let variables = [];
+    document.image_ci.querySelectorAll('input').forEach(item => {
+        if (item.type === 'button') return;
+
+        if (item.type === 'checkbox') {
+            value = item.checked ? 'True' : 'False';
+        } else {
+            value = item.value;
+        }
+
+        if (value !== '') variables.push(`var[${item.name}]=${value}`);
+    });
+
+    const url = `https://gitlab.cern.ch/linuxsupport/testing/image-ci/-/pipelines/new?ref=master&${variables.join('&')}`;
+    return window.open(url, "_blank");
+}
+
+// Let's make sure all input fields validate their input on changes
+document.image_ci.querySelectorAll('input').forEach(item => {
+    item.addEventListener('change',  (event) => validate(), false);
+    item.addEventListener('invalid', (event) => event.preventDefault(), true);
+});
diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css
index 1f8e9a4..5e8bf9e 100644
--- a/docs/stylesheets/extra.css
+++ b/docs/stylesheets/extra.css
@@ -9,6 +9,71 @@
     right: 0;
     margin-left: 0;
     -webkit-transform: none;
-    transform: none;   
+    transform: none;
   }
 }
+
+form.testing {
+  border: 1px solid lightgrey;
+  padding: 0.5em;
+  margin: auto;
+  max-width: 80%;
+}
+
+.testing input {
+  border: 1px solid black;
+  padding: 5px;
+  margin: 5px;
+}
+
+.testing label {
+  margin: 5px;
+}
+
+.testing input:invalid {
+  border: 2px solid red;
+}
+
+.testing .error-message {
+  color: red;
+  font-size: 0.9em;
+}
+
+.testing .help {
+  font-size: 0.8em;
+}
+
+.testing .row {
+  display: flex;
+  margin-bottom: 10px;
+}
+
+.testing fieldset {
+  margin-inline: 10px;
+}
+
+.testing legend {
+  padding-left: 5px;
+  padding-right: 5px;
+}
+
+.testing button {
+  background-color: #4CAF50; /* Green */
+  border: none;
+  color: white;
+  padding: 15px 32px;
+  text-align: center;
+  display: inline-block;
+  font-size: 1.2em;
+  margin: 10px;
+  border-radius: 10px;
+  transition-duration: 0.4s;
+}
+
+.testing button:hover {
+  background-color: #477e49; /* Darker Green */
+}
+
+.testing button:disabled {
+  background-color: #ccc; /* Grey */
+}
diff --git a/mkdocs.yml b/mkdocs.yml
index c33dd59..b43783d 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -13,6 +13,9 @@ theme:
 extra_css:
   - 'stylesheets/extra.css'
 
+extra_javascript:
+  - 'javascripts/testing_form.js'
+
 markdown_extensions:
   - admonition
   - pymdownx.superfences
-- 
GitLab