Skip to content

Commit e123a83

Browse files
committed
added custom sample to find sandbox id from launched job
1 parent 160fbcc commit e123a83

File tree

12 files changed

+714
-7
lines changed

12 files changed

+714
-7
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from cloudshell.workflow.orchestration.sandbox import Sandbox
2+
from cloudshell.helpers.scripts.cloudshell_dev_helpers import attach_to_cloudshell_as
3+
import credentials
4+
from config_ginger import configure_ginger_agents
5+
6+
LIVE_SANDBOX_ID = "bda46630-f777-401c-a27e-c055f6e6732b"
7+
8+
attach_to_cloudshell_as(user=credentials.USER,
9+
password=credentials.PASSWORD,
10+
domain=credentials.DOMAIN,
11+
reservation_id=LIVE_SANDBOX_ID,
12+
server_address=credentials.SERVER)
13+
14+
sandbox = Sandbox()
15+
configure_ginger_agents(sandbox)
16+
pass
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Setup eDTM
2+
Setup will provision and register Ginger Execution agents to the Agent Handler URL.
3+
4+
## Setup Flow
5+
1. Provision one Linux VM per Execution Agent
6+
2. Run config script to Install Docker
7+
3. Read IP of agent handler from sandbox and pass into config script to run container and register with handler
8+
9+
## NOTES
10+
Run container config script param:
11+
- EXECUTION_HANDLER_URL
12+
13+
Docker install script:
14+
https://raw.githubusercontent.com/docker/docker-install/master/rootless-install.sh
15+
16+
Ginger install script:
17+
https://raw.githubusercontent.com/QualiSystemsLab/App-Configuration-Demo-Scripts/master/ginger/register_ginger.sh
18+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from cloudshell.workflow.orchestration.setup.default_setup_orchestrator import DefaultSetupWorkflow
2+
from cloudshell.workflow.orchestration.sandbox import Sandbox
3+
from set_public_ips import set_public_ip_flow
4+
5+
sandbox = Sandbox()
6+
7+
DefaultSetupWorkflow().register(sandbox)
8+
sandbox.workflow.on_connectivity_ended(set_public_ip_flow)
9+
sandbox.execute_setup()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cloudshell-orch-core
2+
cloudshell-sandbox-reporter
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from cloudshell.workflow.orchestration.sandbox import Sandbox
2+
from cloudshell.helpers.sandbox_reporter.reporter import SandboxReporter
3+
4+
5+
PUBLIC_IP_ATTR = "Public IP"
6+
7+
8+
def set_public_ip_flow(sandbox, components=None):
9+
"""
10+
run all other playbooks on apps besides the router ones
11+
:param Sandbox sandbox:
12+
"""
13+
api = sandbox.automation_api
14+
res_id = sandbox.id
15+
logger = sandbox.logger
16+
reporter = SandboxReporter(api, res_id, logger)
17+
resources = api.GetReservationDetails(res_id, True).ReservationDescription.Resources
18+
19+
for resource in resources:
20+
res_details = api.GetResourceDetails(resource.Name)
21+
attrs = res_details.ResourceAttributes
22+
attrs_dict = {x.Name: x.Value for x in attrs}
23+
public_ip = attrs_dict.get(PUBLIC_IP_ATTR)
24+
if public_ip:
25+
reporter.warning(f"Updating address to public IP on {resource.Name}")
26+
api.UpdateResourceAddress(resourceFullPath=resource.Name, resourceAddress=public_ip)
27+
28+
reporter.info("set public IP flow done", console_print=False)
29+
30+
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""
2+
NOTE: - This script is only for updating EXISTING scripts.
3+
- Scripts MUST be uploaded manually first time. (this tool can still be used to do zipping)
4+
"""
5+
from cloudshell.api.cloudshell_api import CloudShellAPISession
6+
import os
7+
import credentials # may need to create this module and set the constants for the api session
8+
9+
# ===== Optional Variables to set =======
10+
11+
# To name zip package something other than the default directory name
12+
CUSTOM_SCRIPT_NAME = ''
13+
14+
15+
# =======================================
16+
17+
18+
def get_api_session():
19+
return CloudShellAPISession(host=credentials.SERVER,
20+
username=credentials.USER,
21+
password=credentials.PASSWORD,
22+
domain=credentials.DOMAIN)
23+
24+
25+
def error_red(err_str):
26+
"""
27+
for printing errors in red in pycharm.
28+
:param err_str:
29+
:return:
30+
"""
31+
CRED = '\033[91m'
32+
CEND = '\033[0m'
33+
return CRED + err_str + CEND
34+
35+
36+
def get_zip_details():
37+
parent_dir_path = os.path.abspath('.')
38+
parent_dir_name = os.path.basename(parent_dir_path)
39+
script_name = CUSTOM_SCRIPT_NAME or parent_dir_name
40+
zip_file_name = script_name + '.zip'
41+
42+
return {"parent_dir_path": parent_dir_path,
43+
"parent_dir_name": parent_dir_name,
44+
"script_name": script_name,
45+
"zip_file_name": zip_file_name}
46+
47+
48+
def is_whitelisted(f, file_path, files_to_exclude):
49+
is_regular_file = os.path.isfile(file_path)
50+
is_not_excluded = f not in files_to_exclude
51+
is_not_pyc = not f.endswith('.pyc')
52+
return is_regular_file and is_not_excluded and is_not_pyc
53+
54+
55+
def make_zipfile(output_filename, source_dir, files_to_exclude, dirs_to_exclude):
56+
import zipfile
57+
with zipfile.ZipFile(output_filename, "w", zipfile.ZIP_DEFLATED) as z:
58+
for root, dirs, files in os.walk(source_dir):
59+
dirs[:] = [d for d in dirs if d not in dirs_to_exclude]
60+
for f in files:
61+
file_path = os.path.join(root, f)
62+
if is_whitelisted(f, file_path, files_to_exclude):
63+
arcname = os.path.join(os.path.relpath(root, source_dir), f)
64+
z.write(file_path, arcname)
65+
66+
67+
def zip_files():
68+
zip_details = get_zip_details()
69+
zip_file_name = zip_details["zip_file_name"]
70+
dirs_to_exclude = [".git"]
71+
files_to_exclude = [zip_file_name, "venv", ".idea", "credentials.py"]
72+
try:
73+
make_zipfile(output_filename=zip_file_name,
74+
source_dir=zip_details["parent_dir_path"],
75+
files_to_exclude=files_to_exclude,
76+
dirs_to_exclude=dirs_to_exclude)
77+
except Exception as e:
78+
print(error_red("[-] error zipping up file: " + str(e)))
79+
exit(1)
80+
else:
81+
if zip_file_name in os.listdir("."):
82+
print("[+] ZIPPED UP: '{zip_name}'".format(zip_name=zip_file_name))
83+
else:
84+
print("[-] ZIP FILE NOT PRESENT")
85+
86+
87+
def update_script_api_wrapper(cs_ses, script_name, zip_address):
88+
try:
89+
cs_ses.UpdateScript(script_name, zip_address)
90+
except Exception as e:
91+
print(error_red("[-] ERROR UPDATING SCRIPT IN PORTAL\n" + str(e)) + "\n"
92+
"PLEASE LOAD SCRIPT MANUALLY THE FIRST TIME")
93+
exit(1)
94+
else:
95+
print("[+] '{script}' updated on CloudShell Successfully".format(script=script_name))
96+
97+
98+
def update_script_on_server():
99+
zip_files()
100+
cs_ses = get_api_session()
101+
zip_details = get_zip_details()
102+
update_script_api_wrapper(cs_ses=cs_ses,
103+
script_name=zip_details["script_name"],
104+
zip_address=zip_details["zip_file_name"])
105+
106+
107+
update_script_on_server()
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
This script is a method to obtain sandbox id of newly formed job.
3+
Methodology is to pass in a UUID as global input, then to query sandbox id for sandbox with matching input value
4+
NOTE: Sandbox Api server may not be hosted on quali server, it is typically hosted together with Portal server
5+
https://help.quali.com/Online%20Help/0.0/Portal/Content/IG/Overview/cs-reqd-ports.htm?Highlight=ports
6+
"""
7+
import time
8+
9+
from quali_api_wrapper import QualiAPISession
10+
from sandbox_rest_api import SandboxRest
11+
import json
12+
from timeit import default_timer
13+
14+
15+
def get_sandbox_id_from_job(quali_api: QualiAPISession, sandbox_api: SandboxRest,
16+
suite_data: dict, global_input_name: str, global_input_value: str):
17+
print(f"starting new job, passing '{global_input_value}' as custom UUID")
18+
19+
# pass in custom global value - assuming only 1 job per suite
20+
global_inputs = suite_data["JobsDetails"][0]["Topology"]["GlobalInputs"]
21+
target_input = [x for x in global_inputs if x["Name"] == global_input_name][0]
22+
target_input["Value"] = global_input_value
23+
24+
# start new suite with quali pai
25+
suite_id = quali_api.enqueue_suite(suite_data=suite_data)
26+
print(f"suite started: {suite_id}")
27+
28+
# give DB a few seconds to propagate new sandbox
29+
time.sleep(3)
30+
31+
# query sandbox api for matching sandbox
32+
print("searching for job's sandbox...")
33+
start = default_timer()
34+
all_sandboxes = sandbox_api.get_sandboxes()
35+
for sandbox in all_sandboxes:
36+
sandbox_details = sandbox_api.get_sandbox_data(sandbox_id=sandbox["id"])
37+
global_inputs = sandbox_details["parameters"]
38+
target_global = [x for x in global_inputs if x["Name"] == global_input_name]
39+
if not target_global:
40+
continue
41+
target_value = target_global[0]["Value"]
42+
if target_value == global_input_value:
43+
print(f"sandbox id found after '{default_timer() - start}' seconds")
44+
return sandbox["id"]
45+
46+
47+
if __name__ == "__main__":
48+
SUITE_JSON_PATH = 'suite_data.json'
49+
TARGET_GLOBAL_PARAM_NAME = "my_uuid"
50+
TARGET_GLOBAL_PARAM_VALUE = "123456789"
51+
52+
quali_api = QualiAPISession(host="localhost", username="admin", password="admin", domain="Global")
53+
sandbox_api = SandboxRest(server="localhost", username="admin", password="admin", domain="Global")
54+
55+
# read in suite json
56+
with open(SUITE_JSON_PATH) as handle:
57+
suite_data_dict = json.loads(handle.read())
58+
59+
sandbox_id = get_sandbox_id_from_job(quali_api=quali_api,
60+
sandbox_api=sandbox_api,
61+
suite_data=suite_data_dict,
62+
global_input_name=TARGET_GLOBAL_PARAM_NAME,
63+
global_input_value=TARGET_GLOBAL_PARAM_VALUE)
64+
print(f"sandbox id: {sandbox_id}")

0 commit comments

Comments
 (0)