class IMGenerateServer(object): def __init__(self): super(IMGenerateServer, self).__init__() #********************* #Static Configuration. #********************* #this is to login in the VM. This MUST be root because IMGenerateScript needs this access. self.rootId = 'root' self.numparams = 10 #this is the user that requested the image self.user = "" self.os = "" self.version = "" self.arch = "" self.software = "" self.givenname = "" self.desc = "" self.getimg = False #load configuration self._genConf = IMServerConf() self._genConf.load_generateServerConfig() self.port = self._genConf.getGenPort() self.proc_max = self._genConf.getProcMax() self.refresh_status = self._genConf.getRefreshStatus() self.wait_max = self._genConf.getWaitMax() self.vmfile_centos = self._genConf.getVmFileCentos() self.vmfile_rhel = self._genConf.getVmFileRhel() self.vmfile_ubuntu = self._genConf.getVmFileUbuntu() self.vmfile_debian = self._genConf.getVmFileDebian() self.xmlrpcserver = self._genConf.getXmlRpcServer() self.bridge = self._genConf.getBridge() self.serverdir = self._genConf.getServerDir() if self.serverdir == None: self.serverdir = os.path.expanduser(os.path.dirname(__file__)) self.addrnfs = self._genConf.getAddrNfs() self.tempdirserver = self._genConf.getTempDirServerGen() self.tempdir = self._genConf.getTempDirGen() self.http_server = self._genConf.getHttpServerGen() self.bcfg2_url = self._genConf.getBcfg2Url() self.bcfg2_port = self._genConf.getBcgf2Port() self.oneauth = self._genConf.getOneUser() + ":" + self._genConf.getOnePass() self.log_filename = self._genConf.getLogGen() self.logLevel = self._genConf.getLogLevelGen() self.logger = self.setup_logger() self._ca_certs = self._genConf.getCaCertsGen() self._certfile = self._genConf.getCertFileGen() self._keyfile = self._genConf.getKeyFileGen() print "\nReading Configuration file from " + self._genConf.getConfigFile() + "\n" #Image repository Object verbose=False printLogStdout=False self._reposervice = IRServiceProxy(verbose,printLogStdout) def setup_logger(self): #Setup logging logger = logging.getLogger("GenerateServer") logger.setLevel(self.logLevel) formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") handler = logging.FileHandler(self.log_filename) handler.setLevel(self.logLevel) handler.setFormatter(formatter) logger.addHandler(handler) logger.propagate = False #Do not propagate to others return logger """ def get_adminpass(self, oneadmin): ############## #GET oneadmin password encoded in SHA1 ############## p = Popen('oneuser list', stdout=PIPE, shell=True) p1 = Popen('grep ' + oneadmin, stdin=p.stdout, stdout=PIPE, shell=True) p2 = Popen('cut -d\" \" -f13', stdin=p1.stdout, shell=True, stdout=PIPE) oneadminpass = p2.stdout.read().strip() return oneadmin + ":" + oneadminpass """ def start(self): self.logger.info('Starting Server on port ' + str(self.port)) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('', self.port)) sock.listen(1) #Maximum of system unaccepted connections. Maximum value depend of the system (usually 5) proc_list = [] total_count = 0 while True: if len(proc_list) == self.proc_max: full = True while full: for i in range(len(proc_list) - 1, -1, -1): #self.logger.debug(str(proc_list[i])) if not proc_list[i].is_alive(): #print "dead" proc_list.pop(i) full = False if full: time.sleep(self.refresh_status) total_count += 1 #channel, details = sock.accept() newsocket, fromaddr = sock.accept() connstream = 0 try: connstream = ssl.wrap_socket(newsocket, server_side=True, ca_certs=self._ca_certs, cert_reqs=ssl.CERT_REQUIRED, certfile=self._certfile, keyfile=self._keyfile, ssl_version=ssl.PROTOCOL_TLSv1) #print connstream proc_list.append(Process(target=self.generate, args=(connstream,))) proc_list[len(proc_list) - 1].start() except ssl.SSLError: self.logger.error("Unsuccessful connection attempt from: " + repr(fromaddr)) self.logger.info("Image Generation Request DONE") except socket.error: self.logger.error("Error with the socket connection") self.logger.info("Image Generation Request DONE") except: self.logger.error("Uncontrolled Error: " + str(sys.exc_info())) if type(connstream) is ssl.SSLSocket: connstream.shutdown(socket.SHUT_RDWR) connstream.close() self.logger.info("Image Generation Request DONE") def auth(self, userCred): return FGAuth.auth(self.user, userCred) def checkUserStatus(self, userId, passwd, userIdB): """ return "Active", "NoActive", "NoUser"; also False in case the connection with the repo fails """ if not self._reposervice.connection(): msg = "ERROR: Connection with the Image Repository failed" self.logger.error(msg) return False else: self.logger.debug("Checking User Status") status= self._reposervice.getUserStatus(userId, passwd, userIdB) self._reposervice.disconnect() return status def generate(self, channel): #this runs in a different proccess start_all = time.time() self.logger = logging.getLogger("GenerateServer." + str(os.getpid())) self.logger.info('Processing an image generation request') #it will have the IP of the VM vmaddr = "" options = '' vmID = 0 destroyed = False #receive the message data = channel.read(2048) self.logger.debug("received data: " + data) params = data.split('|') #params[0] is user #params[1] is operating system #params[2] is version #params[3] is arch #params[4] is software #params[5] is givenname #params[6] is the description #params[7] is to retrieve the image or to upload in the repo (true or false, respectively) #params[8] is the user password #params[9] is the type of password self.user = params[0].strip() self.os = params[1].strip() self.version = params[2].strip() self.arch = params[3].strip() self.software = params[4].strip() self.givenname = params[5].strip() self.desc = params[6].strip() self.getimg = eval(params[7].strip()) #boolean passwd = params[8].strip() passwdtype = params[9].strip() if len(params) != self.numparams: msg = "ERROR: incorrect message" self.errormsg(channel, msg) #break return retry = 0 maxretry = 3 endloop = False while (not endloop): userCred = FGCredential(passwdtype, passwd) if self.auth(userCred): #check the status of the user in the image repository. #This contacts with image repository client to check its db. The user an password are OK because this was already checked. userstatus=self.checkUserStatus(self.user, passwd, self.user) if userstatus == "Active": channel.write("OK") elif userstatus == "NoActive": channel.write("NoActive") msg = "ERROR: The user " + self.user + " is not active" self.errormsg(channel, msg) return elif userstatus == "NoUser": channel.write("NoUser") msg = "ERROR: The user " + self.user + " does not exist" self.logger.error(msg) self.logger.info("Image Generation Request DONE") return else: channel.write("Could not connect with image repository server") msg = "ERROR: Could not connect with image repository server to verify the user status" self.logger.error(msg) self.logger.info("Image Generation Request DONE") return endloop = True else: retry += 1 if retry < maxretry: channel.write("TryAuthAgain") passwd = channel.read(2048) else: msg = "ERROR: authentication failed" endloop = True self.errormsg(channel, msg) return #channel.write("OK") #print "---Auth works---" vmfile = "" if self.os == "ubuntu": vmfile = self.vmfile_ubuntu elif self.os == "debian": vmfile = self.vmfile_debian elif self.os == "rhel": vmfile = self.vmfile_rhel elif self.os == "centos": vmfile = self.vmfile_centos[self.version] # ---Start xmlrpc client to opennebula server------------- try: server = xmlrpclib.ServerProxy(self.xmlrpcserver) except: self.logger.error("Error connection with OpenNebula " + str(sys.exc_info())) #print "Error connecting with OpenNebula " + str(sys.exc_info()) return ########### #BOOT VM## ########## start = time.time() output = self.boot_VM(server, vmfile) end = time.time() self.logger.info('TIME boot VM:' + str(end - start)) vmaddr = output[0] vmID = output[1] ##### if vmaddr != "fail": self.logger.info("The VM deployed is in " + vmaddr) self.logger.info("Mount scratch directory in the VM") cmd = "ssh -q -oBatchMode=yes " + self.rootId + "@" + vmaddr cmdmount = " mount -t nfs " + self.addrnfs + ":" + self.tempdirserver + " " + self.tempdir self.logger.info(cmd + cmdmount) stat = os.system(cmd + cmdmount) if (stat == 0): self.logger.info("Sending IMGenerateScript.py to the VM") cmdscp = "scp -q -oBatchMode=yes " + self.serverdir + '/image/management/IMGenerateScript.py ' + self.rootId + "@" + vmaddr + ":/root/" self.logger.info(cmdscp) stat = os.system(cmdscp) if (stat != 0): msg = "ERROR: sending IMGenerateScript.py to the VM. Exit status " + str(stat) self.errormsg(channel, msg) else: options += "-a " + self.arch + " -o " + self.os + " -v " + self.version + " -u " + self.user + " -t " + self.tempdir if type(self.givenname) is not NoneType: options += " -n " + self.givenname if type(self.desc) is not NoneType: options += " -e " + self.desc if type(self.software) is not NoneType: options += " -s " + self.software options += " -c " + self.http_server + " -b " + self.bcfg2_url + " -p " + str(self.bcfg2_port) cmdexec = " -q '/root/IMGenerateScript.py " + options + " '" self.logger.info(cmdexec) start = time.time() uid = self._rExec(self.rootId, cmdexec, vmaddr) end = time.time() self.logger.info('TIME generate image:' + str(end - start)) self.logger.info("copying fg-image-generate.log to scrach partition " + self.tempdirserver + "/" + str(vmID) + "_gen.log") cmdscp = "scp -q -oBatchMode=yes " + self.rootId + "@" + vmaddr + ":/root/fg-image-generate.log " + self.tempdirserver + "/" + str(vmID) + "_gen.log" os.system(cmdscp) status = uid[0].strip() #it contains error or filename if status == "error": msg = "ERROR: " + str(uid[1]) self.errormsg(channel, msg) else: #stat = 0 #while stat != 0 and : self.logger.info("Umount scratch directory in the VM") cmd = "ssh -q -oBatchMode=yes " + self.rootId + "@" + vmaddr cmdmount = " umount " + self.tempdir + " 2>/dev/null" #stat = os.system(cmd + cmdmount) #self.logger.debug("exit status " + str(stat)) #if stat != 0: # time.sleep(2) start = time.time() #umount the image max_retry = 15 retry_done = 0 umounted = False #Done making changes to root fs while not umounted: self.logger.debug(cmd + cmdmount) stat = os.system(cmd + cmdmount) if stat == 0: umounted = True elif retry_done == max_retry: self.logger.debug("exit status " + str(stat)) umounted = True self.logger.error("Problems to umount the image. Exit status " + str(stat)) else: retry_done += 1 time.sleep(5) end = time.time() self.logger.info('TIME umount image:' + str(end - start)) #destroy VM self.logger.info("Destroy VM") server.one.vm.action(self.oneauth, "finalize", vmID) destroyed = True self.logger.debug("Generating tgz with image and manifest files") self.logger.debug("tar cfz " + self.tempdirserver + "/" + status + ".tgz -C " + self.tempdirserver + \ " " + status + ".manifest.xml " + status + ".img") start = time.time() out = os.system("tar cfz " + self.tempdirserver + "/" + status + ".tgz -C " + self.tempdirserver + \ " " + status + ".manifest.xml " + status + ".img") end = time.time() self.logger.info('TIME tgz image:' + str(end - start)) if out == 0: os.system("rm -f " + self.tempdirserver + "" + status + ".manifest.xml " + self.tempdirserver + \ "" + status + ".img") else: msg = "ERROR: generating compressed file with the image and manifest" self.errormsg(channel, msg) return if self.getimg: #send back the url where the image is channel.write(self.tempdirserver + "" + status + ".tgz") self.logger.info("Waiting until the client retrieve the image") channel.read() #we can include a loop to retry if the client has problems getting the image channel.shutdown(socket.SHUT_RDWR) channel.close() else: status_repo = "" error_repo = False #send back the ID of the image in the repository try: #connect with the server if not self._reposervice.connection(): msg = "ERROR: Connection with the Image Repository failed" self.errormsg(channel, msg) else: self.logger.info("Storing image " + self.tempdirserver + "/" + status + ".tgz" + " in the repository") start = time.time() status_repo = self._reposervice.put(self.user, passwd, self.user, self.tempdirserver + "" + status + ".tgz", "os=" + \ self.os + "_" + self.version + "&arch=" + self.arch + "&description=" + \ self.desc + "&tag=" + status) end = time.time() self.logger.info('TIME upload image to the repo:' + str(end - start)) if (re.search('^ERROR', status_repo)): self.errormsg(channel, status_repo) else: channel.write(str(status_repo)) channel.shutdown(socket.SHUT_RDWR) channel.close() self._reposervice.disconnect() except: msg = "ERROR: uploading image to the repository. " + str(sys.exc_info()) self.errormsg(channel, msg) #Remove file from server because the client or the repository already finished os.system("rm -f " + self.tempdirserver + "" + status + ".tgz") else: msg = "ERROR: booting VM" self.errormsg(channel, msg) #destroy VM if not destroyed: self.logger.info("Destroy VM") server.one.vm.action(self.oneauth, "finalize", vmID) end_all = time.time() self.logger.info('TIME walltime image generate:' + str(end_all - start_all)) self.logger.info("Image Generation DONE") def errormsg(self, channel, msg): self.logger.error(msg) try: channel.write(msg) channel.shutdown(socket.SHUT_RDWR) channel.close() except: self.logger.debug("In errormsg: " + str(sys.exc_info())) self.logger.info("Image Generation DONE") def boot_VM(self, server, vmfile): """ It will boot a VM using XMLRPC API for OpenNebula from lib/ruby/OpenNebula/VirtualMachine.rb index start in 0 VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED} LCM_STATE=%w{LCM_INIT PROLOG BOOT RUNNING MIGRATE SAVE_STOP SAVE_SUSPEND SAVE_MIGRATE PROLOG_MIGRATE PROLOG_RESUME EPILOG_STOP EPILOG SHUTDOWN CANCEL FAILURE CLEANUP UNKNOWN} """ vmaddr = "" fail = False #print vmfile #-----read template into string ------------------------- #s=open('./share/examples/ubuntu_context.one','r').read() s = open(os.path.expanduser(vmfile), 'r').read() #self.logger.debug("Vm template:\n"+s) #-----Start VM------------------------------------------- vm = server.one.vm.allocate(self.oneauth, s) #print self.oneauth #print vm if vm[0]: self.logger.debug("VM ID: " + str(vm[1])) #monitor VM booted = False maxretry = self.wait_max / 5 #time that the VM has to change from penn to runn retry = 0 while not booted and retry < maxretry: #eventually the VM has to boot or fail try: #-------Get Info about VM ------------------------------- vminfo = server.one.vm.info(self.oneauth, vm[1]) #print vminfo[1] manifest = parseString(vminfo[1]) #VM_status (init=0, pend=1, act=3, fail=7) vm_status = manifest.getElementsByTagName('STATE')[0].firstChild.nodeValue.strip() if vm_status == "3": #running #LCM_status (prol=1,boot=2,runn=3, fail=14, unk=16) lcm_status = manifest.getElementsByTagName('LCM_STATE')[0].firstChild.nodeValue.strip() if lcm_status == "3": #if vm_status is 3, this will be 3 too. booted = True elif vm_status == "7": #fail self.logger.error("Fail to deploy VM " + str(vm[1])) booted = True fail = True vmaddr = "fail" elif vm_status == "6": #done self.logger.error("The status of the VM " + str(vm[1]) + " is DONE") booted = True fail = True vmaddr = "fail" else: retry += 1 time.sleep(5) except: pass if retry >= maxretry: self.logger.error("The VM " + str(vm[1]) + " did not change to runn status. Please verify that the status of the OpenNebula hosts " "or increase the wait time in the configuration file (max_wait) \n") vmaddr = "fail" fail = True if not fail: #get IP nics = manifest.getElementsByTagName('NIC') for i in range(len(nics)): if(nics[i].childNodes[0].firstChild.nodeValue.strip() == self.bridge): vmaddr = nics[i].childNodes[1].firstChild.nodeValue.strip() if vmaddr.strip() != "": self.logger.debug("IP of the VM " + str(vm[1]) + " is " + str(vmaddr)) access = False maxretry = 240 #this says that we wait 20 minutes maximum to allow the VM get online. #this also prevent to get here forever if the ssh key was not injected propertly. retry = 0 self.logger.debug("Waiting to have access to VM") while not access and retry < maxretry: cmd = "ssh -q -oBatchMode=yes root@" + vmaddr + " uname" p = Popen(cmd, shell=True, stdout=PIPE) status = os.waitpid(p.pid, 0)[1] #print status if status == 0: access = True self.logger.debug("The VM " + str(vm[1]) + " with ip " + str(vmaddr) + "is accessible") else: retry += 1 time.sleep(5) if retry >= maxretry: self.logger.error("Could not get access to the VM " + str(vm[1]) + " with ip " + str(vmaddr) + "\n" "Please verify the OpenNebula templates to make sure that the public ssh key to be injected is accessible to the oneadmin user. \n" "Also verify that the VM has ssh server and is active on boot.") vmaddr = "fail" else: self.logger.error("Could not determine the IP of the VM " + str(vm[1]) + " for the bridge " + self.bridge) vmaddr = "fail" else: vmaddr = "fail" return [vmaddr, vm[1]] ############################################################ # _rExec ############################################################ def _rExec(self, userId, cmdexec, vmaddr): #TODO: do we want to use the .format statement from python to make code more readable? #Set up random string random.seed() randid = str(random.getrandbits(32)) cmdssh = "ssh -oBatchMode=yes " + userId + "@" + vmaddr tmpFile = "/tmp/" + str(time.time()) + str(randid) #print tmpFile cmdexec = cmdexec + " > " + tmpFile cmd = cmdssh + cmdexec self.logger.info(str(cmd)) stat = os.system(cmd) if (str(stat) != "0"): #print stat self.logger.info(str(stat)) f = open(tmpFile, "r") outputs = f.readlines() f.close() os.system("rm -f " + tmpFile) #output = "" #for line in outputs: # output += line.strip() #print outputs return outputs
class IMDeployServerIaaS(object): def __init__(self): super(IMDeployServerIaaS, self).__init__() self.path = "" self.numparams = 8 #image path self.name = "" self.givenname = "" self.operatingsystem = "" self.version = "" self.arch = "" self.kernel = "" self.user = "" self.iaas = "" #load from config file self._deployConf = IMServerConf() self._deployConf.load_deployServerIaasConfig() self.port = self._deployConf.getIaasPort() self.http_server = self._deployConf.getHttpServerIaas() self.proc_max = self._deployConf.getProcMaxIaas() self.refresh_status = self._deployConf.getRefreshStatusIaas() self.tempdir = self._deployConf.getTempDirIaas() self.log_filename = self._deployConf.getLogIaas() self.logLevel = self._deployConf.getLogLevelIaas() self._ca_certs = self._deployConf.getCaCertsIaas() self._certfile = self._deployConf.getCertFileIaas() self._keyfile = self._deployConf.getKeyFileIaas() self.default_euca_kernel = self._deployConf.getDefaultEucaKernel() self.default_nimbus_kernel = self._deployConf.getDefaultNimbusKernel() self.default_openstack_kernel = self._deployConf.getDefaultOpenstackKernel() self.default_opennebula_kernel = self._deployConf.getDefaultOpennebulaKernel() print "\nReading Configuration file from " + self._deployConf.getConfigFile() + "\n" self.logger = self.setup_logger("") #Image repository Object verbose = False printLogStdout = False self._reposervice = IRServiceProxy(verbose, printLogStdout) def setup_logger(self, extra): #Setup logging logger = logging.getLogger("DeployIaaS" + extra) logger.setLevel(self.logLevel) formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") handler = logging.FileHandler(self.log_filename) handler.setLevel(self.logLevel) handler.setFormatter(formatter) logger.addHandler(handler) logger.propagate = False #Do not propagate to others return logger def start(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('', self.port)) sock.listen(1) self.logger.info('Starting Server on port ' + str(self.port)) proc_list = [] total_count = 0 while True: if len(proc_list) == self.proc_max: full = True while full: for i in range(len(proc_list) - 1, -1, -1): #self.logger.debug(str(proc_list[i])) if not proc_list[i].is_alive(): #print "dead" proc_list.pop(i) full = False if full: time.sleep(self.refresh_status) total_count += 1 #channel, details = sock.accept() newsocket, fromaddr = sock.accept() connstream = 0 try: connstream = ssl.wrap_socket(newsocket, server_side=True, ca_certs=self._ca_certs, cert_reqs=ssl.CERT_REQUIRED, certfile=self._certfile, keyfile=self._keyfile, ssl_version=ssl.PROTOCOL_TLSv1) #print connstream proc_list.append(Process(target=self.process_client, args=(connstream,))) proc_list[len(proc_list) - 1].start() except ssl.SSLError: self.logger.error("Unsuccessful connection attempt from: " + repr(fromaddr)) self.logger.info("IaaS deploy server Request DONE") except socket.error: self.logger.error("Error with the socket connection") self.logger.info("IaaS deploy server Request DONE") except: self.logger.error("Uncontrolled Error: " + str(sys.exc_info())) if type(connstream) is ssl.SSLSocket: connstream.shutdown(socket.SHUT_RDWR) connstream.close() self.logger.info("IaaS deploy server Request DONE") def auth(self, userCred): return FGAuth.auth(self.user, userCred) def checkUserStatus(self, userId, passwd, userIdB): """ return "Active", "NoActive", "NoUser"; also False in case the connection with the repo fails """ if not self._reposervice.connection(): msg = "ERROR: Connection with the Image Repository failed" self.logger.error(msg) return False else: self.logger.debug("Checking User Status") status= self._reposervice.getUserStatus(userId, passwd, userIdB) self._reposervice.disconnect() return status def process_client(self, connstream): start_all = time.time() self.logger = self.setup_logger("." + str(os.getpid())) self.logger.info('Accepted new connection') #receive the message data = connstream.read(2048) params = data.split(',') #print data #params[0] is image ID or image path #param [1] is the source of the image (repo,disk). #params[2] is the iaas cloud #params[3] is the kernel #params[4] is the user #params[5] is the user password #params[6] is the type of password #params[7] is the ldap configure or not imgID = params[0].strip() imgSource = params[1].strip() self.iaas = params[2].strip() self.kernel = params[3].strip() self.user = params[4].strip() passwd = params[5].strip() passwdtype = params[6].strip() ldap = False try: ldap = eval(params[7].strip()) except: self.logger.warning("Ldap configure set to False in except") ldap = False if len(params) != self.numparams: msg = "ERROR: incorrect message" self.errormsg(connstream, msg) return retry = 0 maxretry = 3 endloop = False while (not endloop): userCred = FGCredential(passwdtype, passwd) if (self.auth(userCred)):# contact directly with LDAP #check the status of the user in the image repository. #This contacts with image repository client to check its db. The user an password are OK because this was already checked. userstatus=self.checkUserStatus(self.user, passwd, self.user) if userstatus == "Active": connstream.write("OK") elif userstatus == "NoActive": connstream.write("NoActive") msg = "ERROR: The user " + self.user + " is not active" self.errormsg(connstream, msg) return elif userstatus == "NoUser": connstream.write("NoUser") msg = "ERROR: The user " + self.user + " does not exist" self.logger.error(msg) self.logger.info("IaaS deploy server Request DONE") return else: connstream.write("Could not connect with image repository server") msg = "ERROR: Could not connect with image repository server to verify the user status" self.logger.error(msg) self.logger.info("IaaS deploy server Request DONE") return endloop = True else: retry += 1 if retry < maxretry: connstream.write("TryAuthAgain") passwd = connstream.read(2048) else: msg = "ERROR: authentication failed" endloop = True self.errormsg(connstream, msg) return #create a unique directory auxdir = str(randrange(999999999999999999999999)) localtempdir = self.tempdir + "/" + auxdir + "_0" while os.path.isfile(localtempdir): auxdir = str(randrange(999999999999999999999999)) localtempdir = self.tempdir + "/" + auxdir + "_0" cmd = 'mkdir -p ' + localtempdir self.runCmd(cmd) self.runCmd("chmod 777 " + localtempdir) start = time.time() if imgSource == "repo": #GET IMAGE from repo if not self._reposervice.connection(): msg = "ERROR: Connection with the Image Repository failed" self.errormsg(connstream, msg) return else: self.logger.info("Retrieving image from repository") image = self._reposervice.get(self.user, passwd, self.user, "img", imgID, localtempdir) if image == None: msg = "ERROR: Cannot get access to the image with imgId " + str(imgID) self.errormsg(connstream, msg) self._reposervice.disconnect() self.runCmd("rm -rf " + localtempdir) return else: self._reposervice.disconnect() else: connstream.write(localtempdir) status = connstream.read(1024) status = status.split(',') if len(status) == 2: image = localtempdir + '/' + status[1].strip() if status[0].strip() != 'OK': msg = "ERROR: Receiving image from client: " + str(status) self.errormsg(connstream, msg) return else: msg = "ERROR: Message received from client is incorrect: " + str(status) self.errormsg(connstream, msg) return end = time.time() self.logger.info('TIME retrieve image from repo or client:' + str(end - start)) if not os.path.isfile(image): msg = "ERROR: file " + image + " not found" self.errormsg(connstream, msg) return start = time.time() #extracts image/manifest, read manifest if not self.handle_image(image, localtempdir, connstream): return end = time.time() self.logger.info('TIME untar image: ' + str(end - start)) #self.preprocess() start = time.time() stat=0 if (self.iaas == "euca"): stat=self.euca_method(localtempdir, ldap) elif (self.iaas == "nimbus"): stat=self.nimbus_method(localtempdir, ldap) elif (self.iaas == "opennebula"): stat=self.opennebula_method(localtempdir, ldap) elif (self.iaas == "openstack"): stat=self.openstack_method(localtempdir, ldap) end = time.time() self.logger.info('TIME customize image for specific IaaS framework:' + str(end - start)) start = time.time() #umount the image max_retry = 5 retry_done = 0 umounted = False #Done making changes to root fs while not umounted: status = self.runCmd('sudo umount ' + localtempdir + '/temp') if status == 0: umounted = True elif retry_done == max_retry: umounted = True self.logger.error("Problems to umount the image") else: retry_done +=1 time.sleep(2) end = time.time() self.logger.info('TIME umount image:' + str(end - start)) status = self.runCmd("mv -f " + localtempdir + '/' + self.name + '.img ' + localtempdir + '/' + self.operatingsystem + self.version + self.name + '.img') connstream.write(localtempdir + '/' + self.operatingsystem + self.version + self.name + '.img,' + self.kernel + "," + self.operatingsystem) start = time.time() #wait until client retrieve img self.logger.info("Wait until client get the image") connstream.read() end = time.time() self.logger.info('TIME wait until client get image:' + str(end - start)) #remove image cmd = 'rm -rf ' + localtempdir status = self.runCmd(cmd) try: connstream.shutdown(socket.SHUT_RDWR) connstream.close() except: self.logger.error("ERROR: " + str(sys.exc_info())) end_all = time.time() self.logger.info('TIME walltime image deploy IaaS:' + str(end_all - start_all)) self.logger.info("Image Deploy Request DONE") def configure_ldap(self, localtempdir): start = time.time() if self.operatingsystem == "centos": self.runCmd('sudo chroot ' + localtempdir + '/temp/ yum -y install fuse-sshfs') self.logger.info('Installing LDAP packages') if (self.version == "5"): self.runCmd('sudo chroot ' + localtempdir + '/temp/ yum -y install openldap-clients nss_ldap') self.runCmd('sudo wget ' + self.http_server + '/ldap/nsswitch.conf -O ' + localtempdir + '/temp/etc/nsswitch.conf') elif (self.version == "6"): self.runCmd('sudo chroot ' + localtempdir + '/temp/ yum -y install openldap-clients nss-pam-ldapd sssd') self.runCmd('sudo wget ' + self.http_server + '/ldap/nsswitch.conf_centos6 -O ' + localtempdir + '/temp/etc/nsswitch.conf') self.runCmd('sudo wget ' + self.http_server + '/ldap/sssd.conf_centos6 -O ' + localtempdir + '/temp/etc/sssd/sssd.conf') self.runCmd('sudo chmod 600 ' + localtempdir + '/temp/etc/sssd/sssd.conf') self.runCmd('sudo chroot ' + localtempdir + '/temp/ chkconfig sssd on') self.logger.info('Configuring LDAP access') self.runCmd('sudo mkdir -p ' + localtempdir + '/temp/etc/openldap/cacerts ' + localtempdir + '/temp/N/u') self.runCmd('sudo wget ' + self.http_server + '/ldap/cacerts/12d3b66a.0 -O ' + localtempdir + '/temp/etc/openldap/cacerts/12d3b66a.0') self.runCmd('sudo wget ' + self.http_server + '/ldap/cacerts/cacert.pem -O ' + localtempdir + '/temp/etc/openldap/cacerts/cacert.pem') self.runCmd('sudo wget ' + self.http_server + '/ldap/ldap.conf -O ' + localtempdir + '/temp/etc/ldap.conf') self.runCmd('sudo wget ' + self.http_server + '/ldap/openldap/ldap.conf -O ' + localtempdir + '/temp/etc/openldap/ldap.conf') os.system('sudo sed -i \'s/enforcing/disabled/g\' ' + localtempdir + '/temp/etc/selinux/config') #self.runCmd('sudo wget ' + self.http_server + '/ldap/sshd_centos' + self.version + ' -O ' + localtempdir + '/temp/usr/sbin/sshd') #os.system('echo "UseLPK yes" | sudo tee -a ' + localtempdir + '/temp/etc/ssh/sshd_config > /dev/null') #os.system('echo "LpkLdapConf /etc/ldap.conf" | sudo tee -a ' + localtempdir + '/temp/etc/ssh/sshd_config > /dev/null') #self.runCmd('sudo chroot ' + localtempdir + '/temp/ yum -y install fuse-sshfs') elif self.operatingsystem == "ubuntu": #services will install, but not start f = open(localtempdir + '/_policy-rc.d', 'w') f.write("#!/bin/sh" + '\n' + "exit 101" + '\n') f.close() self.runCmd('sudo mv -f ' + localtempdir + '/_policy-rc.d ' + localtempdir + '/temp/usr/sbin/policy-rc.d') self.runCmd('sudo chmod +x ' + localtempdir + '/temp/usr/sbin/policy-rc.d') self.runCmd('sudo chroot ' + localtempdir + '/temp/ apt-get -y install sshfs') #try this other way #chroot maverick-vm /bin/bash -c 'DEBIAN_FRONTEND=noninteractive apt-get -y --force-yes install linux-image-server' #env DEBIAN_FRONTEND="noninteractive" chroot /tmp/javi3789716749 /bin/bash -c 'apt-get --force-yes -y install ldap-utils libpam-ldap libpam-ldap libnss-ldap nss-updatedb libnss-db' self.logger.info('Configuring LDAP access') self.runCmd('sudo wget ' + self.http_server + '/ldap/nsswitch.conf -O ' + localtempdir + '/temp/etc/nsswitch.conf') self.runCmd('sudo mkdir -p ' + localtempdir + '/temp/etc/ldap/cacerts ' + localtempdir + '/temp/N/u') self.runCmd('sudo wget ' + self.http_server + '/ldap/cacerts/12d3b66a.0 -O ' + localtempdir + '/temp/etc/ldap/cacerts/12d3b66a.0') self.runCmd('sudo wget ' + self.http_server + '/ldap/cacerts/cacert.pem -O ' + localtempdir + '/temp/etc/ldap/cacerts/cacert.pem') self.runCmd('sudo wget ' + self.http_server + '/ldap/ldap.conf -O ' + localtempdir + '/temp/etc/ldap.conf') self.runCmd('sudo wget ' + self.http_server + '/ldap/openldap/ldap.conf -O ' + localtempdir + '/temp/etc/ldap/ldap.conf') os.system('sudo sed -i \'s/openldap/ldap/g\' ' + localtempdir + '/temp/etc/ldap/ldap.conf') os.system('sudo sed -i \'s/openldap/ldap/g\' ' + localtempdir + '/temp/etc/ldap.conf') self.logger.info('Installing LDAP packages') ldapexec = "/tmp/ldap.install" os.system('echo "#!/bin/bash \nexport DEBIAN_FRONTEND=noninteractive \napt-get ' + \ '-y install ldap-utils libnss-ldapd nss-updatedb libnss-db" >' + localtempdir + '/temp/' + ldapexec) os.system('sudo chmod +x ' + localtempdir + '/temp/' + ldapexec) self.runCmd('sudo chroot ' + localtempdir + '/temp/ ' + ldapexec) #I think this is not needed #self.runCmd('wget '+ self.http_server +'/ldap/sshd_ubuntu -O ' + localtempdir + '/temp/usr/sbin/sshd') #os.system('echo "UseLPK yes" | sudo tee -a ' + localtempdir + '/temp/etc/ssh/sshd_config > /dev/null') #os.system('echo "LpkLdapConf /etc/ldap.conf" | sudo tee -a ' + localtempdir + '/temp/etc/ssh/sshd_config > /dev/null') self.runCmd('rm -f ' + localtempdir + '/temp/usr/sbin/policy-rc.d') end = time.time() self.logger.info('TIME configure LDAP (this is included in the TIME customize image for specific IaaS framework):' + str(end - start)) def euca_method(self, localtempdir, ldap): stat = 0 #Select kernel version #This is not yet supported as we get always the same kernel self.logger.debug("kernel: " + self.kernel) if self.kernel == "None": self.kernel = self.default_euca_kernel #Inject the kernel self.logger.info('Retrieving kernel ' + self.kernel) stat=self.runCmd('wget ' + self.http_server + 'kernel/' + self.kernel + '.modules.tar.gz -O ' + localtempdir + '/' + self.kernel + '.modules.tar.gz') if stat==0: self.runCmd('sudo tar xfz ' + localtempdir + '/' + self.kernel + '.modules.tar.gz --directory ' + localtempdir + '/temp/lib/modules/') self.logger.info('Injected kernel ' + self.kernel) # Setup fstab fstab = ''' # Default fstab /dev/sda1 / ext3 defaults,errors=remount-ro 0 0 /dev/sda3 swap swap defaults 0 0 proc /proc proc defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 ''' f = open(localtempdir + '/fstab', 'w') f.write(fstab) f.close() self.runCmd('sudo mv -f ' + localtempdir + '/fstab ' + localtempdir + '/temp/etc/fstab') self.runCmd('sudo chown root:root ' + localtempdir + '/temp/etc/fstab') self.logger.info('fstab Injected') if self.operatingsystem == "centos": os.system('sudo sed -i \'s/enforcing/disabled/g\' ' + localtempdir + '/temp/etc/selinux/config') if ldap: self.configure_ldap(localtempdir) return stat def nimbus_method(self, localtempdir, ldap): #Select kernel version #This is not yet supported as we get always the same kernel stat=0 self.logger.debug("kernel: " + self.kernel) if self.kernel == "None": self.kernel = self.default_nimbus_kernel #Inject the kernel self.logger.info('Retrieving kernel ' + self.kernel) stat=self.runCmd('wget ' + self.http_server + 'kernel/' + self.kernel + '.modules.tar.gz -O ' + localtempdir + '/' + self.kernel + '.modules.tar.gz') if stat==0: self.runCmd('sudo tar xfz ' + localtempdir + '/' + self.kernel + '.modules.tar.gz --directory ' + localtempdir + '/temp/lib/modules/') self.logger.info('Injected kernel ' + self.kernel) # Setup fstab fstab = ''' # Default fstab /dev/sda1 / ext3 defaults,errors=remount-ro 0 0 proc /proc proc defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 ''' f = open(localtempdir + '/fstab', 'w') f.write(fstab) f.close() self.runCmd('sudo mv -f ' + localtempdir + '/fstab ' + localtempdir + '/temp/etc/fstab') self.runCmd('sudo chown root:root ' + localtempdir + '/temp/etc/fstab') self.logger.info('fstab Injected') if self.operatingsystem == "centos": os.system('sudo sed -i \'s/enforcing/disabled/g\' ' + localtempdir + '/temp/etc/selinux/config') os.system('sudo mkdir -p ' + localtempdir + "/temp/root/.ssh") if ldap: self.configure_ldap(localtempdir) return stat def openstack_method(self, localtempdir, ldap): #Select kernel version #This is not yet supported as we get always the same kernel self.logger.debug("kernel: " + self.kernel) if self.kernel == "None": self.kernel = self.default_openstack_kernel #Inject the kernel self.logger.info('Retrieving kernel ' + self.kernel) self.runCmd('wget ' + self.http_server + 'kernel/' + self.kernel + '.modules.tar.gz -O ' + localtempdir + '/' + self.kernel + '.modules.tar.gz') self.runCmd('sudo tar xfz ' + localtempdir + '/' + self.kernel + '.modules.tar.gz --directory ' + localtempdir + '/temp/lib/modules/') self.logger.info('Injected kernel ' + self.kernel) # Setup fstab fstab = ''' # Default fstab /dev/sda1 / ext3 defaults,errors=remount-ro 0 0 proc /proc proc defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 ''' #install sshfs #we need to mount only home directory of user using sshfs. The mount an directory creation can be done before executing the job. we need to inject ssh pub/priv keys f = open(localtempdir + '/fstab', 'w') f.write(fstab) f.close() self.runCmd('sudo mv -f ' + localtempdir + '/fstab ' + localtempdir + '/temp/etc/fstab') self.runCmd('sudo chown root:root ' + localtempdir + '/temp/etc/fstab') self.logger.info('fstab Injected') #install curl just in case if self.operatingsystem == "ubuntu": self.runCmd('sudo chroot ' + localtempdir + '/temp/ apt-get -y install curl cloud-init') cloud_cfg = ''' cloud_type: auto user: root disable_root: 0 preserve_hostname: False ''' f = open(localtempdir + '/cloud.cfg', 'w') f.write(cloud_cfg) f.close() self.runCmd('sudo mv -f ' + localtempdir + '/cloud.cfg ' + localtempdir + '/temp/etc/cloud/cloud.cfg') self.runCmd('sudo chown root:root ' + localtempdir + '/temp/etc/cloud/cloud.cfg') elif self.operatingsystem == "centos": #customize rc.local rc_local = ''' route del -net 169.254.0.0 netmask 255.255.0.0 dev eth0 # load pci hotplug for dynamic disk attach in KVM (for EBS) depmod -a modprobe acpiphp # simple attempt to get the user ssh key using the meta-data service mkdir -p /root/.ssh echo >> /root/.ssh/authorized_keys curl -m 10 -s http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key | grep 'ssh-rsa' >> /root/.ssh/authorized_keys echo "AUTHORIZED_KEYS:" echo "************************" cat /root/.ssh/authorized_keys echo "************************" ''' f_org = open(localtempdir + '/temp/etc/rc.local', 'r') f = open(localtempdir + '/rc.local', 'w') write_remain = False for line in f_org: if (re.search('^#', line) or write_remain): f.write(line) else: f.write(rc_local) write_remain = True f.close() f_org.close() self.runCmd('sudo mv -f ' + localtempdir + '/rc.local ' + localtempdir + '/temp/etc/rc.local') self.runCmd('sudo chroot ' + localtempdir + '/temp/ cp -f /etc/rc.local /etc/rc3.d/../') self.runCmd('sudo chown root:root ' + localtempdir + '/temp/etc/rc.local') self.runCmd('sudo chmod 755 ' + localtempdir + '/temp/etc/rc.local') cmd = 'echo "NOZEROCONF=yes" | sudo tee -a ' + localtempdir + '/temp/etc/sysconfig/network > /dev/null' self.logger.debug(cmd) os.system(cmd) self.runCmd('sudo chroot ' + localtempdir + '/temp/ yum -y install curl') if ldap: self.configure_ldap(localtempdir) def opennebula_method(self, localtempdir, ldap): #Select kernel version #This is not yet supported as we get always the same kernel self.logger.debug("kernel: " + self.kernel) #download vmcontext.sh self.runCmd('sudo wget ' + self.http_server + "/opennebula/" + self.operatingsystem + '/vmcontext.sh -O ' + localtempdir + '/temp/etc/init.d/vmcontext.sh') self.runCmd('sudo chmod +x ' + localtempdir + '/temp/etc/init.d/vmcontext.sh') self.runCmd('sudo chown root:root ' + localtempdir + '/temp/etc/rc.local') device = "sda" rc_local = "" if self.operatingsystem == "ubuntu": #setup vmcontext.sh self.runCmd("sudo sudo chroot " + localtempdir + "/temp ln -s /etc/init.d/vmcontext.sh /etc/rc2.d/S01vmcontext.sh") device = "sda" rc_local = "mount -t iso9660 /dev/sr0 /mnt \n" #delete persisten network rules self.runCmd("sudo rm -f " + localtempdir + "/temp/etc/udev/rules.d/70-persistent-net.rules") if self.kernel == "None": self.kernel = self.default_opennebula_kernel elif self.operatingsystem == "centos": #setup vmcontext.sh self.runCmd("sudo chroot " + localtempdir + "/temp chkconfig --add vmcontext.sh") if self.version == "5": device = "hda" rc_local = "mount -t iso9660 /dev/hdc /mnt \n" elif self.version == "6": device = "sda" rc_local = "mount -t iso9660 /dev/sr0 /mnt \n" #in centos 6 is sr0 self.runCmd("sudo rm -f " + localtempdir + "/temp/etc/udev/rules.d/70-persistent-net.rules") os.system('sudo sed -i \'s/enforcing/disabled/g\' ' + localtempdir + '/temp/etc/selinux/config') if self.kernel == "None": self.kernel = self.default_opennebula_kernel #Inject the kernel self.logger.info('Retrieving kernel ' + self.kernel) self.runCmd('wget ' + self.http_server + 'kernel/' + self.kernel + '.modules.tar.gz -O ' + localtempdir + '/' + self.kernel + '.modules.tar.gz') self.runCmd('sudo tar xfz ' + localtempdir + '/' + self.kernel + '.modules.tar.gz --directory ' + localtempdir + '/temp/lib/modules/') self.logger.info('Injected kernel ' + self.kernel) #customize rc.local rc_local += "if [ -f /mnt/context.sh ]; then \n" rc_local += " . /mnt/init.sh \n" rc_local += "fi \n" rc_local += "umount /mnt \n\n" f_org = open(localtempdir + '/temp/etc/rc.local', 'r') f = open(localtempdir + '/rc.local', 'w') write_remain = False for line in f_org: if (re.search('^#', line) or write_remain): f.write(line) else: f.write(rc_local) write_remain = True f.close() f_org.close() self.runCmd('sudo mv -f ' + localtempdir + '/rc.local ' + localtempdir + '/temp/etc/rc.local') self.runCmd('sudo chown root:root ' + localtempdir + '/temp/etc/rc.local') self.runCmd('sudo chmod 755 ' + localtempdir + '/temp/etc/rc.local') #in centos /etc/rc.local is a symbolink link of /etc/rc.d/rc.local/ os.system('sudo chroot ' + localtempdir + '/temp/ cp -f /etc/rc.local /etc/rc3.d/../') # Setup fstab fstab = "# Default fstab \n " fstab += "/dev/" + device + " / ext3 defaults,errors=remount-ro 0 0 \n" fstab += "proc /proc proc defaults 0 0 \n" fstab += "devpts /dev/pts devpts gid=5,mode=620 0 0 \n" #if ldap: #this is for india # fstab+="149.165.146.145:/users /N/u nfs rw,rsize=1048576,wsize=1048576,intr,nosuid" f = open(localtempdir + '/fstab', 'w') f.write(fstab) f.close() self.runCmd('sudo mv -f ' + localtempdir + '/fstab ' + localtempdir + '/temp/etc/fstab') self.runCmd('sudo chown root:root ' + localtempdir + '/temp/etc/fstab') self.logger.info('fstab Injected') def handle_image(self, image, localtempdir, connstream): #print image success = True """ urlparts = image.split("/") #print urlparts self.logger.debug("urls parts: " + str(urlparts)) if len(urlparts) == 1: nameimg = urlparts[0].split(".")[0] elif len(urlparts) == 2: nameimg = urlparts[1].split(".")[0] else: nameimg = urlparts[len(urlparts) - 1].split(".")[0] self.logger.debug("image name " + nameimg) localtempdir = self.tempdir + "/" + nameimg + "_0" if os.path.isfile(localtempdir): exists = True i = 0 while (exists): aux = fulldestpath + "_" + i.__str__() if os.path.isfile(aux): i += 1 else: exists = False localtempdir = aux + "/" cmd = 'mkdir -p ' + localtempdir self.runCmd(cmd) """ realnameimg = "" self.logger.info('untar file with image and manifest') cmd = "tar xvfz " + image + " -C " + localtempdir self.logger.debug(cmd) p = Popen(cmd.split(' '), stdout=PIPE, stderr=PIPE) std = p.communicate() stat = 0 if len(std[0]) > 0: realnameimg = std[0].split("\n")[0].strip().split(".")[0] if p.returncode != 0: self.logger.error('Command: ' + cmd + ' failed, status: ' + str(p.returncode) + ' --- ' + std[1]) stat = 1 cmd = 'rm -f ' + image status = self.runCmd(cmd) if (stat != 0): msg = "Error: the files were not extracted" self.errormsg(connstream, msg) return False self.manifestname = realnameimg + ".manifest.xml" manifestfile = open(localtempdir + "/" + self.manifestname, 'r') manifest = parse(manifestfile) self.name = "" self.givenname = "" self.operatingsystem = "" self.version = "" self.arch = "" self.name = manifest.getElementsByTagName('name')[0].firstChild.nodeValue.strip() self.givenname = manifest.getElementsByTagName('givenname') self.operatingsystem = manifest.getElementsByTagName('os')[0].firstChild.nodeValue.strip() self.version = manifest.getElementsByTagName('version')[0].firstChild.nodeValue.strip() self.arch = manifest.getElementsByTagName('arch')[0].firstChild.nodeValue.strip() #kernel = manifest.getElementsByTagName('kernel')[0].firstChild.nodeValue.strip() self.logger.debug(self.name + " " + self.operatingsystem + " " + self.version + " " + self.arch) #create rootimg and temp directories cmd = 'mkdir -p ' + localtempdir + '/temp' status = self.runCmd(cmd) if status != 0: msg = "ERROR: creating temp directory inside " + localtempdir self.errormsg(connstream, msg) return False #mount image to extract files cmd = 'sudo mount -o loop ' + localtempdir + '/' + self.name + '.img ' + localtempdir + '/temp' status = self.runCmd(cmd) if status != 0: msg = "ERROR: mounting image" self.errormsg(connstream, msg) return False #Mount proc and pts #runCmd('mount -t proc proc '+localtempdir + '/temp/proc') #runCmd('mount -t devpts devpts '+localtempdir + '/temp/dev/pts') return True def errormsg(self, connstream, msg): self.logger.error(msg) try: connstream.write(msg) connstream.shutdown(socket.SHUT_RDWR) connstream.close() except: self.logger.debug("In errormsg: " + str(sys.exc_info())) self.logger.info("Image Deploy Request DONE") def runCmd(self, cmd): cmdLog = logging.getLogger('DeployIaaS.' + str(os.getpid()) + '.exec') cmdLog.debug(cmd) p = Popen(cmd.split(' '), stdout=PIPE, stderr=PIPE) std = p.communicate() status = 0 if len(std[0]) > 0: cmdLog.debug('stdout: ' + std[0]) cmdLog.debug('stderr: ' + std[1]) if p.returncode != 0: cmdLog.error('Command: ' + cmd + ' failed, status: ' + str(p.returncode) + ' --- ' + std[1]) status = 1 #sys.exit(p.returncode) return status