예제 #1
0
class MaterialAddFileDialog:
    def materialAddFileDialog(self, configname):
        logging.debug("materialAddFileDialog(): Instantiated")
        self.configname = configname
        self.s = SystemConfigIO()
        self.destinationPath = os.path.join(
            self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'],
            self.configname, "Materials")
        widget = QFileDialog()
        filenames = ""
        filenames, _ = QFileDialog.getOpenFileNames(widget, "Choose Material",
                                                    "")
        if len(filenames) > 1:
            successfilenames = self.copyMaterial(filenames)
            return successfilenames
        elif len(filenames) == 1:
            successfilenames = self.copyMaterial(filenames)
            return successfilenames
        else:
            return []
        logging.debug("materialAddFileDialog(): Completed")

    def copyMaterial(self, filenames):
        logging.debug("copyMaterial(): instantiated")
        #self.status = {"vmName" : self.vmName, "adaptorSelected" : self.adaptorSelected}
        #get the first value in adaptorSelected (should always be a number)
        status, successfilenames = MaterialAddingFileDialog(
            None, filenames, self.destinationPath).exec_()
        return successfilenames
예제 #2
0
class HypervisorOpenDialog:
    def hypervisorOpenDialog(self, parent):
        logging.debug("hypervisorOpenDialog(): Instantiated")
        self.parent = parent
        self.s = SystemConfigIO()
        result = self.openHypervisor(self.s.getConfig()["VBOX"]["VBOX_PATH"])
        logging.debug("hypervisorOpenDialog(): Completed")
        return result

    def openHypervisor(self, pathToHypervisor):
        logging.debug("openHypervisor(): instantiated")
        result = HypervisorOpeningDialog(self.parent, pathToHypervisor).exec_()
        return result
예제 #3
0
class ExperimentActionDialog:
    def experimentActionDialog(self, configname, actionname, itype="", name=""):
        logging.debug("experimentActionDialog(): Instantiated")
        self.configname = configname
        self.s = SystemConfigIO()
        self.destinationPath = os.path.join(self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'])
        ouputstr = self.experimentAction(actionname, itype, name)
        logging.debug("experimentActionDialog(): Completed")
        return ouputstr

    def experimentAction(self, actionname, itype, name):
        logging.debug("experimentAction(): instantiated")
        status, outputstr = ExperimentActioningDialog(None, self.configname, actionname, itype, name).exec_()
        return outputstr
예제 #4
0
class MaterialRemoveFileDialog:
    def materialRemoveFileDialog(self, configname, materialname):
        logging.debug("materialRemoveFileDialog(): Instantiated")
        self.configname = configname
        self.materialname = materialname
        self.s = SystemConfigIO()
        self.destinationPath = os.path.join(
            self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'],
            self.configname, "Materials")
        successfilenames = self.removeMaterial(materialname)
        logging.debug("materialRemoveFileDialog(): Completed")
        return successfilenames

    def removeMaterial(self, materialname):
        logging.debug("removeMaterial(): instantiated")
        (status, successfilenames) = MaterialRemovingFileDialog(
            None, materialname, self.destinationPath).exec_()
        return successfilenames
예제 #5
0
class ExperimentAddDialog:
    def experimentAddDialog(self, parent, existingconfignames):
        logging.debug("experimentAddDialog(): Instantiated")
        self.parent = parent
        self.s = SystemConfigIO()
        self.destinationPath = os.path.join(
            self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'])
        self.configname, ok = QInputDialog.getText(
            parent, 'Experiment',
            'Enter new experiment name \r\n(non alphanumeric characters will be removed)'
        )
        if ok:
            #standardize and remove invalid characters
            self.configname = ''.join(e for e in self.configname
                                      if e.isalnum())
            #check to make sure the name doesn't already exist
            if self.configname in existingconfignames:
                QMessageBox.warning(
                    self.parent, "Name Exists",
                    "The experiment name specified already exists",
                    QMessageBox.Ok)
                return None
            ##Otherwise, create the folders for this and return the name so that it can be added to the main GUI window
            successfilenames = self.addExperiment()
            logging.debug("experimentAddDialog(): Completed")
            if len(successfilenames) > 0:
                return self.configname
        return None

    def addExperiment(self):
        logging.debug("copyMaterial(): instantiated")
        #self.status = {"vmName" : self.vmName, "adaptorSelected" : self.adaptorSelected}
        #get the first value in adaptorSelected (should always be a number)
        status, successfoldernames, successfilenames = ExperimentAddingDialog(
            None, self.configname, self.destinationPath).exec_()
        return successfilenames
예제 #6
0
class ExperimentConfigIO:

    __singleton_lock = threading.Lock()
    __singleton_instance = None

    @classmethod
    def getInstance(cls):
        logging.debug("getInstance() ExperimentConfigIO: instantiated")
        if not cls.__singleton_instance:
            with cls.__singleton_lock:
                if not cls.__singleton_instance:
                    cls.__singleton_instance = cls()
        return cls.__singleton_instance

    def __init__(self):
        #Virtually private constructor
        self.s = SystemConfigIO()
        self.rolledoutjson = {}
        self.config_jsondata = {}
        self.config_rdp_userpass = {}

    def storeConfigRDPBrokerCreds(self, configname, username, password, url,
                                  method):
        logging.debug(
            "ExperimentConfigIO: getExperimentXMLFileData(): instantiated")
        self.config_rdp_userpass[configname] = (username, password, url,
                                                method)

    def getConfigRDPBrokerCreds(self, configname):
        logging.debug(
            "ExperimentConfigIO: getExperimentXMLFileData(): instantiated")
        if configname in self.config_rdp_userpass:
            return self.config_rdp_userpass[configname]
        return None

    def getExperimentXMLFileData(self, configname, force_refresh=False):
        logging.debug(
            "ExperimentConfigIO: getExperimentXMLFileData(): instantiated")
        if configname in self.config_jsondata:
            if force_refresh == False:
                return self.config_jsondata[configname]
        try:
            xmlconfigfile = os.path.join(
                self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'],
                configname, "Experiments", configname + ".xml")
            with open(xmlconfigfile) as fd:
                jsondata = xmltodict.parse(fd.read(), process_namespaces=True)
            self.config_jsondata[configname] = jsondata
            return jsondata
        except FileNotFoundError:
            logging.error(
                "Error in getExperimentXMLFileData(): File not found: " +
                str(xmlconfigfile))
            return None
        except Exception:
            logging.error(
                "Error in getExperimentXMLFileData(): An error occured ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None

    def getExperimentServerInfo(self, configname):
        logging.debug(
            "ExperimentConfigIO: getExperimentXMLFileData(): instantiated")
        jsondata = self.getExperimentJSONFileData(configname)
        vmserverip = None
        rdpbroker = None
        chatserver = None
        users_file = None
        if "xml" in jsondata:
            if "testbed-setup" in jsondata["xml"]:
                if "network-config" in jsondata["xml"]["testbed-setup"]:
                    if "vm-server-ip" in jsondata["xml"]["testbed-setup"][
                            "network-config"]:
                        vmserverip = jsondata["xml"]["testbed-setup"][
                            "network-config"]["vm-server-ip"]
                    if "rdp-broker-ip" in jsondata["xml"]["testbed-setup"][
                            "network-config"]:
                        rdpbroker = jsondata["xml"]["testbed-setup"][
                            "network-config"]["rdp-broker-ip"]
                    if "chat-server-ip" in jsondata["xml"]["testbed-setup"][
                            "network-config"]:
                        chatserver = jsondata["xml"]["testbed-setup"][
                            "network-config"]["chat-server-ip"]
                if "vm-set" in jsondata["xml"]["testbed-setup"]:
                    if "vm-set" in jsondata["xml"]["testbed-setup"]:
                        if "users-filename" in jsondata["xml"][
                                "testbed-setup"]["vm-set"]:
                            users_file = jsondata["xml"]["testbed-setup"][
                                "vm-set"]["users-filename"]

        return vmserverip, rdpbroker, chatserver, users_file

    def getExperimentVMRolledOut(self,
                                 configname,
                                 config_jsondata=None,
                                 force_refresh="False"):
        logging.debug(
            "ExperimentConfigIO: getExperimentXMLFileData(): instantiated")
        try:
            if configname in self.rolledoutjson:
                if force_refresh == False:
                    return self.rolledoutjson[configname]

            vmRolledOutList = {}
            if config_jsondata == None or force_refresh:
                config_jsondata = self.getExperimentXMLFileData(
                    configname, force_refresh=True)
            vmServerIP = config_jsondata["xml"]["testbed-setup"][
                "network-config"]["vm-server-ip"]
            rdpBrokerIP = config_jsondata["xml"]["testbed-setup"][
                "network-config"]["rdp-broker-ip"]
            chatServerIP = config_jsondata["xml"]["testbed-setup"][
                "network-config"]["chat-server-ip"]
            vmSet = config_jsondata["xml"]["testbed-setup"]["vm-set"]
            pathToVirtualBox = config_jsondata["xml"]["vbox-setup"][
                "path-to-vboxmanage"]
            numClones = int(vmSet["num-clones"])
            cloneSnapshots = vmSet["clone-snapshots"]
            linkedClones = vmSet["linked-clones"]
            baseGroupname = vmSet["base-groupname"]
            baseOutname = vmSet["base-outname"]
            vrdpBaseport = vmSet["vrdp-baseport"]
            usersFilename = vmSet["users-filename"]

            logging.debug("getExperimentVMRolledOut(): path: " +
                          str(pathToVirtualBox) + " numClones: " +
                          str(numClones) + " linked: " + str(linkedClones) +
                          " baseGroup: " + str(baseGroupname) + " baseOut: " +
                          str(baseOutname) + "vrdpBase: " + str(vrdpBaseport) +
                          " usersFilename: " + str(usersFilename))
            if isinstance(vmSet["vm"], list) == False:
                logging.debug(
                    "getExperimentVMRolledOut(): vmSet only has a single VM; placing into list for compatibility"
                )
                vmSet["vm"] = [vmSet["vm"]]
            #we get the vms in order of group;
            for vm in vmSet["vm"]:
                vmName = vm["name"]
                vmRolledOutList[vmName] = []
                logging.debug(
                    "getExperimentVMRolledOut(): adding data for vm: " +
                    str(vmName))

                startupCmds_reformatted = None
                startupDelay = 0
                #read startup commands
                if "startup" in vm and "cmd" in vm["startup"]:
                    startupCmds_reformatted = {}
                    if "delay" in vm["startup"]:
                        startupDelay = vm["startup"]["delay"]
                    startupcmds = vm["startup"]["cmd"]
                    #if this is not a list, make it one (xml to json limitation)
                    if isinstance(startupcmds, list) == False:
                        startupcmds = [startupcmds]
                    #iterate through each startup command
                    for startupcmd in startupcmds:
                        #if exec does not exist, just quit; can't do anything without it
                        if "exec" not in startupcmd:
                            logging.error(
                                "getExperimentVMRolledOut(): exec tag missing: "
                                + str(startupcmd))
                            continue
                        #set default hypervisor and seq if they aren't specified
                        hypervisor = "vbox"
                        seq = "0"
                        if hypervisor in startupcmd:
                            hypervisor = startupcmd["hypervisor"]
                        if "seq" in startupcmd:
                            seq = startupcmd["seq"]
                        #store the data and allow for duplicate sequences (store as list)
                        if seq not in startupCmds_reformatted:
                            startupCmds_reformatted[seq] = [
                                (hypervisor, startupcmd["exec"])
                            ]
                        else:
                            startupCmds_reformatted[seq].append[(
                                hypervisor, startupcmd["exec"])]

                #get names for clones
                myBaseOutname = baseOutname
                for i in range(1, numClones + 1):
                    cloneVMName = vmName + myBaseOutname + str(i)
                    cloneGroupName = "/" + baseGroupname + "/Set" + str(i)

                    # intnet adaptors
                    internalnets = vm["internalnet-basename"]
                    cloneNetNum = 1
                    logging.debug(
                        "getExperimentVMRolledOut(): Internal net names: " +
                        str(internalnets))
                    cloneNets = []
                    if isinstance(internalnets, list) == False:
                        internalnets = [internalnets]
                    for internalnet in internalnets:
                        cloneNets.append(
                            str(internalnet) + str(myBaseOutname) + str(i))
                        cloneNetNum += 1
                    # vrdp setup, if enabled include the port in the returned json
                    vrdpEnabled = vm["vrdp-enabled"]
                    if vrdpEnabled != None and vrdpEnabled == 'true':
                        vrdpBaseport = str(int(vrdpBaseport))
                        vmRolledOutList[vmName].append({
                            "name":
                            cloneVMName,
                            "group-name":
                            cloneGroupName,
                            "networks":
                            cloneNets,
                            "vrdpEnabled":
                            vrdpEnabled,
                            "vrdpPort":
                            vrdpBaseport,
                            "baseGroupName":
                            baseGroupname,
                            "groupNum":
                            str(i),
                            "vm-server-ip":
                            vmServerIP,
                            "rdp-broker-ip":
                            rdpBrokerIP,
                            "chat-server-ip":
                            chatServerIP,
                            "clone-snapshots":
                            cloneSnapshots,
                            "linked-clones":
                            linkedClones,
                            "startup-cmds":
                            startupCmds_reformatted,
                            "startup-cmds-delay":
                            startupDelay,
                            "users-filename":
                            usersFilename
                        })
                        #vmRolledOutList[vmName].append({"name": cloneVMName, "group-name": cloneGroupName, "networks": cloneNets, "vrdpEnabled": vrdpEnabled, "vrdpPort": vrdpBaseport, "baseGroupName": baseGroupname, "groupNum": str(i), "vm-server-ip": vmServerIP, "clone-snapshots": cloneSnapshots, "linked-clones": linkedClones, "startup-cmds": startupCmds_reformatted, "startup-cmds-delay": startupDelay, "users-filename": usersFilename})
                        vrdpBaseport = int(vrdpBaseport) + 1
                    #otherwise, don't include vrdp port
                    else:
                        #vmRolledOutList[vmName].append({"name": cloneVMName, "group-name": cloneGroupName, "networks": cloneNets, "vrdpEnabled": vrdpEnabled, "baseGroupName": baseGroupname, "groupNum": str(i), "clone-snapshots": cloneSnapshots, "linked-clones": linkedClones, "startup-cmds": startupCmds_reformatted, "startup-cmds-delay": startupDelay, "users-filename": usersFilename})
                        vmRolledOutList[vmName].append({
                            "name":
                            cloneVMName,
                            "group-name":
                            cloneGroupName,
                            "networks":
                            cloneNets,
                            "vrdpEnabled":
                            vrdpEnabled,
                            "baseGroupName":
                            baseGroupname,
                            "groupNum":
                            str(i),
                            "vm-server-ip":
                            vmServerIP,
                            "clone-snapshots":
                            cloneSnapshots,
                            "linked-clones":
                            linkedClones,
                            "startup-cmds":
                            startupCmds_reformatted,
                            "startup-cmds-delay":
                            startupDelay,
                            "users-filename":
                            usersFilename
                        })

                    logging.debug(
                        "getExperimentVMRolledOut(): finished setting up clone: "
                        + str(vmRolledOutList))
            self.rolledoutjson[configname] = vmRolledOutList, numClones
            return vmRolledOutList, numClones

        except Exception:
            logging.error(
                "Error in getExperimentVMRolledOut(): An error occured. Check that file exists and that it is properly formatted."
            )
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None

    def getValidVMsFromTypeName(self,
                                configname,
                                itype,
                                name,
                                rolledoutjson=None):
        logging.debug("getValidVMsFromTypeName(): instantiated")
        if rolledoutjson == None:
            rolledoutjson = self.getExperimentVMRolledOut(configname)
        #get VMs or sets that we need to start
        validvms = []
        validvmnames = []
        if name == "all":
            #if none was specified, just add all vms to the list
            validvms = self.getExperimentVMListsFromRolledOut(
                configname, rolledoutjson)
            for vm in validvms:
                validvmnames.append(vm["name"])
        elif itype == "set":
            validvms = self.getExperimentVMsInSetFromRolledOut(
                configname, name, rolledoutjson)
            for vm in validvms:
                validvmnames.append(vm)
        elif itype == "template":
            validvms = []
            if name in self.getExperimentVMNamesFromTemplateFromRolledOut(
                    configname, rolledoutjson):
                validvms = self.getExperimentVMNamesFromTemplateFromRolledOut(
                    configname, rolledoutjson)[name]
            for vm in validvms:
                validvmnames.append(vm)
        elif itype == "vm":
            validvmnames.append(name)
        elif itype == "":
            #if none was specified, just add all vms to the list
            validvms = self.getExperimentVMListsFromRolledOut(
                configname, rolledoutjson)
            for vm in validvms:
                validvmnames.append(vm["name"])
        return validvmnames

    def getExperimentVMsInSetFromRolledOut(self,
                                           configname,
                                           set_num,
                                           rolledout_jsondata=None):
        logging.debug(
            "ExperimentConfigIO: getExperimentVMsInSetFromRolledOut(): instantiated"
        )
        sets = self.getExperimentSetDictFromRolledOut(
            configname, rolledout_jsondata=rolledout_jsondata)
        set_num_str = str(set_num)
        if set_num_str not in sets:
            return []
        return sets[set_num_str]

    def getExperimentSetDictFromRolledOut(self,
                                          configname,
                                          rolledout_jsondata=None):
        logging.debug(
            "ExperimentConfigIO: getExperimentSetListsFromJSON(): instantiated"
        )
        if rolledout_jsondata == None:
            logging.debug(
                "ExperimentConfigIO: no json provided, reading from file")
            rolledout_jsondata = self.getExperimentVMRolledOut(
                self, configname)
        (template_vms, num_clones) = rolledout_jsondata
        sets = {}
        for template_vm in template_vms:
            for clone_num in range(num_clones):
                if str(clone_num + 1) not in sets:
                    sets[str(clone_num + 1)] = []
                sets[str(clone_num + 1)].append(
                    template_vms[template_vm][clone_num]["name"])
        return sets

    def getExperimentVMNamesFromTemplateFromRolledOut(self,
                                                      configname,
                                                      rolledout_jsondata=None):
        logging.debug(
            "ExperimentConfigIO: getExperimentVMNamesFromTemplateFromRolledOut(): instantiated"
        )
        if rolledout_jsondata == None:
            logging.debug(
                "getExperimentVMNamesFromTemplateFromRolledOut(): no json provided, reading from file"
            )
            rolledout_jsondata = self.getExperimentVMRolledOut(
                self, configname)
        (template_vms, num_clones) = rolledout_jsondata
        templates = {}
        for template_vm in template_vms:
            if template_vm not in templates:
                templates[template_vm] = []
            for vminfo in template_vms[template_vm]:
                vmname = vminfo["name"]
                templates[template_vm].append(vmname)
        return templates

    def getExperimentVMListsFromRolledOut(self,
                                          configname,
                                          rolledout_jsondata=None):
        logging.debug(
            "ExperimentConfigIO: getExperimentVMListsFromRolledOut(): instantiated"
        )
        if rolledout_jsondata == None:
            logging.debug(
                "getExperimentVMListsFromRolledOut(): no json provided, reading from file"
            )
            rolledout_jsondata = self.getExperimentVMRolledOut(
                self, configname)
        (template_vms, num_clones) = rolledout_jsondata
        vms = []
        for template_vm in template_vms:
            for cloned_vm in template_vms[template_vm]:
                vms.append(cloned_vm)
        return vms

    def getExperimentJSONFileData(self, configname, force_refresh=False):
        logging.debug(
            "ExperimentConfigIO: getExperimentJSONFileData(): instantiated")
        if configname in self.config_jsondata:
            if force_refresh == False:
                return self.config_jsondata[configname]
        try:
            jsonconfigfile = os.path.join(
                self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'],
                configname, "Experiments", configname + ".json")
            with open(jsonconfigfile) as fd:
                jsondata = json.load(fd)
            self.config_jsondata[configname] = jsondata
            return jsondata
        except FileNotFoundError:
            logging.error("getExperimentJSONFileData(): File not found: " +
                          str(jsonconfigfile))
            return None
        except Exception:
            logging.error(
                "Error in getExperimentJSONFileData(): An error occured ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None

    def writeExperimentXMLFileData(self, jsondata, configname):
        logging.debug(
            "ExperimentConfigIO: writeExperimentXMLFileData(): instantiated")
        try:
            xmlconfigfile = os.path.join(
                self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'],
                configname, "Experiments", configname + ".xml")
            with open(xmlconfigfile, 'w') as fd:
                xmltodict.unparse(jsondata, output=fd, pretty=True)
        except Exception:
            logging.error(
                "Error in writeExperimentXMLFileData(): An error occured ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None

    def writeExperimentJSONFileData(self, jsondata, configname):
        logging.debug(
            "ExperimentConfigIO: writeExperimentJSONFileData(): instantiated")
        try:
            jsonconfigfile = os.path.join(
                self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'],
                configname, "Experiments", configname + ".json")
            with open(jsonconfigfile, 'w') as fd:
                json.dump(jsondata, fd, indent=4)
        except Exception:
            logging.error(
                "Error in writeExperimentJSONFileData(): An error occured ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None

    def getExperimentXMLFilenames(self, pathcontains=""):
        logging.debug(
            "ExperimentConfigIO: getExperimentXMLFilenames(): Instantiated")
        try:
            #First get the folds in the experiments directory as specified in the config file
            xmlExperimentFilenames = []
            xmlExperimentNames = []
            experimentpath = os.path.join(
                self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'])
            name_list = os.listdir(experimentpath)
            dirs = []
            for name in name_list:
                fullpath = os.path.join(experimentpath, name)
                if os.path.isdir(fullpath) and (pathcontains in name):
                    dirs.append(fullpath)
            logging.debug("getExperimentXMLFilenames(): Completed " +
                          str(dirs))
            if dirs == None or dirs == []:
                return [xmlExperimentFilenames, xmlExperimentNames]
            #now get the actual xml experiment files
            xmlExperimentFilenames = []
            xmlExperimentNames = []
            for basepath in dirs:
                #basepath e.g., ExperimentData/sample
                xmlExperimentPath = os.path.join(basepath, "Experiments")
                #xmlExperimentPath e.g., ExperimentData/sample/Experiments
                logging.debug("getExperimentXMLFilenames(): looking at dir " +
                              str(xmlExperimentPath))
                if os.path.exists(xmlExperimentPath):
                    xmlNameList = os.listdir(xmlExperimentPath)
                    logging.debug(
                        "getExperimentXMLFilenames(): looking at files " +
                        str(xmlNameList))
                    #xmlNameList e.g., [sample.xml]
                    for name in xmlNameList:
                        fullpath = os.path.join(xmlExperimentPath, name)
                        logging.debug(
                            "getExperimentXMLFilenames(): looking at fullpath "
                            + str(fullpath))
                        if fullpath.endswith(".xml"):
                            xmlExperimentFilenames.append(fullpath)
                            baseNoExt = os.path.basename(name)
                            baseNoExt = os.path.splitext(baseNoExt)[0]
                            xmlExperimentNames.append(baseNoExt)
                            logging.debug(
                                "getExperimentXMLFilenames(): adding " +
                                str(xmlExperimentFilenames) + " " +
                                str(xmlExperimentNames))
            return [xmlExperimentFilenames, xmlExperimentNames]

        except FileNotFoundError:
            logging.error(
                "Error in getExperimentXMLFilenames(): Path not found: " +
                str(experimentpath))
            return None
        except Exception:
            logging.error(
                "Error in getExperimentXMLFilenames(): An error occured ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None
예제 #7
0
class VBoxManage(VMManage):
    def __init__(self, initializeVMManage=True):
        logging.info("VBoxManage.__init__(): instantiated")
        VMManage.__init__(self)
        self.cf = SystemConfigIO()
        self.vmanage_path = self.cf.getConfig()['VBOX']['VMANAGE_PATH']
        # A lock for acces/updates to self.vms
        self.lock = RLock()
        self.vms = {}
        self.tempVMs = {}
        if initializeVMManage:
            self.refreshAllVMInfo()
            result = self.getManagerStatus()["writeStatus"]
            while result != self.MANAGER_IDLE:
                #waiting for manager to finish query...
                result = self.getManagerStatus()["writeStatus"]
                time.sleep(.1)

    def configureVMNet(self, vmName, netNum, netName):
        logging.info("VBoxManage: configureVMNet(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        exists = False
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("configureVMNet(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(vmName))
                return -1
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runConfigureVMNet,
                                 args=(vmName, netNum, netName))
            t.start()
            return 0
        finally:
            self.lock.release()

    def configureVMNets(self, vmName, internalNets):
        logging.info("VBoxManageWin: configureVMNets(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        exists = False
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("configureVMNets(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(vmName))
                return -1
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runConfigureVMNets,
                                 args=(vmName, internalNets))
            t.start()
            return 0
        finally:
            self.lock.release()

    def runConfigureVMNets(self, vmName, internalNets):
        try:
            logging.debug("VBoxManage: runConfigureVMNets(): instantiated")
            self.readStatus = VMManage.MANAGER_READING
            logging.debug("runConfigureVMNets(): adding 1 " +
                          str(self.writeStatus))
            cloneNetNum = 1
            logging.debug(
                "runConfigureVMNets(): Processing internal net names: " +
                str(internalNets))
            vmUUID = ""
            try:
                self.lock.acquire()
                vmUUID = str(self.vms[vmName].UUID)
            finally:
                self.lock.release()
            for internalnet in internalNets:
                vmConfigVMCmd = self.vmanage_path + " modifyvm " + vmUUID + " --nic" + str(
                    cloneNetNum) + " intnet " + " --intnet" + str(
                        cloneNetNum) + " " + str(
                            internalnet) + " --cableconnected" + str(
                                cloneNetNum) + " on "
                logging.debug("runConfigureVMNets(): Running " + vmConfigVMCmd)
                subprocess.check_output(shlex.split(vmConfigVMCmd,
                                                    posix=self.POSIX),
                                        encoding='utf-8')
                cloneNetNum += 1

            logging.debug("runConfigureVMNets(): Thread completed")
        except Exception:
            logging.error("runConfigureVMNets() Error: " + " cmd: " +
                          vmConfigVMCmd)
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.readStatus = VMManage.MANAGER_IDLE
            self.writeStatus -= 1
            logging.debug("runConfigureVMNets(): sub 1 " +
                          str(self.writeStatus))

    def guestCommands(self, vmName, cmds, delay=0):
        logging.debug("VBoxManageWin: guestCommands(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        exists = False
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("guestCommands(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(vmName))
                return -1
            self.guestThreadStatus += 1
            t = threading.Thread(target=self.runGuestCommands,
                                 args=(vmName, cmds, delay))
            t.start()
            return 0
        finally:
            self.lock.release()

    def runGuestCommands(self, vmName, cmds, delay):
        try:
            logging.debug("runGuestCommands(): adding 1 " +
                          str(self.writeStatus))
            cmd = "N/A"
            #if a delay was specified... wait
            time.sleep(int(delay))
            for cmd in cmds:
                vmCmd = self.vmanage_path + " guestcontrol " + str(
                    self.vms[vmName].UUID) + " " + cmd
                logging.debug("runGuestCommands(): Running " + vmCmd)
                p = Popen(shlex.split(vmCmd, posix=self.POSIX),
                          stdout=PIPE,
                          stderr=PIPE,
                          encoding="utf-8")
                while True:
                    out = p.stdout.readline()
                    if out == '' and p.poll() != None:
                        break
                    if out != '':
                        logging.debug("output line: " + out)
                p.wait()

            logging.debug("runGuestCommands(): Thread completed")
        except Exception:
            logging.error("runGuestCommands() Error: " + " cmd: " + cmd)
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.guestThreadStatus -= 1
            logging.debug("runGuestCommands(): sub thread 1 " +
                          str(self.writeStatus))

    def refreshAllVMInfo(self):
        logging.info("VBoxManage: refreshAllVMInfo(): instantiated")
        logging.debug("getListVMS() Starting List VMs thread")
        self.readStatus = VMManage.MANAGER_READING
        self.writeStatus += 1
        t = threading.Thread(target=self.runVMSInfo)
        t.start()

    def refreshVMInfo(self, vmName):
        logging.info("VBoxManage: refreshVMInfo(): instantiated: " +
                     str(vmName))
        logging.debug("refreshVMInfo() refresh VMs thread")
        #check to make sure the vm is known, if not should refresh or check name:
        exists = False
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("refreshVMInfo(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(self.vms))
                return -1
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runVMInfo, args=(vmName, ))
            t.start()
            return 0
        finally:
            self.lock.release()

    def runVMSInfo(self):
        logging.debug("VBoxManageWin: runVMSInfo(): instantiated")
        try:
            vmListCmd = self.vmanage_path + " list vms"
            logging.debug("runVMSInfo(): Collecting VM Names using cmd: " +
                          vmListCmd)
            #clear out the current set
            self.tempVMs = {}
            self.readStatus = VMManage.MANAGER_READING
            logging.debug("runVMSInfo(): adding 1 " + str(self.writeStatus))
            p = Popen(shlex.split(vmListCmd, posix=self.POSIX),
                      stdout=PIPE,
                      stderr=PIPE,
                      encoding="utf-8")
            while True:
                out = p.stdout.readline()
                if out == '' and p.poll() != None:
                    break
                if out != '':
                    splitOut = out.split("{")
                    vm = VM()
                    tmpname = splitOut[0].strip()
                    #has to be at least one character and every name has a start and end quote
                    if len(tmpname) > 2:
                        vm.name = splitOut[0].strip()[1:-1]
                    else:
                        break
                    vm.UUID = splitOut[1].split("}")[0].strip()
                    # logging.debug("UUID: " + vm.UUID)
                    self.tempVMs[vm.name] = vm
            p.wait()
            logging.debug("runVMSInfo(): Thread 1 completed: " + vmListCmd)
            logging.debug("runVMSInfo(): Found # VMS: " +
                          str(len(self.tempVMs)))

            #for each vm, get the machine readable info
            logging.debug("runVMSInfo(): collecting VM extended info")
            vmNum = 1
            vmShowInfoCmd = ""
            for aVM in self.tempVMs:
                logging.debug("runVMSInfo(): collecting # " + str(vmNum) +
                              " of " + str(len(self.tempVMs)) + " : " +
                              str(aVM))
                vmShowInfoCmd = self.vmanage_path + " showvminfo " + str(
                    self.tempVMs[aVM].UUID) + " --machinereadable"
                logging.debug("runVMSInfo(): Running " + vmShowInfoCmd)
                p = Popen(shlex.split(vmShowInfoCmd, posix=self.POSIX),
                          stdout=PIPE,
                          stderr=PIPE,
                          encoding="utf-8")
                while True:
                    out = p.stdout.readline()
                    if out == '' and p.poll() != None:
                        break
                    if out != '':
                        #match example: nic1="none"
                        res = re.match("nic[0-9]+=", out)
                        if res:
                            # logging.debug("Found nic: " + out + " added to " + self.tempVMs[aVM].name)
                            out = out.strip()
                            nicNum = out.split("=")[0][3:]
                            nicType = out.split("=")[1]
                            self.tempVMs[aVM].adaptorInfo[nicNum] = nicType
                        res = re.match("groups=", out)
                        if res:
                            # logging.debug("Found groups: " + out + " added to " + self.tempVMs[aVM].name)
                            self.tempVMs[aVM].groups = out.strip()
                        res = re.match("VMState=", out)
                        if res:
                            # logging.debug("Found vmState: " + out + " added to " + self.tempVMs[aVM].name)
                            state = out.strip().split("\"")[1].split("\"")[0]
                            self.tempVMs[aVM].state = state
                        res = re.match("CurrentSnapshotUUID=", out)
                        if res:
                            # logging.debug("Found snaps: " + out + " added to " + self.tempVMs[aVM].latestSnapUUID)
                            latestSnap = out.strip().split("\"")[1].split(
                                "\"")[0]
                            self.tempVMs[aVM].latestSnapUUID = latestSnap
                p.wait()
                vmNum = vmNum + 1
            try:
                self.lock.acquire()
                self.vms = self.tempVMs
            finally:
                self.lock.release()
            logging.debug("runVMSInfo(): Thread 2 completed: " + vmShowInfoCmd)
        except Exception:
            logging.error("Error in runVMSInfo(): An error occured ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.readStatus = VMManage.MANAGER_IDLE
            self.writeStatus -= 1
            logging.debug("runVMSInfo(): sub 1 " + str(self.writeStatus))

    def runVMInfo(self, vmName):
        logging.debug("VBoxManage: runVMInfo(): instantiated")
        try:
            #run vboxmanage to get vm listing
            #Make sure this one isn't cleared before use too...
            vmListCmd = self.vmanage_path + " list vms"
            logging.debug("runVMInfo(): Collecting VM Names using cmd: " +
                          vmListCmd)
            self.readStatus = VMManage.MANAGER_READING
            logging.debug("runVMInfo(): adding 1 " + str(self.writeStatus))
            p = Popen(shlex.split(vmListCmd, posix=self.POSIX),
                      stdout=PIPE,
                      stderr=PIPE,
                      encoding="utf-8")
            while True:
                out = p.stdout.readline()
                if out == '' and p.poll() != None:
                    break
                if out != '':
                    splitOut = out.split("{")
                    vm = VM()
                    tmpname = splitOut[0].strip()
                    #has to be at least one character and every name has a start and end quote
                    if len(tmpname) > 2:
                        vm.name = splitOut[0].strip()[1:-1]
                    else:
                        break
                    vm.UUID = splitOut[1].split("}")[0].strip()
                    # logging.debug("UUID: " + vm.UUID)
                    self.tempVMs[vm.name] = vm
            p.wait()
            logging.debug("runVMInfo(): Thread 1 completed: " + vmListCmd)
            logging.debug("runVMInfo(): Found # VMS: " +
                          str(len(self.tempVMs)))

            if vmName not in self.tempVMs:
                logging.error("runVMInfo(): VM was not found/registered: " +
                              vmName)
                return

            #get the machine readable info
            logging.debug("runVMInfo(): collecting VM extended info")
            vmShowInfoCmd = ""
            vmShowInfoCmd = self.vmanage_path + " showvminfo " + str(
                self.tempVMs[vmName].UUID) + " --machinereadable"
            logging.debug("runVMInfo(): Running " + vmShowInfoCmd)
            p = Popen(shlex.split(vmShowInfoCmd, posix=self.POSIX),
                      stdout=PIPE,
                      stderr=PIPE,
                      encoding="utf-8")
            while True:
                out = p.stdout.readline()
                if out == '' and p.poll() != None:
                    break
                if out != '':
                    #match example: nic1="none"
                    res = re.match("nic[0-9]+=", out)
                    if res:
                        out = out.strip()
                        nicNum = out.split("=")[0][3:]
                        nicType = out.split("=")[1]
                        self.tempVMs[vmName].adaptorInfo[nicNum] = nicType
                    res = re.match("groups=", out)
                    if res:
                        # logging.debug("Found groups: " + out + " added to " + self.tempVMs[vmName].name)
                        self.tempVMs[vmName].groups = out.strip()
                    res = re.match("VMState=", out)
                    if res:
                        # logging.debug("Found vmState: " + out + " added to " + self.tempVMs[vmName].name)
                        state = out.strip().split("\"")[1].split("\"")[0]
                        self.tempVMs[vmName].state = state
                    res = re.match("CurrentSnapshotUUID=", out)
                    if res:
                        # logging.debug("Found snaps: " + out + " added to " + self.tempVMs[vmName].latestSnapUUID)
                        latestSnap = out.strip().split("\"")[1].split("\"")[0]
                        self.tempVMs[vmName].latestSnapUUID = latestSnap
            p.wait()
            try:
                #Set self.vms to our temporary -- did it this way to save time
                self.lock.acquire()
                logging.debug("VM: " + str(vmName) + "\r\nself.vms: " +
                              str(self.vms) + "\r\nself.tempVMs: " +
                              str(self.tempVMs))
                self.vms[vmName] = self.tempVMs[vmName]
            finally:
                self.lock.release()

            logging.debug("runVMInfo(): Thread 2 completed: " + vmShowInfoCmd)
        except Exception:
            logging.error("Error in runVMInfo(): An error occured ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.readStatus = VMManage.MANAGER_IDLE
            self.writeStatus -= 1
            logging.debug("runVMInfo(): sub 1 " + str(self.writeStatus))

    def runConfigureVMNet(self, vmName, netNum, netName):
        try:
            logging.debug("VBoxManage: runConfigureVMNet(): instantiated")
            self.readStatus = VMManage.MANAGER_READING
            vmUUID = ""
            try:
                self.lock.acquire()
                vmUUID = str(self.vms[vmName].UUID)
            finally:
                self.lock.release()

            logging.debug("runConfigureVMNet(): adding 1 " +
                          str(self.writeStatus))
            vmConfigVMCmd = self.vmanage_path + " modifyvm " + vmUUID + " --nic" + str(
                netNum) + " intnet " + " --intnet" + str(netNum) + " " + str(
                    netName) + " --cableconnected" + str(netNum) + " on "
            logging.debug("runConfigureVMNet(): Running " + vmConfigVMCmd)
            subprocess.check_output(shlex.split(vmConfigVMCmd,
                                                posix=self.POSIX),
                                    encoding='utf-8')

            logging.debug("runConfigureVMNet(): Thread completed")
        except Exception:
            logging.error("runConfigureVMNet() Error: " + " cmd: " +
                          vmConfigVMCmd)
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.readStatus = VMManage.MANAGER_IDLE
            self.writeStatus -= 1
            logging.debug("runConfigureVMNet(): sub 1 " +
                          str(self.writeStatus))

    def runVMCmd(self, cmd):
        logging.debug("VBoxManageWin: runVMCmd(): instantiated")
        try:
            self.readStatus = VMManage.MANAGER_READING
            logging.debug("runVMCmd(): adding 1 " + str(self.writeStatus))
            vmCmd = self.vmanage_path + " " + cmd
            logging.debug("runVMCmd(): Running " + vmCmd)
            p = Popen(shlex.split(vmCmd, posix=self.POSIX),
                      stdout=PIPE,
                      stderr=PIPE,
                      encoding="utf-8")
            while True:
                out = p.stdout.readline()
                if out == '' and p.poll() != None:
                    break
                if out != '':
                    logging.debug("output line: " + out)
            p.wait()

            logging.debug("runVMCmd(): Thread completed")
        except Exception:
            logging.error("runVMCmd() Error: " + " cmd: " + cmd)
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.readStatus = VMManage.MANAGER_IDLE
            self.writeStatus -= 1
            logging.debug("runVMCmd(): sub 1 " + str(self.writeStatus))

    def getVMStatus(self, vmName):
        logging.debug("VBoxManage: getVMStatus(): instantiated " + vmName)
        exists = False
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("getVMStatus(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(vmName))
                return -1
            resVM = self.vms[vmName]
            #Don't want to rely on python objects in case we go with 3rd party clients in the future
            return {
                "vmName": resVM.name,
                "vmUUID": resVM.UUID,
                "setupStatus": resVM.setupStatus,
                "vmState": resVM.state,
                "adaptorInfo": resVM.adaptorInfo,
                "groups": resVM.groups,
                "latestSnapUUID": resVM.latestSnapUUID
            }
        finally:
            self.lock.release()

    def getManagerStatus(self):
        logging.debug("VBoxManage: getManagerStatus(): instantiated")
        vmStatus = {}
        try:
            self.lock.acquire()
            for vmName in self.vms:
                resVM = self.vms[vmName]
                vmStatus[resVM.name] = {
                    "vmUUID": resVM.UUID,
                    "setupStatus": resVM.setupStatus,
                    "vmState": resVM.state,
                    "adaptorInfo": resVM.adaptorInfo,
                    "groups": resVM.groups
                }
        finally:
            self.lock.release()

        return {
            "readStatus": self.readStatus,
            "writeStatus": self.writeStatus,
            "vmstatus": vmStatus
        }

    def importVM(self, filepath):
        logging.debug("VBoxManage: importVM(): instantiated")
        cmd = "import \"" + filepath + "\" --options keepallmacs"
        self.readStatus = VMManage.MANAGER_READING
        self.writeStatus += 1
        t = threading.Thread(target=self.runVMCmd, args=(cmd, ))
        t.start()
        return 0

    def snapshotVM(self, vmName):
        logging.debug("VBoxManage: snapshotVM(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("snapshotVM(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(vmName))
                return -1
            cmd = " snapshot " + str(self.vms[vmName].UUID) + " take snapshot"
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runVMCmd, args=(cmd, ))
            t.start()
            return 0
        finally:
            self.lock.release()

    def exportVM(self, vmName, filepath):
        logging.debug("VBoxManage: exportVM(): instantiated")
        #first remove any quotes that may have been entered before (because we will add some after we add the file and extension)
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("exportVM(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(vmName))
                return -1
            filepath = filepath.replace("\"", "")
            exportfilename = os.path.join(filepath, vmName + ".ova")
            cmd = "export " + self.vms[
                vmName].UUID + " -o \"" + exportfilename + "\" --iso"
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runVMCmd, args=(cmd, ))
            t.start()
            return 0
        finally:
            self.lock.release()

    def startVM(self, vmName):
        logging.debug("VBoxManage: startVM(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("startVM(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(self.vms))
                return -1
            cmd = "startvm " + str(self.vms[vmName].UUID) + " --type headless"
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runVMCmd, args=(cmd, ))
            t.start()
            return 0
        finally:
            self.lock.release()

    def pauseVM(self, vmName):
        logging.debug("VBoxManage: pauseVM(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("pauseVM(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(self.vms))
                return -1
            cmd = "controlvm " + str(self.vms[vmName].UUID) + " pause"
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runVMCmd, args=(cmd, ))
            t.start()
            return 0
        finally:
            self.lock.release()

    def suspendVM(self, vmName):
        logging.debug("VBoxManage: suspendVM(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("suspendVM(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(self.vms))
                return -1
            cmd = "controlvm " + str(self.vms[vmName].UUID) + " savestate"
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runVMCmd, args=(cmd, ))
            t.start()
            return 0
        finally:
            self.lock.release()

    def stopVM(self, vmName):
        logging.debug("VBoxManage: stopVM(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("stopVM(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(self.vms))
                return -1
            cmd = "controlvm " + str(self.vms[vmName].UUID) + " poweroff"
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runVMCmd, args=(cmd, ))
            t.start()
            return 0
        finally:
            self.lock.release()

    def removeVM(self, vmName):
        logging.debug("VBoxManage: removeVM(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("removeVM(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(vmName))
                return -1
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runRemoveVM,
                                 args=(vmName, str(self.vms[vmName].UUID)))
            t.start()
            return 0
        finally:
            self.lock.release()

    def runRemoveVM(self, vmName, vmUUID):
        logging.debug("VBoxManage: runRemoveVM(): instantiated")
        try:
            self.readStatus = VMManage.MANAGER_READING
            logging.debug("runRemoveVM(): adding 1 " + str(self.writeStatus))
            vmCmd = self.vmanage_path + " unregistervm " + vmUUID + " --delete"
            logging.debug("runRemoveVM(): Running " + vmCmd)
            success = False
            p = Popen(shlex.split(vmCmd, posix=self.POSIX),
                      stdout=PIPE,
                      stderr=PIPE,
                      encoding="utf-8")
            while True:
                out = p.stderr.readline()
                if out == '' and p.poll() != None:
                    break
                if out != '':
                    logging.debug("output line: " + out)
                    if "100%" in out:
                        success = True
            p.wait()
            if success:
                try:
                    self.lock.acquire()
                    del self.vms[vmName]
                finally:
                    self.lock.release()

            logging.debug("runRemoveVM(): Thread completed")
        except Exception:
            logging.error("runRemoveVM() Error: " + " vmCmd: " + vmCmd)
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.readStatus = VMManage.MANAGER_IDLE
            self.writeStatus -= 1
            logging.debug("runRemoveVM(): sub 1 " + str(self.writeStatus))

    def cloneVMConfigAll(self,
                         vmName,
                         cloneName,
                         cloneSnapshots,
                         linkedClones,
                         groupName,
                         internalNets,
                         vrdpPort,
                         refreshVMInfo=False):
        logging.debug("VBoxManage: cloneVMConfigAll(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("cloneVMConfigAll(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(self.vms))
                return -1
        finally:
            self.lock.release()

        if refreshVMInfo == True:
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            #runVMInfo obtains it's own lock
            self.runVMInfo(vmName)
        self.readStatus = VMManage.MANAGER_READING
        self.writeStatus += 1
        t = threading.Thread(target=self.runCloneVMConfigAll,
                             args=(vmName, cloneName, cloneSnapshots,
                                   linkedClones, groupName, internalNets,
                                   vrdpPort))
        t.start()
        return 0

    def runCloneVMConfigAll(self, vmName, cloneName, cloneSnapshots,
                            linkedClones, groupName, internalNets, vrdpPort):
        logging.debug("VBoxManage: runCloneVMConfigAll(): instantiated")
        try:
            self.readStatus = VMManage.MANAGER_READING
            logging.debug("runCloneVMConfigAll(): adding 1 " +
                          str(self.writeStatus))
            #first clone
            #Check that vm does exist
            try:
                self.lock.acquire()
                exists = vmName in self.vms
                if not exists:
                    logging.error("runCloneVMConfigAll(): " + vmName +
                                  " not found in list of known vms: \r\n" +
                                  str(vmName))
                    return
            finally:
                self.lock.release()
            # clone the VM
            self.writeStatus += 1
            self.runCloneVM(vmName, cloneName, cloneSnapshots, linkedClones,
                            groupName)

            #netsetup
            try:
                self.lock.acquire()
                exists = cloneName in self.vms
                if not exists:
                    logging.error("runCloneVMConfigAll(): " + cloneName +
                                  " not found in list of known vms: \r\n" +
                                  str(cloneName))
                    return
                else:
                    cloneUUID = str(self.vms[cloneName].UUID)
            finally:
                self.lock.release()

            self.writeStatus += 1
            self.runConfigureVMNets(cloneName, internalNets)

            #vrdp setup (if applicable)
            if vrdpPort != None:
                self.writeStatus += 1
                self.runEnableVRDP(cloneName, vrdpPort)

            #create snap
            snapcmd = self.vmanage_path + " snapshot " + cloneUUID + " take snapshot"
            logging.debug("runCloneVMConfigAll(): Running " + snapcmd)
            p = Popen(shlex.split(snapcmd, posix=self.POSIX),
                      stdout=PIPE,
                      stderr=PIPE,
                      encoding="utf-8")
            while True:
                out = p.stdout.readline()
                if out == '' and p.poll() != None:
                    break
                if out != '':
                    logging.debug("runCloneVMConfigAll(): snapproc out: " +
                                  out)
            p.wait()
            logging.debug("runCloneVMConfigAll(): Thread completed")

        except Exception:
            logging.error(
                "runCloneVMConfigAll(): Error in runCloneVMConfigAll(): An error occured "
            )
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.readStatus = VMManage.MANAGER_IDLE
            self.writeStatus -= 1
            logging.debug("runCloneVMConfigAll(): sub 1 " +
                          str(self.writeStatus))

    def cloneVM(self,
                vmName,
                cloneName,
                cloneSnapshots,
                linkedClones,
                groupName,
                refreshVMInfo=False):
        logging.debug("VBoxManage: cloneVM(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("cloneVM(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(self.vms))
                return -1
        finally:
            self.lock.release()

        if refreshVMInfo == True:
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            #runVMInfo obtains it's own lock
            self.runVMInfo(vmName)
        self.readStatus = VMManage.MANAGER_READING
        self.writeStatus += 1
        t = threading.Thread(target=self.runCloneVM,
                             args=(vmName, cloneName, cloneSnapshots,
                                   linkedClones, groupName))
        t.start()
        return 0

    def runCloneVM(self, vmName, cloneName, cloneSnapshots, linkedClones,
                   groupName):
        logging.debug("VBoxManage: runCloneVM(): instantiated")
        try:
            self.readStatus = VMManage.MANAGER_READING
            logging.debug("runCloneVM(): adding 1 " + str(self.writeStatus))
            #First check that the clone doesn't exist:
            try:
                self.lock.acquire()
                exists = cloneName in self.vms
                if exists:
                    logging.error(
                        "runCloneVM(): A VM with the clone name already exists and is registered... skipping "
                        + str(cloneName))
                    return
                else:
                    vmUUID = str(self.vms[vmName].UUID)
                    vmLatestSnapUUID = str(self.vms[vmName].latestSnapUUID)
            finally:
                self.lock.release()
            ###Only time cloneName is used instead of UUID, because it doesn't yet exist..."
            tmpCloneName = cloneName
            if " " in tmpCloneName and not tmpCloneName.startswith(
                    "\"") and not tmpCloneName.endswith("\""):
                tmpCloneName = "\"" + str(tmpCloneName) + "\""
            #Call runVMCommand
            cloneCmd = self.vmanage_path + " clonevm " + vmUUID + " --register" + " --options=keepallmacs"
            #NOTE, the following logic is not in error. Linked clone can only be created from a snapshot.
            if cloneSnapshots == 'true':
                #linked Clones option requires a cloneSnapshotUUID to be specified
                if linkedClones == 'true' and vmLatestSnapUUID != "":
                    logging.debug("runCloneVM(): using linked clones")
                    cloneCmd += " --options "
                    cloneCmd += " link "
                    cloneCmd += " --snapshot " + vmLatestSnapUUID
                else:
                    cloneCmd += " --mode "
                    cloneCmd += " all "
            #cloneCmd += " --options keepallmacs "
            cloneCmd += " --name "
            cloneCmd += str(tmpCloneName)
            logging.debug("runCloneVM(): executing: " + str(cloneCmd))
            result = subprocess.check_output(shlex.split(cloneCmd,
                                                         posix=self.POSIX),
                                             encoding='utf-8')

            #groupCmd = [self.vmanage_path, "modifyvm", tmpCloneName, "--groups", groupName]
            groupCmd = self.vmanage_path + " modifyvm " + str(
                tmpCloneName) + " --groups " + str(groupName)
            logging.debug("runCloneVM(): placing into group: " +
                          str(groupName))
            logging.debug("runCloneVM(): executing: " + str(groupCmd))
            result = subprocess.check_output(shlex.split(groupCmd,
                                                         posix=self.POSIX),
                                             encoding='utf-8')

            logging.debug("runCloneVM(): Clone Created: " + str(tmpCloneName) +
                          " and placed into group: " + groupName)
            #since we added a VM, now we have to add it to the known list
            logging.debug("runCloneVM(): Adding: " + str(tmpCloneName) +
                          " to known VMs")
            self.writeStatus += 1
            self.runVMInfo(tmpCloneName)

        except Exception:
            logging.error(
                "runCloneVM(): Error in runCloneVM(): An error occured; it could be due to a missing snapshot for the VM"
            )
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.readStatus = VMManage.MANAGER_IDLE
            self.writeStatus -= 1
            logging.debug("runCloneVM(): sub 1 " + str(self.writeStatus))

    def enableVRDPVM(self, vmName, vrdpPort):
        logging.debug("VBoxManage: enabledVRDP(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("enabledVRDP(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(self.vms))
                return -1
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runEnableVRDP,
                                 args=(vmName, vrdpPort))
            t.start()
            return 0
        finally:
            self.lock.release()

    def runEnableVRDP(self, vmName, vrdpPort):
        logging.debug("VBoxManage: runEnabledVRDP(): instantiated")
        try:
            self.readStatus = VMManage.MANAGER_READING
            logging.debug("runEnableVRDP(): adding 1 " + str(self.writeStatus))
            #vrdpCmd = [self.vmanage_path, "modifyvm", vmName, "--vrde", "on", "--vrdeport", str(vrdpPort)]
            vrdpCmd = self.vmanage_path + " modifyvm " + str(
                vmName) + " --vrde " + " on " + " --vrdeport " + str(vrdpPort)
            logging.debug("runEnableVRDP(): setting up vrdp for " + vmName)
            logging.debug("runEnableVRDP(): executing: " + str(vrdpCmd))
            result = subprocess.check_output(shlex.split(vrdpCmd,
                                                         posix=self.POSIX),
                                             encoding='utf-8')
            #now these settings will help against the issue when users
            #can't reconnect after an abrupt disconnect
            #https://www.virtualbox.org/ticket/2963
            vrdpCmd = self.vmanage_path + " modifyvm " + str(
                vmName
            ) + " --vrdemulticon " + " on "  #" --vrdereusecon " + " on " + " --vrdemulticon " + " off"
            logging.debug(
                "runEnableVRDP(): Setting disconnect on new connection for " +
                vmName)
            logging.debug("runEnableVRDP(): executing: " + str(vrdpCmd))
            result = subprocess.check_output(shlex.split(vrdpCmd,
                                                         posix=self.POSIX),
                                             encoding='utf-8')
            logging.debug("runEnableVRDP(): completed")
        except Exception:
            logging.error(
                "runEnableVRDP(): Error in runEnableVRDP(): An error occured ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        finally:
            self.readStatus = VMManage.MANAGER_IDLE
            self.writeStatus -= 1
            logging.debug("runEnableVRDP(): sub 1 " + str(self.writeStatus))

    def restoreLatestSnapVM(self, vmName):
        logging.debug("VBoxManage: restoreLatestSnapVM(): instantiated")
        #check to make sure the vm is known, if not should refresh or check name:
        try:
            self.lock.acquire()
            exists = vmName in self.vms
            if not exists:
                logging.error("restoreLatestSnapVM(): " + vmName +
                              " not found in list of known vms: \r\n" +
                              str(self.vms))
                return -1
            cmd = "snapshot " + str(self.vms[vmName].UUID) + " restorecurrent"
            self.readStatus = VMManage.MANAGER_READING
            self.writeStatus += 1
            t = threading.Thread(target=self.runVMCmd, args=(cmd, ))
            t.start()
            return 0
        finally:
            self.lock.release()
예제 #8
0
class ConfigurationDialog(QDialog):
    def __init__(self, parent):
        logging.debug("ConfigurationDialog(): instantiated")
        super(ConfigurationDialog, self).__init__(parent)
        self.parent = parent
        self.s = SystemConfigIO()
        self.setMinimumWidth(435)

        self.createFormGroupBox()

        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok
                                     | QDialogButtonBox.Cancel)
        buttonBox.accepted.connect(self.accept)
        buttonBox.rejected.connect(self.reject)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.formGroupBox)
        mainLayout.addWidget(buttonBox)
        self.setLayout(mainLayout)

        self.setWindowTitle("RES Configuration")

    def createFormGroupBox(self):
        self.formGroupBox = QGroupBox(
            "Configuration Paths (don't change unless you really know what you're doing)"
        )
        self.layout = QFormLayout()
        self.virtualboxPathLineEdit = QLineEdit(
            self.s.getConfig()["VBOX"]["VBOX_PATH"])
        self.layout.addRow(QLabel("VirtualBox Path:"),
                           self.virtualboxPathLineEdit)
        self.vmanagePathLineEdit = QLineEdit(
            self.s.getConfig()["VBOX"]["VMANAGE_PATH"])
        self.layout.addRow(QLabel("VBoxManage Path:"),
                           self.vmanagePathLineEdit)
        self.experimentPathLineEdit = QLineEdit(
            self.s.getConfig()["EXPERIMENTS"]["EXPERIMENTS_PATH"])
        self.layout.addRow(QLabel("Experiments Data Path:"),
                           self.experimentPathLineEdit)
        self.temporaryPathLineEdit = QLineEdit(
            self.s.getConfig()["EXPERIMENTS"]["TEMP_DATA_PATH"])
        self.layout.addRow(QLabel("Temporary Data Path:"),
                           self.temporaryPathLineEdit)

        self.formGroupBox.setLayout(self.layout)

    def exec_(self):
        logging.debug("ConfigurationDialog(): exec_() instantiated")
        result = super(ConfigurationDialog, self).exec_()
        if str(result) == str(1):
            logging.debug("dialog_response(): OK was pressed")
            # For each value on the form, write it to the config file
            self.s.writeConfig("VBOX", "VBOX_PATH",
                               self.virtualboxPathLineEdit.text())
            self.s.writeConfig("VBOX", "VMANAGE_PATH",
                               self.vmanagePathLineEdit.text())
            self.s.writeConfig("EXPERIMENTS", "EXPERIMENTS_PATH",
                               self.experimentPathLineEdit.text())
            self.s.writeConfig("EXPERIMENTS", "TEMP_DATA_PATH",
                               self.temporaryPathLineEdit.text())
            return (QMessageBox.Ok)
        return (QMessageBox.Cancel)
예제 #9
0
class ConnectionActionDialog(QDialog):

    def __init__(self, parent, configname, actionname, experimentHostname, rdpBrokerHostname="<unspecified>", users_file="", itype="", name=""):
        logging.debug("ConnectionActionDialog(): instantiated")
        super(ConnectionActionDialog, self).__init__(parent)
        self.parent = parent
        self.eco = ExperimentConfigIO.getInstance()
        self.s = SystemConfigIO()
        self.configname = configname
        self.actionname = actionname
        self.experimentHostname = experimentHostname
        self.usersFile = users_file
        self.itype = itype
        self.name = name
        if rdpBrokerHostname.strip() == "":
            self.rdpBrokerHostname = "<unspecified>"
            self.setEnabled(False)
        else:
            self.rdpBrokerHostname = rdpBrokerHostname
        self.cm = ConnectionManage()
        self.setMinimumWidth(450)

        self.createFormGroupBox()
        
        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        buttonBox.accepted.connect(self.accept)
        buttonBox.rejected.connect(self.reject)
        
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.formGroupBox)
        mainLayout.addWidget(buttonBox)
        self.setLayout(mainLayout)
        
        self.setWindowTitle(str(actionname) + " Connection")
        
    def createFormGroupBox(self):
        self.formGroupBox = QGroupBox("Connection Information")
        self.layout = QFormLayout()
        self.experimentHostnameLineEdit = QLineEdit(self.experimentHostname)
        self.experimentHostnameLineEdit.setEnabled(False)
        self.layout.addRow(QLabel("VM Server IP:"), self.experimentHostnameLineEdit)
        self.hostnameLineEdit = QLineEdit(self.rdpBrokerHostname)
        self.hostnameLineEdit.setEnabled(False)
        self.layout.addRow(QLabel("RDP Broker Hostname/IP:"), self.hostnameLineEdit)
        mgmusername = ""
        mgmpassword = ""
        url = "/guacamole"
        method = "HTTP"
        cachedCreds = self.eco.getConfigRDPBrokerCreds(self.configname)
        if cachedCreds != None:
            mgmusername = cachedCreds[0]
            mgmpassword = cachedCreds[1]
            url = cachedCreds[2]
            method = cachedCreds[3]
        self.usernameLineEdit = QLineEdit(mgmusername)
        self.passwordLineEdit = QLineEdit(mgmpassword)
        self.passwordLineEdit.setEchoMode(QLineEdit.Password)
        if self.actionname != "Open":
            self.layout.addRow(QLabel("Management Username:"******"Management Password:"******"URL Path:"), self.urlPathLineEdit)
        self.methodComboBox = QComboBox()
        self.methodComboBox.addItem("HTTP")
        self.methodComboBox.addItem("HTTPS")
        if method == "HTTP":
            self.methodComboBox.setCurrentIndex(0)
        else:
            self.methodComboBox.setCurrentIndex(1)
        self.layout.addRow(QLabel("Method:"), self.methodComboBox)
        
        self.maxConnectionsLineEdit = QLineEdit("1")
        self.heightLineEdit = QLineEdit("1400")
        self.widthLineEdit = QLineEdit("1050")
        self.bitdepthComboBox = QComboBox()
        self.bitdepthComboBox.addItem("256 colors (8-bit)")
        self.bitdepthComboBox.addItem("Low color (16-bit)")
        self.bitdepthComboBox.addItem("True color (24-bit)")
        self.bitdepthComboBox.addItem("True color (32-bit)")
        self.bitdepthComboBox.setCurrentIndex(1)

        self.usersFileLabel = QLineEdit(self.usersFile)
        self.usersFileLabel.setEnabled(False)
        if self.actionname == "Add":
            #Need to make a function to create more than one user to a single instance 
            self.layout.addRow(QLabel("Users File: "), self.usersFileLabel)
            self.layout.addRow(QLabel("Max Connections Per User:"******"Display Height:"), self.heightLineEdit)
            self.layout.addRow(QLabel("Display Width:"), self.widthLineEdit)
            self.layout.addRow(QLabel("Bit Depth:"), self.bitdepthComboBox)
        if self.actionname == "Remove":
            self.layout.addRow(QLabel("Users File: "), self.usersFileLabel)
        self.formGroupBox.setLayout(self.layout)

    def exec_(self):
        logging.debug("ConnectionActionDialog(): exec_() instantiated")
        result = super(ConnectionActionDialog, self).exec_()
        if str(result) == str(1):
            logging.debug("dialog_response(): OK was pressed")
            if self.actionname == "Add":
                bitDepth = self.bitdepthComboBox.currentText()
                if bitDepth == "256 colors (8-bit)":
                    bitDepth = "8"
                elif bitDepth == "Low color (16-bit)":
                    bitDepth = "16"
                elif bitDepth == "True color (24-bit)":
                    bitDepth = "24"
                elif bitDepth == "True color (32-bit)":
                    bitDepth = "32"
                self.args = [self.hostnameLineEdit.text(), self.usernameLineEdit.text(), self.passwordLineEdit.text(), self.urlPathLineEdit.text(), self.methodComboBox.currentText(), "1", self.maxConnectionsLineEdit.text(), self.heightLineEdit.text(), self.widthLineEdit.text(), bitDepth, self.usersFileLabel.text(), self.itype, self.name]
            elif self.actionname == "Remove":
                self.args = [self.hostnameLineEdit.text(), self.usernameLineEdit.text(), self.passwordLineEdit.text(), self.urlPathLineEdit.text(), self.methodComboBox.currentText(), self.usersFileLabel.text(), self.itype, self.name]
            elif self.actionname == "Clear":
                self.args = [self.hostnameLineEdit.text(), self.usernameLineEdit.text(), self.passwordLineEdit.text(), self.urlPathLineEdit.text(), self.methodComboBox.currentText()]
            elif self.actionname == "Refresh":
                self.args = [self.hostnameLineEdit.text(), self.usernameLineEdit.text(), self.passwordLineEdit.text(), self.urlPathLineEdit.text(), self.methodComboBox.currentText()]
            elif self.actionname == "Open":
                #get all of the connections from the currently selected item
                userpool = UserPool()
                usersConns = userpool.generateUsersConns(self.configname, creds_file=self.usersFile)
                vmuser_mapping = {}
                for (username, password) in usersConns:
                    for conn in usersConns[(username, password)]:
                        cloneVMName = conn[0]
                        vmuser_mapping[cloneVMName] = (username, password)
                #get all vms based on what's selected
                tentativeVMs = self.eco.getValidVMsFromTypeName(self.configname, self.itype, self.name)
                #get user/password from selected vms and store those in the list of users to open
                usersToOpen = {}
                for vm in tentativeVMs:
                    if vm in vmuser_mapping:
                        usersToOpen[vmuser_mapping[vm]] = True
                logging.debug(str(usersToOpen))
            else:
                pass
            if self.actionname == "Refresh":
                self.eco.storeConfigRDPBrokerCreds(self.configname, self.usernameLineEdit.text(), self.passwordLineEdit.text(), self.urlPathLineEdit.text(), self.methodComboBox.currentText())
                crd = ConnectionRetrievingDialog(self.parent, self.args).exec_()
                return crd
            elif self.actionname == "Open":
                self.eco.storeConfigRDPBrokerCreds(self.configname, self.usernameLineEdit.text(), self.passwordLineEdit.text(), self.urlPathLineEdit.text(), self.methodComboBox.currentText())
                pathToBrowser = self.s.getConfig()["BROWSER"]["BROWSER_PATH"]
                browserArgs = self.s.getConfig()["BROWSER"]["ARGS"]
                url = self.rdpBrokerHostname+self.urlPathLineEdit.text()
                cod = ConnectionOpeningDialog(self.parent, pathToBrowser, browserArgs, usersToOpen, url, self.methodComboBox.currentText()).exec_()
                return cod
            else:
                self.eco.storeConfigRDPBrokerCreds(self.configname, self.usernameLineEdit.text(), self.passwordLineEdit.text(), self.urlPathLineEdit.text(), self.methodComboBox.currentText())
                cad = ConnectionActioningDialog(self.parent, self.configname, self.actionname, self.args).exec_()
                return (QMessageBox.Ok)
        return (QMessageBox.Cancel)
예제 #10
0
class MainApp(QWidget):
    def __init__(self, parent=None):
        logging.debug("MainApp:init() instantiated")
        super().__init__()
        self.baseWidgets = {}
        self.vmWidgets = {}
        self.materialWidgets = {}
        self.cf = SystemConfigIO()
        self.ec = ExperimentConfigIO.getInstance()
        self.statusBar = QStatusBar()

        self.setMinimumSize(670, 565)
        quit = QAction("Quit", self)
        quit.triggered.connect(self.closeEvent)
        self.setWindowTitle("ARL South RES v0.1")

        self.tabWidget = QtWidgets.QTabWidget()
        self.tabWidget.setGeometry(QtCore.QRect(0, 15, 668, 565))
        self.tabWidget.setObjectName("tabWidget")

        # Configuration Window (windowBox) contains:
        ## windowBoxHLayout contains:
        ###experimentTree (Left)
        ###basedataStackedWidget (Right)
        self.windowWidget = QtWidgets.QWidget()
        self.windowWidget.setObjectName("windowWidget")
        self.windowBoxHLayout = QtWidgets.QHBoxLayout()
        #self.windowBoxHLayout.setContentsMargins(0, 0, 0, 0)
        self.windowBoxHLayout.setObjectName("windowBoxHLayout")
        self.windowWidget.setLayout(self.windowBoxHLayout)

        self.experimentTree = QtWidgets.QTreeWidget()
        self.experimentTree.itemSelectionChanged.connect(self.onItemSelected)
        self.experimentTree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.experimentTree.customContextMenuRequested.connect(
            self.showContextMenu)
        self.experimentTree.setEnabled(True)
        self.experimentTree.setMinimumSize(200, 521)
        self.experimentTree.setMaximumWidth(350)
        self.experimentTree.setObjectName("experimentTree")
        self.experimentTree.headerItem().setText(0, "Experiments")
        self.experimentTree.setSortingEnabled(False)
        self.windowBoxHLayout.addWidget(self.experimentTree)

        self.basedataStackedWidget = QStackedWidget()
        self.basedataStackedWidget.setObjectName("basedataStackedWidget")
        self.basedataStackedWidget.setEnabled(False)
        self.windowBoxHLayout.addWidget(self.basedataStackedWidget)
        self.tabWidget.addTab(self.windowWidget, "Configuration")

        # VBox Actions Tab
        self.experimentActionsWidget = ExperimentActionsWidget(
            statusBar=self.statusBar)
        self.experimentActionsWidget.setObjectName("experimentActionsWidget")
        self.tabWidget.addTab(self.experimentActionsWidget,
                              "Experiment Actions")

        # Remote Connections Tab
        self.connectionWidget = ConnectionWidget(statusBar=self.statusBar)
        self.connectionWidget.setObjectName("connectionsWidget")
        self.tabWidget.addTab(self.connectionWidget, "Remote Connections")

        #Create the bottom layout so that we can access the status bar
        self.bottomLayout = QHBoxLayout()
        self.statusBar.showMessage("Loading GUI...")
        self.bottomLayout.addWidget(self.statusBar)
        self.saveButton = QtWidgets.QPushButton("Save Current")
        self.saveButton.clicked.connect(self.saveExperimentButton)
        self.saveButton.setEnabled(False)
        self.bottomLayout.addWidget(self.saveButton)

        self.populateUi()
        self.setupContextMenus()

        self.initMenu()
        self.mainLayout = QVBoxLayout()
        self.mainLayout.addWidget(self.mainMenu)
        self.mainLayout.addWidget(self.tabWidget)
        self.mainLayout.addLayout(self.bottomLayout)

        self.setLayout(self.mainLayout)
        #self.setCentralWidget(self.outerBox)
        self.tabWidget.setCurrentIndex(0)

        #self.statusBar.showMessage("Finished Loading GUI Components")

        # Plugin Section
        self.tabWidget.addTab(CTFi2GUI(), "CTFi2")

    def readSystemConfig(self):
        logging.debug("MainApp:readSystemConfig() instantiated")
        self.vboxPath = self.cf.getConfig()['VBOX']['VMANAGE_PATH']
        self.experimentPath = self.cf.getConfig(
        )['EXPERIMENTS']['EXPERIMENTS_PATH']
        self.statusBar.showMessage("Finished reading system config")

    def setupContextMenus(self):
        logging.debug("MainApp:setupContextMenus() instantiated")
        # Context menu for blank space
        self.blankTreeContextMenu = QtWidgets.QMenu()
        self.addExperiment = self.blankTreeContextMenu.addAction(
            "New Experiment")
        self.addExperiment.triggered.connect(self.addExperimentActionEvent)
        self.importExperiment = self.blankTreeContextMenu.addAction(
            "Import Experiment from RES archive")
        self.importExperiment.triggered.connect(self.importActionEvent)

        # Experiment context menu
        self.experimentContextMenu = QtWidgets.QMenu()
        self.addVMContextSubMenu = QtWidgets.QMenu()
        self.experimentContextMenu.addMenu(self.addVMContextSubMenu)
        self.addVMContextSubMenu.setTitle("Add")
        self.addVM = self.addVMContextSubMenu.addAction("Virtual Machines")
        self.addVM.triggered.connect(self.addVMActionEvent)
        self.addMaterial = self.addVMContextSubMenu.addAction("Material Files")
        self.addMaterial.triggered.connect(self.addMaterialActionEvent)

        # Add line separator here
        self.removeExperiment = self.experimentContextMenu.addAction(
            "Remove Experiment")
        self.removeExperiment.triggered.connect(
            self.removeExperimentItemActionEvent)
        self.exportExperiment = self.experimentContextMenu.addAction(
            "Export Experiment")
        self.exportExperiment.triggered.connect(self.exportActionEvent)

        # VM/Material context menu
        self.itemContextMenu = QtWidgets.QMenu()
        self.removeItem = self.itemContextMenu.addAction(
            "Remove Experiment Item")
        self.removeItem.triggered.connect(self.removeExperimentItemActionEvent)

    def populateUi(self):
        logging.debug("MainApp:populateUi() instantiated")
        self.statusBar.showMessage("Populating UI")
        self.readSystemConfig()
        #####Create the following based on the config file
        result = self.ec.getExperimentXMLFilenames()
        if result == None:
            return
        [xmlExperimentFilenames, xmlExperimentNames] = result
        if xmlExperimentFilenames == [] or xmlExperimentNames == []:
            self.statusBar.showMessage("No configs found")
            return

        #For all experiment files found
        for configname in xmlExperimentNames:
            ####Read Experiment Config Data and Populate Tree
            self.loadConfigname(configname)
        self.statusBar.showMessage(
            "Completed populating the User Interface from " +
            str(len(xmlExperimentNames)) + " config files read", 6000)

    ###############################

    def loadConfigname(self, configname):
        logging.debug("MainApp(): loadConfigname instantiated")
        logging.info("Reading XML data for " + str(configname))
        jsondata = self.ec.getExperimentXMLFileData(configname)
        self.statusBar.showMessage("Finished reading experiment config")

        ##########testbed-setup data######
        if jsondata == None:
            jsondata = {}
        if "xml" not in jsondata or jsondata["xml"] == None or str(
                jsondata["xml"]).strip() == "":
            jsondata["xml"] = {}
        if "testbed-setup" not in jsondata["xml"]:
            jsondata["xml"]["testbed-setup"] = {}
        if "vm-set" not in jsondata["xml"]["testbed-setup"]:
            jsondata["xml"]["testbed-setup"]["vm-set"] = {}
        #Temporary fix for older xml/json files.
        if "users-filename" not in jsondata["xml"]["testbed-setup"]["vm-set"]:
            jsondata["xml"]["testbed-setup"]["vm-set"]["users-filename"] = ""
        if "rdp-broker-ip" not in jsondata["xml"]["testbed-setup"]["vm-set"]:
            jsondata["xml"]["testbed-setup"]["vm-set"]["rdp-broker-ip"] = ""
        if "chat-server-ip" not in jsondata["xml"]["testbed-setup"]["vm-set"]:
            jsondata["xml"]["testbed-setup"]["vm-set"]["chat-server-ip"] = ""

        configTreeWidgetItem = QtWidgets.QTreeWidgetItem(self.experimentTree)
        configTreeWidgetItem.setText(0, configname)
        self.experimentActionsWidget.addExperimentItem(
            configname, config_jsondata=jsondata)
        self.connectionWidget.addExperimentItem(configname,
                                                config_jsondata=jsondata)
        basejsondata = jsondata["xml"]
        # Base Config Widget
        self.baseWidget = BaseWidget(self, configname, configname,
                                     basejsondata)
        self.baseWidgets[configname] = {
            "BaseWidget": {},
            "VMWidgets": {},
            "MaterialWidgets": {}
        }
        self.baseWidgets[configname]["BaseWidget"] = self.baseWidget
        self.basedataStackedWidget.addWidget(self.baseWidget)

        ##########vm data######
        if "vm" in jsondata["xml"]["testbed-setup"]["vm-set"]:
            vmsjsondata = jsondata["xml"]["testbed-setup"]["vm-set"]["vm"]
            if isinstance(vmsjsondata, list):
                for vm in vmsjsondata:
                    vm_item = QtWidgets.QTreeWidgetItem(configTreeWidgetItem)
                    vmlabel = "V: " + vm["name"]
                    vm_item.setText(0, vmlabel)
                    # VM Config Widget
                    vmWidget = VMWidget(None, configname, vm["name"], vm)
                    self.baseWidgets[configname]["VMWidgets"][
                        vmlabel] = vmWidget
                    self.basedataStackedWidget.addWidget(vmWidget)
            else:
                vm_item = QtWidgets.QTreeWidgetItem(configTreeWidgetItem)
                vmlabel = "V: " + vmsjsondata["name"]
                vm_item.setText(0, vmlabel)
                # VM Config Widget
                vmWidget = VMWidget(None, configname, vmsjsondata["name"],
                                    vmsjsondata)
                self.baseWidgets[configname]["VMWidgets"][vmlabel] = vmWidget
                self.basedataStackedWidget.addWidget(vmWidget)

    ##########material data######
        if "material" in jsondata["xml"]["testbed-setup"]["vm-set"]:
            materialsjsondata = jsondata["xml"]["testbed-setup"]["vm-set"][
                "material"]
            if isinstance(materialsjsondata, list):
                for material in materialsjsondata:
                    material_item = QtWidgets.QTreeWidgetItem(
                        configTreeWidgetItem)
                    materiallabel = "M: " + material["name"]
                    material_item.setText(0, materiallabel)
                    # Material Config Widget
                    materialWidget = MaterialWidget(None, configname,
                                                    material["name"], material)
                    self.baseWidgets[configname]["MaterialWidgets"][
                        materiallabel] = materialWidget
                    self.basedataStackedWidget.addWidget(materialWidget)
            else:
                material_item = QtWidgets.QTreeWidgetItem(configTreeWidgetItem)
                materiallabel = "M: " + materialsjsondata["name"]
                material_item.setText(0, materiallabel)
                # Material Config Widget
                materialWidget = MaterialWidget(None, configname,
                                                materialsjsondata["name"],
                                                materialsjsondata)
                self.baseWidgets[configname]["MaterialWidgets"][
                    materiallabel] = materialWidget
                self.basedataStackedWidget.addWidget(materialWidget)
        logging.debug("MainApp(): Finished loading configname: " +
                      str(configname))

    def onItemSelected(self):
        logging.debug("MainApp:onItemSelected instantiated")
        # Get the selected item
        selectedItem = self.experimentTree.currentItem()
        if selectedItem == None:
            logging.debug("MainApp:onItemSelected no configurations left")
            self.statusBar.showMessage(
                "No configuration items selected or available.")
            return
        self.basedataStackedWidget.setEnabled(True)
        # Now enable the save button
        self.saveButton.setEnabled(True)
        self.saveExperimentMenuButton.setEnabled(True)
        #Check if it's the case that an experiment name was selected
        parentSelectedItem = selectedItem.parent()
        if (parentSelectedItem == None):
            #A base widget was selected
            self.basedataStackedWidget.setCurrentWidget(
                self.baseWidgets[selectedItem.text(0)]["BaseWidget"])
        else:
            #Check if it's the case that a VM Name was selected
            if (selectedItem.text(0)[0] == "V"):
                logging.debug("Setting right widget: " +
                              str(self.baseWidgets[parentSelectedItem.text(0)]
                                  ["VMWidgets"][selectedItem.text(0)]))
                self.basedataStackedWidget.setCurrentWidget(
                    self.baseWidgets[parentSelectedItem.text(0)]["VMWidgets"][
                        selectedItem.text(0)])
            #Check if it's the case that a Material Name was selected
            elif (selectedItem.text(0)[0] == "M"):
                logging.debug("Setting right widget: " +
                              str(self.baseWidgets[parentSelectedItem.text(0)]
                                  ["MaterialWidgets"][selectedItem.text(0)]))
                self.basedataStackedWidget.setCurrentWidget(
                    self.baseWidgets[parentSelectedItem.text(
                        0)]["MaterialWidgets"][selectedItem.text(0)])

    def showContextMenu(self, position):
        logging.debug("MainApp:showContextMenu() instantiated: " +
                      str(position))
        if (self.experimentTree.itemAt(position) == None):
            self.blankTreeContextMenu.popup(
                self.experimentTree.mapToGlobal(position))
        elif (self.experimentTree.itemAt(position).parent() == None):
            self.experimentContextMenu.popup(
                self.experimentTree.mapToGlobal(position))
        else:
            self.itemContextMenu.popup(
                self.experimentTree.mapToGlobal(position))

    def addExperimentActionEvent(self):
        logging.debug("MainApp:addExperimentActionEvent() instantiated")
        configname = ExperimentAddDialog().experimentAddDialog(
            self, self.baseWidgets.keys())

        if configname != None:
            logging.debug(
                "configureVM(): OK pressed and valid configname entered: " +
                str(configname))
        else:
            logging.debug("configureVM(): Cancel pressed or no VM selected")
            return

        ##Now add the item to the tree widget and create the baseWidget
        configTreeWidgetItem = QtWidgets.QTreeWidgetItem(self.experimentTree)
        configTreeWidgetItem.setText(0, configname)
        self.experimentActionsWidget.addExperimentItem(configname)
        self.connectionWidget.addExperimentItem(configname)
        # Base Config Widget
        self.baseWidget = BaseWidget(self, configname, configname)
        self.baseWidgets[configname] = {
            "BaseWidget": {},
            "VMWidgets": {},
            "MaterialWidgets": {}
        }
        self.baseWidgets[configname]["BaseWidget"] = self.baseWidget
        self.basedataStackedWidget.addWidget(self.baseWidget)
        self.statusBar.showMessage("Added new experiment: " + str(configname))

    def importActionEvent(self):
        logging.debug("MainApp:importActionEvent() instantiated")
        #Check if it's the case that an experiment name was selected
        confignamesChosen = PackageImportDialog().packageImportDialog(
            self, self.baseWidgets.keys())
        if confignamesChosen == []:
            logging.debug(
                "importActionEvent(): Canceled or a file could not be imported. make sure file exists."
            )
            return
        #for fileChosen in filesChosen:
        logging.debug(
            "MainApp: importActionEvent(): Files choosen (getting only first): "
            + confignamesChosen)
        firstConfignameChosen = confignamesChosen
        self.loadConfigname(firstConfignameChosen)
        #Add the items to the tree
        self.statusBar.showMessage("Imported " + firstConfignameChosen)

    def addVMActionEvent(self):
        logging.debug("MainApp:addVMActionEvent() instantiated")
        selectedItem = self.experimentTree.currentItem()
        if selectedItem == None:
            logging.debug("MainApp:addVMActionEvent no configurations left")
            self.statusBar.showMessage(
                "Could not add VM. No configuration items selected or available."
            )
            return
        selectedItemName = selectedItem.text(0)
        #Now allow the user to choose the VM:
        (response, vmsChosen) = VMRetrieveDialog(self).exec_()

        if response == QMessageBox.Ok and vmsChosen != None:
            logging.debug("configureVM(): OK pressed and VMs selected " +
                          str(vmsChosen))
        else:
            logging.debug("configureVM(): Cancel pressed or no VM selected")
            return

        if vmsChosen == []:
            logging.debug(
                "configureVM(): Canceled or a file could not be added. Try again later or check permissions"
            )
            return

        for vmChosen in vmsChosen:
            logging.debug("MainApp: addVMActionEvent(): File choosen: " +
                          str(vmChosen))
            #Add the item to the tree
            vmItem = QtWidgets.QTreeWidgetItem(selectedItem)
            vmlabel = "V: " + vmChosen
            vmItem.setText(0, vmlabel)
            # VM Config Widget
            #Now add the item to the stack and list of baseWidgets
            vmjsondata = {"name": vmChosen}
            vmWidget = VMWidget(self, selectedItemName, vmChosen, vmjsondata)
            self.baseWidgets[selectedItemName]["VMWidgets"][vmlabel] = vmWidget
            self.basedataStackedWidget.addWidget(vmWidget)
        #Now add data to the experimentActionWidget associated with the current config
        #Check if it's the case that an experiment name was selected
        parentSelectedItem = selectedItem.parent()
        if parentSelectedItem != None:
            selectedItem = parentSelectedItem
        configname = selectedItem.text(0)
        config_jsondata = self.getWritableData(configname)
        self.experimentActionsWidget.resetExperiment(
            configname, config_jsondata=config_jsondata)
        self.connectionWidget.resetExperiment(configname,
                                              config_jsondata=config_jsondata)
        self.statusBar.showMessage("Added " + str(len(vmsChosen)) +
                                   " VM files to experiment: " +
                                   str(selectedItemName))

    def startHypervisorActionEvent(self):
        logging.debug("MainApp:startHypervisorActionEvent() instantiated")
        logging.debug(
            "MainApp:startHypervisorActionEvent no configurations left")

        # Try to open the hypervisor and check if it worked or not
        result = HypervisorOpenDialog().hypervisorOpenDialog(self)
        if result != "success":
            logging.debug(
                "startHypervisorActionEvent(): Could not start the hypervisor")
            self.statusBar.showMessage("Hypervisor could not be started.")
            return

        self.statusBar.showMessage("Started hypervisor.")

    def addMaterialActionEvent(self):
        logging.debug("MainApp:addMaterialActionEvent() instantiated")
        selectedItem = self.experimentTree.currentItem()
        if selectedItem == None:
            logging.debug(
                "MainApp:addMaterialActionEvent no configurations left")
            self.statusBar.showMessage(
                "Could not add item. No configuration items selected or available."
            )
            return

        selectedItemName = selectedItem.text(0)
        #Check if it's the case that an experiment name was selected
        filesChosen = MaterialAddFileDialog().materialAddFileDialog(
            selectedItemName)
        if filesChosen == []:
            logging.debug(
                "addMaterialActionEvent(): Canceled or a file could not be added. Try again later or check permissions"
            )
            return
        for fileChosen in filesChosen:
            fileChosen = os.path.basename(fileChosen)
            logging.debug("MainApp: addMaterialActionEvent(): File choosen: " +
                          fileChosen)
            #Add the item to the tree
            material_item = QtWidgets.QTreeWidgetItem(selectedItem)
            materiallabel = "M: " + fileChosen
            material_item.setText(0, materiallabel)
            # Material Config Widget
            #Now add the item to the stack and list of baseWidgets
            materialsjsondata = {"name": fileChosen}
            materialWidget = MaterialWidget(self, selectedItemName, fileChosen,
                                            materialsjsondata)
            self.baseWidgets[selectedItem.text(
                0)]["MaterialWidgets"][materiallabel] = materialWidget
            self.basedataStackedWidget.addWidget(materialWidget)
        self.statusBar.showMessage("Added " + str(len(filesChosen)) +
                                   " material files to experiment: " +
                                   str(selectedItemName))

    def removeExperimentItemActionEvent(self):
        logging.debug("MainApp:removeExperimentItemActionEvent() instantiated")
        selectedItem = self.experimentTree.currentItem()
        if selectedItem == None:
            logging.debug("MainApp:onItemSelected no configurations left")
            self.statusBar.showMessage(
                "Could not remove. No configuration items selected or available."
            )
            return

        selectedItemName = selectedItem.text(0)
        #Check if it's the case that an experiment name was selected
        parentSelectedItem = selectedItem.parent()
        if (parentSelectedItem == None):
            #A base widget was selected
            successfilenames = ExperimentRemoveFileDialog(
            ).experimentRemoveFileDialog(selectedItemName)
            if successfilenames == [] or successfilenames == "":
                logging.debug(
                    "removeExperimentItemActionEvent(): Canceled or a file could not be removed. Try again later or check permissions"
                )
                return

            self.experimentTree.invisibleRootItem().removeChild(selectedItem)
            self.basedataStackedWidget.removeWidget(
                self.baseWidgets[selectedItemName]["BaseWidget"])
            del self.baseWidgets[selectedItemName]
            self.experimentActionsWidget.removeExperimentItem(selectedItemName)
            self.experimentActionsWidget.removeExperimentItem(selectedItemName)
            self.statusBar.showMessage("Removed experiment: " +
                                       str(selectedItemName))
        else:
            #Check if it's the case that a VM Name was selected
            if (selectedItem.text(0)[0] == "V"):
                parentSelectedItem.removeChild(selectedItem)
                configname = parentSelectedItem.text(0)
                self.basedataStackedWidget.removeWidget(
                    self.baseWidgets[configname]["VMWidgets"][
                        selectedItem.text(0)])
                del self.baseWidgets[configname]["VMWidgets"][
                    selectedItem.text(0)]
                self.statusBar.showMessage("Removed VM: " +
                                           str(selectedItemName) +
                                           " from experiment: " +
                                           str(parentSelectedItem.text(0)))
                #Also remove from the experiment action widget:
                config_jsondata = self.getWritableData(configname)
                self.experimentActionsWidget.resetExperiment(
                    configname, config_jsondata=config_jsondata)
                self.connectionWidget.resetExperiment(
                    configname, config_jsondata=config_jsondata)

            #Check if it's the case that a Material Name was selected
            elif (selectedItem.text(0)[0] == "M"):
                materialName = selectedItemName.split("M: ")[1]
                successfilenames = MaterialRemoveFileDialog(
                ).materialRemoveFileDialog(parentSelectedItem.text(0),
                                           materialName)
                if successfilenames == []:
                    logging.debug(
                        "Canceled or a file could not be removed. Try again later or check permissions"
                    )
                    return
                parentSelectedItem.removeChild(selectedItem)
                self.basedataStackedWidget.removeWidget(
                    self.baseWidgets[parentSelectedItem.text(
                        0)]["MaterialWidgets"][selectedItem.text(0)])
                del self.baseWidgets[parentSelectedItem.text(
                    0)]["MaterialWidgets"][selectedItem.text(0)]
                self.statusBar.showMessage("Removed Material: " +
                                           str(materialName) +
                                           " from experiment: " +
                                           str(parentSelectedItem.text(0)))

    def exportActionEvent(self):
        logging.debug("MainApp:exportActionEvent() instantiated")
        #Check if it's the case that an experiment name was selected
        selectedItem = self.experimentTree.currentItem()
        if selectedItem == None:
            logging.debug("MainApp:exportActionEvent no configurations left")
            self.statusBar.showMessage(
                "Could not export experiment. No configuration items selected or available."
            )
            return
        selectedItemName = selectedItem.text(0)

        folderChosen = PackageExportDialog().packageExportDialog(
            self, selectedItemName)
        if folderChosen == []:
            logging.debug(
                "exportActionEvent(): Canceled or the experiment could not be exported. Check folder permissions."
            )
            return
        folderChosen = os.path.basename(folderChosen[0])

        logging.debug("MainApp: exportActionEvent(): File choosen: " +
                      folderChosen)
        #Add the items to the tree

        self.statusBar.showMessage("Exported to " + folderChosen)

    def editPathActionEvent(self):
        logging.debug("MainApp:editPathActionEvent() instantiated")
        result = ConfigurationDialog(self).exec_()

    def closeEvent(self, event):
        logging.debug("MainApp:closeEvent(): instantiated")
        logging.debug("closeEvent(): returning accept")
        event.accept()
        qApp.quit()
        return

    def initMenu(self):

        self.mainMenu = QMenuBar()
        self.fileMenu = self.mainMenu.addMenu("File")
        self.editMenu = self.mainMenu.addMenu("Edit")
        self.hypervisorMenu = self.mainMenu.addMenu("Hypervisor")

        self.newExperimentMenuButton = QAction(QIcon(), "New Experiment", self)
        self.newExperimentMenuButton.setShortcut("Ctrl+N")
        self.newExperimentMenuButton.setStatusTip("Create New Experiment")
        self.newExperimentMenuButton.triggered.connect(
            self.addExperimentActionEvent)
        self.fileMenu.addAction(self.newExperimentMenuButton)

        self.importExperimentMenuButton = QAction(QIcon(), "Import Experiment",
                                                  self)
        self.importExperimentMenuButton.setShortcut("Ctrl+I")
        self.importExperimentMenuButton.setStatusTip(
            "Import Experiment from RES File")
        self.importExperimentMenuButton.triggered.connect(
            self.importActionEvent)
        self.fileMenu.addAction(self.importExperimentMenuButton)

        self.saveExperimentMenuButton = QAction(QIcon(), "Save Experiment",
                                                self)
        self.saveExperimentMenuButton.setShortcut("Ctrl+I")
        self.saveExperimentMenuButton.setStatusTip(
            "Save currently selected experiment")
        self.saveExperimentMenuButton.triggered.connect(
            self.saveExperimentButton)
        self.saveExperimentMenuButton.setEnabled(False)
        self.fileMenu.addAction(self.saveExperimentMenuButton)

        self.exitMenuButton = QAction(QIcon("exit24.png"), "Exit", self)
        self.exitMenuButton.setShortcut("Ctrl+Q")
        self.exitMenuButton.setStatusTip("Exit application")
        self.exitMenuButton.triggered.connect(self.close)
        self.fileMenu.addAction(self.exitMenuButton)

        self.pathMenuButton = QAction(QIcon(), "Edit Paths", self)
        self.pathMenuButton.setShortcut("Ctrl+E")
        self.pathMenuButton.setStatusTip("Edit Paths")
        self.pathMenuButton.triggered.connect(self.editPathActionEvent)
        self.editMenu.addAction(self.pathMenuButton)

        self.startHypervisorMenuButton = QAction(QIcon(),
                                                 "Instantiate Hypervisor",
                                                 self)
        self.startHypervisorMenuButton.setShortcut("Ctrl+O")
        self.startHypervisorMenuButton.setStatusTip(
            "Start the hypervisor that is currently configured")
        self.startHypervisorMenuButton.triggered.connect(
            self.startHypervisorActionEvent)
        self.hypervisorMenu.addAction(self.startHypervisorMenuButton)

    def getWritableData(self, configname):
        logging.debug("MainApp: getWritableData() instantiated")
        jsondata = {}
        jsondata["xml"] = {}
        #get baseWidget data
        baseWidget = self.baseWidgets[configname]["BaseWidget"]
        ###TODO: make this work for multiple experiments (current testing assumes only one)
        if isinstance(baseWidget, BaseWidget):
            jsondata["xml"] = baseWidget.getWritableData()
        ###Setup the dictionary
        if "testbed-setup" not in jsondata["xml"]:
            jsondata["xml"]["testbed-setup"] = {}
        if "vm-set" not in jsondata["xml"]["testbed-setup"]:
            jsondata["xml"]["testbed-setup"]["vm-set"] = {}
        if "vm" not in jsondata["xml"]["testbed-setup"]["vm-set"]:
            jsondata["xml"]["testbed-setup"]["vm-set"]["vm"] = []
        if "material" not in jsondata["xml"]["testbed-setup"]["vm-set"]:
            jsondata["xml"]["testbed-setup"]["vm-set"]["material"] = []

        for vmData in self.baseWidgets[configname]["VMWidgets"].values():
            jsondata["xml"]["testbed-setup"]["vm-set"]["vm"].append(
                vmData.getWritableData())
        for materialData in self.baseWidgets[configname][
                "MaterialWidgets"].values():
            jsondata["xml"]["testbed-setup"]["vm-set"]["material"].append(
                materialData.getWritableData())
        return jsondata

    def saveExperimentButton(self):
        logging.debug("MainApp: saveExperiment() instantiated")
        self.saveExperiment()

    def saveExperiment(self, configname=None):
        logging.debug("MainApp: saveExperiment() instantiated")
        selectedItem = self.experimentTree.currentItem()
        if selectedItem == None:
            logging.debug("MainApp:onItemSelected no configurations left")
            self.statusBar.showMessage(
                "Could not save. No configuration items selected or available."
            )
            return
        #Check if it's the case that an experiment name was selected
        parentSelectedItem = selectedItem.parent()
        if parentSelectedItem != None:
            selectedItem = parentSelectedItem
        configname = selectedItem.text(0)
        jsondata = self.getWritableData(configname)

        self.ec.writeExperimentXMLFileData(jsondata, configname)
        self.ec.writeExperimentJSONFileData(jsondata, configname)
        self.ec.getExperimentVMRolledOut(configname,
                                         jsondata,
                                         force_refresh=True)
        res = self.ec.getExperimentServerInfo(configname)
        #Now reset the experimentActions view
        self.experimentActionsWidget.resetExperiment(configname, jsondata)
        self.connectionWidget.resetExperiment(configname, jsondata)
        self.statusBar.showMessage(
            "Succesfully saved experiment file for " + str(configname), 2000)
예제 #11
0
class PackageManageVBox(PackageManage):
    def __init__(self, vmManage, experimentManage):
        logging.debug("PackageManageVBox(): instantiated")
        PackageManage.__init__(self)

        self.vmManage = vmManage
        self.em = experimentManage
        self.s = SystemConfigIO()
        self.s.readConfig()

    #abstractmethod
    def importPackage(self, resfilename, runVagrantProvisionScript=False):
        logging.debug("importPackage(): instantiated")
        t = threading.Thread(target=self.runImportPackage,
                             args=(resfilename, ))
        t.start()
        return 0

    def runImportPackage(self,
                         resfilename,
                         vagrantProvisionScriptfilename=None):
        logging.debug("runImportPackage(): instantiated")
        try:
            self.writeStatus = PackageManage.PACKAGE_MANAGE_IMPORTING
            #Unzip the file contents
            # get path for temporary directory to hold uncompressed files
            logging.debug("runImportPackage(): unzipping contents")
            tmpPathBase = os.path.join(
                self.s.getConfig()['EXPERIMENTS']['TEMP_DATA_PATH'], "import")
            assumedExperimentName = os.path.basename(resfilename)
            assumedExperimentName = os.path.splitext(assumedExperimentName)[0]
            tmpPathBaseImportedExperiment = os.path.join(
                tmpPathBase, assumedExperimentName)
            targetPathBase = os.path.join(
                self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'],
                assumedExperimentName)

            self.unzipWorker(resfilename, tmpPathBase)
            logging.debug("runImportPackage(): completed unzipping contents")
            tmpPathVMs = os.path.join(tmpPathBase, assumedExperimentName,
                                      "VMs")
            #For ova files
            #call vmManage to import VMs as specified in config file; wait and query the vmManage status, and then set the complete status
            # Get all files that end with .ova
            #import and then snapshot
            vmFilenames = []
            if os.path.exists(tmpPathVMs):
                vmFilenames = os.listdir(tmpPathVMs)
            logging.debug("runImportPackage(): Unzipped files: " +
                          str(vmFilenames))
            vmNum = 1
            for vmFilename in vmFilenames:
                if vmFilename.endswith(".ova"):
                    logging.debug("runImportPackage(): Importing " +
                                  str(vmFilename) + " into VirtualBox...")
                logging.debug("Importing VM " + str(vmNum) + " of " +
                              str(len(vmFilenames)))
                #Import the VM using a system call
                self.importVMWorker(os.path.join(tmpPathVMs, vmFilename))
                #since we added a new VM, we have to refresh

                ##TODO: replace with updateVMByName()
                self.vmManage.refreshAllVMInfo()
                result = self.vmManage.getManagerStatus()["writeStatus"]
                while result != self.vmManage.MANAGER_IDLE:
                    #waiting for manager to finish query...
                    result = self.vmManage.getManagerStatus()["writeStatus"]
                    time.sleep(.1)

                #now take a snapshot
                self.snapshotVMWorker(os.path.join(vmFilename[:-4]))
                vmNum = vmNum + 1

            #TODO: move all unzipped files (except ovas) to experiment path)
            #remove experiment from experiment folder if it already exists
            if os.path.exists(tmpPathBaseImportedExperiment) == False:
                logging.error(
                    "Experiment folder not found after decompressing files... Skipping: "
                    + str(tmpPathBaseImportedExperiment))
                self.writeStatus = PackageManage.PACKAGE_MANAGE_COMPLETE
                return None
            logging.debug(
                "runImportPackage(): copying experiment files to experiment folder: "
                + str(targetPathBase))
            if os.path.exists(targetPathBase):
                logging.error(
                    "Experiment path already exists. Removing and copying anyway..."
                    + str(targetPathBase))
                shutil.rmtree(targetPathBase, ignore_errors=True)
            #copy all files to experiment folder
            shutil.copytree(tmpPathBaseImportedExperiment,
                            targetPathBase,
                            ignore=shutil.ignore_patterns("*.ova"))

            #now remove the temporary data folder
            logging.debug("runExportPackage(): removing temporary folder: " +
                          str(tmpPathBaseImportedExperiment))
            if os.path.exists(tmpPathBaseImportedExperiment):
                shutil.rmtree(tmpPathBaseImportedExperiment,
                              ignore_errors=True)
            #double check to see if path was removed or not...
            if os.path.exists(tmpPathBaseImportedExperiment):
                logging.error(
                    "runExportPackage(): Could not remove temporary directory: "
                    + str(tmpPathBaseImportedExperiment))

            self.writeStatus = PackageManage.PACKAGE_MANAGE_COMPLETE
        except FileNotFoundError:
            logging.error("Error in runImportPackage(): File not found")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None
        except:
            logging.error("Error in runImportPackage(): An error occured")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None
        finally:
            self.writeStatus = PackageManage.PACKAGE_MANAGE_COMPLETE
            return None

    def unzipWorker(self, resfilename, tmpOutPath):
        logging.debug("unzipWorker() initiated " + str(resfilename))
        zipPath = resfilename
        block_size = 1048576
        try:
            if os.path.exists(zipPath) == False:
                logging.error(
                    "unzipWorker(): path to zip not found... Skipping..." +
                    str(zipPath))
                return

            z = zipfile.ZipFile(zipPath, 'r')
            outputPath = os.path.join(tmpOutPath)
            members_list = z.namelist()

            currmem_num = 0
            for entry_name in members_list:
                if entry_name[-1] is '/':  # if entry is a directory
                    continue
                logging.debug("unzipWorker(): unzipping " + str(entry_name))
                # increment our file progress counter
                currmem_num = currmem_num + 1

                entry_info = z.getinfo(entry_name)
                i = z.open(entry_name)
                if not os.path.exists(outputPath):
                    os.makedirs(outputPath)

                filename = os.path.join(outputPath, entry_name)
                file_dirname = os.path.dirname(filename)
                if not os.path.exists(file_dirname):
                    os.makedirs(file_dirname)

                o = open(filename, 'wb')
                offset = 0
                int_val = 0
                while True:
                    b = i.read(block_size)
                    offset += len(b)
                    logging.debug("unzipWorker(): file_size: " +
                                  str(float(entry_info.file_size)))
                    logging.debug("unzipWorker(): Offset: " + str(offset))
                    if entry_info.file_size > 0.1:
                        status = float(offset) / float(
                            entry_info.file_size) * 100.
                    else:
                        status = 0
                    logging.debug("unzipWorker(): Status: " + str(status))

                    if int(status) > int_val:
                        int_val = int(status)
                        logging.debug("unzipWorker(): Progress: " +
                                      str(float(int_val / 100.)))
                        logging.debug("unzipWorker(): Processing file " +
                                      str(currmem_num) + "/" +
                                      str(len(members_list)) + ":\r\n" +
                                      entry_name + "\r\nExtracting: " +
                                      str(int_val) + " %")
                    if b == b'':
                        break
                    #logging.debug("unzipWorker(): Writing out file data for file: " + str(entry_name) + " data: " + str(b))
                    o.write(b)
                logging.debug("unzipWorker(): Finished processing file: " +
                              str(entry_name))
                i.close()
                o.close()
        except FileNotFoundError:
            logging.error("Error in unzipWorker(): File not found: ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
        except Exception:
            logging.error("Error in unzipWorker(): An error occured ")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)

    def importVMWorker(self, vmFilepath):
        logging.debug("importVMWorker(): instantiated")
        self.vmManage.importVM(vmFilepath)
        res = self.vmManage.getManagerStatus()
        logging.debug("Waiting for import to complete...")
        while res["writeStatus"] != self.vmManage.MANAGER_IDLE:
            time.sleep(.1)
            logging.debug("Waiting for import vm to complete...")
            res = self.vmManage.getManagerStatus()
        logging.debug("Import complete...")
        logging.debug("importVMWorker(): complete")

    def snapshotVMWorker(self, vmName):
        logging.debug("snapshotVMWorker(): instantiated")
        self.vmManage.snapshotVM(vmName)
        res = self.vmManage.getManagerStatus()
        logging.debug("Waiting for snapshot create to complete...")
        while res["writeStatus"] != self.vmManage.MANAGER_IDLE:
            time.sleep(.1)
            logging.debug("Waiting for snapshot vm to complete...")
            res = self.vmManage.getManagerStatus()
        logging.debug("snapshotVMWorker(): complete")

    #abstractmethod
    def exportPackage(self, experimentname, exportpath):
        logging.debug("exportPackage: instantiated")
        t = threading.Thread(target=self.runExportPackage,
                             args=(
                                 experimentname,
                                 exportpath,
                             ))
        t.start()
        return 0

    def runExportPackage(self, experimentname, exportpath):
        logging.debug("runExportPackage(): instantiated")
        try:
            self.writeStatus = PackageManage.PACKAGE_MANAGE_EXPORTING

            #get/create the temp directory to hold all
            experimentDatapath = os.path.join(
                self.s.getConfig()['EXPERIMENTS']['EXPERIMENTS_PATH'],
                experimentname)
            tmpPathBase = os.path.join(
                self.s.getConfig()['EXPERIMENTS']['TEMP_DATA_PATH'], "export",
                experimentname)
            tmpPathVMs = os.path.join(tmpPathBase, "VMs")
            tmpPathMaterials = os.path.join(tmpPathBase, "Materials")
            tmpPathExperiments = os.path.join(tmpPathBase, "Experiments")
            exportfilename = os.path.join(exportpath, experimentname + ".res")

            #copy all files to temp folder
            logging.debug(
                "runExportPackage(): copying experiment files to temporary folder: "
                + str(tmpPathBase))
            if os.path.exists(tmpPathBase):
                shutil.rmtree(tmpPathBase, ignore_errors=True)
            #have to check again if path was removed or not...
            if os.path.exists(tmpPathBase):
                logging.error(
                    "runExportPackage(): Could not remove directory. Cancelling export: "
                    + str(tmpPathBase))
                self.writeStatus = PackageManage.PACKAGE_MANAGE_IDLE
                return

            shutil.copytree(experimentDatapath, tmpPathBase)
            #create any folders that should exist but don't
            if os.path.exists(tmpPathVMs) == False:
                os.makedirs(tmpPathVMs)
            if os.path.exists(tmpPathMaterials) == False:
                os.makedirs(tmpPathMaterials)
            if os.path.exists(tmpPathExperiments) == False:
                os.makedirs(tmpPathExperiments)

            #export vms that are part of this experiment to the temp folder
            vmNames = self.em.getExperimentVMNames(experimentname)
            logging.debug(
                "runExportPackage(): preparing to export experiment vms: " +
                str(vmNames))
            for vmName in vmNames:
                logging.debug("runExportPackage(): exporting: " + str(vmName))
                self.exportVMWorker(vmName, tmpPathVMs)
                logging.debug("runExportPackage(): exporting of " +
                              str(vmName) + " complete")

            #add to zip everything that exists in the experiment folder
            logging.debug("runExportPackage(): zipping files")
            self.zipWorker(tmpPathBase, exportfilename)
            logging.debug("runExportPackage(): completed zipping files")
            #now remove the temporary data folder
            logging.debug("runExportPackage(): removing temporary folder: " +
                          str(tmpPathBase))
            if os.path.exists(tmpPathBase):
                shutil.rmtree(tmpPathBase, ignore_errors=True)
            #double check to see if path was removed or not...
            if os.path.exists(tmpPathBase):
                logging.error(
                    "runExportPackage(): Could not remove temporary directory: "
                    + str(tmpPathBase))
            self.writeStatus = PackageManage.PACKAGE_MANAGE_COMPLETE
        except FileNotFoundError:
            logging.error("Error in runExportPackage(): File not found")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None
        except:
            logging.error("Error in runExportPackage(): An error occured")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None
        finally:
            self.writeStatus = PackageManage.PACKAGE_MANAGE_COMPLETE
            return None

    def zipWorker(self, pathToAdd, zipfilename):
        logging.debug("zipWorker(): instantiated")
        try:
            logging.debug("zipWorker(): checking if destination path exists")
            zipBasePath = os.path.dirname(zipfilename)
            if os.path.exists(zipBasePath) == False:
                logging.debug(
                    "zipWorker(): destination path does not exist; attempting to create it: "
                    + str(zipBasePath))
                os.makedirs(zipBasePath)
            if os.path.exists(pathToAdd):
                outZipFile = zipfile.ZipFile(zipfilename, 'w',
                                             zipfile.ZIP_STORED)
                # The root directory within the ZIP file.
                rootdir = os.path.basename(pathToAdd)
                for dirpath, dirnames, filenames in os.walk(pathToAdd):
                    for filename in filenames:
                        # Write the file named filename to the archive,
                        # giving it the archive name 'arcname'.
                        filepath = os.path.join(dirpath, filename)
                        parentpath = os.path.relpath(filepath, pathToAdd)
                        arcname = os.path.join(rootdir, parentpath)
                        outZipFile.write(filepath, arcname)
        except FileNotFoundError:
            logging.error("Error in zipWorker(): File not found")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None
        except:
            logging.error("Error in zipWorker(): An error occured")
            exc_type, exc_value, exc_traceback = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_traceback)
            return None
        finally:
            return None

    def exportVMWorker(self, vmName, filepath):
        logging.debug("exportVMWorker(): instantiated")
        self.vmManage.refreshAllVMInfo()
        logging.debug("Waiting for export to complete...")
        result = self.vmManage.getManagerStatus()["writeStatus"]
        while result != self.vmManage.MANAGER_IDLE:
            #waiting for manager to finish query...
            result = self.vmManage.getManagerStatus()["writeStatus"]
            time.sleep(.1)

        self.vmManage.exportVM(vmName, filepath)
        res = self.vmManage.getManagerStatus()
        logging.debug("Waiting for export to complete...")
        while res["writeStatus"] != self.vmManage.MANAGER_IDLE:
            time.sleep(.1)
            logging.debug(
                "exportVMWorker(): Waiting for export vm to complete...")
            res = self.vmManage.getManagerStatus()
        logging.debug("Export complete...")

    #abstractmethod
    def getPackageManageStatus(self):
        logging.debug("getPackageManageStatus(): instantiated")
        return {"readStatus": self.readStatus, "writeStatus": self.writeStatus}