first commit
Change-Id: I8a65ee5527dd16d81e87c8ac5d4bdb471e5e759d
Signed-off-by: lombardof <flombardo@cnit.it>
diff --git a/instancehandler/__init__.py b/instancehandler/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/instancehandler/__init__.py
diff --git a/instancehandler/admin.py b/instancehandler/admin.py
new file mode 100644
index 0000000..2e9690a
--- /dev/null
+++ b/instancehandler/admin.py
@@ -0,0 +1,19 @@
+#
+# Copyright 2018 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 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.
+#
+
+from django.contrib import admin
+
+# Register your models here.
diff --git a/instancehandler/apps.py b/instancehandler/apps.py
new file mode 100644
index 0000000..2f49d31
--- /dev/null
+++ b/instancehandler/apps.py
@@ -0,0 +1,23 @@
+#
+# Copyright 2018 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 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.
+#
+
+from __future__ import unicode_literals
+
+from django.apps import AppConfig
+
+
+class InstancehandlerConfig(AppConfig):
+ name = 'instancehandler'
diff --git a/instancehandler/models.py b/instancehandler/models.py
new file mode 100644
index 0000000..21d5735
--- /dev/null
+++ b/instancehandler/models.py
@@ -0,0 +1,21 @@
+#
+# Copyright 2018 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 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.
+#
+
+from __future__ import unicode_literals
+
+from django.db import models
+
+# Create your models here.
diff --git a/instancehandler/template/instance_list.html b/instancehandler/template/instance_list.html
new file mode 100644
index 0000000..1b0868d
--- /dev/null
+++ b/instancehandler/template/instance_list.html
@@ -0,0 +1,152 @@
+{% extends "base.html" %}
+{% load get %}
+{% load staticfiles %}
+
+
+
+{% block head_block %}
+ {{ block.super }}
+ <!-- Codemirror core CSS -->
+ <link rel="stylesheet" href="/static/bower_components/codemirror/lib/codemirror.css">
+ <link rel="stylesheet" href="/static/bower_components/codemirror/addon/fold/foldgutter.css" />
+ <link rel="stylesheet" href="/static/bower_components/codemirror/theme/neat.css">
+ <link rel="stylesheet" href="/static/bower_components/codemirror/addon/dialog/dialog.css">
+ <link rel="stylesheet" href="/static/bower_components/codemirror/addon/display/fullscreen.css">
+{% endblock %}
+{% block title_header_big %}
+ {{ block.super }}
+{% endblock %}
+{% block left_sidebar %}
+ {% include 'osm/osm_project_left_sidebar.html' %}
+{% endblock %}
+
+
+{% block breadcrumb_body %}
+ {{ block.super }}
+ <li><a href="{% url 'projects:instances:list' project_id=project_id type=type %}">Instances</a></li>
+{% endblock %}
+
+{% block content_body %}
+ {{ block.super }}
+ {% include 'modal/instance_create.html' %}
+ {% csrf_token %}
+ <div class="row">
+ <div class="col-md-12">
+
+ <div class="box">
+ <div class="box-header with-border">
+ <h3 class="box-title">Instances</h3>
+ <!--
+ <div class="box-tools">
+ <a href="javascript:newVimModal()" class="btn btn-block btn-primary btn-sm"><i
+ class="fa fa-plus"></i><span> New VIM</span></a>
+ </div>
+ -->
+ </div>
+ <div class="box-body">
+ <table id="instances_table" class="table table-bordered table-striped">
+ <thead>
+ <tr>
+ <th>Id</th>
+ <th>Name</th>
+ <th>Nsd name</th>
+ <th style="width:5%">Operational Status</th>
+ <th style="width:5%">Config Status</th>
+ <th>Detailed Status</th>
+ <th >Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for i in instances %}
+ <tr>
+
+ <td>{{ i|get:"_id" }}</td>
+ <td>{{ i|get:"short-name" }}</td>
+ <td>{{ i|get:"nsd-name-ref" }}</td>
+
+ {% if i|get:"operational-status" == 'failed' %}
+ <td><span class="label label-danger">{{ i|get:"operational-status" }}</span> </td>
+ {% elif i|get:"operational-status" == 'init' %}
+ <td><span class="label label-warning">{{ i|get:"operational-status" }}</span> </td>
+ {% elif i|get:"operational-status" == 'running' %}
+ <td><span class="label label-success">{{ i|get:"operational-status" }}</span> </td>
+ {% else %}
+ <td>{{ i|get:"operational-status" }}</td>
+ {% endif %}
+ {% if i|get:"config-status" == 'failed' %}
+ <td><span class="label label-danger">{{ i|get:"config-status" }}</span> </td>
+ {% elif i|get:"config-status" == 'init' %}
+ <td><span class="label label-warning">{{ i|get:"config-status" }}</span> </td>
+ {% elif i|get:"config-status" == 'running' %}
+ <td><span class="label label-success">{{ i|get:"config-status" }}</span> </td>
+ {% elif i|get:"config-status" == 'configured' %}
+ <td><span class="label label-success">{{ i|get:"config-status" }}</span> </td>
+ {% else %}
+ <td>{{ i|get:"config-status" }}</td>
+ {% endif %}
+ <td style=" max-width:1px;overflow:hidden; white-space:nowrap; text-overflow:ellipsis;">{{ i|get:"detailed-status" }}</td>
+ <td>
+ <div class="btn-group">
+ <button type="button" class="btn btn-default"
+ onclick="javascript:showInstanceDetails('{% url 'projects:instances:show' instance_id=i|get:'_id' project_id=project_id type=type %}')"
+ data-toggle="tooltip" data-placement="top" data-container="body" title="Show Info"><i
+ class="fa fa-info"></i>
+ </button>
+
+ <button type="button" class="btn btn-default"
+ onclick="javascript:deleteNs('{% url 'projects:instances:delete' instance_id=i|get:'_id' project_id=project_id type=type %}')"
+ data-toggle="tooltip" data-placement="top" data-container="body" title="Delete"><i
+ class="fa fa-trash-o"></i></button>
+
+ <button type="button" class="btn btn-default dropdown-toggle"
+ data-toggle="dropdown" aria-expanded="false">Actions
+ <span class="fa fa-caret-down"></span></button>
+ <ul class="dropdown-menu">
+ <li><a href="#" onclick="javascript:performAction('{% url 'projects:instances:action' instance_id=i|get:'_id' project_id=project_id type=type %}')">
+ <i class="fa fa-magic"></i>Exec NS Primitive</a></li>
+ <li><a href="#"> <i class="fa fa-list"></i>Active operations</a></li>
+ </ul>
+
+
+ </div>
+
+ </td>
+
+
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+
+ </div>
+{% include 'modal/instance_show.html' %}
+{% include 'modal/instance_new_action.html' %}
+{% endblock %}
+
+{% block resource_block %}
+ {{ block.super }}
+ <!-- Utility JS -->
+
+ <script src="/static/bower_components/codemirror/lib/codemirror.js"></script>
+ <script src="/static/bower_components/codemirror/addon/fold/foldcode.js"></script>
+ <script src="/static/bower_components/codemirror/addon/fold/foldgutter.js"></script>
+ <script src="/static/bower_components/codemirror/addon/fold/brace-fold.js"></script>
+ <script src="/static/bower_components/codemirror/mode/javascript/javascript.js"></script>
+ <script src="/static/bower_components/codemirror/addon/search/searchcursor.js"></script>
+ <script src="/static/bower_components/codemirror/addon/search/search.js"></script>
+ <script src="/static/bower_components/codemirror/addon/dialog/dialog.js"></script>
+ <script src="/static/bower_components/codemirror/addon/display/autorefresh.js"></script>
+ <script src="/static/bower_components/codemirror/addon/edit/matchbrackets.js"></script>
+ <script src="/static/bower_components/codemirror/addon/edit/closebrackets.js"></script>
+ <script src="/static/bower_components/codemirror/addon/display/fullscreen.js"></script>
+ <script src="/static/bower_components/codemirror/keymap/sublime.js"></script>
+ <script src="/static/src/instancehandler/instance_list.js"></script>
+
+{% endblock %}
+
+{% block footer %}
+ {% include "footer.html" %}
+{% endblock %}
diff --git a/instancehandler/template/modal/instance_create.html b/instancehandler/template/modal/instance_create.html
new file mode 100644
index 0000000..c40ecb2
--- /dev/null
+++ b/instancehandler/template/modal/instance_create.html
@@ -0,0 +1,55 @@
+<div class="modal" id="modal_new_instance" xmlns="http://www.w3.org/1999/html">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+ <span aria-hidden="true">×</span></button>
+ <h4 class="modal-title" >New Instance</h4>
+ </div>
+ <form id="formCreateNS" action='{% url "projects:instances:create" project_id=project_id%}' class="form-horizontal"
+ method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ <div class="modal-body" id="modal_new_instance_body" >
+ <div class="form-group">
+ <label for="nsName" class="col-sm-3 control-label">Name</label>
+ <div class="col-sm-6">
+ <input class="form-control" id="nsName" name="nsName"
+ placeholder="Ns name" required>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="nsDescription" class="col-sm-3 control-label">Description</label>
+ <div class="col-sm-6">
+ <input class="form-control" id="nsDescription" name="nsDescription"
+ placeholder="Description" >
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="nsdId" class="col-sm-3 control-label">Nsd Id</label>
+ <div class="col-sm-6">
+ <input class="form-control" id="nsdId" name="nsdId"
+ placeholder="Nsd Id" >
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="vimAccountId" class="col-sm-3 control-label">Vim Account Id</label>
+ <div class="col-sm-6">
+ <select id="vimAccountId" class="js-example-basic form-control" name="vimAccountId">
+ </select>
+ </div>
+ </div>
+
+
+
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default pull-left" data-dismiss="modal">Cancel</button>
+ <button class="btn btn-primary" data-loading-text="<i class='fa fa-circle-o-notch fa-spin'></i> Creating..." id="create_new_instance">Create</button>
+
+ </div>
+ </form>
+ </div>
+ <!-- /.modal-content -->
+ </div>
+ <!-- /.modal-dialog -->
+</div>
diff --git a/instancehandler/template/modal/instance_new_action.html b/instancehandler/template/modal/instance_new_action.html
new file mode 100644
index 0000000..6cf3059
--- /dev/null
+++ b/instancehandler/template/modal/instance_new_action.html
@@ -0,0 +1,57 @@
+<div class="modal" id="modal_instance_new_action" xmlns="http://www.w3.org/1999/html">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+ <span aria-hidden="true">×</span></button>
+ <h4 class="modal-title" >Perform Action</h4>
+ </div>
+ <form id="formActionNS" action="" class="form-horizontal" method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ <div class="modal-body" id="modal_instance_new_action_body" >
+
+ <div class="row">
+ <label for="primitive" class="col-sm-2">Primitive:</label>
+ <div class="col-sm-3">
+ <input class="form-control input-sm" id="primitive" name="primitive" required>
+ </div>
+
+ <label for="vnf_member_index" class="col-sm-4">VNF Member index: </label>
+ <div class="col-sm-2">
+ <input class="form-control input-sm" id="vnf_member_index" name="vnf_member_index" required>
+ </div>
+ </div>
+
+ <div class="row">
+ <h5 class="col-sm-4">Primitive parameters :</h5>
+
+ </div>
+
+ <div id="primitive_params_div">
+
+ <div class="form-group">
+ <label class="col-sm-2">Name: </label>
+ <div class="col-sm-3">
+ <input name="primitive_params_name" class="form-control input-sm" >
+ </div>
+ <label class="col-sm-2">Value: </label>
+ <div class="col-sm-3">
+ <input name="primitive_params_value" class="form-control input-sm" >
+ </div>
+ <button type="button" class="btn btn-success btn-add btn-sm">+</button>
+ </div>
+ </div>
+
+
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default pull-left" data-dismiss="modal">Cancel</button>
+ <button class="btn btn-primary pull-right" >Execute</button>
+ </div>
+ </form>
+
+ </div>
+ <!-- /.modal-content -->
+ </div>
+ <!-- /.modal-dialog -->
+</div>
diff --git a/instancehandler/template/modal/instance_show.html b/instancehandler/template/modal/instance_show.html
new file mode 100644
index 0000000..6df8bc1
--- /dev/null
+++ b/instancehandler/template/modal/instance_show.html
@@ -0,0 +1,23 @@
+<div class="modal" id="modal_show_instance" xmlns="http://www.w3.org/1999/html">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+ <span aria-hidden="true">×</span></button>
+ <h4 class="modal-title" >Instance details</h4>
+ </div>
+
+ <div class="modal-body" id="modal_show_instance_body" >
+ <textarea id="instance_view_json">
+ </textarea>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default pull-left" data-dismiss="modal">Cancel</button>
+
+ </div>
+
+ </div>
+ <!-- /.modal-content -->
+ </div>
+ <!-- /.modal-dialog -->
+</div>
diff --git a/instancehandler/tests.py b/instancehandler/tests.py
new file mode 100644
index 0000000..79947e6
--- /dev/null
+++ b/instancehandler/tests.py
@@ -0,0 +1,19 @@
+#
+# Copyright 2018 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 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.
+#
+
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/instancehandler/urls.py b/instancehandler/urls.py
new file mode 100644
index 0000000..b6a9e33
--- /dev/null
+++ b/instancehandler/urls.py
@@ -0,0 +1,27 @@
+#
+# Copyright 2018 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 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.
+#
+
+from django.conf.urls import url
+from instancehandler import views
+
+urlpatterns = [
+ url(r'^(?P<type>[ns|vnf]+)/list/', views.list, name='list'),
+ url(r'^create/', views.create, name='create'),
+ url(r'^(?P<type>[ns|vnf]+)/(?P<instance_id>[0-9a-z-]+)/delete$', views.delete, name='delete'),
+ url(r'^(?P<type>[ns|vnf]+)/(?P<instance_id>[0-9a-z-]+)/action', views.action, name='action'),
+ url(r'^(?P<type>[ns|vnf]+)/(?P<instance_id>[0-9a-z-]+)', views.show, name='show'),
+
+]
diff --git a/instancehandler/views.py b/instancehandler/views.py
new file mode 100644
index 0000000..0c9a8a4
--- /dev/null
+++ b/instancehandler/views.py
@@ -0,0 +1,97 @@
+#
+# Copyright 2018 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 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.
+#
+
+from django.shortcuts import render, redirect
+from django.contrib.auth.decorators import login_required, permission_required
+from django.http import HttpResponse, JsonResponse
+import json
+import logging
+from lib.osm.osmclient.client import Client
+
+
+@login_required
+def list(request, project_id=None, type=None):
+ client = Client()
+ if type == 'ns':
+ result = client.ns_list()
+
+ return __response_handler(request, {'instances': result, 'type': 'ns', 'project_id': project_id}, 'instance_list.html')
+
+
+@login_required
+def create(request, project_id=None):
+ result = {}
+ ns_data = {
+ "nsName": request.POST.get('nsName', 'WithoutName'),
+ "nsDescription": request.POST.get('nsDescription', ''),
+ "nsdId": request.POST.get('nsdId', ''),
+ "vimAccountId": request.POST.get('vimAccountId', ''),
+ # "ssh-authorized-key": [
+ # {
+ # request.POST.get('key-pair-ref', ''): request.POST.get('keyValue', '')
+ # }
+ # ]
+ }
+ print ns_data
+ client = Client()
+ result = client.ns_create(ns_data)
+ return __response_handler(request, result, 'projects:instances:list', to_redirect=True, type='ns', project_id=project_id)
+
+
+@login_required
+def action(request, project_id=None, instance_id=None, type=None):
+ result = {}
+ client = Client()
+
+ # result = client.ns_action(instance_id, action_payload)
+ primitive_param_keys = request.POST.getlist('primitive_params_name')
+ primitive_param_value = request.POST.getlist('primitive_params_value')
+ action_payload = {
+ "vnf_member_index": request.POST.get('vnf_member_index'),
+ "primitive": request.POST.get('primitive'),
+ "primitive_params": {k: v for k, v in zip(primitive_param_keys, primitive_param_value) if len(k) > 0}
+ }
+
+ result = client.ns_action(instance_id, action_payload)
+ return __response_handler(request, result, None, to_redirect=False, status=result['status'] )
+
+
+@login_required
+def delete(request, project_id=None, instance_id=None, type=None):
+ result = {}
+ client = Client()
+ result = client.ns_delete(instance_id)
+ print result
+ return __response_handler(request, result, 'projects:instances:list', to_redirect=True, type='ns', project_id=project_id)
+
+
+@login_required
+def show(request, project_id=None, instance_id=None, type=None):
+ # result = {}
+ client = Client()
+ result = client.ns_get(instance_id)
+ print result
+ return __response_handler(request, result)
+
+
+def __response_handler(request, data_res, url=None, to_redirect=None, *args, **kwargs):
+ raw_content_types = request.META.get('HTTP_ACCEPT', '*/*').split(',')
+ if 'application/json' in raw_content_types or url is None:
+ return JsonResponse(data_res, *args, **kwargs)
+ elif to_redirect:
+ return redirect(url, *args, **kwargs)
+ else:
+ return render(request, url, data_res)