def Parse()

in VMBackup/main/WaagentLib.py [0:0]


    def Parse(self, xmlText):
        """
        Write configuration to file ExtensionsConfig.xml.
        Log plugin specific activity to /var/log/azure/<Publisher>.<PluginName>/<Version>/CommandExecution.log.
        If state is enabled:
            if the plugin is installed:
                if the new plugin's version is higher
                if DisallowMajorVersionUpgrade is false or if true, the version is a minor version do upgrade:
                    download the new archive
                    do the updateCommand.
                    disable the old plugin and remove
                    enable the new plugin
                if the new plugin's version is the same or lower:
                    create the new .settings file from the configuration received
                    do the enableCommand
            if the plugin is not installed:
                download/unpack archive and call the installCommand/Enable
        if state is disabled:
            call disableCommand
        if state is uninstall:
            call uninstallCommand
            remove old plugin directory.
        """
        self.reinitialize()
        self.Util = Util()
        dom = xml.dom.minidom.parseString(xmlText)
        LogIfVerbose(xmlText)
        self.plugin_log_dir = '/var/log/azure'
        if not os.path.exists(self.plugin_log_dir):
            os.mkdir(self.plugin_log_dir)
        try:
            self.Extensions = dom.getElementsByTagName("Extensions")
            pg = dom.getElementsByTagName("Plugins")
            if len(pg) > 0:
                self.Plugins = pg[0].getElementsByTagName("Plugin")
            else:
                self.Plugins = []
            incarnation = self.Extensions[0].getAttribute("goalStateIncarnation")
            SetFileContents('ExtensionsConfig.' + incarnation + '.xml', xmlText)
        except Exception as e:
            Error('ERROR:  Error parsing ExtensionsConfig: {0}.'.format(e))
            return None
        for p in self.Plugins:
            if len(p.getAttribute("location")) < 1:  # this plugin is inside the PluginSettings
                continue
            p.setAttribute('restricted', 'false')
            previous_version = None
            version = p.getAttribute("version")
            name = p.getAttribute("name")
            plog_dir = self.plugin_log_dir + '/' + name + '/' + version
            if not os.path.exists(plog_dir):
                os.makedirs(plog_dir)
            p.plugin_log = plog_dir + '/CommandExecution.log'
            handler = name + '-' + version
            if p.getAttribute("isJson") != 'true':
                Error("Plugin " + name + " version: " + version + " is not a JSON Extension.  Skipping.")
                continue
            Log("Found Plugin: " + name + ' version: ' + version)
            if p.getAttribute("state") == 'disabled' or p.getAttribute("state") == 'uninstall':
                # disable
                zip_dir = LibDir + "/" + name + '-' + version
                mfile = None
                for root, dirs, files in os.walk(zip_dir):
                    for f in files:
                        if f in ('HandlerManifest.json'):
                            mfile = os.path.join(root, f)
                    if mfile != None:
                        break
                if mfile == None:
                    Error('HandlerManifest.json not found.')
                    continue
                manifest = GetFileContents(mfile)
                p.setAttribute('manifestdata', manifest)
                if self.launchCommand(p.plugin_log, name, version, 'disableCommand') == None:
                    self.SetHandlerState(handler, 'Enabled')
                    Error('Unable to disable ' + name)
                    SimpleLog(p.plugin_log, 'ERROR: Unable to disable ' + name)
                else:
                    self.SetHandlerState(handler, 'Disabled')
                    Log(name + ' is disabled')
                    SimpleLog(p.plugin_log, name + ' is disabled')

                # uninstall if needed
                if p.getAttribute("state") == 'uninstall':
                    if self.launchCommand(p.plugin_log, name, version, 'uninstallCommand') == None:
                        self.SetHandlerState(handler, 'Installed')
                        Error('Unable to uninstall ' + name)
                        SimpleLog(p.plugin_log, 'Unable to uninstall ' + name)
                    else:
                        self.SetHandlerState(handler, 'NotInstalled')
                        Log(name + ' uninstallCommand completed .')
                    # remove the plugin
                    Run('rm -rf ' + LibDir + '/' + name + '-' + version + '*')
                    Log(name + '-' + version + ' extension files deleted.')
                    SimpleLog(p.plugin_log, name + '-' + version + ' extension files deleted.')

                continue
                # state is enabled
            # if the same plugin exists and the version is newer or
            # does not exist then download and unzip the new plugin
            plg_dir = None

            latest_version_installed = LooseVersion("0.0")
            for item in os.listdir(LibDir):
                itemPath = os.path.join(LibDir, item)
                if os.path.isdir(itemPath) and name in item:
                    try:
                        # Split plugin dir name with '-' to get intalled plugin name and version
                        sperator = item.rfind('-')
                        if sperator < 0:
                            continue
                        installed_plg_name = item[0:sperator]
                        installed_plg_version = LooseVersion(item[sperator + 1:])

                        # Check installed plugin name and compare installed version to get the latest version installed
                        if installed_plg_name == name and installed_plg_version > latest_version_installed:
                            plg_dir = itemPath
                            previous_version = str(installed_plg_version)
                            latest_version_installed = installed_plg_version
                    except Exception as e:
                        Warn("Invalid plugin dir name: {0} {1}".format(item, e))
                        continue

            if plg_dir == None or LooseVersion(version) > LooseVersion(previous_version):
                location = p.getAttribute("location")
                Log("Downloading plugin manifest: " + name + " from " + location)
                SimpleLog(p.plugin_log, "Downloading plugin manifest: " + name + " from " + location)

                self.Util.Endpoint = location.split('/')[2]
                Log("Plugin server is: " + self.Util.Endpoint)
                SimpleLog(p.plugin_log, "Plugin server is: " + self.Util.Endpoint)

                manifest = self.Util.HttpGetWithoutHeaders(location, chkProxy=True)
                if manifest == None:
                    Error(
                        "Unable to download plugin manifest" + name + " from primary location.  Attempting with failover location.")
                    SimpleLog(p.plugin_log,
                              "Unable to download plugin manifest" + name + " from primary location.  Attempting with failover location.")
                    failoverlocation = p.getAttribute("failoverlocation")
                    self.Util.Endpoint = failoverlocation.split('/')[2]
                    Log("Plugin failover server is: " + self.Util.Endpoint)
                    SimpleLog(p.plugin_log, "Plugin failover server is: " + self.Util.Endpoint)

                    manifest = self.Util.HttpGetWithoutHeaders(failoverlocation, chkProxy=True)
                # if failoverlocation also fail what to do then?
                if manifest == None:
                    AddExtensionEvent(name, WALAEventOperation.Download, False, 0, version,
                                      "Download mainfest fail " + failoverlocation)
                    Log("Plugin manifest " + name + " downloading failed from failover location.")
                    SimpleLog(p.plugin_log, "Plugin manifest " + name + " downloading failed from failover location.")

                filepath = LibDir + "/" + name + '.' + incarnation + '.manifest'
                if os.path.splitext(location)[-1] == '.xml':  # if this is an xml file we may have a BOM
                    if ord(manifest[0]) > 128 and ord(manifest[1]) > 128 and ord(manifest[2]) > 128:
                        manifest = manifest[3:]
                SetFileContents(filepath, manifest)
                # Get the bundle url from the manifest
                p.setAttribute('manifestdata', manifest)
                man_dom = xml.dom.minidom.parseString(manifest)
                bundle_uri = ""
                for mp in man_dom.getElementsByTagName("Plugin"):
                    if GetNodeTextData(mp.getElementsByTagName("Version")[0]) == version:
                        bundle_uri = GetNodeTextData(mp.getElementsByTagName("Uri")[0])
                        break
                if len(mp.getElementsByTagName("DisallowMajorVersionUpgrade")):
                    if GetNodeTextData(mp.getElementsByTagName("DisallowMajorVersionUpgrade")[
                                           0]) == 'true' and previous_version != None and previous_version.split('.')[
                        0] != version.split('.')[0]:
                        Log('DisallowMajorVersionUpgrade is true, this major version is restricted from upgrade.')
                        SimpleLog(p.plugin_log,
                                  'DisallowMajorVersionUpgrade is true, this major version is restricted from upgrade.')
                        p.setAttribute('restricted', 'true')
                        continue
                if len(bundle_uri) < 1:
                    Error("Unable to fetch Bundle URI from manifest for " + name + " v " + version)
                    SimpleLog(p.plugin_log, "Unable to fetch Bundle URI from manifest for " + name + " v " + version)
                    continue
                Log("Bundle URI = " + bundle_uri)
                SimpleLog(p.plugin_log, "Bundle URI = " + bundle_uri)

                # Download the zipfile archive and save as '.zip'
                bundle = self.Util.HttpGetWithoutHeaders(bundle_uri, chkProxy=True)
                if bundle == None:
                    AddExtensionEvent(name, WALAEventOperation.Download, True, 0, version,
                                      "Download zip fail " + bundle_uri)
                    Error("Unable to download plugin bundle" + bundle_uri)
                    SimpleLog(p.plugin_log, "Unable to download plugin bundle" + bundle_uri)
                    continue
                AddExtensionEvent(name, WALAEventOperation.Download, True, 0, version, "Download Success")
                b = bytearray(bundle)
                filepath = LibDir + "/" + os.path.basename(bundle_uri) + '.zip'
                SetFileContents(filepath, b)
                Log("Plugin bundle" + bundle_uri + "downloaded successfully length = " + str(len(bundle)))
                SimpleLog(p.plugin_log,
                          "Plugin bundle" + bundle_uri + "downloaded successfully length = " + str(len(bundle)))

                # unpack the archive
                z = zipfile.ZipFile(filepath)
                zip_dir = LibDir + "/" + name + '-' + version
                z.extractall(zip_dir)
                Log('Extracted ' + bundle_uri + ' to ' + zip_dir)
                SimpleLog(p.plugin_log, 'Extracted ' + bundle_uri + ' to ' + zip_dir)

                # zip no file perms in .zip so set all the scripts to +x
                Run("find " + zip_dir + " -type f | xargs chmod  u+x ")
                # write out the base64 config data so the plugin can process it.
                mfile = None
                for root, dirs, files in os.walk(zip_dir):
                    for f in files:
                        if f in ('HandlerManifest.json'):
                            mfile = os.path.join(root, f)
                    if mfile != None:
                        break
                if mfile == None:
                    Error('HandlerManifest.json not found.')
                    SimpleLog(p.plugin_log, 'HandlerManifest.json not found.')
                    continue
                manifest = GetFileContents(mfile)
                p.setAttribute('manifestdata', manifest)
                # create the status and config dirs
                Run('mkdir -p ' + root + '/status')
                Run('mkdir -p ' + root + '/config')
                # write out the configuration data to goalStateIncarnation.settings file in the config path.
                config = ''
                seqNo = '0'
                if len(dom.getElementsByTagName("PluginSettings")) != 0:
                    pslist = dom.getElementsByTagName("PluginSettings")[0].getElementsByTagName("Plugin")
                    for ps in pslist:
                        if name == ps.getAttribute("name") and version == ps.getAttribute("version"):
                            Log("Found RuntimeSettings for " + name + " V " + version)
                            SimpleLog(p.plugin_log, "Found RuntimeSettings for " + name + " V " + version)

                            config = GetNodeTextData(ps.getElementsByTagName("RuntimeSettings")[0])
                            seqNo = ps.getElementsByTagName("RuntimeSettings")[0].getAttribute("seqNo")
                            break
                if config == '':
                    Log("No RuntimeSettings for " + name + " V " + version)
                    SimpleLog(p.plugin_log, "No RuntimeSettings for " + name + " V " + version)

                SetFileContents(root + "/config/" + seqNo + ".settings", config)
                # create HandlerEnvironment.json
                handler_env = '[{  "name": "' + name + '", "seqNo": "' + seqNo + '", "version": 1.0,  "handlerEnvironment": {    "logFolder": "' + os.path.dirname(
                    p.plugin_log) + '",    "configFolder": "' + root + '/config",    "statusFolder": "' + root + '/status",    "heartbeatFile": "' + root + '/heartbeat.log"}}]'
                SetFileContents(root + '/HandlerEnvironment.json', handler_env)
                self.SetHandlerState(handler, 'NotInstalled')

                cmd = ''
                getcmd = 'installCommand'
                if plg_dir != None and previous_version != None and LooseVersion(version) > LooseVersion(
                        previous_version):
                    previous_handler = name + '-' + previous_version
                    if self.GetHandlerState(previous_handler) != 'NotInstalled':
                        getcmd = 'updateCommand'
                        # disable the old plugin if it exists
                        if self.launchCommand(p.plugin_log, name, previous_version, 'disableCommand') == None:
                            self.SetHandlerState(previous_handler, 'Enabled')
                            Error('Unable to disable old plugin ' + name + ' version ' + previous_version)
                            SimpleLog(p.plugin_log,
                                      'Unable to disable old plugin ' + name + ' version ' + previous_version)
                        else:
                            self.SetHandlerState(previous_handler, 'Disabled')
                            Log(name + ' version ' + previous_version + ' is disabled')
                            SimpleLog(p.plugin_log, name + ' version ' + previous_version + ' is disabled')

                        try:
                            Log("Copy status file from old plugin dir to new")
                            old_plg_dir = plg_dir
                            new_plg_dir = os.path.join(LibDir, "{0}-{1}".format(name, version))
                            old_ext_status_dir = os.path.join(old_plg_dir, "status")
                            new_ext_status_dir = os.path.join(new_plg_dir, "status")
                            if os.path.isdir(old_ext_status_dir):
                                for status_file in os.listdir(old_ext_status_dir):
                                    status_file_path = os.path.join(old_ext_status_dir, status_file)
                                    if os.path.isfile(status_file_path):
                                        shutil.copy2(status_file_path, new_ext_status_dir)
                            mrseq_file = os.path.join(old_plg_dir, "mrseq")
                            if os.path.isfile(mrseq_file):
                                shutil.copy(mrseq_file, new_plg_dir)
                        except Exception as e:
                            Error("Failed to copy status file.")

                isupgradeSuccess = True
                if getcmd == 'updateCommand':
                    if self.launchCommand(p.plugin_log, name, version, getcmd, previous_version) == None:
                        Error('Update failed for ' + name + '-' + version)
                        SimpleLog(p.plugin_log, 'Update failed for ' + name + '-' + version)
                        isupgradeSuccess = False
                    else:
                        Log('Update complete' + name + '-' + version)
                        SimpleLog(p.plugin_log, 'Update complete' + name + '-' + version)

                    # if we updated - call unistall for the old plugin
                    if self.launchCommand(p.plugin_log, name, previous_version, 'uninstallCommand') == None:
                        self.SetHandlerState(previous_handler, 'Installed')
                        Error('Uninstall failed for ' + name + '-' + previous_version)
                        SimpleLog(p.plugin_log, 'Uninstall failed for ' + name + '-' + previous_version)
                        isupgradeSuccess = False
                    else:
                        self.SetHandlerState(previous_handler, 'NotInstalled')
                        Log('Uninstall complete' + previous_handler)
                        SimpleLog(p.plugin_log, 'Uninstall complete' + name + '-' + previous_version)

                    try:
                        # rm old plugin dir
                        if os.path.isdir(plg_dir):
                            shutil.rmtree(plg_dir)
                            Log(name + '-' + previous_version + ' extension files deleted.')
                            SimpleLog(p.plugin_log, name + '-' + previous_version + ' extension files deleted.')
                    except Exception as e:
                        Error("Failed to remove old plugin directory")

                    AddExtensionEvent(name, WALAEventOperation.Upgrade, isupgradeSuccess, 0, previous_version)
                else:  # run install
                    if self.launchCommand(p.plugin_log, name, version, getcmd) == None:
                        self.SetHandlerState(handler, 'NotInstalled')
                        Error('Installation failed for ' + name + '-' + version)
                        SimpleLog(p.plugin_log, 'Installation failed for ' + name + '-' + version)
                    else:
                        self.SetHandlerState(handler, 'Installed')
                        Log('Installation completed for ' + name + '-' + version)
                        SimpleLog(p.plugin_log, 'Installation completed for ' + name + '-' + version)

            # end if plg_dir == none or version > = prev
            # change incarnation of settings file so it knows how to name status...
            zip_dir = LibDir + "/" + name + '-' + version
            mfile = None
            for root, dirs, files in os.walk(zip_dir):
                for f in files:
                    if f in ('HandlerManifest.json'):
                        mfile = os.path.join(root, f)
                if mfile != None:
                    break
            if mfile == None:
                Error('HandlerManifest.json not found.')
                SimpleLog(p.plugin_log, 'HandlerManifest.json not found.')

                continue
            manifest = GetFileContents(mfile)
            p.setAttribute('manifestdata', manifest)
            config = ''
            seqNo = '0'
            if len(dom.getElementsByTagName("PluginSettings")) != 0:
                try:
                    pslist = dom.getElementsByTagName("PluginSettings")[0].getElementsByTagName("Plugin")
                except:
                    Error('Error parsing ExtensionsConfig.')
                    SimpleLog(p.plugin_log, 'Error parsing ExtensionsConfig.')

                    continue
                for ps in pslist:
                    if name == ps.getAttribute("name") and version == ps.getAttribute("version"):
                        Log("Found RuntimeSettings for " + name + " V " + version)
                        SimpleLog(p.plugin_log, "Found RuntimeSettings for " + name + " V " + version)

                        config = GetNodeTextData(ps.getElementsByTagName("RuntimeSettings")[0])
                        seqNo = ps.getElementsByTagName("RuntimeSettings")[0].getAttribute("seqNo")
                        break
            if config == '':
                Error("No RuntimeSettings for " + name + " V " + version)
                SimpleLog(p.plugin_log, "No RuntimeSettings for " + name + " V " + version)

            SetFileContents(root + "/config/" + seqNo + ".settings", config)

            # state is still enable
            if (self.GetHandlerState(handler) == 'NotInstalled'):  # run install first if true
                if self.launchCommand(p.plugin_log, name, version, 'installCommand') == None:
                    self.SetHandlerState(handler, 'NotInstalled')
                    Error('Installation failed for ' + name + '-' + version)
                    SimpleLog(p.plugin_log, 'Installation failed for ' + name + '-' + version)

                else:
                    self.SetHandlerState(handler, 'Installed')
                    Log('Installation completed for ' + name + '-' + version)
                    SimpleLog(p.plugin_log, 'Installation completed for ' + name + '-' + version)

            if (self.GetHandlerState(handler) != 'NotInstalled'):
                if self.launchCommand(p.plugin_log, name, version, 'enableCommand') == None:
                    self.SetHandlerState(handler, 'Installed')
                    Error('Enable failed for ' + name + '-' + version)
                    SimpleLog(p.plugin_log, 'Enable failed for ' + name + '-' + version)

                else:
                    self.SetHandlerState(handler, 'Enabled')
                    Log('Enable completed for ' + name + '-' + version)
                    SimpleLog(p.plugin_log, 'Enable completed for ' + name + '-' + version)

            # this plugin processing is complete
            Log('Processing completed for ' + name + '-' + version)
            SimpleLog(p.plugin_log, 'Processing completed for ' + name + '-' + version)

        # end plugin processing loop
        Log('Finished processing ExtensionsConfig.xml')
        try:
            SimpleLog(p.plugin_log, 'Finished processing ExtensionsConfig.xml')
        except:
            pass

        return self