diff --git a/ajax/templates/ajax/openstackDeploymentStatus.html b/ajax/templates/ajax/openstackDeploymentStatus.html
index 7c7ca87..312462c 100644
--- a/ajax/templates/ajax/openstackDeploymentStatus.html
+++ b/ajax/templates/ajax/openstackDeploymentStatus.html
@@ -5,6 +5,11 @@
{% else %}
is_deployed = true;
{% endif %}
+
+ function showSnapSetEditor() {
+ manuallyTogglePanel('createSnapDet', '');
+ }
+
@@ -12,7 +17,7 @@
{% if stack == None %}
-
+ |
Not yet deployed to OpenStack!
|
@@ -32,7 +37,7 @@
Status
|
-
+ |
{{ stack.stack_status }}
|
@@ -40,7 +45,7 @@
Status Detail
|
-
+ |
{{ stack.stack_status_reason }}
|
@@ -104,5 +109,24 @@
onclick="javascript: refreshDeploymentStatus('{{ topology_id }}');"/>
+
+
+
+
+ HEAT Snapshots
+ |
+
+
+
+
+ Create Snapshots
+
+
+
+ List Snapshots
+
+ |
+
+
{% endif %}
diff --git a/ajax/templates/ajax/scriptOutput.html b/ajax/templates/ajax/scriptOutput.html
index 3d456ea..60f9c3d 100644
--- a/ajax/templates/ajax/scriptOutput.html
+++ b/ajax/templates/ajax/scriptOutput.html
@@ -16,7 +16,7 @@
- Manage Scripts
+ Manage Scripts
|
diff --git a/ajax/templates/ajax/scripts.html b/ajax/templates/ajax/scripts.html
index 804de90..388fa50 100644
--- a/ajax/templates/ajax/scripts.html
+++ b/ajax/templates/ajax/scripts.html
@@ -31,7 +31,7 @@
{% endfor %}
- Manage Scripts
+ Manage Scripts
|
diff --git a/ajax/templates/ajax/snapshot_list.html b/ajax/templates/ajax/snapshot_list.html
new file mode 100644
index 0000000..f25ca61
--- /dev/null
+++ b/ajax/templates/ajax/snapshot_list.html
@@ -0,0 +1,61 @@
+{% extends "base.html" %}
+{% block title %}Wistar - Lab Rat - Snapshot List{% endblock %}
+{% load staticfiles %}
+{% block content %}
+
+
+
Stack Snapshot List
+
+ {% for message in messages %}
+ - {{ message }}
+ {% endfor %}
+
+
+
+ Name |
+ Snapshot Id |
+ Stack Name |
+ Options |
+
+ {% for snapshot in snapshot_list %}
+
+
+ {{snapshot.name }}
+ |
+
+ {{ snapshot.id }}
+ |
+
+ {{ snapshot.stack_name }}
+ |
+
+
+
+ |
+
+ {% endfor %}
+
+
+
+{% endblock %}
diff --git a/ajax/urls.py b/ajax/urls.py
index 59520b4..89eebff 100644
--- a/ajax/urls.py
+++ b/ajax/urls.py
@@ -43,7 +43,15 @@
url(r'^deployTopology/$', views.deploy_topology, name='deployTopology'),
url(r'^redeployTopology/$', views.redeploy_topology, name='redeployTopology'),
url(r'^deployStack/(?P[^/]+)$', views.deploy_stack, name='deployStack'),
+ url(r'^updateStack/$', views.update_stack, name='updateStack'),
url(r'^deleteStack/(?P[^/]+)$', views.delete_stack, name='deleteStack'),
+
+ url(r'^listSnapshot/(?P[^/]+)$', views.list_snapshot, name='listSnapshot'),
+ url(r'^deleteSnapshot/(?P[^/]+)/(?P[^/]+)/$', views.delete_snapshot,
+ name='deleteSnapshot'),
+ url(r'^rollbackSnapshot/(?P[^/]+)/(?P[^/]+)/$', views.rollback_snapshot,
+ name='rollbackSnapshot'),
+
url(r'^startTopology/$', views.start_topology, name='startTopology'),
url(r'^pauseTopology/$', views.pause_topology, name='pauseTopology'),
url(r'^manageDomain/$', views.manage_domain, name='manageDomain'),
diff --git a/ajax/views.py b/ajax/views.py
index c3c09fe..cdebcd6 100644
--- a/ajax/views.py
+++ b/ajax/views.py
@@ -874,6 +874,10 @@ def redeploy_topology(request):
except ObjectDoesNotExist:
return render(request, 'ajax/ajaxError.html', {'error': "Topology doesn't exist"})
+ if configuration.deployment_backend == "openstack":
+ logger.info('Redirecting to update stack')
+ return update_stack(request)
+
try:
domains = libvirtUtils.get_domains_for_topology(topology_id)
config = wistarUtils.load_config_from_topology_json(topo.json, topology_id)
@@ -1183,7 +1187,6 @@ def get_topology_config(request):
This is useful to get a list of all objects on the topolgy,
filter for objects of a specific type, and verify their boot up state.
i.e. to run a command against all Junos devices for example
-
"""
if 'topologyId' not in request.POST:
return render(request, 'ajax/ajaxError.html', {'error': "No Topology Id in request"})
@@ -1208,7 +1211,6 @@ def get_topology_config(request):
def execute_linux_automation(request):
"""
execute cli command on all linux instances in topology
-
"""
if 'topologyId' not in request.POST:
return render(request, 'ajax/ajaxError.html', {'error': "No Topology Id in request"})
@@ -1253,7 +1255,6 @@ def execute_linux_automation(request):
def execute_junos_automation(request):
"""
execute cli command on all junos instances in topology
-
"""
if 'topologyId' not in request.POST:
return render(request, 'ajax/ajaxError.html', {'error': "No Topology Id in request"})
@@ -1486,3 +1487,164 @@ def delete_stack(request, topology_id):
logger.debug(openstackUtils.delete_stack(stack_name))
return HttpResponseRedirect('/topologies/' + topology_id + '/')
+
+
+def update_stack(request):
+ """
+ :param request: Django request
+ :param topology_id: id of the topology to export
+ :return: renders the updated heat template
+ """
+ required_fields = set(['topologyId'])
+ if not required_fields.issubset(request.POST):
+ return render(request, 'ajax/ajaxError.html', {'error': "Invalid Parameters in POST"})
+
+ topology_id = request.POST['topologyId']
+
+ logger.debug("-----Inside update stack-----")
+ try:
+ topology = Topology.objects.get(pk=topology_id)
+ except ObjectDoesNotExist:
+ return render(request, 'error.html', {'error': "Topology not found!"})
+ try:
+ # let's parse the json and convert to simple lists and dicts
+ logger.debug("loading config")
+ config = wistarUtils.load_config_from_topology_json(topology.json, topology_id)
+ logger.debug("Config is loaded")
+
+ # get the tenant_id of the desired project
+ tenant_id = openstackUtils.get_project_id(configuration.openstack_project)
+ logger.debug("using tenant_id of: %s" % tenant_id)
+ if tenant_id is None:
+ raise Exception("No project found for %s" % configuration.openstack_project)
+
+ # FIXME - verify all images are in glance before jumping off here!
+ stack_name = topology.name.replace(' ', '_')
+
+ port_list = openstackUtils.get_stack_ports(stack_name, tenant_id)
+ print(port_list)
+ heat_template = wistarUtils.get_heat_json_from_topology_config_for_update(config, port_list)
+ logger.debug("heat template created---test1")
+ logger.debug(heat_template)
+
+ logger.debug(openstackUtils.update_stack_template(stack_name, heat_template))
+ return refresh_deployment_status(request)
+
+ except Exception as e:
+ logger.debug("Caught Exception in deploy")
+ logger.debug(str(e))
+ return render(request, 'error.html', {'error': str(e)})
+
+
+def list_snapshot(request, topology_id):
+ """
+ :param request: Django request
+ :param topology_id: id of the topology to export
+ :return: creates a snapshot of the heat template
+ """
+ try:
+ logger.debug("Inside create Snapshot----------")
+ tenant_id = openstackUtils.get_project_id(configuration.openstack_project)
+ logger.debug("using tenant_id of: %s" % tenant_id)
+ if tenant_id is None:
+ raise Exception("No project found for %s" % configuration.openstack_project)
+
+ logger.debug("Topology id -------------------: %s" % topology_id)
+
+ try:
+ topology = Topology.objects.get(pk=topology_id)
+ except ObjectDoesNotExist:
+ logger.error('topology id %s was not found!' % topology_id)
+ return render(request, 'error.html', {'error': "Topology not found!"})
+
+ # FIXME - verify all images are in glance before jumping off here!
+ stack_name = topology.name.replace(' ', '_')
+ snapshot_list = list()
+ logger.debug("-------------------stack_name--------------------: %s" % stack_name)
+ if openstackUtils.connect_to_openstack():
+ snapshot_list = openstackUtils.get_snapshot_list(tenant_id, stack_name, topology_id)
+
+ context = {'snapshot_list': snapshot_list}
+ logger.debug("Before rendering-----------")
+ return render(request, 'ajax/snapshot_list.html', context)
+
+ except Exception as e:
+ logger.debug("Caught Exception in deploy")
+ logger.debug(str(e))
+ return render(request, 'error.html', {'error': str(e)})
+
+
+def rollback_snapshot(request, snapshot_id, topology_id):
+ """
+ :param request: Django request
+ :param topology_id: id of the topology to export
+ :return: creates a snapshot of the heat template
+ """
+
+ try:
+ logger.debug("Inside rollback Snapshot----------")
+ tenant_id = openstackUtils.get_project_id(configuration.openstack_project)
+ logger.debug("using tenant_id of: %s" % tenant_id)
+ if tenant_id is None:
+ raise Exception("No project found for %s" % configuration.openstack_project)
+
+ logger.debug("Topology id -------------------: %s" % topology_id)
+
+ try:
+ topology = Topology.objects.get(pk=topology_id)
+ except ObjectDoesNotExist:
+ logger.error('topology id %s was not found!' % topology_id)
+ return render(request, 'error.html', {'error': "Topology not found!"})
+
+ # FIXME - verify all images are in glance before jumping off here!
+ stack_name = topology.name.replace(' ', '_')
+ logger.debug("Stack name: %s" % stack_name)
+ logger.debug("Snapshot id: %s" % snapshot_id)
+
+ if openstackUtils.connect_to_openstack():
+ logger.debug(openstackUtils.rollback_snapshot(tenant_id, stack_name, snapshot_id))
+
+ return HttpResponseRedirect('/topologies/' + topology_id + '/')
+
+ except Exception as e:
+ logger.debug("Caught Exception in deploy")
+ logger.debug(str(e))
+ return render(request, 'error.html', {'error': str(e)})
+
+
+def delete_snapshot(request, snapshot_id, topology_id):
+ """
+ :param request: Django request
+ :param topology_id: id of the topology to export
+ :return: creates a snapshot of the heat template
+ """
+
+ try:
+ logger.debug("Inside rollback Snapshot----------")
+ tenant_id = openstackUtils.get_project_id(configuration.openstack_project)
+ logger.debug("using tenant_id of: %s" % tenant_id)
+ if tenant_id is None:
+ raise Exception("No project found for %s" % configuration.openstack_project)
+
+ logger.debug("Topology id -------------------: %s" % topology_id)
+
+ try:
+ topology = Topology.objects.get(pk=topology_id)
+ except ObjectDoesNotExist:
+ logger.error('topology id %s was not found!' % topology_id)
+ return render(request, 'error.html', {'error': "Topology not found!"})
+
+ # FIXME - verify all images are in glance before jumping off here!
+ stack_name = topology.name.replace(' ', '_')
+ logger.debug("Stack name: %s" % stack_name)
+ logger.debug("Snapshot id: %s" % snapshot_id)
+
+ if openstackUtils.connect_to_openstack():
+ logger.debug(openstackUtils.delete_snapshot(tenant_id, stack_name, snapshot_id))
+
+ return HttpResponseRedirect('/topologies/' + topology_id + '/')
+
+ except Exception as e:
+ logger.debug("Caught Exception in deploy")
+ logger.debug(str(e))
+ return render(request, 'error.html', {'error': str(e)})
diff --git a/common/lib/openstackUtils.py b/common/lib/openstackUtils.py
index fc48a29..422dfd1 100644
--- a/common/lib/openstackUtils.py
+++ b/common/lib/openstackUtils.py
@@ -863,3 +863,205 @@ def do_delete(url, data=""):
logger.error("Could not perform DELETE to url: %s" % url)
logger.error("error was %s" % str(e))
return None
+
+
+
+
+def create_stack_snapshot(stack_name, tenant_id, snapshot_name):
+ """
+ Creates a snapshot of the Stack via a HEAT REST call
+ :param stack_name: name of the stack to create
+ :param tenant_id: tenant id of the openstack project
+ :param snapshot_name: name of the snapshot
+ :return: JSON response from HEAT-API or None on failure
+ """
+ logger.debug("In create stack snapshot--------------")
+ stack_details = get_stack_details(stack_name)
+ if stack_details is None:
+ return None
+ else:
+ stack_id = str(stack_details["id"])
+
+ #stack_id = get_stack_details(stack_name)
+ create_snapshot_url = create_heat_url("/" + str(tenant_id) + "/stacks/%s/%s/snapshots" % (stack_name, stack_id))
+ data = """{
+ "name": "%s"
+ }""" % snapshot_name
+ logger.debug("Data before posting-----------")
+ logger.debug(data)
+
+ return do_post(create_snapshot_url, data)
+
+
+
+def get_snapshot_list(tenant_id, stack_name, topology_id):
+
+ print("In snapshot list")
+
+ stack_details = get_stack_details(stack_name)
+ if stack_details is None:
+ return None
+ else:
+ stack_id = str(stack_details["id"])
+ snapshot_list_url = create_heat_url('/%s/stacks/%s/%s/snapshots' % (tenant_id, stack_name, stack_id))
+ stack_snapshot_list = do_get(snapshot_list_url)
+ l1 = json.loads(stack_snapshot_list)
+ #l2 = l1['snapshots']
+ snap_list = list()
+
+ for snap in l1["snapshots"]:
+ if snap["status"] == "COMPLETE":
+ snap_detail = get_snap_detail(snap, stack_name, topology_id)
+ snap_list.append(snap_detail)
+ logger.debug(snap_list)
+ return snap_list
+
+def get_snap_detail(snap, stack_name, topology_id):
+
+ logger.debug("Getting snapshot details-------------")
+ logger.debug(snap)
+ snap_list = dict()
+ snap_list["name"] = snap["name"]
+ snap_list["id"] = snap["id"]
+ snap_list["stack_name"] = stack_name
+ snap_list["topology_id"] = str(topology_id)
+
+ return snap_list
+
+def get_server_details(search_string):
+ server_details_url = create_nova_url('/servers?name=%s' % search_string)
+ server_details_json = do_get(server_details_url)
+ server_details_dict = json.loads(server_details_json)
+
+ if server_details_dict is None:
+ return None
+ else:
+ server_details_list = list()
+ server_details_list = server_details_dict['servers']
+ for det in server_details_list:
+ server_details = det['id']
+ logger.debug(server_details)
+ return server_details
+
+
+
+
+def delete_snapshot(tenant_id, stack_name, snapshot_id):
+ """
+ Deletes a stack from OpenStack
+ :param stack_name: name of the stack to be deleted
+ :return: JSON response fro HEAT API
+ """
+ logger.debug("--- delete_stack_snapshot ---")
+
+ stack_details = get_stack_details(stack_name)
+ if stack_details is None:
+ return None
+ else:
+ stack_id = stack_details["id"]
+ url = create_heat_url("/%s/stacks/%s/%s/snapshots/%s" % (tenant_id, stack_name, stack_id, snapshot_id))
+ return do_delete(url)
+
+
+
+def rollback_snapshot(tenant_id, stack_name, snapshot_id):
+ """
+ Deletes a stack from OpenStack
+ :param stack_name: name of the stack to be deleted
+ :return: JSON response fro HEAT API
+ """
+ logger.debug("--- delete_stack_snapshot ---")
+ data = ""
+ stack_details = get_stack_details(stack_name)
+ if stack_details is None:
+ return None
+ else:
+ stack_id = stack_details["id"]
+ url = create_heat_url("/%s/stacks/%s/%s/snapshots/%s/restore" % (tenant_id, stack_name, stack_id, snapshot_id))
+ return do_post(url, data)
+
+
+
+def rebuild_instance_openstack(server_id, image_id):
+ logger.debug("-------Rebuild server openstack")
+ url = create_nova_url("/servers/%s/action" % server_id)
+ data = '''{
+ "rebuild" : {
+ "imageRef" : "%s"
+ }
+ }''' % str(image_id)
+
+ return do_post(url, data)
+
+
+
+
+def update_stack_template(stack_name, template_string):
+
+ """
+ Creates a Stack via a HEAT template
+ :param stack_name: name of the stack to create
+ :param template_string: HEAT template to be used
+ :return: JSON response from HEAT-API or None on failure
+ """
+ logger.debug("--- update_stack ---")
+ stack_details = get_stack_details(stack_name)
+ if stack_details is None:
+ return None
+ else:
+ stack_id = stack_details["id"]
+
+ url = create_heat_url("/" + str(_tenant_id) + "/stacks/%s/%s" % (stack_name, stack_id))
+ logger.debug("URL to update stack")
+ logger.debug(url)
+ data = '''{
+ "disable_rollback": true,
+ "parameters": {},
+ "template": %s
+ }''' % (template_string)
+ logger.debug("updating CREATING stack with data:")
+ logger.debug(data)
+ try:
+ request = urllib2.Request(url)
+ request.add_header("Content-Type", "application/json")
+ request.add_header("charset", "UTF-8")
+ request.add_header("X-Auth-Token", _auth_token)
+ request.get_method = lambda: 'PATCH'
+
+ if data == "":
+ result = urllib2.urlopen(request)
+ else:
+ result = urllib2.urlopen(request, data)
+
+ return result.read()
+ except URLError as e:
+ logger.error("Could not perform PUT to url: %s" % url)
+ logger.error("error was %s" % str(e))
+ return None
+ #return do_post(url, data)
+
+
+def get_stack_ports(stack_name, tenant_id):
+ stack_details = get_stack_details(stack_name)
+
+ if stack_details is None:
+ return None
+ else:
+ stack_id = str(stack_details["id"])
+
+ try:
+ get_port_url = create_heat_url( '/%s/stacks/%s/%s/resources?type=OS::Neutron::Port' % (tenant_id, stack_name, stack_id))
+ resources = do_get(get_port_url)
+ resource_dict = json.loads(resources)
+ resource_list = resource_dict['resources']
+ print(resource_list)
+ port_list = list()
+ for port in resource_list:
+ port_list.append(port['resource_name'])
+ print(port_list)
+ return port_list
+
+ except URLError as e:
+ logger.error("Could not perform PUT to url: %s" % url)
+ logger.error("error was %s" % str(e))
+ return None
diff --git a/common/lib/wistarUtils.py b/common/lib/wistarUtils.py
index cdaf800..2bd0a04 100644
--- a/common/lib/wistarUtils.py
+++ b/common/lib/wistarUtils.py
@@ -304,6 +304,7 @@ def get_heat_json_from_topology_config(config, project_name='admin'):
# disable port security on all other ports (in case this isn't set globally)
p['port_security_enabled'] = False
+ p["name"] = device["name"] + "_port" + str(index)
pr["properties"] = p
template["resources"][device["name"] + "_port" + str(index)] = pr
index += 1
@@ -311,6 +312,249 @@ def get_heat_json_from_topology_config(config, project_name='admin'):
return json.dumps(template)
+
+def get_heat_json_from_topology_config_for_update(config, port_list):
+ """
+ Generates heat template from the topology configuration object
+ use load_config_from_topology_json to get the configuration from the Topology
+ :param config: configuration dict from load_config_from_topology_json
+ :return: json encoded heat template as String
+ """
+
+ template = dict()
+ template["heat_template_version"] = "2013-05-23"
+ template["resources"] = dict()
+
+ for network in config["networks"]:
+ nr = dict()
+ nr["type"] = "OS::Neutron::Net"
+
+ nrp = dict()
+ nrp["shared"] = False
+ nrp["name"] = network["name"]
+ nrp["admin_state_up"] = True
+
+ nr["properties"] = nrp
+
+ nrs = dict()
+ nrs["type"] = "OS::Neutron::Subnet"
+ #
+ p = dict()
+ p["cidr"] = "1.1.1.0/24"
+ p["enable_dhcp"] = False
+ p["gateway_ip"] = ""
+ p["name"] = network["name"] + "_subnet"
+ if network["name"] == "virbr0":
+ p["network_id"] = configuration.openstack_mgmt_network
+ elif network["name"] == configuration.openstack_external_network:
+ p["network_id"] = configuration.openstack_external_network
+ else:
+ p["network_id"] = {"get_resource": network["name"]}
+
+ nrs["properties"] = p
+
+ template["resources"][network["name"]] = nr
+ template["resources"][network["name"] + "_subnet"] = nrs
+
+ # cache the image_details here to avoid multiple REST calls for details about an image type
+ # as many topologies have lots of the same types of images around
+ image_details_dict = dict()
+
+ for device in config["devices"]:
+
+ if device["imageId"] in image_details_dict:
+ image_details = image_details_dict[device["imageId"]]
+ else:
+ image_details = imageUtils.get_image_detail(device["imageId"])
+ image_details_dict[device["imageId"]] = image_details
+
+ image_name = image_details["name"]
+
+ image_disk_size = 20
+
+ # set the size in GB, rounding up to the nearest int
+ if 'size' in image_details:
+ current_size = int(image_details['size'])
+ image_disk_size = int(math.ceil(current_size / 100000000))
+
+ # if the flavor asks for a minimum disk size, let's see if it's larger that what we have
+ if "min_disk" in image_details and image_details['min_disk'] > image_disk_size:
+ image_disk_size = image_details["min_disk"]
+
+ # if the user has specified a desired disk size, grab it here so we get the correct flavor
+ if type(image_disk_size) is int and device["resizeImage"] > image_disk_size:
+ image_disk_size = device["resizeImage"]
+
+ # determine openstack flavor here
+ device_ram = int(device["ram"])
+ device_cpu = int(device["cpu"])
+
+ flavor_detail = openstackUtils.get_minimum_flavor_for_specs(configuration.openstack_project,
+ device_cpu,
+ device_ram,
+ image_disk_size
+ )
+
+ flavor = flavor_detail["name"]
+
+ dr = dict()
+ dr["type"] = "OS::Nova::Server"
+ dr["properties"] = dict()
+ dr["properties"]["flavor"] = flavor
+ dr["properties"]["networks"] = []
+ index = 0
+ for p in device["interfaces"]:
+ port = dict()
+ port["port"] = dict()
+
+ if index == 0:
+ port["port"]["get_resource"] = device["name"] + "_port" + str(index)
+ else:
+ if device["name"] + "_port" + str(index) in port_list:
+ port["port"]["get_resource"] = device["name"] + "_port" + str(index) + "_nora"
+ else:
+ port["port"]["get_resource"] = device["name"] + "_port" + str(index)
+ index += 1
+ dr["properties"]["networks"].append(port)
+
+ dr["properties"]["image"] = image_name
+ dr["properties"]["name"] = device["name"]
+
+ if device["configDriveSupport"]:
+ dr["properties"]["config_drive"] = True
+ dr["properties"]["user_data_format"] = "RAW"
+ metadata = dict()
+ metadata["hostname"] = device["name"]
+ metadata["console"] = "vidconsole"
+ dr["properties"]["metadata"] = metadata
+
+ # let's check all the configDriveParams and look for a junos config
+ # FIXME - this may need tweaked if we need to include config drive cloud-init support for other platforms
+ # right now we just need to ignore /boot/loader.conf
+ for cfp in device["configDriveParams"]:
+
+ if "destination" in cfp and cfp["destination"] == "/boot/loader.conf":
+ logger.debug("Creating loader.conf config-drive entry")
+ template_name = cfp["template"]
+ loader_string = osUtils.compile_config_drive_params_template(template_name,
+ device["name"],
+ device["label"],
+ device["password"],
+ device["ip"],
+ device["managementInterface"])
+
+ logger.debug('----------')
+ logger.debug(loader_string)
+ logger.debug('----------')
+ for l in loader_string.split('\n'):
+ if '=' in l:
+ left, right = l.split('=')
+ if left not in metadata and left != '':
+ metadata[left] = right.replace('"', '')
+
+ if "destination" in cfp and cfp["destination"] == "/juniper.conf":
+ logger.debug("Creating juniper.conf config-drive entry")
+ template_name = cfp["template"]
+ personality_string = osUtils.compile_config_drive_params_template(template_name,
+ device["name"],
+ device["label"],
+ device["password"],
+ device["ip"],
+ device["managementInterface"])
+
+ dr["properties"]["personality"] = dict()
+ dr["properties"]["personality"] = {"/config/juniper.conf": personality_string}
+ else:
+ logger.debug('No juniper.conf found here ')
+
+ if device['cloudInitSupport']:
+ logger.debug('creating cloud-init script')
+ dr["properties"]["config_drive"] = True
+ dr["properties"]["user_data_format"] = "RAW"
+ metadata = dict()
+ metadata["hostname"] = device["name"]
+ dr["properties"]["metadata"] = metadata
+ # grab the prefix len from the management subnet which is in the form 192.168.122.0/24
+ if '/' in configuration.management_subnet:
+ management_prefix_len = configuration.management_subnet.split('/')[1]
+ else:
+ management_prefix_len = '24'
+
+ management_ip = device['ip'] + '/' + management_prefix_len
+
+ device_config = osUtils.get_cloud_init_config(device['name'],
+ device['label'],
+ management_ip,
+ device['managementInterface'],
+ device['password'])
+
+ script_string = ""
+ if "configScriptId" in device and device["configScriptId"] != 0:
+ logger.debug("Passing script data!")
+ try:
+ script = Script.objects.get(pk=int(device["configScriptId"]))
+ script_string = script.script
+ device_config["script_param"] = device.get("configScriptParam", '')
+ logger.debug(script_string)
+ except ObjectDoesNotExist:
+ logger.info('config script was specified but was not found!')
+
+ user_data_string = osUtils.render_cloud_init_user_data(device_config, script_string)
+ dr["properties"]["user_data"] = user_data_string
+
+ template["resources"][device["name"]] = dr
+
+ for device in config["devices"]:
+ index = 0
+ for port in device["interfaces"]:
+ pr = dict()
+ pr["type"] = "OS::Neutron::Port"
+ p = dict()
+
+ if port["bridge"] == "virbr0":
+ p["network_id"] = configuration.openstack_mgmt_network
+
+ # specify our desired IP address on the management interface
+ p['fixed_ips'] = list()
+ fip = dict()
+ fip['ip_address'] = device['ip']
+ p['fixed_ips'].append(fip)
+
+ elif port["bridge"] == configuration.openstack_external_network:
+ p["network_id"] = configuration.openstack_external_network
+ else:
+ p["network_id"] = {"get_resource": port["bridge"]}
+ # disable port security on all other ports (in case this isn't set globally)
+ p['port_security_enabled'] = False
+
+ if index == 0:
+ p["name"] = device["name"] + "_port" + str(index)
+ else:
+ if device["name"] + "_port" + str(index) in port_list:
+ p["name"] = device["name"] + "_port" + str(index) + "_nora"
+ else:
+ p["name"] = device["name"] + "_port" + str(index)
+
+ pr["properties"] = p
+ if index == 0:
+ template["resources"][device["name"] + "_port" + str(index)] = pr
+ else:
+ if device["name"] + "_port" + str(index) in port_list:
+ template["resources"][device["name"] + "_port" + str(index) + "_nora"] = pr
+ else:
+ template["resources"][device["name"] + "_port" + str(index)] = pr
+ index += 1
+
+ return json.dumps(template)
+
+
+
+
+
+
+
+
+
def _get_management_macs_for_topology(topology_id):
"""
returns a list of all macs used for management interfaces for a topology
diff --git a/topologies/templates/topologies/edit.html b/topologies/templates/topologies/edit.html
index e7d823e..f4aecaa 100644
--- a/topologies/templates/topologies/edit.html
+++ b/topologies/templates/topologies/edit.html
@@ -1217,6 +1217,60 @@
manuallyTogglePanel('configSetCreateRow', 'none');
}
+function submitSnapForm() {
+ var r = confirm("Create Snapshot of the template?");
+
+ if (r == true) {
+
+ jQuery('#createSnapForm').submit();
+ }
+ }
+
+
+function rebuild_instance() {
+
+ var doc = jQuery(document.documentElement);
+ doc.css('cursor', 'progress');
+
+ if ('getName' in s) {
+ instance_name = s.getName();
+
+ } else {
+ console.log('Could not rebuild instance');
+ alert('Could not launch rebuild instance');
+ doc.css('cursor', '');
+ }
+ var url = '/topologies/rebuildInstance/';
+ var params = {
+ 'instance_name' : instance_name,
+ 'topology_id' : '{{topo_id}}'
+ };
+ var post = jQuery.post(url, params, function(response) {
+ var content = jQuery(response);
+ jQuery('#overlayPanel').empty().append(content);
+ showOverlay('#overlayPanel');
+ });
+ post.fail(function() {
+ alert('Could not perform request!');
+ });
+ post.always(function() {
+ doc.css('cursor', '');
+ });
+ }
+
+
+
+
+
+ function rebuild_server_submit() {
+ var r = confirm("Rebuild the Instance?");
+
+ if (r == true) {
+
+ jQuery('#rebuildServerForm').submit();
+ }
+ }
+
function showTopoEditor() {
manuallyTogglePanel('topoEditorForm', '');
manuallyTogglePanel('topoInfo', 'none');
@@ -2063,7 +2117,7 @@
@@ -2155,6 +2206,11 @@
|
+ {% if global_config.deployment_backend == "openstack" and is_deployed == true %}
+
+
+ |
+ {% endif %}
@@ -2528,6 +2584,46 @@
+
+
+
+
+
+
+
{% if topo_id != None %}