From 0dbacc342c2dd721ba8b96a9dc13b1fa0d4f8c49 Mon Sep 17 00:00:00 2001
From: Benjamin Bertrand <benjamin.bertrand@esss.se>
Date: Fri, 13 Jul 2018 14:06:36 +0200
Subject: [PATCH] Add trigger ZTP configuration task

JIRA INFRA-414
---
 app/models.py                        | 17 +++++++
 app/network/forms.py                 |  4 ++
 app/network/views.py                 | 67 +++++++++++++++++++---------
 app/settings.py                      |  1 +
 app/tasks.py                         | 23 ++++++++++
 app/templates/network/view_host.html | 33 ++++++++------
 6 files changed, 112 insertions(+), 33 deletions(-)

diff --git a/app/models.py b/app/models.py
index 0afa49f..d3745fe 100644
--- a/app/models.py
+++ b/app/models.py
@@ -829,6 +829,23 @@ class Host(CreatedMixin, db.Model):
         except IndexError:
             return None
 
+    @property
+    def main_interface(self):
+        """Return the host main interface
+
+        The main interface is the one that has the same name as the host
+        or the first one found
+        """
+        for interface in self.interfaces:
+            if interface.name == self.name:
+                return interface
+        # No interface with the same name found...
+        # Return the first one
+        try:
+            return self.interfaces[0]
+        except IndexError:
+            return None
+
     def __str__(self):
         return str(self.name)
 
diff --git a/app/network/forms.py b/app/network/forms.py
index f349683..208b05d 100644
--- a/app/network/forms.py
+++ b/app/network/forms.py
@@ -227,6 +227,10 @@ class CreateVMForm(CSEntryForm):
         self.memory.choices = utils.get_choices(current_app.config["VM_MEMORY_CHOICES"])
 
 
+class GenerateZTPConfigForm(CSEntryForm):
+    pass
+
+
 class AnsibleGroupForm(CSEntryForm):
     name = StringField(
         "name",
diff --git a/app/network/views.py b/app/network/views.py
index 4104bac..7b4f0c6 100644
--- a/app/network/views.py
+++ b/app/network/views.py
@@ -31,6 +31,7 @@ from .forms import (
     NetworkScopeForm,
     DomainForm,
     CreateVMForm,
+    GenerateZTPConfigForm,
     AnsibleGroupForm,
 )
 from ..extensions import db
@@ -110,28 +111,54 @@ def create_host():
 @login_required
 def view_host(name):
     host = models.Host.query.filter_by(name=name).first_or_404()
-    form = CreateVMForm()
-    if host.is_ioc:
-        form.cores.choices = utils.get_choices(current_app.config["VIOC_CORES_CHOICES"])
-        form.memory.choices = utils.get_choices(
-            current_app.config["VIOC_MEMORY_CHOICES"]
-        )
-    if form.validate_on_submit():
-        if not current_user.is_admin:
-            flash(f"Only admin users are allowed to create a VM!", "info")
-            return redirect(url_for("network.view_host", name=name))
-        else:
-            interface = host.interfaces[0]
-            task = tasks.trigger_vm_creation(
-                name, interface, int(form.memory.data) * 1000, form.cores.data
+    if host.device_type.name == "Network":
+        form = GenerateZTPConfigForm()
+    elif host.device_type.name.startswith("Virtual"):
+        form = CreateVMForm()
+        if host.is_ioc:
+            form.cores.choices = utils.get_choices(
+                current_app.config["VIOC_CORES_CHOICES"]
             )
-            db.session.commit()
-            current_app.logger.info(f"Creation of {name} requested: task {task.id}")
-            flash(
-                f"Creation of {name} requested! Refresh the page to update the status.",
-                "success",
+            form.memory.choices = utils.get_choices(
+                current_app.config["VIOC_MEMORY_CHOICES"]
             )
-            return redirect(url_for("task.view_task", id_=task.id))
+    else:
+        form = None
+    if form is not None and form.validate_on_submit():
+        if host.device_type.name == "Network":
+            if not current_user.is_admin:
+                flash(
+                    f"Only admin users are allowed to generate a ZTP configuration!",
+                    "info",
+                )
+                return redirect(url_for("network.view_host", name=name))
+            else:
+                task = tasks.trigger_ztp_configuration(host)
+                db.session.commit()
+                current_app.logger.info(
+                    f"Generation of {name} ZTP configuration requested: task {task.id}"
+                )
+                flash(
+                    f"Generation of {name} ZTP configuration requested! Refresh the page to update the status.",
+                    "success",
+                )
+                return redirect(url_for("task.view_task", id_=task.id))
+        else:
+            if not current_user.is_admin:
+                flash(f"Only admin users are allowed to create a VM!", "info")
+                return redirect(url_for("network.view_host", name=name))
+            else:
+                interface = host.interfaces[0]
+                task = tasks.trigger_vm_creation(
+                    name, interface, int(form.memory.data) * 1000, form.cores.data
+                )
+                db.session.commit()
+                current_app.logger.info(f"Creation of {name} requested: task {task.id}")
+                flash(
+                    f"Creation of {name} requested! Refresh the page to update the status.",
+                    "success",
+                )
+                return redirect(url_for("task.view_task", id_=task.id))
     return render_template("network/view_host.html", host=host, form=form)
 
 
diff --git a/app/settings.py b/app/settings.py
index 455b247..5b9c946 100644
--- a/app/settings.py
+++ b/app/settings.py
@@ -75,6 +75,7 @@ AWX_URL = "https://torn.tn.esss.lu.se"
 AWX_CORE_SERVICES_UPDATE = "ics-ans-core @ DHCP test"
 AWX_CREATE_VM = "ics-ans-deploy-proxmox-vm"
 AWX_CREATE_VIOC = "ics-ans-deploy-vioc"
+AWX_ZTP_CONFIGURATION = "ics-ans-ztp"
 
 AWX_JOB_ENABLED = False
 AWX_VM_CREATION_ENABLED = False
diff --git a/app/tasks.py b/app/tasks.py
index 97d938a..3015ff2 100644
--- a/app/tasks.py
+++ b/app/tasks.py
@@ -118,6 +118,29 @@ def trigger_vm_creation(name, interface, memory, cores):
     return task
 
 
+def trigger_ztp_configuration(host):
+    """Trigger a job to generate a switch ZTP configuration"""
+    extra_vars = [
+        f"ztp_host={host.name}",
+        f"ztp_ip={host.main_interface.ip}",
+        f"ztp_mac={host.main_interface.mac}",
+        f"ztp_model={host.model}",
+    ]
+    job_template = current_app.config["AWX_ZTP_CONFIGURATION"]
+    current_app.logger.info(
+        f"Launch new job to generate ZTP configuration for {host.name} device: {job_template} with {extra_vars}"
+    )
+    user = utils.cse_current_user()
+    task = user.launch_task(
+        "trigger_ztp_configuration",
+        func="launch_job_template",
+        job_template=job_template,
+        extra_vars=extra_vars,
+        timeout=500,
+    )
+    return task
+
+
 def launch_job_template(job_template, **kwargs):
     rq_job = get_current_job()
     if job_template in (
diff --git a/app/templates/network/view_host.html b/app/templates/network/view_host.html
index 7eef111..92537b6 100644
--- a/app/templates/network/view_host.html
+++ b/app/templates/network/view_host.html
@@ -50,19 +50,26 @@
       </dl>
     </div>
     {% if host.device_type.name.startswith('Virtual') and current_user.is_admin %}
-    {% if host.is_ioc %}
-      {% set vm_type = 'Virtual IOC' %}
-    {% else %}
-      {% set vm_type = 'VM' %}
-    {% endif %}
-    <div class="col-sm-3">
-      <form id="createVMForm" method="POST">
-        {{ form.hidden_tag() }}
-        {{ render_field(form.cores, label_size='6', input_size='6') }}
-        {{ render_field(form.memory, label_size='6', input_size='6') }}
-        {{ submit_button_with_confirmation('Create ' + vm_type, 'Do you really want to create the ' + vm_type + ' ' + host.name + '?') }}
-      </form>
-    </div>
+      {% if host.is_ioc %}
+        {% set vm_type = 'Virtual IOC' %}
+      {% else %}
+        {% set vm_type = 'VM' %}
+      {% endif %}
+      <div class="col-sm-3">
+        <form id="createVMForm" method="POST">
+          {{ form.hidden_tag() }}
+          {{ render_field(form.cores, label_size='6', input_size='6') }}
+          {{ render_field(form.memory, label_size='6', input_size='6') }}
+          {{ submit_button_with_confirmation('Create ' + vm_type, 'Do you really want to create the ' + vm_type + ' ' + host.name + '?') }}
+        </form>
+      </div>
+    {% elif host.device_type.name == 'Network' and host.model and current_user.is_admin %}
+      <div class="col-sm-3">
+        <form id="generateZTPForm" method="POST">
+          {{ form.hidden_tag() }}
+          {{ submit_button_with_confirmation('Generate ZTP configuration', 'Do you really want to generate the ZTP configuration for ' + host.name + '?') }}
+        </form>
+      </div>
     {% endif %}
   </div>
   <h3>Interfaces</h3>
-- 
GitLab