Initial commit.

main
SLW\ARNAUA 2022-01-20 09:19:39 +01:00
commit 6b38243d43
11 changed files with 349 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
bin/
output/
outboard/
.env
.terraform.lock.hcl

18
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Aktuelle Datei",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"args": [
"EMEA_PROD"
],
}
]
}

59
README.md Normal file
View File

@ -0,0 +1,59 @@
# TerraformOnboarding
The purpose of the exportConfig.py script is to export dynatrace specific services as terraform files. The importConfig.py script is used to additionally also export the states for each exported terraform file, since terraform does not do that by default.
# Setup
Run the following command to install all necessary dependencies:
```python
pip install -r requirements.txt
```
In order to ensure full functionality a `.env` file is necessary with the following format:
```yml
# Environment URLs
CN_PREPROD_ENV_URL="https://dynatracemgd-cn.bmwgroup.net/e/ab88c03b-b7fc-45f0-9115-9e9ecc0ced35"
CN_PROD_ENV_URL="https://dynatracemgd-cn.bmwgroup.net/e/b921f1b9-c00e-4031-b9d1-f5a0d530757b"
EMEA_PREPROD_ENV_URL="https://qqk70169.live.dynatrace.com"
EMEA_PROD_ENV_URL="https://xxu26128.live.dynatrace.com"
NA_PREPROD_ENV_URL="https://onb44935.live.dynatrace.com"
NA_PROD_ENV_URL="https://wgv50241.live.dynatrace.com"
# Environment Tokens
CN_PREPROD_API_TOKEN="<your-token>"
CN_PROD_API_TOKEN="<your-token>"
EMEA_PREPROD_API_TOKEN="<your-token>"
EMEA_PROD_API_TOKEN="<your-token>"
NA_PREPROD_API_TOKEN="<your-token>"
NA_PROD_API_TOKEN="<your-token>"
```
Place the `.env` file within the root directory of the project folder:
```bash
TerraformDynatrace Porter # Project Folder
├─── res
├─── templates
├─── .env # Add the environment file
├─── .gitignore
├─── README.md
├─── exportConfig.py
├─── imortConfig.py
├─── main.tf
└─── requirements.txt
```
# Run
You can simply run the script by executing the following example command within the projects root directory:
```python
python exportConfig.py
python importConfig.py
```
**Note:** First run the exportConfig.py script and once that is done run the importConfig.py script.
# Version
```python
Python 3.9.9
```

202
export.py Normal file
View File

@ -0,0 +1,202 @@
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 ")

18
main.tf Normal file
View File

@ -0,0 +1,18 @@
terraform {
required_providers {
dynatrace = {
version = "1.9.1"
source = "dynatrace-oss/dynatrace"
}
}
}
# module "configDir" {
# source = "git::https://github.com/arnauagithub/DynatraceTerraformConfiguration.git?ref=20211130-151123"
# }
module "m1" { source = "./output/20220117-132316_EMEA_PROD/anomalies" }
module "m2" { source = "./output/20220117-132316_EMEA_PROD/credentials" }
module "dynatrace_custom_service" { source = "./output/20220117-132316_EMEA_PROD/custom_services" }
module "dynatrace_service_naming" { source = "./output/20220117-132316_EMEA_PROD/naming/services" }

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
python-dotenv
pyhcl

View File

@ -0,0 +1,12 @@
import subprocess
import sys
if(len(sys.argv) == 1):
try:
process = subprocess.Popen(["terraform", "init"])
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()

9
res/plugin.tf Normal file
View File

@ -0,0 +1,9 @@
terraform {
required_providers {
dynatrace = {
version = "1.9.1"
source = "dynatrace-oss/dynatrace"
}
}
}

3
san.py Normal file
View File

@ -0,0 +1,3 @@
import subprocess
process = subprocess.Popen([".\\bin\\terraform-provider-dynatrace_v1.9.1.exe", "export", "dynatrace_alerting_profile"])
print(process.returncode)

12
templates/main.tf Normal file
View File

@ -0,0 +1,12 @@
terraform {
required_providers {
dynatrace = {
version = "1.9.1"
source = "dynatrace-oss/dynatrace"
}
}
}
# module "configDir" {
# source = "git::https://github.com/arnauagithub/DynatraceTerraformConfiguration.git?ref=20211130-151123"
# }

9
templates/module.tf Normal file
View File

@ -0,0 +1,9 @@
terraform {
required_providers {
dynatrace = {
version = "1.9.1"
source = "dynatrace-oss/dynatrace"
}
}
}