diff options
author | Jack Morgan <jack.morgan@intel.com> | 2018-01-09 00:12:25 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@opnfv.org> | 2018-01-09 00:12:25 +0000 |
commit | 37fa445afe6d63d44a3a52c2a89e4e21ae67b5a6 (patch) | |
tree | a053095a7347ca30245081b3fc44d5f6b7f645d7 /laas-fog/source/api | |
parent | 0700062b04ad49431fbebcfd7c44d4013d654bfe (diff) | |
parent | 30f389c70e8a0a8bd2ef27be09839eef243ab7f5 (diff) |
Merge "Initial Commit for new LaaS Software"
Diffstat (limited to 'laas-fog/source/api')
-rw-r--r-- | laas-fog/source/api/__init__.py | 17 | ||||
-rw-r--r-- | laas-fog/source/api/fog.py | 288 | ||||
-rw-r--r-- | laas-fog/source/api/fuel_api.py | 306 | ||||
-rw-r--r-- | laas-fog/source/api/libvirt_api.py | 331 | ||||
-rw-r--r-- | laas-fog/source/api/vpn.py | 235 |
5 files changed, 0 insertions, 1177 deletions
diff --git a/laas-fog/source/api/__init__.py b/laas-fog/source/api/__init__.py deleted file mode 100644 index 7bb515b..0000000 --- a/laas-fog/source/api/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -############################################################################# -#Copyright 2017 Parker Berberian and others # -# # -#Licensed under the Apache License, Version 2.0 (the "License"); # -#you may not use this file except in compliance with the License. # -#You may obtain a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -#Unless required by applicable law or agreed to in writing, software # -#distributed under the License is distributed on an "AS IS" BASIS, # -#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -#See the License for the specific language governing permissions and # -#limitations under the License. # -############################################################################# -""" diff --git a/laas-fog/source/api/fog.py b/laas-fog/source/api/fog.py deleted file mode 100644 index 6287403..0000000 --- a/laas-fog/source/api/fog.py +++ /dev/null @@ -1,288 +0,0 @@ -""" -############################################################################# -#Copyright 2017 Parker Berberian and others # -# # -#Licensed under the Apache License, Version 2.0 (the "License"); # -#you may not use this file except in compliance with the License. # -#You may obtain a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -#Unless required by applicable law or agreed to in writing, software # -#distributed under the License is distributed on an "AS IS" BASIS, # -#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -#See the License for the specific language governing permissions and # -#limitations under the License. # -############################################################################# -""" - -import requests -import sys -import time - - -class FOG_Handler: - """ - This class talks with the REST web api for the FOG server. - - TODO: convert prints to logs and remove uneeded pass's - """ - - def __init__(self, baseURL, fogKey=None, userKey=None): - """ - init function - baseURL should be http://fog.ip.or.hostname/fog/ - fogKey and userKey can optionally be supplied here or later - They can be found in fog and provide authentication. - """ - self.baseURL = baseURL - self.fogKey = fogKey - self.userKey = userKey - self.header = {} - self.updateHeader() - - def setLogger(self, logger): - """ - saves the refference to the log object as - self.log - """ - self.log = logger - - def getUserKeyFromFile(self, path): - """ - reads the user api key from a file - """ - self.userKey = open(path).read() - self.updateHeader() - - def getFogKeyFromFile(self, path): - """ - reads the api key from a file - """ - self.fogKey = open(path).read() - self.updateHeader() - - def setUserKey(self, key): - """ - sets the user key - """ - self.userKey = key - self.updateHeader() - - def setFogKey(self, key): - """ - sets the fog key - """ - self.fogKey = key - self.updateHeader() - - def updateHeader(self): - """ - recreates the http header used to talk to the fog api - """ - self.header = {} - self.header['fog-api-token'] = self.fogKey - self.header['fog-user-token'] = self.userKey - - def setImage(self, host, imgNum): - """ - Sets the image to be used during ghosting to the image - with id imgNum. host can either be a hostname or number. - """ - try: - host = int(host) - except: - host = self.getHostNumber(host) - url = self.baseURL+"host/"+str(host) - host_conf = requests.get(url, headers=self.header).json() - host_conf['imageID'] = str(imgNum) - requests.put(url+"/edit", headers=self.header, json=host_conf) - - def delTask(self, hostNum): - """ - Tries to delete an existing task for the host - with hostNum as a host number - """ - try: - url = self.baseURL+'fog/host/'+str(hostNum)+'/cancel' - req = requests.delete(url, headers=self.header) - if req.status_code == 200: - self.log.info("%s", "successfully deleted image task") - except Exception: - self.log.exception("Failed to delete the imaging task!") - - def getHostMac(self, hostname): - """ - returns the primary mac address if the given host. - """ - try: - hostNum = int(self.getHostNumber(hostname)) - url = self.baseURL + "host/"+str(hostNum) - req = requests.get(url, headers=self.header) - macAddr = req.json()['primac'] - return macAddr - except Exception: - self.log.exception('%s', "Failed to connect to the FOG server") - - def getHostNumber(self, hostname): - """ - returns the host number of given host - """ - try: - req = requests.get(self.baseURL+"host", headers=self.header) - hostData = req.json() - if hostData is not None: - for hostDict in hostData['hosts']: - if hostname == hostDict['name']: - return hostDict['id'] - return -1 - except Exception: - self.log.exception('%s', "Failed to connect to the FOG server") - - def imageHost(self, hostName, recurse=False): - """ - Schedules an imaging task for the given host. - This automatically uses the "associated" disk image. - To support extra installers, I will need to create - a way to change what that image is before calling - this method. - """ - num = str(self.getHostNumber(hostName)) - url = self.baseURL+'host/'+num+'/task' - - try: - req = requests.post( - url, - headers=self.header, - json={"taskTypeID": 1} - ) - if req.status_code == 200: - self.log.info("%s", "Scheduled image task for host") - except Exception: - if recurse: # prevents infinite loop - self.log.exception("%s", "Failed to schedule task. Exiting") - sys.exit(1) - self.log.warning("%s", "Failed to schedule host imaging") - self.log.warning("%s", "Trying to delete existing image task") - self.delTask(num) - self.imageHost(num, recurse=True) - - def waitForHost(self, host): - """ - tracks the imaging task to completion. - """ - while True: - imageTask = self.getImagingTask(host) - if imageTask is None: - self.log.info("%s", "Imaging complete") - return - state = int(imageTask['stateID']) - if state == 1: - self.log.info("%s", "Waiting for host to check in") - self.waitForTaskToActive(host) - continue - if state == 3: - self.waitForTaskToStart(host) - self.waitForImaging(host) - continue - time.sleep(8) - - def waitForImaging(self, host): - """ - Once the host begins being imaged, this tracks progress. - """ - # print "Host has begun the imaging process\n" - while True: - task = self.getImagingTask(host) - if task is None: - return - per = str(task['percent']) - self.log.info("%s percent done imaging", per) - time.sleep(15) - - def waitForTaskToActive(self, host): - """ - Waits for the host to reboot and pxe boot - into FOG - """ - while True: - try: - task = self.getImagingTask(host) - except: - pass - state = int(task['stateID']) - if state == 1: - time.sleep(4) - else: - return - - def waitForTaskToStart(self, host): - """ - waits for the task to start and imaging to begin. - """ - while True: - try: - per = str(self.getImagingTask(host)['percent']) - except: - pass - if per.strip() == '': - time.sleep(1) - else: - return - - def getImagingTask(self, host): - """ - Sorts through all current tasks to find the image task - associated with the given host. - """ - try: - taskList = requests.get( - self.baseURL+'task/current', - headers=self.header) - taskList = taskList.json()['tasks'] - imageTask = None - for task in taskList: - hostname = str(task['host']['name']) - if hostname == host and int(task['typeID']) == 1: - imageTask = task - return imageTask - except Exception: - self.log.exception("%s", "Failed to talk to FOG server") - sys.exit(1) - - def getHosts(self): - """ - returns a list of all hosts - """ - req = requests.get(self.baseURL+"host", headers=self.header) - return req.json()['hosts'] - - def getHostsinGroup(self, groupName): - """ - returns a list of all hosts in groupName - """ - groupID = None - groups = requests.get(self.baseURL+"group", headers=self.header) - groups = groups.json()['groups'] - for group in groups: - if groupName.lower() in group['name'].lower(): - groupID = group['id'] - if groupID is None: - return - hostIDs = [] - associations = requests.get( - self.baseURL+"groupassociation", - headers=self.header - ) - associations = associations.json()['groupassociations'] - for association in associations: - if association['groupID'] == groupID: - hostIDs.append(association['hostID']) - - hosts = [] - for hostID in hostIDs: - hosts.append(requests.get( - self.baseURL+"host/"+str(hostID), - headers=self.header - ).json()) - return hosts diff --git a/laas-fog/source/api/fuel_api.py b/laas-fog/source/api/fuel_api.py deleted file mode 100644 index 0127800..0000000 --- a/laas-fog/source/api/fuel_api.py +++ /dev/null @@ -1,306 +0,0 @@ -""" -############################################################################# -#Copyright 2017 Parker Berberian and others # -# # -#Licensed under the Apache License, Version 2.0 (the "License"); # -#you may not use this file except in compliance with the License. # -#You may obtain a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -#Unless required by applicable law or agreed to in writing, software # -#distributed under the License is distributed on an "AS IS" BASIS, # -#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -#See the License for the specific language governing permissions and # -#limitations under the License. # -############################################################################# -""" - -import requests -import time -import sys - - -class Fuel_api: - - def __init__(self, url, logger, user="admin", password="admin"): - """ - url is the url of the fog api in the form - http://ip.or.host.name:8000/ - logger is a reference to the logger - the default creds for fuel is admin/admin - """ - self.logger = logger - self.base = url - self.user = user - self.password = password - self.header = {"Content-Type": "application/json"} - - def getKey(self): - """ - authenticates with the user and password - to get a keystone key, used in the headers - from here on to talk to fuel. - """ - url = self.base + 'keystone/v2.0/tokens/' - reqData = {"auth": { - "tenantName": self.user, - "passwordCredentials": { - "username": self.user, - "password": self.password - } - }} - self.logger.info("Retreiving keystone token from %s", url) - token = requests.post(url, headers=self.header, json=reqData) - self.logger.info("Received response code %d", token.status_code) - self.token = token.json()['access']['token']['id'] - self.header['X-Auth-Token'] = self.token - - def getNotifications(self): - """ - returns the fuel notifications - """ - url = self.base+'/api/notifications' - try: - req = requests.get(url, headers=self.header) - return req.json() - - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def waitForBootstrap(self): - """ - Waits for the bootstrap image to build. - """ - while True: - time.sleep(30) - notes = self.getNotifications() - for note in notes: - if "bootstrap image building done" in note['message']: - return - - def getNodes(self): - """ - returns a list of all nodes booted into fuel - """ - url = self.base+'api/nodes' - try: - req = requests.get(url, headers=self.header) - return req.json() - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def getID(self, mac): - """ - gets the fuel id of node with given mac - """ - for node in self.getNodes(): - if node['mac'] == mac: - return node['id'] - - def getNetID(self, name, osid): - """ - gets the id of the network with name - """ - url = self.base+'api/clusters/' - url += str(osid)+'/network_configuration/neutron' - try: - req = requests.get(url, headers=self.header) - nets = req.json()['networks'] - for net in nets: - if net['name'] == name: - return net['id'] - return -1 - - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def createOpenstack(self): - """ - defines a new openstack environment in fuel. - """ - url = self.base+'api/clusters' - data = { - "nodes": [], - "tasks": [], - "name": "OpenStack", - "release_id": 2, - "net_segment_type": "vlan" - } - try: - req = requests.post(url, json=data, headers=self.header) - return req.json()['id'] - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def simpleNetDict(self, osID): - """ - returns a simple dict of network names and id numbers - """ - nets = self.getNetworks(osID) - netDict = {} - targetNets = ['admin', 'public', 'storage', 'management'] - for net in nets['networks']: - for tarNet in targetNets: - if tarNet in net['name']: - netDict[tarNet] = net['id'] - return netDict - - def getNetworks(self, osID): - """ - Returns the pythonizezd json of the openstack networks - """ - url = self.base + 'api/clusters/' - url += str(osID)+'/network_configuration/neutron/' - try: - req = requests.get(url, headers=self.header) - return req.json() - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def uploadNetworks(self, netJson, osID): - """ - configures the networks of the openstack - environment with id osID based on netJson - """ - url = self.base+'api/clusters/' - url += str(osID)+'/network_configuration/neutron' - try: - req = requests.put(url, headers=self.header, json=netJson) - return req.json() - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def addNodes(self, clusterID, nodes): - """ - Adds the nodes into this openstack environment. - nodes is valid json - """ - url = self.base + 'api/clusters/'+str(clusterID)+'/assignment' - try: - req = requests.post(url, headers=self.header, json=nodes) - return req.json() - - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def getIfaces(self, nodeID): - """ - returns the pythonized json describing the - interfaces of given node - """ - url = self.base + 'api/nodes/'+str(nodeID)+'/interfaces' - try: - req = requests.get(url, headers=self.header) - return req.json() - - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def setIfaces(self, nodeID, ifaceJson): - """ - configures the interfaces of node with id nodeID - with ifaceJson - ifaceJson is valid json that fits fuel's schema for ifaces - """ - url = self.base+'/api/nodes/'+str(nodeID)+'/interfaces' - try: - req = requests.put(url, headers=self.header, json=ifaceJson) - return req.json() - - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def getTasks(self): - """ - returns a list of all tasks - """ - url = self.base+"/api/tasks/" - try: - req = requests.get(url, headers=self.header) - return req.json() - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def waitForTask(self, uuid): - """ - Tracks the progress of task with uuid and - returns once the task finishes - """ - progress = 0 - while progress < 100: - for task in self.getTasks(): - if task['uuid'] == uuid: - progress = task['progress'] - self.logger.info("Task is %s percent done", str(progress)) - time.sleep(20) - # Task may hang a minute at 100% without finishing - while True: - for task in self.getTasks(): - if task['uuid'] == uuid and not task['status'] == "ready": - time.sleep(10) - elif task['uuid'] == uuid and task['status'] == "ready": - return - - def getHorizonIP(self, osid): - """ - returns the ip address of the horizon dashboard. - Horizon always takes the first ip after the public router's - """ - url = self.base+'api/clusters/' - url += str(osid)+'/network_configuration/neutron/' - try: - req = requests.get(url, headers=self.header) - routerIP = req.json()['vips']['vrouter_pub']['ipaddr'].split('.') - routerIP[-1] = str(int(routerIP[-1])+1) - return '.'.join(routerIP) - except Exception: - self.logger.exception('%s', "Failed to talk to the Fuel api!") - sys.exit(1) - - def deployOpenstack(self, clusterID): - """ - Once openstack and the nodes are configured, - this method actually deploys openstack. - It takes a while. - """ - # First, we need to provision the cluster - url = self.base+'/api/clusters/'+str(clusterID)+'/provision' - req = requests.put(url, headers=self.header) - if req.status_code < 300: - self.logger.info('%s', "Sent provisioning task") - else: - err = "failed to provision Openstack Environment" - self.logger.error('%s', err) - sys.exit(1) - - taskUID = '' - tasks = self.getTasks() - for task in tasks: - if task['name'] == "provision" and task['cluster'] == clusterID: - taskUID = task['uuid'] - - self.waitForTask(taskUID) - - # Then, we deploy cluster - url = self.base + '/api/clusters/'+str(clusterID)+'/deploy' - req = requests.put(url, headers=self.header) - if req.status_code < 300: - self.logger.info('%s', "Sent deployment task") - taskUID = '' - tasks = self.getTasks() - for task in tasks: - if 'deploy' in task['name'] and task['cluster'] == clusterID: - taskUID = task['uuid'] - if len(taskUID) > 0: - self.waitForTask(taskUID) diff --git a/laas-fog/source/api/libvirt_api.py b/laas-fog/source/api/libvirt_api.py deleted file mode 100644 index 4e19736..0000000 --- a/laas-fog/source/api/libvirt_api.py +++ /dev/null @@ -1,331 +0,0 @@ -""" -############################################################################# -#Copyright 2017 Parker Berberian and others # -# # -#Licensed under the Apache License, Version 2.0 (the "License"); # -#you may not use this file except in compliance with the License. # -#You may obtain a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -#Unless required by applicable law or agreed to in writing, software # -#distributed under the License is distributed on an "AS IS" BASIS, # -#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -#See the License for the specific language governing permissions and # -#limitations under the License. # -############################################################################# -""" - -import libvirt -import time -import xml.dom -import xml.dom.minidom -from domain import Domain -from network import Network -from utilities import Utilities - - -class Libvirt: - """ - This class talks to the Libvirt api. - Given a config file, this class should create all networks and - domains. - - TODO: convert prints to logging and remove uneeded pass statements - """ - - def __init__(self, hostAddr, net_conf=None, dom_conf=None): - """ - init function - hostAddr is the ip address of the host - net_conf and dom_conf are the paths - to the config files - """ - self.host = hostAddr - self.URI = "qemu+ssh://root@"+str(hostAddr)+"/system" - self.hypervisor = None - self.domains = [] - self.networks = [] - self.net_conf = net_conf - self.dom_conf = dom_conf - - def setLogger(self, log): - """ - Saves the logger in self.log - """ - self.log = log - - def bootMaster(self): - """ - starts the previously defined master node - """ - for dom in self.domains: - if 'master' in dom.name(): - try: - dom.create() - except Exception: - pass - - def bootSlaves(self): - """ - boots every defined vm with 'slave' in its name - """ - for dom in self.domains: - if 'slave' in dom.name(): - try: - dom.create() - self.log.info("Booting %s", dom.name()) - except Exception: - self.log.exception("%s", "failed to boot domain") - time.sleep(5) - - def getMacs(self, domName): - """ - returns a dictionary with a network name - mapped to the mac address of the domain on that net - """ - try: - dom = self.hypervisor.lookupByName(domName) - xmlDesc = dom.XMLDesc(0) - parsedXML = xml.dom.minidom.parseString(xmlDesc) - interfacesXML = parsedXML.getElementsByTagName('interface') - netDict = {} - for iface in interfacesXML: - src = iface.getElementsByTagName('source')[0] - mac = iface.getElementsByTagName('mac')[0] - netDict[src] = mac - return netDict - except Exception: - self.log.exception("%s", "Domain not found") - - def defineVM(self, xmlConfig): - """ - Generic method to define a persistent vm with the - given config. - Assumes that self.hypervisor is already connected. - """ - if self.checkForVM(xmlConfig): - vm = self.hypervisor.defineXML(xmlConfig) - if vm is None: - name = self.getName(xmlConfig) - self.log.error("Failed to define vm %s. exiting", name) - exit(1) - else: - self.log.info("Successfully created vm %s", vm.name()) - pass - self.domains.append(vm) - - def checkForVM(self, xmlConfig): - """ - Checks if another vm with the same name exists - on the remote host already. If it does, it will - delete that vm - """ - allGood = False - vms = self.hypervisor.listAllDomains(0) - names = [] - for dom in vms: - names.append(dom.name()) - vmName = Utilities.getName(xmlConfig) - if vmName in names: - self.log.warning("domain %s already exists", vmName) - self.log.warning("%s", "Atempting to delete it") - self.deleteVM(vmName) - allGood = True - else: - allGood = True - return allGood - - def deleteVM(self, name): - """ - removes the given vm from the remote host - """ - try: - vm = self.hypervisor.lookupByName(name) - except: - return - active = vm.isActive() - persistent = vm.isPersistent() - if active: - try: - vm.destroy() - except: - self.log.exception("%s", "Failed to destroy vm") - - if persistent: - try: - vm.undefine() - except: - self.log.exception("%s", "Failed to undefine domain") - pass - - def openConnection(self): - """ - opens a connection to the remote host - and stores it in self.hypervisor - """ - self.log.info("Attempting to connect to libvirt at %s", self.host) - try: - hostHypervisor = libvirt.open(self.URI) - except: - self.log.warning( - "Failed to connect to %s. Trying again", self.host - ) - time.sleep(5) - try: - hostHypervisor = libvirt.open(self.URI) - except: - self.log.exception("Cannot connect to %s. Exiting", self.host) - exit(1) - - if hostHypervisor is None: - self.log.error("Failed to connect to %s. Exiting", self.host) - exit(1) - self.hypervisor = hostHypervisor - - def restartVM(self, vm): - """ - causes the given vm to reboot - """ - dom = self.hypervisor.lookupByName(vm) - dom.destroy() - time.sleep(15) - dom.create() - - def close(self): - """ - Closes connection to remote hypervisor - """ - self.log.info("Closing connection to the hypervisor %s", self.host) - self.hypervisor.close() - - def defineAllDomains(self, path): - """ - Defines a domain from all the xml files in a directory - """ - files = Utilities.getXMLFiles(path) - definitions = [] - for xml_desc in files: - definitions.append(xml_desc.read()) - - for definition in definitions: - self.defineVM(definition) - - def createAllNetworks(self, path): - """ - Creates a network from all xml files in a directory - """ - files = Utilities.getXMLFiles(path) - definitions = [] - for xml_desc in files: - definitions.append(Utilities.fileToString(xml_desc)) - - for definition in definitions: - self.createNet(definition) - - def createNet(self, config): - """ - creates the network on the remote host - config is the xml in string representation - that defines the network - """ - if self.checkNet(config): - network = self.hypervisor.networkDefineXML(config) - - if network is None: - name = self.getName(config) - self.log.warning("Failed to define network %s", name) - network.create() - if network.isActive() == 1: - net = network.name() - self.log.info("Successfully defined network %s", net) - self.networks.append(network) - - def checkNet(self, config): - """ - Checks if another net with the same name exists, and - deletes that network if one is found - """ - allGood = False - netName = Utilities.getName(config) - if netName not in self.hypervisor.listNetworks(): - return True - else: # net name is already used - self.log.warning( - "Network %s already exists. Trying to delete it", netName - ) - network = self.hypervisor.networkLookupByName(netName) - self.deleteNet(network) - allGood = True - return allGood - - def deleteNet(self, net): - """ - removes the given network from the host - """ - active = net.isActive() - persistent = net.isPersistent() - if active: - try: - net.destroy() - except: - self.log.warning("%s", "Failed to destroy network") - - if persistent: - try: - net.undefine() - except: - self.log.warning("%s", "Failed to undefine network") - - def go(self): - """ - This method does all the work of this class, - Parsing the net and vm config files and creating - all the requested nets/domains - returns a list of all networks and a list of all domains - as Network and Domain objects - """ - nets = self.makeNetworks(self.net_conf) - doms = self.makeDomains(self.dom_conf) - return doms, nets - - def makeNetworks(self, conf): - """ - Given a path to a config file, this method - parses the config and creates all requested networks, - and returns them in a list of Network objects - """ - networks = [] - definitions = Network.parseConfigFile(conf) - for definition in definitions: - network = Network(definition) - networks.append(network) - self.createNet(network.toXML()) - return networks - - def makeDomains(self, conf): - """ - Given a path to a config file, this method - parses the config and creates all requested vm's, - and returns them in a list of Domain objects - """ - domains = [] - definitions = Domain.parseConfigFile(conf) - for definition in definitions: - domain = Domain(definition) - domains.append(domain) - self.defineVM(domain.toXML()) - return domains - - @staticmethod - def getName(xmlString): - """ - given xml with a name tag, this returns the value of name - eg: - <name>Parker</name> - returns 'Parker' - """ - xmlDoc = xml.dom.minidom.parseString(xmlString) - nameNode = xmlDoc.documentElement.getElementsByTagName('name') - name = str(nameNode[0].firstChild.nodeValue) - return name diff --git a/laas-fog/source/api/vpn.py b/laas-fog/source/api/vpn.py deleted file mode 100644 index 336a681..0000000 --- a/laas-fog/source/api/vpn.py +++ /dev/null @@ -1,235 +0,0 @@ -from abc import ABCMeta, abstractmethod -import ldap -import os -import random -from base64 import b64encode -from database import BookingDataBase - - -class VPN_BaseClass: - """ - the vpn handler abstract class / interface - - """ - __metaclass__ = ABCMeta - - @abstractmethod - def __init__(self, config): - """ - config is the parsed vpn.yaml file - """ - pass - - @abstractmethod - def makeNewUser(self, user=None): - """ - This method is called when a vpn user is needed. - This method should create a vpn user in whatever - runs the vpn in our infrastructure. returns the - credentials for the vpn user and some uid - that will be associated with the booking in the - database. This uid is used to track the vpn user and - to delete the user when there are no bookings associated - with that uid. - """ - user = "username" - passwd = "password" - uid = "some way for you to identify this user in the database" - return user, passwd, uid - - @abstractmethod - def removeOldUsers(self): - """ - checks the list of all vpn users against a list of - vpn users associated with active bookings and removes - users who dont have an active booking - - If you want your vpn accounts to be persistent, - you can just ignore this - """ - pass - - -names = [ - 'frodo baggins', 'samwise gamgee', 'peregrin took', 'meriadoc brandybuck', - 'bilbo baggins', 'gandalf grey', 'aragorn dunadan', 'arwen evenstar', - 'saruman white', 'pippin took', 'merry brandybuck', 'legolas greenleaf', - 'gimli gloin', 'anakin skywalker', 'padme amidala', 'han solo', - 'jabba hut', 'mace windu', 'sount dooku', 'qui-gon jinn', - 'admiral ackbar', 'emperor palpatine' -] - - -class VPN: - """ - This class communicates with the ldap server to manage vpn users. - This class extends the above ABC, and implements the makeNewUser, - removeOldUser, and __init__ abstract functions you must override to - extend the VPN_BaseClass - """ - - def __init__(self, config): - """ - init takes the parsed vpn config file as an arguement. - automatically connects and authenticates on the ldap server - based on the configuration file - """ - self.config = config - server = config['server'] - self.uri = "ldap://"+server - - self.conn = None - user = config['authentication']['user'] - pswd = config['authentication']['pass'] - if os.path.isfile(pswd): - pswd = open(pswd).read() - self.connect(user, pswd) - - def connect(self, root_dn, root_pass): - """ - Opens a connection to the server in the config file - and authenticates as the given user - """ - self.conn = ldap.initialize(self.uri) - self.conn.simple_bind_s(root_dn, root_pass) - - def addUser(self, full_name, passwd): - """ - Adds a user to the ldap server. Creates the new user with the classes - and in the directory given in the config file. - full_name should be two tokens seperated by a space. The first token - will become the username - private helper function for the makeNewUser() - """ - first = full_name.split(' ')[0] - last = full_name.split(' ')[1] - user_dir = self.config['directory']['user'] - user_dir += ','+self.config['directory']['root'] - dn = "uid=" + first + ',' + user_dir - record = [ - ('objectclass', ['top', 'inetOrgPerson']), - ('uid', first), - ('cn', full_name), - ('sn', last), - ('userpassword', passwd), - ('ou', self.config['directory']['user'].split('=')[1]) - ] - self.conn.add_s(dn, record) - return dn - - def makeNewUser(self, name=None): - """ - creates a new user in the ldap database, with the given name - if supplied. If no name is given, we will try to select from the - pre-written list above, and will resort to generating a random string - as a username if the preconfigured names are all taken. - Returns the username and password the user needs to authenticate, and - the dn that we can use to manage the user. - """ - if name is None: - i = 0 - while not self.checkName(name): - i += 1 - if i == 20: - name = self.randoString(8) - name += ' '+self.randoString(8) - break # generates a random name to prevent infinite loop - name = self.genUserName() - passwd = self.randoString(15) - dn = self.addUser(name, passwd) - return name, passwd, dn - - def checkName(self, name): - """ - returns true if the name is available - """ - if name is None: - return False - uid = name.split(' ')[0] - base = self.config['directory']['user'] + ',' - base += self.config['directory']['root'] - filtr = '(uid=' + uid + ')' - timeout = 5 - ans = self.conn.search_st( - base, - ldap.SCOPE_SUBTREE, - filtr, - timeout=timeout - ) - return len(ans) < 1 - - @staticmethod - def randoString(n): - """ - uses /dev/urandom to generate a random string of length n - """ - n = int(n) - # defines valid characters - alpha = 'abcdefghijklmnopqrstuvwxyz' - alpha_num = alpha - alpha_num += alpha.upper() - alpha_num += "0123456789" - - # generates random string from /dev/urandom - rnd = b64encode(os.urandom(3*n)).decode('utf-8') - random_string = '' - for char in rnd: - if char in alpha_num: - random_string += char - return str(random_string[:n]) - - def genUserName(self): - """ - grabs a random name from the list above - """ - i = random.randint(0, len(names) - 1) - return names[i] - - def deleteUser(self, dn): - self.conn.delete(dn) - - def getAllUsers(self): - """ - returns all the user dn's in the ldap database in a list - """ - base = self.config['directory']['user'] + ',' - base += self.config['directory']['root'] - filtr = '(objectclass='+self.config['user']['objects'][-1]+')' - timeout = 10 - ans = self.conn.search_st( - base, - ldap.SCOPE_SUBTREE, - filtr, - timeout=timeout - ) - users = [] - for user in ans: - users.append(user[0]) # adds the dn of each user - return users - - def removeOldUsers(self): - """ - removes users from the ldap server who dont have any active bookings. - will not delete a user if their uid's are named in the config - file as permanent users. - """ - db = self.config['database'] - # the dn of all users who have an active booking - active_users = BookingDataBase(db).getVPN() - all_users = self.getAllUsers() - for user in all_users: - # checks if they are a permanent user - if self.is_permanent_user(user): - continue - # deletes the user if they dont have an active booking - if user not in active_users: - self.deleteUser(user) - - def is_permanent_user(self, dn): - for user in self.config['permanent_users']: - if (user in dn) or (dn in user): - return True - return False - - -VPN_BaseClass.register(VPN) |