--- /dev/null
+# -*- coding:utf-8 -*-
+
+from django import forms
+from models import Lab, Course
+from django.db import models
+
+class LabForm(forms.ModelForm):
+ title = forms.CharField(label= "Title")
+ subject = forms.FileField(label="Subject of the lab")
+ class Meta:
+ model = Lab
+
+class courseForm(forms.Form):
+ lab = forms.ModelChoiceField(queryset= Lab.objects.all(), empty_label="Select a Lab")
+ nbEnv = forms.IntegerField(min_value=0, label="Number of environment")
+ subnet = forms.CharField(initial='10.1.0.0/16')
+
--- /dev/null
+# -*- coding:utf-8 -*-
+
+from django.db import models
+
+# Used for automatically delete file
+from django.dispatch import receiver
+import os
+
+# Class to describe a service set on a host
+class Service(models.Model):
+ serviceName = models.CharField(max_length=50)
+ servicePort = models.CharField(max_length=10)
+ host = models.ForeignKey('Host')
+
+ def __unicode__(self):
+ if self.servicePort != u'':
+ return u"%s on %s" % (self.serviceName, self.servicePort)
+ else:
+ return u"%s" % self.serviceName
+
+# Class to describe an interface available on a host
+class Interface(models.Model):
+ ip = models.CharField(max_length=16)
+ name = models.CharField(max_length=40)
+ host = models.ForeignKey('Host')
+
+ def __unicode__(self):
+ return u"%s -> %s" % (self.name, self.ip)
+
+# Class to describe a host
+class Host(models.Model):
+ TYPE_CHOICES = (
+ ('PUB', 'Public'),
+ ('PRIV', 'Private'),
+ ('COM', 'Common'),
+ )
+ hostname = models.CharField(max_length=100)
+ hostType = models.CharField(max_length=20, choices=TYPE_CHOICES, default='PRIV')
+ pleSlice = models.ForeignKey('Slice')
+ latitude = models.FloatField()
+ longitude = models.FloatField()
+
+ def __unicode__(self):
+ return u"%s %s" % (self.hostname, self.hostType)
+
+# Class to describe a slice (sliceName and reference to environment)
+class Slice(models.Model):
+ sliceName = models.CharField(max_length=50)
+ environment = models.ForeignKey('Environment')
+
+ def __unicode__(self):
+ return u"%s" % self.sliceName
+
+# Class to describe a student environment (sshKey and reference to a course)
+class Environment(models.Model):
+ sshKey = models.FileField(upload_to='ict_education/keys')
+ course = models.ForeignKey('Course')
+ confFile = models.FileField(upload_to='ict_education/xmlFiles')
+ linkFile = models.FileField(upload_to='ict_education/xmlFiles')
+ ready = models.BooleanField(default=False)
+
+# function used to automatically delete the stored file when deleting the model from the database
+@receiver(models.signals.post_delete, sender = Environment)
+def environment_delete_ssh_key(sender, instance, **kwargs):
+ if instance.sshKey:
+ if os.path.isfile(instance.sshKey.path):
+ os.remove(instance.sshKey.path)
+ if instance.confFile:
+ if os.path.isfile(instance.confFile.path):
+ os.remove(instance.confFile.path)
+ if instance.linkFile:
+ if os.path.isfile(instance.linkFile.path):
+ os.remove(instance.linkFile.path)
+
+# Class to describe a course (ie a set of environment) (reference to lab, mainKey used by the teacher to access all node)
+class Course(models.Model):
+ lab = models.ForeignKey('Lab')
+ mainKey = models.FileField(upload_to='ict_education/keys', null = True)
+ ready = models.BooleanField(default=False)
+ sliceName = models.CharField(max_length=50)
+
+ def __unicode__(self):
+ return u"%s %s" % (self.lab, self.sliceName)
+
+# function used to automatically delete the stored file when deleting the model from the database
+@receiver(models.signals.post_delete, sender = Course)
+def course_delete_main_ssh_key(sender, instance, **kwargs):
+ if instance.mainKey:
+ if os.path.isfile(instance.mainKey.path):
+ os.remove(instance.mainKey.path)
+
+# Class to describe a lab
+class Lab(models.Model):
+ title = models.CharField(max_length=100)
+ author = models.CharField(max_length=40)
+ subject = models.FileField(upload_to='ict_education/Labs/subjects')
+ configurationFile = models.FileField(upload_to='ict_education/Labs/xmlFiles')
+ linkFile = models.FileField(upload_to='ict_education/Labs/xmlFiles')
+
+ def __unicode__(self):
+ return u"%s %s" % (self.title, self.author)
+
+# function used to automatically delete the stored file when deleting the model from the database
+@receiver(models.signals.post_delete, sender = Lab)
+def lab_delete_files(sender, instance, **kwargs):
+ # Remove the subject
+ if instance.subject:
+ if os.path.isfile(instance.subject.path):
+ os.remove(instance.subject.path)
+ # Remove the configuration file
+ if instance.configurationFile:
+ if os.path.isfile(instance.configurationFile.path):
+ os.remove(instance.configurationFile.path)
+ # Remove the link file
+ if instance.linkFile:
+ if os.path.isfile(instance.linkFile.path):
+ os.remove(instance.linkFile.path)
+
--- /dev/null
+#!/usr/bin/python
+import xmlrpclib
+
+auth={'AuthMethod': 'password', 'Username': 'pierre.vigreux@lip6.fr', 'AuthString': '1245780'}
+
+plc_host='www.planet-lab.eu'
+api_url="https://%s:443/PLCAPI/"%plc_host
+
+plc_api= xmlrpclib.ServerProxy(api_url, allow_none=True)
+
+def printRes(results):
+ for result in results:
+ print result
--- /dev/null
+#!/usr/bin/python
+import xmlrpclib
+
+auth={'AuthMethod': 'password', 'Username': 'pierre.vigreux@lip6.fr', 'AuthString': '1245780'}
+
+plc_host='www.planet-lab.eu'
+api_url="https://%s:443/PLCAPI/"%plc_host
+
+plc_api= xmlrpclib.ServerProxy(api_url, allow_none=True)
+
+def printRes(results):
+ for result in results:
+ print result
--- /dev/null
+#!/usr/bin/env python
+# Update with latest key
+
+from Auth import *
+
+keyId = plc_api.GetKeys(auth, {'person_id': 249241}, ['key_id'])
+for key in keyId:
+ if key['key_id'] != 117822:
+ plc_api.DeleteKey(auth, key['key_id'])
+ print "Deleting a key id ->",key['key_id']
+
--- /dev/null
+#!/usr/bin/python
+
+import xmlrpclib
+import Auth
+import sys
+
+plc_host='www.planet-lab.eu'
+slice_pref='upmc_'
+
+api_url='https://%s:443/PLCAPI/'%plc_host
+plc_api=xmlrpclib.ServerProxy(api_url, allow_none=True)
+
+slice_name = slice_pref+raw_input('Give the name of the slice : ')
+
+try:
+ returnCode = plc_api.DeleteSlice(Auth.auth, slice_name)
+except Exception, why:
+ print "An error occured while trying to delete the slice "+slice_name
+ print why
+ sys.exit(2)
+if returnCode != 1:
+ print "An error occured while trying to delete the slice "+slice_name
--- /dev/null
+#!/usr/bin/python
+from Auth import *
+
+nodesLxc = plc_api.GetNodeTags(auth, {'value': 'lxc', 'tagname':'pldistro'}, ['node_id', 'hostname'])
+
+site_ids = []
+for node in nodesLxc:
+ site_ids.append(plc_api.GetNodes(auth, node['node_id'], ['site_id'])[0]['site_id'])
+
+sites = plc_api.GetSites(auth, site_ids, ['site_id', 'name', 'abbreviated_name'])
+for site in sites:
+ print site
--- /dev/null
+#!/usr/bin/python
+import xmlrpclib
+import getpass
+import Auth
+
+plc_host='www.planet-lab.eu'
+
+api_url="https://%s:443/PLCAPI/"%plc_host
+plc_api= xmlrpclib.ServerProxy(api_url, allow_none=True)
+
+nodeId = int(raw_input("Give me the node id: "))
+
+nodes = plc_api.GetNodes(Auth.auth, [nodeId], ['boot_state', 'site_id', 'hostname'])
+
+for node in nodes:
+ print node
--- /dev/null
+#!/usr/bin/python
+import xmlrpclib
+import getpass
+import Auth
+
+plc_host='www.planet-lab.eu'
+
+api_url="https://%s:443/PLCAPI/"%plc_host
+plc_api= xmlrpclib.ServerProxy(api_url, allow_none=True)
+
+siteId = raw_input("Give me the id of the site : ")
+try:
+ siteId = int(siteId)
+except Exception, why:
+ pass
+print type(siteId)
+sites = plc_api.GetSites(Auth.auth, [siteId], ['site_id', 'name', 'max_slices', 'slice_ids', 'node_ids', 'ext_consortium_id', 'login_base'])
+
+i = j = 0
+for site in sites:
+ if i <= 5:
+ print site
+ i+=1
+ else:
+ j+=1
+
+print "i = ",i," j = ",j
--- /dev/null
+#!/usr/bin/python
+import xmlrpclib
+import Auth
+
+plc_host='www.planet-lab.eu'
+slice_name='upmc_tp'
+
+api_url="https://%s:443/PLCAPI/"%plc_host
+plc_api= xmlrpclib.ServerProxy(api_url, allow_none=True)
+
+N = input("Number of environment wanted :")
+M = input("Number of node wanted by environment :")
+sites = plc_api.GetSites(Auth.auth, ['*'], ['site_id', 'name', 'max_slices', 'slice_ids', 'node_ids'])
+sitesSelected = []
+
+i = 0
+for site in sites:
+ if i < N:
+ j = 0
+ nodesSite = plc_api.GetNodes(Auth.auth, site['node_ids'], ['hostname', 'run_level', 'boot_state'])
+ for node in nodesSite:
+ #print node
+ if node['boot_state'] == 'boot' and node['run_level'] == 'boot':
+ j+=1
+ if j >= M:
+ i += 1
+ sitesSelected.append(site)
+
+for site in sitesSelected:
+ print site['name'], site['site_id']
+
+if len(sitesSelected) < N:
+ print "\tWe just manage to find ",len(sitesSelected),"environment"
--- /dev/null
+#!/usr/bin/python
+
+import xmlrpclib
+import Auth
+import sys
+
+slice_pref='upmc_'
+
+plc_host='www.planet-lab.eu'
+api_url="https://%s:443/PLCAPI/"%plc_host
+
+plc_api= xmlrpclib.ServerProxy(api_url, allow_none=True)
+
+sliceName = slice_pref+raw_input("Give me the name of the slice : ")
+
+sliceWanted = None
+slices = plc_api.GetSlices(Auth.auth, sliceName, ['creator_person_id', 'name', 'max_nodes', 'node_ids', 'person_ids', 'slice_id'])
+
+if len(slices) > 0:
+ for slice_i in slices:
+ print slice_i['name']
+ sliceWanted = slices[0]
+
+if sliceWanted == None:
+ print "The slice "+sliceName+" doesn't exist"
+ sys.exit(2)
+persons = plc_api.GetPersons(Auth.auth, sliceWanted['person_ids'], ['first_name', 'email'])
+nodes = plc_api.GetNodes(Auth.auth, sliceWanted['node_ids'], ['hostname', 'site_id', 'node_id'])
+
+tags = plc_api.GetSliceTags(Auth.auth, {'slice_id': sliceWanted['slice_id']}, ['description', 'tagname', 'value', 'slice_tag_id'])
+
+creator = plc_api.GetPersons(Auth.auth, sliceWanted['creator_person_id'], ['first_name', 'email'])
+
+
+for person in persons:
+ print person
+
+if creator not in persons:
+ print "\tCreator"
+ print "\t\t"+str(creator)
+else:
+ print "\tCreator is in user list"
+
+print sliceWanted
+for node in nodes:
+ print "\t"+str(node)
+ pass
+print "Tag list"
+for tag in tags:
+ #print "\t"+str(tag)
+ pass
--- /dev/null
+#!/usr/bin/env python
+
+from Auth import *
+
+keyId = plc_api.GetKeys(auth, {'person_id': 249241}, ['key_id', 'key'])
+for key in keyId:
+ print "A new key:"
+ print "Key value ->", key['key']
+ print "Key id ->",key['key_id']
+
--- /dev/null
+#!/usr/bin/python
+import xmlrpclib
+import Auth
+
+plc_host='www.planet-lab.eu'
+slice_pref='upmc_'
+
+slice_name=slice_pref+raw_input('Give me the name of the slice : ')
+
+api_url="https://%s:443/PLCAPI/"%plc_host
+plc_api= xmlrpclib.ServerProxy(api_url, allow_none=True)
+
+# The slice's node ids
+node_ids = plc_api.GetSlices(Auth.auth, slice_name,['node_ids'])[0]['node_ids']
+
+# Get Hostname for these nodes
+slice_nodes = plc_api.GetNodes(Auth.auth, node_ids, ['hostname', 'run_level'])
+
+for node in slice_nodes:
+ print node
--- /dev/null
+Slice name : upmc_testForge
+ Env 1
+ distance : 0 hostname : planetlab2.upc.es longitude : 2.11273 latitude : 41.3897 type : private id : 931
+ distance : 0 hostname : aguila1.lsi.upc.edu longitude : 2.11273 latitude : 41.3897 type : common id : 15840
+ distance : 1198 hostname : aladdin.planetlab.extranet.uni-passau.de longitude : 13.47 latitude : 48.58 type : common id : 14809
+ distance : 19310 hostname : planetlab-n2.wand.net.nz longitude : 175.318 latitude : -37.7892 type : common id : 14617
+ Env 2
+ distance : 0 hostname : planetlab1.upc.es longitude : 2.11273 latitude : 41.3897 type : private id : 930
+ distance : 0 hostname : aguila1.lsi.upc.edu longitude : 2.11273 latitude : 41.3897 type : common id : 15840
+ distance : 1198 hostname : aladdin.planetlab.extranet.uni-passau.de longitude : 13.47 latitude : 48.58 type : common id : 14809
+ distance : 19310 hostname : planetlab-n2.wand.net.nz longitude : 175.318 latitude : -37.7892 type : common id : 14617
--- /dev/null
+#!/usr/bin/env python
+
+from serviceScript import *
+
+class String:
+ def __init__(self):
+ self.value = None
+
+ def __str__(self):
+ if self.value == None:
+ return "None"
+ else:
+ return self.value
+
+class Device:
+ def __init__(self):
+ self.id_dev = None
+ self.ip = None
+
+ def __str__(self):
+ if self.id_dev == None:
+ return "It's a new Device"
+ else:
+ return "Device "+self.id_dev+" --> "+self.ip
+
+class Host:
+ def __init__(self):
+ self.id_host = None
+ self.url = String()
+ self.ssh = None
+ self.devices = []
+ self.services = None
+ self.routes = []
+ self.hostType = String()
+
+ def __str__(self):
+ if len(self.devices) == 0:
+ return "It's a new Host"
+ else:
+ return "Host "+str(self.id_host)+" on "+str(self.url)+" has "+str(len(self.devices))+" device(s)"
+
+class Slice:
+ def __str__(self):
+ if len(self.hosts) == 0:
+ return "It's a new Slice"
+ else:
+ return "Slice "+str(self.slice_name)+" contain "+str(len(self.hosts))+" host(s)"
+
+ def __init__(self):
+ self.slice_name = String()
+ self.hosts = []
+
+class HostLink:
+ def __init__(self):
+ self.slice_name = None
+ self.id_host = None
+ self.url = None
+ self.ssh = None
+ self.bridge_name = None
+
+ def __str__(self):
+ return str(self.slice_name)+"@"+str(self.url)+"->"+str(self.bridge_name)
+
+class Link:
+ def __init__(self):
+ self.host1 = None
+ self.host2 = None
+
+ def __str__(self):
+ return " "+str(self.host1)+" <===> "+str(self.host2)
+
+class Route:
+ def __init__(self, slice_name, host_url, ssh, host_id):
+ self.slice_name = slice_name
+ self.host_url = host_url
+ self.host_ssh = ssh
+ self.host_id = host_id
+ self.subnet = None
+ self.gateway = None
+ self.device = None
+
+ def __str__(self):
+ if self.slice_name == None:
+ return "Empty route"
+ else:
+ return " On "+str(self.slice_name)+"@"+str(self.host_url)+" add "+self.subnet+" gw "+self.gateway+" dev "+self.device
+
+ def setRoute(self):
+ execute("sudo -S sh -c \"echo \\\"add "+self.subnet+" gw "+self.gateway+" "+self.device+"\\\" > /vsys/vroute.in\"", self.host_ssh, display = True)
+
+class Service:
+ def __init__(self, slice_name, url, ssh):
+ self.slice_name = slice_name
+ self.host_url = url
+ self.host_ssh = ssh
+ self.services = []
+
+ def __str__(self):
+ if len(self.services) == 0:
+ retour = ''
+ else:
+ retour = " On "+str(self.slice_name)+"@"+str(self.host_url)+" set:"
+ for service, port in self.services:
+ if port != '':
+ retour += "\n\t"+service+" on port "+port
+ else:
+ retour += "\n\t"+service
+ return retour
+
+ def setService(self):
+ print "\tOn "+str(self.slice_name)+"@"+str(self.host_url)+" now setting :"
+ for i in range(len(self.services)):
+ if self.services[i][0] == "x11":
+ setXRedirect(self.host_ssh)
+ elif self.services[i][0] == "httpd":
+ if port != '':
+ self.services[i][1] = setHttpd(self.host_ssh, port, self.host_url)
+ else:
+ print "Error you didn't specified the port used by httpd"
+ elif self.services[i][0] == "wireshark":
+ setWireshark(self.host_ssh)
+ elif self.services[i][0] == "firefox":
+ setFirefox(self.host_ssh)
+ elif self.services[i][0] == "php" or self.services[i][0] == 'PHP':
+ setPHP(self.host_ssh)
+ else:
+ print "The service "+service+" is not available"
+
+ def removeService(self):
+ for service, port in self.services:
+ if service == "x11":
+ removeXRedirect(self.host_ssh)
+ elif service == "httpd":
+ removeHttpd(self.host_ssh)
+ elif service == "wireshark":
+ removeWireshark(self.host_ssh)
+ elif service == "firefox":
+ removeFirefox(self.host_ssh)
+ elif service == "php" or service == 'PHP':
+ removePHP(self.host_ssh)
+
--- /dev/null
+[updates-testing]
+name=Fedora $releasever - $basearch - Test Updates
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/testing/$releasever/$basearch/
+#baseurl=http://ftp-stud.hs-esslingen.de/pub/Mirrors/archive.fedoraproject.org/fedora/linux/updates/testing/$releasever/$basearch/
+mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-testing-f$releasever&arch=$basearch
+enabled=0
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch
+
+[updates-testing-debuginfo]
+name=Fedora $releasever - $basearch - Test Updates Debug
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/testing/$releasever/$basearch/debug/
+baseurl=http://ftp-stud.hs-esslingen.de/pub/Mirrors/archive.fedoraproject.org/fedora/linux/updates/testing/$releasever/$basearch/debug/
+mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-testing-debug-f$releasever&arch=$basearch
+enabled=0
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch
+
+[updates-testing-source]
+name=Fedora $releasever - Test Updates Source
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/testing/$releasever/SRPMS/
+baseurl=http://ftp-stud.hs-esslingen.de/pub/Mirrors/archive.fedoraproject.org/fedora/linux/updates/testing/$releasever/SRPMS/
+mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-testing-source-f$releasever&arch=$basearch
+enabled=0
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch
--- /dev/null
+[updates]
+name=Fedora $releasever - $basearch - Updates
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/$basearch/
+baseurl=http://ftp-stud.hs-esslingen.de/pub/Mirrors/archive.fedoraproject.org/fedora/linux/updates/$releasever/$basearch/
+#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f$releasever&arch=$basearch
+enabled=1
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch
+
+[updates-debuginfo]
+name=Fedora $releasever - $basearch - Updates - Debug
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/$basearch/debug/
+baseurl=http://ftp-stud.hs-esslingen.de/pub/Mirrors/archive.fedoraproject.org/fedora/linux/updates/$releasever/$basearch/debug/
+#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-released-debug-f$releasever&arch=$basearch
+enabled=0
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch
+
+[updates-source]
+name=Fedora $releasever - Updates Source
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/SRPMS/
+baseurl=http://ftp-stud.hs-esslingen.de/pub/Mirrors/archive.fedoraproject.org/fedora/linux/updates/$releasever/SRPMS/
+#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-released-source-f$releasever&arch=$basearch
+enabled=0
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch
--- /dev/null
+[fedora]
+name=Fedora $releasever - $basearch
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/
+baseurl=http://ftp-stud.hs-esslingen.de/pub/Mirrors/archive.fedoraproject.org/fedora/linux/releases/$releasever/Everything/$basearch/os/
+#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
+enabled=1
+metadata_expire=7d
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch
+
+[fedora-debuginfo]
+name=Fedora $releasever - $basearch - Debug
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/debug/
+baseurl=http://ftp-stud.hs-esslingen.de/pub/Mirrors/archive.fedoraproject.org/fedora/linux/releases/$releasever/Everything/$basearch/debug/
+#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=fedora-debug-$releasever&arch=$basearch
+enabled=0
+metadata_expire=7d
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch
+
+[fedora-source]
+name=Fedora $releasever - Source
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/source/SRPMS/
+mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=fedora-source-$releasever&arch=$basearch
+enabled=0
+metadata_expire=7d
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$basearch
--- /dev/null
+#
+# This is the main Apache server configuration file. It contains the
+# configuration directives that give the server its instructions.
+# See <URL:http://httpd.apache.org/docs/2.2/> for detailed information.
+# In particular, see
+# <URL:http://httpd.apache.org/docs/2.2/mod/directives.html>
+# for a discussion of each configuration directive.
+#
+#
+# Do NOT simply read the instructions in here without understanding
+# what they do. They're here only as hints or reminders. If you are unsure
+# consult the online docs. You have been warned.
+#
+# The configuration directives are grouped into three basic sections:
+# 1. Directives that control the operation of the Apache server process as a
+# whole (the 'global environment').
+# 2. Directives that define the parameters of the 'main' or 'default' server,
+# which responds to requests that aren't handled by a virtual host.
+# These directives also provide default values for the settings
+# of all virtual hosts.
+# 3. Settings for virtual hosts, which allow Web requests to be sent to
+# different IP addresses or hostnames and have them handled by the
+# same Apache server process.
+#
+# Configuration and logfile names: If the filenames you specify for many
+# of the server's control files begin with "/" (or "drive:/" for Win32), the
+# server will use that explicit path. If the filenames do *not* begin
+# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
+# with ServerRoot set to "/etc/httpd" will be interpreted by the
+# server as "/etc/httpd/logs/foo.log".
+#
+
+### Section 1: Global Environment
+#
+# The directives in this section affect the overall operation of Apache,
+# such as the number of concurrent requests it can handle or where it
+# can find its configuration files.
+#
+
+#
+# Don't give away too much information about all the subcomponents
+# we are running. Comment out this line if you don't mind remote sites
+# finding out what major optional modules you are running
+ServerTokens OS
+
+#
+# ServerRoot: The top of the directory tree under which the server's
+# configuration, error, and log files are kept.
+#
+# NOTE! If you intend to place this on an NFS (or otherwise network)
+# mounted filesystem then please read the LockFile documentation
+# (available at <URL:http://httpd.apache.org/docs/2.2/mod/mpm_common.html#lockfile>);
+# you will save yourself a lot of trouble.
+#
+# Do NOT add a slash at the end of the directory path.
+#
+ServerRoot "/etc/httpd"
+
+#
+# PidFile: The file in which the server should record its process
+# identification number when it starts.
+#
+PidFile run/httpd.pid
+
+#
+# Timeout: The number of seconds before receives and sends time out.
+#
+Timeout 120
+
+#
+# KeepAlive: Whether or not to allow persistent connections (more than
+# one request per connection). Set to "Off" to deactivate.
+#
+KeepAlive Off
+
+#
+# MaxKeepAliveRequests: The maximum number of requests to allow
+# during a persistent connection. Set to 0 to allow an unlimited amount.
+# We recommend you leave this number high, for maximum performance.
+#
+MaxKeepAliveRequests 100
+
+#
+# KeepAliveTimeout: Number of seconds to wait for the next request from the
+# same client on the same connection.
+#
+KeepAliveTimeout 15
+
+##
+## Server-Pool Size Regulation (MPM specific)
+##
+
+# prefork MPM
+# StartServers: number of server processes to start
+# MinSpareServers: minimum number of server processes which are kept spare
+# MaxSpareServers: maximum number of server processes which are kept spare
+# ServerLimit: maximum value for MaxClients for the lifetime of the server
+# MaxClients: maximum number of server processes allowed to start
+# MaxRequestsPerChild: maximum number of requests a server process serves
+<IfModule prefork.c>
+StartServers 8
+MinSpareServers 5
+MaxSpareServers 20
+ServerLimit 256
+MaxClients 256
+MaxRequestsPerChild 4000
+</IfModule>
+
+# worker MPM
+# StartServers: initial number of server processes to start
+# MaxClients: maximum number of simultaneous client connections
+# MinSpareThreads: minimum number of worker threads which are kept spare
+# MaxSpareThreads: maximum number of worker threads which are kept spare
+# ThreadsPerChild: constant number of worker threads in each server process
+# MaxRequestsPerChild: maximum number of requests a server process serves
+<IfModule worker.c>
+StartServers 2
+MaxClients 150
+MinSpareThreads 25
+MaxSpareThreads 75
+ThreadsPerChild 25
+MaxRequestsPerChild 0
+</IfModule>
+
+#
+# Listen: Allows you to bind Apache to specific IP addresses and/or
+# ports, in addition to the default. See also the <VirtualHost>
+# directive.
+#
+# Change this to Listen on specific IP addresses as shown below to
+# prevent Apache from glomming onto all bound IP addresses (0.0.0.0)
+#
+#Listen 12.34.56.78:80
+Listen *:80
+
+#
+# Dynamic Shared Object (DSO) Support
+#
+# To be able to use the functionality of a module which was built as a DSO you
+# have to place corresponding `LoadModule' lines at this location so the
+# directives contained in it are actually available _before_ they are used.
+# Statically compiled modules (those listed by `httpd -l') do not need
+# to be loaded here.
+#
+# Example:
+# LoadModule foo_module modules/mod_foo.so
+#
+LoadModule auth_basic_module modules/mod_auth_basic.so
+LoadModule auth_digest_module modules/mod_auth_digest.so
+LoadModule authn_file_module modules/mod_authn_file.so
+LoadModule authn_alias_module modules/mod_authn_alias.so
+LoadModule authn_anon_module modules/mod_authn_anon.so
+LoadModule authn_dbm_module modules/mod_authn_dbm.so
+LoadModule authn_default_module modules/mod_authn_default.so
+LoadModule authz_host_module modules/mod_authz_host.so
+LoadModule authz_user_module modules/mod_authz_user.so
+LoadModule authz_owner_module modules/mod_authz_owner.so
+LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
+LoadModule authz_dbm_module modules/mod_authz_dbm.so
+LoadModule authz_default_module modules/mod_authz_default.so
+LoadModule ldap_module modules/mod_ldap.so
+LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
+LoadModule include_module modules/mod_include.so
+LoadModule log_config_module modules/mod_log_config.so
+LoadModule logio_module modules/mod_logio.so
+LoadModule env_module modules/mod_env.so
+LoadModule ext_filter_module modules/mod_ext_filter.so
+LoadModule mime_magic_module modules/mod_mime_magic.so
+LoadModule expires_module modules/mod_expires.so
+LoadModule deflate_module modules/mod_deflate.so
+LoadModule headers_module modules/mod_headers.so
+LoadModule usertrack_module modules/mod_usertrack.so
+LoadModule setenvif_module modules/mod_setenvif.so
+LoadModule mime_module modules/mod_mime.so
+LoadModule dav_module modules/mod_dav.so
+LoadModule status_module modules/mod_status.so
+LoadModule autoindex_module modules/mod_autoindex.so
+LoadModule info_module modules/mod_info.so
+LoadModule dav_fs_module modules/mod_dav_fs.so
+LoadModule vhost_alias_module modules/mod_vhost_alias.so
+LoadModule negotiation_module modules/mod_negotiation.so
+LoadModule dir_module modules/mod_dir.so
+LoadModule actions_module modules/mod_actions.so
+LoadModule speling_module modules/mod_speling.so
+LoadModule userdir_module modules/mod_userdir.so
+LoadModule alias_module modules/mod_alias.so
+LoadModule rewrite_module modules/mod_rewrite.so
+LoadModule proxy_module modules/mod_proxy.so
+LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
+LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
+LoadModule proxy_http_module modules/mod_proxy_http.so
+LoadModule proxy_connect_module modules/mod_proxy_connect.so
+LoadModule cache_module modules/mod_cache.so
+LoadModule suexec_module modules/mod_suexec.so
+LoadModule disk_cache_module modules/mod_disk_cache.so
+LoadModule cgi_module modules/mod_cgi.so
+
+#
+# The following modules are not loaded by default:
+#
+#LoadModule cern_meta_module modules/mod_cern_meta.so
+#LoadModule asis_module modules/mod_asis.so
+
+#
+# Load config files from the config directory "/etc/httpd/conf.d".
+#
+Include conf.d/*.conf
+
+#
+# ExtendedStatus controls whether Apache will generate "full" status
+# information (ExtendedStatus On) or just basic information (ExtendedStatus
+# Off) when the "server-status" handler is called. The default is Off.
+#
+#ExtendedStatus On
+
+#
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.
+#
+# User/Group: The name (or #number) of the user/group to run httpd as.
+# . On SCO (ODT 3) use "User nouser" and "Group nogroup".
+# . On HPUX you may not be able to use shared memory as nobody, and the
+# suggested workaround is to create a user www and use that user.
+# NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET)
+# when the value of (unsigned)Group is above 60000;
+# don't use Group #-1 on these systems!
+#
+User apache
+Group apache
+
+### Section 2: 'Main' server configuration
+#
+# The directives in this section set up the values used by the 'main'
+# server, which responds to any requests that aren't handled by a
+# <VirtualHost> definition. These values also provide defaults for
+# any <VirtualHost> containers you may define later in the file.
+#
+# All of these directives may appear inside <VirtualHost> containers,
+# in which case these default settings will be overridden for the
+# virtual host being defined.
+#
+
+#
+# ServerAdmin: Your address, where problems with the server should be
+# e-mailed. This address appears on some server-generated pages, such
+# as error documents. e.g. admin@your-domain.com
+#
+ServerAdmin root@localhost
+
+#
+# ServerName gives the name and port that the server uses to identify itself.
+# This can often be determined automatically, but we recommend you specify
+# it explicitly to prevent problems during startup.
+#
+# If this is not set to valid DNS name for your host, server-generated
+# redirections will not work. See also the UseCanonicalName directive.
+#
+# If your host doesn't have a registered DNS name, enter its IP address here.
+# You will have to access it by its address anyway, and this will make
+# redirections work in a sensible way.
+#
+#ServerName www.example.com:80
+
+#
+# UseCanonicalName: Determines how Apache constructs self-referencing
+# URLs and the SERVER_NAME and SERVER_PORT variables.
+# When set "Off", Apache will use the Hostname and Port supplied
+# by the client. When set "On", Apache will use the value of the
+# ServerName directive.
+#
+UseCanonicalName Off
+
+#
+# DocumentRoot: The directory out of which you will serve your
+# documents. By default, all requests are taken from this directory, but
+# symbolic links and aliases may be used to point to other locations.
+#
+DocumentRoot "/var/www/html"
+
+#
+# Each directory to which Apache has access can be configured with respect
+# to which services and features are allowed and/or disabled in that
+# directory (and its subdirectories).
+#
+# First, we configure the "default" to be a very restrictive set of
+# features.
+#
+<Directory />
+ Options FollowSymLinks
+ AllowOverride None
+</Directory>
+
+#
+# Note that from this point forward you must specifically allow
+# particular features to be enabled - so if something's not working as
+# you might expect, make sure that you have specifically enabled it
+# below.
+#
+
+#
+# This should be changed to whatever you set DocumentRoot to.
+#
+<Directory "/var/www/html">
+
+#
+# Possible values for the Options directive are "None", "All",
+# or any combination of:
+# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
+#
+# Note that "MultiViews" must be named *explicitly* --- "Options All"
+# doesn't give it to you.
+#
+# The Options directive is both complicated and important. Please see
+# http://httpd.apache.org/docs/2.2/mod/core.html#options
+# for more information.
+#
+ Options Indexes FollowSymLinks
+
+#
+# AllowOverride controls what directives may be placed in .htaccess files.
+# It can be "All", "None", or any combination of the keywords:
+# Options FileInfo AuthConfig Limit
+#
+ AllowOverride None
+
+#
+# Controls who can get stuff from this server.
+#
+ Order allow,deny
+ Allow from all
+
+</Directory>
+
+#
+# UserDir: The name of the directory that is appended onto a user's home
+# directory if a ~user request is received.
+#
+# The path to the end user account 'public_html' directory must be
+# accessible to the webserver userid. This usually means that ~userid
+# must have permissions of 711, ~userid/public_html must have permissions
+# of 755, and documents contained therein must be world-readable.
+# Otherwise, the client will only receive a "403 Forbidden" message.
+#
+# See also: http://httpd.apache.org/docs/misc/FAQ.html#forbidden
+#
+<IfModule mod_userdir.c>
+ #
+ # UserDir is disabled by default since it can confirm the presence
+ # of a username on the system (depending on home directory
+ # permissions).
+ #
+ UserDir disabled
+
+ #
+ # To enable requests to /~user/ to serve the user's public_html
+ # directory, remove the "UserDir disabled" line above, and uncomment
+ # the following line instead:
+ #
+ #UserDir public_html
+
+</IfModule>
+
+#
+# Control access to UserDir directories. The following is an example
+# for a site where these directories are restricted to read-only.
+#
+#<Directory /home/*/public_html>
+# AllowOverride FileInfo AuthConfig Limit
+# Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
+# <Limit GET POST OPTIONS>
+# Order allow,deny
+# Allow from all
+# </Limit>
+# <LimitExcept GET POST OPTIONS>
+# Order deny,allow
+# Deny from all
+# </LimitExcept>
+#</Directory>
+
+#
+# DirectoryIndex: sets the file that Apache will serve if a directory
+# is requested.
+#
+# The index.html.var file (a type-map) is used to deliver content-
+# negotiated documents. The MultiViews Option can be used for the
+# same purpose, but it is much slower.
+#
+DirectoryIndex index.html index.html.var
+
+#
+# AccessFileName: The name of the file to look for in each directory
+# for additional configuration directives. See also the AllowOverride
+# directive.
+#
+AccessFileName .htaccess
+
+#
+# The following lines prevent .htaccess and .htpasswd files from being
+# viewed by Web clients.
+#
+<Files ~ "^\.ht">
+ Order allow,deny
+ Deny from all
+</Files>
+
+#
+# TypesConfig describes where the mime.types file (or equivalent) is
+# to be found.
+#
+TypesConfig /etc/mime.types
+
+#
+# DefaultType is the default MIME type the server will use for a document
+# if it cannot otherwise determine one, such as from filename extensions.
+# If your server contains mostly text or HTML documents, "text/plain" is
+# a good value. If most of your content is binary, such as applications
+# or images, you may want to use "application/octet-stream" instead to
+# keep browsers from trying to display binary files as though they are
+# text.
+#
+DefaultType text/plain
+
+#
+# The mod_mime_magic module allows the server to use various hints from the
+# contents of the file itself to determine its type. The MIMEMagicFile
+# directive tells the module where the hint definitions are located.
+#
+<IfModule mod_mime_magic.c>
+# MIMEMagicFile /usr/share/magic.mime
+ MIMEMagicFile conf/magic
+</IfModule>
+
+#
+# HostnameLookups: Log the names of clients or just their IP addresses
+# e.g., www.apache.org (on) or 204.62.129.132 (off).
+# The default is off because it'd be overall better for the net if people
+# had to knowingly turn this feature on, since enabling it means that
+# each client request will result in AT LEAST one lookup request to the
+# nameserver.
+#
+HostnameLookups Off
+
+#
+# EnableMMAP: Control whether memory-mapping is used to deliver
+# files (assuming that the underlying OS supports it).
+# The default is on; turn this off if you serve from NFS-mounted
+# filesystems. On some systems, turning it off (regardless of
+# filesystem) can improve performance; for details, please see
+# http://httpd.apache.org/docs/2.2/mod/core.html#enablemmap
+#
+#EnableMMAP off
+
+#
+# EnableSendfile: Control whether the sendfile kernel support is
+# used to deliver files (assuming that the OS supports it).
+# The default is on; turn this off if you serve from NFS-mounted
+# filesystems. Please see
+# http://httpd.apache.org/docs/2.2/mod/core.html#enablesendfile
+#
+#EnableSendfile off
+
+#
+# ErrorLog: The location of the error log file.
+# If you do not specify an ErrorLog directive within a <VirtualHost>
+# container, error messages relating to that virtual host will be
+# logged here. If you *do* define an error logfile for a <VirtualHost>
+# container, that host's errors will be logged there and not here.
+#
+ErrorLog logs/error_log
+
+#
+# LogLevel: Control the number of messages logged to the error_log.
+# Possible values include: debug, info, notice, warn, error, crit,
+# alert, emerg.
+#
+LogLevel warn
+
+#
+# The following directives define some format nicknames for use with
+# a CustomLog directive (see below).
+#
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%h %l %u %t \"%r\" %>s %b" common
+LogFormat "%{Referer}i -> %U" referer
+LogFormat "%{User-agent}i" agent
+
+# "combinedio" includes actual counts of actual bytes received (%I) and sent (%O); this
+# requires the mod_logio module to be loaded.
+#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
+
+#
+# The location and format of the access logfile (Common Logfile Format).
+# If you do not define any access logfiles within a <VirtualHost>
+# container, they will be logged here. Contrariwise, if you *do*
+# define per-<VirtualHost> access logfiles, transactions will be
+# logged therein and *not* in this file.
+#
+#CustomLog logs/access_log common
+
+#
+# If you would like to have separate agent and referer logfiles, uncomment
+# the following directives.
+#
+#CustomLog logs/referer_log referer
+#CustomLog logs/agent_log agent
+
+#
+# For a single logfile with access, agent, and referer information
+# (Combined Logfile Format), use the following directive:
+#
+CustomLog logs/access_log combined
+
+#
+# Optionally add a line containing the server version and virtual host
+# name to server-generated pages (internal error documents, FTP directory
+# listings, mod_status and mod_info output etc., but not CGI generated
+# documents or custom error documents).
+# Set to "EMail" to also include a mailto: link to the ServerAdmin.
+# Set to one of: On | Off | EMail
+#
+ServerSignature On
+
+#
+# Aliases: Add here as many aliases as you need (with no limit). The format is
+# Alias fakename realname
+#
+# Note that if you include a trailing / on fakename then the server will
+# require it to be present in the URL. So "/icons" isn't aliased in this
+# example, only "/icons/". If the fakename is slash-terminated, then the
+# realname must also be slash terminated, and if the fakename omits the
+# trailing slash, the realname must also omit it.
+#
+# We include the /icons/ alias for FancyIndexed directory listings. If you
+# do not use FancyIndexing, you may comment this out.
+#
+Alias /icons/ "/var/www/icons/"
+
+<Directory "/var/www/icons">
+ Options Indexes MultiViews FollowSymLinks
+ AllowOverride None
+ Order allow,deny
+ Allow from all
+</Directory>
+
+#
+# WebDAV module configuration section.
+#
+<IfModule mod_dav_fs.c>
+ # Location of the WebDAV lock database.
+ DAVLockDB /var/lib/dav/lockdb
+</IfModule>
+
+#
+# ScriptAlias: This controls which directories contain server scripts.
+# ScriptAliases are essentially the same as Aliases, except that
+# documents in the realname directory are treated as applications and
+# run by the server when requested rather than as documents sent to the client.
+# The same rules about trailing "/" apply to ScriptAlias directives as to
+# Alias.
+#
+ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
+
+#
+# "/var/www/cgi-bin" should be changed to whatever your ScriptAliased
+# CGI directory exists, if you have that configured.
+#
+<Directory "/var/www/cgi-bin">
+ AllowOverride None
+ Options None
+ Order allow,deny
+ Allow from all
+</Directory>
+
+#
+# Redirect allows you to tell clients about documents which used to exist in
+# your server's namespace, but do not anymore. This allows you to tell the
+# clients where to look for the relocated document.
+# Example:
+# Redirect permanent /foo http://www.example.com/bar
+
+#
+# Directives controlling the display of server-generated directory listings.
+#
+
+#
+# IndexOptions: Controls the appearance of server-generated directory
+# listings.
+#
+IndexOptions FancyIndexing VersionSort NameWidth=* HTMLTable Charset=UTF-8
+
+#
+# AddIcon* directives tell the server which icon to show for different
+# files or filename extensions. These are only displayed for
+# FancyIndexed directories.
+#
+AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
+
+AddIconByType (TXT,/icons/text.gif) text/*
+AddIconByType (IMG,/icons/image2.gif) image/*
+AddIconByType (SND,/icons/sound2.gif) audio/*
+AddIconByType (VID,/icons/movie.gif) video/*
+
+AddIcon /icons/binary.gif .bin .exe
+AddIcon /icons/binhex.gif .hqx
+AddIcon /icons/tar.gif .tar
+AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
+AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
+AddIcon /icons/a.gif .ps .ai .eps
+AddIcon /icons/layout.gif .html .shtml .htm .pdf
+AddIcon /icons/text.gif .txt
+AddIcon /icons/c.gif .c
+AddIcon /icons/p.gif .pl .py
+AddIcon /icons/f.gif .for
+AddIcon /icons/dvi.gif .dvi
+AddIcon /icons/uuencoded.gif .uu
+AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
+AddIcon /icons/tex.gif .tex
+AddIcon /icons/bomb.gif core
+
+AddIcon /icons/back.gif ..
+AddIcon /icons/hand.right.gif README
+AddIcon /icons/folder.gif ^^DIRECTORY^^
+AddIcon /icons/blank.gif ^^BLANKICON^^
+
+#
+# DefaultIcon is which icon to show for files which do not have an icon
+# explicitly set.
+#
+DefaultIcon /icons/unknown.gif
+
+#
+# AddDescription allows you to place a short description after a file in
+# server-generated indexes. These are only displayed for FancyIndexed
+# directories.
+# Format: AddDescription "description" filename
+#
+#AddDescription "GZIP compressed document" .gz
+#AddDescription "tar archive" .tar
+#AddDescription "GZIP compressed tar archive" .tgz
+
+#
+# ReadmeName is the name of the README file the server will look for by
+# default, and append to directory listings.
+#
+# HeaderName is the name of a file which should be prepended to
+# directory indexes.
+ReadmeName README.html
+HeaderName HEADER.html
+
+#
+# IndexIgnore is a set of filenames which directory indexing should ignore
+# and not include in the listing. Shell-style wildcarding is permitted.
+#
+IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
+
+#
+# DefaultLanguage and AddLanguage allows you to specify the language of
+# a document. You can then use content negotiation to give a browser a
+# file in a language the user can understand.
+#
+# Specify a default language. This means that all data
+# going out without a specific language tag (see below) will
+# be marked with this one. You probably do NOT want to set
+# this unless you are sure it is correct for all cases.
+#
+# * It is generally better to not mark a page as
+# * being a certain language than marking it with the wrong
+# * language!
+#
+# DefaultLanguage nl
+#
+# Note 1: The suffix does not have to be the same as the language
+# keyword --- those with documents in Polish (whose net-standard
+# language code is pl) may wish to use "AddLanguage pl .po" to
+# avoid the ambiguity with the common suffix for perl scripts.
+#
+# Note 2: The example entries below illustrate that in some cases
+# the two character 'Language' abbreviation is not identical to
+# the two character 'Country' code for its country,
+# E.g. 'Danmark/dk' versus 'Danish/da'.
+#
+# Note 3: In the case of 'ltz' we violate the RFC by using a three char
+# specifier. There is 'work in progress' to fix this and get
+# the reference data for rfc1766 cleaned up.
+#
+# Catalan (ca) - Croatian (hr) - Czech (cs) - Danish (da) - Dutch (nl)
+# English (en) - Esperanto (eo) - Estonian (et) - French (fr) - German (de)
+# Greek-Modern (el) - Hebrew (he) - Italian (it) - Japanese (ja)
+# Korean (ko) - Luxembourgeois* (ltz) - Norwegian Nynorsk (nn)
+# Norwegian (no) - Polish (pl) - Portugese (pt)
+# Brazilian Portuguese (pt-BR) - Russian (ru) - Swedish (sv)
+# Simplified Chinese (zh-CN) - Spanish (es) - Traditional Chinese (zh-TW)
+#
+AddLanguage ca .ca
+AddLanguage cs .cz .cs
+AddLanguage da .dk
+AddLanguage de .de
+AddLanguage el .el
+AddLanguage en .en
+AddLanguage eo .eo
+AddLanguage es .es
+AddLanguage et .et
+AddLanguage fr .fr
+AddLanguage he .he
+AddLanguage hr .hr
+AddLanguage it .it
+AddLanguage ja .ja
+AddLanguage ko .ko
+AddLanguage ltz .ltz
+AddLanguage nl .nl
+AddLanguage nn .nn
+AddLanguage no .no
+AddLanguage pl .po
+AddLanguage pt .pt
+AddLanguage pt-BR .pt-br
+AddLanguage ru .ru
+AddLanguage sv .sv
+AddLanguage zh-CN .zh-cn
+AddLanguage zh-TW .zh-tw
+
+#
+# LanguagePriority allows you to give precedence to some languages
+# in case of a tie during content negotiation.
+#
+# Just list the languages in decreasing order of preference. We have
+# more or less alphabetized them here. You probably want to change this.
+#
+LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW
+
+#
+# ForceLanguagePriority allows you to serve a result page rather than
+# MULTIPLE CHOICES (Prefer) [in case of a tie] or NOT ACCEPTABLE (Fallback)
+# [in case no accepted languages matched the available variants]
+#
+ForceLanguagePriority Prefer Fallback
+
+#
+# Specify a default charset for all content served; this enables
+# interpretation of all content as UTF-8 by default. To use the
+# default browser choice (ISO-8859-1), or to allow the META tags
+# in HTML content to override this choice, comment out this
+# directive:
+#
+AddDefaultCharset UTF-8
+
+#
+# AddType allows you to add to or override the MIME configuration
+# file mime.types for specific file types.
+#
+#AddType application/x-tar .tgz
+
+#
+# AddEncoding allows you to have certain browsers uncompress
+# information on the fly. Note: Not all browsers support this.
+# Despite the name similarity, the following Add* directives have nothing
+# to do with the FancyIndexing customization directives above.
+#
+#AddEncoding x-compress .Z
+#AddEncoding x-gzip .gz .tgz
+
+# If the AddEncoding directives above are commented-out, then you
+# probably should define those extensions to indicate media types:
+#
+AddType application/x-compress .Z
+AddType application/x-gzip .gz .tgz
+
+#
+# MIME-types for downloading Certificates and CRLs
+#
+AddType application/x-x509-ca-cert .crt
+AddType application/x-pkcs7-crl .crl
+
+#
+# AddHandler allows you to map certain file extensions to "handlers":
+# actions unrelated to filetype. These can be either built into the server
+# or added with the Action directive (see below)
+#
+# To use CGI scripts outside of ScriptAliased directories:
+# (You will also need to add "ExecCGI" to the "Options" directive.)
+#
+#AddHandler cgi-script .cgi
+
+#
+# For files that include their own HTTP headers:
+#
+#AddHandler send-as-is asis
+
+#
+# For type maps (negotiated resources):
+# (This is enabled by default to allow the Apache "It Worked" page
+# to be distributed in multiple languages.)
+#
+AddHandler type-map var
+
+#
+# Filters allow you to process content before it is sent to the client.
+#
+# To parse .shtml files for server-side includes (SSI):
+# (You will also need to add "Includes" to the "Options" directive.)
+#
+AddType text/html .shtml
+AddOutputFilter INCLUDES .shtml
+
+#
+# Action lets you define media types that will execute a script whenever
+# a matching file is called. This eliminates the need for repeated URL
+# pathnames for oft-used CGI file processors.
+# Format: Action media/type /cgi-script/location
+# Format: Action handler-name /cgi-script/location
+#
+
+#
+# Customizable error responses come in three flavors:
+# 1) plain text 2) local redirects 3) external redirects
+#
+# Some examples:
+#ErrorDocument 500 "The server made a boo boo."
+#ErrorDocument 404 /missing.html
+#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
+#ErrorDocument 402 http://www.example.com/subscription_info.html
+#
+
+#
+# Putting this all together, we can internationalize error responses.
+#
+# We use Alias to redirect any /error/HTTP_<error>.html.var response to
+# our collection of by-error message multi-language collections. We use
+# includes to substitute the appropriate text.
+#
+# You can modify the messages' appearance without changing any of the
+# default HTTP_<error>.html.var files by adding the line:
+#
+# Alias /error/include/ "/your/include/path/"
+#
+# which allows you to create your own set of files by starting with the
+# /var/www/error/include/ files and
+# copying them to /your/include/path/, even on a per-VirtualHost basis.
+#
+
+Alias /error/ "/var/www/error/"
+
+<IfModule mod_negotiation.c>
+<IfModule mod_include.c>
+ <Directory "/var/www/error">
+ AllowOverride None
+ Options IncludesNoExec
+ AddOutputFilter Includes html
+ AddHandler type-map var
+ Order allow,deny
+ Allow from all
+ LanguagePriority en es de fr
+ ForceLanguagePriority Prefer Fallback
+ </Directory>
+
+# ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var
+# ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
+# ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var
+# ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var
+# ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var
+# ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var
+# ErrorDocument 410 /error/HTTP_GONE.html.var
+# ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var
+# ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var
+# ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
+# ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var
+# ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var
+# ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var
+# ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var
+# ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var
+# ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var
+# ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var
+
+</IfModule>
+</IfModule>
+
+#
+# The following directives modify normal HTTP response behavior to
+# handle known problems with browser implementations.
+#
+BrowserMatch "Mozilla/2" nokeepalive
+BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
+BrowserMatch "RealPlayer 4\.0" force-response-1.0
+BrowserMatch "Java/1\.0" force-response-1.0
+BrowserMatch "JDK/1\.0" force-response-1.0
+
+#
+# The following directive disables redirects on non-GET requests for
+# a directory that does not include the trailing slash. This fixes a
+# problem with Microsoft WebFolders which does not appropriately handle
+# redirects for folders with DAV methods.
+# Same deal with Apple's DAV filesystem and Gnome VFS support for DAV.
+#
+BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
+BrowserMatch "MS FrontPage" redirect-carefully
+BrowserMatch "^WebDrive" redirect-carefully
+BrowserMatch "^WebDAVFS/1.[0123]" redirect-carefully
+BrowserMatch "^gnome-vfs/1.0" redirect-carefully
+BrowserMatch "^XML Spy" redirect-carefully
+BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
+
+#
+# Allow server status reports generated by mod_status,
+# with the URL of http://servername/server-status
+# Change the ".example.com" to match your domain to enable.
+#
+#<Location /server-status>
+# SetHandler server-status
+# Order deny,allow
+# Deny from all
+# Allow from .example.com
+#</Location>
+
+#
+# Allow remote server configuration reports, with the URL of
+# http://servername/server-info (requires that mod_info.c be loaded).
+# Change the ".example.com" to match your domain to enable.
+#
+#<Location /server-info>
+# SetHandler server-info
+# Order deny,allow
+# Deny from all
+# Allow from .example.com
+#</Location>
+
+#
+# Proxy Server directives. Uncomment the following lines to
+# enable the proxy server:
+#
+#<IfModule mod_proxy.c>
+#ProxyRequests On
+#
+#<Proxy *>
+# Order deny,allow
+# Deny from all
+# Allow from .example.com
+#</Proxy>
+
+#
+# Enable/disable the handling of HTTP/1.1 "Via:" headers.
+# ("Full" adds the server version; "Block" removes all outgoing Via: headers)
+# Set to one of: Off | On | Full | Block
+#
+#ProxyVia On
+
+#
+# To enable a cache of proxied content, uncomment the following lines.
+# See http://httpd.apache.org/docs/2.2/mod/mod_cache.html for more details.
+#
+#<IfModule mod_disk_cache.c>
+# CacheEnable disk /
+# CacheRoot "/var/cache/mod_proxy"
+#</IfModule>
+#
+
+#</IfModule>
+# End of proxy directives.
+
+### Section 3: Virtual Hosts
+#
+# VirtualHost: If you want to maintain multiple domains/hostnames on your
+# machine you can setup VirtualHost containers for them. Most configurations
+# use only name-based virtual hosts so the server doesn't need to worry about
+# IP addresses. This is indicated by the asterisks in the directives below.
+#
+# Please see the documentation at
+# <URL:http://httpd.apache.org/docs/2.2/vhosts/>
+# for further details before you try to setup virtual hosts.
+#
+# You may use the command line option '-S' to verify your virtual host
+# configuration.
+
+#
+# Use name-based virtual hosting.
+#
+#NameVirtualHost *:80
+#
+# NOTE: NameVirtualHost cannot be used without a port specifier
+# (e.g. :80) if mod_ssl is being used, due to the nature of the
+# SSL protocol.
+#
+
+#
+# VirtualHost example:
+# Almost any Apache directive may go into a VirtualHost container.
+# The first VirtualHost section is used for requests without a known
+# server name.
+#
+#<VirtualHost *:80>
+# ServerAdmin webmaster@dummy-host.example.com
+# DocumentRoot /www/docs/dummy-host.example.com
+# ServerName dummy-host.example.com
+# ErrorLog logs/dummy-host.example.com-error_log
+# CustomLog logs/dummy-host.example.com-access_log common
+#</VirtualHost>
--- /dev/null
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDg67pRFT/QYg3sZB1QIHO83Mme1Vl8m3yV48JDiHki2c12IuMbhUunDqq/BoXmHEEUcRLuvVhslzl3/oaeY1udO6m+JP4Xvb3RBw0vtzxlKxlCUoz48Pshb2Zx9bCup2g8VUMeWzYQwggjqxQ4Jiom7T+czQWdnPqi8If0x/OGOeSKimP7NhHqiHrGoNLG2k6fwFApTK4PTSyvegx13tDwcwF14C6OGA84kVmOyU/6xH/sa3Lsj08/1J00fcIn7KI/3LG62n6riuPAu4Dki9UV7TaM5dvN1VcTzcaU0X/mtOrOQnlJ5vyOGgPCxGhnYvirnQLBeh7NwrIb/sasfWUJ belgarion@debian
--- /dev/null
+<html><body><h1>It works!</h1>
+<p>This is the default web page for this server.</p>
+<p>The web server software is running but no content has been added, yet.</p>
+</body></html>
--- /dev/null
+Protocol 2
+SyslogFacility AUTHPRIV
+
+PubkeyAuthentication yes
+AuthorizedKeysFile .ssh/id_rsa.pub
+
+PasswordAuthentication yes
+
+ChallengeResponseAuthentication no
+UsePAM yes
+
+X11Forwarding yes
+
+# The listening port is added by the function from service.py
--- /dev/null
+#!/usr/bin/python
+
+class FailToConnect(Exception):
+ def __init__(self, nodeId, nodeUrl):
+ self.nodeId = nodeId
+ self.nodeUrl = nodeUrl
+ def __str__(self):
+ return repr(self.siteId)
+ def getNodeId(self):
+ return self.nodeId
+ def getNodeUrl(self):
+ return self.nodeUrl
+
+class SSHConnectError(Exception):
+ def __init__(self, host, sliceName):
+ self.why = "Can't connect to the node "+str(sliceName)+"@"+str(host)
+
+ def __str__(self):
+ return repr(self.why)
+
+class NodeConstraintError(Exception):
+ def __init__(self, constraint, envList):
+ self.why = "Can't find node with constraint : "+str(constraint)
+ self.envList = envList
+
+ def getEnvList(self):
+ return self.envList
--- /dev/null
+#!/usr/bin/env python
+
+import sys
+import argparse
+
+import logging
+import paramiko
+import signal
+import os
+import time
+
+# Import the class used (Slice, Host, Device, Link, HostLink)
+from classDefinition import *
+
+from exceptionDefinition import SSHConnectError
+
+class TransformXml:
+
+ def __init__(self, confFile = 'Conf.xml', linkFile = 'Link.xml', prefix = '', port = 22, keyFile = '~/.ssh/id_rsa'):
+ self.__currentNodeConf__ = None
+ self.__currentNodeLink__ = None
+ self.__currentNodeRoute__= None
+ self.__currentNodeService__ = None
+ self.__sliceList__ = []
+ self.__linkList__ = []
+
+ self.readXml(prefix+confFile, prefix+linkFile)
+ self.sshPort = port
+ self.sshKey = keyFile
+ self.xmlToSliceObject()
+ self.xmlToLinkObject()
+
+ def readXml(self, confPath, linkPath):
+ from xml.dom.minidom import parse
+ if not(os.path.isfile(confPath) and os.path.isfile(linkPath)):
+ print "Error file "+confPath+" or "+linkPath+" does not exist"
+ sys.exit(2)
+ self.conf = parse(confPath)
+ self.link = parse(linkPath)
+
+ def getRootElementConf(self):
+ if self.__currentNodeConf__ == None:
+ self.__currentNodeConf__ = self.conf.documentElement
+ return self.__currentNodeConf__
+
+ def getRootElementLink(self):
+ if self.__currentNodeLink__ == None:
+ self.__currentNodeLink__ = self.link.documentElement
+ return self.__currentNodeLink__
+
+ def xmlToServiceObject(self, rootService, host, slice_name):
+ i = 0
+ newService = Service(slice_name, host.url, host.ssh)
+ for service_i in rootService.getElementsByTagName("service"):
+ try:
+ service = self.getText(service_i)
+ except:
+ print "The tag service is missig"
+ servicePart = service.partition(':')
+ newService.services.append([servicePart[0], servicePart[2]])
+ host.services = newService
+
+ def setServices(self):
+ print "Now setting the service"
+ for slice_i in self.__sliceList__:
+ for host_i in slice_i.hosts:
+ host_i.services.setService()
+
+ def xmlToRouteObject(self, rootRoute, host, sliceName):
+ for route_i in rootRoute.getElementsByTagName("route"):
+ newRoute = Route(sliceName, host.url, host.ssh, host.id_host)
+ try:
+ newRoute.subnet = self.getText(route_i.getElementsByTagName("subnet")[0])
+ newRoute.gateway = self.getText(route_i.getElementsByTagName("gateway")[0])
+ devId = self.getText(route_i.getElementsByTagName("device")[0])
+ except:
+ print "The tag subnet / gateway or device is missing"
+ sys.exit(2)
+ newRoute.device = self.getTapId(newRoute, devId, host)
+ host.routes.append(newRoute)
+
+ def setRoutes(self):
+ for slice_i in self.__sliceList__:
+ for host_i in slice_i.hosts:
+ for route_i in host_i.routes:
+ route_i.setRoute()
+
+ def xmlToSliceObject(self):
+ i = j = k = 0
+ for slice_i in self.getRootElementConf().getElementsByTagName("slice"):
+ i += 1
+ newSlice = Slice()
+ try:
+ newSlice.slice_name.value = self.getText(slice_i.getElementsByTagName("slice_name")[0])
+ except :
+ print "The tag slice_name is missing"
+ sys.exit(2)
+ for host_i in slice_i.getElementsByTagName("host"):
+ j+=1
+ newHost = Host()
+ try:
+ newHost.hostType.value = self.getText(host_i.getElementsByTagName("type")[0])
+ newHost.id_host = self.getText(host_i.getElementsByTagName("id")[0])
+ newHost.url.value = self.getText(host_i.getElementsByTagName("url")[0])
+ except Exception, why:
+ print "Tag id or url is missing"
+ print "Slice",newSlice.slice_name," Host ",newHost.url," Interface ",str(k)
+ print "Why -> ", why
+ sys.exit(2)
+ newHost.ssh = self.sshCheck(newHost.url.value, newSlice.slice_name.value)
+ for interface_i in host_i.getElementsByTagName("interface"):
+ k+=1
+ newDevice = Device()
+ try:
+ newDevice.id_dev = self.getText(interface_i.getElementsByTagName("bridge_name")[0])
+ newDevice.ip = self.getText(interface_i.getElementsByTagName("ip")[0])
+ except:
+ print "Tag bridge_name or ip is missing"
+ #sys.exit(2)
+ newHost.devices.append(newDevice)
+ try:
+ serviceRoot = host_i.getElementsByTagName("services")[0]
+ self.xmlToServiceObject(serviceRoot, newHost, newSlice.slice_name)
+ except:
+ newHost.services = Service("","","")
+ try:
+ routeRoot = host_i.getElementsByTagName("routes")[0]
+ self.xmlToRouteObject(routeRoot, newHost, newSlice.slice_name)
+ except:
+ print "No additionnal route for host "+str(newSlice.slice_name)+"@"+str(newHost.url)
+ newSlice.hosts.append(newHost)
+ self.__sliceList__.append(newSlice)
+
+ def setSliceConf(self):
+ for slice_i in self.__sliceList__:
+ for host_i in slice_i.hosts:
+ if len(host_i.devices) > 0:
+ print "\tOn "+str(slice_i.slice_name)+"@"+str(host_i.url)
+ self.execute("sudo -S sliver-ovs start_db", host_i.ssh, display = True)
+ self.execute("sudo -S sliver-ovs start_switch", host_i.ssh, display = True)
+ for interface_i in host_i.devices:
+ returnCode = -1
+ i = 0
+ while returnCode != 0:
+ returnCode = self.execute("sudo -S sliver-ovs create_bridge "+interface_i.id_dev+" "+interface_i.ip,host_i.ssh)
+
+ if returnCode != 0:
+ i += 1
+ self.execute("sudo -S sliver-ovs del_bridge "+interface_i.id_dev, host_i.ssh)
+ if i > 10:
+ print "I have make ",i," iteration"
+ time.sleep(60)
+ else:
+ print "I make",i,"iteration before successfully create the interface"
+
+ def xmlToLinkObject(self):
+ for link_i in self.getRootElementLink().getElementsByTagName("link"):
+ newLink = Link()
+ newHost1 = HostLink()
+ newHost2 = HostLink()
+ try:
+ host1 = link_i.getElementsByTagName("host1")[0]
+ host2 = link_i.getElementsByTagName("host2")[0]
+ except:
+ print "Tag host1/host2 is missing"
+ sys.exit(2)
+ try:
+ newHost1.slice_name = self.getText(host1.getElementsByTagName("slice")[0])
+ newHost1.id_host = self.getText(host1.getElementsByTagName("id")[0])
+ newHost1.bridge_name = self.getText(host1.getElementsByTagName("bridge_name")[0])
+ except:
+ print "Tag slice, id or bridge_name is missing for host1"
+ sys.exit(2)
+ try:
+ newHost2.slice_name = self.getText(host2.getElementsByTagName("slice")[0])
+ newHost2.id_host = self.getText(host2.getElementsByTagName("id")[0])
+ newHost2.bridge_name = self.getText(host2.getElementsByTagName("bridge_name")[0])
+ except:
+ print "Tag slice, id or bridge_name is missing for host2"
+
+ newHost1.ssh, newHost1.url = self.getSSHAccessUrl(newHost1.slice_name, newHost1.id_host )
+ newHost2.ssh, newHost2.url = self.getSSHAccessUrl(newHost2.slice_name, newHost2.id_host )
+ newLink.host1 = newHost1
+ newLink.host2 = newHost2
+ self.__linkList__.append(newLink)
+
+ def setLinks(self):
+ import subprocess
+ print "Creating Links"
+ for link_i in self.__linkList__:
+ host1 = link_i.host1
+ host2 = link_i.host2
+ link_name_host1 = host1.slice_name+"@"+str(host1.url)+"@"+host1.bridge_name
+ link_name_host2 = host2.slice_name+"@"+str(host2.url)+"@"+host2.bridge_name
+ link_name = link_name_host1+"---"+link_name_host2
+ print "\tOn "+str(host1.slice_name)+"@"+str(host1.url)
+ self.execute("sudo -S sliver-ovs create_port "+host1.bridge_name+" "+link_name, host1.ssh)
+ print "\tOn "+str(host2.slice_name)+"@"+str(host2.url)
+ self.execute("sudo -S sliver-ovs create_port "+host2.bridge_name+" "+link_name, host2.ssh)
+ proc = subprocess.Popen(["host "+str(host1.url)+" | sed -n 's/^.*has address *//p'"], stdout=subprocess.PIPE, shell=True)
+ (out, err) = proc.communicate()
+ ip1 = out.replace('\n','')
+ proc = subprocess.Popen(["host "+str(host2.url)+" | sed -n 's/^.*has address *//p'"], stdout=subprocess.PIPE, shell=True)
+ (out, err) = proc.communicate()
+ ip2 = out.replace('\n','')
+ portUDP1 = self.execute("sudo -S sliver-ovs get_local_endpoint "+link_name, host1.ssh, retour=True).replace('\n','')
+ portUDP2 = self.execute("sudo -S sliver-ovs get_local_endpoint "+link_name, host2.ssh, retour=True).replace('\n','')
+ print "\tPort UDP1 = "+str(portUDP1)+" Port UDP2 = "+str(portUDP2)
+ self.execute("sudo -S sliver-ovs set_remote_endpoint "+link_name+" "+ip2+" "+portUDP2, host1.ssh)
+ self.execute("sudo -S sliver-ovs set_remote_endpoint "+link_name+" "+ip1+" "+portUDP1, host2.ssh)
+
+ def getSSHAccessUrl(self, slice_name, id_host):
+ host_search = self.getHost(slice_name, id_host)
+ return host_search.ssh, host_search.url
+
+ def getHost(self, slice_name, host_id):
+ i = j = 0
+ slice_search = self.__sliceList__[i]
+ try:
+ while slice_search.slice_name.value != slice_name:
+ i+=1
+ slice_search = self.__sliceList__[i]
+ host_search = slice_search.hosts[j]
+ while host_search.id_host != host_id:
+ j+=1
+ host_search = slice_search.hosts[j]
+ except IndexError:
+ print "The host in slice ->",slice_name,"and host id ->",host_id,"doesn't exist"
+ print "\tAn IndexError occured"
+ sys.exit(2)
+ return host_search
+
+ def getUrl(self, slice_name, id_host):
+ host_search = self.getHost(slice_name, id_host)
+ return host_search.url
+
+ def getTapId(self, route, idDev, host):
+ idUser = self.execute("id -u", route.host_ssh, retour = True).replace('\n','')
+ i = 0
+ dev_searched = host.devices[i]
+ try:
+ while dev_searched.id_dev != idDev:
+ i += 1
+ dev_searched = host_searched.devices[i]
+ except IndexError:
+ print "Error while setting the route"
+ print "For slice ->",host_searched.slice_name," id host ->",host_searched.id_host," the following device does not exist ->",idDev
+ sys.exit(2)
+ return "tap"+idUser+"-"+str(i)
+
+ #TODO change the function for online mode
+ def sshCheck(self, host, slice_name):
+ ssh = paramiko.SSHClient()
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ try:
+ ssh.connect(host, username=slice_name, port=self.sshPort, key_filename=self.sshKey)
+ pass
+ # This error is raised if the ssh key has not already been installed on the node
+ except paramiko.PasswordRequiredException, why:
+ print "Password required exception"
+ print "Error: ", why
+ raise SSHConnectError(host, slice_name)
+ except paramiko.SSHException:
+ print "An SSH exception occured"
+ raise SSHConnectError(host, slice_name)
+ except Exception, why:
+ print "An error occured for host "+str(host)+" on slice "+str(slice_name)
+ print why
+ raise SSHConnectError(host, slice_name)
+ return ssh
+
+ def timeout(signum, frame):
+ raise TimeOutException, "Command ran for too long"
+
+ def getText(self, node):
+ return node.childNodes[0].nodeValue
+
+ def execute(self, command, ssh, display=False, retour=False):
+ print "# "+command
+ stdin, stdout, stderr = ssh.exec_command(command)
+ stdin.close()
+ while not stdout.channel.exit_status_ready():
+ time.sleep(2)
+ err = stderr.read()
+ if err != None:
+ splitted = err.splitlines()
+ if len(splitted) > 0:
+ print "\tError in execution"
+ for line in splitted:
+ print "\t>",line
+ if display:
+ for line in stdout.read().splitlines() :
+ print " > " + line
+ elif retour:
+ return stdout.read()
+ return stdout.channel.recv_exit_status()
+
+ def clearConf(self):
+ print "Removing the topology configuration"
+ for slice_i in self.__sliceList__:
+ for host_i in slice_i.hosts:
+ self.sshCheck(host_i.url.value, slice_i.slice_name.value)
+ print "\tOn "+str(slice_i.slice_name)+"@"+str(host_i.url)+" clearing the conf :"
+ sshHost = host_i.ssh
+ for device_i in host_i.devices:
+ self.execute("sudo -S sliver-ovs del_bridge "+device_i.id_dev, sshHost, display=True)
+ self.execute("sudo -S sliver-ovs stop_switch", sshHost, display=True)
+ self.execute("sudo -S sliver-ovs stop_db", sshHost, display=True)
+ host_i.services.removeService()
+
+ def printSlice(self):
+ print "List of slice/host/interface"
+ for slice_i in self.__sliceList__:
+ print slice_i
+ for host_i in slice_i.hosts:
+ print "\t"+str(host_i)
+ for dev_i in host_i.devices:
+ print "\t\t"+str(dev_i)
+
+ def printLink(self):
+ print "\nList of link"
+ for link_i in self.__linkList__:
+ print link_i
+
+ def printRoute(self):
+ print "\nList of additionnal route"
+ for slice_i in self.__sliceList__:
+ for host_i in slice_i.hosts:
+ for route_i in host_i.routes:
+ print route_i
+
+ def printService(self):
+ print "\nList of deployed service"
+ for slice_i in self.__sliceList__:
+ for host_i in slice_i.hosts:
+ serviceStr = str(host_i.services)
+ if serviceStr != '':
+ print host_i.services
+
+ def getSliceList(self):
+ return self.__sliceList__
+
+ @classmethod
+ def helpOption(self):
+ print "You can use the following options:"
+ print "\t setTopology : to create the topology"
+ print "\t clearTopology : to clear the topology"
+ print "\t printTopology : to print the topology"
+ print "Optionnal:"
+ print "\t $2 : configuration xml file"
+ print "\t $3 : link xml file"
+ print "\t $2 : prefix to find the xml file"
+ print "\t If not given default are Conf.xml, Link.xml"
+
+def keyFile(x):
+ print x
+ if not os.path.exists(x) and x!=os.path.expanduser('~/.ssh/id_rsa'):
+ raise argparse.ArgumentError("{0} does not exist".format(x))
+ return x
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ #parser = argparse.ArgumentParser("This script allow you to deploy a configured topology on planetlab node, the topology has to be descript in xml file\nYou have to use one of the action option (-c -s -p)\nYou have to specify the input file that need to be used")
+ parser.add_argument("action", help="The action you want to perform choices are print, set or clear the topology", choices = ['print','set','clear'], default='print', nargs='?')
+ parser.add_argument("-k", "--key", help="The location of the ssh private key file (default value is ~/.ssh/id_rsa)", default=os.path.expanduser('~/.ssh/id_rsa'), type=keyFile)
+ parser.add_argument('-p', '--port', help='The port used for the ssh connection (default is 22)', default=22, type = int)
+
+ groupInput = parser.add_mutually_exclusive_group()
+ groupInput.add_argument("-f", "--file", help="The xml file that will be used, Link xml file then Configuration xml file", type=str, default='', nargs=2)
+ groupInput.add_argument("-d", "--directory", help="The directory used to find the xml file the script will look at prefix+Conf.xml and prefix+Link.xml", type=str, default='./', dest='prefix')
+
+ try:
+ args = parser.parse_args()
+ except Exception, why:
+ print "An error occured while parsing the argument"
+ parser.print_help()
+ print why
+ sys.exit(2)
+
+ if args.file != '':
+ x = TransformXml(confFile = args.file[0], linkFile = args.file[1], port = args.port, keyFile = args.key)
+ else:
+ x = TransformXml(prefix = args.prefix, port = args.port, keyFile = args.key )
+
+ if args.action == "set" :
+ x.setSliceConf()
+ x.setLinks()
+ x.setRoutes()
+ x.setServices()
+ elif args.action == "clear" :
+ x.clearConf()
+ elif args.action == "print" :
+ x.printSlice()
+ x.printLink()
+ x.printRoute()
+ x.printService()
+
--- /dev/null
+#!/usr/bin/python
+
+import xmlrpclib
+import Auth
+import sys
+import paramiko
+import subprocess
+import time
+import geopy
+import geopy.distance
+import argparse
+import os
+import socket
+import urllib2
+import csv
+from openvswitch import TransformXml
+from exceptionDefinition import FailToConnect, NodeConstraintError
+from scp import SCPClient
+
+
+yumOpt = "sudo -S yum -y --nogpgcheck "
+
+class TransformRawXml:
+ def __init__(self, confFile = "", linkFile = "", subnet = "", prefix = "", sliceName = "", nbEnv = 1, mainKeyPriv = None, mainKeyPub = None, sliceUrl = 'http://onelab.eu', sliceDescription = 'Slice used for educationnal purpose', country = False):
+ # Definition of the api used for the actions on planetlab
+ plc_host='www.planet-lab.eu'
+ api_url='https://%s:443/PLCAPI/'%plc_host
+ self.plc_api=xmlrpclib.ServerProxy(api_url, allow_none=True)
+ # Prefix used for the slice name
+ slice_pref='upmc_'
+
+ self.sliceUrl = sliceUrl
+ self.sliceDescription = sliceDescription
+
+ myOpsPLC = urllib2.urlopen('http://monitor.planet-lab.org/monitor/query?hostname=on&tg_format=plain&object=nodes&nodehistory_hostname=&observed_status=on&rpmvalue=')
+ self.myOpsPLCCsv = list(csv.reader(myOpsPLC))
+ myOpsPLE = urllib2.urlopen('http://monitor.planet-lab.eu/monitor/query?hostname=on&tg_format=plain&object=nodes&nodehistory_hostname=&observed_status=on&rpmvalue=')
+ self.myOpsPLECsv = list(csv.reader(myOpsPLE))
+
+ self.subnet = subnet
+ if prefix != "":
+ self.xmlFileConf = prefix+'Conf.xml'
+ self.xmlFileLink = prefix+'Link.xml'
+ else:
+ self.xmlFileConf = confFile
+ self.xmlFileLink = linkFile
+ if 'upmc_' not in sliceName:
+ self.slice_name = slice_pref+sliceName
+ else:
+ self.slice_name = sliceName
+
+ self.nbEnv = int(nbEnv)
+
+ self.country = country
+
+ # Attribute for ssh key
+ self.mainKeyPriv = mainKeyPriv
+ self.mainKeyPub = mainKeyPub
+ self.envKeyPriv = []
+ self.envKeyPub = []
+
+ # Attribute that will contain the list of environment
+ self.envList = []
+
+ self.envConfFile = []
+ self.envLinkFile = []
+
+ # Delete the slice
+ def deleteSlice(self):
+ errorCode = self.plc_api.DeleteSlice(Auth.auth, self.slice_name)
+ if errorCode != 1:
+ print "An error occured unable to delete the slice"
+ print errorCode
+ print self.slice_name
+
+ # Add 15 days to the expiration date
+ def renewSlice(self, day = 15):
+ print self.slice_name
+ expiration = self.plc_api.GetSlices(Auth.auth, self.slice_name, ['expires'])[0]['expires']
+ print expiration
+ newExpiration = expiration + (3600*24*day)
+ self.plc_api.UpdateSlice(Auth.auth, self.slice_name, {'expires': newExpiration})
+ expiration = self.plc_api.GetSlices(Auth.auth, self.slice_name, ['expires'])[0]['expires']
+ print expiration
+
+ # Generate a ssh key pair
+ def generateKeyPair(self,pref = "", bit = 1024):
+ key = paramiko.RSAKey.generate(bit)
+ # Save the private key file
+ keyFilePriv = pref+"id_rsa.priv"
+ key.write_private_key_file(keyFilePriv)
+ # Save the public key file
+ keyFilePub = pref+"id_rsa.pub"
+ openedFile = open(keyFilePub, 'w')
+ openedFile.write("%s %s \n" % (key.get_name(), key.get_base64()))
+ return keyFilePriv, keyFilePub
+
+ # press any key to continue function
+ def anykey(self, prompt="Press enter to continue...", failChars=""):
+ char = raw_input(prompt)
+ return (char not in failChars)
+
+ def checkSSH(self, node):
+ countFailSSH = 9
+ ssh = paramiko.SSHClient()
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ connected = False
+ error = None
+ i = 0
+ while(connected == False):
+ print "\n"+self.mainKeyPriv+" -> "+self.slice_name+"@"+node['hostname']
+ try:
+ ssh.connect(node['hostname'], username = self.slice_name, key_filename = self.mainKeyPriv)
+ connected = True
+ except paramiko.PasswordRequiredException, why:
+ print "Password required exception"
+ print "Error: ", why
+
+ except paramiko.SSHException, why:
+ print "An SSH exception occured"
+ print "Error: ", why
+
+ except socket.error, why:
+ print "A soccket error occured"
+ print why
+ failingNode = self.plc_api.GetNodes(Auth.auth, node['id'])[0]
+ print 'FailingNode node_id -> '+str(failingNode['node_id'])
+ raise FailToConnect(failingNode['node_id'], failingNode['hostname'])
+
+ except Exception, why:
+ print "An error occured for host "+str(node['hostname'])+" on slice "+str(self.slice_name)
+ print type(why)
+ print why
+ sys.exit(2)
+ if str(why)!=error:
+ print why
+ error=str(why)
+
+ if i > countFailSSH and connected==False:
+ print error
+ failingNode = self.plc_api.GetNodes(Auth.auth, node['id'])[0]
+ raise Exception(failingNode['hostname'])
+ try:
+ if connected == False:
+ print "Now waiting 5 minutes for an update of the node"
+ time.sleep(300)
+ except KeyboardInterrupt, why:
+ print "You interrupt the wait"
+ i += 1
+ print "I make",i,"iteration before getting connection"
+ copied = False
+ i=0
+ while(copied == False):
+ try:
+ SCPClient(ssh.get_transport()).put('configService/fedora.repo')
+ SCPClient(ssh.get_transport()).put('configService/fedora-updates.repo')
+ SCPClient(ssh.get_transport()).put('configService/fedora-updates-testing.repo')
+ self.execute("sudo -S mv *.repo /etc/yum.repos.d/", ssh)
+ self.execute("sudo -S chown root:root /etc/yum.repos.d/*.repo", ssh)
+ copied = True
+ except Exception, why:
+ print "An error occured while configuring yum"
+ print "Error: ",why
+ if i > 4 and copied == False:
+ failingNode = self.plc_api.GetNodes(Auth.auth, node['id'])[0]
+ raise Exception(failingNode['hostname'])
+ if copied == False:
+ time.sleep(60)
+ i+=1
+
+ return ssh
+
+
+ # Install an alternate ssh server
+ def installSSH(self, userKeyFile, node):
+ ssh = self.checkSSH(node)
+ returnCode = -1
+ i = 0
+ while(returnCode != 0):
+ if i > 3:
+ failingNode = self.plc_api.GetNodes(Auth.auth, node['id'])[0]
+ raise Exception(failingNode['hostname'])
+ returnCode = self.execute(yumOpt+"install openssh-server", ssh, display= True)
+ print "Return Code is ->", returnCode
+ time.sleep(5)
+ i += 1
+ self.execute("mkdir .ssh", ssh, display= True)
+ if node['type'] == 'private':
+ SCPClient(ssh.get_transport()).put(userKeyFile, ".ssh/id_rsa.pub")
+ SCPClient(ssh.get_transport()).put("configService/sshd_config", "./")
+ elif node['type'] == 'public':
+ SCPClient(ssh.get_transport()).put(userKeyFile, ".ssh/id_rsa.pub.tmp")
+ SCPClient(ssh.get_transport()).put("configService/sshd_config", "./")
+ self.execute("cat .ssh/id_rsa.pub.tmp >> .ssh/id_rsa.pub", ssh)
+ self.execute("sudo -S mv ./sshd_config /etc/ssh/", ssh)
+ self.execute("sudo -S sh -c \"echo \\\"Port 2222\\\" >> /etc/ssh/sshd_config\"", ssh)
+ port = 2222
+ returnCode = -1
+ while (returnCode != 0):
+ time.sleep(2)
+ returnCode = self.execute("sudo -S service sshd restart", ssh, display = True)
+ if returnCode != 0:
+ self.execute("sudo -S sed -i -e \"s/Port "+str(port)+"/Port "+str(port+1)+"/g\" /etc/ssh/sshd_config", ssh)
+ port +=1
+ return port
+
+ # Execute a command on a remote machine
+ def execute(self, command, ssh, display= False, retour= False):
+ print "# "+command
+ stdin, stdout, stderr = ssh.exec_command(command)
+ stdin.close()
+ while not stdout.channel.exit_status_ready():
+ time.sleep(2)
+
+ err = stderr.read()
+ if err != None:
+ splitted = err.splitlines()
+ if len(splitted) > 0:
+ print "Error in execution"
+ for line in splitted:
+ print "> "+line
+ if display:
+ for line in stdout.read().splitlines():
+ print "> "+line
+ elif retour:
+ return stdout.read()
+ return stdout.channel.recv_exit_status()
+
+ # Create the xml file corresponding to each environment
+ def createXmlFile(self, hostList, idEnv):
+ from xml.dom.minidom import parse
+ conf = parse(self.xmlFileConf)
+ link = parse(self.xmlFileLink)
+ sliceNames = link.getElementsByTagName('slice')
+ for value in sliceNames:
+ value.firstChild.nodeValue = self.slice_name
+ sliceNames = conf.getElementsByTagName('slice_name')
+ for value in sliceNames:
+ value.firstChild.nodeValue = self.slice_name
+ urlList = conf.getElementsByTagName('url')
+ if len(hostList) < len(urlList):
+ print "hostlist -> "+str(len(hostList))
+ print "urllist -> "+str(len(urlList))
+ for host in hostList:
+ print host
+ for i in range(len(urlList)):
+ urlList[i].firstChild.nodeValue = hostList[i]
+ subnetIP, subnetMask = self.subnet.split('/')
+ subnetMask = int(subnetMask)
+ subnetIP = subnetIP.split('.')
+ ipList = conf.getElementsByTagName('ip')
+ for ipWithMask in ipList:
+ ip, mask = str(ipWithMask.firstChild.nodeValue).split('/')
+ ip = ip.split('.')
+ mask = int(mask)
+ newIP = ''
+ if subnetMask > mask:
+ sys.exit(2)
+ # TODO define SubnetException
+ pass
+ #raise SubnetException()
+ else:
+ subnetRange = subnetMask/8
+ for i in range(len(ip)):
+ if i < subnetRange:
+ newIP+=subnetIP[i]
+ else:
+ if ip[i] == 'N':
+ newIP+=str(idEnv)
+ else:
+ newIP+=ip[i]
+ if i < 3:
+ newIP+='.'
+ newIP+='/'+str(mask)
+ ipWithMask.firstChild.nodeValue = newIP
+ confFileName = 'requ'+str(idEnv)+'Conf.xml'
+ confFile = open(confFileName, 'w')
+ conf.writexml(confFile)
+ confFile.close()
+ self.envConfFile.append(confFileName)
+ linkFileName = 'requ'+str(idEnv)+'Link.xml'
+ linkFile = open(linkFileName, 'w')
+ link.writexml(linkFile)
+ linkFile.close()
+ self.envLinkFile.append(linkFileName)
+
+ def getNodeAvailable(self, site, nodeUsed = []):
+ nodes = self.plc_api.GetNodes(Auth.auth, site['node_ids'])
+ if site['peer_id'] == 1:
+ myOpsCsv = self.myOpsPLCCsv
+ else:
+ myOpsCsv = self.myOpsPLECsv
+ for node in nodes:
+ for row in myOpsCsv:
+ if node['hostname'] == row[0]:
+ node['myOpsStatus'] = row[1]
+ break
+ nodeAvailable = []
+ for node in nodes:
+ if (node['myOpsStatus'] == 'BOOT' and node['boot_state'] == 'boot' and node['run_level'] == 'boot' and node['node_id'] not in nodeUsed):
+ nodeAvailable.append(node)
+ return nodeAvailable
+
+ def getEnvironmentWithCountryConstraint(self, countryListPrivate, contryListCommon, sites, siteBanned):
+ print "Now looking for the environment using the country constraint"
+ sitesTmp = []
+ for site in sites:
+ if len(site['address_ids']) == 1:
+ sitesTmp.append(site)
+ sites = sitesTmp
+ sitesEnv = sitesCommon = []
+
+ # Getting the private allowed address
+ try:
+ privateAddrAuth = structToArray(self.plc_api.GetAddresses(Auth.auth, {'country': countryListPrivate}, ['address_id']), 'address_id')
+ except Exception, why:
+ print why
+ sys.exit(2)
+
+ privateAddresses = []
+ i = 0
+ for site in sites:
+ if site['address_ids'][0] in privateAddrAuth and i < self.nbEnv:
+ privateAddresses.append(site['address_ids'][0])
+ i += 1
+ # Getting the private Node
+ print "Getting the private node matching with the requirement"
+ i = 0
+ for site in sites:
+ if len(site['address_ids']) == 1 and site['address_ids'][0] in privateAddrAuth:
+ nodeEnv = []
+ if i < self.nbEnv:
+ j = 0
+ nodeSite = self.plc_api.GetNodes(Auth.auth, site['node_ids'], ['hostname', 'run_level', 'node_id', 'boot_state', 'hostname'])
+ for node in nodeSite:
+ if i < self.nbEnv:
+ if node['boot_state'] == 'boot':
+ j+=1
+ nodeEnv.append({'type': 'private', 'id': node['node_id'], 'hostname': node['hostname']})
+ if j>=nbNodeByEnv:
+ i += 1
+ nodeStructList.append(nodeEnv)
+ sitesEnv.append(site)
+ nodeIdList = structToArray(nodeEnv, 'id')
+ nodeEnv = []
+ j = 0
+
+ print nodeIdList
+ print "List of site for environment :"
+ if len(nodeStructList) < self.nbEnv:
+ print "Error we are not able to find enough environment"
+ sys.exit(2)
+ for site in sitesEnv:
+ print "\t"+str(site)
+
+ # Getting the addresse wanted for common node
+ commonAddresses = []
+ for country in countryListCommon:
+ address = self.plc_api.GetAddresses(Auth.auth, {'country': country}, ['address_id'])[0]['address_id']
+ if address not in privateAddresses:
+ commonAddresses.append(address)
+
+ # Getting the common node
+ commonNodes = []
+ for site in sites:
+ if site['address_ids'][0] in commonAddresses:
+ nodeSite = self.plc_api.GetNodes(Auth.auth, site['node_ids'], ['hostname', 'run_level', 'node_id', 'boot_state'])
+ for node in nodeSite:
+ if node['boot_state'] == 'boot' and node['node_id'] not in nodeIdList:
+ commonNodes.append({'type': 'common','id': node['node_id'], 'hostname': node['hostname']})
+ nodeIdList.append(node['node_id'])
+ break
+
+ for env in nodeStructList:
+ for node in commonNodes:
+ env.append(node)
+
+
+ print "Address list :"
+ #for addresse in commonAddresses:
+ # print "\t"+str(addresse)
+ print privateAddresses
+ print commonAddresses
+
+ return nodeStructList
+
+ def getEnvironmentWithDistanceConstraint(self, constraintList, sitesList, siteBanned, nodeBanned):
+ print "Now looking for the environment using the distance constraint"
+ envList = []
+ nbPrivate = nbCommon = 0
+ nbInitPrivate = nbInitCommon = 0
+ # Counting the number of private and common node
+ # Also counting the number of node located at the same point
+ for node in constraintList:
+ if node['type'] == 'private':
+ nbPrivate += 1
+ if node['max'] == 0 and node['min'] == 0:
+ nbInitPrivate += 1
+ elif node['type'] == 'common' or node['type'] == 'public':
+ nbCommon += 1
+ if node['max'] == 0 and node['min'] == 0:
+ nbInitCommon += 1
+
+ print "Common "+str(nbCommon)+" "+str(nbInitCommon), " Private "+str(nbPrivate)+" "+str(nbInitPrivate)
+ nbReservedEnvironment = 0
+ siteUsed = []
+ nodePrivate = []
+ nodeShared = []
+ while nbReservedEnvironment < self.nbEnv:
+ tmpListEnv = []
+ maxNode = []
+ for site in sitesList:
+ if site['site_id'] not in siteUsed and site['site_id'] not in siteBanned:
+ try:
+ nodeAvailable = self.getNodeAvailable(site, nodeBanned)
+ if len(nodeAvailable) > len(maxNode):
+ maxNode = nodeAvailable
+ siteInit = site
+ except Exception, why:
+ print 'Couldn\'t get the node available'
+ print site['name']
+ print why
+ sys.exit(2)
+ siteUsed.append(siteInit['site_id'])
+ newEnv = []
+ print "Site used -> "+str(siteUsed)
+ print siteInit['name']
+ for i in range(len(maxNode)-nbInitCommon):
+ node = maxNode[i]
+ if nbReservedEnvironment < self.nbEnv:
+ newEnv.append({'type': 'private', 'id': node['node_id'], 'hostname': node['hostname'], 'distance': 0, 'latitude': siteInit['latitude'], 'longitude': siteInit['longitude']})
+ nodePrivate.append(node['node_id'])
+ if len(newEnv) == nbInitPrivate:
+ tmpListEnv.append(newEnv)
+ newEnv = []
+ nbReservedEnvironment += 1
+ else:
+ break
+ commonNode = []
+ for i in range(nbInitPrivate,len(constraintList)):
+ nodeAdded = False
+ print constraintList[i]
+ if constraintList[i]['type'] in ['common', 'public']:
+ for site in sitesList:
+ if site['site_id'] not in siteBanned:
+ initPoint = geopy.Point(siteInit['latitude'], siteInit['longitude'])
+ distPoint = geopy.Point(site['latitude'], site['longitude'])
+ distance = geopy.distance.distance(initPoint, distPoint).km
+ if distance >= constraintList[i]['min'] and distance <= constraintList[i]['max']:
+ nodeAvailable = self.getNodeAvailable(site, nodePrivate+nodeBanned)
+ if len(nodeAvailable) > 0:
+ print distance
+ print site['name']
+ siteUsed.append(site['site_id'])
+ node = nodeAvailable[0]
+ nodeShared.append(node['node_id'])
+ commonNode.append({'type': constraintList[i]['type'], 'id': node['node_id'], 'hostname': node['hostname'], 'distance': int(distance), 'latitude': site['latitude'], 'longitude': site['longitude']})
+ nodeAdded = True
+ break
+ if not(nodeAdded) and constraintList[i]['type'] in ['common', 'public']:
+ print 'Error no node added for constraint -> '+str(constraintList[i])
+ raise NodeConstraintError(constraintList[i], envList)
+ elif constraintList[i]['type'] == 'private':
+ nodeToAdd = []
+ for env in tmpListEnv:
+ if len(nodeToAdd) == 0:
+ for site in sitesList:
+ if site['site_id'] not in siteBanned:
+ initPoint = geopy.Point(siteInit['latitude'], siteInit['longitude'])
+ distPoint = geopy.Point(site['latitude'], site['longitude'])
+ distance = geopy.distance.distance(initPoint, distPoint).km
+ if distance >= constraintList[i]['min'] and distance <= constraintList[i]['max']:
+ nodeAvailable = self.getNodeAvailable(site, nodePrivate+nodeShared+nodeBanned)
+ if len(nodeAvailable) > 0:
+ nodeToAdd = nodeAvailable
+ node = nodeToAdd.pop(0)
+ env.append({'type': 'private', 'id': node['node_id'], 'hostname': node['hostname'], 'distance': int(distance), 'latitude': site['latitude'], 'longitude': site['longitude']})
+
+ for env in tmpListEnv:
+ for node in commonNode:
+ env.append(node)
+
+ envList.extend(tmpListEnv)
+
+ return envList
+
+ # Reading the raw xml file to get information
+ # Return an array of array of struct containing the information concerning each environment requested
+ def readRawXml(self, siteBanned, nodeBanned):
+ print "Banned Site ->",siteBanned
+ print "Node banned ->",nodeBanned
+ from xml.dom.minidom import parse
+ conf = parse(self.xmlFileConf)
+ nbNodeByEnv = nbCommonNode = 0
+ nodeStructList = []
+ nodeIdList = []
+ countryListCommon = []
+ countryListPrivate = []
+ constraintList = []
+ for host_i in conf.getElementsByTagName('host'):
+ hostType = ""
+ try:
+ hostType = host_i.getElementsByTagName('type')[0].firstChild.nodeValue
+ except Exception, why:
+ print why
+ if hostType == 'private' or hostType == "":
+ nbNodeByEnv += 1
+ elif hostType == 'common' or hostType == 'public':
+ nbCommonNode += 1
+ else:
+ print "Error the host type "+hostType+" doesn't exist"
+ sys.exit(2)
+ if self.country:
+ try:
+ hostCountry = host_i.getElementsByTagName('country')[0].firstChild.nodeValue
+ if hostType == 'common':
+ countryListCommon.append(hostCountry)
+ elif hostType == 'private':
+ countryListPrivate.append(hostCountry)
+ except Exception, why:
+ print "An error occured"
+ print why
+ sys.exit(2)
+ else:
+ try:
+ distance = host_i.getElementsByTagName('distances')[0]
+ distMin = int(distance.getElementsByTagName('min')[0].firstChild.nodeValue)
+ distMax = int(distance.getElementsByTagName('max')[0].firstChild.nodeValue)
+ constraintList.append({'type': hostType, 'min': distMin, 'max': distMax})
+ except Exception, why:
+ print "An error occured"
+ print why
+ sys.exit(2)
+
+
+ print "Getting all the site available"
+ sites = self.plc_api.GetSites(Auth.auth, ['*'])
+
+ if self.country:
+ nodeStructList = self.getEnvironmentWithCountryConstraint(countryListPrivate, contryListCommon, sites, siteBanned, nodeBanned)
+ else:
+ try:
+ nodeStructList = self.getEnvironmentWithDistanceConstraint(constraintList, sites, siteBanned, nodeBanned)
+ except NodeConstraintError as error:
+ self.nbEnv = len(error.getEnvList())
+ nodeStructList = error.getEnvList()
+
+
+ # Creating a file containing all the information about the slice created
+ origStdout = sys.stdout
+ sys.stdout = open('Test', 'w')
+ i = 0
+ print "Slice name : "+self.slice_name
+ for env in nodeStructList:
+ i+=1
+ print "\tEnv %i"%i
+ for node in env:
+ strNode = '\t'
+ for key in node.keys():
+ strNode += "\t"+str(key)+" : "+str(node[key])
+ print strNode
+ sys.stdout.close()
+ sys.stdout = origStdout
+
+ return(nodeStructList)
+
+ def structToArray(self, requestAnswer, key):
+ #return [i[key] for i in requestAnswer]
+ array = []
+ for i in requestAnswer:
+ array.append(i[key])
+ return array
+
+ def addSliceTag(self, sliceId, tagName, tagValue):
+ try:
+ returnCode = self.plc_api.AddSliceTag(Auth.auth, sliceId, tagName, tagValue)
+ if returnCode == 0:
+ print "An error Occured while adding the tag %s -> %s"% tagName, tagValue
+ except xmlrpclib.Fault as fault:
+ if fault.faultCode != 102:
+ print "An error occured"
+ print fault
+ sys.exit(2)
+
+ def getSlice(self):
+ try:
+ sliceId = self.plc_api.GetSlices(Auth.auth, self.slice_name)[0]['slice_id']
+ except xmlrpclib.Fault, why:
+ print "An error while getting the slice already existing"
+ print why
+ sys.exit(2)
+ return sliceId
+
+ def createSlice(self):
+ sliceId = 0
+ print "Creating a new slice called : "+self.slice_name
+ try:
+ sliceId = self.plc_api.AddSlice(Auth.auth, {'description': self.sliceDescription, 'name':self.slice_name, 'url': self.sliceUrl})
+ except xmlrpclib.Fault, why:
+ print "An error occured while creating the slice "+self.slice_name
+ print why
+ except Exception, why:
+ print "An error occured while createing the slice "+self.slice_name
+ print type(why)
+ print why
+ return sliceId
+
+ def setSlice(self):
+ sliceId = self.createSlice()
+ if (sliceId == 0):
+ print 'Slice exist'
+ sliceId = self.getSlice()
+ print "Adding user to the slice"
+ returnCode = self.plc_api.AddPersonToSlice(Auth.auth, Auth.auth['Username'], sliceId)
+
+ if type(self.nbEnv) != int:
+ print "You must enter a number"
+ sys.exit(2)
+
+ print "Generating and adding the main ssh key"
+ print os.getcwd()
+ if self.mainKeyPriv == None:
+ self.mainKeyPriv, self.mainKeyPub = self.generateKeyPair(pref = "./key/"+self.slice_name+"main", bit = 1024)
+ f = open(self.mainKeyPub)
+ keyString = f.read()
+ try:
+ keyId = self.plc_api.AddPersonKey(Auth.auth, Auth.auth['Username'], {'key_type': 'ssh', 'key': keyString})
+ if returnCode == 0:
+ print "An error occured while adding the key to the user"
+ sys.exit(2)
+ except xmlrpclib.Fault as fault:
+ print fault
+ sys.exit(2)
+
+ success = False
+ #TODO Ban failing site, waiting for fix
+ #FU Berlin || Reykjavik University || FOKUS || University of Goettingen
+ siteBanned = [7341, 7336, 443, 7059]
+ # TODO banned new lip6 node + FUNDP Site + DSCHINI
+ nodeBanned = [15953, 15954, 15955, 15956, 14810]
+ while success == False:
+ nodeList = self.readRawXml(siteBanned[:], nodeBanned)
+
+ print "Adding node to the slice"
+ i = 0
+ for env in nodeList:
+ for node in env:
+ failToAdd = True
+ j = 0
+ while failToAdd:
+ try:
+ if node['type'] == 'private' or ((node['type'] == 'common' or node['type'] == 'public') and i == 0):
+ returnCode = self.plc_api.AddSliceToNodes(Auth.auth, sliceId, [node['id']])
+ if returnCode != 1:
+ print "An error occured while adding a node to the slice"
+ time.sleep(30)
+ else:
+ failToAdd = False
+ except xmlrpclib.Fault as fault:
+ print fault
+ time.sleep(30)
+ if j > 2 and failToAdd:
+ raise FailToConnect(node['id'], node['hostname'])
+ j+=1
+ i = 1
+
+
+
+ i=0
+ # Set additional ssh server using generated key file and port 2222
+ try:
+ for envList in nodeList:
+ envKeyPriv, envKeyPub = self.generateKeyPair(pref = "./key/"+self.slice_name+"group"+str(i+1), bit = 1024)
+ self.envKeyPriv.append(envKeyPriv)
+ self.envKeyPub.append(envKeyPub)
+ for node in envList:
+ print node['hostname']
+ if node['type'] != 'common':
+ self.installSSH(self.envKeyPub[i], node)
+ pass
+ else:
+ self.checkSSH(node)
+ pass
+ i+=1
+ success = True
+ except FailToConnect as error:
+ print "Not able to get the ssh connection for node", error.getNodeUrl()
+ print 'Error node id -> '+str(error.getNodeId())
+ print 'Before adding failing node -> '+str(nodeBanned)
+ nodeBanned.append(error.getNodeId())
+ print 'After adding failing node -> '+str(nodeBanned)
+ except Exception, why:
+ print "Not able to get the ssh connection", why
+
+
+
+ print "Adding requested tag to the slice"
+ # Adding the tag needed :
+ # - TAG -> VALUE : DEF
+ # - vsys -> vif_up
+ # - vsys -> vif_down
+ # - vsys -> fd_tuntap : Allow to create tun/tap interface
+ # - vsys -> vroute : Allow to define new route
+ # - vsys_vnet -> SUBNET : Define the subnet allowed for tun/tap device
+
+ self.addSliceTag(sliceId, 'vsys', 'vif_up')
+ self.addSliceTag(sliceId, 'vsys', 'vif_down')
+ self.addSliceTag(sliceId, 'vsys', 'fd_tuntap')
+ self.addSliceTag(sliceId, 'vsys', 'vroute')
+ self.addSliceTag(sliceId, 'vsys_vnet', self.subnet)
+
+ # Configuring the node using the openvswitch.py script
+ # Command used to execute the script
+ i = 0
+ for env in nodeList:
+ i+=1
+ print "Env ",i
+ hostnameList = self.structToArray(env, 'hostname')
+ self.createXmlFile(hostnameList, i)
+ try:
+ x = None
+ x = TransformXml(prefix = 'requ'+str(i), keyFile = self.mainKeyPriv)
+ x.setSliceConf()
+ x.setLinks()
+ x.setRoutes()
+ x.setServices()
+ self.envList.append(x.getSliceList())
+ except Exception, why:
+ print "An error occured while configuring the environment number "+str(i-1)
+ print Exception
+ print ''
+ print why
+ sys.exit(2)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-s", "--subnet", help="The subnet reserved for the slice, it must include at least all the ip address used by the tp. The syntax is SUBNET/PREFIX (e.g 10.1.0.0/16 which is the default value)", default='10.1.0.0/16')
+ parser.add_argument("-n", "--name", help="Name of the slice", default='tp')
+ parser.add_argument("-nb", "--number", help="Number of the environment you want", type=int, default=1)
+ groupInput = parser.add_mutually_exclusive_group()
+ groupInput.add_argument('-f', '--file', help="The xml file that will be used, Link xml file then Configuration xml file", type=str, default='', nargs=2)
+ groupInput.add_argument("-p", "--prefix", help="A prefix used to find the xml file, the script will look at prefix+Conf.xml and prefix+Link.xml", type=str, dest='prefix')
+
+ try:
+ args = parser.parse_args()
+ except Exception, why:
+ print "An error occured while parsing the argument"
+ parser.print_help()
+ print why
+ sys.exit(2)
+
+ if args.file != '':
+ x = TransformRawXml(confFile = args.file[0], linkFile = args.file[1], subnet = args.subnet, sliceName = args.name, nbEnv = args.number)
+ x.setSlice()
+ else:
+ x = TransformRawXml(prefix = args.prefix, subnet = args.subnet, sliceName = args.name, nbEnv = args.number)
+ x.setSlice()
+
--- /dev/null
+# scp.py
+# Copyright (C) 2008 James Bardin <jbardin@bu.edu>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+"""
+Utilities for sending files over ssh using the scp1 protocol.
+"""
+
+import os
+from socket import timeout as SocketTimeout
+
+class SCPClient(object):
+ """
+ An scp1 implementation, compatible with openssh scp.
+ Raises SCPException for all transport related errors. Local filesystem
+ and OS errors pass through.
+
+ Main public methods are .put and .get
+ The get method is controlled by the remote scp instance, and behaves
+ accordingly. This means that symlinks are resolved, and the transfer is
+ halted after too many levels of symlinks are detected.
+ The put method uses os.walk for recursion, and sends files accordingly.
+ Since scp doesn't support symlinks, we send file symlinks as the file
+ (matching scp behaviour), but we make no attempt at symlinked directories.
+
+ Convenience methods:
+ put_r: put with recursion
+ put_p: put preserving times
+ put_rp: put with recursion, preserving times
+ get_r: get with recursion
+ get_p: get preserving times
+ get_rp: get with recursion, preserving times
+ """
+ def __init__(self, transport, buff_size = 16384, socket_timeout = 5.0,
+ callback = None):
+ """
+ Create an scp1 client.
+
+ @param transport: an existing paramiko L{Transport}
+ @type transport: L{Transport}
+ @param buff_size: size of the scp send buffer.
+ @type buff_size: int
+ @param socket_timeout: channel socket timeout in seconds
+ @type socket_timeout: float
+ @param callback: callback function for transfer status
+ @type callback: func
+ """
+ self.transport = transport
+ self.buff_size = buff_size
+ self.socket_timeout = socket_timeout
+ self.channel = None
+ self.preserve_times = False
+ self.callback = callback
+ self._recv_dir = ''
+ self._utime = None
+ self._dirtimes = {}
+
+ def put(self, files, remote_path = '.',
+ recursive = False, preserve_times = False):
+ """
+ Transfer files to remote host.
+
+ @param files: A single path, or a list of paths to be transfered.
+ recursive must be True to transfer directories.
+ @type files: string OR list of strings
+ @param remote_path: path in which to receive the files on the remote
+ host. defaults to '.'
+ @type remote_path: str
+ @param recursive: transfer files and directories recursively
+ @type recursive: bool
+ @param preserve_times: preserve mtime and atime of transfered files
+ and directories.
+ @type preserve_times: bool
+ """
+ self.preserve_times = preserve_times
+ self.channel = self.transport.open_session()
+ self.channel.settimeout(self.socket_timeout)
+ scp_command = ('scp -t %s\n', 'scp -r -t %s\n')[recursive]
+ self.channel.exec_command(scp_command % remote_path)
+ self._recv_confirm()
+
+ if not isinstance(files, (list, tuple)):
+ files = [files]
+
+ if recursive:
+ self._send_recursive(files)
+ else:
+ self._send_files(files)
+
+ if self.channel:
+ self.channel.close()
+
+ def put_r(self, files, remote_path = '.'):
+ """
+ Convenience function for a recursive put
+
+ @param files: A single path, or a list of paths to be transfered.
+ @type files: str, list
+ @param remote_path: path in which to receive the files on the remote
+ host. defaults to '.'
+ @type remote_path: bool
+ """
+ self.put(files, remote_path, recursive = True)
+
+ def put_p(self, files, remote_path = '.'):
+ """
+ Convenience function to put preserving times.
+
+ @param files: A single path, or a list of paths to be transfered.
+ @type files: str, list
+ @param remote_path: path in which to receive the files on the remote
+ host. defaults to '.'
+ @type remote_path: bool
+ """
+ self.put(files, remote_path, preserve_times = True)
+
+ def put_rp(self, files, remote_path = '.'):
+ """
+ Convenience function for a recursive put, preserving times.
+
+ @param files: A single path, or a list of paths to be transfered.
+ @type files: str, list
+ @param remote_path: path in which to receive the files on the remote
+ host. defaults to '.'
+ @type remote_path: bool
+ """
+ self.put(files, remote_path, recursive = True, preserve_times = True)
+
+ def get(self, remote_path, local_path = '',
+ recursive = False, preserve_times = False):
+ """
+ Transfer files from remote host to localhost
+
+ @param remote_path: path to retreive from remote host. since this is
+ evaluated by scp on the remote host, shell wildcards and
+ environment variables may be used.
+ @type remote_path: str
+ @param local_path: path in which to receive files locally
+ @type local_path: str
+ @param recursive: transfer files and directories recursively
+ @type recursive: bool
+ @param preserve_times: preserve mtime and atime of transfered files
+ and directories.
+ @type preserve_times: bool
+ """
+ self._recv_dir = local_path or os.getcwd()
+ rcsv = ('', ' -r')[recursive]
+ prsv = ('', ' -p')[preserve_times]
+ self.channel = self.transport.open_session()
+ self.channel.settimeout(self.socket_timeout)
+ self.channel.exec_command('scp%s%s -f %s' % (rcsv, prsv, remote_path))
+ self._recv_all()
+
+ if self.channel:
+ self.channel.close()
+
+ def get_r(self, remote_path, local_path = '.'):
+ """
+ Convenience function for a recursive get
+
+ @param remote_path: path to retrieve from server
+ @type remote_path: str
+ @param local_path: path in which to recieve files. default cwd
+ @type local_path: str
+ """
+ self.get(remote_path, local_path, recursive = True)
+
+ def get_p(self, remote_path, local_path = '.'):
+ """
+ Convenience function for get, preserving times.
+
+ @param remote_path: path to retrieve from server
+ @type remote_path: str
+ @param local_path: path in which to recieve files. default cwd
+ @type local_path: str
+ """
+ self.get(remote_path, local_path, preserve_times = True)
+
+ def get_rp(self, remote_path, local_path = '.'):
+ """
+ Convenience function for a recursive get, preserving times.
+
+ @param remote_path: path to retrieve from server
+ @type remote_path: str
+ @param local_path: path in which to recieve files. default cwd
+ @type local_path: str
+ """
+ self.get(remote_path, local_path, recursive = True, preserve_times = True)
+
+ def _read_stats(self, name):
+ """return just the file stats needed for scp"""
+ stats = os.stat(name)
+ mode = oct(stats.st_mode)[-4:]
+ size = stats.st_size
+ atime = int(stats.st_atime)
+ mtime = int(stats.st_mtime)
+ return (mode, size, mtime, atime)
+
+ def _send_files(self, files):
+ for name in files:
+ basename = os.path.basename(name)
+ (mode, size, mtime, atime) = self._read_stats(name)
+ if self.preserve_times:
+ self._send_time(mtime, atime)
+ file_hdl = file(name, 'rb')
+ self.channel.sendall('C%s %d %s\n' % (mode, size, basename))
+ self._recv_confirm()
+ file_pos = 0
+ buff_size = self.buff_size
+ chan = self.channel
+ while file_pos < size:
+ chan.sendall(file_hdl.read(buff_size))
+ file_pos = file_hdl.tell()
+ if self.callback:
+ self.callback(file_pos, size)
+ chan.sendall('\x00')
+ file_hdl.close()
+
+ def _send_recursive(self, files):
+ for base in files:
+ lastdir = base
+ for root, dirs, fls in os.walk(base):
+ # pop back out to the next dir in the walk
+ while lastdir != os.path.commonprefix([lastdir, root]):
+ self._send_popd()
+ lastdir = os.path.split(lastdir)[0]
+ self._send_pushd(root)
+ lastdir = root
+ self._send_files([os.path.join(root, f) for f in fls])
+
+ def _send_pushd(self, directory):
+ (mode, size, mtime, atime) = self._read_stats(directory)
+ basename = os.path.basename(directory)
+ if self.preserve_times:
+ self._send_time(mtime, atime)
+ self.channel.sendall('D%s 0 %s\n' % (mode, basename))
+ self._recv_confirm()
+
+ def _send_popd(self):
+ self.channel.sendall('E\n')
+ self._recv_confirm()
+
+ def _send_time(self, mtime, atime):
+ self.channel.sendall('T%d 0 %d 0\n' % (mtime, atime))
+ self._recv_confirm()
+
+ def _recv_confirm(self):
+ # read scp response
+ msg = ''
+ try:
+ msg = self.channel.recv(512)
+ except SocketTimeout:
+ raise SCPException('Timout waiting for scp response')
+ if msg and msg[0] == '\x00':
+ return
+ elif msg and msg[0] == '\x01':
+ raise SCPException(msg[1:])
+ elif self.channel.recv_stderr_ready():
+ msg = self.channel.recv_stderr(512)
+ raise SCPException(msg)
+ elif not msg:
+ raise SCPException('No response from server')
+ else:
+ raise SCPException('Invalid response from server: ' + msg)
+
+ def _recv_all(self):
+ # loop over scp commands, and recive as necessary
+ command = {'C': self._recv_file,
+ 'T': self._set_time,
+ 'D': self._recv_pushd,
+ 'E': self._recv_popd}
+ while not self.channel.closed:
+ # wait for command as long as we're open
+ self.channel.sendall('\x00')
+ msg = self.channel.recv(1024)
+ if not msg: # chan closed while recving
+ break
+ code = msg[0]
+ try:
+ command[code](msg[1:])
+ except KeyError:
+ raise SCPException(repr(msg))
+ # directory times can't be set until we're done writing files
+ self._set_dirtimes()
+
+ def _set_time(self, cmd):
+ try:
+ times = cmd.split()
+ mtime = int(times[0])
+ atime = int(times[2]) or mtime
+ except:
+ self.channel.send('\x01')
+ raise SCPException('Bad time format')
+ # save for later
+ self._utime = (mtime, atime)
+
+ def _recv_file(self, cmd):
+ chan = self.channel
+ parts = cmd.split()
+ try:
+ mode = int(parts[0], 8)
+ size = int(parts[1])
+ path = os.path.join(self._recv_dir, parts[2])
+ except:
+ chan.send('\x01')
+ chan.close()
+ raise SCPException('Bad file format')
+
+ try:
+ file_hdl = file(path, 'wb')
+ except IOError, e:
+ chan.send('\x01'+e.message)
+ chan.close()
+ raise
+
+ buff_size = self.buff_size
+ pos = 0
+ chan.send('\x00')
+ try:
+ while pos < size:
+ # we have to make sure we don't read the final byte
+ if size - pos <= buff_size:
+ buff_size = size - pos
+ file_hdl.write(chan.recv(buff_size))
+ pos = file_hdl.tell()
+ if self.callback:
+ self.callback(pos, size)
+
+ msg = chan.recv(512)
+ if msg and msg[0] != '\x00':
+ raise SCPException(msg[1:])
+ except SocketTimeout:
+ chan.close()
+ raise SCPException('Error receiving, socket.timeout')
+
+ file_hdl.truncate()
+ try:
+ os.utime(path, self._utime)
+ self._utime = None
+ os.chmod(path, mode)
+ # should we notify the other end?
+ finally:
+ file_hdl.close()
+ # '\x00' confirmation sent in _recv_all
+
+ def _recv_pushd(self, cmd):
+ parts = cmd.split()
+ try:
+ mode = int(parts[0], 8)
+ path = os.path.join(self._recv_dir, parts[2])
+ except:
+ self.channel.send('\x01')
+ raise SCPException('Bad directory format')
+ try:
+ if not os.path.exists(path):
+ os.mkdir(path, mode)
+ elif os.path.isdir(path):
+ os.chmod(path, mode)
+ else:
+ raise SCPException('%s: Not a directory' % path)
+ self._dirtimes[path] = (self._utime)
+ self._utime = None
+ self._recv_dir = path
+ except (OSError, SCPException), e:
+ self.channel.send('\x01'+e.message)
+ raise
+
+ def _recv_popd(self, *cmd):
+ self._recv_dir = os.path.split(self._recv_dir)[0]
+
+ def _set_dirtimes(self):
+ try:
+ for d in self._dirtimes:
+ os.utime(d, self._dirtimes[d])
+ finally:
+ self._dirtimes = {}
+
+
+class SCPException(Exception):
+ """SCP exception class"""
+ pass
--- /dev/null
+#!/usr/bin/env python
+
+import paramiko
+from scp import SCPClient
+import time
+
+yumOpt = "sudo -S yum -y --nogpgcheck "
+
+# Functions used for the php module (you need to install an http server)
+def setPHP(ssh):
+ execute(yumOpt+" install php", ssh)
+ execute("sudo -S /sbin/service httpd restart", ssh)
+
+def removePHP(ssh):
+ execute(yumOpt+" remove php", ssh)
+
+# Functions used for the X redirection using ssh
+def setXRedirect(ssh):
+ # Installing X11 system and an alternate ssh server
+ execute(yumOpt+" install xorg-x11-xauth", ssh)
+ #time.sleep(10)
+
+def removeXRedirect(ssh):
+ # Remove X11 system and the alternate ssh server
+ execute(yumOpt+" remove xorg-x11-xauth", ssh)
+
+
+# Functions used for an http server
+def setHttpd(ssh, port, hostUrl):
+ port = int(port)
+ execute(yumOpt+" install -y httpd", ssh)
+ SCPClient(ssh.get_transport()).put("./configService/httpd.conf", "~")
+ SCPClient(ssh.get_transport()).put("./configService/index.html", "~")
+ execute("sudo -S mv ~/index.html /var/www/html/", ssh)
+ execute("sudo -S echo \"<html>You are on "+str(hostUrl)+"</html>\" >> /var/www/html/index.html", ssh)
+ execute("sudo -S dd if=/dev/zero of=/var/www/html/file1Mo bs=1M count=1", ssh)
+ execute("sudo -S chmod a+r /var/www/html/file1Mo", ssh)
+ execute("sudo -S mv ~/httpd.conf /etc/httpd/conf/", ssh, display = True)
+ execute("sudo -S chown root:root /etc/httpd/conf/httpd.conf", ssh, display = True)
+ execute("sudo -S sed -i -e \"s/Listen \\*:80/Listen \\*:"+str(port)+"/g\" /etc/httpd/conf/httpd.conf", ssh)
+ returnCode = -1
+ while(returnCode != 0):
+ time.sleep(2)
+ returnCode = execute("sudo -S /sbin/service httpd restart", ssh, display = True)
+ print returnCode
+ if returnCode != 0:
+ execute("sudo -S sed -i -e \"s/Listen \\*:"+str(port)+"/Listen \\*:"+str(port+1)+"/g\" /etc/httpd/conf/httpd.conf", ssh)
+ port += 1
+ return port
+
+def removeHttpd(ssh):
+ #Remove the httpd service
+ execute(yumOpt+" remove httpd", ssh)
+ execute("sudo -S rm -rf /etc/httpd/*", ssh)
+
+
+# Functions used for wireshark traffic analyzer (you have to install X redirection)
+def setWireshark(ssh):
+ # Install wireshark
+ execute(yumOpt+" install wireshark wireshark-gnome", ssh)
+ execute(yumOpt+" install wireshark xorg-x11-fonts-Type1", ssh)
+
+def removeWireshark(ssh):
+ # Remove wireshark
+ execute(yumOpt+" remove wireshark wireshark-gnome", ssh)
+ execute(yumOpt+" remove wireshark xorg-x11-fonts-Type1", ssh)
+
+# Functions used for the browser firefox (you have to install X redirection)
+def setFirefox(ssh):
+ # Install firefox
+ execute(yumOpt+" install firefox", ssh)
+ execute("sudo -S sh -c \"dbus-uuidgen > /var/lib/dbus/machine-id\"", ssh)
+
+def removeFirefox(ssh):
+ # Remove firefox
+ execute(yumOpt+" remove firefox", ssh)
+
+
+# Function used to execute a command on a remote host using ssh
+def execute(command, ssh, display=False, retour=False):
+ print "# "+command
+ stdin, stdout, stderr = ssh.exec_command(command)
+ stdin.close()
+ # Wait for the end of the command
+ while not stdout.channel.exit_status_ready():
+ time.sleep(2)
+ err = stderr.read()
+ if err != None:
+ splitted = err.splitlines()
+ if len(splitted) > 0:
+ print "\tError in execution"
+ for line in splitted:
+ print "\t > " + line
+ if display:
+ for line in stdout.read().splitlines():
+ print " > " + line
+ elif retour:
+ return stdout.read()
+ return stdout.channel.recv_exit_status()
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <id>1</id>
+ <url>Host1</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.1/24</ip>
+ </interface>
+ </host>
+ <host>
+ <id>2</id>
+ <url>Host2</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.2/24</ip>
+ </interface>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>upmc_tp</slice_name>
+ <host>
+ <id>1</id>
+ <url>ple2.ipv6.lip6.fr</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.2/24</ip>
+ </interface>a
+ <routes>
+ <route>
+ <subnet>10.1.2.0/24</subnet>
+ <gateway>10.1.1.1</gateway>
+ <device>tap1</device>
+ </route>
+ </routes>
+ </host>
+ <host>
+ <id>2</id>
+ <url>ple3.ipv6.lip6.fr</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.1/24</ip>
+ </interface>
+ <interface>
+ <bridge_name>tap2</bridge_name>
+ <ip>10.1.2.1/24</ip>
+ </interface>
+ </host>
+ <host>
+ <id>3</id>
+ <url>ple4.ipv6.lip6.fr</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.2.2/24</ip>
+ </interface>
+ <routes>
+ <route>
+ <subnet>10.1.1.0/24</subnet>
+ <gateway>10.1.2.1</gateway>
+ <device>tap1</device>
+ </route>
+ </routes>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>upmc_tp</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>upmc_tp</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+ <link>
+ <host1>
+ <slice>upmc_tp</slice>
+ <id>2</id>
+ <bridge_name>tap2</bridge_name>
+ </host1>
+ <host2>
+ <slice>upmc_tp</slice>
+ <id>3</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>upmc_tp</slice_name>
+ <host>
+ <id>1</id>
+ <url>ple2.ipv6.lip6.fr</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.1/24</ip>
+ </interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ <host>
+ <id>2</id>
+ <url>ple3.ipv6.lip6.fr</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.2/24</ip>
+ </interface>
+ <services>
+ <service>x11:2222</service>
+ <service>firefox</service>
+ <service>wireshark</service>
+ </services>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>upmc_tp</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>upmc_tp</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>upmc_tp</slice_name>
+ <host>
+ <id>1</id>
+ <url>ple4.ipv6.lip6.fr</url>
+ <interface>
+ <bridge_name>tap2</bridge_name>
+ <ip>10.1.3.3/24</ip>
+ </interface>
+ </host>
+ <host>
+ <id>2</id>
+ <url>ple3.ipv6.lip6.fr</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.3.2/24</ip>
+ </interface>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>upmc_tp</slice>
+ <id>1</id>
+ <bridge_name>tap2</bridge_name>
+ </host1>
+ <host2>
+ <slice>upmc_tp</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <id>1</id>
+ <url>host1</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.2/24</ip>
+ </interface>
+ <routes>
+ <route>
+ <subnet>10.1.2.0/24</subnet>
+ <gateway>10.1.1.1</gateway>
+ <device>tap1</device>
+ </route>
+ </routes>
+ </host>
+ <host>
+ <id>2</id>
+ <url>host2</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.1/24</ip>
+ </interface>
+ <interface>
+ <bridge_name>tap2</bridge_name>
+ <ip>10.1.2.1/24</ip>
+ </interface>
+ </host>
+ <host>
+ <id>3</id>
+ <url>host3</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.2.2/24</ip>
+ </interface>
+ <routes>
+ <route>
+ <subnet>10.1.1.0/24</subnet>
+ <gateway>10.1.2.1</gateway>
+ <device>tap1</device>
+ </route>
+ </routes>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>2</id>
+ <bridge_name>tap2</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>3</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <type>private</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>1</id>
+ <url>host1</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.8.N/24</ip>
+ </interface>
+ <services>
+ <service>x11</service>
+ <service>firefox</service>
+ <service>wireshark</service>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>2</id>
+ <url>host2</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.8.100/24</ip>
+ </interface>
+ <services>
+ <service>httpd:8085</service>
+ </services>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <type>private</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>1</id>
+ <url>host1</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.8.N/24</ip>
+ </interface>
+ <services>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>2</id>
+ <url>host2</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.8.100/24</ip>
+ </interface>
+ <services>
+ </services>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <type>common</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>1</id>
+ <url>host1</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.8.N/24</ip>
+ </interface>
+ <services>
+ <service>x11</service>
+ <service>firefox</service>
+ <service>wireshark</service>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>2</id>
+ <url>host2</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.8.100/24</ip>
+ </interface>
+ <services>
+ <service>httpd:8085</service>
+ </services>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <type>private</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>1</id>
+ <url>host1</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.N/24</ip>
+ </interface>
+ <services>
+ <service>x11</service>
+ <service>firefox</service>
+ <service>wireshark</service>
+ </services>
+ </host>
+ <host>
+ <type>public</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>2</id>
+ <url>host2</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.102/24</ip>
+ </interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Italy</country>
+ <distances>
+ <min>1000</min>
+ <max>1500</max>
+ </distances>
+ <id>3</id>
+ <url>host3</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.100/24</ip>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </interface>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Spain</country>
+ <distances>
+ <min>10000</min>
+ <max>30000</max>
+ </distances>
+ <id>4</id>
+ <url>host4</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.101/24</ip>
+ </interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <type>private</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>1</id>
+ <url>host1</url>
+ <services>
+ <service>httpd:8080</service>
+ <service>php</service>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>2</id>
+ <url>host2</url>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Italy</country>
+ <distances>
+ <min>1000</min>
+ <max>1500</max>
+ </distances>
+ <id>3</id>
+ <url>host3</url>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Spain</country>
+ <distances>
+ <min>10000</min>
+ <max>30000</max>
+ </distances>
+ <id>4</id>
+ <url>host4</url>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <type>private</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>1</id>
+ <url>host1</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.N/24</ip>
+ </interface>
+ <services>
+ <service>x11</service>
+ <service>firefox</service>
+ <service>wireshark</service>
+ </services>
+ </host>
+ <host>
+ <type>public</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>2</id>
+ <url>host2</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.102/24</ip>
+ </interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Italy</country>
+ <distances>
+ <min>1000</min>
+ <max>1500</max>
+ </distances>
+ <id>3</id>
+ <url>host3</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.100/24</ip>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </interface>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Spain</country>
+ <distances>
+ <min>1500</min>
+ <max>90000</max>
+ </distances>
+ <id>4</id>
+ <url>host4</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.101/24</ip>
+ </interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <type>private</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>1</id>
+ <url>host1</url>
+ <interface>
+ </interface>
+ <services>
+ </services>
+ </host>
+ <host>
+ <type>public</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>2</id>
+ <url>host2</url>
+ <interface>
+ </interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Italy</country>
+ <distances>
+ <min>1000</min>
+ <max>1500</max>
+ </distances>
+ <id>3</id>
+ <url>host3</url>
+ <interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </interface>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Spain</country>
+ <distances>
+ <min>10000</min>
+ <max>30000</max>
+ </distances>
+ <id>4</id>
+ <url>host4</url>
+ <interface>
+ </interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>SliceName</slice_name>
+ <host>
+ <type>private</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>1</id>
+ <url>host1</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.N/24</ip>
+ </interface>
+ <services>
+ </services>
+ </host>
+ <host>
+ <type>public</type>
+ <country>France</country>
+ <distances>
+ <min>0</min>
+ <max>0</max>
+ </distances>
+ <id>2</id>
+ <url>host2</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.102/24</ip>
+ </interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Italy</country>
+ <distances>
+ <min>1000</min>
+ <max>1500</max>
+ </distances>
+ <id>3</id>
+ <url>host3</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.100/24</ip>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </interface>
+ </host>
+ <host>
+ <type>common</type>
+ <country>Spain</country>
+ <distances>
+ <min>10000</min>
+ <max>30000</max>
+ </distances>
+ <id>4</id>
+ <url>host4</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.1.101/24</ip>
+ </interface>
+ <services>
+ <service>httpd:8080</service>
+ </services>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>3</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>4</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+ <link>
+ <host1>
+ <slice>SliceName</slice>
+ <id>1</id>
+ <bridge_name>tap1</bridge_name>
+ </host1>
+ <host2>
+ <slice>SliceName</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+<links>
+</links>
--- /dev/null
+<conf>
+ <slice>
+ <slice_name>upmc_tp</slice_name>
+ <host>
+ <id>1</id>
+ <url>ple2.ipv6.lip6.fr</url>
+ <interface>
+ <bridge_name>tap2</bridge_name>
+ <ip>10.1.3.1/24</ip>
+ </interface>
+ </host>
+ <host>
+ <id>2</id>
+ <url>ple1.cesnet.cz</url>
+ <interface>
+ <bridge_name>tap1</bridge_name>
+ <ip>10.1.3.2/24</ip>
+ </interface>
+ </host>
+ </slice>
+</conf>
--- /dev/null
+<links>
+ <link>
+ <host1>
+ <slice>upmc_tp</slice>
+ <id>1</id>
+ <bridge_name>tap2</bridge_name>
+ </host1>
+ <host2>
+ <slice>upmc_tp</slice>
+ <id>2</id>
+ <bridge_name>tap1</bridge_name>
+ </host2>
+ </link>
+</links>
--- /dev/null
+# -*- coding:utf-8 -*-
+from django.core.files import File
+from celery import task, current_task
+from djcelery.models import TaskState
+from xmlrpclib import Fault
+
+from forge.models import *
+
+import forge.script.Auth as Auth
+import time
+
+# Import class used to create the environment
+from forge.script.request import TransformRawXml
+from forge.script.openvswitch import TransformXml
+
+# Import the settings
+from django.conf import settings
+
+@task()
+def taskInstallEnvironment(env):
+ env.ready = False
+ env.save()
+ #TODO Change directory location
+ curDir = os.getcwd()
+ os.chdir('./ict_education/script/')
+ try:
+ xml = TransformXml(confFile = curDir+env.confFile.url, linkFile = curDir+env.linkFile.url, keyFile = curDir+env.course.mainKey.url)
+ xml.clearConf()
+ xml.setSliceConf()
+ xml.setLinks()
+ xml.setRoutes()
+ xml.setServices()
+ except Exception, why:
+ print why
+ os.chdir(curDir)
+ env.ready = True
+ env.save()
+
+@task()
+def taskDeleteCourse(course):
+ environments = course.environment_set.all()
+ #TODO Change directory location
+ curDir = os.getcwd()
+ os.chdir('./ict_education/script/')
+ for env in environments:
+ try:
+ xml = TransformXml(confFile = curDir+env.confFile.url, linkFile = curDir+env.linkFile.url, keyFile = curDir+env.course.mainKey.url)
+ xml.clearConf()
+ except Exception, why:
+ print why
+ try:
+ rawXml = TransformRawXml(sliceName=course.sliceName)
+ rawXml.deleteSlice()
+ except Fault, why:
+ print "I got an xmlrpc Fault"
+ print why
+ os.chdir(curDir)
+ course.delete()
+
+@task()
+def taskRenewSlice(course):
+ rawXml = TransformRawXml(sliceName=course.sliceName)
+ rawXml.renewSlice()
+
+@task()
+def taskCreateCourse(form):
+ newCourse = Course()
+ newCourse.lab = Lab.objects.get(id=form.cleaned_data['lab'].id)
+ newCourse.ready = False
+ newCourse.sliceName = form.cleaned_data['sliceName']
+ newCourse.save()
+ #TODO Change directory location
+ curDir = os.getcwd()
+ os.chdir('./ict_education/script/')
+ if form.cleaned_data['keyLocation'] == '':
+ keyLocation = None
+ else:
+ keyLocation = form.cleaned_data['keyLocation']
+ if form.cleaned_data['url'] == '':
+ sliceUrl = 'http://onelab.eu'
+ else:
+ sliceUrl = form.cleaned_data['url']
+ if form.cleaned_data['description'] == '':
+ sliceDescription = 'Slice used for educational purpose'
+ else:
+ sliceDescription = form.cleaned_data['url']
+ try:
+ rawXml = TransformRawXml(confFile = settings.MEDIA_ROOT+newCourse.lab.configurationFile.name, linkFile = settings.MEDIA_ROOT+newCourse.lab.linkFile.name, subnet = form.cleaned_data['subnet'], sliceName = form.cleaned_data['sliceName'], nbEnv = form.cleaned_data['nbEnv'], sliceUrl = sliceUrl, sliceDescription = sliceDescription, mainKeyPriv = keyLocation)
+ rawXml.setSlice()
+ newCourse.mainKey.save(rawXml.mainKeyPriv.split('/')[-1], File(open(rawXml.mainKeyPriv)))
+ newCourse.save()
+ i = 0
+ for environment in rawXml.envList:
+ newEnv = Environment()
+ newEnv.ready = False
+ newEnv.course = newCourse
+ newEnv.sshKey.save(rawXml.envKeyPriv[i].split('/')[-1], File(open(rawXml.envKeyPriv[i])))
+ newEnv.confFile.save(rawXml.envConfFile[i].split('/')[-1], File(open(rawXml.envConfFile[i])))
+ newEnv.linkFile.save(rawXml.envLinkFile[i].split('/')[-1], File(open(rawXml.envLinkFile[i])))
+ newEnv.save()
+ i += 1
+ for plSlice in environment:
+ newSlice = Slice()
+ newSlice.sliceName = plSlice.slice_name
+ newSlice.environment = newEnv
+ newSlice.save()
+ for host in plSlice.hosts:
+ newHost = Host()
+ nodeSelected = ''
+ for env in rawXml.nodeList:
+ for node in env:
+ if node['hostname'] == host.url:
+ nodeselected = node
+ break
+ if nodeSelected != '':
+ break
+ newHost.hostname = host.url
+ newHost.pleSlice = newSlice
+ newHost.latitude = nodeSelected['latitude']
+ newHost.longitude = nodeSelected['longitude']
+ newHost.save()
+ for serviceName, port in host.services.services:
+ newService = Service()
+ newService.serviceName = serviceName
+ newService.servicePort = str(port)
+ newService.host = newHost
+ newService.save()
+ for device in host.devices:
+ newInterface = Interface()
+ newInterface.ip = device.ip
+ newInterface.name = device.id_dev
+ newInterface.host = newHost
+ newInterface.save()
+ newEnv.ready = True
+ newEnv.save()
+ os.chdir(curDir)
+ newCourse.ready = True
+ newCourse.save()
+ except Exception, why:
+ print "An error occured deleting the environment"
+ print why
+ rawXml = TransformRawXml(sliceName=newCourse.sliceName)
+ rawXml.deleteSlice()
+ raise Exception('Global Fault')
+ return 0
--- /dev/null
+<div class="col-md-2">
+</div>
+<div class="col-md-8">
+ <form action="." method="post" enctype="multipart/form-data">
+ {{ form.as_p }}
+ <p><input type="submit" value="Create Class" /></p>
+ </form>
+</div>
+<div class="col-md-2">
+</div>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Create a new Class</title>
+ </head>
+ <body>
+ <form action="{% url "ict_education.views.createCourse" %}" method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ {{ form.as_p }}
+ <p><input type="submit" value="Create Class" /></p>
+ </form>
+ </body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Create a new Lab</title>
+ </head>
+ <body>
+ <!-- List of existing labs -->
+ {% if labs %}
+ <ul>
+ {% for lab in labs %}
+ <li>{{ lab }}
+ <a href="/ict_education/lab-details/{{ lab.id }}">Lab details</a>
+ <a href="/ict_education/delete-lab/{{ lab.id }}">Delete Lab</a>
+ </li>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p>No lab</p>
+ {% endif %}
+
+ <!-- Upload form. Note enctype attribute! -->
+ <form action="{% url "ict_education.views.createLab" %}" method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ {{ form.as_p }}
+ <p><input type="submit" value="Add Lab" /></p>
+ </form>
+ </body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Details of lab {{ lab.title }}</title>
+ </head>
+ <body>
+ <h1>{{ lab.title }}</h1>
+ <h2>{{ lab.author }}</h2>
+ <p><a href="{{ lab.subject.url }}">Subject</a></p>
+ <p><a href="{{ lab.configurationFile.url }}">Configuration File</a><p>
+ <p><a href="{{ lab.linkFile.url }}">{{ lab.linkFile.name }}</a></p>
+ </body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Minimal Django File Upload Example</title>
+ </head>
+ <body>
+ <!-- List of uploaded documents -->
+ {% if documents %}
+ <ul>
+ {% for document in documents %}
+ <li><a href="{{ document.docfile.url }}">{{ document.docfile.name }}</a></li>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p>No documents.</p>
+ {% endif %}
+
+ <!-- Upload form. Note enctype attribute! -->
+ <form action="{% url "ict_education.views.list" %}" method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ <p>{{ form.non_field_errors }}</p>
+ <p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
+ <p>
+ {{ form.docfile.errors }}
+ {{ form.docfile }}
+ </p>
+ <p><input type="submit" value="Upload" /></p>
+ </form>
+ </body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>List of all your class</title>
+ </head>
+ <body>
+ {% if courses %}
+ <ul>
+ {% for course, environments in courses %}
+
+ {% if course.ready %}
+ <ul>
+ <li><a href=" {{ course.mainKey.url }}">Main SSH Key</a></li>
+ {# <li>{{ course.id }}</li> #}
+ <li><a href=" {{ course.lab.subject.url }}">Subject</a></li>
+ <li><a href="/ict_education/delete-course/{{ course.id }}">Delete Course</a></li>
+ <li><a href="/ict_education/renew-slice/{{ course.id }}">Renew-Slice</a></li>
+ <ul>
+ {% for environment, slices in environments %}
+ {% if environment.ready %}
+ <li>Environment <a href="/ict_education/install-env/{{ environment.id }}">Re-install environment</a></li>
+ <li><a href=" {{ environment.sshKey.url }}">SSH Key</a></li>
+ <ul>
+ {% for pleSlice, hosts in slices %}
+ <li>{{ pleSlice.sliceName }}</li>
+ <ul>
+ {% for host, services, interfaces in hosts %}
+ <li>Hostname : {{ host.hostname }} Type : {{ host.hostType }}</li>
+ <ul>
+ {% if services %}
+ <li>Service List :</li>
+ <ul>
+ {% for service in services %}
+ {% if service.servicePort == '' %}
+ <li>{{ service.serviceName }}</li>
+ {% else %}
+ <li>{{ service.serviceName }} on {{ service.servicePort }}</li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% endif %}
+ {% if interfaces %}
+ <li>Interface List :</li>
+ <ul>
+ {% for interface in interfaces %}
+ <li>{{ interface.name }} : {{ interface.ip }}</li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+ </ul>
+ {% endfor %}
+ </ul>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <ul>Now installing this environment</ul>
+ <li>Environment <a href="/ict_education/install-env/{{ environment.id }}">Re-install environment</a></li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% else %}
+ <li>Course not ready</li>
+ <li>{{ course.ready }}</li>
+ {% endif %}
+ </ul>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p>You have not created a class yet</p>
+ {% endif %}
+ </body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>ICT Education</title>
+ </head>
+ <body>
+ <!-- List of available action -->
+ <p><a href="create-lab">Create a new lab</a></p>
+ <p><a href="create-class">Create a new course</a></p>
+ <p><a href="list-course">List of your course</a></p>
+
+ </body>
+</html
--- /dev/null
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.assertEqual(1 + 1, 2)
--- /dev/null
+# -*- coding:utf-8 -*-
+# Create your views here.
+
+# Several import from the django facilities
+from django.template import RequestContext
+from django.shortcuts import render, get_object_or_404, render_to_response, redirect
+from django.template import RequestContext
+from django.core.urlresolvers import reverse
+from django.core.files import File
+
+# Import of the forms and models
+from forge.models import *
+from forge.forms import *
+
+# Import of the task and TaskState (used to link task in the database)
+from forge.tasks import *
+from djcelery.models import TaskState
+
+# Import the settings
+from django.conf import settings
+
+import os
+
+# Import class used to create the environment
+from forge.script.request import TransformRawXml
+
+from myslice.theme import ThemeView
+from unfold.loginrequired import FreeAccessView
+
+class CreateCourseViev (FreeAccessView, ThemeView):
+ template_name = 'create-course.html'
+
+ def get (self, request, slicename, state=None):
+ username = self.request.user
+ split_slicename = slicename.split('.')
+ ple_slicename = split_slicename[0] + '8' + split_slicename[1] + '_' + split_slicename[2]
+ if not Course.objects.get(sliceName = ple_slicename).exists():
+ if request.method == 'POST':
+ form = courseForm(request.POST)
+ if form.is_valid():
+ result = taskCreateCourse.delay(form)
+ else:
+ labs = Lab.objects.all()
+ form = courseForm()
+ return render_to_response(self.template, { 'theme' : self.theme,'slicename':slicename, 'ple_slicename':ple_slicename, 'username':username, 'form': form }, context_instance=RequestContext(request))
+
+def mainView(request):
+ return render(request, 'mainView.html', locals())
+
+
+def createLab(request):
+ if request.method == 'POST':
+ form = LabForm(request.POST, request.FILES)
+ if form.is_valid():
+ newLab = Lab(
+ title = form['title'].value(),
+ author = form['author'].value(),
+ subject = request.FILES['subject'],
+ configurationFile = request.FILES['configurationFile'],
+ linkFile = request.FILES['linkFile'],
+ )
+ newLab.save()
+ else:
+ form = LabForm()
+ labs = Lab.objects.all()
+ return render_to_response('createLab.html', {'labs': labs, 'form':form}, context_instance=RequestContext(request))
+
+def labDetails(request, id):
+ try:
+ lab = Lab.objects.get(id=id)
+ except Lab.DoesNotExist:
+ raise Http404
+ return render(request, 'labDetails.html', locals())
+
+def deleteLab(request, id):
+ try:
+ lab = Lab.objects.get(id=id)
+ except Lab.DoesNotExist:
+ raise Http404
+ lab.delete()
+ return redirect('forge.views.createLab')
+
+def createCourse(request):
+ if request.method == 'POST':
+ form = courseForm(request.POST)
+ if form.is_valid():
+ result = taskCreateCourse.delay(form)
+ else:
+ labs = Lab.objects.all()
+ form = courseForm()
+ return render(request, 'createCourse.html', locals())
+
+def installEnvironment(request, id):
+ task = taskInstallEnvironment.delay(Environment.objects.get(id=id))
+ return redirect('forge.views.listCourse')
+
+def renewSlice(request, id):
+ task = taskRenewSlice.delay(Course.objects.get(id=id))
+ return redirect('forge.views.listCourse')
+
+def deleteCourse(request, id):
+ task = taskDeleteCourse.delay(Course.objects.get(id=id))
+ return redirect('forge.views.listCourse')
+
+def listCourse(request):
+ courses = Course.objects.all()
+ environments = Environment.objects.all()
+ slices = Slice.objects.all()
+ hosts = Host.objects.all()
+ services = Service.objects.all()
+ renderCourses = []
+ for course in courses:
+ renderEnvironment = []
+ if course.ready:
+ for environment in course.environment_set.all():
+ renderSlice = []
+ for pleSlice in environment.slice_set.all():
+ renderHost = []
+ for host in pleSlice.host_set.all():
+ renderService = []
+ for service in host.service_set.all():
+ renderService.append(service)
+ renderInterface = []
+ for interface in host.interface_set.all():
+ renderInterface.append(interface)
+ renderHost.append([host, renderService, renderInterface])
+ renderSlice.append([pleSlice, renderHost])
+ renderEnvironment.append([environment, renderSlice])
+ renderCourses.append([course, renderEnvironment])
+
+
+ return render(request, 'listCourse.html', {'courses': renderCourses})