1+ import os
2+ import sys
3+ import subprocess
4+ import logging
5+ import json
6+ from typing import List
7+
8+ # Configure logging
9+ logging .basicConfig (
10+ level = logging .INFO , format = "%(asctime)s - %(levelname)s - %(message)s"
11+ )
12+
13+
14+ STK_IAM_DOMAIN = os .getenv ("STK_IAM_DOMAIN" , "https://idm.stackspot.com" )
15+ STK_RUNTIME_MANAGER_DOMAIN = os .getenv (
16+ "STK_RUNTIME_MANAGER_DOMAIN" , "https://runtime-manager.v1.stackspot.com"
17+ )
18+ CONTAINER_IAC_URL = os .getenv ("CONTAINER_IAC_URL" , "stackspot/runtime-job-iac:latest" )
19+ CONTAINER_DEPLOY_URL = os .getenv (
20+ "CONTAINER_DEPLOY_URL" , "stackspot/runtime-job-deploy:latest"
21+ )
22+
23+ FEATURES_BASEPATH_TMP = "/tmp/runtime/deploys"
24+ FEATURES_BASEPATH_EBS = "/opt/runtime"
25+ FEATURES_TEMPLATES_FILEPATH = "/app/"
26+ FEATURES_BASEPATH_TERRAFORM = "/root/.asdf/shims/terraform"
27+
28+
29+ def check (result : subprocess .Popen ) -> None :
30+ """
31+ Checks the result of a subprocess execution. If the return code is non-zero,
32+ it logs an error message and exits the program.
33+
34+ Args:
35+ result (subprocess.Popen): The result of the subprocess execution.
36+ """
37+ result .wait () # Wait for the process to complete
38+ if result .returncode != 0 :
39+ logging .error (f"Failed to execute: { result .args } " )
40+ logging .error (f"Error output: { result .stderr .read ()} " )
41+ sys .exit (1 )
42+
43+
44+ def run_command (command : List [str ]) -> subprocess .Popen :
45+ """
46+ Runs a command using subprocess.Popen and returns the result.
47+
48+ Args:
49+ command (List[str]): The command to be executed as a list of strings.
50+
51+ Returns:
52+ subprocess.Popen: The result of the command execution.
53+ """
54+ try :
55+ logging .info (f"Running command: { ' ' .join (command )} " )
56+ # Start the process
57+ process = subprocess .Popen (
58+ command , stdout = subprocess .PIPE , stderr = subprocess .PIPE , text = True
59+ )
60+
61+ # Read and print output in real-time
62+ for line in process .stdout :
63+ print (line , end = "" ) # Print each line as it is produced
64+
65+ # Check the result after the process completes
66+ check (process )
67+ return process
68+ except Exception as e :
69+ logging .error (f"Exception occurred while running command: { command } " )
70+ logging .error (str (e ))
71+ sys .exit (1 )
72+
73+
74+ def build_iac_flags (inputs : dict ) -> list :
75+ docker_flags : dict = dict (
76+ FEATURES_LEVEL_LOG = inputs .get ("features_level_log" ) or "info" ,
77+ REPOSITORY_NAME = inputs ["repository_name" ],
78+ AUTHENTICATE_CLIENT_ID = inputs ["client_id" ],
79+ AUTHENTICATE_CLIENT_SECRET = inputs ["client_key" ],
80+ AUTHENTICATE_CLIENT_REALMS = inputs ["client_realm" ],
81+ AWS_ACCESS_KEY_ID = inputs ["aws_access_key_id" ],
82+ AWS_SECRET_ACCESS_KEY = inputs ["aws_secret_access_key" ],
83+ AWS_SESSION_TOKEN = inputs ["aws_session_token" ],
84+ AWS_REGION = inputs ["aws_region" ],
85+ AUTHENTICATE_URL = STK_IAM_DOMAIN ,
86+ FEATURES_API_MANAGER = STK_RUNTIME_MANAGER_DOMAIN ,
87+ )
88+ flags = []
89+ for k , v in docker_flags .items ():
90+ flags += ["-e" , f"{ k } ={ v } " ]
91+
92+ return flags
93+
94+
95+ def run_iac (inputs : dict ):
96+ run_task_id : str = inputs ["run_task_id" ]
97+ base_path_output : str = inputs .get ("base_path_output" ) or "."
98+ path_to_mount : str = inputs .get ("path_to_mount" ) or "."
99+ path_to_mount = f"{ path_to_mount } :/app-volume"
100+
101+ flags = build_iac_flags (inputs )
102+ cmd = (
103+ ["docker" , "run" , "--rm" , "-v" , path_to_mount ]
104+ + flags
105+ + [
106+ "--entrypoint=/app/stackspot-runtime-job-iac" ,
107+ CONTAINER_IAC_URL ,
108+ "start" ,
109+ f"--run-task-id={ run_task_id } " ,
110+ f"--base-path-output={ base_path_output } " ,
111+ ]
112+ )
113+
114+ run_command (cmd )
115+
116+
117+ def build_deploy_flags (inputs : dict ) -> list :
118+
119+ docker_flags : dict = dict (
120+ FEATURES_LEVEL_LOG = inputs .get ("features_level_log" ) or "info" ,
121+ FEATURES_TERRAFORM_LOGPROVIDER = inputs .get ("tf_log_provider" ) or "info" ,
122+ FEATURES_RELEASE_LOCALEXEC = inputs .get ("localexec_enabled" ) or "False" ,
123+ FEATURES_TERRAFORM_MODULES = inputs .get ("features_terraform_modules" ) or "[]" ,
124+ AWS_ACCESS_KEY_ID = inputs ["aws_access_key_id" ],
125+ AWS_SECRET_ACCESS_KEY = inputs ["aws_secret_access_key" ],
126+ AWS_SESSION_TOKEN = inputs ["aws_session_token" ],
127+ AUTHENTICATE_CLIENT_ID = inputs ["client_id" ],
128+ AUTHENTICATE_CLIENT_SECRET = inputs ["client_key" ],
129+ AUTHENTICATE_CLIENT_REALMS = inputs ["client_realm" ],
130+ REPOSITORY_NAME = inputs ["repository_name" ],
131+ AWS_REGION = inputs ["aws_region" ],
132+ AUTHENTICATE_URL = STK_IAM_DOMAIN ,
133+ FEATURES_API_MANAGER = STK_RUNTIME_MANAGER_DOMAIN ,
134+ FEATURES_BASEPATH_TMP = FEATURES_BASEPATH_TMP ,
135+ FEATURES_BASEPATH_EBS = FEATURES_BASEPATH_EBS ,
136+ FEATURES_TEMPLATES_FILEPATH = FEATURES_TEMPLATES_FILEPATH ,
137+ FEATURES_BASEPATH_TERRAFORM = FEATURES_BASEPATH_TERRAFORM ,
138+ )
139+ flags = []
140+ for k , v in docker_flags .items ():
141+ flags += ["-e" , f"{ k } ={ v } " ]
142+
143+ return flags
144+
145+
146+ def run_deploy (inputs : dict ):
147+ run_task_id : str = inputs ["run_task_id" ]
148+ output_file : str = inputs .get ("output_file" ) or "deploy-output.json"
149+ path_to_mount : str = inputs .get ("path_to_mount" ) or "."
150+ path_to_mount = f"{ path_to_mount } :/app-volume"
151+
152+ flags = build_deploy_flags (inputs )
153+ cmd = (
154+ ["docker" , "run" , "--rm" , "-v" , path_to_mount ]
155+ + flags
156+ + [
157+ "--entrypoint=/app/stackspot-runtime-job-deploy" ,
158+ CONTAINER_DEPLOY_URL ,
159+ "start" ,
160+ f"--run-task-id={ run_task_id } " ,
161+ f"--output-file={ output_file } " ,
162+ ]
163+ )
164+
165+ run_command (cmd )
166+
167+
168+ def run (metadata ):
169+ with open ("manager-output.log" , "r" ) as file :
170+ data = json .loads (file .read ().replace ("'" , '"' ))
171+
172+ task_runners = dict (IAC_SELF_HOSTED = run_iac , DEPLOY_SELF_HOSTED = run_deploy )
173+ for t in data ["tasks" ]:
174+ runner = task_runners .get (t ["taskType" ])
175+ runner and runner (run_task_id = t ["runTaskId" ], ** metadata .inputs )
0 commit comments