LCM/scripts/OMS_MetaConfigHelper.py (145 lines of code) (raw):

#!/usr/bin/python import os import sys import imp import subprocess import signal from os.path import basename, dirname, join, realpath, split from imp import load_source from os.path import dirname, isfile, join, realpath pathToCurrentScript = realpath(__file__) pathToCommonScriptsFolder = dirname(pathToCurrentScript) helperLibPath = join(pathToCommonScriptsFolder, 'helperlib.py') helperlib = load_source('helperlib', helperLibPath) conf_path = "/etc/opt/microsoft/omsagent/conf/omsadmin.conf" metamof_path = "/etc/opt/omi/conf/omsconfig/generated_meta_config.mof" agentid_path = "/etc/opt/omi/conf/omsconfig/agentid" omshelper_disable_path = "/etc/opt/omi/conf/omsconfig/omshelper_disable" # Redirect output to our log file pathToCurrentScript = realpath(__file__) pathToCommonScriptsFolder = dirname(pathToCurrentScript) fullPathDSCLogger = os.path.join(pathToCommonScriptsFolder, 'nxDSCLog.py') nxDSCLog = imp.load_source('nxDSCLog', fullPathDSCLogger) logger = nxDSCLog.ConsoleAndFileLogger() sys.stdout = logger proc = None # function to handle ternimation signals received from omsagent. # Child process are created by with a new group id. # We issue termination signal together to all childprocesses with group id. def signal_handler(signalNumber, frame): printVerboseMessage("OMS_MetaconfigHelper.py script received SIGTERM signal.") if proc is not None: printVerboseMessage("Terminating child process by sending SIGTERM signal.") os.killpg(os.getpgid(proc.pid), signal.SIGTERM) else: printVerboseMessage("There is no child process running. It is either completed execution or has not been invoked.") def exitWithError(message, errorCode = 1): errorMessage = "ERROR from OMS_MetaConfigHelper.py: " + message print(errorMessage) sys.exit(errorCode) def printVerboseMessage(message): verboseMessage = "VERBOSE from OMS_MetaConfigHelper.py: " + message print(verboseMessage) def generate_meta_mof(serverurl): return """ instance of MSFT_WebDownloadManager as $MSFT_WebDownloadManager1ref { ResourceID = "[ConfigurationRepositoryWeb]OMSConfigurationManager"; SourceInfo = "GeneratedLocally"; ServerURL = "%s"; }; instance of MSFT_WebReportManager as $MSFT_WebReportManager1ref { SourceInfo = "GeneratedLocally"; ServerURL = "%s"; ResourceID = "[ReportServerWeb]OMSConfigurationManager"; }; instance of MSFT_WebResourceManager as $MSFT_WebResourceManager1ref { SourceInfo = "GeneratedLocally"; ServerURL = "%s"; ResourceID = "[ResourceRepositoryWeb]OMSConfigurationManager"; }; instance of MSFT_DSCMetaConfiguration as $MSFT_DSCMetaConfiguration1ref { RefreshMode = "Pull"; AllowModuleOverwrite = True; RefreshFrequencyMins = 5; RebootNodeIfNeeded = False; ConfigurationModeFrequencyMins = 5; ConfigurationMode = "ApplyAndAutoCorrect"; ResourceModuleManagers = { $MSFT_WebResourceManager1ref }; ReportManagers = { $MSFT_WebReportManager1ref }; ConfigurationDownloadManagers = { $MSFT_WebDownloadManager1ref }; }; instance of OMI_ConfigurationDocument { Version="2.0.0"; MinimumCompatibleVersion = "2.0.0"; }; """ % (serverurl, serverurl, serverurl) def generate_push_meta_mof(): return """ instance of MSFT_DSCMetaConfiguration as $MSFT_DSCMetaConfiguration1ref { RefreshMode = "Push"; AllowModuleOverwrite = True; RefreshFrequencyMins = 30; RebootNodeIfNeeded = True; ConfigurationModeFrequencyMins = 60; ConfigurationMode = "ApplyAndAutoCorrect"; }; instance of OMI_ConfigurationDocument { Version="2.0.0"; MinimumCompatibleVersion = "2.0.0"; }; """ def source_file(filename): retval = dict() f = open(filename, "r") try: contents = f.read() finally: f.close() lines = contents.splitlines() for line in lines: # Find first '='; everything before is key, everything after is value midpoint = line.find("=") if (midpoint == 0 or midpoint == -1): # Skip over lines without = or lines that begin with = continue key = line[:midpoint] value = line[midpoint+1:] retval[key] = value return retval Variables = dict() Defines = [] # register the SIGTERM handler signal.signal(signal.SIGTERM, signal_handler) # Parse command line arguments args = [] optlist = [] for arg in sys.argv[1:]: if len(arg) < 2: # Must be a file args.append(arg) continue if arg[0:2] == "--": tokens = arg[2:].split("=",1) if len(tokens) == 1: # This is a define Defines.append(tokens[0]) Variables[tokens[0]] = "" else: # This is a variable Variables[tokens[0]] = tokens[1] else: args.append(arg) enable_flag = False disable_flag = False if "enable" in Variables: enable_flag = True if "disable" in Variables: disable_flag = True if enable_flag == True and disable_flag == True: exitWithError("Error: Cannot use both disable and enable options at the same time.") if enable_flag == True: printVerboseMessage("Enable flag set to True, setting mof to enabled mode.") if os.path.isfile(omshelper_disable_path): os.remove(omshelper_disable_path) if disable_flag == True: printVerboseMessage("Disable flag set to True, setting mof to disabled mode.") disableFileHandle = open(omshelper_disable_path, "w") try: disableFileHandle.write("a") finally: disableFileHandle.close() os.system("chown omsagent " + omshelper_disable_path) if not os.path.isfile(omshelper_disable_path): # source the omsadmin conf file and get the key/value pairs printVerboseMessage("OMS config path being read: " + os.path.realpath(conf_path)) keyvals = source_file(conf_path) # Looking for DSC_ENDPOINT and AGENT_GUID if "DSC_ENDPOINT" not in keyvals or "AGENT_GUID" not in keyvals: exitWithError("Error: Unable to find needed key/value pairs in " + conf_path) DSC_ENDPOINT = keyvals["DSC_ENDPOINT"].strip() # Cut off everything after Nodes in the URL including Nodes, if Nodes is in URL (it should be) Nodes_loc = DSC_ENDPOINT.find("/Nodes") if Nodes_loc != -1: DSC_ENDPOINT = DSC_ENDPOINT[:Nodes_loc] AGENT_GUID = keyvals["AGENT_GUID"].strip() # Write out agentID f = open(agentid_path, "w") try: f.write(AGENT_GUID) finally: f.close() os.system("chown omsagent " + agentid_path) # Write metaconfig metaConfig = generate_meta_mof(DSC_ENDPOINT) else: metaConfig = generate_push_meta_mof() f = open(metamof_path, "w") try: f.write(metaConfig) finally: f.close() os.system("chown omsagent " + metamof_path) if os.geteuid() == 0: commandToRun = "su - omsagent -c '/opt/microsoft/omsconfig/Scripts/SetDscLocalConfigurationManager.py -configurationmof " + metamof_path + "'" else: commandToRun = "/opt/microsoft/omsconfig/Scripts/SetDscLocalConfigurationManager.py -configurationmof " + metamof_path # Apply the metaconfig using SetDscLocalConfiguration proc = subprocess.Popen(commandToRun, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, close_fds=True, preexec_fn=os.setsid) exit_code = proc.wait() stdout, stderr = proc.communicate() printVerboseMessage("Output from: " + commandToRun + ": " + str(stdout)) set_metaconfig_success_string = "" if "omsconfig" in helperlib.DSC_SCRIPT_PATH: set_metaconfig_success_string = "Operation SendMetaConfigurationApply completed successfully." else: set_metaconfig_success_string = "ReturnValue=0" # This file is only for python 2 if ((exit_code == 0) and (stderr == '' or (sys.version_info >= (3, 0) and stderr.decode(encoding = 'UTF-8') == '') and (set_metaconfig_success_string in str(stdout)))): printVerboseMessage('Successfully configured omsconfig.') else: if exit_code == 0: exit_code = 1 if (stderr != ''): exitWithError(("Error on running command: " + commandToRun + " Error Message: " + stderr), exit_code) elif ((sys.version_info >= (3, 0) and stderr.decode(encoding = 'UTF-8') != '')): exitWithError(("Error on running command: " + commandToRun + " Error Message: " + stderr.decode(encoding = 'UTF-8')), exit_code) else: exitWithError(("Failed on running command: " + commandToRun), exit_code)