import os import subprocess import sys import time import shutil import hcl from dotenv import load_dotenv from glob import glob # [AA 2021.12.10] Method to set environments def setEnv(env, time, path): os.environ['DYNATRACE_ENV_URL'] = str(os.getenv(env + "_ENV_URL")) os.environ['DYNATRACE_API_TOKEN'] = str(os.getenv(env + "_API_TOKEN")) os.environ['DYNATRACE_TARGET_FOLDER'] = str(path + time + "_" + env) return os.environ # [AA 2021.12.10] Method to call process synchronously def runProcess(process_name, input_params): process_names = ["Export", "Terraform init"] success = False try: process = subprocess.Popen(input_params) process.wait(timeout=60*10) # 10 minutes success = True print("[DEBUG]", "Process:", process_name, "Success:", success) # print("[DEBUG]", "Process return code:", outs) except subprocess.TimeoutExpired: print("[DEBUG]", "Exception occured:", subprocess.TimeoutExpired) print("[DEBUG]", "Killing process:", process_name) process.kill() success = False print("[DEBUG]", "Process:", process_name, "Success:", success) except: if process_name in process_names and success == False: print("[DEBUG]", "Process:", process_name, "Success:", success) print("[DEBUG]", "Exiting program.") process.kill() success = False sys.exit(1) else: print("[FAILED]", input_params) # [AA 2021.12.13] Fill dictionary def readFile(path): with open(path, 'r', encoding='utf8') as cfg: # [AA 2021.12.01] Load the content of the particular resource file in eg: management_zones obj = hcl.load(cfg) # [AA, EW 2021.12.01] Store resource type and resource name of that file into a dictionary key = list(obj['resource'].keys())[0] val = list(obj['resource'][key].keys())[0] return key, val # [AA, EW 2022.01.17] Load all resources and add them to a dictionary def createResourceDict(): files = [os.path.normpath(f).replace('\\', '/') for f in glob(targetFolder + "**/**.tf", recursive=True)] for index, file in enumerate(files): filedir = "./"+("./"+os.path.dirname(file)).replace(targetFolder, "") splittedFilename = os.path.basename(file).split(".") if len(splittedFilename) == 5: resourceID = splittedFilename[1] moduleName, resourceName = readFile(file) if not filedir in myDict.keys(): myDict.setdefault(filedir, {}) if not moduleName in myDict[filedir].keys(): myDict[filedir].setdefault(moduleName, []) resourceValue = {"resourceName": resourceName, "resourceID": resourceID} myDict[filedir][moduleName].append(resourceValue) # [AA, EW 2022.01.17] Copy main.tf into the target folder def copyMainTemplate(): shutil.copyfile(templatesFolder + "main.tf", targetFolder + "main.tf") # [AA 2022.01.17] Copy module.tf in all folders and subfolders except where main.tf is def copyModuleTemplate(): dirs = glob(targetFolder + "**/", recursive=True) for index, dir in enumerate(dirs): if index != 0: shutil.copyfile(templatesFolder + "module.tf", dir + "module.tf") # [AA 2021.12.13] Append correct configuration path def writeFile(k, d): with open(".\\main.tf", "a") as mf: mf.writelines("\n" + "module \"" + k + "\" { source = \"" + d + "\" }") # [AA, EW 2022.01.17] Adjust the resource module name def getModuleTag(str): return str.replace("./", "").replace("/", "_") # [AA, EW 2022.01.17] Set the resource names def editMainTF(): with open(targetFolder + "main.tf", "a") as mf: for index, (filedir, value) in enumerate(myDict.items()): mf.writelines("\n" + "module \"" + getModuleTag(filedir) + "\" { source = \"" + filedir + "\" }") # [AA, EW 2022.01.17] Start importing def importStates(): os.chdir(targetFolder) input_params = ["terraform", "init"] runProcess("Terraform init",input_params) for filedir, resourceV in myDict.items(): for resource, valueArray in resourceV.items(): for rObject in valueArray: input_params = ["terraform", "import", "module."+getModuleTag( filedir)+"."+resource+"."+rObject["resourceName"], rObject["resourceID"]] runProcess("Import", input_params) # terraform import module.alerting_profiles.dynatrace_alerting_profiles.CD_ABC 9348098098safs9f8 os.chdir(cwd) # [AA 2022.01.17] Arguments passed if(len(sys.argv) == 2): # [AA 2021.11.29] Load enviroment file load_dotenv() # [AA 2022.01.17] Set available resources Resources = [ # "dynatrace_custom_service", # "dynatrace_dashboard", # "dynatrace_management_zone", # "dynatrace_maintenance_window", # "dynatrace_request_attribute", "dynatrace_alerting_profile", "dynatrace_notification", # "dynatrace_autotag" # "dynatrace_aws_credentials", # "dynatrace_azure_credentials", # "dynatrace_k8s_credentials", # "dynatrace_service_anomalies", # "dynatrace_application_anomalies", # "dynatrace_host_anomalies", # "dynatrace_database_anomalies", # "dynatrace_custom_anomalies", # "dynatrace_disk_anomalies", # "dynatrace_calculated_service_metric", #issue -> bug: windows specific due to path length limit # "dynatrace_service_naming", # "dynatrace_host_naming", # "dynatrace_processgroup_naming", # "dynatrace_slo", # issue -> bug: whitespace issue # "dynatrace_span_entry_point", # "dynatrace_span_capture_rule", # "dynatrace_span_context_propagation", # "dynatrace_resource_attributes", # "dynatrace_span_attribute", # "dynatrace_mobile_application", # "dynatrace_credentials", #issue -> bug: unknown issue? not supported? # "dynatrace_browser_monitor", # "dynatrace_http_monitor", ] # [AA, EW 2022.01.17] Set global variables global timestamp, templatesFolder, outputFolder, targetFolder, myDict, cwd # timestamp = time.strftime("%Y%m%d-%H%M%S") timestamp = "20220120-084944" cwd = os.getcwd() outputFolder = "./output/" targetFolder = outputFolder + timestamp + "_" + sys.argv[1] + "/" templatesFolder = "./templates/" myDict = {} # [AA, EW 2022.01.17] Set env varibales setEnv(sys.argv[1], timestamp, outputFolder) # [AA, EW 2022.01.17] Download resource files # runProcess("Export", [".\\bin\\terraform-provider-dynatrace_v1.9.1.exe", "export"] + Resources) # [AA, EW 2022.01.17] Create a dictionary to store information of resources createResourceDict() # [AA, EW 2022.01.17] Copy main.tf file and add module.tf files # copyMainTemplate() # copyModuleTemplate() # [AA, EW 2022.01.17] Print the module names with their associated module path into the main.tf file # editMainTF() # [AA, EW 2022.01.17] Import the states for each module # importStates() print("Finished!") else: print("Usage example: ") print("List of available environments: CN_PREPROD, CN_PROD, EMEA_PREPROD, EMEA_PROD, NA_PREPROD, NA_PROD") print("python .\exportConfig.py EMEA_PROD ")