def copyApp(fromdir, to, appDir=None): "Private: Copy application files to the other blades" logdir = os.getenv("ASP_LOGDIR") if logdir: logFileName = logdir + os.sep + 'appdeploy.log' else: logFileName = 'appdeploy.log' try: fout = file(logFileName, 'w+') except: # lack of debug logging should not be fatal fout = None exp = pexpect.spawn('bash') exp.delaybeforesend = 0 # to make sessions a lot faster i = exp.expect([pexpect.TIMEOUT, '[$#>]'], timeout=10) if i == 0: # timeout raise DeployError("Could not start bash session") exp.setwinsize(200, 1024) exp.logfile = fout exp.sendline("export PS1='_expectpromptlocal_'") pshell = psh.Psh(exp, '_expectpromptlocal_') # the "to" argument can be a string containing the node name, slot number or IP address, OR it can be an AmfNodeEntity if type(to) is type(""): node = clusterinfo.ci.nodes[to] else: node = to try: fout2 = file(logFileName + "1", 'w+') except: fout2 = None retries = 0 while retries < 4: retries += 1 tgtexp = pxssh.pxssh() tgtexp.logfile = fout2 log.info("Connecting to %s user %s pw %s" % (node.localIp, node.localUser, node.localPasswd)) try: result = tgtexp.login(node.localIp, node.localUser, node.localPasswd, login_timeout=30) retries = 10000 except pxssh.ExceptionPxssh, e: # Could not synchronize with original prompt if retries > 3: raise DeployError("Cannot connect to %s exception: %s" % (node.localIp, str(e)))
def copyApp(fromdir,to,appDir=None): "Private: Copy application files to the other blades" logdir = os.getenv("ASP_LOGDIR") if logdir: logFileName = logdir + os.sep + 'appdeploy.log' else: logFileName = 'appdeploy.log' try: fout = file(logFileName, 'w+') except: # lack of debug logging should not be fatal fout = None exp = pexpect.spawn('bash') exp.delaybeforesend = 0 # to make sessions a lot faster i = exp.expect([pexpect.TIMEOUT, '[$#>]'], timeout=10) if i==0: # timeout raise DeployError("Could not start bash session") exp.setwinsize(200, 1024) exp.logfile = fout exp.sendline("export PS1='_expectpromptlocal_'") pshell = psh.Psh(exp, '_expectpromptlocal_') # the "to" argument can be a string containing the node name, slot number or IP address, OR it can be an AmfNodeEntity if type(to) is type(""): node = clusterinfo.ci.nodes[to] else: node = to try: fout2 = file(logFileName + "1", 'w+') except: fout2 = None retries = 0 while retries<4: retries += 1 tgtexp = pxssh.pxssh() tgtexp.logfile = fout2 log.info("Connecting to %s user %s pw %s" % (node.localIp, node.localUser, node.localPasswd)) try: result = tgtexp.login(node.localIp, node.localUser, node.localPasswd, login_timeout=30) retries = 10000 except pxssh.ExceptionPxssh,e: # Could not synchronize with original prompt if retries>3: raise DeployError("Cannot connect to %s exception: %s" % (node.localIp,str(e)))
def ReloadApps(self): """Reload the entire DB from archive files in the AppArchiveDir""" self.apps = {} # Clear the old objects # Find all .tgz files in the app dir and process them for base, dirs, files in os.walk(self.appdir): # Blow away all the temporary directories for d in dirs: os.removedirs(base + os.sep + d) for f in files: (noext, ext) = os.path.splitext(f) if ext == ".tgz" or ext == ".tar.gz": try: self.NewAppFile(base + os.sep + f) except Error, e: # Bad file log.info("Bad archive [%s] error: [%s]" % (base + os.sep + f, str(e))) os.remove(base + os.sep + f) except xml2dict.BadConfigFile, e: log.info("Bad archive [%s] error: [%s]" % (base + os.sep + f, str(e)))
def createModel(fromdir,cfg,tgtblades,specifiedNodes): ci = clusterinfo.ci notes = [] errors = [] # Create the SAF AMF entities corresponding to this application for (appname,appcfg) in cfg.items(): integration = appcfg.get("GuiIntegration",None) if integration: install = integration.install exec install in globals(), {} basename = appcfg.get("deployPrefix",appname) # Deploy preferentially with the deployment prefix, but use the app name if there isn't one nameIndex = 0 for existingSg in ci.sgList: if basename + "SGi" in existingSg.name: i = int(existingSg.name.replace(basename + "SGi","")) if i >= nameIndex: nameIndex = i+1 if nameIndex: notes.append("Name %s exists, so appending the numeral %d." % (basename,nameIndex)) compNames = appcfg.programNames.values() nodes = [] ninst = 1 if appcfg.modifiers.has_key('instancesPerNode'): ninst = int(appcfg.modifiers.instancesPerNode) tgtblades = tgtblades * ninst if specifiedNodes: numNodes = len(tgtblades) # We deploy to where the user selected else: numNodes = min(appcfg.totalNodes*ninst,len(tgtblades)) # If no blades chosen, we just deploy the recommended instance(s) if appcfg.redundancyModel in ["2N", "2n", "2"]: log.info("%s uses 2N redundancy model" % basename) appcfg.rModel = "2N" appcfg.activePerSg = 1 appcfg.standbyPerSg = 1 nodesPerSg = 2 elif appcfg.redundancyModel.lower() == "custom": appcfg.rModel = "custom" nodesPerSg = appcfg.totalNodes appcfg.setdefault("activePerSg", nodesPerSg) appcfg.setdefault("standbyPerSg", 0) else: log.info("%s uses N+M redundancy model" % basename) regexp = r'\s*(?P<active>\d+)\s*\+\s*(?P<standby>\d+)\s*' m = re.match(regexp, appcfg.redundancyModel) d = m.groupdict() appcfg.rModel = "M+N" # This configures the SG exactly as suggested in the appcfg.xml # appcfg.activePerSg = int(d['active']) # appcfg.standbyPerSg = int(d['standby']) # nodesPerSg = appcfg.activePerSg + appcfg.standbyPerSg try: # If the # active is not a number then that's ok (see below) active = int(d['active']) except: active = None standby = int(d['standby']) if numNodes<3 and standby>0: # If there's 1 or 2 nodes, use 1+1 appcfg.activePerSg = 1 appcfg.standbyPerSg = 1 elif active is None: # (N+1) Keep the specified # of standby and let active grow. appcfg.standbyPerSg = standby appcfg.activePerSg = max(1,numNodes-standby) # But at least 1 active of course else: # (3+1) Make sure there's at least 1 standby, otherwise keep the ratio intact sbratio = float(standby)/(float(active)+float(standby)) nstandby = int(numNodes*sbratio) if nstandby < 1: nstandby = 1 appcfg.standbyPerSg = nstandby appcfg.activePerSg = max(1,numNodes-standby) # But at least 1 active of course # Assign each node to an SG. if 0: # This logic generates multiple SGs if more nodes are passed than numNodes nodeCnt = 0 while nodeCnt < numNodes: sgNodes = [] for perSg in range(0,nodesPerSg): if nodeCnt >= numNodes: break sgNodes.append(tgtblades[nodeCnt]) nodeCnt +=1 nodes.append(sgNodes) # Make a list of sgs which is therefore a list of lists of nodes else: # Instead, I'm just going to create a bigger SG nodes.append(tgtblades[0:numNodes]) log.debug("Nodes: %s" % str([[x.name for x in y] for y in nodes])) entities = aspAmfCreate.CreateApp(compNames,nodes,appcfg,appcfg.get('work', None),basename, {},nameIndex) return (entities,(errors,notes))
def ConnectToServiceGroups(self, cinfo=None): """ Iterate through the clusterinfo service groups and connect them up to apps and appfiles """ if cinfo is None: cinfo = ci # Clear out the old connections for e in self.entities.values(): e.sg = [] log.info("Connecting App Database to existing Service Groups") for sg in cinfo.sgList: if sg.associatedData: log.info("Service Group %s, data: %s" % (sg.name, sg.associatedData)) try: [appName, appVer] = sg.associatedData.split() except ValueError: # The data isn't in the right format, so it is probably not for me log.info( "Improperly formatted entity associated data [%s]. Expecting 'appName version'." % (sg.associatedData) ) continue # appName = None # skip the rest of the logic for this SG app = self.entities.get(appName, None) if app: log.info("App %s found" % (app.name)) app.sg.append(sg) appFile = app.version.get(appVer, None) sg.app = app if appFile: log.info("AppFile %s found" % (appFile.name)) appFile.sg.append(sg) sg.appVer = appFile else: log.info("Service Group %s, no app data" % (sg.name))
def createModel(fromdir, cfg, tgtblades, specifiedNodes): ci = clusterinfo.ci notes = [] errors = [] # Create the SAF AMF entities corresponding to this application for (appname, appcfg) in cfg.items(): integration = appcfg.get("GuiIntegration", None) if integration: install = integration.install exec install in globals(), {} basename = appcfg.get( "deployPrefix", appname ) # Deploy preferentially with the deployment prefix, but use the app name if there isn't one nameIndex = 0 for existingSg in ci.sgList: if basename + "SGi" in existingSg.name: i = int(existingSg.name.replace(basename + "SGi", "")) if i >= nameIndex: nameIndex = i + 1 if nameIndex: notes.append("Name %s exists, so appending the numeral %d." % (basename, nameIndex)) compNames = appcfg.programNames.values() nodes = [] ninst = 1 if appcfg.modifiers.has_key('instancesPerNode'): ninst = int(appcfg.modifiers.instancesPerNode) tgtblades = tgtblades * ninst if specifiedNodes: numNodes = len(tgtblades) # We deploy to where the user selected else: numNodes = min( appcfg.totalNodes * ninst, len(tgtblades) ) # If no blades chosen, we just deploy the recommended instance(s) if appcfg.redundancyModel in ["2N", "2n", "2"]: log.info("%s uses 2N redundancy model" % basename) appcfg.rModel = "2N" appcfg.activePerSg = 1 appcfg.standbyPerSg = 1 nodesPerSg = 2 elif appcfg.redundancyModel.lower() == "custom": appcfg.rModel = "custom" nodesPerSg = appcfg.totalNodes appcfg.setdefault("activePerSg", nodesPerSg) appcfg.setdefault("standbyPerSg", 0) else: log.info("%s uses N+M redundancy model" % basename) regexp = r'\s*(?P<active>\d+)\s*\+\s*(?P<standby>\d+)\s*' m = re.match(regexp, appcfg.redundancyModel) d = m.groupdict() appcfg.rModel = "M+N" # This configures the SG exactly as suggested in the appcfg.xml # appcfg.activePerSg = int(d['active']) # appcfg.standbyPerSg = int(d['standby']) # nodesPerSg = appcfg.activePerSg + appcfg.standbyPerSg try: # If the # active is not a number then that's ok (see below) active = int(d['active']) except: active = None standby = int(d['standby']) if numNodes < 3 and standby > 0: # If there's 1 or 2 nodes, use 1+1 appcfg.activePerSg = 1 appcfg.standbyPerSg = 1 elif active is None: # (N+1) Keep the specified # of standby and let active grow. appcfg.standbyPerSg = standby appcfg.activePerSg = max( 1, numNodes - standby) # But at least 1 active of course else: # (3+1) Make sure there's at least 1 standby, otherwise keep the ratio intact sbratio = float(standby) / (float(active) + float(standby)) nstandby = int(numNodes * sbratio) if nstandby < 1: nstandby = 1 appcfg.standbyPerSg = nstandby appcfg.activePerSg = max( 1, numNodes - standby) # But at least 1 active of course # Assign each node to an SG. if 0: # This logic generates multiple SGs if more nodes are passed than numNodes nodeCnt = 0 while nodeCnt < numNodes: sgNodes = [] for perSg in range(0, nodesPerSg): if nodeCnt >= numNodes: break sgNodes.append(tgtblades[nodeCnt]) nodeCnt += 1 nodes.append( sgNodes ) # Make a list of sgs which is therefore a list of lists of nodes else: # Instead, I'm just going to create a bigger SG nodes.append(tgtblades[0:numNodes]) log.debug("Nodes: %s" % str([[x.name for x in y] for y in nodes])) entities = aspAmfCreate.CreateApp(compNames, nodes, appcfg, appcfg.get('work', None), basename, {}, nameIndex) return (entities, (errors, notes))