aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sdv/docker/sdvmodel/Dockerfile15
-rw-r--r--sdv/docker/sdvmodel/resource-estimation/requirements.txt2
-rwxr-xr-xsdv/docker/sdvmodel/resource-estimation/server340
-rw-r--r--sdv/docker/sdvmodel/resource-estimation/template/report.html75
-rw-r--r--sdv/docker/sdvmodel/website/actions.js39
-rw-r--r--sdv/docker/sdvmodel/website/assets/plus-circle-solid.svg59
-rw-r--r--sdv/docker/sdvmodel/website/assets/server.svg123
-rw-r--r--sdv/docker/sdvmodel/website/assets/trash-alt-regular.svg59
-rw-r--r--sdv/docker/sdvmodel/website/assets/vnf.svg83
-rw-r--r--sdv/docker/sdvmodel/website/controller.js34
-rw-r--r--sdv/docker/sdvmodel/website/index.html124
-rw-r--r--sdv/docker/sdvmodel/website/mergeDeep.js46
-rw-r--r--sdv/docker/sdvmodel/website/readFromHTML.js72
-rw-r--r--sdv/docker/sdvmodel/website/style/array.css55
-rw-r--r--sdv/docker/sdvmodel/website/style/index.css198
-rw-r--r--sdv/docker/sdvmodel/website/style/report.css90
-rw-r--r--sdv/docker/sdvstate/core/__init__.py1
-rw-r--r--sdv/docker/sdvstate/core/display_report.py57
-rw-r--r--sdv/docker/sdvstate/example/kubepod1020
-rw-r--r--sdv/docker/sdvstate/example/kubepod1520
-rw-r--r--sdv/docker/sdvstate/example/state.yml3
-rw-r--r--[-rwxr-xr-x]sdv/docker/sdvstate/server0
-rw-r--r--sdv/docker/sdvstate/settings/common.yml10
-rwxr-xr-xsdv/docker/sdvstate/state15
-rw-r--r--sdv/docker/sdvstate/validator/airship/__init__.py49
-rw-r--r--sdv/docker/sdvstate/validator/airship/airship.py92
-rw-r--r--sdv/docker/sdvstate/validator/airship/ceph_check.py51
-rw-r--r--sdv/docker/sdvstate/validator/airship/compute_check.py646
-rw-r--r--sdv/docker/sdvstate/validator/airship/monitoring_logging_agent_check.py243
-rw-r--r--sdv/docker/sdvstate/validator/airship/network_check.py114
-rw-r--r--sdv/docker/sdvstate/validator/airship/pod_health_check.py41
-rw-r--r--sdv/docker/sdvstate/validator/airship/store_result.py28
-rw-r--r--sdv/docker/sdvurls/Dockerfile10
-rw-r--r--sdv/docker/sdvurls/requirements.txt13
-rw-r--r--sdv/docker/sdvurls/server281
-rw-r--r--sdv/docs/docker/urls/userguide.rst24
-rw-r--r--sdv/docs/pdf/user/userguide.rst29
-rwxr-xr-xsdv/pdf/site/assets/pdfrep.pngbin0 -> 158477 bytes
-rw-r--r--sdv/pdf/site/assets/plus-circle-solid.svg59
-rw-r--r--sdv/pdf/site/assets/plus-square-regular.svg1
-rw-r--r--sdv/pdf/site/assets/redo-alt-solid.svg1
-rw-r--r--sdv/pdf/site/assets/trash-alt-regular.svg59
-rw-r--r--sdv/pdf/site/index.html1797
-rw-r--r--sdv/pdf/site/scripts/actions.js24
-rw-r--r--sdv/pdf/site/scripts/createfile.js13
-rw-r--r--sdv/pdf/site/scripts/mergeDeep.js31
-rw-r--r--sdv/pdf/site/scripts/readFromHTML.js57
-rw-r--r--sdv/pdf/site/scripts/writeToHTML.js117
-rw-r--r--sdv/pdf/site/style/array.css55
-rw-r--r--sdv/pdf/site/style/multitab.css109
-rw-r--r--sdv/pdf/template/pdf_template.json536
51 files changed, 5958 insertions, 62 deletions
diff --git a/sdv/docker/sdvmodel/Dockerfile b/sdv/docker/sdvmodel/Dockerfile
new file mode 100644
index 0000000..a71575e
--- /dev/null
+++ b/sdv/docker/sdvmodel/Dockerfile
@@ -0,0 +1,15 @@
+FROM python:3.8-slim-buster
+
+MAINTAINER Parth Yadav <parthyadav3105@gmail.com>
+
+WORKDIR /server/
+
+COPY resource-estimation/requirements.txt /server/requirements.txt
+RUN pip install -r requirements.txt
+
+COPY website/ /website/
+COPY resource-estimation/ /server/
+
+RUN rm requirements.txt
+
+CMD [ "python", "/server/server" ]
diff --git a/sdv/docker/sdvmodel/resource-estimation/requirements.txt b/sdv/docker/sdvmodel/resource-estimation/requirements.txt
new file mode 100644
index 0000000..8fd63d9
--- /dev/null
+++ b/sdv/docker/sdvmodel/resource-estimation/requirements.txt
@@ -0,0 +1,2 @@
+tornado == 6.0.4
+Jinja2 == 2.11.2
diff --git a/sdv/docker/sdvmodel/resource-estimation/server b/sdv/docker/sdvmodel/resource-estimation/server
new file mode 100755
index 0000000..bae9781
--- /dev/null
+++ b/sdv/docker/sdvmodel/resource-estimation/server
@@ -0,0 +1,340 @@
+#!/usr/bin/env python3
+
+# Copyright 2020 Spirent Communications, University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+"""
+Server
+"""
+
+
+import logging
+import os
+import sys
+import copy
+import json
+from tornado.web import Application
+from tornado.ioloop import IOLoop
+import tornado.concurrent
+import tornado.httpserver
+import tornado.ioloop
+import tornado.options
+import tornado.web
+import tornado.log
+import jinja2
+
+# SOF: 11124247: Massey101 and Corey Klein
+class StreamToLogger():
+ """
+ file-like stream object that redirects writes to a logger instance.
+ """
+ def __init__(self, logger, log_level=logging.INFO):
+ self.logger = logger
+ self.log_level = log_level
+ self.linebuf = ''
+
+ def write(self, buf):
+ """
+ write logs
+ """
+ temp_linebuf = self.linebuf + buf
+ self.linebuf = ''
+ for line in temp_linebuf.splitlines(True):
+ # From the io.TextIOWrapper docs:
+ # On output, if newline is None, any '\n' characters written
+ # are translated to the system default line separator.
+ # By default sys.stdout.write() expects '\n' newlines and then
+ # translates them so this is still cross platform.
+ if line[-1] == '\n':
+ self.logger.log(self.log_level, line.rstrip())
+ else:
+ self.linebuf += line
+
+ def flush(self):
+ """
+ flush the buffer
+ """
+ if self.linebuf != '':
+ self.logger.log(self.log_level, self.linebuf.rstrip())
+ self.linebuf = ''
+
+
+
+class Server():
+ """
+ Server
+ """
+ # pylint: disable=too-many-instance-attributes
+
+ def __init__(self, hw_profile):
+ self.vcpus = hw_profile['vcpus']
+ self.numas = hw_profile['numas']
+ self.numa_vcpu_map = []
+ self.sriov_support = False
+ self.hosted_vnfs = []
+ for count in range(int(self.numas)):
+ self.numa_vcpu_map.append(hw_profile['numa'
+ +str(count)
+ +'_cpus_4vnfs'])
+ self.create_numa_sriov_map(hw_profile['nics'])
+ self.zone = 'default'
+ self.cpu_isolation = hw_profile['cpu_isol_set']
+ self.available_cpu_map = self.numa_vcpu_map
+
+ def create_numa_sriov_map(self, nics):
+ """
+ Search for all sriov and nonsriov numas
+ """
+ self.sriov_numas = []
+ self.nonsriov_numas = []
+ for nic in nics:
+ if nic['type'] == 'sriov':
+ self.sriov_support = True
+ if nic['numa'] not in self.sriov_numas:
+ self.sriov_numas.append(int(nic['numa']))
+ else:
+ if nic['numa'] not in self.sriov_numas:
+ self.nonsriov_numas.append(int(nic['numa']))
+
+ def dump_profile(self):
+ """
+ Print Server Profile
+ """
+ print("The number of vCPUs: %s" %self.vcpus)
+ print("Number of NUMA nodes on this server: %s" %self.numas)
+ print("vCPUs available for the application in each NUMA: %s" %self.numa_vcpu_map)
+ print("SRIOV Support? %s" %self.sriov_support)
+ print("The Zone this server belongs to: %s" %self.zone)
+ print("vCPUs Isolated: %s" %self.cpu_isolation)
+ print("Numa to which SRIOV Nics belogs to: %s" %str(self.sriov_numas))
+
+class Deployment():
+ """
+ Model deployment
+ """
+ def __init__(self, rack_count, hw_profile):
+ self.server_list = []
+ self.total_servers = 0
+ self.hw_profile = hw_profile
+ self.rack_count = rack_count
+ self.server_zones = {}
+
+ def create_deployment(self, vnf_profiles):
+ """
+ Understand zones.
+ """
+ zones = []
+ for vnf in vnf_profiles:
+ if vnf['availability_zone'] not in zones:
+ zones.append(vnf['availability_zone'])
+ # print(zones)
+ for zone in zones:
+ for vnf in vnf_profiles:
+ if zone == vnf['availability_zone']:
+ for count in range(int(vnf['num_of_vnfs'])):
+ self.deploy(vnf, count)
+ self.server_zones[zone] = copy.deepcopy(self.server_list)
+ self.total_servers += len(self.server_list)
+ self.server_list.clear()
+
+ def deploy(self, vnf, suffix):
+ """
+ Understand deployment
+ """
+ # pylint: disable=too-many-branches
+
+ deploy = False
+ # If no servers, just do the deployment there and apped it.
+ if len(self.server_list) == 0:
+ server = Server(self.hw_profile)
+ for cnt in range(len(server.available_cpu_map)):
+ if int(server.available_cpu_map[cnt]) >= int(vnf['vcpus']):
+ if not ((vnf['sriov_support'] == 'yes' and cnt not in server.sriov_numas) or\
+ (vnf['sriov_support'] == 'no' and cnt not in server.nonsriov_numas)):
+ server.available_cpu_map[cnt] = str(
+ int(server.available_cpu_map[cnt]) - int(vnf['vcpus']))
+ deploy = True
+ server.hosted_vnfs.append({'vnf':vnf['profile_name'] +\
+ str(suffix), 'numa': cnt})
+ self.server_list.append(server)
+ return
+ if not deploy:
+ print("The existing hardware profile is not Suitable")
+ sys.exit()
+ # Servers already exist. Check if any eserver can accommodate the vnf:
+ for server in self.server_list:
+ # Check if SRIOV support is required for VNF and server supports
+ # Check if cpus are available in any of the numas
+ for cnt in range(len(server.available_cpu_map)):
+ if int(server.available_cpu_map[cnt]) >= int(vnf['vcpus']):
+ if not ((vnf['sriov_support'] == 'yes' and cnt not in server.sriov_numas) or\
+ (vnf['sriov_support'] == 'no' and cnt not in server.nonsriov_numas)):
+ server.available_cpu_map[cnt] = str(int(server.available_cpu_map[cnt])
+ - int(vnf['vcpus']))
+ deploy = True
+ server.hosted_vnfs.append({'vnf':vnf['profile_name'] +\
+ str(suffix), 'numa': cnt})
+ return
+ # We need to create new server, do deployment there and append it the list
+ if not deploy:
+ server = Server(self.hw_profile)
+ for cnt in range(len(server.available_cpu_map)):
+ if int(server.available_cpu_map[cnt]) >= int(vnf['vcpus']):
+ if not ((vnf['sriov_support'] == 'yes' and cnt not in server.sriov_numas) or\
+ (vnf['sriov_support'] == 'no' and cnt not in server.nonsriov_numas)):
+ server.available_cpu_map[cnt] = str(
+ int(server.available_cpu_map[cnt]) - int(vnf['vcpus']))
+ deploy = True
+ server.hosted_vnfs.append({'vnf':vnf['profile_name'] +\
+ str(suffix), 'numa': cnt})
+ self.server_list.append(server)
+ return
+ if not deploy:
+ print("The existing hardware profile is not Suitable")
+ sys.exit()
+
+ def display_deployment(self):
+ """
+ Print Deployment Report
+ """
+ print("Number of servers used %d" % self.total_servers)
+ print("------------------------------------------------")
+ count = 0
+ for zone, server_list in self.server_zones.items():
+ print("SERVERS IN AVAILABILITY ZONE: %s" %(zone))
+ print("------------------------------------------------")
+ for server in server_list:
+ print("Server ID: " + str(count))
+ for vnf in server.hosted_vnfs:
+ print("VNF: " + vnf['vnf'] + " NUMA: " + str(vnf['numa']))
+ count = count + 1
+ print("------------------------------------------------")
+
+ def get_deployment(self):
+ """
+ Returns servers and zones
+ """
+ return self.total_servers, self.server_zones
+
+
+# pylint: disable=W0223
+
+class Estimate(tornado.web.RequestHandler):
+ """
+ Resource estimator
+ """
+ # def set_default_headers(self):
+ # self.set_header('Content-Type', 'application/json')
+
+ def post(self):
+ """
+ Server Resource Modelling Report
+ """
+ model = {}
+ config = self.get_argument('config', None)
+ data = json.loads(config)
+
+ vnf_profiles = (data['vnf_profiles'])
+ hw_profile = (data['hardware_profile'])
+ model['vnf_profiles'] = vnf_profiles
+ print("--------- Resource Modelling Report ------------")
+ print("------------------------------------------------")
+ print("The VNFs:")
+ for profile in vnf_profiles:
+ print(profile['profile_name'])
+ print("------------------------------------------------")
+ print("The Compute-Server Profile:")
+ server = Server(hw_profile)
+ server.dump_profile()
+ model['server'] = hw_profile
+ print("------------------------------------------------")
+ deployment = Deployment(2, hw_profile)
+ deployment.create_deployment(vnf_profiles)
+ deployment.display_deployment()
+ count, placement = deployment.get_deployment()
+ model['deployment_count'] = count
+ model['deployment'] = placement
+ loader = jinja2.FileSystemLoader(searchpath="template/")
+ jenv = jinja2.Environment(loader=loader)
+ template = jenv.get_template('report.html')
+ htmlout = template.render(model=model)
+
+ self.finish(htmlout)
+
+
+class HomeHandler(tornado.web.RequestHandler):
+ """
+ Handler for '/' endpoint
+ """
+ def get(self):
+ """
+ Server Home Page
+ """
+ self.render('/website/index.html')
+
+
+
+def server_main_block():
+ """
+ Main Function
+ """
+
+ app = Application([('/validate', Estimate),
+ ('/', HomeHandler),
+ ('/(.*)', tornado.web.StaticFileHandler, {'path' : '/website'})])
+
+ # Cli Config
+ tornado.options.define("port", default=80, help="run on the given port", type=int)
+ tornado.options.parse_command_line()
+
+
+ # Server Config
+ http_server = tornado.httpserver.HTTPServer(app)
+ http_server.listen(tornado.options.options.port)
+
+ est_file = "/tmp/estimate.txt"
+ if os.path.exists(est_file):
+ os.remove(est_file)
+
+ # Logging
+ logging.basicConfig(
+ level=logging.DEBUG,
+ format='%(message)s',
+ filename=est_file,
+ filemode='a'
+ )
+
+ stdout_logger = logging.getLogger('STDOUT')
+ sys.stdout = StreamToLogger(stdout_logger, logging.INFO)
+
+ stderr_logger = logging.getLogger('STDERR')
+ sys.stderr = StreamToLogger(stderr_logger, logging.ERROR)
+
+ tornado.log.enable_pretty_logging()
+
+ # Tornado's event loop handles it from here
+ print("# Servering.... \n [Ctrl + C] to quit")
+
+ try:
+ tornado.ioloop.IOLoop.instance().start()
+ except KeyboardInterrupt:
+ tornado.ioloop.IOLoop.instance().stop()
+
+ # start
+ IOLoop.instance().start()
+
+
+if __name__ == "__main__":
+ server_main_block()
diff --git a/sdv/docker/sdvmodel/resource-estimation/template/report.html b/sdv/docker/sdvmodel/resource-estimation/template/report.html
new file mode 100644
index 0000000..b53ea9f
--- /dev/null
+++ b/sdv/docker/sdvmodel/resource-estimation/template/report.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Resource Modelling Report</title>
+
+ <meta charset="UTF-8">
+ <meta content="width=device-width, initial-scale=1" name="viewport">
+
+ <link rel="stylesheet" type="text/css" href="style/report.css">
+ <link rel="stylesheet" type="text/css" href="style/index.css">
+ <link href="https://fonts.googleapis.com/css2?family=Ubuntu&display=swap" rel="stylesheet">
+</head>
+
+<body>
+ <div class="report">
+
+ <h1>Resource Modelling Report</h1>
+ <br>
+
+ <h3>The VNFs Considered for Modelling:</h3>
+
+ <div class="holder">
+ {% for profile in model['vnf_profiles'] %}
+ <div class="vnf">
+ {{ profile['profile_name'] }}
+ <img src="/assets/vnf.svg">
+ </div>
+ {% endfor %}
+ </div>
+ <hr>
+
+ <h3>The Compute-Node Server Profile:</h3>
+
+ The number of vCPUs: {{ model['server']['vcpus'] }}
+ <br>Number of NUMA nodes on this server: {{ model['server']['numas']}}
+ <br>vCPUs available for the application in each NUMA:
+ <br>SRIOV Support?: {{model['sriov_support']}}
+ <br>vCPUs Isolated: {{ model['server']['cpu_isol_set'] }}
+ <br>Number of Servers Used: {{ model['deployment_count'] }}
+ <br>
+
+ <hr>
+
+ {% for zone, server_list in model['deployment'].items() %}
+ <h3>Servers in Availability zone: {{ zone }}</h3>
+
+ {% for server in server_list %}
+ <div class="tab">Server ID: {{ loop.index }}</div>
+ <div class="holder server">
+ {% for vnf in server.hosted_vnfs %}
+ <div class="vnf">
+ {{ vnf['vnf'] }} (numa:{{ vnf['numa'] }})
+ <img src="/assets/vnf.svg">
+ </div>
+ {% endfor %}
+ </div>
+ <br>
+ {% endfor %}
+
+ <hr>
+ {% endfor %}
+
+ </div>
+
+<br>
+<button onclick="window.location.href='/'">Go to Home</button>
+
+
+
+
+
+
+</body>
+</html>
+
diff --git a/sdv/docker/sdvmodel/website/actions.js b/sdv/docker/sdvmodel/website/actions.js
new file mode 100644
index 0000000..aeb0e91
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/actions.js
@@ -0,0 +1,39 @@
+/* Copyright 2020 University Of Delhi.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+// expand-arrow button
+function toggleClass(element, classname){
+ element.classList.toggle(classname)
+}
+
+// Add button
+function duplicate(button){
+ if (button.previousElementSibling.hasAttribute('name') &&
+ button.previousElementSibling.getAttribute('name') != null)
+ {
+ newdiv = button.previousElementSibling.cloneNode(true);
+ if (!newdiv.lastElementChild.classList.contains('del-button')){
+ del ='<div class="del-button" onclick="remove(this)"></div>'
+ newdiv.innerHTML += del;
+ }
+ button.parentNode.insertBefore(newdiv, button)
+ }
+}
+
+// Delete Button
+function remove(button){
+ button.parentNode.parentNode.removeChild(button.parentNode);
+} \ No newline at end of file
diff --git a/sdv/docker/sdvmodel/website/assets/plus-circle-solid.svg b/sdv/docker/sdvmodel/website/assets/plus-circle-solid.svg
new file mode 100644
index 0000000..39a0f8e
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/assets/plus-circle-solid.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:version="1.0 (6e3e5246a0, 2020-05-07)"
+ sodipodi:docname="plus-circle-solid.svg"
+ id="svg4"
+ version="1.1"
+ viewBox="0 0 512 512"
+ role="img"
+ class="svg-inline--fa fa-plus-circle fa-w-16"
+ data-icon="plus-circle"
+ data-prefix="fas"
+ focusable="false"
+ aria-hidden="true">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ inkscape:current-layer="svg4"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:cy="256"
+ inkscape:cx="114.5679"
+ inkscape:zoom="1.265625"
+ showgrid="false"
+ id="namedview6"
+ inkscape:window-height="794"
+ inkscape:window-width="1600"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0"
+ guidetolerance="10"
+ gridtolerance="10"
+ objecttolerance="10"
+ borderopacity="1"
+ bordercolor="#666666"
+ pagecolor="#ffffff" />
+ <path
+ style="fill:#61b9ff;fill-opacity:1"
+ id="path2"
+ d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"
+ fill="currentColor" />
+</svg>
diff --git a/sdv/docker/sdvmodel/website/assets/server.svg b/sdv/docker/sdvmodel/website/assets/server.svg
new file mode 100644
index 0000000..547cdaf
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/assets/server.svg
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="36.512501mm"
+ width="65.167557mm"
+ inkscape:version="1.0 (1.0+r73+1)"
+ sodipodi:docname="server.svg"
+ id="svg4"
+ version="1.1"
+ viewBox="0 0 246.30241 137.99999"
+ role="img"
+ class="svg-inline--fa fa-server fa-w-16"
+ data-icon="server"
+ data-prefix="fas"
+ focusable="false"
+ aria-hidden="true">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ units="mm"
+ fit-margin-bottom="0"
+ fit-margin-right="0"
+ fit-margin-left="0"
+ fit-margin-top="0"
+ inkscape:current-layer="svg4"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:cy="80.582597"
+ inkscape:cx="196.50384"
+ inkscape:zoom="1.3340661"
+ showgrid="false"
+ id="namedview6"
+ inkscape:window-height="658"
+ inkscape:window-width="1366"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0"
+ guidetolerance="10"
+ gridtolerance="10"
+ objecttolerance="10"
+ borderopacity="1"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ inkscape:document-rotation="0" />
+ <path
+ d="m 9.563242,4 h 7.490814 c 0.295503,0 0.635382,0.327 0.635382,18 v 92 c 0,17.673 -0.339879,18 -0.635382,18 H 9.563242 C 9.267739,132 8.927861,131.673 8.927861,114 V 22 c 0,-17.673 0.339878,-18 0.635381,-18 z"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ id="path2428"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ sodipodi:nodetypes="sssssssss"
+ id="path2428-3"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ d="m 29.563242,4 h 7.490814 c 0.295503,0 0.635382,0.327 0.635382,18 v 92 c 0,17.673 -0.339879,18 -0.635382,18 h -7.490814 c -0.295502,0 -0.635381,-0.327 -0.635381,-18 V 22 c 0,-17.673 0.339879,-18 0.635381,-18 z" />
+ <path
+ sodipodi:nodetypes="sssssssss"
+ id="path2428-5"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ d="m 49.563242,4 h 7.490814 c 0.295503,0 0.635382,0.327 0.635382,18 v 92 c 0,17.673 -0.339879,18 -0.635382,18 h -7.490814 c -0.295503,0 -0.635381,-0.327 -0.635381,-18 V 22 c 0,-17.673 0.339878,-18 0.635381,-18 z" />
+ <path
+ d="m 69.563242,4 h 7.490814 c 0.295503,0 0.635382,0.327 0.635382,18 v 92 c 0,17.673 -0.339879,18 -0.635382,18 h -7.490814 c -0.295502,0 -0.635381,-0.327 -0.635381,-18 V 22 c 0,-17.673 0.339879,-18 0.635381,-18 z"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ id="path2428-3-6"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ sodipodi:nodetypes="sssssssss"
+ id="path2428-2"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ d="m 89.563242,4 h 7.49081 c 0.29551,0 0.63539,0.327 0.63539,18 v 92 c 0,17.673 -0.33988,18 -0.63539,18 h -7.49081 c -0.2955,0 -0.63538,-0.327 -0.63538,-18 V 22 c 0,-17.673 0.33988,-18 0.63538,-18 z" />
+ <path
+ d="m 109.56324,4 h 7.49081 c 0.29551,0 0.63539,0.327 0.63539,18 v 92 c 0,17.673 -0.33988,18 -0.63539,18 h -7.49081 c -0.2955,0 -0.63538,-0.327 -0.63538,-18 V 22 c 0,-17.673 0.33988,-18 0.63538,-18 z"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ id="path2428-3-9"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ sodipodi:nodetypes="sssssssss"
+ id="path2428-6"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ d="m 129.56324,4 h 7.49081 c 0.2955,0 0.63538,0.327 0.63538,18 v 92 c 0,17.673 -0.33988,18 -0.63538,18 h -7.49081 c -0.2955,0 -0.63538,-0.327 -0.63538,-18 V 22 c 0,-17.673 0.33988,-18 0.63538,-18 z" />
+ <path
+ d="m 149.56324,4 h 7.49081 c 0.2955,0 0.63538,0.327 0.63538,18 v 92 c 0,17.673 -0.33988,18 -0.63538,18 h -7.49081 c -0.2955,0 -0.63539,-0.327 -0.63539,-18 V 22 c 0,-17.673 0.33988,-18 0.63539,-18 z"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ id="path2428-3-0"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ d="m 169.56324,4 h 7.49081 c 0.2955,0 0.63538,0.327 0.63538,18 v 92 c 0,17.673 -0.33988,18 -0.63538,18 h -7.49081 c -0.29551,0 -0.63539,-0.327 -0.63539,-18 V 22 c 0,-17.673 0.33988,-18 0.63539,-18 z"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ id="path2428-5-6"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ sodipodi:nodetypes="sssssssss"
+ id="path2428-3-6-2"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ d="m 189.56324,4 h 7.49081 c 0.2955,0 0.63538,0.327 0.63538,18 v 92 c 0,17.673 -0.33988,18 -0.63538,18 h -7.49081 c -0.29551,0 -0.63539,-0.327 -0.63539,-18 V 22 c 0,-17.673 0.33988,-18 0.63539,-18 z" />
+ <path
+ d="m 209.56324,4 h 7.49081 c 0.29551,0 0.63539,0.327 0.63539,18 v 92 c 0,17.673 -0.33988,18 -0.63539,18 h -7.49081 c -0.2955,0 -0.63538,-0.327 -0.63538,-18 V 22 c 0,-17.673 0.33988,-18 0.63538,-18 z"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ id="path2428-2-6"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ sodipodi:nodetypes="sssssssss"
+ id="path2428-3-9-1"
+ style="opacity:0.13180452;fill:#787878;fill-opacity:1;stroke-width:0.135569"
+ d="m 229.56323,4 h 7.49081 c 0.29551,0 0.63539,0.327 0.63539,18 v 92 c 0,17.673 -0.33988,18 -0.63539,18 h -7.49081 c -0.2955,0 -0.63538,-0.327 -0.63538,-18 V 22 c 0,-17.673 0.33988,-18 0.63538,-18 z" />
+</svg>
diff --git a/sdv/docker/sdvmodel/website/assets/trash-alt-regular.svg b/sdv/docker/sdvmodel/website/assets/trash-alt-regular.svg
new file mode 100644
index 0000000..fbce77b
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/assets/trash-alt-regular.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:version="1.0 (6e3e5246a0, 2020-05-07)"
+ sodipodi:docname="trash-alt-regular.svg"
+ id="svg4"
+ version="1.1"
+ viewBox="0 0 448 512"
+ role="img"
+ class="svg-inline--fa fa-trash-alt fa-w-14"
+ data-icon="trash-alt"
+ data-prefix="far"
+ focusable="false"
+ aria-hidden="true">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ inkscape:current-layer="svg4"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:cy="192.79012"
+ inkscape:cx="224"
+ inkscape:zoom="1.265625"
+ showgrid="false"
+ id="namedview6"
+ inkscape:window-height="794"
+ inkscape:window-width="1600"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0"
+ guidetolerance="10"
+ gridtolerance="10"
+ objecttolerance="10"
+ borderopacity="1"
+ bordercolor="#666666"
+ pagecolor="#ffffff" />
+ <path
+ style="fill:#ff6161;fill-opacity:1"
+ id="path2"
+ d="M268 416h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12zM432 80h-82.41l-34-56.7A48 48 0 0 0 274.41 0H173.59a48 48 0 0 0-41.16 23.3L98.41 80H16A16 16 0 0 0 0 96v16a16 16 0 0 0 16 16h16v336a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128h16a16 16 0 0 0 16-16V96a16 16 0 0 0-16-16zM171.84 50.91A6 6 0 0 1 177 48h94a6 6 0 0 1 5.15 2.91L293.61 80H154.39zM368 464H80V128h288zm-212-48h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12z"
+ fill="currentColor" />
+</svg>
diff --git a/sdv/docker/sdvmodel/website/assets/vnf.svg b/sdv/docker/sdvmodel/website/assets/vnf.svg
new file mode 100644
index 0000000..7bd67e4
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/assets/vnf.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="113.15604"
+ width="140.09048"
+ inkscape:version="1.0 (b51213c273, 2020-08-10)"
+ sodipodi:docname="vnf.svg"
+ id="svg4"
+ version="1.1"
+ viewBox="0 0 140.09048 113.15604"
+ role="img"
+ class="svg-inline--fa fa-server fa-w-16"
+ data-icon="server"
+ data-prefix="fas"
+ focusable="false"
+ aria-hidden="true">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ fit-margin-bottom="0"
+ fit-margin-right="0"
+ fit-margin-left="0"
+ fit-margin-top="0"
+ inkscape:current-layer="svg4"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:cy="165.58202"
+ inkscape:cx="181.58465"
+ inkscape:zoom="1.7552979"
+ showgrid="false"
+ id="namedview6"
+ inkscape:window-height="794"
+ inkscape:window-width="1600"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0"
+ guidetolerance="10"
+ gridtolerance="10"
+ objecttolerance="10"
+ borderopacity="1"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ inkscape:document-rotation="0" />
+ <rect
+ style="opacity:1;fill:none;stroke:none"
+ id="rect887"
+ width="140.09048"
+ height="113.15604"
+ x="0"
+ y="0" />
+ <ellipse
+ ry="22.535322"
+ rx="24.521544"
+ cy="56.892029"
+ cx="43.126831"
+ id="path832-6-7"
+ style="opacity:1;fill:#3dbbf5;stroke-width:1.19657;fill-opacity:1" />
+ <ellipse
+ style="opacity:1;fill:#3dbbf5;stroke-width:1.19657;fill-opacity:1"
+ id="path832-6-7-5"
+ cx="97.109772"
+ cy="56.811798"
+ rx="24.521544"
+ ry="22.535322" />
+</svg>
diff --git a/sdv/docker/sdvmodel/website/controller.js b/sdv/docker/sdvmodel/website/controller.js
new file mode 100644
index 0000000..5b71352
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/controller.js
@@ -0,0 +1,34 @@
+/* Copyright 2020 University Of Delhi.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+function getModel(){
+
+ config = {}
+
+ // Get current values from form
+ for(category of document.getElementsByClassName('resmodData'))
+ config = mergeDeep(config, objectifyDiv(category));
+
+ requestModel(config);
+}
+
+function requestModel(config){
+
+ form = document.getElementById('validate');
+ form.elements['config'].value = JSON.stringify(config);
+ form.submit();
+}
+
+
diff --git a/sdv/docker/sdvmodel/website/index.html b/sdv/docker/sdvmodel/website/index.html
new file mode 100644
index 0000000..b08481a
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/index.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Resource Modelling</title>
+
+ <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+ <meta content="utf-8" http-equiv="encoding">
+
+ <link rel="stylesheet" href="style/index.css">
+ <link rel="stylesheet" href="style/array.css">
+
+ <script src="mergeDeep.js"></script>
+ <script src="readFromHTML.js"></script>
+ <script src="actions.js"></script>
+ <script src="controller.js"></script>
+
+
+
+ <link href="https://fonts.googleapis.com/css2?family=Ubuntu&display=swap" rel="stylesheet">
+</head>
+
+
+
+<body>
+
+<div id="site"><form>
+
+
+ <fieldset class='resmodData'>
+ <legend class="collapse-arrow" onclick="toggleClass(this,'expand-arrow')">
+ VNFs
+ </legend>
+ <div>
+
+ <label>VNFs:</label><br>
+ <div class="arr" name="vnf_profiles">
+
+ <label>VNF Name:</label>
+ <input type="text" name="profile_name" value="userplane_app"><br>
+ <label>VCPUs:</label>
+ <input type="text" name="vcpus" value="36"><br>
+ <label>NUMAs:</label>
+ <input type="text" name="numas" value="1"><br>
+ <label>CPUs in NUMA0:</label>
+ <input type="text" name="cpus_in_numa0" value="36"><br>
+ <label>CPUs in NUMA1:</label>
+ <input type="text" name="cpus_in_numa1" value="0"><br>
+ <label>RAM Size</label>
+ <input type="text" name="ram_size" value="64"><br>
+ <label>Interface Count</label>
+ <input type="text" name="interfaces" value="6"><br>
+ <label>SRIOV Support</label>
+ <input type="text" name="sriov_support" value="yes"><br>
+ <label>VIRTIO Support</label>
+ <input type="text" name="virtio_support" value="yes"><br>
+ <label>Availability Zone</label>
+ <input type="text" name="availability_zone" value="dataplane_zone"><br>
+ <label>CPU Policy</label>
+ <input type="text" name="cpu_policy" value="sw==decicated"><br>
+ <label>CPU Pinned</label>
+ <input type="text" name="cpu_pinned" value="yes"><br>
+ <label>Number of VNFs</label>
+ <input type="text" name="num_of_vnfs" value="9"><br>
+
+ </div><div class="add-button" onclick="duplicate(this)"></div>
+
+ </div>
+ </fieldset>
+
+
+ <fieldset class='resmodData'>
+ <legend class="collapse-arrow" onclick="toggleClass(this,'expand-arrow')">
+ Compute Hardware
+ </legend>
+ <div>
+ <label>Compute Node Hardware Info</label><br>
+ <div name="hardware_profile">
+ <label> Total CPUs:</label>
+ <input type="text" name="vcpus" value="80"><br>
+
+ <label> NUMAs:</label>
+ <input type="text" name="numas" value="2"><br>
+
+ <label> #of Numa0 CPUS for VNFs:</label>
+ <input type="text" name="numa0_cpus_4vnfs" value="36"><br>
+
+ <label> #of Numa1 CPUS for VNFs:</label>
+ <input type="text" name="numa1_cpus_4vnfs" value="36"><br>
+
+ <label>RAM Size:</label>
+ <input type="text" name="ram_size" value="384 "><br>
+ <label>CPU Isolation Set</label>
+ <input type="text" name="cpu_isol_set" value="0-44"><br>
+
+ <label>NICs:</label><br>
+ <div class="arr" name="nics">
+ <div>
+ <label>NIC Name:</label>
+ <input type="text" name="name" value="ens785f0"><br>
+ <label>NIC Type:</label>
+ <input type="text" name="type" value="sriov">
+ <label>NIC Speed:</label>
+ <input type="text" name="speed" value="25"><br>
+ <label>NIC NUMA:</label>
+ <input type="text" name="numa" value="0"><br>
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ </fieldset>
+
+</form>
+
+
+<form id="validate" action="/validate" method="post">
+ <input type="hidden" name="config">
+</form>
+<button id="save-changes" type="button" onclick="getModel()">Show Modelling</button>
+
+
+</div>
+</body>
+</html>
diff --git a/sdv/docker/sdvmodel/website/mergeDeep.js b/sdv/docker/sdvmodel/website/mergeDeep.js
new file mode 100644
index 0000000..970983a
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/mergeDeep.js
@@ -0,0 +1,46 @@
+/* Copyright 2020 University Of Delhi.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+/**
+* Performs a deep merge of objects and returns new object. Does not modify
+* objects (immutable) and merges arrays via concatenation.
+*
+* @param {...object} objects - Objects to merge
+* @returns {object} New object with merged key/values
+*/
+function mergeDeep(...objects) {
+ const isObject = obj => obj && typeof obj === 'object';
+
+ return objects.reduce((prev, obj) => {
+ Object.keys(obj).forEach(key => {
+ const pVal = prev[key];
+ const oVal = obj[key];
+
+ if (Array.isArray(pVal) && Array.isArray(oVal)) {
+ prev[key] = pVal.concat(...oVal);
+ }
+ else if (isObject(pVal) && isObject(oVal)) {
+ prev[key] = mergeDeep(pVal, oVal);
+ }
+ else {
+ prev[key] = oVal;
+ }
+ });
+
+ return prev;
+ }, {});
+}
+
diff --git a/sdv/docker/sdvmodel/website/readFromHTML.js b/sdv/docker/sdvmodel/website/readFromHTML.js
new file mode 100644
index 0000000..f14e089
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/readFromHTML.js
@@ -0,0 +1,72 @@
+/* Copyright 2020 University Of Delhi.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+/**
+* Reads HTML contents into javascript object
+*
+*
+* @param {element} element to read, can be input or div element
+* @returns {object} New object with values read
+*/
+function objectifyDiv(element){
+ var obj = {};
+ var el = element.childNodes;
+ for(var i in el){
+
+ if(el[i] instanceof HTMLInputElement && el[i].hasAttribute('name')) {
+
+ if(el[i].type == 'text')
+ obj = mergeDeep(obj, objectify(el[i].name, el[i].value));
+
+ }
+ if(el[i] instanceof HTMLSelectElement && el[i].hasAttribute('name')){
+ obj = mergeDeep(obj, objectify(el[i].name, el[i].value));
+ }
+ if(el[i] instanceof HTMLDivElement){
+
+ if(el[i].classList.contains('arr')){
+ var key = el[i].getAttribute('name');
+ var value = objectifyDiv(el[i]);
+ if(obj[key] == undefined)
+ obj[key] =[];
+ obj[key].push(value[key]);
+ }
+ else
+ obj = mergeDeep(obj, objectifyDiv(el[i]));
+
+ }
+ }
+
+ if(element.hasAttribute('name')){
+ var newobj = {};
+ newobj[element.getAttribute('name')] = obj;
+ return newobj;
+ }
+ return obj;
+}
+
+
+
+function objectify(key, value){
+ var obj = {};
+ var keys = key.split('.');
+ for(var i = keys.length-1; i >= 0; i--){
+ obj[keys[i]] = value;
+ value = obj;
+ obj = {};
+ }
+ return value;
+}
diff --git a/sdv/docker/sdvmodel/website/style/array.css b/sdv/docker/sdvmodel/website/style/array.css
new file mode 100644
index 0000000..45a53fc
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/style/array.css
@@ -0,0 +1,55 @@
+
+@keyframes popup {
+ 0%{
+ transform: scale(0.5);
+ }
+ 90%{
+ transform: scale(1.1);
+ }
+ 100%{
+ transform: scale(1.0);
+ }
+}
+
+.arr{
+ border-radius: 6px;
+ border-style: dashed;
+ border-color: #c9c9c9;
+ border-width: 2px;
+ display: inline-block;
+ padding-right: 3em;
+ margin-right: 15px;
+ margin-bottom: 5px;
+ position: relative;
+ animation: popup 0.2s ease;
+}
+
+
+.add-button{
+ background-image: url("../assets/plus-circle-solid.svg");
+ opacity: 0.7;
+ width: 2em;
+ height: 2em;
+ display: inline-block;
+ left: 0;
+}
+.add-button:hover{
+ opacity: 1
+}
+
+
+
+.del-button{
+ background-image: url("../assets/trash-alt-regular.svg");
+ background-repeat: no-repeat;
+ opacity: 0.7;
+ width: 2em;
+ height: 2em;
+ position: absolute;
+ right: 0.5em;
+ bottom: 0.5em;
+}
+.del-button:hover{
+ opacity: 1
+}
+
diff --git a/sdv/docker/sdvmodel/website/style/index.css b/sdv/docker/sdvmodel/website/style/index.css
new file mode 100644
index 0000000..882c31a
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/style/index.css
@@ -0,0 +1,198 @@
+
+html,body
+{
+ padding: 0px;
+ margin: 0px;
+ font-family: 'Ubuntu', sans-serif;
+ color: #333333;
+ background-color: white;
+ scroll-behavior: smooth;
+}
+
+
+#site{
+ margin: 8%;
+ margin-top: 0px;
+ padding-bottom: 90px;
+}
+
+.add-new{
+ border: solid #c9c9c9;
+ border-width: 1px;
+ color: #f5f5f5;
+ opacity: 0.8;
+ font-size: 1.1em;
+ padding: 15px;
+ padding-top: 3px;
+ padding-bottom: 3px;
+ margin: 30px;
+ cursor: pointer;
+ display: inline-block;
+ text-align: center;
+ vertical-align: middle;
+ background-color: #1fad4e;
+}
+.add-new:hover{
+ opacity: 1;
+ text-shadow: #f5f5f5 0px 0px 1px;
+}
+
+.add-new img{
+ width: 1em;
+ height: 1em;
+ margin-left: 5px;
+ vertical-align: middle;
+ filter: brightness(0) invert(1);
+ box-shadow: white 0px 0px 1px;
+}
+
+fieldset {
+ border-radius: 6px;
+ border-color: #c9c9c9;
+ border-width: 1px;
+ margin-top: 45px;
+ margin-bottom: 45px;
+ background-color: #f5f5f5;
+}
+
+
+
+fieldset legend{
+ font-weight: bold;
+ padding: 1em;
+ text-shadow: #bbb 0px 0px 2px;
+}
+
+.collapse-arrow::after{
+ content: "â–²";
+ margin: 1em;
+ color: #61b9ff;
+ text-shadow: #61b9ff 0px 0px 4px;
+ cursor: pointer;
+ font-size: 1.2em;
+}
+
+.expand-arrow::after {
+ content: "â–¼";
+}
+
+@keyframes expand {
+ 0%{
+ transform: scale(0.5);
+ }
+ 90%{
+ transform: scale(1.1);
+ }
+ 100%{
+ transform: scale(1.0);
+ }
+}
+
+/* when expand-arrow hide all siblings */
+.expand-arrow ~ *{
+ display:none;
+}
+
+
+
+
+fieldset label{
+ padding: 1em;
+ padding-left: 2em;
+ text-shadow: #f0f0f0 0px 0px 2px;
+ width: 230px;
+ display: inline-block;
+}
+
+
+fieldset input{
+ border: solid #c9c9c9;
+ border-radius: 6px;
+ border-width: 1px;
+ padding: 5px;
+ padding-left: 15px;
+ color: #333333;
+ width: 150px;
+}
+
+fieldset input:hover{
+ background-color: #e8e8e8;
+}
+
+button{
+ border: solid #c9c9c9;
+ border-width: 1px;
+ height: 45px;
+ width: 170px;
+ color: #f5f5f5;
+ opacity: 0.8;
+ font-size: 1.1em;
+ margin: 30px;
+ cursor: pointer;
+}
+button:hover{
+ opacity: 1;
+ text-shadow: #f5f5f5 0px 0px 1px;
+}
+
+#save-changes{
+ background-color: #50affa;
+ float: right;
+}
+
+#save-changes::after{
+ content: "";
+ clear: both;
+ display: inline;
+}
+
+#delete{
+ background-color: #fa3c3c;
+}
+
+#reload{
+ background-color: #1fad4e;
+}
+
+button img{
+ width: 1em;
+ height: 1em;
+ margin-right: 10px;
+ margin-left: 10px;
+ filter: brightness(0) invert(1);
+}
+
+
+
+
+#save-changes.changed{
+ background-color: #deae00;
+
+}
+
+
+select{
+ background-color: white;
+ appearance: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ border: solid #c9c9c9;
+ border-radius: 6px;
+ border-width: 1px;
+ padding: 3px;
+ padding-left: 15px;
+ color: #333333;
+ min-width: 150px;
+ cursor: pointer;
+}
+
+select:hover{
+ background-color: #e8e8e8;
+}
+
+
+.select::after{
+ content: "â–¼";
+ color: transparent;
+ text-shadow: #61b9ff -1.5em 0px 0px;
+}
diff --git a/sdv/docker/sdvmodel/website/style/report.css b/sdv/docker/sdvmodel/website/style/report.css
new file mode 100644
index 0000000..bc259fb
--- /dev/null
+++ b/sdv/docker/sdvmodel/website/style/report.css
@@ -0,0 +1,90 @@
+
+
+.report{
+ text-align: left;
+ margin: 8%;
+ margin-top: 3%;
+ padding: 50px;
+
+ background-color: #f5f5f5;
+ border-radius: 6px;
+ border-color: #c9c9c9;
+ border-width: 1px;
+ border-style: solid;
+ text-shadow: #CCC 0px 0px 2px;
+ word-spacing: 0.1em;
+ line-height: 1.5em;
+}
+
+hr{
+ width: 60%;
+}
+
+
+button{
+ background-color: #50affa;
+ float: right;
+}
+
+
+.holder{
+ display: flex;
+ flex-wrap: wrap;
+ width: 98%;
+}
+
+
+.tab{
+ background-color: #f0f0f0;
+ border-radius: 8px;
+ border-bottom-right-radius: 0px;
+ border-bottom-left-radius: 0px;
+ border-color: #757474;
+ border-width: 2px;
+ border-style: solid;
+ display: inline-block;
+ padding: 3px;
+ padding-left: 6px;
+ padding-right: 10px;
+}
+
+.server{
+ background-image: url("/assets/server.svg");
+ background-repeat: repeat;
+ background-size: auto 100%;
+
+ background-color: #e3e3e3;
+ border-color: #757474;
+ border-width: 8px;
+ border-style: double;
+}
+
+
+
+.vnf{
+ min-width: 80px;
+ margin: 10px;
+
+ font-size: 0.9em;
+ padding: 5px;
+
+
+ border-radius: 8px;
+ border-color: #3dbbf5;
+ border-width: 3px;
+ border-style: solid;
+
+ background-color: #e6f4fa;
+}
+
+.vnf::after{
+ clear: both;
+ content: '';
+ display: inline-block;
+}
+
+.vnf > img{
+ width: 35px;
+ margin-left: 10px;
+ float: right
+}
diff --git a/sdv/docker/sdvstate/core/__init__.py b/sdv/docker/sdvstate/core/__init__.py
index ed33752..47830c5 100644
--- a/sdv/docker/sdvstate/core/__init__.py
+++ b/sdv/docker/sdvstate/core/__init__.py
@@ -19,3 +19,4 @@ contains all program specific dependencies
"""
from .load_pdf import load_pdf
+from .display_report import display_report
diff --git a/sdv/docker/sdvstate/core/display_report.py b/sdv/docker/sdvstate/core/display_report.py
new file mode 100644
index 0000000..97ccb55
--- /dev/null
+++ b/sdv/docker/sdvstate/core/display_report.py
@@ -0,0 +1,57 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+"""Display Report
+"""
+
+import logging
+from datetime import datetime as dt
+
+
+
+def display_report(report):
+ """
+ Logs the final report
+ """
+ installer = report['installer']
+ result = report['criteria']
+ start_time = dt.strptime(report['start_date'], '%Y-%m-%d %H:%M:%S')
+ stop_time = dt.strptime(report['stop_date'], '%Y-%m-%d %H:%M:%S')
+ duration = (stop_time - start_time).total_seconds()
+
+ logger = logging.getLogger(__name__)
+ logger.info('')
+ logger.info('')
+ logger.info('========================================')
+ logger.info('')
+ logger.info(f' Installer: {installer}')
+ logger.info(f' Duration: {duration}')
+ logger.info(f' Result: {result}')
+ logger.info('')
+ logger.info('')
+ logger.info(f' CHECKS PASSED:')
+ logger.info(' =============')
+ for case_name in report['details']['pass']:
+ logger.info(f' {case_name}')
+ logger.info('')
+ logger.info('')
+ logger.info(f' CHECKS FAILED:')
+ logger.info(' =============')
+ for case_name in report['details']['fail']:
+ logger.info(f' {case_name}')
+ logger.info('')
+ logger.info('========================================')
+ logger.info('')
+ logger.info('')
diff --git a/sdv/docker/sdvstate/example/kubepod10 b/sdv/docker/sdvstate/example/kubepod10
deleted file mode 100644
index 2717fc6..0000000
--- a/sdv/docker/sdvstate/example/kubepod10
+++ /dev/null
@@ -1,20 +0,0 @@
----
-apiVersion: v1
-clusters:
-- cluster:
- server: https://10.10.100.21:6553
- insecure-skip-tls-verify: true
- name: kubernetes
-contexts:
-- context:
- cluster: kubernetes
- user: admin
- name: admin@kubernetes
-current-context: admin@kubernetes
-kind: Config
-preferences: {}
-users:
-- name: admin
- user:
- client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURZRENDQWtpZ0F3SUJBZ0lVQmN1akh5bmUzMFBnMUw5MnNJZERmWEtlVm5Vd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0tqRVRNQkVHQTFVRUNoTUtTM1ZpWlhKdVpYUmxjekVUTUJFR0ExVUVBeE1LYTNWaVpYSnVaWFJsY3pBZQpGdzB4T1RFd01UY3hOakUzTURCYUZ3MHlNREV3TVRZeE5qRTNNREJhTUNreEZ6QVZCZ05WQkFvVERuTjVjM1JsCmJUcHRZWE4wWlhKek1RNHdEQVlEVlFRREV3VmhaRzFwYmpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVAKQURDQ0FRb0NnZ0VCQUxRVnpUeG1UTUZHRkdiWks1OGwyUXZkT2hUZVZ2dzVKTWJyVE8wY2hhd1BtdmJXeXczSApMeUFpNTJsZkU5VGdONXBBVzVrVzJmS2tkREMwRnNXZXF2VDV4SFVvbVFGa3RRM2RWMEJnMXRXYVNIdnVHMXQwCndac2hIQWN6RTl0ZS93dFR6ajhkdFl0ZXdIbXpzd1J1bk9sRnFaUVZZT1hReENPYkEvZ2Z1V0o5RUFKNlduZDcKcUhZdEJvbzR0RkhVTmFocDRwUXNNS1VlbDZPUnA4NEM0WnNIenYyZm9Jb2pYd1V2TmJMNUE1VlZjallrK0taZwpCc3IyMWowT0c4N1F3Q0ZuOThMelJqUU92L01FTFRPOEoxemIrK3pvbkg0ZkpDckc1Q2RKNUFQbU81UnBEMGluCmJKNnFOR2QyY0kxaGdVWWx2aWI4QURXc21VelRkWU5wa0JrQ0F3RUFBYU4vTUgwd0RnWURWUjBQQVFIL0JBUUQKQWdXZ01CMEdBMVVkSlFRV01CUUdDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFNQmdOVkhSTUJBZjhFQWpBQQpNQjBHQTFVZERnUVdCQlRKSXRERnJwcGR3RExOTWFWY2IzQ1JiNVhBZURBZkJnTlZIU01FR0RBV2dCUjcwU1Z4Ck8wVlpzNXVRQkpaOEZ0cmluT25EaERBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQUFBRUQrQXNaaEFsWnRucTkKR0w5a1dvWDd5d0ZmR2FRdEgvSnFaT0VGYkx0bFdLVmlHc3gyVWlSRTN2U3l6VlFpMVBhNGR3cXF1MXc4bVNIVworc1REVlN1aGE5Q2NlbzcvT3F4dnl3ME43c0t2L0NPeml6YWF5djlXTmlBYXhFNjRMSk1sTWlrS2wrZG1zSlVMCktVUXJLVzhvcnlhZk4zSzZnd3NLS2FtU2Mzb1J4TG9wWHVveEo5a2lyVG5DOWpMVGdWSU1EM0I5aEtleEtLQ3YKb1hKVkUyMWViVnNiOExiSUcyaldRcWlnVktxWEFRN3gwcEt6RFcvN1dIc1JyRFRkbFpYU0ZUZS9IQUpZd2tuVwp1cmd2blJkZ1BYUHl6cHJhWU9iTCtTV3dvejRTS216OGV5TWpQcFd0TkFZQTdIYm5XT3RqU2NXNFJKWnpaQ1V3CldicStNZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
- client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBdEJYTlBHWk13VVlVWnRrcm55WFpDOTA2Rk41Vy9Ea2t4dXRNN1J5RnJBK2E5dGJMCkRjY3ZJQ0xuYVY4VDFPQTNta0JibVJiWjhxUjBNTFFXeFo2cTlQbkVkU2laQVdTMURkMVhRR0RXMVpwSWUrNGIKVzNUQm15RWNCek1UMjE3L0MxUE9QeDIxaTE3QWViT3pCRzZjNlVXcGxCVmc1ZERFSTVzRCtCKzVZbjBRQW5wYQpkM3VvZGkwR2lqaTBVZFExcUduaWxDd3dwUjZYbzVHbnpnTGhtd2ZPL1orZ2lpTmZCUzgxc3ZrRGxWVnlOaVQ0CnBtQUd5dmJXUFE0Ynp0REFJV2Yzd3ZOR05BNi84d1F0TTd3blhOdjc3T2ljZmg4a0tzYmtKMG5rQStZN2xHa1AKU0tkc25xbzBaM1p3aldHQlJpVytKdndBTmF5WlROTjFnMm1RR1FJREFRQUJBb0lCQUYxcnlmS0JaMlFFUk9VdAoyQkZSZ3cxQ2tMVHV1dFZSbDZDUnhIQmxFWHMzQlQ3MElwWmRORGRKcEI3bnNkUUhGUkV5UGRKbkpsMVhydWJ0Ckpic1RHc0RIS1lGVnREb2kwa0lGQnhSZ3FGSmJIU3NkVkpmWE0vQ1Q5b1JOblFsNmVIaVoyeTZtN04wR0pIZCsKSDJvM0w3TmI3aUxpREVoc1NyUGw0T05CSWR6VEFQYy91b3hQbVQxQ2ZiQ3hVU051d1EzOS9mWHJVNzJTOFU4ZAoybXd2dDZpczQ2c09IWkNkNG0xNGJENE11Y2VsUG83V2ptT0hRZlUzd0g1NTE5Q0FtV0hDRFA0ZndNY3dYWlJUClZWUHcyU1VZRW9lMS9DM083cVVqMlRTMldJdysveHZOQml6WFpqajZTdmd5ME1FREtzamhsbWM2OE81MVAvajgKcmh3dFp1RUNnWUVBeTE1c2NuRFVidWFob1dJNzlCVzAxdWlyY0V1Vnp2TXhmc3ptbEJhZnp3dDZPL0FNQ3l1NwpKS2ZNR1JFQmxXR1RGMUhiUlREbGZzK3lTNFpjKzRQUDlmZVNVNFI1NWJkczlZRU44K3liSjJvbzVPcFlGOVFkCmtoL2JQRUZkN3pTbVQ0R2l2V2lxNklqVlFrTGNOVWFlczN4WlZ2d2NqUXd5cENtTU1aRlJtN1VDZ1lFQTRyREsKSTZITUdDcTR4eWZuaUhhT0ZkNlVEYjdmS3ZJNTJZYnU5R0IyR0JXdmkrcEhOZ1V1dU44SG9GT0hQS2NuYnkweQoyS0FwRjVaYTFSZUNHNGdSTE8vMjMybU42VnVCMERGWlNnUEFITTJKd1BtOFUrYjlWZFZaZEI1ZWJrTDhxNXlkCmZqM3F3S2NRVTZMR09wVy83ZEhsMUVUWE9kMUYzTi8wNFdzcGlWVUNnWUJtb0UrNXNKYURJSCtRSVRLQUNqUW4KLzJJRVdTQlFQd2xMSTd0NEg3S2xtUFVtS2d6cDFqZXFWOEwzSTAzWlJGUW1BSGpXZ2NaT0tDR2hXenl3NytPUwpERTBiT0U4TFRYVCtyeEdMZG1zVmlNejZPQWdjZmo0dDcwV0RNcmxrYlAxQVFmc04ralBGQk1nWm1BUG9IcXNYCmlEak5YSXhMNFV2czY4cURlUUhsd1FLQmdGTGs3UFg4cTJKRzlReTJsZDc3NDFjeDdoZmNyVVRLRU1kdnBSK3QKeW1GaVJMQTRPbFFScnhVaFVXdWFQOEM1S3gxbmZNbGtQOEtGVTYvS2llUkJiRzV2VFdwQzhnYmNWR3JxTU1sMAo5NkpRc3NmalNxK3Zyd0hkSTNubnhRWXk3cXhlZCtUN0JVWHZrWFBUK1FMaFVhN0lhMitrd01OREc5SDUvMVVTCjE3eUZBb0dBZjBubW53RjJRMTZVYXhhanI2M3hjUFlQS09FY1pHTFcxalhoMHVpNFJnK3lscEdSZ25xdVJzMk8KL3RDYTlUYm1JcG9KZHA3aWFPOTIzenI1MWphcnlBOCtuWWhoZ2dRQ29IdWNIY0ZBR213Ryt6R2NyMlBZYklseAo5TkVsUEFZM2pndFNWTW4yUkhMak0wUWVuTUQ1aG1HcHQvWVJOd3hPNkNBdXhaNUhzOTQ9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
diff --git a/sdv/docker/sdvstate/example/kubepod15 b/sdv/docker/sdvstate/example/kubepod15
deleted file mode 100644
index 7710cbc..0000000
--- a/sdv/docker/sdvstate/example/kubepod15
+++ /dev/null
@@ -1,20 +0,0 @@
----
-apiVersion: v1
-clusters:
-- cluster:
- server: https://10.10.150.21:6553
- insecure-skip-tls-verify: true
- name: kubernetes
-contexts:
-- context:
- cluster: kubernetes
- user: admin
- name: admin@kubernetes
-current-context: admin@kubernetes
-kind: Config
-preferences: {}
-users:
-- name: admin
- user:
- client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURZRENDQWtpZ0F3SUJBZ0lVRFZ1T2IvczEyKzR1dGNTRnBuOEhQbFlIVWFBd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0tqRVRNQkVHQTFVRUNoTUtTM1ZpWlhKdVpYUmxjekVUTUJFR0ExVUVBeE1LYTNWaVpYSnVaWFJsY3pBZQpGdzB4T1RFeU1UVXdNelExTURCYUZ3MHlNREV5TVRRd016UTFNREJhTUNreEZ6QVZCZ05WQkFvVERuTjVjM1JsCmJUcHRZWE4wWlhKek1RNHdEQVlEVlFRREV3VmhaRzFwYmpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVAKQURDQ0FRb0NnZ0VCQUo0Z3R2ZUMyVktnV1BwRHRMTWE3d2k0aE1hZlBEZUVveUg2LzBrWUdKWEF6TTRuVE55NApZdXVldCtBZUdDNnJ6cHNDRG1GcVBrVkRRM1ZkMEsrd05VSXZmOGpZVXlMbWVXUEZxNStqV25SaHpSbUVyT2VBCk9UK0lMa0pFMUN3T2hPbEtjMlB0TjhPUzdFbVR1NmxkZHQ4OXM5Z1M5aXNmbm5JQmY2YkhNdGdqWWJrZEEzbEQKb0VLL282VS9LdkpydTN2L01IRXl6VUwwbjB4UHpHK3ZPVDRpRVZRV3A3M3o0d2gzalN4SENvQmJ4RU9hTk5mSgpoQjNFMUZhSTZMY3U4VHdWdnZ3WStHc3Z3NURXblJ5VXczL0REUXpNMGNQZkc2WUNmeWhjQkVJSUJ5ZEtwUTdYCi9NZ0p4MWV1QmRHdVFheHNaNHhvS0taZW4vQWhCbWZDTUVjQ0F3RUFBYU4vTUgwd0RnWURWUjBQQVFIL0JBUUQKQWdXZ01CMEdBMVVkSlFRV01CUUdDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFNQmdOVkhSTUJBZjhFQWpBQQpNQjBHQTFVZERnUVdCQlJMYUVVWXRRaGxMQnFCQUtJdTRrUDRwWWhRTlRBZkJnTlZIU01FR0RBV2dCU2g3bE54CmJXZ1pUSjZKRkUwdHhTdGdIS3hqd3pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQXBpWXFVaUMyNFVLM2YxUW8KMnp1YTlTKzVaeWZXOTgvcG9zWDVFZ0x2c25uYmJoaXRFeXptc1RQaG1yNTZ2WmNkVlVjb3B4NFc2M0luaDRUYQpHQlBUMjVwdGZIVEE1bTNURDIrb1dFQXlKMHhBbjR3M0VpdzRhYmY0aCs1Q0JlTm9ldXJlOXhMYlIzNnZZSG9aCnQ0aVk1Q3BraHhud3VLV0FZTnE4a2lsQTlvUzV2bm5ndUMxYVJEckQ5bTJLZlk1aWtiRndGWWUzRzRLTXAyaUgKWVpiMUxhZ3BlZHRjbTJSNnhNZ0RVSktKbkN5WFpIcXp1WHMzT1h1TTFRVzZlMVl2VU1aQUdMV25NYkJ2S3MzNQpyMUdsdFY5OUh0WHBoTnBqeFd6a1RNS0s2K0wwQ0xxNXducVZjVzNUK1Y1V05HbkhWMThBMkhEM0NUc3NRWmxBCm5pbGVXdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
- client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBbmlDMjk0TFpVcUJZK2tPMHN4cnZDTGlFeHA4OE40U2pJZnIvU1JnWWxjRE16aWRNCjNMaGk2NTYzNEI0WUxxdk9td0lPWVdvK1JVTkRkVjNRcjdBMVFpOS95TmhUSXVaNVk4V3JuNk5hZEdITkdZU3MKNTRBNVA0Z3VRa1RVTEE2RTZVcHpZKzAzdzVMc1NaTzdxVjEyM3oyejJCTDJLeCtlY2dGL3BzY3kyQ05odVIwRAplVU9nUXIranBUOHE4bXU3ZS84d2NUTE5RdlNmVEUvTWI2ODVQaUlSVkJhbnZmUGpDSGVOTEVjS2dGdkVRNW8wCjE4bUVIY1RVVm9qb3R5N3hQQlcrL0JqNGF5L0RrTmFkSEpURGY4TU5ETXpSdzk4YnBnSi9LRndFUWdnSEowcWwKRHRmOHlBbkhWNjRGMGE1QnJHeG5qR2dvcGw2ZjhDRUdaOEl3UndJREFRQUJBb0lCQUJ5cFkyQ3p0LzZSRCsrMAo3QUQyNWRMWDEwRkZSWjN1amI4d0JxdlNFVXE3bXFQWFhjZzRKNzM3aytxc3FjZHozc3diOEUxWis1V0VYcXJjCmFXSWU5MWhhMGJldTlrckNLY2lhNE1QYjBSNTlSN2JUWkovRmp4cmo3VGFYMFRsM0hFSkkrMmRtYlJBbkJtdEQKdXVVMUNzSG1KajRKR2RPeE5JQUhvNEt3WXBmb2NPME9acFhVZFlOQktwSUhseFhOWjJ4RkJiVzh6a1FRekZ6MAplWmQ3YzZNUmlaZFRPd0pqNWl4c0FWSytBTXVGRkFSamNmc1FBZktlS2J2YUdDTFBvQmFSak5US0Z6MEVhWmlZClNTM2NYMDRCTnk0NWNPVWlHK3RsSlgxeEhGT04weittMlArZWQ1dCtHSHB3UUg4ak1ZQzhkZlJCUVdSeGNCTjcKemd3NWp5RUNnWUVBeEM4REVPWm9QNXhOcFZwbXB6OVAvY2NiVE9XekdUTlZpZzFhcmdSMC90RWRRK0lKQlpDdgpqMzlWVk9FeDUrSlJHVmhmSG9NczlXZVZuSmJSZTFyN1QrWU1WOVFCOVYvbDVhdkJoc0Vhc1NpaThsVEpzT3dXCmJRTDQyMDd1QVhGemFoMHhPS253T2gwN3p0TTBFMXQwWFVrR1BFSzE2bldPbFc4K3IyOEEvSmNDZ1lFQXpsZEgKSlo5RTUxT0dmZU96Y2VQdWV0ZU9PYnNvWVU4eHhOaUg0MitKWVpKNFVqNVY2RGw4OHdEaS91NVNVOVBtUWM1dAozOFpncXdRRjRFWklTbk0rbElKZnluUmhmWU9YZXB4bEJnVFBVb2dUeGY1bm5jZjNOWGZrVVJxUWViZURqTEdjClBrbU1LbE9kK21jRnYxdGI4eXhzbVEwbjhFVWplVkdLT3JKVjc5RUNnWUJ1NC9QanRaanZlN1lYNVFWcE84eEgKTWlnb1N4MzAvS001S1ZzOFNhQ24rQ09HbjFsaUgrcGNQaWxKbFJEVWRZUkp3ejNnelZ5NFNoaXpManl5Y1RiawpickJEWkw3R3A3SVhKQUo3M09MdGlINnlZMkt0OG9TcWthZUFyeGl4RUNPZ3MyZURFK3VKcmNTRW43VXJ5K0gyCmFMUnhrM09vVjFLRS9TQjlvVXo1ZVFLQmdFZ1g4b0hRbmhCOC9IYXJ3aHkrMktvTyttQnRaZlJwNlNldngvck4KRTZFRnZnaHVRekc2TkUvck5XU0EvRDdSd0plcGVuWS9KN05ZMm55NzBiSkJoZEg1bzJKbk8xRFJVM0hCaHdLTgpWNnFzWk13KzBSRXR0cy8xcmM0d2k5NGJJbGxjRFEwdVFVemdua2ZKQ3hjSzRwdWFIKzl4eTB5RnU1azl4aUF3CkF4cWhBb0dBUlc3Qno1UjlSOWZKVUp3ZEhvMGpRVmhrL3lzSWlmQWRxQ3d6blpOcVM4cU9KMXpsSExhWkozMXcKbVdjNzA3UUN6Q3BOMk1YV2lnMzc2VVJpdXFtcEJTZW14bzFRendhQWJhK0Yvd1I1VzlncndzTmZ2RDR6TkVHbgp2dFllSS9taXlJOVFaay9PVkcrblRLL1ZIZExha3FOVFNKQUl6WSttZ2Y4SWphUTUrVW89Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== \ No newline at end of file
diff --git a/sdv/docker/sdvstate/example/state.yml b/sdv/docker/sdvstate/example/state.yml
index 1ca61e1..89dc548 100644
--- a/sdv/docker/sdvstate/example/state.yml
+++ b/sdv/docker/sdvstate/example/state.yml
@@ -15,3 +15,6 @@ PDF_FILE: example/intel-pod10.json
# Path to kube-config file
KUBE_CONFIG : example/kubepod10
+MASTER_ROLE_NAME : masters
+WORKER_ROLE_NAME : workers
+
diff --git a/sdv/docker/sdvstate/server b/sdv/docker/sdvstate/server
index ca37eca..ca37eca 100755..100644
--- a/sdv/docker/sdvstate/server
+++ b/sdv/docker/sdvstate/server
diff --git a/sdv/docker/sdvstate/settings/common.yml b/sdv/docker/sdvstate/settings/common.yml
index 65f131c..f25f861 100644
--- a/sdv/docker/sdvstate/settings/common.yml
+++ b/sdv/docker/sdvstate/settings/common.yml
@@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
+project_name: cirv-sdv
+project_version: 1.0
##################################
# Program behavior configurations
@@ -24,4 +25,9 @@ log_verbosity: info
# Results
results_dir: /tmp/state/
-save_results_locally: True \ No newline at end of file
+save_results_locally: True
+
+# Test API
+enable_testapi: True
+testapi_url: http://testresults.opnfv.org/test/api/v1
+
diff --git a/sdv/docker/sdvstate/state b/sdv/docker/sdvstate/state
index 41d17a4..353df71 100755
--- a/sdv/docker/sdvstate/state
+++ b/sdv/docker/sdvstate/state
@@ -27,10 +27,12 @@ import re
import ast
import sys
from datetime import datetime
+import requests
from tools.conf import settings
from tools.result_api import result_api, Local
from core import load_pdf
+from core import display_report
from validator import AirshipValidator
@@ -229,6 +231,19 @@ def main():
if installer == 'airship':
airship = AirshipValidator()
airship.validate()
+ report = airship.get_report()
+
+
+ # Displaying Report
+ display_report(report)
+
+ if settings.getValue('enable_testapi'):
+ logger = logging.getLogger(__name__)
+ logger.info('Publishing results to TestAPI')
+ url = settings.getValue('testapi_url')
+ url += "/results/"
+ response = requests.post(url, json=report)
+ logger.info(response)
diff --git a/sdv/docker/sdvstate/validator/airship/__init__.py b/sdv/docker/sdvstate/validator/airship/__init__.py
new file mode 100644
index 0000000..78e42c4
--- /dev/null
+++ b/sdv/docker/sdvstate/validator/airship/__init__.py
@@ -0,0 +1,49 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+"""
+Package for Airship
+"""
+
+
+### Pod Health Checks
+from .pod_health_check import pod_health_check
+
+### Ceph Health Checks
+from .ceph_check import ceph_health_check
+
+### Monitoring & Logging Agents Checks
+from .monitoring_logging_agent_check import prometheus_check
+from .monitoring_logging_agent_check import grafana_check
+# from .monitoring_logging_agent_check import prometheus_alert_manager_check
+from .monitoring_logging_agent_check import elasticsearch_check
+from .monitoring_logging_agent_check import kibana_check
+from .monitoring_logging_agent_check import nagios_check
+from .monitoring_logging_agent_check import elasticsearch_exporter_check
+from .monitoring_logging_agent_check import fluentd_exporter_check
+
+### Network Checks
+from .network_check import physical_network_check
+
+### Compute Related Checks
+from .compute_check import reserved_vnf_cores_check
+from .compute_check import isolated_cores_check
+from .compute_check import vswitch_pmd_cores_check
+from .compute_check import vswitch_dpdk_lcores_check
+from .compute_check import os_reserved_cores_check
+from .compute_check import nova_scheduler_filters_check
+from .compute_check import cpu_allocation_ratio_check
+
+from .store_result import store_result
diff --git a/sdv/docker/sdvstate/validator/airship/airship.py b/sdv/docker/sdvstate/validator/airship/airship.py
index e77f06f..18de66d 100644
--- a/sdv/docker/sdvstate/validator/airship/airship.py
+++ b/sdv/docker/sdvstate/validator/airship/airship.py
@@ -18,16 +18,15 @@ Airship Validator
"""
import logging
-import ast
-import json
+from datetime import datetime as dt
from tools.conf import settings
-from tools.result_api import result_api, rfile
-from tools.kube_utils import *
+from tools.kube_utils import load_kube_api
from validator.validator import Validator
-## Checks
-from .pod_health_check import pod_health_check
+from . import *
+
+
@@ -42,10 +41,87 @@ class AirshipValidator(Validator):
super(AirshipValidator, self).__init__()
self._logger = logging.getLogger(__name__)
+ self._report = {"installer": "Airship",
+ "criteria": "pass",
+ "details": {"total_checks": 0,
+ "pass": [],
+ "fail": [],
+ "metadata": {}
+ }
+ }
+
load_kube_api()
-
+
def validate(self):
"""
+ Validation method
"""
- pod_health_check()
+
+ self._report['scenario'] = 'none'
+ self._report['case_name'] = 'ook_airship'
+ self._report['start_date'] = dt.now().strftime('%Y-%m-%d %H:%M:%S')
+
+
+ # PLATFORM CHECKS
+ self.update_report(pod_health_check())
+
+ # STORAGE CHECKS
+ self.update_report(ceph_health_check())
+
+ # MONITORING & LOGGING AGENTS CHECKS
+ self.update_report(prometheus_check())
+ self.update_report(grafana_check())
+ ## current version of AlertManager doesn't support this
+ # prometheus_alert_manager_check()
+ self.update_report(elasticsearch_check())
+ self.update_report(kibana_check())
+ self.update_report(nagios_check())
+ self.update_report(elasticsearch_exporter_check())
+ self.update_report(fluentd_exporter_check())
+
+ # NETWORK CHECKS
+ self.update_report(physical_network_check())
+
+ # COMPUTE CHECKS
+ self.update_report(reserved_vnf_cores_check())
+ self.update_report(isolated_cores_check())
+ self.update_report(vswitch_pmd_cores_check())
+ self.update_report(vswitch_dpdk_lcores_check())
+ self.update_report(os_reserved_cores_check())
+ self.update_report(nova_scheduler_filters_check())
+ self.update_report(cpu_allocation_ratio_check())
+
+ self._report['stop_date'] = dt.now().strftime('%Y-%m-%d %H:%M:%S')
+
+
+ def update_report(self, result):
+ """
+ Updates report with new results
+ """
+ case_name = result['case_name']
+ criteria = result['criteria']
+
+ self._report['details']['total_checks'] += 1
+ if criteria == 'pass':
+ self._report['details']['pass'].append(case_name)
+ elif criteria == 'fail':
+ self._report['details']['fail'].append(case_name)
+ self._report['criteria'] = 'fail'
+
+
+
+ def get_report(self):
+ """
+ Return final report as dict
+ """
+ self._report["project_name"] = settings.getValue("project_name")
+ self._report["version"] = settings.getValue("project_version")
+ self._report["build_tag"] = "none"
+
+ pdf = settings.getValue('pdf_file')
+ self._report["pod_name"] = pdf['management_info']['resource_pool_name']
+
+ store_result(self._report)
+
+ return self._report
diff --git a/sdv/docker/sdvstate/validator/airship/ceph_check.py b/sdv/docker/sdvstate/validator/airship/ceph_check.py
new file mode 100644
index 0000000..b33e876
--- /dev/null
+++ b/sdv/docker/sdvstate/validator/airship/ceph_check.py
@@ -0,0 +1,51 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Ceph Related Checks
+"""
+
+import ast
+
+from tools.kube_utils import get_pod_with_labels, kube_exec
+from .store_result import store_result
+
+
+
+
+def ceph_health_check():
+ """
+ Check health of Ceph
+ """
+ pod = get_pod_with_labels('application=ceph,component=mon')
+
+ cmd = ['ceph', 'health', '-f', 'json']
+ response = kube_exec(pod, cmd)
+
+ response = ast.literal_eval(response)
+
+ result = {'category': 'storage',
+ 'case_name': 'ceph_health_check',
+ 'details': []
+ }
+
+ if response['status'] == 'HEALTH_OK':
+ result['criteria'] = 'pass'
+ result['details'] = 'HEALTH_OK'
+ else:
+ result['criteria'] = 'fail'
+ result['details'] = response
+
+ store_result(result)
+ return result
diff --git a/sdv/docker/sdvstate/validator/airship/compute_check.py b/sdv/docker/sdvstate/validator/airship/compute_check.py
new file mode 100644
index 0000000..ff6f6db
--- /dev/null
+++ b/sdv/docker/sdvstate/validator/airship/compute_check.py
@@ -0,0 +1,646 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Compute Related Checks
+"""
+
+import configparser
+import json
+
+from tools.kube_utils import kube_exec, get_pod_with_labels
+from tools.conf import settings
+from .store_result import store_result
+
+
+###########
+# Checks
+###########
+
+def isolated_cores_check():
+ """
+ isolated_cores_check
+ """
+ traced_value = trace_isolated_cores()
+ required_value = required_isolated_cores()
+
+ result = {'category': 'compute',
+ 'case_name': 'isolated_cores_check',
+ 'details': {'traced_cores': traced_value,
+ 'required_cores': required_value
+ }
+ }
+
+ if is_ranges_equals(traced_value, required_value):
+ result['criteria'] = 'pass'
+ else:
+ result['criteria'] = 'fail'
+
+
+ store_result(result)
+ return result
+
+
+
+def reserved_vnf_cores_check():
+ """
+ reserved_vnf_cores_check
+ """
+ traced_value = trace_reserved_vnf_cores()
+ required_value = required_reserved_vnf_cores()
+
+ result = {'category': 'compute',
+ 'case_name': 'reserved_vnf_cores_check',
+ 'details': {'traced_cores': traced_value,
+ 'required_cores': required_value
+ }
+ }
+
+ if is_ranges_equals(traced_value, required_value):
+ result['criteria'] = 'pass'
+ else:
+ result['criteria'] = 'fail'
+
+
+ store_result(result)
+ return result
+
+
+
+def vswitch_pmd_cores_check():
+ """
+ vswitch_pmd_cores_check
+ """
+ traced_value = trace_vswitch_pmd_cores()
+ required_value = required_vswitch_pmd_cores()
+
+ result = {'category': 'compute',
+ 'case_name': 'vswitch_pmd_cores_check',
+ 'details': {'traced_cores': traced_value,
+ 'required_cores': required_value
+ }
+ }
+
+ if is_ranges_equals(traced_value, required_value):
+ result['criteria'] = 'pass'
+ else:
+ result['criteria'] = 'fail'
+
+
+ store_result(result)
+ return result
+
+
+
+def vswitch_dpdk_lcores_check():
+ """
+ vswitch_dpdk_lcores_check
+ """
+ traced_value = trace_vswitch_dpdk_lcores()
+ required_value = required_vswitch_dpdk_lcores()
+
+ result = {'category': 'compute',
+ 'case_name': 'vswitch_dpdk_lcores_check',
+ 'details': {'traced_cores': traced_value,
+ 'required_cores': required_value
+ }
+ }
+
+ if is_ranges_equals(traced_value, required_value):
+ result['criteria'] = 'pass'
+ else:
+ result['criteria'] = 'fail'
+
+
+ store_result(result)
+ return result
+
+
+
+def os_reserved_cores_check():
+ """
+ os_reserved_cores_check
+ """
+ traced_value = trace_os_reserved_cores()
+ required_value = required_os_reserved_cores()
+
+ result = {'category': 'compute',
+ 'case_name': 'os_reserved_cores_check',
+ 'details': {'traced_cores': traced_value,
+ 'required_cores': required_value
+ }
+ }
+
+ if is_ranges_equals(traced_value, required_value):
+ result['criteria'] = 'pass'
+ else:
+ result['criteria'] = 'fail'
+
+
+ store_result(result)
+ return result
+
+
+
+def nova_scheduler_filters_check():
+ """
+ nova_scheduler_filters_check
+ """
+ traced_value = trace_nova_scheduler_filters()
+ required_value = required_nova_scheduler_filters()
+
+ result = {'category': 'compute',
+ 'case_name': 'nova_scheduler_filters_check',
+ 'details': {'traced_filters': traced_value,
+ 'required_filters': required_value
+ }
+ }
+
+ if are_lists_equal(traced_value, required_value):
+ result['criteria'] = 'pass'
+ else:
+ result['criteria'] = 'fail'
+
+ store_result(result)
+ return result
+
+
+
+def cpu_allocation_ratio_check():
+ """
+ cpu_allocation_ratio_check
+ """
+ traced_value = trace_cpu_allocation_ratio()
+ required_value = required_cpu_allocation_ratio()
+
+ result = {'category': 'compute',
+ 'case_name': 'cpu_allocation_ratio_check',
+ 'details': {'traced_ratio': traced_value,
+ 'required_ratio': required_value
+ }
+ }
+
+ if traced_value == required_value:
+ result['criteria'] = 'pass'
+ else:
+ result['criteria'] = 'fail'
+
+ store_result(result)
+ return result
+
+
+
+
+
+
+
+
+###############
+# helper functions
+###############
+
+
+
+def trace_isolated_cores():
+ """
+ Trace isolated_cores from Airship deployment
+
+ :return: value traced from `isolcpus` key in `/proc/cmdline`
+ """
+ pod = get_pod_with_labels('application=nova,component=compute')
+
+ cmd = ['cat', '/proc/cmdline']
+ proc_cmd = kube_exec(pod, cmd)
+
+ for option in proc_cmd.split():
+ if 'isolcpus' in option:
+ _, isolcpus_value = split_key_value(option)
+ break
+
+ return isolcpus_value
+
+
+def required_isolated_cores():
+ """
+ Returns value of `isolated_cpus` from platform_profile used by
+ Role for worker nodes in PDF
+
+ :return: isolated_cores value expected by the PDF
+ """
+ worker_role = settings.getValue('WORKER_ROLE_NAME')
+ profile = get_platform_profile_by_role(worker_role)
+ return profile['isolated_cpus']
+
+
+
+
+
+
+def trace_reserved_vnf_cores():
+ """
+ Trace vnf_reserved_cores from Airship deployment
+
+ :return: value traced from `vcpu_pin_set` key in nova.conf
+ of actual deployment
+ """
+ try:
+ config = get_nova_conf()
+ vcpu_pin_set = config.get('DEFAULT', 'vcpu_pin_set')
+ except (configparser.NoOptionError, configparser.MissingSectionHeaderError):
+ vcpu_pin_set = ''
+
+ return vcpu_pin_set
+
+
+def required_reserved_vnf_cores():
+ """
+ Returns value of vnf_cores from platform_profile used by
+ Role for worker nodes in PDF
+
+ :return: vnf_reserverd_core value expected by the PDF
+ """
+ worker_role = settings.getValue('WORKER_ROLE_NAME')
+ profile = get_platform_profile_by_role(worker_role)
+ return profile['vnf_cores']
+
+
+
+
+
+
+def trace_vswitch_pmd_cores():
+ """
+ Trace vswitch_pmd_cores from Airship deployment
+
+ :return: value traced from `other_config:pmd-cpu-mask` in
+ openvswitchdb using ovs-vsctl
+ """
+ ovs_pod = get_pod_with_labels('application=openvswitch,component=openvswitch-vswitchd')
+
+ cmd = ['ovs-vsctl', '-t', '5', 'get', 'Open_vSwitch', '.', 'other_config']
+ response = kube_exec(ovs_pod, cmd)
+
+ response.replace('=', ':')
+ config = json.loads(response)
+
+ if 'pmd-cpu-mask' in config:
+ pmd_cores = hex_to_comma_list(config['pmd-cpu-mask'])
+ else:
+ pmd_cores = ''
+
+ return pmd_cores
+
+
+def required_vswitch_pmd_cores():
+ """
+ Returns value of vswitch_pmd_cores from platform_profile used by
+ Role for worker nodes in PDF
+
+ :return: vswitch_pmd_cores value expected by the PDF
+ """
+ worker_role = settings.getValue('WORKER_ROLE_NAME')
+ profile = get_platform_profile_by_role(worker_role)
+ return profile['vswitch_pmd_cores']
+
+
+
+
+
+
+def trace_vswitch_dpdk_lcores():
+ """
+ Trace vswitch_dpdk_lcores from Airship deployment
+
+ :return: value traced from `other_config:dpdk-lcore-mask` in
+ openvswitchdb using ovs-vsctl
+ """
+ ovs_pod = get_pod_with_labels('application=openvswitch,component=openvswitch-vswitchd')
+
+ cmd = ['ovs-vsctl', '-t', '5', 'get', 'Open_vSwitch', '.', 'other_config']
+ response = kube_exec(ovs_pod, cmd)
+
+ response.replace('=', ':')
+ config = json.loads(response)
+
+ if 'dpdk-lcore-mask' in config:
+ pmd_cores = hex_to_comma_list(config['dpdk-lcore-mask'])
+ else:
+ pmd_cores = ''
+
+ return pmd_cores
+
+
+def required_vswitch_dpdk_lcores():
+ """
+ Returns value of vswitch_dpdk_lcores from platform_profile used by
+ Role for worker nodes in PDF
+
+ :return: vswitch_dpdk_lcores value expected by the PDF
+ """
+ worker_role = settings.getValue('WORKER_ROLE_NAME')
+ profile = get_platform_profile_by_role(worker_role)
+ return profile['vswitch_dpdk_lcores']
+
+
+
+
+
+
+def trace_os_reserved_cores():
+ """
+ Trace os_reserved_cores from Airship deployment
+
+ os_reserved_cores = all_cores - (reserved_vnf_cores +
+ vswitch_pmd_cores +
+ vswitch_dpdk_lcores)
+ """
+ worker_role = settings.getValue('WORKER_ROLE_NAME')
+ all_cores = get_cores_by_role(worker_role)
+
+ reserved_vnf_cores = trace_reserved_vnf_cores()
+ vswitch_pmd_cores = trace_vswitch_pmd_cores()
+ vswitch_dpdk_lcores = trace_vswitch_dpdk_lcores()
+
+ non_os_cores = []
+ non_os_cores.extend(convert_range_to_list(reserved_vnf_cores))
+ non_os_cores.extend(convert_range_to_list(vswitch_pmd_cores))
+ non_os_cores.extend(convert_range_to_list(vswitch_dpdk_lcores))
+
+ os_reserved_cores = set(all_cores).difference(set(non_os_cores))
+
+ # return as string with comma separated value
+ return ','.join(map(str, list(os_reserved_cores)))
+
+
+def required_os_reserved_cores():
+ """
+ Returns value of os_reserved_cores from platform_profile used by
+ Role for worker nodes in PDF
+
+ :return: os_reserved_cores value expected by the PDF
+ """
+ worker_role = settings.getValue('WORKER_ROLE_NAME')
+ profile = get_platform_profile_by_role(worker_role)
+ return profile['os_reserved_cores']
+
+
+
+
+
+def trace_nova_scheduler_filters():
+ """
+ Trace scheduler_filters from Airship deployment
+
+ :return: value traced from `enabled_filters` key in nova.conf
+ of actual deployment
+ """
+ try:
+ config = get_nova_conf()
+ filters = config.get('filter_scheduler', 'enabled_filters')
+ except (configparser.NoOptionError, configparser.MissingSectionHeaderError):
+ filters = ''
+
+ filters = filters.split(',')
+ map(str.strip, filters)
+
+ return filters
+
+def required_nova_scheduler_filters():
+ """
+ Required nova scheduler_filters by the PDF
+ """
+ pdf = settings.getValue('pdf_file')
+ filters = pdf['vim_functional']['scheduler_filters']
+
+ filters = filters.split(',')
+ map(str.strip, filters)
+
+ return filters
+
+
+
+
+
+
+
+def trace_cpu_allocation_ratio():
+ """
+ Trace cpu_allocation_ratio from Airship deployment
+
+ :return: value traced from `cpu_allocation_ratio` key in nova.conf
+ of actual deployment
+ """
+ try:
+ config = get_nova_conf()
+ cpu_allocation_ratio = config.get('DEFAULT', 'cpu_allocation_ratio')
+ except (configparser.NoOptionError, configparser.MissingSectionHeaderError):
+ cpu_allocation_ratio = ''
+
+ return float(cpu_allocation_ratio)
+
+def required_cpu_allocation_ratio():
+ """
+ Required cpu_allocation_ratio by the PDF
+ """
+ pdf = settings.getValue('pdf_file')
+ cpu_allocation_ratio = pdf['vim_functional']['cpu_allocation_ratio']
+
+ return float(cpu_allocation_ratio)
+
+
+
+
+
+
+
+def get_role(role_name):
+ """
+ Searches and returns role with `role_name`
+ """
+ roles = settings.getValue('pdf_file')['roles']
+
+ for role in roles:
+ if role['name'] == role_name:
+ role_details = role
+
+ return role_details
+
+
+def get_platform_profile(profile_name):
+ """
+ Searches and returns platform_profile with `profile_name`
+ """
+ platform_profiles = settings.getValue('pdf_file')['platform_profiles']
+
+ for profile in platform_profiles:
+ if profile['profile_name'] == profile_name:
+ profile_details = profile
+
+ return profile_details
+
+def get_processor_profile(profile_name):
+ """
+ Searches and returns processor_profile with `profile_name`
+ """
+ processor_profiles = settings.getValue('pdf_file')['processor_profiles']
+
+ for profile in processor_profiles:
+ if profile['profile_name'] == profile_name:
+ profile_details = profile
+
+ return profile_details
+
+def get_platform_profile_by_role(role_name):
+ """
+ Returns platform profile details of a role
+ """
+ role = get_role(role_name)
+ profile = get_platform_profile(role['platform_profile'])
+ return profile
+
+
+def get_hardware_profile_by_role(role_name):
+ """
+ Returns hardware profile details of a role
+ """
+ role = get_role(role_name)
+
+ hardware_profiles = settings.getValue('pdf_file')['hardware_profiles']
+
+ for profile in hardware_profiles:
+ if profile['profile_name'] == role['hardware_profile']:
+ profile_details = profile
+
+ return profile_details
+
+
+def get_cores_by_role(role_name):
+ """
+ Returns cpu cores list of server hardware used in the role
+ """
+ hardware_profile = get_hardware_profile_by_role(role_name)
+ processor_profile = hardware_profile['profile_info']['processor_profile']
+ profile = get_processor_profile(processor_profile)
+
+ cpus = []
+
+ for numa in profile['profile_info']['numas']:
+ cpus.extend(convert_range_to_list(numa['cpu_set']))
+
+ return cpus
+
+
+
+
+
+
+
+def get_nova_conf():
+ """
+ Returns parsed nova.conf
+ """
+ pod = get_pod_with_labels('application=nova,component=compute')
+
+ cmd = ['cat', '/etc/nova/nova.conf']
+ response = kube_exec(pod, cmd)
+
+ config = configparser.ConfigParser()
+ config.read_string(response)
+
+ return config
+
+
+### cpu cores related helper function
+
+def convert_range_to_list(x):
+ """
+ Returns list of numbers from given range as string
+
+ e.g.: convert_range_to_list('3-5') will give [3, 4, 5]
+ """
+ # pylint: disable=C0103
+ result = []
+ for part in x.split(','):
+ if '-' in part:
+ a, b = part.split('-')
+ a, b = int(a), int(b)
+ result.extend(range(a, b + 1))
+ elif part != '':
+ a = int(part)
+ result.append(a)
+ # remove duplicates
+ result = list(dict.fromkeys(result))
+ return result
+
+
+def is_ranges_equals(range1, range2):
+ """
+ Checks whether two ranges passed as string are equal
+
+ e.g.: is_ranges_equals('2-5', '2-4,5') returns true
+ """
+ set1 = set(convert_range_to_list(range1))
+ set2 = set(convert_range_to_list(range2))
+ return set1 == set2
+
+def are_lists_equal(list1, list2):
+ """
+ Checks whether two list are identicals
+ """
+ set1 = set(list1)
+ set2 = set(list2)
+ return set1 == set2
+
+
+
+def hex_to_comma_list(hex_mask):
+ """
+ Converts CPU mask given in hex to list of cores
+ """
+ binary = bin(int(hex_mask, 16))[2:]
+ reversed_binary = binary[::-1]
+ i = 0
+ output = ""
+ for bit in reversed_binary:
+ if bit == '1':
+ output = output + str(i) + ','
+ i = i + 1
+ return output[:-1]
+
+
+def comma_list_to_hex(cpus):
+ """
+ Converts a list of cpu cores in corresponding hex value
+ of cpu-mask
+ """
+ cpu_arr = cpus.split(",")
+ binary_mask = 0
+ for cpu in cpu_arr:
+ binary_mask = binary_mask | (1 << int(cpu))
+ return format(binary_mask, '02x')
+
+
+
+def split_key_value(key_value_str, delimiter='='):
+ """
+ splits given string into key and value based on delimiter
+
+ :param key_value_str: example string `someKey=somevalue`
+ :param delimiter: default delimiter is `=`
+ :return: [ key, value]
+ """
+ key, value = key_value_str.split(delimiter)
+ key = key.strip()
+ value = value.strip()
+ return key, value
diff --git a/sdv/docker/sdvstate/validator/airship/monitoring_logging_agent_check.py b/sdv/docker/sdvstate/validator/airship/monitoring_logging_agent_check.py
new file mode 100644
index 0000000..3754299
--- /dev/null
+++ b/sdv/docker/sdvstate/validator/airship/monitoring_logging_agent_check.py
@@ -0,0 +1,243 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Monitoring & Logging Agents Related Checks
+"""
+
+import ast
+
+from tools.kube_utils import kube_curl
+from tools.result_api import rfile
+from .store_result import store_result
+
+
+def prometheus_check():
+ """
+ Check health of Prometheus
+ """
+ username = "prometheus"
+ password = "password123"
+ service = "prom-metrics"
+ namespace = "osh-infra"
+
+ health = "fail" #default
+ res = kube_curl("-sL", "-m", "3", "-u", f'{username}:{password}', f'{service}.{namespace}/-/healthy')
+ if 'Prometheus is Healthy' in res:
+ health = "pass"
+
+ readiness = "fail" #default
+ res = kube_curl("-sL", "-m", "3", "-u", f'{username}:{password}', f'{service}.{namespace}/-/ready')
+ if 'Prometheus is Ready' in res:
+ readiness = "pass"
+
+ if health == "pass" and readiness == "pass":
+ state = "pass"
+ else:
+ state = "fail"
+
+ result = {'category': 'platform',
+ 'case_name': 'prometheus_check',
+ 'criteria': state,
+ 'details': {'health': health, 'readiness': readiness}
+ }
+
+ store_result(result)
+ return result
+
+
+
+def grafana_check():
+ """
+ Check health of Grafana
+ """
+ username = "grafana"
+ password = "password123"
+ service = "grafana-dashboard"
+ namespace = "osh-infra"
+
+ state = "fail" #default
+ res = kube_curl("-sL", "-m", "3", "-w", "%{http_code}",\
+ "-o", "/dev/null", "-u", \
+ f'{username}:{password}', \
+ f'{service}.{namespace}:3000/api/health')
+ if res == '200':
+ state = "pass"
+
+ result = {'category': 'platform',
+ 'case_name': 'grafana_check',
+ 'criteria': state
+ }
+
+ store_result(result)
+ return result
+
+
+def prometheus_alert_manager_check():
+ """
+ Check health of Alert Manager
+ """
+ service = "alerts-engine"
+ namespace = "osh-infra"
+
+ health = "fail" #default
+ res = kube_curl("-sL", "-m", "3", f'{service}.{namespace}:9093/-/healthy')
+ if 'Prometheus is Healthy' in res:
+ health = "pass"
+
+ readiness = "fail" #default
+ res = kube_curl("-sL", "-m", "3", f'{service}.{namespace}:9093/-/ready')
+ if 'Prometheus is Ready' in res:
+ readiness = "pass"
+
+ if health == "pass" and readiness == "pass":
+ state = "pass"
+ else:
+ state = "fail"
+
+ result = {'category': 'platform',
+ 'case_name': 'prometheus_alert_manager_check',
+ 'criteria': state,
+ 'details': {'health': health, 'readiness': readiness}
+ }
+
+
+ store_result(result)
+ return result
+
+
+def elasticsearch_check():
+ """
+ Check health of Elasticsearch cluster
+ """
+ username = "elasticsearch"
+ password = "password123"
+ service = "elasticsearch"
+ namespace = "osh-infra"
+
+ state = "fail" #default
+ res = kube_curl("-sL", "-m", "3", "-u", f'{username}:{password}', f'{service}.{namespace}/_cluster/health')
+
+ if res == '':
+ res = 'Elasticsearch not reachable'
+ else:
+ res = ast.literal_eval(res)
+ if res['status'] == 'green':
+ state = "pass"
+
+ result = {'category': 'platform',
+ 'case_name': 'elasticsearch_check',
+ 'criteria': state,
+ 'details': res
+ }
+
+ store_result(result)
+ return result
+
+
+def kibana_check():
+ """
+ Check health of Kibana
+ """
+ username = "elasticsearch"
+ password = "password123"
+ service = "kibana-dash"
+ namespace = "osh-infra"
+
+ state = "fail" #default
+ res = kube_curl("-sL", "-m", "3", "-u", f'{username}:{password}', f'{service}.{namespace}/api/status')
+
+ if res == '':
+ res = 'kibana not reachable'
+ else:
+ res = ast.literal_eval(res)
+ if res['status']['overall']['state'] == 'green':
+ state = "pass"
+
+ result = {'category': 'platform',
+ 'case_name': 'kibana_check',
+ 'criteria': state,
+ 'details': rfile(str(res))
+ }
+
+ store_result(result)
+ return result
+
+
+def nagios_check():
+ """
+ Check health of Nagios
+ """
+ username = "nagios"
+ password = "password123"
+ service = "nagios-metrics"
+ namespace = "osh-infra"
+
+ state = "fail" #default
+ res = kube_curl("-sL", "-m", "3", "-w", "%{http_code}",\
+ "-o", "/dev/null", "-u", \
+ f'{username}:{password}', \
+ f'{service}.{namespace}')
+ if res == '200':
+ state = "pass"
+
+ result = {'category': 'platform',
+ 'case_name': 'nagios_check',
+ 'criteria': state
+ }
+
+ store_result(result)
+ return result
+
+
+def elasticsearch_exporter_check():
+ """
+ Check health of Elasticsearch Exporter
+ """
+ service = "elasticsearch-exporter"
+ namespace = "osh-infra"
+
+ state = "fail" #default
+ res = kube_curl("-sL", "-m", "3", "-w", "%{http_code}", "-o", "/dev/null", f'{service}.{namespace}:9108/metrics')
+ if res == '200':
+ state = "pass"
+
+ result = {'category': 'platform',
+ 'case_name': 'elasticsearch_exporter_check',
+ 'criteria': state
+ }
+
+ store_result(result)
+ return result
+
+
+def fluentd_exporter_check():
+ """
+ Check health of Fluentd Exporter
+ """
+ service = "fluentd-exporter"
+ namespace = "osh-infra"
+
+ state = "fail" #default
+ res = kube_curl("-sL", "-m", "3", "-w", "%{http_code}", "-o", "/dev/null", f'{service}.{namespace}:9309/metrics')
+ if res == '200':
+ state = "pass"
+
+ result = {'category': 'platform',
+ 'case_name': 'fluentd_exporter_check',
+ 'criteria': state
+ }
+
+ store_result(result)
+ return result
diff --git a/sdv/docker/sdvstate/validator/airship/network_check.py b/sdv/docker/sdvstate/validator/airship/network_check.py
new file mode 100644
index 0000000..bddf579
--- /dev/null
+++ b/sdv/docker/sdvstate/validator/airship/network_check.py
@@ -0,0 +1,114 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Network Related Checks
+"""
+
+
+import configparser
+
+from tools.conf import settings
+from tools.kube_utils import kube_exec, get_pod_with_labels
+
+from .store_result import store_result
+
+
+def physical_network_check():
+ """
+ physical_network_check
+ """
+ ml2_config = neutron_ml2_config()
+
+ physical_networks = settings.getValue('pdf_file')['physical_networks']
+
+ type_drivers = ml2_config.get('ml2', 'type_drivers').split(',')
+
+ flat_networks = ml2_config.get('ml2_type_flat', 'flat_networks').split(',')
+
+ vlan_networks = []
+ network_vlan_ranges = ml2_config.get('ml2_type_vlan', 'network_vlan_ranges').split(',')
+ for network in network_vlan_ranges:
+ vlan_networks.append(network.split(':')[0])
+
+ result = {'category': 'network',
+ 'case_name': 'physical_network_check',
+ 'criteria': 'pass',
+ 'details': []
+ }
+
+ for physnet in physical_networks:
+
+ res = {'network_name': physnet['name'],
+ 'type': physnet['type'],
+ 'criteria': 'fail'
+ }
+
+ if physnet['type'] in type_drivers:
+ if physnet['type'] == 'flat':
+ if physnet['name'] in flat_networks or '*' in flat_networks:
+ res['criteria'] = 'pass'
+ else:
+ res['details'] = 'physical network name not found'
+ if physnet['type'] == 'vlan':
+ if physnet['name'] in vlan_networks:
+ res['criteria'] = 'pass'
+ else:
+ res['details'] = 'physical network name not found'
+ else:
+ res['details'] = 'physical network type not found'
+
+ result['details'].append(res)
+ if res['criteria'] == 'fail':
+ result['criteria'] = 'fail'
+
+ store_result(result)
+ return result
+
+
+
+def neutron_ml2_config():
+ """
+ Returns parsed ml2 config from neutron
+ """
+ ovs = get_pod_with_labels("application=neutron,component=neutron-ovs-agent")
+ sriov = get_pod_with_labels("application=neutron,component=neutron-sriov-agent")
+
+ confs = get_neutron_ml2_conf_from_pod(ovs)
+ confs.extend(get_neutron_ml2_conf_from_pod(sriov))
+
+ config = configparser.ConfigParser()
+ for conf in confs:
+ config.read_string(conf)
+
+ return config
+
+
+
+
+def get_neutron_ml2_conf_from_pod(pod):
+ """
+ Reads ml2 config from neutron pod
+ """
+ cmd = ['ls', '/etc/neutron/plugins/ml2/']
+ response = kube_exec(pod, cmd)
+ files = response.rstrip("\n").split()
+
+ response = []
+ for filename in files:
+ cmd = ['cat', '/etc/neutron/plugins/ml2/' + filename]
+ conf = kube_exec(pod, cmd)
+ response.append(conf)
+
+ return response
diff --git a/sdv/docker/sdvstate/validator/airship/pod_health_check.py b/sdv/docker/sdvstate/validator/airship/pod_health_check.py
index 34a6747..0093ffc 100644
--- a/sdv/docker/sdvstate/validator/airship/pod_health_check.py
+++ b/sdv/docker/sdvstate/validator/airship/pod_health_check.py
@@ -13,13 +13,19 @@
# limitations under the License.
+"""
+Pod Health Checks
+"""
+
+
import logging
-from kubernetes import client, config
from tools.kube_utils import kube_api
from tools.conf import settings
-from tools.result_api import result_api, rfile
+from tools.result_api import rfile
+
+from .store_result import store_result
@@ -29,13 +35,25 @@ def pod_health_check():
"""
api = kube_api()
namespace_list = settings.getValue('airship_namespace_list')
+
+ result = {'category': 'platform',
+ 'case_name': 'pod_health_check',
+ 'criteria': 'pass',
+ 'details': []
+ }
+
for namespace in namespace_list:
pod_list = api.list_namespaced_pod(namespace)
for pod in pod_list.items:
- result = pod_status(pod)
- if result['state'] == 'fail':
- result['logs'] = get_logs(pod)
- result_api.store(result)
+ pod_stats = pod_status(pod)
+ if pod_stats['criteria'] == 'fail':
+ pod_stats['logs'] = get_logs(pod)
+ result['criteria'] = 'fail'
+ result['details'].append(pod_stats)
+
+
+ store_result(result)
+ return result
@@ -43,14 +61,13 @@ def pod_status(pod):
"""
Check health of a pod and returns it's status as result
"""
- result = {'state': 'ok',
- 'kind': 'pod',
+ result = {'criteria': 'pass',
'name': pod.metadata.name,
'namespace': pod.metadata.namespace,
'node': pod.spec.node_name}
if pod.status.container_statuses is None:
- result['state'] = 'fail'
+ result['criteria'] = 'fail'
result['pod_details'] = rfile(str(pod))
else:
for container in pod.status.container_statuses:
@@ -62,14 +79,14 @@ def pod_status(pod):
status = container.state.waiting.reason
if status not in ('Running', 'Completed'):
- result['state'] = 'fail'
+ result['criteria'] = 'fail'
result['pod_details'] = rfile(str(pod))
- info = f'[Health: {result["state"]}] Name: {result["name"]}, '
+ info = f'[Health: {result["criteria"]}] Name: {result["name"]}, '
info = info + f'Namespace: {result["namespace"]}, Node: {result["node"]}'
logger = logging.getLogger(__name__)
- logger.info(info)
+ logger.debug(info)
return result
diff --git a/sdv/docker/sdvstate/validator/airship/store_result.py b/sdv/docker/sdvstate/validator/airship/store_result.py
new file mode 100644
index 0000000..52f4e10
--- /dev/null
+++ b/sdv/docker/sdvstate/validator/airship/store_result.py
@@ -0,0 +1,28 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+store_result function to log and store result
+"""
+import logging
+from tools.result_api import result_api
+
+def store_result(result):
+ """
+ Logs and stores result
+ """
+ logger = logging.getLogger(__name__)
+ logger.info(f'[State: {result["criteria"]}] {result["case_name"]}')
+
+ result_api.store(result)
diff --git a/sdv/docker/sdvurls/Dockerfile b/sdv/docker/sdvurls/Dockerfile
new file mode 100644
index 0000000..e6d447a
--- /dev/null
+++ b/sdv/docker/sdvurls/Dockerfile
@@ -0,0 +1,10 @@
+FROM python:3.8-slim-buster
+
+WORKDIR /sdvurls/
+
+COPY requirements.txt /state/requirements.txt
+RUN pip install -r requirements.txt
+
+COPY server /sdvurls/
+
+CMD [ "python", "/sdvurls/server" ]
diff --git a/sdv/docker/sdvurls/requirements.txt b/sdv/docker/sdvurls/requirements.txt
new file mode 100644
index 0000000..c38d2e9
--- /dev/null
+++ b/sdv/docker/sdvurls/requirements.txt
@@ -0,0 +1,13 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
+# Copyright (c) 2020 Spirent Communications
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+
+tornado == 6.0.4
+urllib3 # MIT
+GitPython;python_version>='3.0' # BSD License (3 clause)
diff --git a/sdv/docker/sdvurls/server b/sdv/docker/sdvurls/server
new file mode 100644
index 0000000..8d3ec7a
--- /dev/null
+++ b/sdv/docker/sdvurls/server
@@ -0,0 +1,281 @@
+# Copyright 2020 Spirent Communications.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Airship implementation of Software Predeployment Validation
+"""
+
+import os
+import shutil
+from pathlib import Path
+import logging
+import json
+import git
+import urllib3
+
+from tornado.web import Application
+from tornado.ioloop import IOLoop
+import tornado.concurrent
+import tornado.httpserver
+import tornado.ioloop
+import tornado.options
+import tornado.web
+import tornado.log
+
+
+def check_link(link):
+ """
+ Function the check the availability of Hyperlinks
+ """
+ timeout = urllib3.util.Timeout(connect=5.0, read=7.0)
+ http = urllib3.PoolManager(timeout=timeout)
+ try:
+ http.request('HEAD', link)
+ except urllib3.exceptions.LocationValueError as err:
+ print(err.args)
+ return False
+ except urllib3.exceptions.MaxRetryError as err:
+ print(err.args)
+ return False
+ except urllib3.exceptions.RequestError as err:
+ print(err.args)
+ return False
+ except urllib3.exceptions.ConnectTimeoutError as err:
+ print(err.args)
+ return False
+ except urllib3.exceptions.PoolError as err:
+ print(err.args)
+ return False
+ except urllib3.exceptions.HTTPError as err:
+ print(err.args)
+ return False
+ return True
+
+
+class Airship():
+ """
+ Ariship URLS Validation
+ """
+ def __init__(self, params):
+ """ Airship class constructor """
+ self.url = params['AIRSHIP_MANIFEST_URL']
+ self.branch = params['AIRSHIP_MANIFEST_BRANCH']
+ self.dl_path = '/tmp'
+ self.site_name = params['AIRSHIP_MANIFEST_SITE_NAME']
+ self.tmversion = params['AIRSHIP_TREASUREMAP_VERSION']
+ self.manifest = None
+ self.dirpath = Path(self.dl_path, 'airship')
+ self.tmdirpath = Path(self.dl_path, 'treasuremap')
+ self.locations = []
+ self.validcount = 0
+ self.invalidcount = 0
+ self.respath = os.path.join(self.dl_path, ('urls-' +
+ self.site_name +
+ '-check.txt'))
+
+ def clone_repo(self):
+ """
+ Cloning the repos
+ """
+ git.Repo.clone_from(self.url,
+ self.dirpath,
+ branch=self.branch)
+ git.Repo.clone_from('https://github.com/airshipit/treasuremap',
+ self.tmdirpath,
+ branch=self.tmversion)
+
+ def cleanup_manifest(self):
+ """
+ Remove existing manifests
+ """
+ # Next Remove any manifest files, if it exists
+ if self.dirpath.exists() and self.dirpath.is_dir():
+ shutil.rmtree(self.dirpath)
+ if self.tmdirpath.exists() and self.tmdirpath.is_dir():
+ shutil.rmtree(self.tmdirpath)
+
+ def manifest_exists_locally(self):
+ """
+ Check if manifests exists locally
+ """
+ if self.dirpath.exists() and self.dirpath.is_dir():
+ return True
+ return False
+
+ def validate(self):
+ """
+ Hyperlink Validation
+ """
+ self.cleanup_manifest()
+ # Next, clone the repo to the provided path.
+ self.clone_repo()
+
+ if self.dirpath.exists() and self.dirpath.is_dir():
+ # Get the file(s) where links are defined.
+ self.find_locations(
+ os.path.join(self.dirpath, 'type',
+ 'cntt', 'software',
+ 'config', 'versions.yaml'))
+ self.find_locations(
+ os.path.join(self.tmdirpath, 'global',
+ 'software', 'config', 'versions.yaml'))
+
+ with open(self.respath, "w+") as report:
+ for location in self.locations:
+ if check_link(location):
+ report.write("The Link: %s is VALID" % (location))
+ self.validcount += 1
+ else:
+ self.invalidcount += 1
+ report.write("The Link: %s is INVALID" % (location))
+ self.cleanup_manifest()
+
+ def getresults(self):
+ """
+ Return Valid and Invalid Counts
+ """
+ return(self.validcount, self.invalidcount)
+
+ # pylint: disable=consider-using-enumerate
+ def find_locations(self, yamlfile):
+ """
+ Find all the hyperlinks in the manifests
+ """
+ with open(yamlfile, 'r') as filep:
+ lines = filep.readlines()
+ for index in range(len(lines)):
+ line = lines[index].strip()
+ if line.startswith('location:'):
+ link = line.split(":", 1)[1]
+ if "opendev" in link:
+ if ((len(lines) > index+1) and
+ (lines[index+1].strip().startswith(
+ 'reference:'))):
+ ref = lines[index+1].split(":", 1)[1]
+ link = link + '/commit/' + ref.strip()
+ if link.strip() not in self.locations:
+ print(link)
+ self.locations.append(link.strip())
+ if 'docker.' in line:
+ link = line.split(":", 1)[1]
+ link = link.replace('"', '')
+ parts = link.split('/')
+ if len(parts) == 3:
+ link = ('https://index.' +
+ parts[0].strip() +
+ '/v1/repositories/' +
+ parts[1] + '/' + parts[2].split(':')[0] +
+ '/tags/' + parts[2].split(':')[-1])
+ if link.strip() not in self.locations:
+ print(link)
+ self.locations.append(link.strip())
+ # quay.io/coreos/etcd:v3.4.2
+ # https://quay.io/api/v1/repository/coreos/etcd/tag/v3.4.2
+ if 'quay.' in line:
+ link = line.split(":", 1)[1]
+ link = link.replace('"', '')
+ parts = link.split('/')
+ if len(parts) == 3:
+ link = ('https://' +
+ parts[0].strip() +
+ '/api/v1/repository/' +
+ parts[1] + '/' + parts[2].split(':')[0] +
+ '/tag/' + parts[2].split(':')[-1])
+ if link.strip() not in self.locations:
+ print(link)
+ self.locations.append(link.strip())
+
+
+# pylint: disable=W0223
+class AirshipUrlsValidator(tornado.web.RequestHandler):
+ """ Validate URLS """
+ def set_default_headers(self):
+ """ set default headers"""
+ self.set_header('Content-Type', 'application/json')
+
+ def post(self):
+ """
+ POST request
+ usage:
+ /airship/?name='' installer='' link='' version=''
+ :return: logs from test results
+ """
+ # decode the body
+ data = json.loads(self.request.body.decode())
+ params = {}
+ branch = 'master'
+ installer = data['installer']
+ name = data['name']
+ link = data['link']
+ version = data['version']
+ if installer and 'airship' in installer.lower():
+ if name and link and branch and version:
+ params['AIRSHIP_MANIFEST_URL'] = link
+ params['AIRSHIP_MANIFEST_BRANCH'] = branch
+ params['AIRSHIP_MANIFEST_SITE_NAME'] = name
+ params['AIRSHIP_TREASUREMAP_VERSION'] = version
+ airship = Airship(params)
+ airship.validate()
+ valid, invalid = airship.getresults()
+ self.write("Valid Links: " +
+ str(valid) +
+ " Invalid Links: " +
+ str(invalid))
+
+
+# pylint: disable=W0223
+class TripleoUrlsValidator(tornado.web.RequestHandler):
+ """ Validate URLS """
+
+ def post(self):
+ """
+ POST request
+ """
+ self.write('error: Not Implemented')
+
+
+def main():
+ """ The Main Control """
+ app = Application([('/airship', AirshipUrlsValidator),
+ ('/tripleo', TripleoUrlsValidator)])
+
+ # Cli Config
+ tornado.options.define("port", default=8989,
+ help="running on the given port", type=int)
+ tornado.options.parse_command_line()
+
+ # Server Config
+ http_server = tornado.httpserver.HTTPServer(app)
+ http_server.listen(tornado.options.options.port)
+
+ # Tornado's event loop handles it from here
+ print("# Server Listening.... \n [Ctrl + C] to quit")
+
+ # Logging
+ log_file_filename = "/var/log/tornado.log"
+ handler = logging.FileHandler(log_file_filename)
+ app_log = logging.getLogger("tornado.general")
+ tornado.log.enable_pretty_logging()
+ app_log.addHandler(handler)
+
+ try:
+ tornado.ioloop.IOLoop.instance().start()
+ except KeyboardInterrupt:
+ tornado.ioloop.IOLoop.instance().stop()
+
+ # start
+ IOLoop.instance().start()
+
+if __name__ == "__main__":
+ main()
diff --git a/sdv/docs/docker/urls/userguide.rst b/sdv/docs/docker/urls/userguide.rst
new file mode 100644
index 0000000..15d0724
--- /dev/null
+++ b/sdv/docs/docker/urls/userguide.rst
@@ -0,0 +1,24 @@
+********************************************************
+CIRV-SDV: Validating the URLs in the Installer Manifests
+********************************************************
+
+Supported Installer Manifest: Airship.
+
+Building and starting the container:
+* Go to folder sdv/docker/sdvurls
+* Build the container with 'docker build' command. Consider naming/tagging the container properly.
+* Run the container using docker run. The container creates a report under /tmp folder. Hence, consider mapping a volume to '/tmp' folder to get the report.
+
+
+Interacting with the container
+##############################
+Inputs:
+
+* Installer Used. Keyword: "installer". Example Value: "airship". This is mandatory
+* Link to the installer manifests. Keyword: "link". Example Value: "https://gerrit.opnfv.org/gerrit/airship". This is mandatory
+* Version (For Airship, this refers to Treasuremap Version). Keyword: "version". Example Value: "v1.7". This is mandatory only for Airship.
+* Name of the site. Keyword: "name". Example Value: "intel-pod10". This is mandatory only for Airship
+
+Assuming the container is running locally, the example command would be::
+
+ curl --header "Content-Type: application/json" --redata '{"installer":"airship", "link":"https://gerrit.opnfv.org/gerrit/airship", "version":"v1.7", "name":"intel-pod10"}' http://localhost:8989/airship
diff --git a/sdv/docs/pdf/user/userguide.rst b/sdv/docs/pdf/user/userguide.rst
new file mode 100644
index 0000000..2394888
--- /dev/null
+++ b/sdv/docs/pdf/user/userguide.rst
@@ -0,0 +1,29 @@
+*******************************************
+Platform Descriptor File (PDF) : User Guide
+*******************************************
+
+Using the PDF template
+######################
+Please follow these steps.
+
+* Go to sdv/pdf/template folder.
+* Make a copy of it using site name ::
+
+
+ cp pdf_template.json <sitename_pdf>.json.
+
+* Fill all the values.
+
+* Use the <sitename_pdf>.json with sdvconfig tool to extrapolate the pdf. Refer to sdvconfig documentation.
+* PDF is ready to use.
+
+Using GUI to create platform-description
+########################################
+Please follow these steps.
+
+* Go to sdv/pdf/site folder.
+* Open index.html with any browser.
+* Follow the guidelines and fill all the values.
+* Click Submit and Download. File named sitepdf.json will be downloaded.
+* Use the sitepdf.json with sdvconfig tool to extrapolate the pdf. Refer to sdvconfig documentation.
+* PDF is ready to use.
diff --git a/sdv/pdf/site/assets/pdfrep.png b/sdv/pdf/site/assets/pdfrep.png
new file mode 100755
index 0000000..ed144f3
--- /dev/null
+++ b/sdv/pdf/site/assets/pdfrep.png
Binary files differ
diff --git a/sdv/pdf/site/assets/plus-circle-solid.svg b/sdv/pdf/site/assets/plus-circle-solid.svg
new file mode 100644
index 0000000..39a0f8e
--- /dev/null
+++ b/sdv/pdf/site/assets/plus-circle-solid.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:version="1.0 (6e3e5246a0, 2020-05-07)"
+ sodipodi:docname="plus-circle-solid.svg"
+ id="svg4"
+ version="1.1"
+ viewBox="0 0 512 512"
+ role="img"
+ class="svg-inline--fa fa-plus-circle fa-w-16"
+ data-icon="plus-circle"
+ data-prefix="fas"
+ focusable="false"
+ aria-hidden="true">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ inkscape:current-layer="svg4"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:cy="256"
+ inkscape:cx="114.5679"
+ inkscape:zoom="1.265625"
+ showgrid="false"
+ id="namedview6"
+ inkscape:window-height="794"
+ inkscape:window-width="1600"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0"
+ guidetolerance="10"
+ gridtolerance="10"
+ objecttolerance="10"
+ borderopacity="1"
+ bordercolor="#666666"
+ pagecolor="#ffffff" />
+ <path
+ style="fill:#61b9ff;fill-opacity:1"
+ id="path2"
+ d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"
+ fill="currentColor" />
+</svg>
diff --git a/sdv/pdf/site/assets/plus-square-regular.svg b/sdv/pdf/site/assets/plus-square-regular.svg
new file mode 100644
index 0000000..b9e300d
--- /dev/null
+++ b/sdv/pdf/site/assets/plus-square-regular.svg
@@ -0,0 +1 @@
+<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="plus-square" class="svg-inline--fa fa-plus-square fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M352 240v32c0 6.6-5.4 12-12 12h-88v88c0 6.6-5.4 12-12 12h-32c-6.6 0-12-5.4-12-12v-88h-88c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h88v-88c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v88h88c6.6 0 12 5.4 12 12zm96-160v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"></path></svg> \ No newline at end of file
diff --git a/sdv/pdf/site/assets/redo-alt-solid.svg b/sdv/pdf/site/assets/redo-alt-solid.svg
new file mode 100644
index 0000000..b8e9455
--- /dev/null
+++ b/sdv/pdf/site/assets/redo-alt-solid.svg
@@ -0,0 +1 @@
+<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="redo-alt" class="svg-inline--fa fa-redo-alt fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256.455 8c66.269.119 126.437 26.233 170.859 68.685l35.715-35.715C478.149 25.851 504 36.559 504 57.941V192c0 13.255-10.745 24-24 24H345.941c-21.382 0-32.09-25.851-16.971-40.971l41.75-41.75c-30.864-28.899-70.801-44.907-113.23-45.273-92.398-.798-170.283 73.977-169.484 169.442C88.764 348.009 162.184 424 256 424c41.127 0 79.997-14.678 110.629-41.556 4.743-4.161 11.906-3.908 16.368.553l39.662 39.662c4.872 4.872 4.631 12.815-.482 17.433C378.202 479.813 319.926 504 256 504 119.034 504 8.001 392.967 8 256.002 7.999 119.193 119.646 7.755 256.455 8z"></path></svg> \ No newline at end of file
diff --git a/sdv/pdf/site/assets/trash-alt-regular.svg b/sdv/pdf/site/assets/trash-alt-regular.svg
new file mode 100644
index 0000000..fbce77b
--- /dev/null
+++ b/sdv/pdf/site/assets/trash-alt-regular.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:version="1.0 (6e3e5246a0, 2020-05-07)"
+ sodipodi:docname="trash-alt-regular.svg"
+ id="svg4"
+ version="1.1"
+ viewBox="0 0 448 512"
+ role="img"
+ class="svg-inline--fa fa-trash-alt fa-w-14"
+ data-icon="trash-alt"
+ data-prefix="far"
+ focusable="false"
+ aria-hidden="true">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ inkscape:current-layer="svg4"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:cy="192.79012"
+ inkscape:cx="224"
+ inkscape:zoom="1.265625"
+ showgrid="false"
+ id="namedview6"
+ inkscape:window-height="794"
+ inkscape:window-width="1600"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0"
+ guidetolerance="10"
+ gridtolerance="10"
+ objecttolerance="10"
+ borderopacity="1"
+ bordercolor="#666666"
+ pagecolor="#ffffff" />
+ <path
+ style="fill:#ff6161;fill-opacity:1"
+ id="path2"
+ d="M268 416h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12zM432 80h-82.41l-34-56.7A48 48 0 0 0 274.41 0H173.59a48 48 0 0 0-41.16 23.3L98.41 80H16A16 16 0 0 0 0 96v16a16 16 0 0 0 16 16h16v336a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128h16a16 16 0 0 0 16-16V96a16 16 0 0 0-16-16zM171.84 50.91A6 6 0 0 1 177 48h94a6 6 0 0 1 5.15 2.91L293.61 80H154.39zM368 464H80V128h288zm-212-48h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12z"
+ fill="currentColor" />
+</svg>
diff --git a/sdv/pdf/site/index.html b/sdv/pdf/site/index.html
new file mode 100644
index 0000000..fe88f29
--- /dev/null
+++ b/sdv/pdf/site/index.html
@@ -0,0 +1,1797 @@
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Cloud Platform Description</title>
+ <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+ <meta content="utf-8" http-equiv="encoding">
+
+ <link rel="stylesheet" href="style/multitab.css">
+ <link rel="stylesheet" href="style/array.css">
+ <script src="scripts/actions.js"></script>
+ <script src="scripts/readFromHTML.js"></script>
+ <script src="scripts/writeToHTML.js"></script>
+ <script src="scripts/mergeDeep.js"></script>
+ <script src="scripts/createfile.js"></script>
+<script>
+ window.console = window.console || function(t) {};
+</script>
+<script>
+ if (document.location.search.match(/type=embed/gi)) {
+ window.parent.postMessage("resize", "*");
+ }
+</script>
+</head>
+<body translate="no">
+<div class="form-area">
+ <div class="form-header">
+ <div class="top-header">
+ <div class="devider-row">
+ <div class="half-2">
+ <!-- <div class="logo-area">
+ <h1><a href="javascript:;">Cloud Platform Description</a></h1>
+ </div>
+ -->
+ <div class="logo-area">
+ <h1>Cloud Platform Description</h1>
+ </div>
+ </div>
+ <div class="half-2">
+ <div class="need-help">
+ <a href="javascript:;">About PDF <i>?</i></a>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="bottom-header">
+ <div class="devider-row">
+ <div class="half-2">
+ <div class="status">
+ <h3> Guidelines: </h2>
+ <ul>
+ <li> Please add the values correctly - No validations are included in this version. </li>
+ <li> The Deployment can be OOO, OOK, OWK or OaV. In the first three deployments, openstack services are deployed as containers. </li>
+ <li> Block Storage method is either rbd or iscsi </li>
+ <li> Example Power-state prefetcher setting: C4_C6_MLC-STR_MLC-SPA_DCU_DCA_RAS_TURBO </li>
+ <li> Under Physical Network please include IPMI Network Information too. </li>
+ <li> A network link could be a trunk, bond, interface or a bridge. </li>
+ <li> Please click of Submit button before clicking the Dowload button. </li>
+
+ </ul>
+ </div>
+ </div>
+ <div class="half-2">
+ <img src="assets/pdfrep.png" style="margin:auto; width:500px;height=400px;display:block" />
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="form-body">
+ <div class="multitab-form-area">
+ <div class="tab-links-area">
+ <h1>PDF 2.0</h1>
+ <p>Platform Description Categories</p>
+ <hr>
+ <ul>
+ <li><a data-toggle="formtab" href="#mgmtinfo" class="active">Management Information</a></li>
+ <li><a data-toggle="formtab" href="#userInfo">User Information</a></li>
+ <li><a data-toggle="formtab" href="#ntpInfo">NTP Information</a></li>
+ <li><a data-toggle="formtab" href="#dnsInfo">DNS Information</a></li>
+ <li><a data-toggle="formtab" href="#proxyInfo">Proxy Information</a></li>
+ <li><a data-toggle="formtab" href="#ldapInfo">LDAP Information</a></li>
+ <li><a data-toggle="formtab" href="#vimInfo">VIM Information</a></li>
+ <li><a data-toggle="formtab" href="#vimfInfo">VIM Functional Info</a></li>
+ <li><a data-toggle="formtab" href="#deployInfo">Deployment Information</a></li>
+ <li><a data-toggle="formtab" href="#jumpInfo">Jump Host Information</a></li>
+ <li><a data-toggle="formtab" href="#rackInfo">Rack Information</a></li>
+ <li><a data-toggle="formtab" href="#stocluInfo">Storage Cluster Information</a></li>
+ <li><a data-toggle="formtab" href="#biosProfiles">BIOS Profiles</a></li>
+ <li><a data-toggle="formtab" href="#procProfiles">Processor Profiles</a></li>
+ <li><a data-toggle="formtab" href="#disksProfiles">Disks Profiles</a></li>
+ <li><a data-toggle="formtab" href="#nicProfiles">NIC Profiles</a></li>
+ <li><a data-toggle="formtab" href="#hwProfiles">Hardware Profiles</a></li>
+ <li><a data-toggle="formtab" href="#storprofiles">Storage Profiles</a></li>
+ <li><a data-toggle="formtab" href="#virNets">Networks</a></li>
+ <li><a data-toggle="formtab" href="#phyNets">Physical Networks</a></li>
+ <li><a data-toggle="formtab" href="#netLinks">Network Links</a></li>
+ <li><a data-toggle="formtab" href="#ifMap">Interface Mapping Profiles</a></li>
+ <li><a data-toggle="formtab" href="#pfProfiles">Platform Profiles</a></li>
+ <li><a data-toggle="formtab" href="#ucOok">Undercloud OOK</a></li>
+ <li><a data-toggle="formtab" href="#ucOoo">Undercloud OOO</a></li>
+ <li><a data-toggle="formtab" href="#usSw">Undercloud Software Profiles</a></li>
+ <li><a data-toggle="formtab" href="#osSw">Openstack Sofware Profiles</a></li>
+ <li><a data-toggle="formtab" href="#infSw">Infra Software Profiles</a></li>
+ <li><a data-toggle="formtab" href="#swSet">Software Sets</a></li>
+ <li><a data-toggle="formtab" href="#roles">Roles</a></li>
+ <li><a data-toggle="formtab" href="#extraPo">Extrapolation Info</a></li>
+ <li><a data-toggle="formtab" href="#hostAg">Host Aggregates</a></li>
+ </ul>
+ </div>
+ <div class="tab-form-area" id="pdfform">
+ <div class="tabs-panels active" id="mgmtinfo">
+ <div class="tab-part">
+ <h4>Management Information</h4>
+ <hr>
+ <div class="devider-row" name="mgmt_profile">
+ <div class="form-field">
+ <label>Owner</label>
+ <input type="text" placeholder="Contact Name" name="owner">
+ </div>
+ <div class="form-field">
+ <label>Area Name</label>
+ <input type="text" placeholder="Region Name" name="area_name">
+ </div>
+ <div class="form-field">
+ <label>Area Center Name</label>
+ <input type="text" placeholder="Region Center" name="area_center_name">
+ </div>
+ <div class="form-field">
+ <label>Room ID</label>
+ <input type="text" placeholder="00000" name="room_id">
+ </div>
+ <div class="form-field">
+ <label>City</label>
+ <input type="text" placeholder="Bangalore" name="city">
+ </div>
+ <div class="form-field">
+ <label>Resource Pool Name</label>
+ <input type="text" placeholder="EPG" name="resource_pool_name">
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#userInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="userInfo">
+ <div class="tab-part">
+ <h4> User Information </h4>
+ <hr>
+ <div class="arr" name="user_info">
+ <div class="form-field">
+ <label>Username</label>
+ <input type="text" placeholder="sridhar" name="username">
+ </div>
+ <div class="form-field">
+ <label>Password</label>
+ <input type="text" placeholder="*******" name="password">
+ </div>
+ <div class="form-field">
+ <label>Public Key</label>
+ <input type="text" rows="4" cols="60" name="pub_key">
+ </div>
+ <div class="form-field">
+ <label>Pass-Phrase</label>
+ <input type="text" placeholder="Spirent" name="name">
+ </div>
+ <div class="form-field">
+ <label>TLS CA Cert</label>
+ <input type="text" name="tls_ca_cert">
+ </div>
+ <div class="form-field">
+ <label>TLS Cert</label>
+ <input type="text" name="tls_cert">
+ </div>
+ <div class="form-field">
+ <label>TLS Key</label>
+ <input type="text" name="tls_key">
+ </div>
+ <div class="form-field">
+ <label>Email</label>
+ <input type="text" placeholder="sridhar.rao@spirent.com" name="email">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#ntpInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="ntpInfo">
+ <div class="tab-part">
+ <h4> NTP Information </h4>
+ <hr>
+ <div class="devider-row" name="ntp_info">
+ <div class="form-field">
+ <label>Primary IP</label>
+ <input type="text" placeholder="a:b:c:d" name="primary_ip">
+ </div>
+ <div class="form-field">
+ <label>Primary Zone</label>
+ <input type="text" placeholder="Zone-A" name="primary_zone">
+ </div>
+ <div class="form-field">
+ <label>Secondary IP</label>
+ <input type="text" placeholder="a:b:c:d" name="secondary_ip">
+ </div>
+ <div class="form-field">
+ <label>Secondary Zone</label>
+ <input type="text" placeholder="Zone-B" name="secondary_zone">
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#dnsInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="dnsInfo">
+ <div class="tab-part">
+ <h4> DNS Information</h4>
+ <hr>
+ <div class="devider-row" name="dns_info">
+ <div class="form-field">
+ <label>Name</label>
+ <input type="text" placeholder="Telco-A" name="name">
+ </div>
+ <div class="form-field">
+ <label>domain</label>
+ <input type="text" placeholder="Domain-A" name="domain">
+ </div>
+ <div class="form-field">
+ <label>Servers</label>
+ </div>
+ <div class="arr" name="servers">
+ <div class="form-field">
+ <label>IP Address</label>
+ <input type="text" placeholder="a:b:c:d" name="ip">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#proxyInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="proxyInfo">
+ <div class="tab-part">
+ <h4> Proxy Information </h4>
+ <hr>
+ <div class="devider-row" name="proxy_info">
+ <div class="form-field">
+ <label>Proxy Address</label>
+ <input type="text" placeholder="a:b:c:d" name="address">
+ </div>
+ <div class="form-field">
+ <label>Port </label>
+ <input type="text" placeholder="8081" name="port">
+ </div>
+ <div class="form-field">
+ <label>Username</label>
+ <input type="text" placeholder="Sridhar" name="user">
+ </div>
+ <div class="form-field">
+ <label>Password</label>
+ <input type="text" placeholder="******" name="password">
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#ldapInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="ldapInfo">
+ <div class="tab-part">
+ <h4> LDAP Information </h4>
+ <hr>
+ <div class="devider-row" name="ldap_info">
+ <div class="form-field">
+ <label>Base URL</label>
+ <input type="text" placeholder="a:b:c:d" name="base_url">
+ </div>
+ <div class="form-field">
+ <label>URL</label>
+ <input type="text" placeholder="Zone-A" name="url">
+ </div>
+ <div class="form-field">
+ <label>Authentication Path</label>
+ <input type="text" placeholder="a:b:c:d" name="auth_path">
+ </div>
+ <div class="form-field">
+ <label>Common Name</label>
+ <input type="text" placeholder="Zone-B" name="common_name">
+ </div>
+ <div class="form-field">
+ <label>Sub-Domain </label>
+ <input type="text" placeholder="a:b:c:d" name="subdomain">
+ </div>
+ <div class="form-field">
+ <label>Domain</label>
+ <input type="text" placeholder="Zone-B" name="domain">
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#vimInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="vimInfo">
+ <div class="tab-part">
+ <h4> VIM Information </h4>
+ <hr>
+ <div class="devider-row" name="vim_info">
+ <div class="form-field">
+ <label> VIM Name </label>
+ <input type="text" placeholder=" " name="vim_name">
+ </div>
+ <div class="form-field">
+ <label>VIM ID </label>
+ <input type="text" placeholder=" " name="vim_id">
+ </div>
+ <div class="form-field">
+ <label> Vendor </label>
+ <input type="text" placeholder=" " name="vendor">
+ </div>
+ <div class="form-field">
+ <label> Version </label>
+ <input type="text" placeholder=" " name="version">
+ </div>
+ <div class="form-field">
+ <label> Installer </label>
+ <input type="text" placeholder=" " name="installer">
+ </div>
+ <div class="form-field">
+ <label> Deployment Style </label>
+ <input type="text" placeholder=" " name="deployment_style">
+ </div>
+ <div class="form-field">
+ <label> Container Orchestrator </label>
+ <input type="text" placeholder=" " name="container_orchestrator">
+ </div>
+ <div class="form-field">
+ <label> Storage Type </label>
+ <input type="text" placeholder=" " name="storage_type">
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#vimfInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="vimfInfo">
+ <div class="tab-part">
+ <h4> VIM Functional Information </h4>
+ <hr>
+ <div class="devider-row" name="vim_functional_info">
+ <div class="form-field">
+ <label>Scheduler Filters </label>
+ <input type="text" placeholder=" " name="schedule_filters">
+ </div>
+ <div class="form-field">
+ <label> CPU Allocation Ratio </label>
+ <input type="text" placeholder=" " name="cpu_allocation_ratio">
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#deployInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="deployInfo">
+ <div class="tab-part">
+ <h4> Deployment Information </h4>
+ <hr>
+ <div class="devider-row" name="deployment_info">
+ <div class="form-field">
+ <label> High Availability (Y/N) </label>
+ <input type="text" placeholder=" " name="high_availability">
+ </div>
+ <div class="form-field">
+ <label> Introspection </label>
+ <input type="text" placeholder=" " name="introspection">
+ </div>
+ <div class="form-field">
+ <label> Deployment Type</label>
+ <input type="text" placeholder=" " name="deployment_type">
+ </div>
+ <div class="form-field">
+ <label> Installer Used </label>
+ <input type="text" placeholder=" " name="installer_used">
+ </div>
+ <div class="form-field">
+ <label> Workload VNF (Y/N) </label>
+ <input type="text" placeholder=" " name="workload_vnf">
+ </div>
+ <div class="form-field">
+ <label> Workload CNF (Y/N)</label>
+ <input type="text" placeholder=" " name="workload_cnf">
+ </div>
+ <div class="form-field">
+ <label> SDN Controller (Y/N)</label>
+ <input type="text" placeholder=" " name="sdn_controller">
+ </div>
+ <div class="form-field">
+ <label> SDN Controller Version </label>
+ <input type="text" placeholder=" " name="sdn_controller_version">
+ </div>
+ <div class="form-field">
+ <label> SDN NB-APPs </label>
+ <input type="text" placeholder=" " name="sdn_controller_nbapps">
+ </div>
+ <div class="form-field">
+ <label> VNFM (Y/N) </label>
+ <input type="text" placeholder=" " name="vnfm">
+ </div>
+ <div class="form-field">
+ <label> VNFM Version </label>
+ <input type="text" placeholder=" " name="vnfm_version">
+ </div>
+ <div class="form-field">
+ <label> Dataplane Used</label>
+ <input type="text" placeholder=" " name="data_plane_used">
+ </div>
+ <div class="form-field">
+ <label> Ironic Deployment Interface</label>
+ <input type="text" placeholder=" " name="ironic_deploy_interface">
+ </div>
+ <div class="form-field">
+ <label> External Storage Cluster (Y/N) </label>
+ <input type="text" placeholder=" " name="external_storage_cluster">
+ </div>
+ <div class="form-field">
+ <label> Block Storage Connection Method</label>
+ <input type="text" placeholder=" " name="bl_str_connect_method">
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#jumpInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="jumpInfo">
+ <div class="tab-part">
+ <h4> Jump Host Information </h4>
+ <hr>
+ <div class="devider-row" name="jumphost_info">
+ <div class="form-field">
+ <label> IP Address </label>
+ <input type="text" placeholder=" " name="ip">
+ </div>
+ <div class="form-field">
+ <label> Name of the Server </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#rackInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="rackInfo">
+ <div class="tab-part">
+ <h4> Rack Information </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr" name="rack_info" >
+ <div class="form-field">
+ <label> Rack ID </label>
+ <input type="text" placeholder=" " name="rack_id">
+ </div>
+ <div class="form-field">
+ <label> Rack Details </label>
+ <hr>
+ <div class="form-field">
+ <label> Rack Name </label>
+ <input type="text" placeholder=" " name=" ">
+ </div>
+ <div class="form-field">
+ <label> Rack Description </label>
+ <input type="text" placeholder=" " name=" ">
+ </div>
+ <div class="form-field">
+ <label> Rack Availability Zone </label>
+ <input type="text" placeholder=" " name=" ">
+ </div>
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#stocluInfo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="stocluInfo">
+ <div class="tab-part">
+ <h4> Storage Cluster Information </h4>
+ <hr>
+ <div class="devider-row" name="storage_cluster_info">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Cluster Type </label>
+ <input type="text" placeholder=" " name="cluster_type">
+ </div>
+ <div class="form-field">
+ <label> Cluster ID </label>
+ <input type="text" placeholder=" " name="cluster_id">
+ </div>
+ <div class="form-field">
+ <label> Authentication Type </label>
+ <input type="text" placeholder=" " name="auth_type">
+ </div>
+ <div class="form-field">
+ <label> Username </label>
+ <input type="text" placeholder=" " name="username">
+ </div>
+ <div class="form-field">
+ <label> Password </label>
+ <input type="text" placeholder=" " name="password">
+ </div>
+ <div class="form-field">
+ <label> Monitoring Host IPs </label>
+ </div>
+ <div class="arr" name="mon_host_ips">
+ <div class="form-field">
+ <label>IP Address</label>
+ <input type="text" placeholder="a:b:c:d" name="ips">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ <div class="form-field">
+ <label> Certification Location </label>
+ <input type="text" placeholder=" " name="certificate_location">
+ </div>
+ <div class="form-field">
+ <label> Client Key </label>
+ <input type="text" placeholder=" " name="client_key">
+ </div>
+ <div class="form-field">
+ <label> Public CIDR </label>
+ <input type="text" placeholder=" " name="public_cidr">
+ </div>
+ <div class="form-field">
+ <label> Cluster CIDR </label>
+ <input type="text" placeholder=" " name="cluster_cidr">
+ </div>
+ <div class="form-field">
+ <label> Pools </label>
+ </div>
+ <div class="arr" name="pools">
+ <div class="form-field">
+ <label> Key </label>
+ <input type="text" placeholder=" " name="key">
+ </div>
+ <div class="form-field">
+ <label>Value </label>
+ <input type="text" placeholder=" " name="value">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#biosProfiles">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="biosProfiles">
+ <div class="tab-part">
+ <h4> BIOS Profiles </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr" name="bios_profile">
+ <div class="form-field">
+ <label>Profile Name </label>
+ <input type="text" placeholder=" " name="profile_name">
+ </div>
+ <div class="form-field">
+ <label> Bios Values </label>
+ <div class="form-field">
+ <label> Bios Version </label>
+ <input type="text" placeholder=" " name="bios_version">
+ </div>
+ <div class="form-field">
+ <label> Bios Mode </label>
+ <input type="text" placeholder=" " name="bios_mode">
+ </div>
+ <div class="form-field">
+ <label> Bootstrap Protocol </label>
+ <input type="text" placeholder=" " name="bootstrap_proto">
+ </div>
+ <div class="form-field">
+ <label> Hyperthreading Enabled (Y/N) </label>
+ <input type="text" placeholder=" " name="hyperthreading_enabled">
+ </div>
+ <div class="form-field">
+ <label> Flags - Power-Prefetcher combo </label>
+ <input type="text" placeholder=" " name="bios_setting">
+ </div>
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#procProfiles">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="procProfiles">
+ <div class="tab-part">
+ <h4> Processor Profiles </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr" name="processor_profiles">
+ <div class="form-field">
+ <label> Profile Name </label>
+ <input type="text" placeholder=" " name="profile_name">
+ </div>
+ <div class="form-field">
+ <label> Profile Info </label>
+ <div class="form-field">
+ <label> Manufacturer </label>
+ <input type="text" placeholder=" " name="manufacturer">
+ </div>
+ <div class="form-field">
+ <label> Generation </label>
+ <input type="text" placeholder=" " name="generation">
+ </div>
+ <div class="form-field">
+ <label> Speed </label>
+ <input type="text" placeholder=" " name="speed">
+ </div>
+ <div class="form-field">
+ <label> Model </label>
+ <input type="text" placeholder=" " name="model">
+ </div>
+ <div class="form-field">
+ <label> Architecture </label>
+ <input type="text" placeholder=" " name="architecture">
+ </div>
+ <div class="form-field">
+ <label> CPU C-Flags </label>
+ <input type="text" placeholder=" " name="cpu_cflags">
+ </div>
+ <div class="form-field">
+ <label> Cache Size </label>
+ <input type="text" placeholder=" " name="cache_size">
+ </div>
+ <div class="form-field">
+ <label> NUMAs </label>
+ <div class="arr" name="numas">
+ <div class="form-field">
+ <label> NUMA Node-ID </label>
+ <input type="text" placeholder=" " name="node_id">
+ </div>
+ <div class="form-field">
+ <label> CPU SET </label>
+ <input type="text" placeholder=" " name="cpu_set">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#disksProfiles">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="disksProfiles">
+ <div class="tab-part">
+ <h4> Disk Profiles </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr" name="disk_profiles">
+ <div class="form-field">
+ <label> Profile Name </label>
+ <input type="text" placeholder=" " name="profile_name">
+ </div>
+ <div class="form-field">
+ <label> Profile Info </label>
+ </div>
+ <div class="arr" name="profile_info">
+ <div class="form-field">
+ <label> Alias </label>
+ <input type="text" placeholder=" " name="alias">
+ </div>
+ <div class="form-field">
+ <label> Vendor </label>
+ <input type="text" placeholder=" " name="vendor">
+ </div>
+ <div class="form-field">
+ <label> Address </label>
+ <input type="text" placeholder=" " name="address">
+ </div>
+ <div class="form-field">
+ <label> Size </label>
+ <input type="text" placeholder=" " name="size">
+ </div>
+ <div class="form-field">
+ <label> Model </label>
+ <input type="text" placeholder=" " name="model">
+ </div>
+ <div class="form-field">
+ <label> Device Type </label>
+ <input type="text" placeholder=" " name="dev_type">
+ </div>
+ <div class="form-field">
+ <label> Rotation </label>
+ <input type="text" placeholder=" " name="rotation">
+ </div>
+ <div class="form-field">
+ <label> Bus </label>
+ <input type="text" placeholder=" " name="bus">
+ </div>
+ <div class="form-field">
+ <label> Logical Name </label>
+ <input type="text" placeholder=" " name="logical_name">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#nicProfiles">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="nicProfiles">
+ <div class="tab-part">
+ <h4> NIC Profiles </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr" name = "nic_profiles">
+ <div class="form-field">
+ <label> Profile Name </label>
+ <input type="text" placeholder=" " name="profile_name">
+ </div>
+ <div class="form-field">
+ <label> Profile Info </label>
+ </div>
+ <div class="arr" name="profile_info">
+ <div class="form-field">
+ <label> Alias </label>
+ <input type="text" placeholder=" " name="alias">
+ </div>
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Address </label>
+ <input type="text" placeholder=" " name="address">
+ </div>
+ <div class="form-field">
+ <label> Device Type </label>
+ <input type="text" placeholder=" " name="dev_type">
+ </div>
+ <div class="form-field">
+ <label> Bus </label>
+ <input type="text" placeholder=" " name="bus">
+ </div>
+ <div class="form-field">
+ <label> SRIOV Capable (Y/N) </label>
+ <input type="text" placeholder=" " name="sriov_capable">
+ </div>
+ <div class="form-field">
+ <label> Numa ID </label>
+ <input type="text" placeholder=" " name="numa_id">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#hwProfiles">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="hwProfiles">
+ <div class="tab-part">
+ <h4> Hardware Profiles </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr">
+ <div class="form-field">
+ <label> Profile Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Profile Info </label>
+ <div class="form-field">
+ <label> Server Manufacturer </label>
+ <input type="text" placeholder=" " name="manufacturer">
+ </div>
+ <div class="form-field">
+ <label> Compute Server Model </label>
+ <input type="text" placeholder=" " name="model">
+ </div>
+ <div class="form-field">
+ <label> Compute Server Generation </label>
+ <input type="text" placeholder=" " name="generation">
+ </div>
+ <div class="form-field">
+ <label> Bios Profile</label>
+ <input type="text" placeholder=" " name="bios_profile">
+ </div>
+ <div class="form-field">
+ <label> Processor Profile </label>
+ <input type="text" placeholder=" " name="processor_profile">
+ </div>
+ <div class="form-field">
+ <label> Compute Server RAM size </label>
+ <input type="text" placeholder=" " name="memory">
+ </div>
+ <div class="form-field">
+ <label> Disks Profile </label>
+ <input type="text" placeholder=" " name="disks_profile">
+ </div>
+ <div class="form-field">
+ <label> NIC Profile</label>
+ <input type="text" placeholder=" " name="nics_profile">
+ </div>
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#storProfiles">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="storProfiles">
+ <div class="tab-part">
+ <h4> Storage Profiles </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr" name="storage_profile">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Boot Disk </label>
+ <input type="text" placeholder=" " name="bootdrive">
+ </div>
+ <div class="form-field">
+ <label> Boot Disk Partitions </label>
+ </div>
+ <div class="arr" name="bd_partitions">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Size </label>
+ <input type="text" placeholder=" " name="size">
+ </div>
+ <div class="form-field">
+ <label> Bootable (Y/N) </label>
+ <input type="text" placeholder=" " name="bootable">
+ </div>
+ <div class="form-field" name="filesystem">
+ <label> Filesystem </label>
+ <div class="form-field">
+ <label> Mount Point </label>
+ <input type="text" placeholder=" " name="mountpoint">
+ </div>
+ <div class="form-field">
+ <label> Filesystem Type </label>
+ <input type="text" placeholder=" " name="fstype">
+ </div>
+ <div class="form-field">
+ <label> Mount Options </label>
+ <input type="text" placeholder=" " name="mount_options">
+ </div>
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ <div class="form-field">
+ <label> Data Devices </label>
+ </div>
+ <div class="arr" name="data_devices">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Partitions </label>
+ </div>
+ <div class="arr" name="partitions">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Size </label>
+ <input type="text" placeholder=" " name="size">
+ </div>
+ <div class="form-field">
+ <label> File System </label>
+ <div class="form-field">
+ <label> Mountpoint </label>
+ <input type="text" placeholder=" " name="mountpoint">
+ </div>
+ <div class="form-field">
+ <label> Filesystem Type </label>
+ <input type="text" placeholder=" " name="fstype">
+ </div>
+ <div class="form-field">
+ <label> Mount Options </label>
+ <input type="text" placeholder=" " name="mount_options">
+ </div>
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ <div class="form-field">
+ <label> Jounal Devices </label>
+ </div>
+ <div class="arr" name="journal_devices">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Mapped OSDs </label>
+ <input type="text" placeholder=" " name="mapped_osds">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#virNets">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="virNets">
+ <div class="tab-part">
+ <h4> Virtual Networks </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr", name="networks">
+ <div class="form-field">
+ <label> Network Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Tunnel Type </label>
+ <input type="text" placeholder=" " name="tunnel_type">
+ </div>
+ <div class="form-field">
+ <label> Tunnel ID </label>
+ <input type="text" placeholder=" " name="tunnel_id">
+ </div>
+ <div class="form-field">
+ <label> Tunnel ID Range </label>
+ <input type="text" placeholder=" " name="tunnel_id_range">
+ </div>
+ <div class="form-field">
+ <label> MTU </label>
+ <input type="text" placeholder=" " name="mtu">
+ </div>
+ <div class="form-field">
+ <label> Route Domain </label>
+ <input type="text" placeholder=" " name="routedomain">
+ </div>
+ <div class="form-field">
+ <label> IPV4 CIDR </label>
+ <input type="text" placeholder=" " name="cidr">
+ </div>
+ <div class="form-field">
+ <label> IPV6 CIDR </label>
+ <input type="text" placeholder=" " name="v6_cidr">
+ </div>
+ <div class="form-field">
+ <label> DNS </label>
+ <input type="text" placeholder=" " name="dns">
+ </div>
+ <div class="form-field">
+ <label> VIPs </label>
+ </div>
+ <div class="arr" name="vips">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> IP </label>
+ <input type="text" placeholder=" " name="ip">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ <div class="form-field">
+ <label> Routes </label>
+ </div>
+ <div class="arr">
+ <div class="form-field" name="routes">
+ <label> Subnet </label>
+ <input type="text" placeholder=" " name="subnet">
+ </div>
+ <div class="form-field">
+ <label> Gateway </label>
+ <input type="text" placeholder=" " name="gateway">
+ </div>
+ <div class="form-field">
+ <label> Metric </label>
+ <input type="text" placeholder=" " name="metric">
+ </div>
+ <div class="form-field">
+ <label> Route Domain </label>
+ <input type="text" placeholder=" " name="routedomain">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ <div class="form-field">
+ <label> IPV4 Allocation Pools </label>
+ </div>
+ <div class="arr" name="allocation_pools">
+ <div class="form-field">
+ <label> Type </label>
+ <input type="text" placeholder=" " name="type">
+ </div>
+ <div class="form-field">
+ <label> Start </label>
+ <input type="text" placeholder=" " name="start">
+ </div>
+ <div class="form-field">
+ <label> End </label>
+ <input type="text" placeholder=" " name="end">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ <div class="form-field">
+ <label> IPV6 Allocation Pools </label>
+ </div>
+ <div class="arr" name="v6_allocation_pools">
+ <div class="form-field">
+ <label> Type </label>
+ <input type="text" placeholder=" " name="type">
+ </div>
+ <div class="form-field">
+ <label> Start </label>
+ <input type="text" placeholder=" " name="start">
+ </div>
+ <div class="form-field">
+ <label> End </label>
+ <input type="text" placeholder=" " name="end">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#phyNets">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="phyNets">
+ <div class="tab-part">
+ <h4> Physical Networks </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr", name="physical_networks">
+ <div class="form-field">
+ <label> Network Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> CIDR </label>
+ <input type="text" placeholder=" " name="cidr">
+ </div>
+ <div class="form-field">
+ <label> Tunnel ID </label>
+ <input type="text" placeholder=" " name="tpe">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#netLinks">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="netLinks">
+ <div class="tab-part">
+ <h4> Network Links </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr", name="network_link">
+ <div class="form-field">
+ <label> Link Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Link Type </label>
+ <input type="text" placeholder=" " name="type">
+ </div>
+ <div class="form-field">
+ <label> Bonding Mode </label>
+ <input type="text" placeholder=" " name="bonding_mode">
+ </div>
+ <div class="form-field">
+ <label> MTU </label>
+ <input type="text" placeholder=" " name="mtu">
+ </div>
+ <div class="form-field">
+ <label> Link Speed </label>
+ <input type="text" placeholder=" " name="linkspeed">
+ </div>
+ <div class="form-field">
+ <label> Trunking Mode </label>
+ <input type="text" placeholder=" " name="trunking_mode">
+ </div>
+ <div class="form-field">
+ <label> Trunking Default Network </label>
+ <input type="text" placeholder=" " name="trunking_default_nw">
+ </div>
+ <div class="form-field">
+ <label> VID </label>
+ <input type="text" placeholder=" " name="vid">
+ </div>
+ <div class="form-field">
+ <label> VF Count </label>
+ <input type="text" placeholder=" " name="vf_count">
+ </div>
+ <div class="form-field">
+ <label> Meta Data </label>
+ </div>
+ <div class="arr" name="metadata">
+ <div class="form-field">
+ <label> Key </label>
+ <input type="text" placeholder=" " name="key">
+ </div>
+ <div class="form-field">
+ <label> Value </label>
+ <input type="text" placeholder=" " name="value">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ <div class="form-field">
+ <label> Members </label>
+ </div>
+ <div class="arr" name="members">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Type </label>
+ <input type="text" placeholder=" " name="type">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#ifMap">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="ifMap">
+ <div class="tab-part">
+ <h4> Network-Interface Mapping </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr", name="interface_mapping_profiles">
+ <div class="form-field">
+ <label> Profile Name </label>
+ <input type="text" placeholder=" " name="profile_name">
+ </div>
+ <div class="form-field">
+ <label> Profile Data </label>
+ </div>
+ <div class="arr" name="profile_data">
+ <div class="form-field">
+ <label> Interface Name </label>
+ <input type="text" placeholder=" " name="interface_name">
+ </div>
+ <div class="form-field">
+ <label> Interface Type </label>
+ <input type="text" placeholder=" " name="interface_type">
+ </div>
+ <div class="form-field">
+ <label> Use DHCP (Y/N) </label>
+ <input type="text" placeholder=" " name="use_dhcp">
+ </div>
+ <div class="form-field">
+ <label> Networks </label>
+ </div>
+ <div class="arr" name="networks">
+ <div class="form-field">
+ <label> Network Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#pfProfiles">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="pfProfiles">
+ <div class="tab-part">
+ <h4> Platform Profiles </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr", name="platform_profiles">
+ <div class="form-field">
+ <label> Profile Name </label>
+ <input type="text" placeholder=" " name="profile_name">
+ </div>
+ <div class="form-field">
+ <label> Operating System </label>
+ <input type="text" placeholder=" " name="os">
+ </div>
+ <div class="form-field">
+ <label> Real-Time KVM (Y/N) </label>
+ <input type="text" placeholder=" " name="rt_kvm">
+ </div>
+ <div class="form-field">
+ <label> Kernel Version </label>
+ <input type="text" placeholder=" " name="kernel_version">
+ </div>
+ <div class="form-field">
+ <label> Kernel Parameters </label>
+ <input type="text" placeholder=" " name="kernel_parameters">
+ </div>
+ <div class="form-field">
+ <label> Isolated CPUs </label>
+ <input type="text" placeholder=" " name="isolated_cpus">
+ </div>
+ <div class="form-field">
+ <label> VNF Cores </label>
+ <input type="text" placeholder=" " name="vnf_cores">
+ </div>
+ <div class="form-field">
+ <label> OS reserved Cores </label>
+ <input type="text" placeholder=" " name="os_reserved_cores">
+ </div>
+ <div class="form-field">
+ <label> IOMMU (Y/N) </label>
+ <input type="text" placeholder=" " name="iommu">
+ </div>
+ <div class="form-field">
+ <label> vSwitch Daemon Cores </label>
+ <input type="text" placeholder=" " name="vswitch_daemon_cores">
+ </div>
+ <div class="form-field">
+ <label> vSwitch Type </label>
+ <input type="text" placeholder=" " name="vswitch_type">
+ </div>
+ <div class="form-field">
+ <label> vSwitch UIO Drivers </label>
+ <input type="text" placeholder=" " name="vswitch_uio_driver">
+ </div>
+ <div class="form-field">
+ <label> vSwitch Memory Channels </label>
+ <input type="text" placeholder=" " name="vswitch_mem_channels">
+ </div>
+ <div class="form-field">
+ <label> vSwitch Socket Memory </label>
+ <input type="text" placeholder=" " name="vswitch_socket_memory">
+ </div>
+ <div class="form-field">
+ <label> vSwitch PMD Cores </label>
+ <input type="text" placeholder=" " name="vswitch_pmd_cores">
+ </div>
+ <div class="form-field">
+ <label> vSwitch DPDK Lcores </label>
+ <input type="text" placeholder=" " name="vswitch_dpdk_lcores">
+ </div>
+ <div class="form-field">
+ <label> vSwitch DPDK Rxqs </label>
+ <input type="text" placeholder=" " name="vswitch_dpdk_rxqs">
+ </div>
+ <div class="form-field">
+ <label> vSwitch Options </label>
+ <input type="text" placeholder=" " name="vswitch_options">
+ </div>
+ <div class="form-field">
+ <label> Hugepage Count </label>
+ <input type="text" placeholder=" " name="hugepage_count">
+ </div>
+ <div class="form-field">
+ <label> Hugepages </label>
+ </div>
+ <div class="arr" name="hugepages">
+ <div class="form-field">
+ <label> Hugepage Count </label>
+ <input type="text" placeholder=" " name="hugepage_count">
+ </div>
+ <div class="form-field">
+ <label> Size </label>
+ <input type="text" placeholder=" " name="hugepage_size">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#ucOok">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="ucOok">
+ <div class="tab-part">
+ <h4> Undercloud: Openstack Over Kubernetes</h4>
+ <hr>
+ <div class="devider-row" name="undercloud_ook">
+ <div name = "dns">
+ <label> DNS </label>
+ <div class="form-field">
+ <label> Cluster Domain </label>
+ <input type="text" placeholder=" " name="cluster_domain">
+ </div>
+ <div class="form-field">
+ <label> Service IP </label>
+ <input type="text" placeholder=" " name="service_ip">
+ </div>
+ </div>
+ <div name = "etcd">
+ <label> ETCD Details </label>
+ <div class="form-field">
+ <label> Service IP </label>
+ <input type="text" placeholder=" " name="service_ip">
+ </div>
+ <div class="form-field">
+ <label> Container Port </label>
+ <input type="text" placeholder=" " name="container_port">
+ </div>
+ <div class="form-field">
+ <label> HA Proxy Port </label>
+ <input type="text" placeholder=" " name="haproxy_port">
+ </div>
+ </div>
+ <div>
+ <label> Masters </label>
+ </div>
+ <div class="arr" name = "masters">
+ <div class="form-field">
+ <label> Hostname </label>
+ <input type="text" placeholder=" " name="hostname">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ <div name = "networking">
+ <label> Networking </label>
+ <div class="form-field">
+ <label> Type </label>
+ <input type="text" placeholder=" " name="type">
+ </div>
+ <div class="form-field">
+ <label> Interface Used </label>
+ <input type="text" placeholder=" " name="interface_used">
+ </div>
+ <div class="form-field">
+ <label> API Server IP </label>
+ <input type="text" placeholder=" " name="api_service_ip">
+ </div>
+ <div class="form-field">
+ <label> Etcd Server IP </label>
+ <input type="text" placeholder=" " name="etcd_service_ip">
+ </div>
+ <div class="form-field">
+ <label> POD CIDR </label>
+ <input type="text" placeholder=" " name="pod_cidr">
+ </div>
+ <div class="form-field">
+ <label> Service CIDR </label>
+ <input type="text" placeholder=" " name="service_cidr">
+ </div>
+ <div class="form-field">
+ <label> API Server Port </label>
+ <input type="text" placeholder=" " name="apiserver_port">
+ </div>
+ <div class="form-field">
+ <label> HA Proxy Port </label>
+ <input type="text" placeholder=" " name="haproxy_port">
+ </div>
+ <div class="form-field">
+ <label> Service Node Port Range </label>
+ <input type="text" placeholder=" " name="servicenoe_port_range">
+ </div>
+ </div>
+ <div>
+ <label> Key-Value Pairs </label>
+ </div>
+ <div class="arr" name="kvps">
+ <div class="form-field">
+ <label> Key </label>
+ <input type="text" placeholder=" " name="key">
+ </div>
+ <div class="form-field">
+ <label> Value </label>
+ <input type="text" placeholder=" " name="value">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#ucOoo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="ucOoo">
+ <div class="tab-part">
+ <h4> Undercloud: Openstack Over Openstack</h4>
+ <hr>
+ <div class="devider-row" name="undercloud_ooo">
+ <div class="form-field">
+ <label> Host Name </label>
+ <input type="text" placeholder=" " name="host_name">
+ </div>
+ <div class="form-field">
+ <label> Local IP </label>
+ <input type="text" placeholder=" " name="local_ip">
+ </div>
+ <div class="form-field">
+ <label> Public Host </label>
+ <input type="text" placeholder=" " name="public_host">
+ </div>
+ <div class="form-field">
+ <label> Admin Host </label>
+ <input type="text" placeholder=" " name="admin_host">
+ </div>
+ <div class="form-field">
+ <label> Local Interface </label>
+ <input type="text" placeholder=" " name="local_interface">
+ </div>
+ <div class="form-field">
+ <label> Inspection Interface </label>
+ <input type="text" placeholder=" " name="inspection_interface">
+ </div>
+ <div name="networking">
+ <label> Networking </label>
+ <div class="form-field">
+ <label> Control Plane CIDR </label>
+ <input type="text" placeholder=" " name="ctrlplane_cidr">
+ </div>
+ <div class="form-field">
+ <label> Control IP Start </label>
+ <input type="text" placeholder=" " name="ctrlplane_ip_start">
+ </div>
+ <div class="form-field">
+ <label> Control IP End </label>
+ <input type="text" placeholder=" " name="ctrlplane_ip_end">
+ </div>
+ <div class="form-field">
+ <label> Inspection Range </label>
+ <input type="text" placeholder=" " name="inspection_range">
+ </div>
+ <div class="form-field">
+ <label> Gateway </label>
+ <input type="text" placeholder=" " name="gateway">
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#ucSw">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="ucSw">
+ <div class="tab-part">
+ <h4> Undercloud Software </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr", name="undercloud_sw_profiles">
+ <div class="form-field">
+ <label> Profile Name </label>
+ <input type="text" placeholder=" " name="profile_name">
+ </div>
+ <div class="form-field">
+ <label> Software list</label>
+ </div>
+ <div class="arr", name="sw_list">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Version </label>
+ <input type="text" placeholder=" " name="version">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#osSw">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="osSw">
+ <div class="tab-part">
+ <h4> Openstack Software </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr", name="openstack_sw_profiles">
+ <div class="form-field">
+ <label> Profile Name </label>
+ <input type="text" placeholder=" " name="profile_name">
+ </div>
+ <div class="form-field">
+ <label> Software list</label>
+ </div>
+ <div class="arr", name="sw_list">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Version </label>
+ <input type="text" placeholder=" " name="version">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#infSw">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="infSw">
+ <div class="tab-part">
+ <h4> Infrastructure Software </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr", name="infra_sw_profiles">
+ <div class="form-field">
+ <label> Profile Name </label>
+ <input type="text" placeholder=" " name="profile_name">
+ </div>
+ <div class="form-field">
+ <label> Software list</label>
+ </div>
+ <div class="arr", name="sw_list">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Version </label>
+ <input type="text" placeholder=" " name="version">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#swSet">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="swSet">
+ <div class="tab-part">
+ <h4> Software Set </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr", name="software_set">
+ <label> Software Set </label>
+ <div class="form-field">
+ <label> Set Name </label>
+ <input type="text" placeholder=" " name="set_name ">
+ </div>
+ <div class="form-field">
+ <label> Undercloud Profile </label>
+ <input type="text" placeholder=" " name="undercloud_profile ">
+ </div>
+ <div class="form-field">
+ <label> Infra Software Profile </label>
+ <input type="text" placeholder=" " name="infrasw_profile ">
+ </div>
+ <div class="form-field">
+ <label> Openstack Software Profile </label>
+ <input type="text" placeholder=" " name="openstack_profile ">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#roles">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="roles">
+ <div class="tab-part">
+ <h4> Roles </h4>
+ <hr>
+ <div class="devider-row" name="roles">
+ <div class="arr">
+ <div class="form-field">
+ <label> Name </label>
+ <input type="text" placeholder=" " name="name">
+ </div>
+ <div class="form-field">
+ <label> Hostname Prefix </label>
+ <input type="text" placeholder=" " name="hostname_prefix">
+ </div>
+ <div class="form-field">
+ <label> Hostname Suffix </label>
+ <input type="text" placeholder=" " name="hostname_suffix">
+ </div>
+ <div class="form-field">
+ <label> Hostname Number Start </label>
+ <input type="text" placeholder=" " name="hostname_number_start">
+ </div>
+ <div class="form-field">
+ <label> Count </label>
+ <input type="text" placeholder=" " name="count">
+ </div>
+ <div class="form-field">
+ <label> Hardware Profile </label>
+ <input type="text" placeholder=" " name="hardware_profile">
+ </div>
+ <div class="form-field">
+ <label> Interface Mapping </label>
+ <input type="text" placeholder=" " name="interface_mapping">
+ </div>
+ <div class="form-field">
+ <label> Storage Mapping </label>
+ <input type="text" placeholder=" " name="storage_mapping">
+ </div>
+ <div class="form-field">
+ <label> Platform Profile </label>
+ <input type="text" placeholder=" " name="platform_profile">
+ </div>
+ <div class="form-field">
+ <label> Software Set </label>
+ <input type="text" placeholder=" " name="sw_set_name">
+ </div>
+ <div>
+ <label> Metadata </label>
+ </div>
+ <div class="arr" name="metadata">
+ <div>
+ <div class="form-field">
+ <label> On Count Condition </label>
+ <input type="text" placeholder=" " name="on_count_condition">
+ </div>
+ <div class="form-field">
+ <label> Count </label>
+ <input type="text" placeholder=" " name="count">
+ </div>
+ <div class="form-field">
+ <label> Key </label>
+ <input type="text" placeholder=" " name="key">
+ </div>
+ <div class="form-field">
+ <label> Value </label>
+ <input type="text" placeholder=" " name="value">
+ </div>
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#extraPo">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="extraPo">
+ <div class="tab-part">
+ <h4> Extrapolation Information </h4>
+ <hr>
+ <div class="devider-row" name="extrapolation_info">
+ <div class="form-field">
+ <label>ILO Username </label>
+ <input type="text" placeholder=" " name="ilo_user">
+ </div>
+ <div class="form-field">
+ <label> ILO Password </label>
+ <input type="text" placeholder=" " name="ilo_password">
+ </div>
+ <div class="form-field">
+ <label> IP Increment </label>
+ <input type="text" placeholder=" " name="ip_increment ">
+ </div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <a data-toggle="formtab" href="#hostAg">Next</a>
+ </div>
+ </div>
+ <div class="tabs-panels" id="hostAg">
+ <div class="tab-part">
+ <h4> Host Aggregates </h4>
+ <hr>
+ <div class="devider-row">
+ <div class="arr">
+ <div class="form-field">
+ <label> Aggregate Name </label>
+ <input type="text" placeholder=" " name="aggregate_name">
+ </div>
+ <div class="form-field">
+ <label> Properties </label>
+ </div>
+ <div class="arr" name="properties">
+ <div class="form-field">
+ <label> Key </label>
+ <input type="text" placeholder=" " name="key">
+ </div>
+ <div class="form-field">
+ <label> Value </label>
+ <input type="text" placeholder=" " name="value">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ <div class="form-field">
+ <label> Servers </label>
+ </div>
+ <div class="arr" name="servers">
+ <div class="form-field">
+ <label> Identifier </label>
+ <input type="text" placeholder=" " name="identifier">
+ </div>
+ <div class="form-field">
+ <label> ILO IP </label>
+ <input type="text" placeholder=" " name="ilo_ip">
+ </div>
+ <div class="form-field">
+ <label> Host Name </label>
+ <input type="text" placeholder=" " name="hostname">
+ </div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ <div class="add-button" onclick="duplicate(this)"></div>
+ </div>
+ </div>
+ <div class="next-btn">
+ <button type="submit" onclick="createjson()">Submit</button>
+ </div>
+ <div class="next-btn">
+ <label> Click Submit before Download. </label>
+ <hr>
+ <label> Download filename: sitepdf.json </label>
+ <a id="download_link" download="sitepdf.json" href="" > Download JSON </a>
+ </div>
+ </div>
+ <div class="note">
+ <p>*Please fill values correctly. No field is mandatory.</p>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="form-footer">
+ <p>This is Part of OPNFV-CIRV SDV Project</p>
+ </div>
+
+</div>
+
+<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
+
+<script id="rendered-js">
+$('a[data-toggle="formtab"]').click(function () {
+ var targetId = $(this).attr('href');
+
+ $('.tabs-panels').removeClass('active');
+ $('a[data-toggle="formtab"]').removeClass('active');
+
+ $(targetId).addClass('active');
+ $('a[href="' + targetId + '"]').addClass('active');
+
+
+
+});
+//# sourceURL=pen.js
+</script>
+
+</body>
+</html>
diff --git a/sdv/pdf/site/scripts/actions.js b/sdv/pdf/site/scripts/actions.js
new file mode 100644
index 0000000..464c57f
--- /dev/null
+++ b/sdv/pdf/site/scripts/actions.js
@@ -0,0 +1,24 @@
+
+// expand-arrow button
+function toggleClass(element, classname){
+ element.classList.toggle(classname)
+}
+
+// Add button
+function duplicate(button){
+ if (button.previousElementSibling.hasAttribute('name') &&
+ button.previousElementSibling.getAttribute('name') != null)
+ {
+ newdiv = button.previousElementSibling.cloneNode(true);
+ if (!newdiv.lastElementChild.classList.contains('del-button')){
+ del ='<div class="del-button" onclick="remove(this)"></div>'
+ newdiv.innerHTML += del;
+ }
+ button.parentNode.insertBefore(newdiv, button)
+ }
+}
+
+// Delete Button
+function remove(button){
+ button.parentNode.parentNode.removeChild(button.parentNode);
+} \ No newline at end of file
diff --git a/sdv/pdf/site/scripts/createfile.js b/sdv/pdf/site/scripts/createfile.js
new file mode 100644
index 0000000..2e13f2f
--- /dev/null
+++ b/sdv/pdf/site/scripts/createfile.js
@@ -0,0 +1,13 @@
+/**
+ * This function creates a Json file to support client-side file download
+ */
+
+function createjson() {
+ element=document.getElementById('pdfform')
+ data = objectifyDiv(element);
+ jsonstr = JSON.stringify(data);
+ var data = new Blob([jsonstr], {type: 'application/json'});
+ var url = window.URL.createObjectURL(data);
+ document.getElementById('download_link').href = url;
+ console.log(jsonstr);
+}
diff --git a/sdv/pdf/site/scripts/mergeDeep.js b/sdv/pdf/site/scripts/mergeDeep.js
new file mode 100644
index 0000000..ebede4e
--- /dev/null
+++ b/sdv/pdf/site/scripts/mergeDeep.js
@@ -0,0 +1,31 @@
+
+/**
+* Performs a deep merge of objects and returns new object. Does not modify
+* objects (immutable) and merges arrays via concatenation.
+*
+* @param {...object} objects - Objects to merge
+* @returns {object} New object with merged key/values
+*/
+function mergeDeep(...objects) {
+ const isObject = obj => obj && typeof obj === 'object';
+
+ return objects.reduce((prev, obj) => {
+ Object.keys(obj).forEach(key => {
+ const pVal = prev[key];
+ const oVal = obj[key];
+
+ if (Array.isArray(pVal) && Array.isArray(oVal)) {
+ prev[key] = pVal.concat(...oVal);
+ }
+ else if (isObject(pVal) && isObject(oVal)) {
+ prev[key] = mergeDeep(pVal, oVal);
+ }
+ else {
+ prev[key] = oVal;
+ }
+ });
+
+ return prev;
+ }, {});
+}
+
diff --git a/sdv/pdf/site/scripts/readFromHTML.js b/sdv/pdf/site/scripts/readFromHTML.js
new file mode 100644
index 0000000..3255e79
--- /dev/null
+++ b/sdv/pdf/site/scripts/readFromHTML.js
@@ -0,0 +1,57 @@
+
+/**
+* Reads HTML contents into javascript object
+*
+*
+* @param {element} element to read, can be input or div element
+* @returns {object} New object with values read
+*/
+function objectifyDiv(element){
+ var obj = {};
+ var el = element.childNodes;
+ for(var i in el){
+
+ if(el[i] instanceof HTMLInputElement && el[i].hasAttribute('name')) {
+
+ if(el[i].type == 'text')
+ obj = mergeDeep(obj, objectify(el[i].name, el[i].value));
+
+ }
+ if(el[i] instanceof HTMLSelectElement && el[i].hasAttribute('name')){
+ obj = mergeDeep(obj, objectify(el[i].name, el[i].value));
+ }
+ if(el[i] instanceof HTMLDivElement){
+
+ if(el[i].classList.contains('arr')){
+ var key = el[i].getAttribute('name');
+ var value = objectifyDiv(el[i]);
+ if(obj[key] == undefined)
+ obj[key] =[];
+ obj[key].push(value[key]);
+ }
+ else
+ obj = mergeDeep(obj, objectifyDiv(el[i]));
+
+ }
+ }
+
+ if(element.hasAttribute('name')){
+ var newobj = {};
+ newobj[element.getAttribute('name')] = obj;
+ return newobj;
+ }
+ return obj;
+}
+
+
+
+function objectify(key, value){
+ var obj = {};
+ var keys = key.split('.');
+ for(var i = keys.length-1; i >= 0; i--){
+ obj[keys[i]] = value;
+ value = obj;
+ obj = {};
+ }
+ return value;
+}
diff --git a/sdv/pdf/site/scripts/writeToHTML.js b/sdv/pdf/site/scripts/writeToHTML.js
new file mode 100644
index 0000000..8eb8c29
--- /dev/null
+++ b/sdv/pdf/site/scripts/writeToHTML.js
@@ -0,0 +1,117 @@
+
+/**
+* Processes target HTML element and fill with values passed in
+* javascript object
+*
+* @param {element} element to update with values
+* @param {obj} Object from which values will be read
+*/
+ function writeToHTML(element, obj){
+
+ var el = element.childNodes;
+ for(var i in el)
+ {
+
+ if(el[i] instanceof HTMLInputElement && el[i].hasAttribute('name')){
+
+ if(el[i].type == 'text')
+ el[i].value = getValue(obj, el[i].name);
+
+ }
+ if(el[i] instanceof HTMLSelectElement && el[i].hasAttribute('name')){
+
+ var option = getValue(obj, el[i].name);
+ var defaultValue = el[i].value;
+ el[i].value = option;
+ if ( el[i].value != option){
+ el[i].focus();
+ alert(option + " is an invalid value! Setting to default");
+ el[i].value = defaultValue;
+ }
+
+ }
+ if(el[i] instanceof HTMLDivElement){
+
+ if(el[i].hasAttribute('name'))
+ {
+ if(el[i].classList.contains('arr')){
+
+ name = el[i].getAttribute('name');
+ values = getValue(obj, name);
+
+ // Sync number of Arr div with name inside element with number of values
+ syncArr(element, name, values.length);
+
+ // Update value inside all divs
+ var i = 0;
+ for(var div of element.getElementsByClassName('arr'))
+ if(div.getAttribute("name") == name)
+ writeToHTML(div , values[i++]);
+
+ } //else-if single div
+ else
+ writeToHTML(el[i], getValue(obj, el[i].getAttribute('name')));
+
+ }//else-if blank div without attribute name, then simply pass values to next child
+ else
+ writeToHTML(el[i], obj);
+ }
+
+ }
+ }
+
+ // Reads value from obj with string 'key1.key2.key3' convention
+ function getValue(obj, str) {
+ str = str.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
+ str = str.replace(/^\./, ''); // strip a leading dot
+ var a = str.split('.');
+ for (var i = 0; i < a.length; ++i) {
+ var key = a[i];
+ if (key in obj) {
+ obj = obj[key];
+ } else {
+ alert('Invalid PDF file! Key '+key+ ' not Found');
+ return "";
+ }
+ }
+ return obj;
+ }
+
+function syncArr(el, name, length){
+
+ // count number of arr-div with name present inside el
+ var count = 0;
+ var cp = null;
+ for(var div of el.getElementsByClassName('arr')){
+ if(div.getAttribute("name") == name){
+ count++;
+ cp = div;
+ }
+ }
+
+ // balance loop
+ while(count - length){
+ if((count - length) < 0)
+ { // add more div
+ newdiv = cp.cloneNode(true);
+ if (!newdiv.lastElementChild.classList.contains('del-button')){
+ del ='<div class="del-button" onclick="remove(this)"></div>'
+ newdiv.innerHTML += del;
+ }
+ cp.after(newdiv);
+ count++;
+ }
+ else
+ { // remove div
+ for(var div of el.getElementsByClassName('arr'))
+ if(div.getAttribute("name") == name)
+ if (div.lastElementChild.classList.contains('del-button')){
+ div.parentNode.removeChild(div);
+ count--;
+ if((count - length)==0)
+ break;
+ }
+ }
+ }
+
+}
diff --git a/sdv/pdf/site/style/array.css b/sdv/pdf/site/style/array.css
new file mode 100644
index 0000000..45a53fc
--- /dev/null
+++ b/sdv/pdf/site/style/array.css
@@ -0,0 +1,55 @@
+
+@keyframes popup {
+ 0%{
+ transform: scale(0.5);
+ }
+ 90%{
+ transform: scale(1.1);
+ }
+ 100%{
+ transform: scale(1.0);
+ }
+}
+
+.arr{
+ border-radius: 6px;
+ border-style: dashed;
+ border-color: #c9c9c9;
+ border-width: 2px;
+ display: inline-block;
+ padding-right: 3em;
+ margin-right: 15px;
+ margin-bottom: 5px;
+ position: relative;
+ animation: popup 0.2s ease;
+}
+
+
+.add-button{
+ background-image: url("../assets/plus-circle-solid.svg");
+ opacity: 0.7;
+ width: 2em;
+ height: 2em;
+ display: inline-block;
+ left: 0;
+}
+.add-button:hover{
+ opacity: 1
+}
+
+
+
+.del-button{
+ background-image: url("../assets/trash-alt-regular.svg");
+ background-repeat: no-repeat;
+ opacity: 0.7;
+ width: 2em;
+ height: 2em;
+ position: absolute;
+ right: 0.5em;
+ bottom: 0.5em;
+}
+.del-button:hover{
+ opacity: 1
+}
+
diff --git a/sdv/pdf/site/style/multitab.css b/sdv/pdf/site/style/multitab.css
new file mode 100644
index 0000000..8460d8b
--- /dev/null
+++ b/sdv/pdf/site/style/multitab.css
@@ -0,0 +1,109 @@
+@import url('https://fonts.googleapis.com/css?family=Roboto:400,700');
+*{ box-sizing: border-box;}
+button:active, button:focus{ outline: none; box-shadow: none;}
+body{ background: #eeffad;; font-family: 'Roboto', sans-serif;}
+.multitab-form-area { max-width: 750px; margin: 0 auto; background:#eee; padding: 20px}
+.form-field input:focus, .form-field input:active, .form-field select:focus, .form-field select:active, .form-field textarea:active, .form-field textarea:focus {outline: 1px solid #8aa71c;}
+.tab-links-area {width: 240px; display: inline-block; vertical-align: top; padding-right: 20px;}
+.tab-form-area { width: calc(100% - 245px); display: inline-block; background: #fff; vertical-align: top; padding: 16px; border-radius: 5px;}
+.tab-links-area p {margin: 0; font-size: 14px; color: #999;}
+.tab-links-area h1 { margin: 0; font-size: 24px;}
+.tab-part h4 {font-size: 24px;margin: 0;}
+.multitab-form-area hr {border: 0; height: 1px; width: 100%; background: rgba(0,0,0,0.3);}
+.tab-links-area ul li a {text-decoration: none;font-size: 14px;padding: 10px 15px;display: block;color: #333; position: relative;}
+.tab-links-area ul li a:before {content: '';height: 0%;width: 3px;background: #8aa71c;position: absolute;left: -2px;top: 0;bottom: 0;margin: auto;transition: 0.3s ease;}
+.tab-links-area ul li a.active:before{ height: 100%;}
+.tab-links-area ul li {display: block; border-left: 1px solid #eee;}
+.tab-links-area ul {list-style: none;padding: 0; margin: 20px 0 0;}
+.form-field input, .form-field select {width: 100%; font-family: 'Roboto', sans-serif; height: 35px; padding-left: 10px; border: 1px solid #ccc;}
+.form-field select {padding: 0 0 0 2px;}
+.form-field label { font-size: 14px; display: block; padding:10px 0;}
+.half-2 {width: 50%; padding: 0 10px; float: left;}
+.devider-row:after {content: '';display: table;clear: both;}
+.devider-row {margin: 0 -10px;clear: both;}
+.half-3 {width: calc(100%/3); float: left; padding: 0 10px;}
+.next-btn button, .next-btn a {background: #8aa71c;cursor: pointer;border: 1px solid #8aa71c;transition: 0.3s ease;color: #fff;height: 35px;width: 90px;border-radius: 100px;margin: 20px 0 10px auto;display: block;text-transform: uppercase;text-align: center;line-height: 35px;text-decoration: none;font-size: 14px;}
+.next-btn button:hover, .next-btn a:hover {background: transparent; color: #8aa71c;}
+.tabs-panels.active { display: block;}
+.tabs-panels { display: none; animation: fadeIn 0.3s ease;}
+.full {padding: 0 10px; width: 100%;}
+.form-field textarea {width: 100%;height: 100px;padding: 10px;font-size: 14px;border: 1px solid #ccc;font-family: 'Roboto', sans-serif;}
+.checkbox label:after {content: '';position: absolute;border-style: solid;border-color: #333;height: 8px;width: 5px;border-width: 0 3px 3px 0;left: 5px;z-index: 2;transform: rotate(35deg);top: 4px; display: none;}
+.checkbox label:before {content: '';height: 20px;width: 21px;background: #fff;position: absolute;border: 1px solid #8aa71c;left: -2px;top: 0;border-radius: 3px;}
+.checkbox {position: relative;margin: 10px 0;}
+.checkbox label {display: inline-block;vertical-align: middle;padding: 0;}
+.checkbox input[type="checkbox"] {width: 20px;height: 20px;display: inline-block;vertical-align: middle;margin: 0;position: relative;z-index: 3;opacity: 0;}
+.radio label:after { content: ''; display: none; height: 15px; width: 15px; position: absolute; background: #8aa71c; border-radius: 100px; left: 2px; top: 2px; z-index: 1;}
+.radio label:before {content: ''; height: 21px; width: 21px; background: #fff; border: 1px solid #8aa71c; position: absolute; left: -2px; top: -2px; border-radius: 100px;}
+.radio input[type="radio"] { height: 20px; width: 20px; display: inline-block; margin: 0; position: relative; z-index: 3; opacity: 0; vertical-align: middle;}
+.radio label {padding: 0; display: inline-block; margin: 0; vertical-align: middle;}
+.radio { position: relative; margin: 10px 0;}
+.radio input:checked + label:after, .checkbox input:checked + label:after{ display: block;}
+.note p { margin: 0; font-size: 12px; color: #999;}
+.form-area {max-width: 80%; margin: 0 auto; background: #eee; border-radius: 10px; overflow: hidden; box-shadow: 0 5px 20px rgba(0,0,0,0.25)}
+.form-footer p {margin: 0; font-size: 12px;}
+.form-footer {padding: 20px; text-align: center; color: #676767;}
+.form-header {background: #fff; box-shadow: 0 2px 7px rgba(0,0,0,0.1); margin-bottom: 20px;}
+.logo-area {padding: 0 10%;}
+.logo-area h1 a {color: #000; text-decoration: none; outline: none;}
+.logo-area h1 {margin: 0; font-size: 24px;}
+.need-help a i {background: #333; color: #fff; font-style: normal; font-size: 10px; height: 13px; width: 13px; display: inline-block; text-align: center; border-radius: 100px;}
+.need-help a {font-size: 12px; color: #333; text-decoration: none;}
+.need-help {text-align: right; padding: 0 10%;}
+.top-header {padding: 15px 0; border-bottom: 2px dashed #ccc;}
+.status p {font-size: 12px; color: #676767}
+.status h5, .status p { margin: 0;}
+.bars label { text-align: center; display: block; font-size: 14px;}
+.bars {position: relative;}
+.blank-bar {width: 100%; background: #ccc; height: 3px; border-radius: 100px;}
+.full-bar { width: 50%; background: #8aa71c; height: 3px; position: relative; bottom: -3px;}
+.bars span { height: 8px; width: 8px; display: inline-block; position: absolute; background: #ccc; border-radius: 100px; z-index: 1;}
+.bars span:nth-of-type(2) {left: 15%;}
+.bars span:nth-of-type(3) {left: 50%;}
+.bars span:nth-of-type(4) {left: 85%;}
+.bars span:nth-of-type(5) {left: 100%;}
+.bars span.active{background: #8aa71c;}
+.bottom-header {padding: 15px 10%;}
+.status {padding-left: 10%;}
+/*keyframes*/
+@-webkit-keyframes fadeIn {
+ 0% {
+ opacity: 0;
+ }
+
+ 100% {
+ opacity: 1;
+ }
+}
+
+@keyframes fadeIn {
+ 0% {
+ opacity: 0;
+ }
+
+ 100% {
+ opacity: 1;
+ }
+}
+
+.fadeIn {
+ -webkit-animation-name: fadeIn;
+ animation-name: fadeIn;
+}
+
+@media(max-width:750px){
+ .half-2 {width: 100%;}
+ .top-header .half-2 {width: 50%;}
+ .logo-area {padding: 0 5%; text-align: left;}
+ .status { padding-top: 20px; padding-left: 0;}
+}
+
+@media(max-width:570px){
+ .tab-links-area {width: 100%;display: block; margin-bottom: 20px;}
+ .tab-form-area{ width: 100%;}
+ .bottom-header {padding: 15px 5%;}
+}
+
+@media(max-width:420px){
+ .form-area {max-width: 90%;}
+}
diff --git a/sdv/pdf/template/pdf_template.json b/sdv/pdf/template/pdf_template.json
new file mode 100644
index 0000000..c389330
--- /dev/null
+++ b/sdv/pdf/template/pdf_template.json
@@ -0,0 +1,536 @@
+{
+ "_comment_head1":"User should Configure all profiles. Add new, if reqd.",
+ "_comment_head2":"User should Configure the roles",
+ "_comment_head3":"All infos should be filled by the user",
+ "_comment_head4":"The servers data will be automatically generated",
+ "_comment_info1":"All Infos",
+ "management_info": {
+ "owner":"",
+ "area_name": "",
+ "area_center_name": "",
+ "room_id": "",
+ "city": "",
+ "resource_pool_name": ""
+ },
+ "user_info": [
+ {
+ "username":"",
+ "password":"",
+ "pub_key":"",
+ "passphrase":"",
+ "tls_ca_cert":"",
+ "tls_cert":"",
+ "tls_key":"",
+ "email":""
+ }
+ ],
+ "ntp_info": {
+ "primary_ip":"",
+ "primary_zone":"",
+ "secondary_ip":"",
+ "secondary_zone":""
+ },
+ "syslog_info": {
+ "server_ip":"",
+ "transport":""
+ },
+ "dns_info": [
+ {
+ "name":"",
+ "domain":"",
+ "servers": [
+ {
+ "ip": ""
+ }
+ ]
+ }
+ ],
+ "proxy_info": {
+ "address":"",
+ "port":"",
+ "user":"",
+ "password":""
+ },
+ "ldap_info": {
+ "base_url":"",
+ "url":"",
+ "auth_path":"",
+ "common_name":"",
+ "subdomain":"",
+ "domain":""
+ },
+ "vim_info": {
+ "vim_name": " ",
+ "vim_id": " ",
+ "vendor": " ",
+ "version": " ",
+ "installer":"",
+ "deployment_style":"",
+ "container_orchestrator":"",
+ "storage_type":""
+ },
+ "_comment_deployment":" Type can be OOK or NOOK, block storage method is rbd or iscsi",
+ "deployment_info": {
+ "high_availability":"",
+ "introspection":"",
+ "deployment_type":"",
+ "installer_used":"",
+ "workload_vnf":"",
+ "workload_cnf":"",
+ "sdn_controller":"",
+ "sdn_controller_version":"",
+ "sdn_controller_nbapps":"",
+ "vnfm":"",
+ "vnfm_version":"",
+ "data_plane_used":"",
+ "ironic_deploy_interface":"",
+ "external_storage_cluster":"",
+ "bl_str_connect_method":""
+ },
+ "vim_functional": {
+ "scheduler_filters":"",
+ "cpu_allocation_ratio":""
+ },
+ "jumphost_info": {
+ "ip":"",
+ "name":""
+ },
+ "rack_info": [
+ {
+ "rack_id":"",
+ "rack_details": {
+ "rack_name":"",
+ "rack_description":"",
+ "rack_az":""
+ }
+ }
+ ],
+ "storage_cluster_info": {
+ "name":"",
+ "cluster_type":"",
+ "cluster_id":"",
+ "auth_type":"",
+ "username":"",
+ "password":"",
+ "certificate_location":"",
+ "client_key":"",
+ "mon_host_ips": [
+ {
+ "ips":""
+ }
+ ],
+ "public_cidr":"",
+ "cluster_cidr":"",
+ "pools": [
+ {
+ "key":"",
+ "value":""
+ }
+ ]
+ },
+ "_comment_info2": "End of Information - Except Software-INFO",
+ "bios_profile": [
+ {
+ "profile_name":"",
+ "bios_info":
+ {
+ "bios_version": "",
+ "bios_mode":"",
+ "bootstrap_proto":"",
+ "hyperthreading_enabled":"",
+ "_comment":"C4_C6_MLC-STR_MLC-SPA_DCU_DCA_RAS_TURBO",
+ "bios_setting":""
+ }
+ }
+ ],
+ "processor_profiles": [
+ {
+ "profile_name":"",
+ "profile_info":
+ {
+ "manufacturer": "",
+ "generation":"",
+ "speed":"",
+ "model":"",
+ "architecture":"",
+ "cpu_cflags":"",
+ "cache_size":"",
+ "numas": [
+ {
+ "node_id":"",
+ "cpu_set":""
+ }
+ ]
+ }
+ }
+ ],
+ "disks_profiles": [
+ {
+ "profile_name":"",
+ "profile_info": [
+ {
+ "alias":"",
+ "vendor":"",
+ "address":"",
+ "size":"",
+ "model":"",
+ "dev_type":"",
+ "rotation":"",
+ "bus":"",
+ "logical_name":""
+ }
+ ]
+ }
+ ],
+ "nic_profiles": [
+ {
+ "profile_name":"",
+ "profile_info": [
+ {
+ "alias":"",
+ "name":"",
+ "address":"",
+ "dev_type":"",
+ "bus":"",
+ "sriov_capable":"",
+ "numa_id":""
+ }
+ ]
+ }
+ ],
+ "hardware_profiles": [
+ {
+ "profile_name": "",
+ "profile_info": {
+ "manufacturer": "",
+ "model": "",
+ "generation":"",
+ "bios_profile":"",
+ "processor_profile": "",
+ "memory": "",
+ "disks_profile": "",
+ "nics_profile":""
+ }
+ }
+ ],
+ "_comment_hw":" Hardware Information is complete",
+ "storage_profile": [
+ {
+ "name":"",
+ "bootdrive":"",
+ "bd_partitions": [
+ {
+ "name":"",
+ "size":"",
+ "bootable":"",
+ "filesystem": {
+ "mountpoint":"",
+ "fstype":"",
+ "mount_options":""
+ }
+ }
+ ],
+ "data_devices": [
+ {
+ "name":"",
+ "partitions": [
+ {
+ "name":"ceph",
+ "size":"available",
+ "filesystem": {
+ "mountpoint":"/var/lib/ceph",
+ "fstype":"ext4",
+ "mount_options":"defaults"
+ }
+ }
+ ]
+ }
+ ],
+ "journal_devices": [
+ {
+ "name":""
+ }
+ ]
+
+ }
+ ],
+ "_comment_nw1": "Network Info, Please include IPMI & Physnets info too",
+ "networks": [
+ {
+ "name":"",
+ "vips":[
+ {
+ "name":"",
+ "ip":""
+ }
+ ],
+ "tunnel_type":"",
+ "tunnel_id":"",
+ "tunnel_id_range":"",
+ "mtu":"",
+ "routedomain":"",
+ "cidr":"",
+ "dns":"",
+ "routes": [
+ {
+ "subnet":"",
+ "gateway":"",
+ "metric":"",
+ "routedomain":""
+ }
+ ],
+ "allocation_pools": [
+ {
+ "type":"",
+ "start":"",
+ "end":""
+ }
+ ],
+ "v6_cidr":"",
+ "v6_allocation_pools": [
+ {
+ "type":"",
+ "start":"",
+ "end":""
+ }
+ ]
+ }
+ ],
+ "physical_networks": [
+ {
+ "name":"external",
+ "cidr":"",
+ "type":"flat"
+ }
+ ],
+ "_comment_nw2":" type: trunk (airship), bond, interface, bridge",
+ "network_link": [
+ {
+ "name":"",
+ "type":"",
+ "bonding_mode":"",
+ "mtu":"",
+ "linkspeed":"auto",
+ "trunking_mode":"",
+ "trunking_default_nw":"",
+ "metadata": [
+ {
+ "key":"",
+ "value":""
+ }
+ ],
+ "members":[
+ {
+ "name":"",
+ "type":""
+ }
+ ],
+ "vid":"",
+ "vf_count":""
+ }
+ ],
+ "_comment_nw4": "The interface_name could be i/f, bond, bridges",
+ "_comment_nw5": "These profiles are mapped to roles",
+ "interface_mapping_profiles": [
+ {
+ "profile_name":"",
+ "profile_data": [
+ {
+ "interface_name":"",
+ "interface_type":"",
+ "networks": [
+ {
+ "name":""
+ }
+ ],
+ "use_dhcp":""
+ }
+ ]
+ }
+ ],
+ "platform_profiles": [
+ {
+ "profile_name":"",
+ "os":"",
+ "rt_kvm":"",
+ "kernel_version":"",
+ "kernel_parameters":"",
+ "isolated_cpus":"",
+ "vnf_cores":"",
+ "os_reserved_cores": " ",
+ "hugepage_count":"",
+ "hugepages": [
+ {
+ "hugepage_count":"",
+ "hugepage_size":""
+ }
+ ],
+ "iommu":"",
+ "vswitch_daemon_cores": " ",
+ "vswitch_type":"",
+ "vswitch_uio_driver":"",
+ "vswitch_mem_channels":"",
+ "vswitch_socket_memory":"",
+ "vswitch_pmd_cores":"",
+ "vswitch_dpdk_lcores":"",
+ "vswitch_dpdk_rxqs":"",
+ "vswitch_options":""
+ }
+ ],
+ "undercloud_ook":{
+ "dns": {
+ "cluster_domain":"",
+ "service_ip":""
+ },
+ "etcd":{
+ "service_ip":"",
+ "container_port":"",
+ "haproxy_port":""
+ },
+ "masters": [
+ {
+ "hostname":""
+ }
+ ],
+ "networking":{
+ "type":"",
+ "interface_used":"",
+ "api_service_ip":"",
+ "etcd_service_ip":"",
+ "pod_cidr":"",
+ "service_cidr":"",
+ "apiserver_port":"",
+ "haproxy_port":"",
+ "servicenode_port_range":""
+ },
+ "kvps":[
+ {
+ "key":"",
+ "value":""
+ }
+ ]
+
+ },
+ "undercloud_ooo":{
+ "host_name":"",
+ "local_ip":"",
+ "public_host":"",
+ "admin_host":"",
+ "local_interface":"",
+ "inspection_interface":"",
+ "networking":{
+ "ctrlplane_cidr":"",
+ "ctrlplane_ip_start":"",
+ "ctrlplane_ip_end":"",
+ "inspection_range":"",
+ "gateway":""
+ }
+ },
+ "_comment_sw1":"Software Begins",
+ "undercloud_sw_profiles":[
+ {
+ "profile_name":"",
+ "sw_list": [
+ {
+ "name":"",
+ "version":""
+ }
+ ]
+ }
+ ],
+ "openstack_sw_profiles":[
+ {
+ "profile_name":"",
+ "sw_list": [
+ {
+ "name":"",
+ "version":""
+ }
+ ]
+ }
+ ],
+ "infra_sw_profiles":[
+ {
+ "profile_name":"",
+ "sw_list": [
+ {
+ "name":"",
+ "version":""
+ }
+ ]
+ }
+ ],
+ "software_set": [
+ {
+ "set_name":"",
+ "undercloud_profile":"",
+ "infrasw_profile":"",
+ "openstack_profile":""
+ }
+ ],
+ "_comment_role1":"User has to configure this - What profile to use for a role",
+ "_comment_role2":"Based on this server_info will be autogenerated for all servers",
+ "roles": [
+ {
+ "name":"",
+ "hostname_prefix":"",
+ "hostname_suffix":"",
+ "hostname_number_start":"",
+ "count":"",
+ "hardware_profile":"",
+ "interface_mapping":"",
+ "storage_mapping":"",
+ "platform_profile":"",
+ "sw_set_name":"",
+ "metadata": [
+ {
+ "on_count_condition":"",
+ "count":"",
+ "key":"",
+ "value":""
+ }
+ ]
+ }
+ ],
+ "_comment_ex1":"C:City, A:Area, R:Room, N:Unique Number",
+ "_comment_ex2":"All are 2 characters. City-Capitals, Area-Small",
+ "extrapolation_info": {
+ "ilo_password":"CID-AID-RID-NID",
+ "ilo_user":"owner",
+ "ip_increment":""
+ },
+ "host_aggregates": [
+ {
+ "aggregate_name":"",
+ "properties": [
+ {
+ "key":"",
+ "value":""
+ }
+ ],
+ "servers": [
+ {
+ "identifier":"",
+ "ilo_ip":"",
+ "hostname":""
+ }
+ ]
+ }
+ ],
+ "_comment_servers1":"This will be auto generated",
+ "_comment_servers2":"This describes the entire cloud.",
+ "servers": [
+ {
+ "role_name":"",
+ "device_name":"",
+ "az_name": " ",
+ "ha_name": " ",
+ "rack":"",
+ "ilo_info": {
+ "ip":"",
+ "user":"",
+ "password":""
+ }
+ }
+ ]
+}