From b8750689bf1668ca1549ed731db2b876d295992d Mon Sep 17 00:00:00 2001 From: Bhargava Chary Chollaty Date: Wed, 8 Jul 2020 12:33:57 +0530 Subject: [PATCH] Added Exception Logging in InstallModule.py and RemoveModule.py --- LCM/scripts/InstallModule.py | 460 ++++++++++++++++++----------------- LCM/scripts/RemoveModule.py | 252 ++++++++++--------- 2 files changed, 366 insertions(+), 346 deletions(-) diff --git a/LCM/scripts/InstallModule.py b/LCM/scripts/InstallModule.py index 9613d8760..55edfe3c4 100755 --- a/LCM/scripts/InstallModule.py +++ b/LCM/scripts/InstallModule.py @@ -7,6 +7,7 @@ import sys import platform from os.path import basename, dirname, join, realpath, split +from traceback import format_exc pathToCurrentScript = realpath(__file__) pathToCommonScriptsFolder = dirname(pathToCurrentScript) @@ -79,284 +80,291 @@ def main(args): The omireg script is not used here because it needs to run as root. OMS DSC runs this script as the user omsagent. ''' + try: + # Parameter validation + if len(args) != 1 and len(args) != 2: + usage() - # Parameter validation - if len(args) != 1 and len(args) != 2: - usage() - - moduleZipFilePath = args[0] + moduleZipFilePath = args[0] - if not os.path.isfile(moduleZipFilePath): - exitWithError("The provided module zip file path (" + moduleZipFilePath + ") does not point to an existing, accessible file.") + if not os.path.isfile(moduleZipFilePath): + exitWithError("The provided module zip file path (" + moduleZipFilePath + ") does not point to an existing, accessible file.") - if len(args) == 2: - verifyChecksum = args[1] in ['1', 'True'] - else: - verifyChecksum = False + if len(args) == 2: + verifyChecksum = args[1] in ['1', 'True'] + else: + verifyChecksum = False - moduleZipFileName = os.path.basename(moduleZipFilePath) - indexOfLastUnderScoreInModuleZipFileName = moduleZipFileName.rfind("_") + moduleZipFileName = os.path.basename(moduleZipFilePath) + indexOfLastUnderScoreInModuleZipFileName = moduleZipFileName.rfind("_") - if indexOfLastUnderScoreInModuleZipFileName == -1: - exitWithError("The provided module zip file name (" + moduleZipFileName + ") is not formatted correctly. Please provide a .zip file with the file name in the format NAME_VERSION.zip. The version must also contain a dot.") + if indexOfLastUnderScoreInModuleZipFileName == -1: + exitWithError("The provided module zip file name (" + moduleZipFileName + ") is not formatted correctly. Please provide a .zip file with the file name in the format NAME_VERSION.zip. The version must also contain a dot.") - indexOfZipExtensionInModuleZipFileName = moduleZipFileName.rfind(".zip") + indexOfZipExtensionInModuleZipFileName = moduleZipFileName.rfind(".zip") - if indexOfZipExtensionInModuleZipFileName == -1: - exitWithError("The provided module zip file name (" + moduleZipFileName + ") is not a zip file. Please provide a .zip file with the file name in the format NAME_VERSION.zip. The version must also contain a dot.") + if indexOfZipExtensionInModuleZipFileName == -1: + exitWithError("The provided module zip file name (" + moduleZipFileName + ") is not a zip file. Please provide a .zip file with the file name in the format NAME_VERSION.zip. The version must also contain a dot.") - moduleName = moduleZipFileName[0:indexOfLastUnderScoreInModuleZipFileName] - moduleVersion = moduleZipFileName[indexOfLastUnderScoreInModuleZipFileName + 1:indexOfZipExtensionInModuleZipFileName] + moduleName = moduleZipFileName[0:indexOfLastUnderScoreInModuleZipFileName] + moduleVersion = moduleZipFileName[indexOfLastUnderScoreInModuleZipFileName + 1:indexOfZipExtensionInModuleZipFileName] - if '.' not in moduleVersion: - exitWithError("The provided module zip file name (" + moduleZipFileName + ") contains an invalid version declaration. Please provide a .zip file with the file name in the format NAME_VERSION.zip. The version must also contain a dot.") + if '.' not in moduleVersion: + exitWithError("The provided module zip file name (" + moduleZipFileName + ") contains an invalid version declaration. Please provide a .zip file with the file name in the format NAME_VERSION.zip. The version must also contain a dot.") - # Open the zip file - moduleZipFile = zipfile.ZipFile(moduleZipFilePath) + # Open the zip file + moduleZipFile = zipfile.ZipFile(moduleZipFilePath) - try: - # Check that the zip file members all have valid CRC's and file headers - firstBadFileName = moduleZipFile.testzip() - if firstBadFileName is not None: - exitWithError("The provided module zip file contains at least one invalid file. The first invalid file is named " + firstBadFileName + ". Please ensure that the file has a valid CRC and file header.") + try: + # Check that the zip file members all have valid CRC's and file headers + firstBadFileName = moduleZipFile.testzip() + if firstBadFileName is not None: + exitWithError("The provided module zip file contains at least one invalid file. The first invalid file is named " + firstBadFileName + ". Please ensure that the file has a valid CRC and file header.") - # Check if the module was zipped to include the module folder or just the module folder's contents. - zipIncludesModuleFolder = False + # Check if the module was zipped to include the module folder or just the module folder's contents. + zipIncludesModuleFolder = False - for moduleZipMemberName in moduleZipFile.namelist(): - if moduleZipMemberName.startswith('/') or moduleZipMemberName.startswith('..'): - exitWithError("The provided module zip file contains at least one file with an invalid name that starts with '/' or '..'. The first invalid file is named " + moduleZipMemberName + ". Please ensure that all files have valid names.") + for moduleZipMemberName in moduleZipFile.namelist(): + if moduleZipMemberName.startswith('/') or moduleZipMemberName.startswith('..'): + exitWithError("The provided module zip file contains at least one file with an invalid name that starts with '/' or '..'. The first invalid file is named " + moduleZipMemberName + ". Please ensure that all files have valid names.") - if moduleZipMemberName.startswith(moduleName + "/"): - zipIncludesModuleFolder = True + if moduleZipMemberName.startswith(moduleName + "/"): + zipIncludesModuleFolder = True - if zipIncludesModuleFolder: - moduleZipExtrationPath = helperlib.DSC_MODULES_PATH - else: - moduleZipExtrationPath = join(helperlib.DSC_MODULES_PATH, moduleName) - - # Extract module to destination path - printVerboseMessage("Extracting module zip file from " + moduleZipFilePath + " to " + moduleZipExtrationPath) - moduleZipFile.extractall(moduleZipExtrationPath) - finally: - moduleZipFile.close() - - # Check that we can find the extracted module folder - moduleDestinationPath = join(moduleZipExtrationPath, moduleName) - if not os.path.isdir(moduleDestinationPath): - exitWithError("Unable to find module directory after attempting to extract module from zip to the path " + moduleDestinationPath) - - # Check that we can find the DSCResources folder under the extracted module folder - moduleDscResourcesDestinationPath = join(moduleDestinationPath, 'DSCResources') - if not os.path.isdir(moduleDscResourcesDestinationPath): - exitWithError("Unable to find the DSCResources directory under the module directory at the path " + moduleDscResourcesDestinationPath + " after extracting module from zip to the path.") - - # Populate commom main DSC path - dscMainFolderPath = join(helperlib.CONFIG_SYSCONFDIR, helperlib.CONFIG_SYSCONFDIR_DSC) - - # Verify the module checksum if specified - if verifyChecksum: - # Check that we can find the keyring file - keyringFilePath = join(dscMainFolderPath, 'keyring.gpg') - if not os.path.isfile(keyringFilePath): - exitWithError("Unable to find DSC keyring file at " + keyringFilePath) - - # Check that we can find the asc file - ascFileName = moduleName + ".asc" - ascFilePath = join(moduleDestinationPath, ascFileName) - if not os.path.isfile(ascFilePath): - exitWithError("Unable to find module asc file at " + ascFilePath) - - # check that we can find the SHA256 sums file - sha256SumsFileName = moduleName + ".sha256sums" - sha256SumsFilePath = join(moduleDestinationPath, sha256SumsFileName) - if not os.path.isfile(sha256SumsFilePath): - exitWithError("Unable to find module SHA256 sums file at " + sha256SumsFilePath) - - # Verify the SHA256 sums file with the keyring and asc files - verifySha256SumsCommand = "HOME=" + dscMainFolderPath + " gpg --no-default-keyring --keyring " + keyringFilePath + " --verify " + ascFilePath + " " + sha256SumsFilePath - verifySha256SumsResult = subprocess.call(verifySha256SumsCommand, shell = True) - if verifySha256SumsResult != 0: - exitWithError("Failed to verify module SHA256 sums file at " + sha256SumsFilePath + " using signature in module.", 2) - - # Perform SHA256 sums to verify module - performSha256SumsCommand = "cd " + moduleDestinationPath + "; sha256sum -c " + sha256SumsFileName - performSha256SumsResult = subprocess.call(performSha256SumsCommand, shell = True) - if performSha256SumsResult != 0: - exitWithError("Failed to verify module with the SHA256 sums file at " + sha256SumsFilePath, 2) - - # Write the module version file - moduleVersionFilePath = join(moduleDestinationPath, 'VERSION') - moduleVersionFileHandle = open(moduleVersionFilePath, "w+") - try: - moduleVersionFileHandle.write(moduleVersion) - finally: - moduleVersionFileHandle.close() + if zipIncludesModuleFolder: + moduleZipExtrationPath = helperlib.DSC_MODULES_PATH + else: + moduleZipExtrationPath = join(helperlib.DSC_MODULES_PATH, moduleName) - # Populate common DSC paths - dscConfigurationFolderPath = join (dscMainFolderPath, 'configuration') - dscConfigurationRegistrationFolderPath = join(dscConfigurationFolderPath, 'registration') - dscConfigurationSchemaFolderPath = join(dscConfigurationFolderPath, 'schema') + # Extract module to destination path + printVerboseMessage("Extracting module zip file from " + moduleZipFilePath + " to " + moduleZipExtrationPath) + moduleZipFile.extractall(moduleZipExtrationPath) + finally: + moduleZipFile.close() + + # Check that we can find the extracted module folder + moduleDestinationPath = join(moduleZipExtrationPath, moduleName) + if not os.path.isdir(moduleDestinationPath): + exitWithError("Unable to find module directory after attempting to extract module from zip to the path " + moduleDestinationPath) + + # Check that we can find the DSCResources folder under the extracted module folder + moduleDscResourcesDestinationPath = join(moduleDestinationPath, 'DSCResources') + if not os.path.isdir(moduleDscResourcesDestinationPath): + exitWithError("Unable to find the DSCResources directory under the module directory at the path " + moduleDscResourcesDestinationPath + " after extracting module from zip to the path.") + + # Populate commom main DSC path + dscMainFolderPath = join(helperlib.CONFIG_SYSCONFDIR, helperlib.CONFIG_SYSCONFDIR_DSC) + + # Verify the module checksum if specified + if verifyChecksum: + # Check that we can find the keyring file + keyringFilePath = join(dscMainFolderPath, 'keyring.gpg') + if not os.path.isfile(keyringFilePath): + exitWithError("Unable to find DSC keyring file at " + keyringFilePath) + + # Check that we can find the asc file + ascFileName = moduleName + ".asc" + ascFilePath = join(moduleDestinationPath, ascFileName) + if not os.path.isfile(ascFilePath): + exitWithError("Unable to find module asc file at " + ascFilePath) + + # check that we can find the SHA256 sums file + sha256SumsFileName = moduleName + ".sha256sums" + sha256SumsFilePath = join(moduleDestinationPath, sha256SumsFileName) + if not os.path.isfile(sha256SumsFilePath): + exitWithError("Unable to find module SHA256 sums file at " + sha256SumsFilePath) + + # Verify the SHA256 sums file with the keyring and asc files + verifySha256SumsCommand = "HOME=" + dscMainFolderPath + " gpg --no-default-keyring --keyring " + keyringFilePath + " --verify " + ascFilePath + " " + sha256SumsFilePath + verifySha256SumsResult = subprocess.call(verifySha256SumsCommand, shell = True) + if verifySha256SumsResult != 0: + exitWithError("Failed to verify module SHA256 sums file at " + sha256SumsFilePath + " using signature in module.", 2) + + # Perform SHA256 sums to verify module + performSha256SumsCommand = "cd " + moduleDestinationPath + "; sha256sum -c " + sha256SumsFileName + performSha256SumsResult = subprocess.call(performSha256SumsCommand, shell = True) + if performSha256SumsResult != 0: + exitWithError("Failed to verify module with the SHA256 sums file at " + sha256SumsFilePath, 2) + + # Write the module version file + moduleVersionFilePath = join(moduleDestinationPath, 'VERSION') + moduleVersionFileHandle = open(moduleVersionFilePath, "w+") + try: + moduleVersionFileHandle.write(moduleVersion) + finally: + moduleVersionFileHandle.close() - # Populate common OMI namespace path - omiNamespaceFolderName = helperlib.DSC_NAMESPACE.replace('/', '-') - omiRegistrationFolderPath = join(helperlib.CONFIG_SYSCONFDIR, 'omiregister') - omiNamespaceFolderPath = join(omiRegistrationFolderPath, omiNamespaceFolderName) + # Populate common DSC paths + dscConfigurationFolderPath = join (dscMainFolderPath, 'configuration') + dscConfigurationRegistrationFolderPath = join(dscConfigurationFolderPath, 'registration') + dscConfigurationSchemaFolderPath = join(dscConfigurationFolderPath, 'schema') - # Populate common platform architecture - resourceArchitectureFolderName = getPlatformArchitectureFolderName() + # Populate common OMI namespace path + omiNamespaceFolderName = helperlib.DSC_NAMESPACE.replace('/', '-') + omiRegistrationFolderPath = join(helperlib.CONFIG_SYSCONFDIR, 'omiregister') + omiNamespaceFolderPath = join(omiRegistrationFolderPath, omiNamespaceFolderName) - # Install the module's resources - moduleResources = os.listdir(moduleDscResourcesDestinationPath) + # Populate common platform architecture + resourceArchitectureFolderName = getPlatformArchitectureFolderName() - # Python 2.4 and 3 recognize different formats for octal - if sys.version_info >= (3, 0): - strMode = "0o777" - else: - strMode = "0777" + # Install the module's resources + moduleResources = os.listdir(moduleDscResourcesDestinationPath) - octMode = int(strMode, base=8) + # Python 2.4 and 3 recognize different formats for octal + if sys.version_info >= (3, 0): + strMode = "0o777" + else: + strMode = "0777" - for resource in moduleResources: - resourceFolderPath = join(moduleDscResourcesDestinationPath, resource) + octMode = int(strMode, base=8) - # Skip anything that is not a directory - if not os.path.isdir(resourceFolderPath): - continue + for resource in moduleResources: + resourceFolderPath = join(moduleDscResourcesDestinationPath, resource) - printVerboseMessage("Installing resource " + resource) + # Skip anything that is not a directory + if not os.path.isdir(resourceFolderPath): + continue - # Create the resource DSC schema folder if it does not already exist - resourceDscSchemaFolderPath = join(dscConfigurationSchemaFolderPath, resource) - if not os.path.isdir(resourceDscSchemaFolderPath): - os.mkdir(resourceDscSchemaFolderPath) + printVerboseMessage("Installing resource " + resource) - # Copy the resource DSC schema to the the resource DSC schema folder - resourceDscSchemaFileName = resource + ".schema.mof" - resourceDscSchemaFileSourcePath = join(resourceFolderPath, resourceDscSchemaFileName) - if os.path.isfile(resourceDscSchemaFileSourcePath): - shutil.copy(resourceDscSchemaFileSourcePath, resourceDscSchemaFolderPath) - else: - exitWithError("Unable to find .schema.mof file for resource " + resource + " at the path " + resourceDscSchemaFileSourcePath) + # Create the resource DSC schema folder if it does not already exist + resourceDscSchemaFolderPath = join(dscConfigurationSchemaFolderPath, resource) + if not os.path.isdir(resourceDscSchemaFolderPath): + os.mkdir(resourceDscSchemaFolderPath) - # Create the resource DSC registration folder if it does not already exist - resourceDscRegistrationFolderPath = join(dscConfigurationRegistrationFolderPath, resource) - if not os.path.isdir(resourceDscRegistrationFolderPath): - os.mkdir(resourceDscRegistrationFolderPath) + # Copy the resource DSC schema to the the resource DSC schema folder + resourceDscSchemaFileName = resource + ".schema.mof" + resourceDscSchemaFileSourcePath = join(resourceFolderPath, resourceDscSchemaFileName) + if os.path.isfile(resourceDscSchemaFileSourcePath): + shutil.copy(resourceDscSchemaFileSourcePath, resourceDscSchemaFolderPath) + else: + exitWithError("Unable to find .schema.mof file for resource " + resource + " at the path " + resourceDscSchemaFileSourcePath) - # Create the DSC registration file in the resource DSC registration folder - resourceDscRegistrationFileName = resource + ".registration.mof" - resourceDscRegistrationFileContent = getDscRegistrationFileContent(resource) + # Create the resource DSC registration folder if it does not already exist + resourceDscRegistrationFolderPath = join(dscConfigurationRegistrationFolderPath, resource) + if not os.path.isdir(resourceDscRegistrationFolderPath): + os.mkdir(resourceDscRegistrationFolderPath) - resourceDscRegistrationFileDestinationPath = join(resourceDscRegistrationFolderPath, resourceDscRegistrationFileName) - resourceDscRegistrationFileDesintationHandle = open(resourceDscRegistrationFileDestinationPath, "w+") - try: - resourceDscRegistrationFileDesintationHandle.write(resourceDscRegistrationFileContent) - finally: - resourceDscRegistrationFileDesintationHandle.close() + # Create the DSC registration file in the resource DSC registration folder + resourceDscRegistrationFileName = resource + ".registration.mof" + resourceDscRegistrationFileContent = getDscRegistrationFileContent(resource) - # Copy the resource Python scripts to the DSC scripts directories - resourceLibraryFolderPath = join(resourceFolderPath, resourceArchitectureFolderName) - if not os.path.isdir(resourceLibraryFolderPath): - exitWithError("Unable to find the resource library folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceLibraryFolderPath + " in the extracted module.") + resourceDscRegistrationFileDestinationPath = join(resourceDscRegistrationFolderPath, resourceDscRegistrationFileName) + resourceDscRegistrationFileDesintationHandle = open(resourceDscRegistrationFileDestinationPath, "w+") + try: + resourceDscRegistrationFileDesintationHandle.write(resourceDscRegistrationFileContent) + finally: + resourceDscRegistrationFileDesintationHandle.close() - resourceScriptsFolderPath = join(resourceLibraryFolderPath, 'Scripts') - if not os.path.isdir(resourceLibraryFolderPath): - exitWithError("Unable to find the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsFolderPath + " in the extracted module.") + # Copy the resource Python scripts to the DSC scripts directories + resourceLibraryFolderPath = join(resourceFolderPath, resourceArchitectureFolderName) + if not os.path.isdir(resourceLibraryFolderPath): + exitWithError("Unable to find the resource library folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceLibraryFolderPath + " in the extracted module.") - pythonVersionFileNames = ['2.4x-2.5x', '2.6x-2.7x', '3.x'] + resourceScriptsFolderPath = join(resourceLibraryFolderPath, 'Scripts') + if not os.path.isdir(resourceLibraryFolderPath): + exitWithError("Unable to find the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsFolderPath + " in the extracted module.") - for pythonVersionFileName in pythonVersionFileNames: - resourceScriptsPythonVersionFolderPath = join(resourceScriptsFolderPath, pythonVersionFileName) - if not os.path.isdir(resourceScriptsPythonVersionFolderPath): - exitWithError("Unable to find the version-specific Python folder under the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsPythonVersionFolderPath + " in the extracted module.") + pythonVersionFileNames = ['2.4x-2.5x', '2.6x-2.7x', '3.x'] - resourceScriptsPythonVersionScriptsFolderPath = join(resourceScriptsPythonVersionFolderPath, 'Scripts') - if not os.path.isdir(resourceScriptsPythonVersionScriptsFolderPath): - exitWithError("Unable to find the version-specific Python scripts folder under the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsPythonVersionScriptsFolderPath + " in the extracted module.") + for pythonVersionFileName in pythonVersionFileNames: + resourceScriptsPythonVersionFolderPath = join(resourceScriptsFolderPath, pythonVersionFileName) + if not os.path.isdir(resourceScriptsPythonVersionFolderPath): + exitWithError("Unable to find the version-specific Python folder under the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsPythonVersionFolderPath + " in the extracted module.") - resourceScriptFileNames = os.listdir(resourceScriptsPythonVersionScriptsFolderPath) + resourceScriptsPythonVersionScriptsFolderPath = join(resourceScriptsPythonVersionFolderPath, 'Scripts') + if not os.path.isdir(resourceScriptsPythonVersionScriptsFolderPath): + exitWithError("Unable to find the version-specific Python scripts folder under the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsPythonVersionScriptsFolderPath + " in the extracted module.") - dscScriptsPythonVersionFolderPath = join(helperlib.DSC_SCRIPT_PATH, pythonVersionFileName) - dscScriptsPythonVersionScriptsFolderPath = join(dscScriptsPythonVersionFolderPath, 'Scripts') + resourceScriptFileNames = os.listdir(resourceScriptsPythonVersionScriptsFolderPath) - for resourceScriptFileName in resourceScriptFileNames: - resourceScriptFilePath = join(resourceScriptsPythonVersionScriptsFolderPath, resourceScriptFileName) - if (os.path.isfile(resourceScriptFilePath)): - shutil.copy(resourceScriptFilePath, dscScriptsPythonVersionScriptsFolderPath) + dscScriptsPythonVersionFolderPath = join(helperlib.DSC_SCRIPT_PATH, pythonVersionFileName) + dscScriptsPythonVersionScriptsFolderPath = join(dscScriptsPythonVersionFolderPath, 'Scripts') - # Copy the resource library file to the OMI library folder - resourceLibraryFileName = "lib" + resource + ".so" - resourceLibraryFileSourcePath = join(resourceLibraryFolderPath, resourceLibraryFileName) + for resourceScriptFileName in resourceScriptFileNames: + resourceScriptFilePath = join(resourceScriptsPythonVersionScriptsFolderPath, resourceScriptFileName) + if (os.path.isfile(resourceScriptFilePath)): + shutil.copy(resourceScriptFilePath, dscScriptsPythonVersionScriptsFolderPath) - if helperlib.DSC_NAMESPACE == "root/Microsoft/DesiredStateConfiguration": - resourceLibraryFileDestinationName = resourceLibraryFileName - else: - resourceLibraryFileDestinationName = resourceLibraryFileName.replace('.so', "_" + omiNamespaceFolderName + ".so") + # Copy the resource library file to the OMI library folder + resourceLibraryFileName = "lib" + resource + ".so" + resourceLibraryFileSourcePath = join(resourceLibraryFolderPath, resourceLibraryFileName) - resourceLibraryFileDestinationPath = join(helperlib.CONFIG_LIBDIR, resourceLibraryFileDestinationName) + if helperlib.DSC_NAMESPACE == "root/Microsoft/DesiredStateConfiguration": + resourceLibraryFileDestinationName = resourceLibraryFileName + else: + resourceLibraryFileDestinationName = resourceLibraryFileName.replace('.so', "_" + omiNamespaceFolderName + ".so") - shutil.copy(resourceLibraryFileSourcePath, resourceLibraryFileDestinationPath) - os.chmod(resourceLibraryFileDestinationPath , stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) - filePermission = oct(os.stat(resourceLibraryFileDestinationPath).st_mode & octMode) - if filePermission == "0644" or filePermission == "0o644": - printVerboseMessage("Updated permissions of file: " + resourceLibraryFileDestinationPath + " to " + filePermission) - else: - exitWithError("Permissions on file: " + resourceLibraryFileDestinationPath + " set incorrectly: " + filePermission) + resourceLibraryFileDestinationPath = join(helperlib.CONFIG_LIBDIR, resourceLibraryFileDestinationName) - - if "omsconfig" in helperlib.DSC_SCRIPT_PATH: - # Copy the resource library file to the OMSCONFIG library folder - resourceSharedObjectDestinationPath = join("/opt/dsc/lib", resource) + shutil.copy(resourceLibraryFileSourcePath, resourceLibraryFileDestinationPath) + os.chmod(resourceLibraryFileDestinationPath , stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) + filePermission = oct(os.stat(resourceLibraryFileDestinationPath).st_mode & octMode) + if filePermission == "0644" or filePermission == "0o644": + printVerboseMessage("Updated permissions of file: " + resourceLibraryFileDestinationPath + " to " + filePermission) + else: + exitWithError("Permissions on file: " + resourceLibraryFileDestinationPath + " set incorrectly: " + filePermission) - if not os.path.isdir(resourceSharedObjectDestinationPath): - os.mkdir(resourceSharedObjectDestinationPath) + + if "omsconfig" in helperlib.DSC_SCRIPT_PATH: + # Copy the resource library file to the OMSCONFIG library folder + resourceSharedObjectDestinationPath = join("/opt/dsc/lib", resource) - resourceSharedObjectFileDestinationPath = join(resourceSharedObjectDestinationPath, resourceLibraryFileName) + if not os.path.isdir(resourceSharedObjectDestinationPath): + os.mkdir(resourceSharedObjectDestinationPath) - shutil.copy(resourceLibraryFileSourcePath, resourceSharedObjectFileDestinationPath) - os.chmod(resourceSharedObjectFileDestinationPath , stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) - filePermission = oct(os.stat(resourceSharedObjectFileDestinationPath).st_mode & octMode) - if filePermission == "0644" or filePermission == "0o644": - printVerboseMessage("Updated permissions of file: " + resourceSharedObjectFileDestinationPath + " to " + filePermission) - else: - exitWithError("Permissions on file: " + resourceSharedObjectFileDestinationPath + " set incorrectly: " + filePermission) + resourceSharedObjectFileDestinationPath = join(resourceSharedObjectDestinationPath, resourceLibraryFileName) - # Copy or write the OMI registration file to the OMI registration folder - resourceOmiRegistrationFileName = resource + ".reg" - resourceOmiRegistrationFileSourcePath = join(resourceFolderPath, resourceOmiRegistrationFileName) - resourceOmiRegistrationFileDestinationPath = join(omiNamespaceFolderPath, resourceOmiRegistrationFileName) + shutil.copy(resourceLibraryFileSourcePath, resourceSharedObjectFileDestinationPath) + os.chmod(resourceSharedObjectFileDestinationPath , stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) + filePermission = oct(os.stat(resourceSharedObjectFileDestinationPath).st_mode & octMode) + if filePermission == "0644" or filePermission == "0o644": + printVerboseMessage("Updated permissions of file: " + resourceSharedObjectFileDestinationPath + " to " + filePermission) + else: + exitWithError("Permissions on file: " + resourceSharedObjectFileDestinationPath + " set incorrectly: " + filePermission) - if helperlib.DSC_NAMESPACE == "root/Microsoft/DesiredStateConfiguration": - shutil.copy(resourceOmiRegistrationFileSourcePath, resourceOmiRegistrationFileDestinationPath) + # Copy or write the OMI registration file to the OMI registration folder + resourceOmiRegistrationFileName = resource + ".reg" + resourceOmiRegistrationFileSourcePath = join(resourceFolderPath, resourceOmiRegistrationFileName) + resourceOmiRegistrationFileDestinationPath = join(omiNamespaceFolderPath, resourceOmiRegistrationFileName) - else: - # Read the resource OMI registration file - resourceOmiRegistrationFileSourceHandle = open(resourceOmiRegistrationFileSourcePath, "r") - try: - resourceOmiRegistrationFileContent = resourceOmiRegistrationFileSourceHandle.read() - finally: - resourceOmiRegistrationFileSourceHandle.close() + if helperlib.DSC_NAMESPACE == "root/Microsoft/DesiredStateConfiguration": + shutil.copy(resourceOmiRegistrationFileSourcePath, resourceOmiRegistrationFileDestinationPath) - # Replace the namespace in the resource DSC registration file - resourceOmiRegistrationFileContentWithOmsLib = resourceOmiRegistrationFileContent.replace("LIBRARY=" + resource, "LIBRARY=" + resource + '_' + omiNamespaceFolderName) + else: + # Read the resource OMI registration file + resourceOmiRegistrationFileSourceHandle = open(resourceOmiRegistrationFileSourcePath, "r") + try: + resourceOmiRegistrationFileContent = resourceOmiRegistrationFileSourceHandle.read() + finally: + resourceOmiRegistrationFileSourceHandle.close() + + # Replace the namespace in the resource DSC registration file + resourceOmiRegistrationFileContentWithOmsLib = resourceOmiRegistrationFileContent.replace("LIBRARY=" + resource, "LIBRARY=" + resource + '_' + omiNamespaceFolderName) + + # Write the content with the replaced namespace to the resource DSC registration file in the resource DSC registration folder + resourceOmiRegistrationFileDesintationHandle = open(resourceOmiRegistrationFileDestinationPath, "w+") + try: + resourceOmiRegistrationFileDesintationHandle.write(resourceOmiRegistrationFileContentWithOmsLib) + finally: + resourceOmiRegistrationFileDesintationHandle.close() + + os.chmod(resourceOmiRegistrationFileDestinationPath, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) + filePermission = oct(os.stat(resourceOmiRegistrationFileDestinationPath).st_mode & octMode) + if filePermission == "0644" or filePermission == "0o644": + printVerboseMessage("Updated permissions of file: " + resourceOmiRegistrationFileDestinationPath + " to " + filePermission) + else: + exitWithError("Permissions on file: " + resourceOmiRegistrationFileDestinationPath + " set incorrectly: " + filePermission) - # Write the content with the replaced namespace to the resource DSC registration file in the resource DSC registration folder - resourceOmiRegistrationFileDesintationHandle = open(resourceOmiRegistrationFileDestinationPath, "w+") - try: - resourceOmiRegistrationFileDesintationHandle.write(resourceOmiRegistrationFileContentWithOmsLib) - finally: - resourceOmiRegistrationFileDesintationHandle.close() + # Regenerate the DSC Python scripts init files + regenerateDscPythonScriptInitFiles() - os.chmod(resourceOmiRegistrationFileDestinationPath, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) - filePermission = oct(os.stat(resourceOmiRegistrationFileDestinationPath).st_mode & octMode) - if filePermission == "0644" or filePermission == "0o644": - printVerboseMessage("Updated permissions of file: " + resourceOmiRegistrationFileDestinationPath + " to " + filePermission) - else: - exitWithError("Permissions on file: " + resourceOmiRegistrationFileDestinationPath + " set incorrectly: " + filePermission) + printVerboseMessage("Succesfully Installed Module " + moduleName) - # Regenerate the DSC Python scripts init files - regenerateDscPythonScriptInitFiles() + except Exception: + # Python 2.4-2.7 and 2.6-3 recognize different formats for exceptions. This methods works in all versions. + formattedExceptionMessage = format_exc() + exitWithError('Python exception raised from InstallModule.py: ' + formattedExceptionMessage) if __name__ == "__main__": main(sys.argv[1:]) diff --git a/LCM/scripts/RemoveModule.py b/LCM/scripts/RemoveModule.py index 936f90b50..f224696ce 100755 --- a/LCM/scripts/RemoveModule.py +++ b/LCM/scripts/RemoveModule.py @@ -6,6 +6,7 @@ import platform import imp from os.path import dirname, join, realpath +from traceback import format_exc pathToCurrentScript = realpath(__file__) pathToCommonScriptsFolder = dirname(pathToCurrentScript) @@ -53,147 +54,158 @@ def main(args): Removes all the resources in the named module from DSC and OMI. ''' - # Parameter validation - if len(args) != 1: - usage() + try: + # Parameter validation + if len(args) != 1: + usage() - moduleName = args[0] - modulePath = join(helperlib.DSC_MODULES_PATH, moduleName) - - if os.path.isdir(modulePath): - printVerboseMessage("Found installed module " + moduleName + " at the path " + modulePath + ". Removing module.") - else: - exitWithError("Unable to find installed module " + moduleName + " at the path " + modulePath) - - # TODO: Move this module-specifc section out of this generic script. - # Special section for nxOMSAutomationWorker module. - # The Linux Hybrid worker and manager needs to be killed before the module is removed. - # Also a good idea to remove the state and working directories. - if moduleName == "nxOMSAutomationWorker": - # Invoke deregister when it becomes available. - # Kill all processes running under the nxOMSAutomationWorker user. - # In some cases, there might be no processes to kill, and the return code of the following command might be non-zero. - # We make a best attempt to terminate the processes and don't care about its return code. - nxOMSAutomationWorkerUserName = "nxautomation" - subprocess.call(["sudo", "pkill", "-u", nxOMSAutomationWorkerUserName, ".*"]) - - # Remove the state directory for nxOMSAutomationWorker - nxOMSAutomationWorkerStateFolderPath = "/var/opt/microsoft/omsagent/state/automationworker" - shutil.rmtree(nxOMSAutomationWorkerStateFolderPath, ignore_errors=True) - - # Remove the working directory for nxOMSAutomationWorker - nxOMSAutomationWorkerWorkingFolderPath = "/var/opt/microsoft/omsagent/run/automationworker" - shutil.rmtree(nxOMSAutomationWorkerWorkingFolderPath, ignore_errors=True) - - # Populate common DSC paths - dscMainFolderPath = join(helperlib.CONFIG_SYSCONFDIR, helperlib.CONFIG_SYSCONFDIR_DSC) - dscConfigurationFolderPath = join (dscMainFolderPath, 'configuration') - dscConfigurationRegistrationFolderPath = join(dscConfigurationFolderPath, 'registration') - dscConfigurationSchemaFolderPath = join(dscConfigurationFolderPath, 'schema') - - # Populate common OMI namespace path - omiNamespaceFolderName = helperlib.DSC_NAMESPACE.replace('/', '-') - omiRegistrationFolderPath = join(helperlib.CONFIG_SYSCONFDIR, 'omiregister') - omiNamespaceFolderPath = join(omiRegistrationFolderPath, omiNamespaceFolderName) - - # Populate common platform architecture - resourceArchitectureFolderName = getPlatformArchitectureFolderName() - - # Remove all the resources in the module from DSC and OMI - moduleResourcePath = join(modulePath, 'DSCResources') - moduleResources = os.listdir(moduleResourcePath) - - for resource in moduleResources: - resourceFolderPath = join(moduleResourcePath, resource) - - # Skip anything that is not a directory - if not os.path.isdir(resourceFolderPath): - continue - - printVerboseMessage("Removing resource " + resource) - - # Remove DSC schema for the resource + moduleName = args[0] + modulePath = join(helperlib.DSC_MODULES_PATH, moduleName) + + if os.path.isdir(modulePath): + printVerboseMessage("Found installed module " + moduleName + " at the path " + modulePath + ". Removing module.") + else: + exitWithError("Unable to find installed module " + moduleName + " at the path " + modulePath) + + # TODO: Move this module-specifc section out of this generic script. + # Special section for nxOMSAutomationWorker module. + # The Linux Hybrid worker and manager needs to be killed before the module is removed. + # Also a good idea to remove the state and working directories. + if moduleName == "nxOMSAutomationWorker": + # Invoke deregister when it becomes available. + # Kill all processes running under the nxOMSAutomationWorker user. + # In some cases, there might be no processes to kill, and the return code of the following command might be non-zero. + # We make a best attempt to terminate the processes and don't care about its return code. + nxOMSAutomationWorkerUserName = "nxautomation" + subprocess.call(["sudo", "pkill", "-u", nxOMSAutomationWorkerUserName, ".*"]) + + # Remove the state directory for nxOMSAutomationWorker + nxOMSAutomationWorkerStateFolderPath = "/var/opt/microsoft/omsagent/state/automationworker" + shutil.rmtree(nxOMSAutomationWorkerStateFolderPath, ignore_errors=True) + + # Remove the working directory for nxOMSAutomationWorker + nxOMSAutomationWorkerWorkingFolderPath = "/var/opt/microsoft/omsagent/run/automationworker" + shutil.rmtree(nxOMSAutomationWorkerWorkingFolderPath, ignore_errors=True) + + # Populate common DSC paths + dscMainFolderPath = join(helperlib.CONFIG_SYSCONFDIR, helperlib.CONFIG_SYSCONFDIR_DSC) + dscConfigurationFolderPath = join (dscMainFolderPath, 'configuration') + dscConfigurationRegistrationFolderPath = join(dscConfigurationFolderPath, 'registration') dscConfigurationSchemaFolderPath = join(dscConfigurationFolderPath, 'schema') - resourceDscSchemaFolderPath = join(dscConfigurationSchemaFolderPath, resource) - if os.path.isdir(resourceDscSchemaFolderPath): - shutil.rmtree(resourceDscSchemaFolderPath) - else: - printVerboseMessage("Unable to find DSC schema folder for resource " + resource + " at the path " + resourceDscSchemaFolderPath + ". Continuing with resource removal.") + # Populate common OMI namespace path + omiNamespaceFolderName = helperlib.DSC_NAMESPACE.replace('/', '-') + omiRegistrationFolderPath = join(helperlib.CONFIG_SYSCONFDIR, 'omiregister') + omiNamespaceFolderPath = join(omiRegistrationFolderPath, omiNamespaceFolderName) - # Remove DSC registration for the resource - resourceDscRegistrationFolderPath = join(dscConfigurationRegistrationFolderPath, resource) + # Populate common platform architecture + resourceArchitectureFolderName = getPlatformArchitectureFolderName() - if os.path.isdir(resourceDscRegistrationFolderPath): - shutil.rmtree(resourceDscRegistrationFolderPath) - else: - printVerboseMessage("Unable to find DSC registration folder for resource " + resource + " at the path " + resourceDscRegistrationFolderPath + ". Continuing with resource removal.") + # Remove all the resources in the module from DSC and OMI + moduleResourcePath = join(modulePath, 'DSCResources') + moduleResources = os.listdir(moduleResourcePath) - # Remove the resource Python scripts from the DSC scripts directories - resourceLibraryFolderPath = join(resourceFolderPath, resourceArchitectureFolderName) - if not os.path.isdir(resourceLibraryFolderPath): - exitWithError("Unable to find the resource library folder for the " + resourceArchitectureFolderName + " architecture in the module at " + resourceLibraryFolderPath) + for resource in moduleResources: + resourceFolderPath = join(moduleResourcePath, resource) - resourceScriptsFolderPath = join(resourceLibraryFolderPath, 'Scripts') - if not os.path.isdir(resourceLibraryFolderPath): - exitWithError("Unable to find the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsFolderPath + " in the extracted module.") + # Skip anything that is not a directory + if not os.path.isdir(resourceFolderPath): + continue + printVerboseMessage("Removing resource " + resource) - pythonVersionFileNames = ['2.4x-2.5x', '2.6x-2.7x', '3.x'] + # Remove DSC schema for the resource + dscConfigurationSchemaFolderPath = join(dscConfigurationFolderPath, 'schema') + resourceDscSchemaFolderPath = join(dscConfigurationSchemaFolderPath, resource) - for pythonVersionFileName in pythonVersionFileNames: - resourceScriptsPythonVersionFolderPath = join(resourceScriptsFolderPath, pythonVersionFileName) - if not os.path.isdir(resourceScriptsPythonVersionFolderPath): - exitWithError("Unable to find the version-specific Python folder under the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsPythonVersionFolderPath + " in the extracted module.") + if os.path.isdir(resourceDscSchemaFolderPath): + shutil.rmtree(resourceDscSchemaFolderPath) + else: + printVerboseMessage("Unable to find DSC schema folder for resource " + resource + " at the path " + resourceDscSchemaFolderPath + ". Continuing with resource removal.") - resourceScriptsPythonVersionScriptsFolderPath = join(resourceScriptsPythonVersionFolderPath, 'Scripts') - if not os.path.isdir(resourceScriptsPythonVersionScriptsFolderPath): - exitWithError("Unable to find the version-specific Python scripts folder under the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsPythonVersionScriptsFolderPath + " in the extracted module.") + # Remove DSC registration for the resource + resourceDscRegistrationFolderPath = join(dscConfigurationRegistrationFolderPath, resource) - resourceScriptFileNames = os.listdir(resourceScriptsPythonVersionScriptsFolderPath) + if os.path.isdir(resourceDscRegistrationFolderPath): + shutil.rmtree(resourceDscRegistrationFolderPath) + else: + printVerboseMessage("Unable to find DSC registration folder for resource " + resource + " at the path " + resourceDscRegistrationFolderPath + ". Continuing with resource removal.") - dscScriptsPythonVersionFolderPath = join(helperlib.DSC_SCRIPT_PATH, pythonVersionFileName) - dscScriptsPythonVersionScriptsFolderPath = join(dscScriptsPythonVersionFolderPath, 'Scripts') + # Remove the resource Python scripts from the DSC scripts directories + resourceLibraryFolderPath = join(resourceFolderPath, resourceArchitectureFolderName) + if not os.path.isdir(resourceLibraryFolderPath): + exitWithError("Unable to find the resource library folder for the " + resourceArchitectureFolderName + " architecture in the module at " + resourceLibraryFolderPath) - for resourceScriptFileName in resourceScriptFileNames: - resourceScriptFilePath = join(dscScriptsPythonVersionScriptsFolderPath, resourceScriptFileName) - if os.path.isfile(resourceScriptFilePath): - os.remove(resourceScriptFilePath) - else: - printVerboseMessage("Unable to find resource script " + resourceScriptFileName + " under the DSC scripts folder at the path " + resourceScriptFilePath + ". Continuing with resource removal.") + resourceScriptsFolderPath = join(resourceLibraryFolderPath, 'Scripts') + if not os.path.isdir(resourceLibraryFolderPath): + exitWithError("Unable to find the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsFolderPath + " in the extracted module.") - # Remove OMI library file for the resource - resourceLibraryOriginalName = "lib" + resource + ".so" - - if helperlib.DSC_NAMESPACE == "root/Microsoft/DesiredStateConfiguration": - resourceLibraryFileName = resourceLibraryOriginalName - else: - resourceLibraryFileName = resourceLibraryOriginalName.replace('.so', "_" + omiNamespaceFolderName + ".so") - resourceLibraryFilePath = join(helperlib.CONFIG_LIBDIR, resourceLibraryFileName) + pythonVersionFileNames = ['2.4x-2.5x', '2.6x-2.7x', '3.x'] - if os.path.isfile(resourceLibraryFilePath): - os.remove(resourceLibraryFilePath) - else: - printVerboseMessage("Unable to find OMI library file for resource " + resource + " at the path " + resourceLibraryFilePath + ". Continuing with resource removal.") - - # Remove OMSCONFIG library file for the resource - if "omsconfig" in helperlib.DSC_SCRIPT_PATH: - resourceSharedObjectDestinationPath = join("/opt/dsc/lib", resource) + for pythonVersionFileName in pythonVersionFileNames: + resourceScriptsPythonVersionFolderPath = join(resourceScriptsFolderPath, pythonVersionFileName) + if not os.path.isdir(resourceScriptsPythonVersionFolderPath): + exitWithError("Unable to find the version-specific Python folder under the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsPythonVersionFolderPath + " in the extracted module.") + + resourceScriptsPythonVersionScriptsFolderPath = join(resourceScriptsPythonVersionFolderPath, 'Scripts') + if not os.path.isdir(resourceScriptsPythonVersionScriptsFolderPath): + exitWithError("Unable to find the version-specific Python scripts folder under the resource library scripts folder for the resource " + resource + " and platform architecture " + resourceArchitectureFolderName + " at the path " + resourceScriptsPythonVersionScriptsFolderPath + " in the extracted module.") + + resourceScriptFileNames = os.listdir(resourceScriptsPythonVersionScriptsFolderPath) + + dscScriptsPythonVersionFolderPath = join(helperlib.DSC_SCRIPT_PATH, pythonVersionFileName) + dscScriptsPythonVersionScriptsFolderPath = join(dscScriptsPythonVersionFolderPath, 'Scripts') + + for resourceScriptFileName in resourceScriptFileNames: + resourceScriptFilePath = join(dscScriptsPythonVersionScriptsFolderPath, resourceScriptFileName) + if os.path.isfile(resourceScriptFilePath): + os.remove(resourceScriptFilePath) + else: + printVerboseMessage("Unable to find resource script " + resourceScriptFileName + " under the DSC scripts folder at the path " + resourceScriptFilePath + ". Continuing with resource removal.") - if os.path.isdir(resourceSharedObjectDestinationPath): - shutil.rmtree(resourceSharedObjectDestinationPath) + # Remove OMI library file for the resource + resourceLibraryOriginalName = "lib" + resource + ".so" + + if helperlib.DSC_NAMESPACE == "root/Microsoft/DesiredStateConfiguration": + resourceLibraryFileName = resourceLibraryOriginalName + else: + resourceLibraryFileName = resourceLibraryOriginalName.replace('.so', "_" + omiNamespaceFolderName + ".so") - # Remove OMI registration for the resource - resourceOmiRegistrationFileName = resource + ".reg" - resourceOmiRegistrationFilePath = join(omiNamespaceFolderPath, resourceOmiRegistrationFileName) - os.remove(resourceOmiRegistrationFilePath) + resourceLibraryFilePath = join(helperlib.CONFIG_LIBDIR, resourceLibraryFileName) - # Regenerate the DSC Python scripts init files - regenerateDscPythonScriptInitFiles() + if os.path.isfile(resourceLibraryFilePath): + os.remove(resourceLibraryFilePath) + else: + printVerboseMessage("Unable to find OMI library file for resource " + resource + " at the path " + resourceLibraryFilePath + ". Continuing with resource removal.") + + # Remove OMSCONFIG library file for the resource + if "omsconfig" in helperlib.DSC_SCRIPT_PATH: + resourceSharedObjectDestinationPath = join("/opt/dsc/lib", resource) - # Remove the extracted module directory and everything in it - shutil.rmtree(modulePath) + if os.path.isdir(resourceSharedObjectDestinationPath): + shutil.rmtree(resourceSharedObjectDestinationPath) + + # Remove OMI registration for the resource + resourceOmiRegistrationFileName = resource + ".reg" + resourceOmiRegistrationFilePath = join(omiNamespaceFolderPath, resourceOmiRegistrationFileName) + if os.path.isfile(resourceOmiRegistrationFilePath): + os.remove(resourceOmiRegistrationFilePath) + else: + printVerboseMessage("Unable to find OMI registration file for resource " + resource + " at the path " + resourceOmiRegistrationFilePath + ". Continuing with resource removal.") + + # Regenerate the DSC Python scripts init files + regenerateDscPythonScriptInitFiles() + + # Remove the extracted module directory and everything in it + shutil.rmtree(modulePath) + + printVerboseMessage("Succesfully Removed Module " + moduleName) + + except Exception: + # Python 2.4-2.7 and 2.6-3 recognize different formats for exceptions. This methods works in all versions. + formattedExceptionMessage = format_exc() + exitWithError('Python exception raised from RemoveModule.py: ' + formattedExceptionMessage) if __name__ == "__main__": main(sys.argv[1:])