#!/usr/bin/env python """ Load Dynatrace Configuration Script. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ __author__ = "Arnautovic Arnel" __contact__ = "Arnel.Arnautovic@nttdata.com" __copyright__ = "Copyright 2021, NTT DATA" __credits__ = ["Ermis Wieger", "René Forstner"] __date__ = "2021/11/29" __deprecated__ = False __license__ = "GPLv3" __maintainer__ = "developer" __status__ = "Prototype" __version__ = "0.0.4" # [AA 2021.11.29] Import modules from logging import exception import os import subprocess import sys import time import shutil import hcl from dotenv import load_dotenv # [AA 2021.12.10] Method to set environments def set_env(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 run_proc(proc, data): try: process = subprocess.Popen([proc, "export"] + data) outs = process.wait(timeout=10*60) print("[DEBUG]", "Process return code:", outs) except subprocess.TimeoutExpired: print("[DEBUG]", "Exception occured:", subprocess.TimeoutExpired) print("[DEBUG]", "Killing process.") process.kill() # [AA 2021.12.10] Simple copy methd def copy(src, dst): shutil.copyfile(".\\templates\\" + src, dst) # [AA, EW 2021.12.13] Check if the path exists and decide between folder or file def checkdir(d): dflag = False # [AA 2021.12.13] If the path exists and the associated path points to a directory if os.path.exists(d) and os.path.isdir(d): # [AA 2021.12.13] If the directory exists, but is empty, delete directory if not os.listdir(d): # [AA 2021.12.13] Delete Folder if empty print("[DEBUG]", "Found and deleting empty directory:", d) os.rmdir(d) else: print("[DEBUG]", "Found directory:", d) dflag = True else: print("[DEBUG]", "Found file:", d) return d, dflag # [AA 2021.12.13] Fill dictionary def readfile(d, f): with open(os.path.join(d, f), 'r') 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 2021.12.13] Add kay, value to dictionary def addentry(key, val, myDict): myDict.setdefault(key, []) if(val) not in myDict.get(key): myDict[key].append(val) return myDict # [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 2021.12.10] Set timestamp once when script is executed timestamp = time.strftime("%Y%m%d-%H%M%S") # [AA 2021.11.29] Load enviroment file load_dotenv() # [AA 2021.12.10] Set environments/tenants Environments = ["EUPROD"] # "EUPREPROD", # "NAPROD", # "NAPREPROD", # "CNPROD", # "CNPREPROD"] # [AA 2021.12.10] 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", # "dynatrace_service_naming", # "dynatrace_host_naming", # "dynatrace_processgroup_naming", # "dynatrace_slo", # "dynatrace_span_entry_point", # "dynatrace_span_capture_rule", # "dynatrace_span_context_propagation", # "dynatrace_resource_attributes", # "dynatrace_span_attribute", # "dynatrace_mobile_application", # "dynatrace_credentials", # "dynatrace_browser_monitor", # "dynatrace_http_monitor", ] # [AA 2021.12.13] Set default values setdir = '.' # [AA 2021.11.29] Arguments passed if(len(sys.argv) == 1): # [AA 2021.12.10] Loop through all four envirionments and two tenants for e in Environments: # [AA 2021.12.10] Set environment variables env = set_env(e, timestamp, "./configuration/") # [AA 2021.12.10] Run the process synchronously! run_proc(".\\bin\\terraform-provider-dynatrace_v1.8.4.exe", Resources) # [AA 2021.12.01] Create main.tf file if it does not exist, otherwise overwrite copy("main.tf", ".\\main.tf") # [AA, EW 2021.11.30] Copy configuration into each configration folder copy("configuration.tf", env['DYNATRACE_TARGET_FOLDER'] + "\\configuration.tf") # [AA, EW 2021.11.30] Iterate trough each folder in targetfolder, f...file/folder for dirname in os.listdir(env['DYNATRACE_TARGET_FOLDER']): d, dflag = checkdir(os.path.join( env['DYNATRACE_TARGET_FOLDER'], dirname)) # print('[DEBUG]', 'd', d) # [AA 2021.12.13] If the associated path is a directory if dflag: # [AA 2021.12.09] Create empty dictinary to store resource type and resource name myDict = {} # [AA 2021.12.01] Loop through directory, eg: management_zones, autotags for file in os.listdir(d): setskipflag = False # [AA 2021.12.13] Check if there is another subdirectory or a file dd, ddflag = checkdir(os.path.join(d, file)) # print('[DEBUG]', 'ddir', dd, 'ddflag', ddflag) # [AA 2021.12.14] If dd was not deleted and is a "sub"-directory if os.path.exists(dd) and ddflag: # [AA 2021.12.13] Set directory setdir = dd.replace(os.sep, '/') # [AA 2021.12.13] Loop through that particular directory, where the files are! for ffile in os.listdir(dd): key, value = readfile(dd, ffile) myDict = addentry(key, val, myDict) # [AA 2021.12.14] If dd was not deleted and is not a directory (=a file) elif os.path.exists(dd) and ddflag is False: # [AA 2021.12.13] Set directory setdir = d.replace(os.sep, '/') # [AA 2021.12.13] There is no subdirectory, it is a file # print("[DEBUG]", "Reading", "configDirFile", d) key, val = readfile(d, file) myDict = addentry(key, val, myDict) # [AA 2021.12.14] The directory was deleted elif not os.path.exists(dd) and ddflag is False: print("[DEBUG]", "Directory was deleted:", dd) setskipflag = True # [AA 2021.12.14] Directory could not be deleted elif not os.path.exists(dd) and ddflag is True: print("[DEBUG]", "Deletion not successful:", dd) setskipflag = True # [AA 2021.12.14] Manual exception will be thrown else: print("[DEBUG]", "Uncaught Exception Error.") setskipflag = True if setskipflag is not True: # [AA, EW 2021.11.30] Copy module copy("module.tf", setdir + "\\module.tf") # [AA 2021.12.10] Print the amount of resources exported from Dynatrace print("[DICTIONARY]", "resource", ", ".join(myDict.keys()), "amount", "0" if myDict.get(key) is None else len(myDict.get(key)), "\n") # [AA 2021.12.13] Append the necessary modules to the main.tf file writefile(key, setdir) # print("[DEBUG]", "Set directory:", setdir) else: print("Usage example: ") print("python .\exportConfig.py")