From 30f389c70e8a0a8bd2ef27be09839eef243ab7f5 Mon Sep 17 00:00:00 2001 From: Parker Berberian Date: Wed, 20 Dec 2017 12:48:17 -0500 Subject: Initial Commit for new LaaS Software JIRA: PHAROS-318 The old code I had in here was super beta and no good. I reworked the code to use Stackstorm instead of trying to roll my own automation services. This commit adds a README, install scripts, and the skeleton of a stackstorm pack Change-Id: Ia1c0c29e23316ad0e635c9c181c9a68fdacee664 Signed-off-by: Parker Berberian --- laas-fog/source/utilities.py | 346 ------------------------------------------- 1 file changed, 346 deletions(-) delete mode 100644 laas-fog/source/utilities.py (limited to 'laas-fog/source/utilities.py') diff --git a/laas-fog/source/utilities.py b/laas-fog/source/utilities.py deleted file mode 100644 index bbe0946..0000000 --- a/laas-fog/source/utilities.py +++ /dev/null @@ -1,346 +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 os -import logging -import string -import sys -import subprocess -import xml.dom -import xml.dom.minidom -import re -import random -import yaml -from database import HostDataBase, BookingDataBase -from api.vpn import VPN -LOGGING_DIR = "" - - -class Utilities: - """ - This class defines some useful functions that may be needed - throughout the provisioning and deployment stage. - The utility object is carried through most of the deployment process. - """ - def __init__(self, host_ip, hostname, conf): - """ - init function - host_ip is the ip of the target host - hostname is the FOG hostname of the host - conf is the parsed config file - """ - self.host = host_ip - self.hostname = hostname - root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - self.scripts = os.path.join(root_dir, "hostScripts/") - self.remoteDir = "/root/hostScripts/" - self.conf = conf - self.logger = logging.getLogger(hostname) - - def execRemoteScript(self, script, args=[]): - """ - executes the given script on the - remote host with the given args. - script must be found in laas/hostScripts - """ - cmd = [self.remoteDir+script] - for arg in args: - cmd.append(arg) - self.sshExec(cmd) - - def waitForBoot(self): - """ - Continually pings the host, waiting for it to boot - """ - i = 0 - while (not self.pingHost()) and i < 30: - i += 1 - if i == 30: - self.logger.error("Host %s has not booted", self.host) - sys.exit(1) - - def checkHost(self): - """ - returns true if the host responds to two pings. - Sometimes, while a host is pxe booting, a host will - respond to one ping but quickly go back offline. - """ - if self.pingHost() and self.pingHost(): - return True - return False - - def pingHost(self): - """ - returns true if the host responds to a ping - """ - i = 0 - response = 1 - cmd = "ping -c 1 "+self.host - cmd = cmd.split(' ') - nul = open(os.devnull, 'w') - while i < 10 and response != 0: - response = subprocess.call(cmd, stdout=nul, stderr=nul) - i = i + 1 - if response == 0: - return True - return False - - def copyDir(self, localDir, remoteDir): - """ - uses scp to copy localDir to remoteDir on the - remote host - """ - cmd = "mkdir -p "+remoteDir - self.sshExec(cmd.split(" ")) - cmd = "scp -o StrictHostKeyChecking=no -r " - cmd += localDir+" root@"+self.host+":/root" - cmd = cmd.split() - nul = open(os.devnull, 'w') - subprocess.call(cmd, stdout=nul, stderr=nul) - - def copyScripts(self): - """ - Copies the hostScrpts dir to the remote host. - """ - self.copyDir(self.scripts, self.remoteDir) - - def sshExec(self, args): - """ - executes args as an ssh - command on the remote host. - """ - cmd = ['ssh', 'root@'+self.host] - for arg in args: - cmd.append(arg) - nul = open(os.devnull, 'w') - return subprocess.call(cmd, stdout=nul, stderr=nul) - - def resetKnownHosts(self): - """ - edits your known hosts file to remove the previous entry of host - Sometimes, the flashing process gives the remote host a new - signature, and ssh complains about it. - """ - lines = [] - sshFile = open('/root/.ssh/known_hosts', 'r') - lines = sshFile.read() - sshFile.close() - lines = lines.split('\n') - sshFile = open('/root/.ssh/known_hosts', 'w') - for line in lines: - if self.host not in line: - sshFile.write(line+'\n') - sshFile.close() - - def restartHost(self): - """ - restarts the remote host - """ - cmd = ['shutdown', '-r', 'now'] - self.sshExec(cmd) - - @staticmethod - def randoString(length): - """ - this is an adapted version of the code found here: - https://stackoverflow.com/questions/2257441/ - random-string-generation-with-upper-case-letters-and-digits-in-python - generates a random alphanumeric string of length length. - """ - randStr = '' - chars = string.ascii_uppercase + string.digits - for x in range(length): - randStr += random.SystemRandom().choice(chars) - return randStr - - def changePassword(self): - """ - Sets the root password to a random string and returns it - """ - paswd = self.randoString(15) - command = "printf "+paswd+" | passwd --stdin root" - self.sshExec(command.split(' ')) - return paswd - - def markHostDeployed(self): - """ - Tells the database that this host has finished its deployment - """ - db = HostDataBase(self.conf['database']) - db.makeHostDeployed(self.hostname) - db.close() - - def make_vpn_user(self): - """ - Creates a vpn user and associates it with this booking - """ - config = yaml.safe_load(open(self.conf['vpn_config'])) - myVpn = VPN(config) - # name = dashboard.getUserName() - u, p, uid = myVpn.makeNewUser() # may pass name arg if wanted - self.logger.info("%s", "created new vpn user") - self.logger.info("username: %s", u) - self.logger.info("password: %s", p) - self.logger.info("vpn user uid: %s", uid) - self.add_vpn_user(uid) - - def add_vpn_user(self, uid): - """ - Adds the dn of the vpn user to the database - so that we can clean it once the booking ends - """ - db = BookingDataBase(self.conf['database']) - # converts from hostname to pharos resource id - inventory = yaml.safe_load(open(self.conf['inventory'])) - host_id = -1 - for resource_id in inventory.keys(): - if inventory[resource_id] == self.hostname: - host_id = resource_id - break - db.setVPN(host_id, uid) - - def finishDeployment(self): - """ - Last method call once a host is finished being deployed. - It notifies the database and changes the password to - a random string - """ - self.markHostDeployed() - self.make_vpn_user() - passwd = self.changePassword() - self.logger.info("host %s provisioning done", self.hostname) - self.logger.info("You may access the host at %s", self.host) - self.logger.info("The password is %s", passwd) - notice = "You should change all passwords for security" - self.logger.warning('%s', notice) - - @staticmethod - def restartRemoteHost(host_ip): - """ - This method assumes that you already have ssh access to the target - """ - nul = open(os.devnull, 'w') - ret_code = subprocess.call([ - 'ssh', '-o', 'StrictHostKeyChecking=no', - 'root@'+host_ip, - 'shutdown', '-r', 'now'], - stdout=nul, stderr=nul) - - return ret_code - - @staticmethod - def getName(xmlString): - """ - Gets the name value from xml. for example: - Parker returns Parker - """ - xmlDoc = xml.dom.minidom.parseString(xmlString) - nameNode = xmlDoc.documentElement.getElementsByTagName('name') - name = str(nameNode[0].firstChild.nodeValue) - return name - - @staticmethod - def getXMLFiles(directory): - """ - searches directory non-recursively and - returns a list of all xml files - """ - contents = os.listdir(directory) - fileContents = [] - for item in contents: - if os.path.isfile(os.path.join(directory, item)): - fileContents.append(os.path.join(directory, item)) - xmlFiles = [] - for item in fileContents: - if 'xml' in os.path.basename(item): - xmlFiles.append(item) - return xmlFiles - - @staticmethod - def createLogger(name, log_dir=LOGGING_DIR): - """ - Initializes the logger if it does not yet exist, and returns it. - Because of how python logging works, calling logging.getLogger() - with the same name always returns a reference to the same log file. - So we can call this method from anywhere with the hostname as - the name arguement and it will return the log file for that host. - The formatting includes the level of importance and the time stamp - """ - global LOGGING_DIR - if log_dir != LOGGING_DIR: - LOGGING_DIR = log_dir - log = logging.getLogger(name) - if len(log.handlers) > 0: # if this logger is already initialized - return log - log.setLevel(10) - han = logging.FileHandler(os.path.join(log_dir, name+".log")) - han.setLevel(10) - log_format = '[%(levelname)s] %(asctime)s [#] %(message)s' - formatter = logging.Formatter(fmt=log_format) - han.setFormatter(formatter) - log.addHandler(han) - return log - - @staticmethod - def getIPfromMAC(macAddr, logFile, remote=None): - """ - searches through the dhcp logs for the given mac - and returns the associated ip. Will retrieve the - logFile from a remote host if remote is given. - if given, remote should be an ip address or hostname that - we can ssh to. - """ - if remote is not None: - logFile = Utilities.retrieveFile(remote, logFile) - ip = Utilities.getIPfromLog(macAddr, logFile) - if remote is not None: - os.remove(logFile) - return ip - - @staticmethod - def retrieveFile(host, remote_loc, local_loc=os.getcwd()): - """ - Retrieves file from host and puts it in the current directory - unless local_loc is given. - """ - subprocess.call(['scp', 'root@'+host+':'+remote_loc, local_loc]) - return os.path.join(local_loc, os.path.basename(remote_loc)) - - @staticmethod - def getIPfromLog(macAddr, logFile): - """ - Helper method for getIPfromMAC. - uses regex to find the ip address in the - log - """ - try: - messagesFile = open(logFile, "r") - allLines = messagesFile.readlines() - except Exception: - sys.exit(1) - importantLines = [] - for line in allLines: - if macAddr in line and "DHCPACK" in line: - importantLines.append(line) - ipRegex = r'(\d+\.\d+\.\d+\.\d+)' - IPs = [] - for line in importantLines: - IPs.append(re.findall(ipRegex, line)) - if len(IPs) > 0 and len(IPs[-1]) > 0: - return IPs[-1][0] - return None -- cgit 1.2.3-korg