From 4f886c1f041b4d89a5a6053760359bbd6814f845 Mon Sep 17 00:00:00 2001 From: pnispero Date: Tue, 24 Mar 2026 17:14:09 -0700 Subject: [PATCH 1/6] Refactor configuration for more transparency. And refactored deployment controller to a more simpler generic deployment that most types of apps can follow. Fixed bugs with deployment controller --- bs_cli/adbs_cli/admin_commands.py | 201 ++---- bs_cli/adbs_cli/entry_point_commands.py | 26 +- build_scripts/start_build.sh | 21 +- deploy_controller/deployment_controller.py | 686 +++++++-------------- examples/firmware_config.yaml | 103 ++++ examples/ioc_config.yaml | 26 + examples/pydm_config.yaml | 17 + examples/pydm_deploy.yml | 43 ++ 8 files changed, 468 insertions(+), 655 deletions(-) create mode 100644 examples/firmware_config.yaml create mode 100644 examples/ioc_config.yaml create mode 100644 examples/pydm_config.yaml create mode 100644 examples/pydm_deploy.yml diff --git a/bs_cli/adbs_cli/admin_commands.py b/bs_cli/adbs_cli/admin_commands.py index 9659be7..c85156a 100644 --- a/bs_cli/adbs_cli/admin_commands.py +++ b/bs_cli/adbs_cli/admin_commands.py @@ -82,6 +82,7 @@ def add_initial_deployment(component: str, verbose: bool = False): # so if api ever changes, you don't need to update this function. # Grab deployment info from cram ls + click.confirm("Ensure you did a 'kinit' before continuing. Continue?") click.echo("== ADBS == Adding initial deployment configuration") click.echo("== ADBS == Running 'cram ls'...") @@ -108,24 +109,16 @@ def add_initial_deployment(component: str, verbose: bool = False): print(json.dumps(facility_data, indent=2)) print("\n" + "-"*50 + "\n") if (click.confirm("Does the above deployment info look correct")): - question = [ - inquirer.List( - "deploymentType", - message="What type of deployment will this app use?", - choices=["ioc", "hla", "tools", "matlab", "pydm", "container"] - ), - ] - deployment_type = inquirer.prompt(question)['deploymentType'] for facility, facility_data in result.items(): data_to_write = { "facility": facility, "component_name": component, "tag": facility_data['tag'], "user": cli_configuration['github_uname'], - "type": deployment_type + "type": "ioc", + "ioc_list": facility_data['dependsOn'] } - if (deployment_type == 'ioc'): - data_to_write["ioc_list"] = facility_data['dependsOn'] + data_to_write["ioc_list"] = facility_data['dependsOn'] request = Request(Component(component), Api.DEPLOYMENT) request.set_endpoint(ApiEndpoints.DEPLOYMENT_INITIAL) request.add_dict_to_payload(data_to_write) @@ -147,34 +140,20 @@ def add_repo(verbose: bool=False): manifest_filepath = user_src_repo + '/config.yaml' manifest_data = request.component.parse_manifest(manifest_filepath) - # 3) Populate the payload + # 3) Populate the payload from config.yaml request.add_to_payload("name", manifest_data["repo"]) request.add_to_payload("description", manifest_data["description"]) - request.add_to_payload("testingCriteria", manifest_data["testingCriteria"]) - request.add_to_payload("approvalRule", manifest_data["approvalRule"]) organization = manifest_data["organization"] request.add_to_payload("organization", organization) - issue_tracker = manifest_data["issueTracker"] - request.add_to_payload("issueTracker", issue_tracker) - if (issue_tracker != 'jira' and issue_tracker != 'github'): - click.echo("== ADBS == issue tracker must be jira or github.") - return - if (issue_tracker == 'jira'): - request.add_to_payload("jiraProjectKey", manifest_data["jiraProjectKey"]) - - build_os = {"buildOs": manifest_data.get("environments")} - request.add_dict_to_payload(build_os) request.add_to_payload("url", f"https://github.com/{organization}/{request.component.name}") request.add_to_payload("ssh", f"git@github.com:{organization}/{request.component.name}.git") - if (not click.confirm("Do you want to add automated build and tests?")): - request.add_to_payload("skipBuildAndTests", True) - + request.set_endpoint(ApiEndpoints.COMPONENT) request.post_request(verbose, msg="Add component to component database") - # Create another put request but to enable permissions for backend to receive events + # Enable permissions for backend to receive events request = Request(request.component) - request.set_endpoint(ApiEndpoints.COMPONENT_EVENT, + request.set_endpoint(ApiEndpoints.COMPONENT_EVENT, component_name=request.component.name, enable="true") request.put_request(log=verbose, msg="Enable events for component") @@ -197,10 +176,15 @@ def add_repo(verbose: bool=False): @click.option("-v", "--verbose", is_flag=True, required=False, help="More detailed output") def onboard_repo(ctx, verbose: bool=False): """Command to onboard a repo to software factory. - Creates config.yaml, adds component to database, adds initial deployment configuration (if existing IOC application)""" - click.confirm("Ensure you did a 'kinit' before continuing.") + Adds component to database and adds initial deployment configuration (if existing IOC application). + NOTE: You must create your own config.yaml before running this command. + See BuildSystem/examples/ for templates.""" + click.confirm("Please create a config.yaml in the top level of your repo (see BuildSystem/examples/ for templates) before running this command. Continue?") + click.confirm("Ensure you have created a config.yaml in the top level of your repo (see BuildSystem/examples/ for templates). Continue?") + + # Add component to database (reads repo/org/description from config.yaml) + add_repo(verbose) - # Create the config.yaml ===================================================== # Get user input at_top = click.confirm("Are you at the TOP level of your repo?") if (at_top): @@ -213,111 +197,22 @@ def onboard_repo(ctx, verbose: bool=False): else: click.echo(f"Error: The specified path '{top_level}' does not exist.") return - - org_name = input(INPUT_PREFIX + "Specify name of GitHub organization: ") - description = input(INPUT_PREFIX + "Specify repo description: ") - build_command = input(INPUT_PREFIX + "Specify how to build (if applicable, can be as simple as 'make'): ") - question = [ - inquirer.List( - "issueTracker", - message="What issue tracking system does this app use?", - choices=["github", "jira"] - ), - ] - issue_tracker = inquirer.prompt(question)['issueTracker'] - jira_project_key = 'n/a' - if (issue_tracker == 'jira'): - jira_project_key = input(INPUT_PREFIX + "Specify jira project key: ") - question = [ - inquirer.Checkbox( - "buildOs", - message="What are the operating systems this app runs on?", - choices=["ROCKY9", "RHEL7", "RHEL6", "RHEL5"], - default=[], - ), - ] - build_os_list = inquirer.prompt(question)['buildOs'] - question = [ - inquirer.List( - "deploymentType", - message="What type of deployment will this app use?", - choices=["ioc", "hla", "tools", "matlab", "pydm", "container"] - ), - ] - deployment_type = inquirer.prompt(question)['deploymentType'] - - # Create the content - content = f"""# [Required] -# Basic component information -repo: {repo_name} -organization: {org_name} -url: https://github.com/{org_name}/{repo_name} -description: {description} - -# [Required] -# Continous integration -approvalRule: all -testingCriteria: all -issueTracker: {issue_tracker} -jiraProjectKey: {jira_project_key} - -# [Required] -# Type of deployment -# Types: [ioc, hla, tools, matlab, pydm, container] -deploymentType: {deployment_type} - -# [Optional] -# Build method for building the component -# Can be a simple command like 'make' -""" - if (build_command == ""): - content += "# build: \n" - else: - content += f"build: {build_command}\n" - - if (build_os_list == []): - content += """ -# [Optional] -# Environments this app runs on -# environments: -""" - else: - content += f""" -# [Optional] -# Environments this app runs on -environments: -{chr(10).join(' - ' + env for env in build_os_list)} -""" - runtime_dependencies = click.confirm("Are there any runtime dependencies?") - if (runtime_dependencies): - deps_input = click.prompt("Enter dependencies (comma-separated)") - dependencies = [d.strip() for d in deps_input.split(',')] - content += f""" -# [Optional] -# Directories and files needed to run application -runtimeDependencies: -{chr(10).join(' - ' + dependency for dependency in dependencies)} -""" + + # Parse manifest to determine deployment type and get repo info + manifest_data = Component().parse_manifest(os.path.join(top_level, 'config.yaml')) + repo_name = manifest_data["repo"] + org_name = manifest_data["organization"] + playbook = manifest_data.get('deploy', {}).get('playbook', '') + if 'ioc_module' in playbook: + deployment_type = 'ioc' + elif 'pydm_module' in playbook: + deployment_type = 'pydm' else: - content += f""" -# [Optional] -# Directories and files needed to run application -# runtimeDependencies: -""" - - # Generate full filepath - filepath = os.path.join(top_level, 'config.yaml') - - # Write to file - with open(filepath, 'w') as f: - f.write(content) - - click.echo(f"File '{filepath}' has been generated successfully!") - - # Create the github actions deployment workflow file - if (deployment_type == "pydm"): - content = """name: Request Deployment - PyDM Display + deployment_type = 'generic' + # Write deploy.yml for pydm apps + if deployment_type == 'pydm': + pydm_deploy_content = """\ on: workflow_dispatch: inputs: @@ -345,12 +240,12 @@ def onboard_repo(ctx, verbose: bool=False): description: 'Tag to deploy' required: true type: string - + permissions: deployments: write contents: read actions: read - + jobs: deploy: uses: ad-build-test/build-system-playbooks/.github/workflows/request-deployment.yml@main @@ -362,22 +257,14 @@ def onboard_repo(ctx, verbose: bool=False): tag: ${{ inputs.tag }} deployment_type: 'pydm' """ - - # Generate full filepath - filepath = os.path.join(top_level, '.github/workflows/deploy.yml') - - # Create the directory if it doesn't exist - os.makedirs(os.path.dirname(filepath), exist_ok=True) - - # Write to file - with open(filepath, 'w') as f: - f.write(content) - - click.echo(f"File '{filepath}' has been generated successfully!") - - # If deployment type is IOC, then generate RELEASE_SITE, and remove .cram, and remove RELEASE_SITE from .gitignore - if (deployment_type == 'ioc'): - + deploy_yml_path = os.path.join(top_level, '.github/workflows/deploy.yml') + os.makedirs(os.path.dirname(deploy_yml_path), exist_ok=True) + with open(deploy_yml_path, 'w') as f: + f.write(pydm_deploy_content) + click.echo(f"File '{deploy_yml_path}' has been generated successfully!") + + # IOC-specific steps + if deployment_type == 'ioc': # Generate RELEASE_SITE release_site_contents = f""" #============================================================================== @@ -399,21 +286,17 @@ def onboard_repo(ctx, verbose: bool=False): ALARM_CONFIGS_TOP=/afs/slac/g/lcls/tools/AlarmConfigsTop #============================================================================== """ - # Generate full filepath filepath = os.path.join(top_level, 'RELEASE_SITE') - - # Write to file with open(filepath, 'w') as f: f.write(release_site_contents) - click.echo(f"File '{filepath}' has been generated successfully!") # Remove .cram directory try: shutil.rmtree(".cram") - click.echo(f"Successfully removed .cram directory") + click.echo("Successfully removed .cram directory") except FileNotFoundError: - pass # Already doesn't exist + pass # Remove RELEASE_SITE from .gitignore # Read all lines diff --git a/bs_cli/adbs_cli/entry_point_commands.py b/bs_cli/adbs_cli/entry_point_commands.py index b6acbdc..0b69aeb 100644 --- a/bs_cli/adbs_cli/entry_point_commands.py +++ b/bs_cli/adbs_cli/entry_point_commands.py @@ -466,14 +466,17 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: deployment_request = Request(Component(component), Api.DEPLOYMENT) deployment_request.set_component_name() - # Get app type + # Get app type from deploy.playbook in config.yaml user_src_repo = deployment_request.component.git_get_top_dir() manifest_filepath = user_src_repo + '/config.yaml' manifest_data = deployment_request.component.parse_manifest(manifest_filepath) - deployment_type = manifest_data.get('deploymentType', '').lower() - if not deployment_type: - click.echo("== ADBS == Error: 'deploymentType' not found or empty in manifest") - return + playbook = manifest_data.get('deploy', {}).get('playbook', '') + if 'ioc_module' in playbook: + deployment_type = 'ioc' + elif 'pydm_module' in playbook: + deployment_type = 'pydm' + else: + deployment_type = 'generic' # 1.1) Option - test if (test): @@ -562,10 +565,6 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: "dry_run": dry_run } - # 7) Figure out what the deployment type is and set the endpoint accordingly - user_src_repo = deployment_request.component.git_get_top_dir() - manifest_filepath = user_src_repo + '/config.yaml' - # 6) Error check - If user specified iocs - Confirm with database that every ioc found in the source tree is in the database. if (deployment_type == 'ioc' and ioc): # 6.1) First check that user is in repo @@ -674,10 +673,6 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: if (deployment_type == 'pydm'): subsystem = deployment_request.component.name.replace("pydm-", "") # Remove "pydm-" playbook_args_dict["subsystem"] = subsystem - # Error check - For pydm deployments, there can be a pydm subsystem for more than one facility - # So user_specified_facilities is required. - if (len(user_specified_facilities) < 1): - click.echo("== ADBS == ERROR: Please specify the facility(s)") deployment_request.add_to_payload("return_elog", True) # Get elog entry back from deployment playbook to print to user @@ -687,8 +682,11 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: deployment_request.add_dict_to_payload(playbook_args_dict) if (len(user_specified_facilities) > 0): click.echo("== ADBS == Deploying to " + str(user_specified_facilities) + "...") + elif (deployment_type == 'ioc'): + click.echo("== ADBS == Deploying to all facilities with active deployments...") else: - click.echo("== ADBS == Deploying...") + click.echo("== ADBS == ERROR: Please specify the facility(s)") + return deployment_response = deployment_request.put_request(log=verbose) if (not deployment_response.ok): try: diff --git a/build_scripts/start_build.sh b/build_scripts/start_build.sh index a0defe9..80e3b08 100755 --- a/build_scripts/start_build.sh +++ b/build_scripts/start_build.sh @@ -1,9 +1,20 @@ #!/bin/bash -# This is the official script for build containers. +# This is the official entrypoint script for build pods. +set -e -# Source the dev environment (This is needed for apps that have dependencies on the dev environment -# For example, apps that build for linuxRT have dependencies on certain library paths) -source /afs/slac/g/lcls/tools/script/ENVS64.bash +# If ADBS_COMMAND is set, run it directly (new config.yaml flow). +# The command from config.yaml is what runs — no hidden steps. +if [ -n "$ADBS_COMMAND" ]; then + cd "$ADBS_SOURCE" + echo "=== CBS Build ===" + echo "Component: $ADBS_COMPONENT" + echo "Branch: $ADBS_BRANCH" + echo "Command: $ADBS_COMMAND" + echo "=================" + eval "$ADBS_COMMAND" + exit $? +fi -# Call the main python script to do the build +# Legacy fallback: source dev environment and run start_build.py +source /afs/slac/g/lcls/tools/script/ENVS64.bash python3 /build/start_build.py \ No newline at end of file diff --git a/deploy_controller/deployment_controller.py b/deploy_controller/deployment_controller.py index 3f7613d..5c02cee 100644 --- a/deploy_controller/deployment_controller.py +++ b/deploy_controller/deployment_controller.py @@ -4,7 +4,6 @@ Usage: python3 deployment_controller.py note - this would have to run 24/7 as a service """ -from contextlib import asynccontextmanager, contextmanager import os import shutil import uuid @@ -20,10 +19,10 @@ import time import asyncio from fastapi import FastAPI, BackgroundTasks, HTTPException -from fastapi.responses import JSONResponse, FileResponse, Response +from fastapi.responses import JSONResponse, FileResponse from pydantic import BaseModel -from typing import Dict, Optional -from datetime import datetime, timezone, timedelta +from typing import Optional +from datetime import datetime from dateutil import parser """ @@ -61,6 +60,7 @@ ELOG_HEADERS = {"x-vouch-idp-accesstoken": ELOG_USER_PASSWORD} APP_PATH = "/app" +REQUEST_TIMEOUT = 60 # seconds, for all external HTTP calls # Container deployment secrets are loaded per-app from environment variables. # Naming convention: CONTAINER_{APP_KEY}_{SECRET} @@ -135,8 +135,8 @@ def save_task(task: DeploymentTask): "result": task.result, "error": task.error } - # Auto-expire after 5 mins - redis_client.setex(f"task:{task.task_id}", 300, json.dumps(task_dict)) + # Auto-expire after 10 mins + redis_client.setex(f"task:{task.task_id}", 600, json.dumps(task_dict)) def get_task(task_id: str) -> DeploymentTask: """Load task from Redis""" @@ -161,47 +161,34 @@ class RevertDict(Component): user: str facility: str ioc_list: Optional[list] = None - reboot_iocs: Optional[bool] = False # Optional + reboot_iocs: Optional[bool] = False -class IocDict(Component): - facilities: Optional[list] = None # Optional, defaults to None - tag: str - ioc_list: Optional[list] = None - user: str - dry_run: Optional[bool] = False # Optional - reboot_iocs: Optional[bool] = False # Optional - -class PydmDict(Component): - facilities: Optional[list] = None # Optional +class DeployDict(Component): + """Unified deployment request model. The playbook field determines app type and which + Ansible playbook runs. Special logic is applied for ioc_module and pydm_module playbooks; + everything else uses the generic handler (download release → run playbook).""" tag: str user: str - dry_run: Optional[bool] = False # Optional - subsystem: Optional[str] = "" # Optional Ex: [mps, mgnt, vac, prof, etc.] - return_elog: Optional[bool] = False # Optional - -class ContainerDict(Component): - facilities: Optional[list] = None # Optional - tag: str - user: str - return_elog: Optional[bool] = False # Optional - force_deploy: Optional[bool] = False # Optional - # App-specific configuration - docker_network: Optional[str] = None # Docker network name for inter-container DNS - migration_command: Optional[str] = None # e.g., "alembic upgrade head" — skipped if not set - health_check_path: Optional[str] = "/health" # Health check endpoint path - # Secrets — passed from GitHub Actions via core-build-system, with env var fallback + playbook: str # e.g. "ioc_module/ioc_deploy.yml" + facilities: Optional[list] = None + dry_run: Optional[bool] = False + return_elog: Optional[bool] = False + # IOC-specific + ioc_list: Optional[list] = None + reboot_iocs: Optional[bool] = False + # PyDM-specific + subsystem: Optional[str] = "" + # Container-specific + force_deploy: Optional[bool] = False + docker_network: Optional[str] = None + migration_command: Optional[str] = None + health_check_path: Optional[str] = "/health" database_url: Optional[str] = None redis_url: Optional[str] = None ghcr_token: Optional[str] = None ghcr_user: Optional[str] = None - -class AppDict(Component): - facilities: Optional[list] = None - tag: str - user: str - return_elog: Optional[bool] = False - artifact_url: Optional[str] = None # GitHub release asset URL - artifact_type: Optional[str] = 'rpm' # rpm, tar, zip + # Generic extra vars forwarded to the playbook as-is + extra_vars: Optional[dict] = None class InitialDeploymentDict(Component): # Used for the initial deployment endpoint @@ -235,7 +222,7 @@ def add_log_to_component(facility: str, timestamp: str, user: str, component_to_ "user": user, } endpoint = BACKEND_URL + f'deployments/{component_to_update}/{facility}/logs' - response = requests.post(endpoint, json=deployment_log) + response = requests.post(endpoint, json=deployment_log, timeout=REQUEST_TIMEOUT) return True def add_new_component(facility: str, app_type: str, component_name: str, @@ -260,7 +247,7 @@ def add_new_component(facility: str, app_type: str, component_name: str, logging.debug(f"new_component: {new_component}") endpoint = BACKEND_URL + 'deployments' - response = requests.post(endpoint, json=new_component) + response = requests.post(endpoint, json=new_component, timeout=REQUEST_TIMEOUT) return True def update_component_in_facility(facility: str, app_type: str, component_to_update: str, @@ -294,14 +281,14 @@ def update_component_in_facility(facility: str, app_type: str, component_to_upda # 4) Update component in db logging.debug(component) endpoint = BACKEND_URL + f'deployments/{component_to_update}/{facility}' - response = requests.put(endpoint, json=component) + response = requests.put(endpoint, json=component, timeout=REQUEST_TIMEOUT) logging.debug(f"response.json(): {response.json()}") return True def find_component_in_facility(facility: str, component_to_find: str) -> dict: """ Function to return component information """ endpoint = BACKEND_URL + f'deployments/{component_to_find}/{facility}' - response = requests.get(endpoint) + response = requests.get(endpoint, timeout=REQUEST_TIMEOUT) if (response.ok): return response.json()['payload'] else: @@ -312,7 +299,7 @@ def find_recent_deployment_for_component_facility(facility: str, component_to_fi deployment_index: 0 is the most recent, 1 is second most recent, etc. """ endpoint = BACKEND_URL + f'deployments/{component_to_find}/{facility}/logs' - response = requests.get(endpoint) + response = requests.get(endpoint, timeout=REQUEST_TIMEOUT) if (response.ok): payload = response.json()['payload'] else: @@ -343,29 +330,12 @@ def find_facility_an_ioc_is_in(ioc_to_find: str, component_with_ioc: str) -> lis def extract_date(entry) -> datetime: return datetime.fromisoformat(entry['date']) -def change_directory(path): - try: - os.chdir(path) - # print(f"Changed directory to {os.getcwd()}") - except FileNotFoundError: - raise FileNotFoundError(f"Directory {path} not found.") - -def rename_directory(src_dir, dest_dir): - try: - if os.path.isdir(src_dir): - os.rename(src_dir, dest_dir) - print(f"Renamed directory {src_dir} to {dest_dir}") - else: - raise ValueError(f"Directory {src_dir} not found.") - except Exception as e: - raise ValueError(f"Error renaming directory: {e}") - def create_tarball(directory, tag): tarball_name = f"{tag}.tar.gz" try: with tarfile.open(tarball_name, "w:gz") as tar: tar.add(directory, arcname=os.path.basename(directory)) - print(f"Created tarball: {tarball_name}") + logging.debug(f"Created tarball: {tarball_name}") return tarball_name except Exception as e: raise ValueError(f"Error creating tarball: {e}") @@ -383,7 +353,7 @@ def parse_shebang(shebang_line: str): binary_name = parts[1] # Second part is the binary name (e.g., myApp) return architecture, binary_name else: - print(f"Warning: Invalid path structure in shebang line: {shebang_line}") + logging.warning(f"Invalid path structure in shebang line: {shebang_line}") return None, None def extract_ioc_cpu_shebang_info(app_dir_name: str) -> dict: @@ -395,7 +365,7 @@ def extract_ioc_cpu_shebang_info(app_dir_name: str) -> dict: # 3) Check if the iocBoot directory exists if not os.path.exists(iocBoot_dir): - print(f"Error: The directory {iocBoot_dir} does not exist in the extracted files.") + logging.error(f"Directory {iocBoot_dir} does not exist in the extracted files.") return [] results = [] @@ -423,7 +393,7 @@ def extract_ioc_cpu_shebang_info(app_dir_name: str) -> dict: 'binary': binary_name }) else: - print(f"Warning: No shebang line in {st_cmd_path}") + logging.warning(f"No shebang line in {st_cmd_path}") return results @@ -440,7 +410,7 @@ def cleanup_temp_deployment_dir(directory: str): logging.error(f"Error cleaning up directory {directory}: {str(e)}") def download_release_helper(endpoint: str, download_dir: str, tarball_name: str, extract_tarball: bool): - response = requests.get(endpoint) + response = requests.get(endpoint, timeout=REQUEST_TIMEOUT) # Download file from api, and extract to download_dir # Download the .tar.gz file tarball_filepath = os.path.join(download_dir, tarball_name) @@ -519,6 +489,24 @@ def write_file(filepath: str, content: str): with open(filepath, 'w') as file: file.write(content) +def get_inventory_path() -> str: + """Return the Ansible inventory file path based on TEST_INVENTORY flag.""" + suffix = 'test_inventory.ini' if TEST_INVENTORY else 'global_inventory.ini' + return ANSIBLE_PLAYBOOKS_PATH + suffix + +def finalize_deployment(component_name: str, tag: str, user: str, facilities: list, + deployment_output: str, status: int, deployment_success: bool, + deployment_report_file: str, dry_run: bool, + facilities_ioc_dict: dict = None) -> dict: + """Generate deployment report, write to ELOG, and return the standard result dict.""" + summary = generate_report(component_name, tag, user, deployment_output, status, + deployment_report_file, facilities_ioc_dict, dry_run) + elog_url = "" + if not dry_run: + elog_url = send_deployment_to_elog(component_name, tag, facilities, summary) or "" + return {"summary": summary, "report_file": deployment_report_file, + "status": status, "success": deployment_success, "elog_url": elog_url} + def generate_report(component_name: str, tag: str, user: str, deployment_output: str, status: int, deployment_report_file: str, facilities_ioc_dict: dict=None, dry_run: bool=False): """ Generate a deployment report """ summary = \ @@ -530,9 +518,7 @@ def generate_report(component_name: str, tag: str, user: str, deployment_output: summary += f"\n#### IOCs deployed: {facilities_ioc_dict}" if (status == 200): # 200 means success - # 6.2) Write summary of deployment to report at the top summary += "\n#### Overall status: Success\n\n" + deployment_output - write_file(deployment_report_file, summary) else: # Failure status = 400 summary += "\n#### Overall status: Failure - PLEASE REVIEW\n\n" + deployment_output @@ -545,7 +531,7 @@ def send_deployment_to_elog(component_name: str, tag: str, facilities: list, sum """ Writes processed data to ELOG backend API based on the message type """ - print(f"Writing to the ELOG (SW_LOG) logbook through backend API for: {component_name} - {tag}") + logging.debug(f"Writing to the ELOG (SW_LOG) logbook through backend API for: {component_name} - {tag}") title = f"Deployment: {component_name} - {tag} {facilities}" text = f"
{summary_report}
" @@ -567,58 +553,57 @@ def send_deployment_to_elog(component_name: str, tag: str, facilities: list, sum # Send the request try: - print(f"Sending request to: {ELOG_ENDPOINT}") - print(f"Headers: {ELOG_HEADERS}") - response = requests.post(ELOG_ENDPOINT, headers=ELOG_HEADERS, json=payload) + logging.debug(f"Sending request to: {ELOG_ENDPOINT}") + response = requests.post(ELOG_ENDPOINT, headers=ELOG_HEADERS, json=payload, timeout=REQUEST_TIMEOUT) - print(f"Response status code: {response.status_code}") - print(f"Response headers: {response.headers}") + logging.debug(f"Response status code: {response.status_code}") + logging.debug(f"Response headers: {response.headers}") # Try to raise for status response.raise_for_status() - print(f"Successfully sent to ELOG API: {response.status_code}") - print(f"response: {response}") - print(f"response payload: {response.json()['payload']}") + logging.debug(f"Successfully sent to ELOG API: {response.status_code}") + logging.debug(f"response: {response}") + logging.debug(f"response payload: {response.json()['payload']}") elog_url = ELOG_URL_PREFIX + response.json()['payload'] + ELOG_URL_POSTFIX return elog_url except requests.exceptions.HTTPError as http_err: - print(f"HTTP Error: {http_err}") + logging.error(f"HTTP Error: {http_err}") # Print detailed response information - print(f"Response status code: {response.status_code}") - print(f"Response reason: {response.reason}") + logging.error(f"Response status code: {response.status_code}") + logging.error(f"Response reason: {response.reason}") # Try to get response text (may contain error details) try: - print(f"Response text: {response.text}") + logging.error(f"Response text: {response.text}") except: - print("Could not get response text") + logging.error("Could not get response text") # Try to parse JSON response (may contain error details) try: - print(f"Response JSON: {response.json()}") + logging.debug(f"Response JSON: {response.json()}") except: - print("Response is not valid JSON") + logging.error("Response is not valid JSON") - print(f"Request URL: {response.request.url}") - print(f"Request method: {response.request.method}") - print(f"Request headers: {response.request.headers}") - print(f"Request body: {response.request.body}") + logging.debug(f"Request URL: {response.request.url}") + logging.debug(f"Request method: {response.request.method}") + logging.debug(f"Request headers: {response.request.headers}") + logging.debug(f"Request body: {response.request.body}") return False except requests.exceptions.ConnectionError as conn_err: - print(f"Connection Error: {conn_err}") + logging.error(f"Connection Error: {conn_err}") return False except requests.exceptions.Timeout as timeout_err: - print(f"Timeout Error: {timeout_err}") + logging.error(f"Timeout Error: {timeout_err}") return False except requests.exceptions.RequestException as req_err: - print(f"Request Error: {req_err}") + logging.error(f"Request Error: {req_err}") return False except Exception as e: - print(f"General Error: {e}") - print(f"Failed payload: {payload}") + logging.error(f"General Error: {e}") + logging.error(f"Failed payload: {payload}") return False # Begin API functions ================================================================================= @@ -706,32 +691,6 @@ async def download_deployment_report(task_id: str): media_type='text/plain' ) -@app.post("/tag") -async def post_tag_creation(tag_request: TagDict): - """ - Function to create a tag and push it to artifact storage - """ - return NotImplementedError - results_dir_top = os.path.join(SCRATCH_FILEPATH, tag_request.results, tag_request.component_name) - - # 1) Change to the 'build_results' directory - build_results_dir = os.path.join(results_dir_top, "build_results") - build_results = f"{tag_request.component_name}-{tag_request.branch}" - change_directory(build_results_dir) - - # 2) Rename the specified directory to the tag - build_results_full_path = os.path.join(build_results_dir, build_results) - tagged_dir_path = os.path.join(build_results_dir, tag_request.tag) - rename_directory(build_results_full_path, tagged_dir_path) - - # 3) Create a tarball of the renamed directory - tarball_name = create_tarball(tagged_dir_path, tag_request.tag) - full_tarball_path = os.path.join(build_results_dir, tarball_name) - # 4) Push to artifact storage - return_code = artifact_api.put_component_to_registry(tag_request.component_name, full_tarball_path, tag_request.tag) - return JSONResponse(content={"payload": "Success"}, status_code=return_code) - - @app.put("/ioc/deployment/revert") async def revert_ioc_deployment(ioc_to_deploy: RevertDict, background_tasks: BackgroundTasks): """ @@ -759,116 +718,74 @@ async def revert_ioc_deployment(ioc_to_deploy: RevertDict, background_tasks: Bac revert_tag = previous_deployment.get("tag") - # 2) Deploy the reverted deployment for this facility - revert_deployment = IocDict(component_name=ioc_to_deploy.component_name, + # 2) Deploy the reverted deployment for this facility + if not revert_tag: + return JSONResponse(status_code=400, content={"payload": "No previous deployment found to revert to"}) + revert_deployment = DeployDict(component_name=ioc_to_deploy.component_name, facilities=[ioc_to_deploy.facility], tag=revert_tag, ioc_list=iocs_that_changed, - user=ioc_to_deploy.user) - - task_id = await deploy_ioc(revert_deployment, background_tasks, True) + user=ioc_to_deploy.user, + playbook='ioc_module/ioc_deploy.yml') - return JSONResponse( - status_code=202, - content={ - "task_id": task_id, - "status": "pending" - } - ) + return await deploy(revert_deployment, background_tasks) -@app.put("/ioc/deployment") -async def deploy_ioc(ioc_to_deploy: IocDict, background_tasks: BackgroundTasks, return_id_only: bool=False): - """Main entry point for IOC deployment API (async 202 pattern)""" +@app.put("/deployment") +async def deploy(deploy_request: DeployDict, background_tasks: BackgroundTasks): + """Unified deployment endpoint. Routes to IOC, PyDM, container, or generic handler + based on the playbook field (e.g. 'ioc_module/...', 'pydm_module/...', 'container_module/...').""" task_id = str(uuid.uuid4()) - - # Create task task = DeploymentTask(task_id, save_callback=save_task) save_task(task) - - # Start deployment in background - background_tasks.add_task( - deploy_ioc_async, - task_id, - ioc_to_deploy - ) - logging.debug(f"Returning TASK_ID: {task_id}") - if (return_id_only): - return task_id - - return JSONResponse( - status_code=202, - content={ - "task_id": task_id, - "status": "pending" - } - ) + background_tasks.add_task(deploy_async, task_id, deploy_request) + return JSONResponse(status_code=202, content={"task_id": task_id, "status": "pending"}) -async def deploy_ioc_async(task_id: str, ioc_to_deploy: IocDict): - """ - Runs the deployment logic asynchronously and updates task status - - Main entry point for IOC deployment API. - Handles these deployment scenarios: - 1. Deploy tag to select existing IOCs - (IOCs specified, facility not required) - ex: bs deploy -i sioc-sys0-bs01, sioc-sys0-bs02 R1.3.4 - 2. Deploy tag to all existing IOCs - (IOCs specified, facility not required) - 2.1. Deploy tag to all existing IOCs but user specified which facilities they want to update. - This would end up being case 2, but the cli would need logic - to figure out which IOCs in the facilities to deploy - ex: bs deploy -i ALL -f LCLS, FACET R1.3.4 - 3. Deploy tag to new IOCs - (IOCs specified, facility required) - ex: bs deploy -i sioc-sys0-bs01, sioc-sys0-bs02 -f LCLS R1.3.4 - 4. Deploy tag to component - (no IOCs, facility required) - works for both new and existing components - ex: bs deploy -f LCLS R1.3.4 - 5. Deploy tag to new component AND new IOCs - (IOCs specified, facility required) - ex: bs deploy -i sioc-sys0-bs01, sioc-sys0-bs02 -f LCLS R1.3.4 - """ - await asyncio.sleep(0.1) # Force yield +async def deploy_async(task_id: str, deploy_request: DeployDict): + """Dispatch to the right deployment handler based on playbook path.""" + await asyncio.sleep(0.1) task = get_task(task_id) - temp_download_dir = f"{APP_PATH}/tmp/{task_id}" - task.temp_dir = temp_download_dir - + temp_dir = f"{APP_PATH}/tmp/{task_id}" + os.makedirs(temp_dir, exist_ok=True) + task.temp_dir = temp_dir try: - os.makedirs(temp_download_dir, exist_ok=True) - logging.info(f"New deployment request data: {ioc_to_deploy}") - - task.update_progress("Determining deployment type", 5) - - # Handle component-only deployment - if not ioc_to_deploy.ioc_list: - logging.info("Component-only deployment") - task.update_progress("Component-only deployment", 10) - result = deploy_component(ioc_to_deploy, temp_download_dir, task) - - # Handle IOC deployments - elif ioc_to_deploy.facilities: - logging.info("Deploy tag to new IOCs") - # Case 3: Deploy tag to new IOCs (IOCs specified, facility required) - # Case 5: Deploy new component AND new IOCs (IOCs specified, facility required) - task.update_progress("Deploying to new IOCs", 10) - result = deploy_iocs_with_facility(ioc_to_deploy, temp_download_dir, task) + if 'ioc_module' in deploy_request.playbook: + result = await asyncio.get_running_loop().run_in_executor(None, deploy_ioc_sync, deploy_request, temp_dir, task) + elif 'container_module' in deploy_request.playbook: + result = await asyncio.get_running_loop().run_in_executor(None, deploy_container_sync, deploy_request, temp_dir, task) else: - logging.info("Deploy tag to existing IOCs") - # Cases 1 & 2: Deploy tag to existing IOCs (facility not required) - task.update_progress("Deploying to existing IOCs", 10) - result = deploy_existing_iocs(ioc_to_deploy, temp_download_dir, task) - - # Store result (summary and report file path) + result = await asyncio.get_running_loop().run_in_executor(None, run_generic_deployment, deploy_request, temp_dir, task) task.complete(result) - except Exception as e: logging.exception(f"Deployment {task_id} failed") task.fail(str(e)) - # Cleanup on failure - if os.path.exists(temp_download_dir): - cleanup_temp_deployment_dir(temp_download_dir) + cleanup_temp_deployment_dir(temp_dir) -def deploy_component(ioc_to_deploy: IocDict, temp_download_dir: str, task: DeploymentTask): +def deploy_ioc_sync(ioc_to_deploy: DeployDict, temp_download_dir: str, task: DeploymentTask): + """ + IOC deployment logic. Handles these scenarios: + 1. Deploy tag to select existing IOCs (IOCs specified, facility not required) + 2. Deploy tag to all existing IOCs + 3. Deploy tag to new IOCs (IOCs specified, facility required) + 4. Deploy tag to component only (no IOCs, facility required) + 5. Deploy new component AND new IOCs + """ + logging.info(f"New IOC deployment request: {ioc_to_deploy}") + # Handle component-only deployment + if not ioc_to_deploy.ioc_list: + logging.info("Component-only deployment") + task.update_progress("Component-only deployment", 10) + return deploy_component(ioc_to_deploy, temp_download_dir, task) + # IOC deployments with facility specified (new IOCs or new component) + elif ioc_to_deploy.facilities: + logging.info("Deploy tag to new IOCs") + task.update_progress("Deploying to new IOCs", 10) + return deploy_iocs_with_facility(ioc_to_deploy, temp_download_dir, task) + else: + logging.info("Deploy tag to existing IOCs") + task.update_progress("Deploying to existing IOCs", 10) + return deploy_existing_iocs(ioc_to_deploy, temp_download_dir, task) + +def deploy_component(ioc_to_deploy: DeployDict, temp_download_dir: str, task: DeploymentTask): """ Handle component-only deployment - Deploy tag to component (either new or existing) with facility specified @@ -898,7 +815,7 @@ def deploy_component(ioc_to_deploy: IocDict, temp_download_dir: str, task: Deplo facilities_ioc_dict, new_component, task ) -def deploy_existing_iocs(ioc_to_deploy: IocDict, temp_download_dir: str, task: DeploymentTask): +def deploy_existing_iocs(ioc_to_deploy: DeployDict, temp_download_dir: str, task: DeploymentTask): """ Handle deployments to existing IOCs - Case 1: Deploy tag to select existing IOCs @@ -929,7 +846,7 @@ def deploy_existing_iocs(ioc_to_deploy: IocDict, temp_download_dir: str, task: D facilities_ioc_dict, False, task # No new components ) -def deploy_iocs_with_facility(ioc_to_deploy: IocDict, temp_download_dir: str, task: DeploymentTask): +def deploy_iocs_with_facility(ioc_to_deploy: DeployDict, temp_download_dir: str, task: DeploymentTask): """ Handle deployment of IOCs with facility specified - Case 3: Deploy tag to new IOCs (facility required) @@ -961,7 +878,7 @@ def deploy_iocs_with_facility(ioc_to_deploy: IocDict, temp_download_dir: str, ta ) -def execute_ioc_deployment(ioc_to_deploy: IocDict, temp_download_dir: str, +def execute_ioc_deployment(ioc_to_deploy: DeployDict, temp_download_dir: str, facilities_ioc_dict: dict, new_component: bool, task: DeploymentTask): """ Called by the specific deployment functions after they determine what to deploy. @@ -990,9 +907,7 @@ def execute_ioc_deployment(ioc_to_deploy: IocDict, temp_download_dir: str, ioc_playbooks_path = ANSIBLE_PLAYBOOKS_PATH + 'ioc_module' playbook_args_dict['playbook_path'] = ioc_playbooks_path local_ioc_playbooks_path = ANSIBLE_PLAYBOOKS_PATH + 'ioc_module' - inventory_file_path = ANSIBLE_PLAYBOOKS_PATH - if (TEST_INVENTORY): inventory_file_path += 'test_inventory.ini' - else: inventory_file_path += 'global_inventory.ini' + inventory_file_path = get_inventory_path() # Skip facilities with empty IOC lists for component-only deployments is_component_only = len(facilities_ioc_dict[facility]) == 0 @@ -1074,144 +989,22 @@ def execute_ioc_deployment(ioc_to_deploy: IocDict, temp_download_dir: str, facilities_ioc_dict[facility] ) - # Error check - If deployment output is empty, then nothing was deployed - if (deployment_output == ""): - return JSONResponse(content={"payload": {"Error": "No deployments performed. This may be due to empty IOC lists or invalid component/facility combinations."}}, status_code=400) + if deployment_output == "": + raise ValueError("No deployments performed. This may be due to empty IOC lists or invalid component/facility combinations.") - # Generate summary for report task.update_progress("Generating deployment report", 90) - summary = generate_report(ioc_to_deploy.component_name, ioc_to_deploy.tag, ioc_to_deploy.user, - deployment_output, status, deployment_report_file, facilities_ioc_dict, ioc_to_deploy.dry_run) - - # Send summary to elog - if (not ioc_to_deploy.dry_run): + if not ioc_to_deploy.dry_run: task.update_progress("Writing to ELOG", 95) - send_deployment_to_elog(ioc_to_deploy.component_name, ioc_to_deploy.tag, list(facilities_ioc_dict.keys()), summary) - - task.complete(summary) - - # Return ansible playbook output to user - return { - "summary": summary, - "report_file": deployment_report_file, - "status": status - } - -@app.put("/pydm/deployment") -async def deploy_pydm(pydm_to_deploy: PydmDict, background_tasks: BackgroundTasks): - """ - Function to deploy a pydm "screen/display" component - """ - # 1) Setup temporary directory for deployment contents - request_id = str(uuid.uuid4()) - temp_download_dir = f"{APP_PATH}/tmp/{request_id}" - os.makedirs(temp_download_dir, exist_ok=True) - logging.info(f"New deployment request data: {pydm_to_deploy}") - # 2) Call to backend to get component/tag from github releases - if (not download_release(pydm_to_deploy.component_name, pydm_to_deploy.tag, temp_download_dir, all_os=False)): - return JSONResponse(content={"payload": {"Error": "Deployment tag may not exist or software factory backend is broken"}}, status_code=400) - - # 3) Logic for special cases - facilities = pydm_to_deploy.facilities - - # If subsystem not passed, then use component name - pydm_to_deploy.subsystem = pydm_to_deploy.component_name.replace("pydm-", "").replace("-displays", "") - - # Special case - if adding new deployment - deploy_new_component = False - # If adding to multiple facilities, loop through them - for facility in facilities: - # Check if deployment already exists - component = find_component_in_facility(facility, pydm_to_deploy.component_name) - logging.debug(f"component: {component}") - if (component): - deploy_new_component = False - else: - # Otherwise create a new entry to deployment database - deploy_new_component = True - logging.debug(f"deploy_new_component: {deploy_new_component}") - - local_pydm_playbooks_path = ANSIBLE_PLAYBOOKS_PATH + 'pydm_module' - inventory_file_path = ANSIBLE_PLAYBOOKS_PATH - if (TEST_INVENTORY): inventory_file_path += 'test_inventory.ini' - else: inventory_file_path += 'global_inventory.ini' - - tarball = f'{pydm_to_deploy.tag}.tar.gz' - tarball_filepath = os.path.join(temp_download_dir, tarball) - - # in the loop below copy the ioc_dict, but only get the iocs within that facility (facilities_ioc_dict[facility]) - # 4) Call the appropriate ansible playbook for each applicable facility - playbook_args_dict = pydm_to_deploy.model_dump() - playbook_args_dict['tarball'] = tarball_filepath - status = 200 - deployment_report_file = temp_download_dir + '/deployment-report-' + pydm_to_deploy.component_name + '-' + pydm_to_deploy.tag + '.log' - deployment_output = "" - for facility in facilities: - logging.info(f"facility: {facility}") - # 5) If component doesn't exist in facility and not a new component, then skip. - if (not deploy_new_component and find_component_in_facility(facility, pydm_to_deploy.component_name) is None): - continue - - playbook_args_dict['facility'] = facility - # TODO: - may want to do a dry run first to see if there would be any fails. - playbook_args = json.dumps(playbook_args_dict) # Convert dictionary to JSON string - stdout, stderr, return_code = ansible_api.run_ansible_playbook(inventory_file_path, local_pydm_playbooks_path + '/pydm_deploy.yml', - facility, playbook_args, return_output=True, no_color=True, check_mode=pydm_to_deploy.dry_run) - # 5.1) Combine output - current_output = "" - current_output += "== Deployment output for " + facility + ' ==\n\n' + stdout - deployment_success = True - if (return_code != 0): - status = 400 # Deployment failed - if (stderr != ''): - current_output += "\n== Errors ==\n\n" + stderr - deployment_success = False - deployment_output += current_output - - - if (not pydm_to_deploy.dry_run): - # 6) Write new configuration to deployment db for each facility - update_db_after_deployment(deployment_success, deploy_new_component, facility, 'pydm', pydm_to_deploy.component_name, - pydm_to_deploy.tag, pydm_to_deploy.user, current_output) - - # Error check - If deployment output is empty, then the component can't be found in deployment database - if (deployment_output == ""): - return JSONResponse(content={"payload": {"No deployments performed. This may be due to invalid component/facility combinations"}}, status_code=400) - - # 6) Generate summary for report - summary = generate_report(pydm_to_deploy.component_name, pydm_to_deploy.tag, pydm_to_deploy.user, - deployment_output, status, deployment_report_file, dry_run=pydm_to_deploy.dry_run) - - # Send summary to elog - if (not pydm_to_deploy.dry_run): - elog_url = send_deployment_to_elog(pydm_to_deploy.component_name, pydm_to_deploy.tag, facilities, summary) - - # Add cleanup - background_tasks.add_task(cleanup_temp_deployment_dir, temp_download_dir) - - # 7) Return ansible playbook output to user - if os.getenv('PYTHON_TESTING') == 'True': - content = summary - return Response(content=content, media_type="text/plain", status_code=status) - elif (pydm_to_deploy.return_elog): - return JSONResponse(content={ - "success": deployment_success, - "elog_url": elog_url - }) - else: - return FileResponse(path=deployment_report_file, status_code=status) - + return finalize_deployment( + ioc_to_deploy.component_name, ioc_to_deploy.tag, ioc_to_deploy.user, + list(facilities_ioc_dict.keys()), deployment_output, status, deployment_success, + deployment_report_file, ioc_to_deploy.dry_run, facilities_ioc_dict + ) -@app.put("/container/deployment") -async def deploy_container(container_to_deploy: ContainerDict, background_tasks: BackgroundTasks): - """ - Deploy a containerized application via Docker Compose. - Runs the container_module Ansible playbook to pull images and deploy services. - Secrets can be passed in the request body (from GitHub Actions) or loaded from environment variables as fallback. - """ +def deploy_container_sync(container_to_deploy: DeployDict, temp_dir: str, task: DeploymentTask): + """Container deployment logic. No source tarball needed — just runs the container playbook.""" logging.info(f"New container deployment request: {container_to_deploy}") - # Use request body secrets if provided, otherwise fall back to per-app env vars env_secrets = get_container_secrets(container_to_deploy.component_name) secrets = { 'database_url': container_to_deploy.database_url or env_secrets['database_url'], @@ -1221,13 +1014,9 @@ async def deploy_container(container_to_deploy: ContainerDict, background_tasks: } if not secrets['database_url']: app_key = container_to_deploy.component_name.upper().replace("-", "_") - return JSONResponse(content={"payload": {"Error": f"database_url not provided in request and CONTAINER_{app_key}_DATABASE_URL environment variable not set"}}, status_code=500) + raise ValueError(f"database_url not provided and CONTAINER_{app_key}_DATABASE_URL env var not set") - # Setup paths - local_container_playbooks_path = ANSIBLE_PLAYBOOKS_PATH + 'container_module' - inventory_file_path = ANSIBLE_PLAYBOOKS_PATH - if (TEST_INVENTORY): inventory_file_path += 'test_inventory.ini' - else: inventory_file_path += 'global_inventory.ini' + inventory_file_path = get_inventory_path() # Build extra-vars for Ansible (app_name comes from component_name) # Only include optional fields that are configured @@ -1253,17 +1042,15 @@ async def deploy_container(container_to_deploy: ContainerDict, background_tasks: status = 200 deployment_output = "" deployment_success = True - request_id = str(uuid.uuid4()) - temp_download_dir = f"{APP_PATH}/tmp/{request_id}" - os.makedirs(temp_download_dir, exist_ok=True) - deployment_report_file = temp_download_dir + '/deployment-report-' + container_to_deploy.component_name + '-' + container_to_deploy.tag + '.log' + deployment_report_file = os.path.join(temp_dir, f'deployment-report-{container_to_deploy.component_name}-{container_to_deploy.tag}.log') + full_playbook_path = os.path.join(ANSIBLE_PLAYBOOKS_PATH, container_to_deploy.playbook) for facility in facilities: logging.info(f"Deploying container to facility: {facility}") playbook_args = json.dumps(playbook_args_dict) stdout, stderr, return_code = ansible_api.run_ansible_playbook( inventory_file_path, - local_container_playbooks_path + '/container_deploy.yml', + full_playbook_path, facility, playbook_args, return_output=True, @@ -1278,147 +1065,92 @@ async def deploy_container(container_to_deploy: ContainerDict, background_tasks: deployment_success = False deployment_output += current_output - # Update deployment database update_db_after_deployment(deployment_success, True, facility, 'container', container_to_deploy.component_name, container_to_deploy.tag, container_to_deploy.user, current_output) - if (deployment_output == ""): - return JSONResponse(content={"payload": {"Error": "No deployments performed"}}, status_code=400) - - # Generate report - summary = generate_report(container_to_deploy.component_name, container_to_deploy.tag, - container_to_deploy.user, deployment_output, status, deployment_report_file) - - # Send to elog - elog_url = send_deployment_to_elog(container_to_deploy.component_name, container_to_deploy.tag, facilities, summary) + if deployment_output == "": + raise ValueError("No deployments performed") - # Cleanup - background_tasks.add_task(cleanup_temp_deployment_dir, temp_download_dir) + return finalize_deployment( + container_to_deploy.component_name, container_to_deploy.tag, container_to_deploy.user, + facilities, deployment_output, status, deployment_success, + deployment_report_file, container_to_deploy.dry_run + ) - if os.getenv('PYTHON_TESTING') == 'True': - return Response(content=summary, media_type="text/plain", status_code=status) - elif (container_to_deploy.return_elog): - return JSONResponse(content={ - "success": deployment_success, - "elog_url": elog_url - }) - else: - return FileResponse(path=deployment_report_file, status_code=status) +def run_generic_deployment(deploy_request: DeployDict, temp_dir: str, task: DeploymentTask): + """Generic deployment: download tagged release tarball, then run the specified playbook. + Handles pydm, HLA, TOOLS, and any other app type without IOC or container-specific logic.""" + logging.info(f"Generic deployment request: {deploy_request}") -@app.put("/app/deployment") -async def deploy_app(app_to_deploy: AppDict, background_tasks: BackgroundTasks): - """ - Deploy an application artifact (RPM, tarball, zip) to target servers. - Downloads the artifact from a GitHub release asset URL, then runs the - artifact_module Ansible playbook to extract and symlink on each facility. - """ - logging.info(f"New app deployment request: {app_to_deploy}") + # Default subsystem for pydm apps if not provided + if 'pydm_module' in deploy_request.playbook and not deploy_request.subsystem: + deploy_request.subsystem = deploy_request.component_name.replace("pydm-", "").replace("-displays", "") - # Validate artifact_url - if not app_to_deploy.artifact_url: - return JSONResponse(content={"payload": {"Error": "artifact_url is required for app deployments"}}, status_code=400) + # Derive app_type for the deployment DB from the playbook path + if 'pydm_module' in deploy_request.playbook: + app_type = 'pydm' + else: + app_type = deploy_request.playbook.split('/')[0] # e.g. 'hla_module' -> 'hla_module' - # Setup paths - request_id = str(uuid.uuid4()) - temp_download_dir = f"{APP_PATH}/tmp/{request_id}" - os.makedirs(temp_download_dir, exist_ok=True) + task.update_progress("Downloading release", 20) + if not download_release(deploy_request.component_name, deploy_request.tag, temp_dir, all_os=False, extract_tarball=True): + raise ValueError(f"Failed to download release for {deploy_request.component_name} tag {deploy_request.tag}") - # Determine file extension from artifact_type - ext_map = {'rpm': 'rpm', 'tar': 'tar.gz', 'tar.gz': 'tar.gz', 'tgz': 'tar.gz', 'zip': 'zip'} - ext = ext_map.get(app_to_deploy.artifact_type, app_to_deploy.artifact_type) - artifact_filename = f"{app_to_deploy.component_name}-{app_to_deploy.tag}.{ext}" - artifact_filepath = os.path.join(temp_download_dir, artifact_filename) + full_playbook_path = os.path.join(ANSIBLE_PLAYBOOKS_PATH, deploy_request.playbook) + inventory_file_path = get_inventory_path() - # Download artifact from GitHub release asset URL - github_token = os.environ.get("GITHUB_TOKEN", "") - headers = {"Accept": "application/octet-stream"} - if github_token: - headers["Authorization"] = f"token {github_token}" - - try: - response = requests.get(app_to_deploy.artifact_url, headers=headers, stream=True, allow_redirects=True) - if response.status_code != 200: - logging.error(f"Failed to download artifact: HTTP {response.status_code}") - return JSONResponse(content={"payload": {"Error": f"Failed to download artifact from {app_to_deploy.artifact_url}: HTTP {response.status_code}"}}, status_code=400) - - with open(artifact_filepath, 'wb') as f: - for chunk in response.iter_content(chunk_size=1024*1024): - if chunk: - f.write(chunk) - logging.info(f"Artifact downloaded to {artifact_filepath}") - except Exception as e: - logging.error(f"Error downloading artifact: {e}") - return JSONResponse(content={"payload": {"Error": f"Failed to download artifact: {str(e)}"}}, status_code=500) - - # Ansible setup - local_artifact_playbooks_path = ANSIBLE_PLAYBOOKS_PATH + 'artifact_module' - inventory_file_path = ANSIBLE_PLAYBOOKS_PATH - if TEST_INVENTORY: - inventory_file_path += 'test_inventory.ini' - else: - inventory_file_path += 'global_inventory.ini' + facilities = deploy_request.facilities or [] + tarball_filepath = os.path.join(temp_dir, f"{deploy_request.tag}.tar.gz") + deployment_report_file = os.path.join(temp_dir, f'deployment-report-{deploy_request.component_name}-{deploy_request.tag}.log') playbook_args_dict = { - 'component_name': app_to_deploy.component_name, - 'tag': app_to_deploy.tag, - 'artifact_path': artifact_filepath, - 'artifact_type': app_to_deploy.artifact_type, + 'component_name': deploy_request.component_name, + 'tag': deploy_request.tag, + 'user': deploy_request.user, + 'tarball': tarball_filepath, } + if deploy_request.subsystem: + playbook_args_dict['subsystem'] = deploy_request.subsystem + if deploy_request.extra_vars: + playbook_args_dict.update(deploy_request.extra_vars) - facilities = app_to_deploy.facilities status = 200 deployment_output = "" deployment_success = True - deployment_report_file = os.path.join(temp_download_dir, f'deployment-report-{app_to_deploy.component_name}-{app_to_deploy.tag}.log') - - for facility in facilities: - logging.info(f"Deploying app artifact to facility: {facility}") + elog_url = "" + for i, facility in enumerate(facilities): + task.update_progress(f"Deploying to {facility}", 30 + int(60 * i / max(len(facilities), 1))) + playbook_args_dict['facility'] = facility playbook_args = json.dumps(playbook_args_dict) stdout, stderr, return_code = ansible_api.run_ansible_playbook( - inventory_file_path, - local_artifact_playbooks_path + '/artifact_deploy.yml', - facility, - playbook_args, - return_output=True, - no_color=True - ) - - current_output = "== App deployment output for " + facility + ' ==\n\n' + stdout + inventory_file_path, full_playbook_path, facility, playbook_args, + return_output=True, no_color=True, check_mode=deploy_request.dry_run) + current_output = f"== Deployment output for {facility} ==\n\n{stdout}" + deployment_success = True if return_code != 0: status = 400 - if stderr != '': - current_output += "\n== Errors ==\n\n" + stderr + if stderr: + current_output += f"\n== Errors ==\n\n{stderr}" deployment_success = False deployment_output += current_output - - update_db_after_deployment(deployment_success, True, facility, 'app', - app_to_deploy.component_name, app_to_deploy.tag, - app_to_deploy.user, current_output) + if not deploy_request.dry_run: + update_db_after_deployment(deployment_success, True, facility, app_type, + deploy_request.component_name, deploy_request.tag, + deploy_request.user, current_output) if deployment_output == "": - return JSONResponse(content={"payload": {"Error": "No deployments performed"}}, status_code=400) - - # Generate report - summary = generate_report(app_to_deploy.component_name, app_to_deploy.tag, - app_to_deploy.user, deployment_output, status, deployment_report_file) - - # Send to elog - elog_url = send_deployment_to_elog(app_to_deploy.component_name, app_to_deploy.tag, facilities, summary) - - # Cleanup - background_tasks.add_task(cleanup_temp_deployment_dir, temp_download_dir) - - if os.getenv('PYTHON_TESTING') == 'True': - return Response(content=summary, media_type="text/plain", status_code=status) - elif app_to_deploy.return_elog: - return JSONResponse(content={ - "success": deployment_success, - "elog_url": elog_url - }) - else: - return FileResponse(path=deployment_report_file, status_code=status) + raise ValueError("No deployments performed — check facilities list and component name") + + task.update_progress("Generating report", 92) + if not deploy_request.dry_run: + task.update_progress("Writing to ELOG", 96) + return finalize_deployment( + deploy_request.component_name, deploy_request.tag, deploy_request.user, + facilities, deployment_output, status, deployment_success, + deployment_report_file, deploy_request.dry_run + ) @app.put("/initial/deployment") @@ -1441,7 +1173,7 @@ async def initial_deployment(initial_deployment: InitialDeploymentDict): new_component['dependsOn'] = initial_deployment.ioc_list logging.debug(f"new_component: {new_component}") endpoint = BACKEND_URL + 'deployments' - response = requests.post(endpoint, json=new_component) + response = requests.post(endpoint, json=new_component, timeout=REQUEST_TIMEOUT) add_log_to_component(initial_deployment.facility, timestamp, initial_deployment.user, initial_deployment.component_name, "Initial deployment entry added by software factory admins") return JSONResponse(content={"payload": {"Success": "Deployment added to database"}}, status_code=200) diff --git a/examples/firmware_config.yaml b/examples/firmware_config.yaml new file mode 100644 index 0000000..efb84ab --- /dev/null +++ b/examples/firmware_config.yaml @@ -0,0 +1,103 @@ +# Example config.yaml for a firmware application (LLRF) +# [Required] +repo: lcls2_llrf +organization: ad-build-test +url: https://github.com/ad-build-test/lcls2_llrf +description: LCLS-II LLRF firmware + +# [Optional] Docker image for build pods +image: ghcr.io/ad-build-test/bookworm-env:latest + +# [Optional] Global env vars available to all stages +variables: + XILINX_VIVADO: /non-free/Xilinx/Vivado/2020.2 + +# [Optional] Software tests — each gets its own pod +test: + sel4v_test: + command: "cd firmware/prc/sel4v && make && make clean" + prc_test: + command: "cd firmware/prc && make && make checks && make clean && make Vclm CONFIG=marble_sim" + resonance_control_test: + command: "cd firmware/resonance_control && make && make checks && make clean" + resonance_control_cdc_test: + command: "cd firmware/resonance_control && make application_top_cdc.txt" + prc_soft_test: + command: "cd software/prc && make checks && make clean" + injector_test: + command: "cd firmware/injector && make && make clean" + prc_cdc_test: + command: "cd firmware/prc && make application_top_cdc.txt CONFIG=cdc_test" + flake8: + command: "flake8 firmware/prc/*.py firmware/resonance_control/*.py software/prc/*.py" + +# [Required] Build — multi-target with matrix expansion +# Each target x matrix value gets its own build pod +build: + prc: + command: "cd firmware/prc && PATH=$XILINX_VIVADO/bin:$PATH make CONFIG=$TARGET prc.bit" + matrix: + TARGET: [qf2_v07, cmoc_qf2_v07, fiber_qf2_v07, marble, fiber_marble] + artifacts: + - "firmware/prc/*.bit" + resonance_control: + command: "cd firmware/resonance_control && PATH=$XILINX_VIVADO/bin:$PATH make CONFIG=$TARGET resonance_control.bit" + matrix: + TARGET: [qf2_v07, fiber_qf2_v07, marble, fiber_marble, marblepip] + artifacts: + - "firmware/resonance_control/*.bit" + injector: + command: "cd firmware/injector && XILINX_VIVADO=/non-free/Xilinx/Vivado/2018.3 PATH=$XILINX_VIVADO/bin:$PATH make CONFIG=$TARGET injector.bit" + matrix: + TARGET: [qf2_v07] + artifacts: + - "firmware/injector/*.bit" + +# [Optional] Hardware tests — triggered after ALL builds pass +hardwareTest: + runner: llrf-test-bench + prc_qf2_v07_run: + needs: [prc] + command: "cd software/prc && PYTHON=python3 sh lcls2_ci.sh -b ../../firmware/prc/prc*.bit -s 8350" + artifacts: + - "software/prc/rf_controls_*" + prc_qf2_cmoc_v07_run: + needs: [prc] + command: "cd software/prc && PYTHON=python3 sh cmoc_ci.sh -b ../../firmware/prc/prc*.bit" + artifacts: + - "software/prc/rf_controls_*" + prc_qf2_pip2_v07_run: + needs: [prc] + command: "cd software/prc && PYTHON=python3 sh pip2_ci.sh -b ../../firmware/prc/prc*.bit" + artifacts: + - "software/prc/rf_controls_*" + prc_fiber_qf2_v07_run: + needs: [prc] + command: "cd software/prc && PYTHON=python3 sh lcls2_ci.sh -b ../../firmware/prc/prc*.bit -a 192.168.0.201:803 -k -s 12500 -p" + artifacts: + - "software/prc/rf_controls_*" + injector_qf2_v07_hires_run: + needs: [injector] + command: "cd software/injector && PYTHON=python3 BIT=../../firmware/injector/injector*.bit IP=192.168.1.30 CONFIG=b46_gun sh injector_ci.sh" + artifacts: + - "software/injector/injector_rf_*" + injector_qf2_v07_lcls2_run: + needs: [injector] + command: "cd software/injector && PYTHON=python3 BIT=../../firmware/injector/injector*.bit IP=192.168.1.40 CONFIG=lcls2_buncher sh injector_ci.sh" + artifacts: + - "software/injector/injector_rf_*" + prc_marble_run: + needs: [prc] + command: "cd software/prc && PYTHON=python3 sh lcls2_ci.sh -b ../../firmware/prc/prc_marble*.bit -m -ms 39" + artifacts: + - "software/prc/rf_controls_*" + prc_fiber_marble_run: + needs: [prc] + command: "cd software/prc && PYTHON=python3 sh lcls2_ci.sh -b ../../firmware/prc/prc_fiber_marble*.bit -m -ms 39 -k" + artifacts: + - "software/prc/rf_controls_*" + resonance_control_qf2_v07_run: + needs: [resonance_control] + command: "cd software/res_ctl && PYTHON=python3 sh lbnl_rack.sh -b ../../firmware/resonance_control/resonance_control*.bit" + artifacts: + - "software/res_ctl/piezo_chirp_check__*" diff --git a/examples/ioc_config.yaml b/examples/ioc_config.yaml new file mode 100644 index 0000000..308f634 --- /dev/null +++ b/examples/ioc_config.yaml @@ -0,0 +1,26 @@ +# Example config.yaml for an IOC application +# [Required] +repo: test-ioc +organization: ad-build-test +url: https://github.com/ad-build-test/test-ioc +description: Test IOC application + +# [Optional] Docker image for build pods +image: ghcr.io/ad-build-test/rocky9-env:latest + +# [Required] Build command +build: + command: | + source /afs/slac/g/lcls/tools/script/ENVS64.bash && + make + +# [Optional] Files/directories to package for deployment +artifacts: + - bin + - db + - dbd + - iocBoot + +# [Optional] Deployment playbook +deploy: + playbook: ioc_module/ioc_deploy.yml diff --git a/examples/pydm_config.yaml b/examples/pydm_config.yaml new file mode 100644 index 0000000..18cc360 --- /dev/null +++ b/examples/pydm_config.yaml @@ -0,0 +1,17 @@ +# Example config.yaml for a PyDM display application +# [Required] +repo: mc-displays +organization: slaclab +url: https://github.com/slaclab/mc-displays +description: mc-displays + +# [Optional] Docker image for build pods +# image: ghcr.io/ad-build-test/rocky9-env:latest + +# [Optional] Build command — skip if no build step needed +# build: +# command: "pip install -r requirements.txt" + +# [Optional] Deployment playbook +deploy: + playbook: pydm_module/pydm_deploy.yml diff --git a/examples/pydm_deploy.yml b/examples/pydm_deploy.yml new file mode 100644 index 0000000..722c115 --- /dev/null +++ b/examples/pydm_deploy.yml @@ -0,0 +1,43 @@ +on: + workflow_dispatch: + inputs: + deploy_to_dev: + description: 'DEV' + required: false + type: boolean + default: false + deploy_to_lcls: + description: 'LCLS' + required: false + type: boolean + default: false + deploy_to_facet: + description: 'FACET' + required: false + type: boolean + default: false + deploy_to_testfac: + description: 'TESTFAC' + required: false + type: boolean + default: false + tag: + description: 'Tag to deploy' + required: true + type: string + +permissions: + deployments: write + contents: read + actions: read + +jobs: + deploy: + uses: ad-build-test/build-system-playbooks/.github/workflows/request-deployment.yml@main + with: + deploy_to_dev: ${{ inputs.deploy_to_dev }} + deploy_to_lcls: ${{ inputs.deploy_to_lcls }} + deploy_to_facet: ${{ inputs.deploy_to_facet }} + deploy_to_testfac: ${{ inputs.deploy_to_testfac }} + tag: ${{ inputs.tag }} + deployment_type: 'pydm' \ No newline at end of file From bfc777359ec994c1cd1e2b8c6e940ac6dae43e8f Mon Sep 17 00:00:00 2001 From: pnispero Date: Wed, 25 Mar 2026 16:30:09 -0700 Subject: [PATCH 2/6] Removed deploymentType, added in playbook to pass to deployment, every deployment through CLI is now polled as well like IOCs for easier to track progress, and should work for other types of deployments --- bs_cli/adbs_cli/admin_commands.py | 2 +- bs_cli/adbs_cli/cli_configuration.py | 4 +- bs_cli/adbs_cli/entry_point_commands.py | 31 +++-- deploy_controller/deployment_controller.py | 3 +- .../test_deployment_controller.py | 112 ++++++++++-------- 5 files changed, 81 insertions(+), 71 deletions(-) diff --git a/bs_cli/adbs_cli/admin_commands.py b/bs_cli/adbs_cli/admin_commands.py index c85156a..8977486 100644 --- a/bs_cli/adbs_cli/admin_commands.py +++ b/bs_cli/adbs_cli/admin_commands.py @@ -255,7 +255,7 @@ def onboard_repo(ctx, verbose: bool=False): deploy_to_facet: ${{ inputs.deploy_to_facet }} deploy_to_testfac: ${{ inputs.deploy_to_testfac }} tag: ${{ inputs.tag }} - deployment_type: 'pydm' + playbook: 'pydm_module/pydm_deploy.yml' """ deploy_yml_path = os.path.join(top_level, '.github/workflows/deploy.yml') os.makedirs(os.path.dirname(deploy_yml_path), exist_ok=True) diff --git a/bs_cli/adbs_cli/cli_configuration.py b/bs_cli/adbs_cli/cli_configuration.py index 6ece1fe..32f7c9a 100644 --- a/bs_cli/adbs_cli/cli_configuration.py +++ b/bs_cli/adbs_cli/cli_configuration.py @@ -20,8 +20,8 @@ class ApiEndpoints(str, Enum): DEPLOYMENT_CREATE_GH_STATUS = "deployments/status" # From deployment controller api - DEPLOYMENT = "{deployment_type}/deployment" - DEPLOYMENT_REVERT = "{deployment_type}/deployment/revert" + DEPLOYMENT = "deployment" + DEPLOYMENT_REVERT = "ioc/deployment/revert" DEPLOYMENT_STATUS = "deployment/{task_id}/status" DEPLOYMENT_REPORT = "deployment/{task_id}/report" DEPLOYMENT_INFO = "deployment/info" diff --git a/bs_cli/adbs_cli/entry_point_commands.py b/bs_cli/adbs_cli/entry_point_commands.py index 0b69aeb..435d450 100644 --- a/bs_cli/adbs_cli/entry_point_commands.py +++ b/bs_cli/adbs_cli/entry_point_commands.py @@ -137,9 +137,10 @@ def generate_deployment_report(file_content: str, component_name: str, tag: str) click.echo(f"Report downloaded successfully to {file_path}") def poll_deployment(response, deployment_status_request: Request): - """Poll deployment until complete, return final status""" + """Poll deployment until complete, return (report_response, elog_url)""" data = response.json() task_id = data.get("task_id", None) + elog_url = "" sleep(2) # Wait a bit for deployment status for _ in range(30): # 5 min max deployment_status_request.set_endpoint(ApiEndpoints.DEPLOYMENT_STATUS, @@ -153,6 +154,7 @@ def poll_deployment(response, deployment_status_request: Request): click.echo(f"\r\033[K{progress['percent']}% - {progress['current_step']} ", nl=False) if status_data["status"] == "completed": + elog_url = status_data.get("result", {}).get("elog_url", "") click.echo("\n== ADBS == Completed deployment. ") break @@ -160,7 +162,7 @@ def poll_deployment(response, deployment_status_request: Request): # Download report deployment_status_request.set_endpoint(ApiEndpoints.DEPLOYMENT_REPORT, task_id=task_id) - return deployment_status_request.get_request(log=False) + return deployment_status_request.get_request(log=False), elog_url @click.command() def configure_user(): @@ -526,8 +528,7 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: return deployment_request.add_to_payload("component_name", deployment_request.component.name) deployment_request.add_to_payload("user", linux_uname) - deployment_request.set_endpoint(ApiEndpoints.DEPLOYMENT_REVERT, - deployment_type=deployment_type) + deployment_request.set_endpoint(ApiEndpoints.DEPLOYMENT_REVERT) click.echo("== ADBS == Deploying to " + str(user_specified_facilities) + "...") for facility in user_specified_facilities: deployment_request.add_to_payload("facility", facility) @@ -535,8 +536,8 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: if (not response.ok): click.echo(f"== ADBS == Error - {response.json()}") return - response = poll_deployment(response, deployment_request) - file_content = response.content.decode('utf-8') + report_response, _ = poll_deployment(response, deployment_request) + file_content = report_response.content.decode('utf-8') generate_deployment_report(file_content, deployment_request.component.name, "revert") return @@ -562,7 +563,8 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: "component_name": deployment_request.component.name, "tag": tag, "user": linux_uname, - "dry_run": dry_run + "dry_run": dry_run, + "playbook": playbook } # 6) Error check - If user specified iocs - Confirm with database that every ioc found in the source tree is in the database. @@ -673,12 +675,9 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: if (deployment_type == 'pydm'): subsystem = deployment_request.component.name.replace("pydm-", "") # Remove "pydm-" playbook_args_dict["subsystem"] = subsystem - - deployment_request.add_to_payload("return_elog", True) # Get elog entry back from deployment playbook to print to user # 8) Send deployment request to deployment controller - deployment_request.set_endpoint(ApiEndpoints.DEPLOYMENT, - deployment_type=deployment_type) + deployment_request.set_endpoint(ApiEndpoints.DEPLOYMENT) deployment_request.add_dict_to_payload(playbook_args_dict) if (len(user_specified_facilities) > 0): click.echo("== ADBS == Deploying to " + str(user_specified_facilities) + "...") @@ -712,18 +711,16 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: except Exception: pass - if (deployment_type == 'ioc'): # If ioc deployment, then poll status - response = poll_deployment(response, deployment_request) - # Get the file content from the response - file_content = response.content.decode('utf-8') + # Poll all deployment types — PUT /deployment always returns 202 async + report_response, elog_url = poll_deployment(deployment_response, deployment_request) + if (deployment_type == 'ioc'): + file_content = report_response.content.decode('utf-8') generate_deployment_report(file_content, deployment_request.component.name, tag) - elog_url = deployment_response.json().get("elog_url", "") click.echo(f"== ADBS == Complete, log for details - {elog_url}") if (deployment_type == 'pydm'): # add github deployment status success deployment_status_request.add_to_payload("status", "SUCCESS") deployment_status_request.add_to_payload("logUrl", elog_url) - response = deployment_status_request.put_request(log=verbose) for facility in user_specified_facilities: deployment_status_request.add_to_payload("facility", facility) deployment_status_request.set_endpoint(ApiEndpoints.DEPLOYMENT_CREATE_GH_STATUS) diff --git a/deploy_controller/deployment_controller.py b/deploy_controller/deployment_controller.py index 5c02cee..2c9efd5 100644 --- a/deploy_controller/deployment_controller.py +++ b/deploy_controller/deployment_controller.py @@ -662,7 +662,8 @@ async def get_deployment_status(task_id: str): if task.status == "completed": response["result"] = { - "summary": task.result.get("summary") + "summary": task.result.get("summary"), + "elog_url": task.result.get("elog_url", "") } elif task.status == "failed": response["error"] = task.error diff --git a/deploy_controller/test_deployment_controller.py b/deploy_controller/test_deployment_controller.py index 02aa1d2..bf5c5f1 100644 --- a/deploy_controller/test_deployment_controller.py +++ b/deploy_controller/test_deployment_controller.py @@ -63,7 +63,7 @@ import fakeredis from fastapi.testclient import TestClient from unittest.mock import patch, MagicMock, mock_open -from deployment_controller import app, IocDict, PydmDict, RevertDict +from deployment_controller import app, DeployDict, RevertDict from httpx import AsyncClient, ASGITransport import asyncio @@ -85,7 +85,8 @@ def mock_paths(): patch('deployment_controller.TEST_INVENTORY', True), \ patch('deployment_controller.BACKEND_URL', 'https://ad-build-dev.slac.stanford.edu/api/cbs/v1/'), \ patch('deployment_controller.FACILITIES_LIST', ["test", "test2", "LCLS", "FACET", "TESTFAC", "DEV", "SANDBOX"]), \ - patch('deployment_controller.ANSIBLE_PLAYBOOKS_PATH', '/home/pnispero/test-deployment-controller/build-system-playbooks/'): + patch('deployment_controller.ANSIBLE_PLAYBOOKS_PATH', '/home/pnispero/test-deployment-controller/build-system-playbooks/'), \ + patch('deployment_controller.send_deployment_to_elog', return_value='http://mock-elog-url'): yield ####### Tests for get_deployment_component_info @@ -127,16 +128,17 @@ async def test_deploy_ioc_new_component_success(mock_paths): test_tag = "1.0.65" test_user = "test_user" - ioc_request = IocDict( + ioc_request = DeployDict( facilities=[test_facility], component_name=test_component, tag=test_tag, user=test_user, + playbook='ioc_module/ioc_deploy.yml', ) - print("Sending request to /ioc/deployment") + print("Sending request to /deployment") async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/ioc/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) summary = await wait_for_deployment(ac, response) assert "Deployment report" in summary @@ -167,17 +169,18 @@ async def test_deploy_ioc_new_component_and_ioc_success(mock_paths): test_ioc_list = "sioc-b34-gtest01" test_user = "test_user" - ioc_request = IocDict( + ioc_request = DeployDict( facilities=[test_facility], component_name=test_component, tag=test_tag, ioc_list=[test_ioc_list], - user=test_user + user=test_user, + playbook='ioc_module/ioc_deploy.yml', ) - print("Sending request to /ioc/deployment") + print("Sending request to /deployment") async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/ioc/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) summary = await wait_for_deployment(ac, response) assert "Deployment report" in summary @@ -206,17 +209,18 @@ async def test_deploy_ioc_new_ioc_success(mock_paths): print("Starting test_deploy_ioc_new_ioc_success - add a new ioc to an existing component\n \ bs deploy --facility test -i sioc-b34-gtest02 1.0.65") - ioc_request = IocDict( + ioc_request = DeployDict( facilities=["test"], component_name="test-ioc", tag="1.0.65", ioc_list=["sioc-b34-gtest02"], - user="test_user" + user="test_user", + playbook='ioc_module/ioc_deploy.yml', ) - print("Sending request to /ioc/deployment") + print("Sending request to /deployment") async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/ioc/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) summary = await wait_for_deployment(ac, response) assert "Deployment report" in summary @@ -234,18 +238,19 @@ async def test_deploy_ioc_new_tag_all_success_dry_run(mock_paths): test_ioc_list = ["sioc-b34-gtest01", "sioc-b34-gtest02"] test_user = "test_user" - ioc_request = IocDict( + ioc_request = DeployDict( component_name=test_component, tag=test_tag, ioc_list=test_ioc_list, user=test_user, - dry_run=True + dry_run=True, + playbook='ioc_module/ioc_deploy.yml', ) - print("Sending request to /ioc/deployment") + print("Sending request to /deployment") print(ioc_request.model_dump()) async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/ioc/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) summary = await wait_for_deployment(ac, response) assert "Deployment report" in summary @@ -277,17 +282,18 @@ async def test_deploy_ioc_new_tag_all_success(mock_paths): test_ioc_list = ["sioc-b34-gtest01", "sioc-b34-gtest02"] test_user = "test_user" - ioc_request = IocDict( + ioc_request = DeployDict( component_name=test_component, tag=test_tag, ioc_list=test_ioc_list, - user=test_user + user=test_user, + playbook='ioc_module/ioc_deploy.yml', ) - print("Sending request to /ioc/deployment") + print("Sending request to /deployment") print(ioc_request.model_dump()) async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/ioc/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) summary = await wait_for_deployment(ac, response) assert "Deployment report" in summary @@ -337,17 +343,18 @@ async def test_deploy_ioc_new_tag_specific_ioc_success(mock_paths): print("Starting test_deploy_ioc_new_tag_specific_ioc_success - deploy a new tag to an existing ioc in an existing component\n \ bs deploy -i sioc-b34-gtest02 1.0.67") - ioc_request = IocDict( + ioc_request = DeployDict( component_name="test-ioc", tag="1.0.67", ioc_list=["sioc-b34-gtest02"], - user="test_user" + user="test_user", + playbook='ioc_module/ioc_deploy.yml', ) - print("Sending request to /ioc/deployment") + print("Sending request to /deployment") print(ioc_request.model_dump()) async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/ioc/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) summary = await wait_for_deployment(ac, response) assert "Deployment report" in summary @@ -365,17 +372,18 @@ async def test_deploy_same_component_and_iocs_in_another_test_facility_success(m test_ioc_list = ["sioc-b34-gtest01", "sioc-b34-gtest02"] test_user = "test_user" - ioc_request = IocDict( + ioc_request = DeployDict( facilities=[test_facility], component_name=test_component, tag=test_tag, ioc_list=test_ioc_list, user=test_user, + playbook='ioc_module/ioc_deploy.yml', ) - print("Sending request to /ioc/deployment") + print("Sending request to /deployment") async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/ioc/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) summary = await wait_for_deployment(ac, response) assert "Deployment report" in summary @@ -405,17 +413,18 @@ async def test_deploy_ioc_new_tag_specific_ioc_multiple_facilities_success(mock_ - deploy a new tag to an existing ioc in an existing component, in multiple facilities\n \ bs deploy -i sioc-b34-gtest01 1.0.67") - ioc_request = IocDict( + ioc_request = DeployDict( component_name="test-ioc", tag="1.0.67", ioc_list=["sioc-b34-gtest01"], - user="test_user" + user="test_user", + playbook='ioc_module/ioc_deploy.yml', ) - print("Sending request to /ioc/deployment") + print("Sending request to /deployment") print(ioc_request.model_dump()) async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/ioc/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) summary = await wait_for_deployment(ac, response) assert "Deployment report" in summary @@ -434,18 +443,19 @@ async def test_deploy_ioc_new_tag_specific_ioc_specific_facility_success(mock_pa test_ioc_list = ["sioc-b34-gtest02"] test_user = "test_user" - ioc_request = IocDict( + ioc_request = DeployDict( facilities=[test_facility], component_name=test_component, tag=test_tag, ioc_list=test_ioc_list, user=test_user, + playbook='ioc_module/ioc_deploy.yml', ) - print("Sending request to /ioc/deployment") + print("Sending request to /deployment") print(ioc_request.model_dump()) async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/ioc/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) summary = await wait_for_deployment(ac, response) assert "Deployment report" in summary @@ -484,21 +494,22 @@ async def test_deploy_pydm_new_component_success(mock_paths): print("Starting test_deploy_pydm_new_component_success - add a new component entirely\n \ bs deploy --facility test 1.0.0") - pydm_request = PydmDict( + pydm_request = DeployDict( facilities=["test"], component_name="pydm-mps", tag="R1.0.0", user="test_user", - subsystem="mps" + subsystem="mps", + playbook='pydm_module/pydm_deploy.yml', ) - print("Sending request to /pydm/deployment") + print("Sending request to /deployment") async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/pydm/deployment", json=pydm_request.model_dump()) + response = await ac.put("/deployment", json=pydm_request.model_dump()) + summary = await wait_for_deployment(ac, response) - assert response.status_code == 200 - assert "Deployment report" in response.text - assert "Success" in response.text + assert "Deployment report" in summary + assert "Success" in summary @pytest.mark.asyncio async def test_deploy_pydm_new_tag_success(mock_paths): @@ -511,23 +522,24 @@ async def test_deploy_pydm_new_tag_success(mock_paths): test_user = "test_user" test_subsystem="mps" - ioc_request = PydmDict( + ioc_request = DeployDict( facilities=[test_facility], component_name=test_component, tag=test_tag, user=test_user, - subsystem=test_subsystem + subsystem=test_subsystem, + playbook='pydm_module/pydm_deploy.yml', ) - print("Sending request to /pydm/deployment") + print("Sending request to /deployment") async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: - response = await ac.put("/pydm/deployment", json=ioc_request.model_dump()) + response = await ac.put("/deployment", json=ioc_request.model_dump()) + summary = await wait_for_deployment(ac, response) - print(f"Received response with status code: {response.status_code}") + print(f"Received response with completed summary") - assert response.status_code == 200 - assert "Deployment report" in response.text - assert "Success" in response.text + assert "Deployment report" in summary + assert "Success" in summary print("Confirm deployment database contents are correct...") response = client.request("GET", "/deployment/info", json={"component_name": "pydm-mps"}) From 1374bd7c3ff9a8cb33a8e5ed47375d7ec186d427 Mon Sep 17 00:00:00 2001 From: pnispero Date: Thu, 26 Mar 2026 14:20:16 -0700 Subject: [PATCH 3/6] Bug fixes for deployment controller, make github deployment workflow available for any type of deployment --- bs_cli/adbs_cli/admin_commands.py | 10 +++++----- deploy_controller/deployment_controller.py | 3 ++- deploy_controller/test_deployment_controller.py | 2 ++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bs_cli/adbs_cli/admin_commands.py b/bs_cli/adbs_cli/admin_commands.py index 8977486..48cab1a 100644 --- a/bs_cli/adbs_cli/admin_commands.py +++ b/bs_cli/adbs_cli/admin_commands.py @@ -210,9 +210,9 @@ def onboard_repo(ctx, verbose: bool=False): else: deployment_type = 'generic' - # Write deploy.yml for pydm apps - if deployment_type == 'pydm': - pydm_deploy_content = """\ + # Write deploy.yml for github actions deployment (No IOC support yet) + if deployment_type == 'pydm' or deployment_type == 'generic': + deploy_content = f"""\ on: workflow_dispatch: inputs: @@ -255,12 +255,12 @@ def onboard_repo(ctx, verbose: bool=False): deploy_to_facet: ${{ inputs.deploy_to_facet }} deploy_to_testfac: ${{ inputs.deploy_to_testfac }} tag: ${{ inputs.tag }} - playbook: 'pydm_module/pydm_deploy.yml' + playbook: '{playbook}' """ deploy_yml_path = os.path.join(top_level, '.github/workflows/deploy.yml') os.makedirs(os.path.dirname(deploy_yml_path), exist_ok=True) with open(deploy_yml_path, 'w') as f: - f.write(pydm_deploy_content) + f.write(deploy_content) click.echo(f"File '{deploy_yml_path}' has been generated successfully!") # IOC-specific steps diff --git a/deploy_controller/deployment_controller.py b/deploy_controller/deployment_controller.py index 2c9efd5..549a9ff 100644 --- a/deploy_controller/deployment_controller.py +++ b/deploy_controller/deployment_controller.py @@ -1137,7 +1137,8 @@ def run_generic_deployment(deploy_request: DeployDict, temp_dir: str, task: Depl deployment_success = False deployment_output += current_output if not deploy_request.dry_run: - update_db_after_deployment(deployment_success, True, facility, app_type, + is_new_component = find_component_in_facility(facility, deploy_request.component_name) is None + update_db_after_deployment(deployment_success, is_new_component, facility, app_type, deploy_request.component_name, deploy_request.tag, deploy_request.user, current_output) diff --git a/deploy_controller/test_deployment_controller.py b/deploy_controller/test_deployment_controller.py index bf5c5f1..33082e8 100644 --- a/deploy_controller/test_deployment_controller.py +++ b/deploy_controller/test_deployment_controller.py @@ -10,6 +10,7 @@ 2) git clone https://github.com/ad-build-test/build-system-playbooks 3) Alter the paths for 'test' group in build-system-playbooks/global_inventory.ini to your username 4) Then in mock_paths(), alter the paths to your local ~/test-deployment-controller/ (Anywhere it says pnispero, change to your username) +5) Look in the dev mongodb and make sure test-ioc and pydm-mps are not already in the deployments collection. If they are, please delete those entries before testing. Usage: pytest test_deployment_controller.py @@ -58,6 +59,7 @@ os.environ['PYTHON_TESTING'] = 'True' os.environ['ELOG_USER_PASSWORD'] = "mock" +os.environ['ELOG_SW_LOG_ID'] = "mock" import pytest import fakeredis From 4174fdfef0f4b420b78fa8231f57a83065d0fa3d Mon Sep 17 00:00:00 2001 From: pnispero Date: Mon, 30 Mar 2026 13:49:44 -0700 Subject: [PATCH 4/6] Added more examples for config.yaml and fixed some bugs with admin cli and deployment controller os --- RELEASE_NOTES.md | 4 +++ bs_cli/adbs_cli/admin_commands.py | 5 ++-- bs_cli/dist/adbs_cli-1.1.12-py3-none-any.whl | Bin 28022 -> 27391 bytes bs_cli/dist/adbs_cli-1.1.12.tar.gz | Bin 25586 -> 25070 bytes bs_cli/setup.py | 2 +- build_scripts/README | 3 +++ deploy_controller/deployment_controller.py | 2 +- examples/firmware_config.yaml | 11 ++++---- examples/ioc_config.yaml | 9 +++---- examples/ioc_multiple_build_config.yml | 26 +++++++++++++++++++ examples/pydm_config.yaml | 10 +------ 11 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 build_scripts/README create mode 100644 examples/ioc_multiple_build_config.yml diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 23a0ff3..21218b0 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -3,6 +3,10 @@ Release notes for the AD Build System (Software Factory) ## Releases: +* tag:1.2.0 30-Mar-2026 P. Nisperos (pnispero) + * Refactor configuration for more transparency. And refactored deployment controller to a more simpler generic deployment that most types of apps can follow. Fixed bugs with deployment controller + * Removed deploymentType, added in playbook to pass to deployment, every deployment through CLI is now polled as well like IOCs for easier to track progress, and should work for other types of deployments + * tag:1.1.12 17-Feb-2026 P. Nisperos (pnispero) * CLI bs clone bug fix with tab complete diff --git a/bs_cli/adbs_cli/admin_commands.py b/bs_cli/adbs_cli/admin_commands.py index 48cab1a..fb8562b 100644 --- a/bs_cli/adbs_cli/admin_commands.py +++ b/bs_cli/adbs_cli/admin_commands.py @@ -180,7 +180,6 @@ def onboard_repo(ctx, verbose: bool=False): NOTE: You must create your own config.yaml before running this command. See BuildSystem/examples/ for templates.""" click.confirm("Please create a config.yaml in the top level of your repo (see BuildSystem/examples/ for templates) before running this command. Continue?") - click.confirm("Ensure you have created a config.yaml in the top level of your repo (see BuildSystem/examples/ for templates). Continue?") # Add component to database (reads repo/org/description from config.yaml) add_repo(verbose) @@ -213,6 +212,8 @@ def onboard_repo(ctx, verbose: bool=False): # Write deploy.yml for github actions deployment (No IOC support yet) if deployment_type == 'pydm' or deployment_type == 'generic': deploy_content = f"""\ +name: Deploy + on: workflow_dispatch: inputs: @@ -312,8 +313,6 @@ def onboard_repo(ctx, verbose: bool=False): file.writelines(filtered_lines) click.echo(f"Successfully removed RELEASE_SITE from .gitignore") - - add_repo(verbose) if (deployment_type == 'ioc'): if (click.confirm("Is this an existing IOC application?")): diff --git a/bs_cli/dist/adbs_cli-1.1.12-py3-none-any.whl b/bs_cli/dist/adbs_cli-1.1.12-py3-none-any.whl index 06c79aabbe2588b7da1fcc108f0a2d968e1d4253..7cc8c70cefc68c585cd57491184f47c6d93e23c2 100644 GIT binary patch delta 16432 zcmZX*V~}RS)}~#yZM)01ZQHi3r)=A{ZC7`hUAAqz>g#i2zIS3~Rz^nb9eHQu`jdC$ z-g&L(b>N>R-~@hz)>o86+pjuF3n&T_OCBi$&f)bI z(Qa!~Dbl~=$;vozP5tX_{iQ4gmKX@D5NR>4^hZ?%exe@Xg8V?f03VX%0px;T-RwN?(tW7M1>S3xE`+V%dHRU4c92#Ae!(9FH_won#_yM?xZi zcg%Nj30~QR6Xty@6V+4!N2wLtr6LC_1cX`Q8z*-m_)_rboM**)RzNaVSox%ldP~(2C0dr}O79d=Pi5g>)&Q<7pH3HPfSxulAsh4@awdds~%K5xr@d^!DRKVSDvHwItMT>1T{ z{eAD=^6#LpFLFPCdhacLiNekTA<-xs=`=>YIw}*gNEOB06e@O4-f*{$t;v>ZP7+E5 zSd5b-WwJz2q>*UQko2UDi;e;SFQTyaG?JkN#S?)oO#22Ok{(|?sbIT?9HY|~5KY%i zU@m8xhTdILi54-A%{o|h;43Gc6>iJ04bFB%sk*Q*&^ZG^mRn``pNRTj~@+9s4q1GEd`}%M3!p zt~Zy1Sg(*mC-@J>;?|5K?91TuDT(Hwpz3*={Hhfi+>jQG$gzg{&u~3b;iin}O(|cH zZ4BO5C|N!K;pbrs;Lh)-`tjNPr-tp!LD z+G5F_&&ZWiwY00vKGI>j=K7UQWZ@9NfobVl6d1KLebT|E5NfypC_K0t62;e}5^bqJ zAuezEoARVikSPl!S?@PKi>&OAP|h`OH-No!yz?NhO{VpR_cAb$M|EOwVL0fls6HQ^kQZ5pT2<+B#&in290i=aXi<9^%880h7f8h%LG`sn zEgun9QObXzG#SbX&T);c^Wgz<@bhz@8O4=_^MNYd5bIR2XU{ zDY_Sw-NPNBA2Jm-$fM{(o<#}wbc{=fEYe9z3uQ;ig4+QBkR53!S$~Upi6-CXfy1Jz zaEZ{ z*=%jV1H$1PM=#dsJw`iWb{pgPea2$|_yHlLe{u(w*<)|JRf4DkWh2%ssJGS*Ae*!o zL>@>5goQ4!s2e-)VZ#j&#@+4R`c4*n%oBMk-0EO^8@yds8I>=z;p<@HWPhl@(Q}zW z)qAn#duZ%7O@;>(}LjPvh3R=EyA*=|FF!`VczM>q}{BSs$r z;9osnIT8p!eFelbjM5xjsUmIu?gh&d0|_AkAEllEDPS=q!sx< z4K**9+0S-3xeJ;p{78B6AamE?j&3bYU4Yg)+E>Q$!V^# zyZ(i}aJt6GllJNheKPgR9J54vBX-Y?dba*u#vf&8eW~ar&D}7b#Ut78vb4biU@77? zb)qlopaU{54@z!Ck9jMH8Y=CMA z@OWdjvUtq;(x`Jg!$6JW-f!LHphX|P+vTf1AZOCcF=@)2@wc?birg|}pD@)q3x2?* z5*#ki7X`oKE6)S9HMRAxmQw)ha;b_xM`lHz)ltr31n1Kow__eG4EKKn07pFlKvc$c z0B6#=1bZ`{Yt@xW>)1&Jl(a#k`H8;|X-{uCLLCu{+kCJGeP4%C$1hhM3fiiRM}Y(8 zcfU}0edB9}WJ7YqoFHz;=tMYYgfTX``@{#}*?VLwS)@?{iz9hj1dak zn2TXd%NNS**_tggnScekRytN&gbbUk9b?i~S((A&8ob{o8a6sP#O&NKb?KoUHs!o4 zXjL!4TsM#d#GBxym*x08xQjx#e{Awv=ald-VUTE$)aanGATmRM1PYuTSY=Q;Jpku; zdplJV8+VwdbrJ+l0VqlE6Vy=$bU4ug9K)HCb@&2i+^0(9k7_wR2(p+F#n$n>rdd8w zhp7M5%#6;7~Ak5?*g^W>8RkuFt|ywj@&hMbGY{o zj5h5bw=ypHgQGBjYGXb(VhbulIm)kvx;t38V+i*T-`;f7EhJjbZ?=HNir?Iqhsl{9 z$m3~+lG@IVc~~_;nsP6FATM*|$YmI!;#g--ImbeE*cKZ?ZL;F%SP~`b`XI55tM5d= zDsM6>E#Z@5i&a>7mwjKszDvx9fX}iLJrp)BvkGg0>*G`a9&px?N=Bge7#TWNaN^*u z-OjCBpw2&Y$#mYl$7tQD+#Y|nBr#H_Df#Es?KpZ{+8qSofagHpQL z=BHw!2T!y-6SYdf2}l#lM0?)Fu|lEn#Z>Q+_=%kh8ZP@o z-*Yn(p1kG|g4K)=;EQ>_X37ovXn^L0T;pB@tL_E^=!Lg3GQT00r~M2po)d zyo9&y1wC{Bx)fLQu_B^kO*&$=lLzLu@8;|I(p=vLoI%68+L>sHv=jw04|?a1LP>E?JIZ~y+e18f`AAEK+>>hv zYK^g=JZSIBYjC(U#7C2AIL%R*1$f>7403X(-4Ul9)W5y|a5pzMC;P?F46xnLyqfyn z4GQq`_<4N#cUkNj=78DyQIS~1U3~tnGR@K=jqh9N%i3tzFo$7FkgzkX{#tc_VY{?g z6|@>x{Ys#`Zmy2ifkdiN(j$+q;A^ADDy<_uW|P-5AN;*I0OyYEBqnD%;_9Xch>zx; zj`GmT6u&34Bu+r@*Rg51EEt0MF0+D-mhX?(3UrbPw_@*g*`~4Wkic*SJ#NJKDWeHI3O1Ucfo;E=ZOMhV0cpGih>0Ccfg4DvkUMtZ9bikn1|l zCpW?C_IHj3!5fv#ZVR{ZgvWU;DfUN1Zqi?!n2)1gPIKXdB5jfp(++dsD;m@U|I31O?BJblqTffvy0HT?BUmwhRYHWRyw&)hqVMF1)v8g|CkeUGZisp&UpWG|< zV_9Q+-S{?A0Tu?6{IH#_{w*P4VyOXAEGh#5(aGU`LrQEGE+kP!c;65h@GRAW_DCo) zX-&97Vq7Zvd+WT!*rgd!>42LRHLDd-R{8H-;-H22TAoTzd4xaH3 zTsSgoqQSroqW;IPblNJl6@%C=6O}u)wCrS73^r)-e{i>sgA0+%zrd& zo{VbkT4$y=ILy950NoJQ06vs$*cFZngTD>iShxs5}nZ~=cDc_f*%eMDCYfKm>6ZK3wSV6xFfW^TZzG!lXU)PX|!;4fm z*r2&zYCEYmGaT*|`pXE?60xnap0(#j>FAYdEUQ*5ReR@x6OsSz5|n9sc%{s!p8A{0 zu(o!4Z1-zy^2|{VVFQ7TcDvk>P|g$~MFXB}mqnYO8io8xJO>mxQtmD!485R|&> z;b(|haA1`^AVdXDWw7#=hPVxsD-BR1+uA@uM zoc{XE0aS}UK*>jshX#w7om88`p75``vM=gM(TGtFKpYDp=sSUXzV`^WCJ48CRlHMd zlA6E%@VFg;Atv}tAJV{2M|8U~J}Ku=nJ8(D@$ZV+) z*2t?FFh*u#(?EP9DWb!NN;SV|Ub^XY!~3pqSuM{}xcG9bUklM~xLwbWI`_|q8uw2* zI+s8#z*r5osJT$O)UiRL0MZ*|$LWTQDisc~F}Iy4N9^(TM2W901W z?4%VieOIl#n)_*ECgFoN_a>ky0}6%)1Ox=tOo`C|f#Or{rCV$QH7g1R1Vji61cVQi z3}a20426#m*uW4YoH>m|z)IEQ=abn2}Xcxz(>)5obV3eW>RZ4QH($4b$ zwlRV6!w(~qqwe=EkWog{z}|w$N@kr4gPP)pwNwu)G1SPE9gZ*E=cYp2Kx)NJhQE4d z3K!t->2B28^*g@rfKmV#CHX~$D$YUE8Bl2UTOGI#rlJZc<{0ihdDbJ@Ni95I+El_2 zo1dE=z&efB-ah|{a!t|v<`Pau!21AAsP+69bO6E-Y>75q%<_|M<*@nV8s_9H3zqhc zMvsnswl3fj`^`PuaVFJnp9#}+_;`j#oHvaz&w!M%O#Y|ol8z~=rK?G9iYd z9b*XjVgj*KH#Cel4`{>VqHT&{a$l^pJ{?ZJGI90PHU3i#g#;F3Xl#yO2 z4LKL*ve_5Zyx8Ue$rR@qm8A^ba2G_kM-Kmtjc1}`hBKD~jRqd6^tUU|8u5v`GOeLc zBK*Rp$}t>uk>UsEv$)30$Ie&n?~rRHVEF1|uD`}nKV<>{tg~?h+TtQb<0s=hVkI=S zJ`~11Ih>kg7C1&+y2b?b{5Pu5{92f@F10BSxCo)X;@eJe$LF4Rv+I(h@)ObW(?G=& zm}SDsI*)^zHu7s?7ZhEmtiP=ZPAP@lU zFW*t-Pq}*^Smh3x5zywKDs`2Ab7dyc+Wm$fe>8{jcYpvO@cXqE18VC^*ugQ_dL@)W z6q-VPWsdOA?g(}=8_JPk^k@nSwQ@ulWZI#ZnqGwmoH!4fFq0JLw3%3RAVrW0{EX-u z3w3Q2Ffw+{@=~h#K%2g zSvh}MJB>XCHfqoPgepRISOgrIC|nMu|D%=Wi%?VO>WlordwHg>Z`bP%E1q$cexC8$ z`sw>)lrVr$qx!OR%<iJljl@kydG~R?_0aMnPK;cf1yi=Zk^Ht} zK$$b*C9=A+7DYvjfE~9x`1L$Uh;B8TLy}V2P|wK}^gTKAxqD{kKgN>GV2#u4M2v}u z;#}*cYt?pizexfFG!zL0L;&`g0^(^V-+E4cLR+3pJOpzNXSydHrBjw(4Ks( z$$Y8QlueT4I~ncL7T?pzmFc*MlEg{dlNJG9pnDDOW&NVPw8fjG&=ka=I1wzkTE;!q z&qqwY3TEZ^lqTY%Kbr>Xw!*-FCZk{%E=9jD9~)7Ky#4+tkF~8c!EU0jYQ=WHd>S_TgT9pnRCa zYic=Yfg5sagS!|MYrKH)Yqr0FGYvGN&LMZK6*%mOab3{51t;HCl3&qzhlyTEe~hrv z7pUYw$?PSesGkje@Ms*f7-&rcc=A)doFtA^2?>DntTPef_v*ndWCpp8l$g4WA9@Ta zM|V)yz|i+lNr)OUAUJ607kqJE8NvcqZ|^a8vhpo#H6oTkup0rQGY{aC&5v=!XG@Gw zU1Ax|YNm^jd>c&!1j4_h!i-ZxrEh^GM6Du}!Jr{8adEACAYoKdtUYrWyuw%zgF9lQ zGLEWIGQ^OndsS*B1rgpZX*hr?MFWBNmy96T1q_4xyoe^Sys_8lp5rOyxfr6J?~?#j z5*B}?QO2fboqz$8k_U(?fvi|W@Ka=^V~~nTDLqiEwvq6XV^kye{11K>beVyZe`)c1 zqm>7J)Y5rD+K5&YfmW#;$uMx5r6|;i3?224RvTb|#<6LCIFIg%v4peBO*+gJ5(y}2 zDF=h~d!cw5qRBi4onyJ`;MDHerKQV*^y>GAs8GjQLyrK(hsFt}91X5U<4>_Qm(A6> zDIG(G6j4;U{6NeZr;%JWn4rG>6Vm)xJ5Pj&s&()U?0; zDk?dJ+gt;76ygyANnuzCT$`($p~xBWT3EyGtQ*k+#Yn5OTQT?_!T}J|cvD{=7vb|? z)4>W;;H>?L)`}chAo+Bna~DgPzkHxwA0a`jxCg5I`XKLyfNhET$?p)7pcGI3puM_;1AhV7!fz_#N}O2!rUe=+*_ciB&PQBb z_wt#M)_{|pa8Lm%5%Iu~PxU?C81WDQGrXkQeV2(C66hdqADl;4&LZ68BA1>mr_Few zZ+0N}=&9(G-4Mh(6b;wqy7MA*&+Iv^2xx-Hb#OHU>}_EVJ2!-vp^y?g>bjlJQu~Pn zQ4oM%f_^ai3nM6QM4}aW5CON6O4@C-(cMwyY#Bz#gPbA-*Z~m}sSPch{!@rLWtk&X zo5H>{L2FAi-3Vg$u!LXNPb&u6#&Wf^HEqr8ijdSF!Anat1NFlh#ilTyYFvb$GdFB) zf%>ctt;&l=rFVK+#>h1dc8AzWdNr)qh}O0*#G3Qh))G!O%whz8>X zRV&AY=DyThsl-vZksl>ghQ@+At#EJSWW-Vwk<*+YkX^U*L7cTaVun}0sgTo&bURX_ zP3d*W>ZZ*Mo=L^|HLI;y5B%#Z1=zl!zl73{SrD|9mB!gqC}4D0ZfoHgEdw-J$I1b0 z4f5UjEHXX4Y|L`NQOafbwH*{Eyrcmv2=+J`b%Il$2zs3NG*QfgGH86AD0$RMy4VL= zExYGN*m{3COsxF3KtG_Y(=vx$e3S=^Fubx`V?R3=@9!XrRb zs3iLm)Jl1ojyr2~V+Dberz@A$`iKA*y6Zm;mjh#h)!t(Qw7~GcS#H0Nt!C}u{vwBX zwjije>VqM`#q@EWkUYqonb2g)u%)^b`jGs&+@H6|8#^J-*nxk<)X&}Kvm>A@vOy3O zHGEo3hYERP(;CAVE_s7XyL{$xLeCoLpJye<9&SL;Okx<&i_VXOskC=z-a zaHc&jneAop$MJ2%@F=YBQ zD1HJ0dHAc3+79hKd+M8^AK2EekGPT(BK=)eJ2y4FX9pZLZsf5s!3}(YJMF#S`0Jgi z-o@7CM@-^p7lNK-|F;V+y4^Vdl25yyxKbeo4b0$){(N$WC($-e^2)MG=bw2uCXO~x zXrbBmY6=BJEWsUZ`KFec{@%`R#Ib6cT3Fma6s%wDYfVVmLuwOsLgi>^pQlXSU$K3l?J2i%15>|NcCm&VCRWLfJj7 zO{~hSg#lK9%t0s_6^pkSDXgoGf`vZN7vX$5LFL1&x;N4Ya)#`E|-a&UF;90 zh`J3QxRSdbycm7fN_|V%)`EBdxtKuWj{?Q01f|8lZ2WOn0+JXM%-*HHZSB6Y$?}}t z14pS#YK!)H$$W}YJWce7;3;-HEYK2lllDq?4ZnhE51x_Qr+oj&Ntfh6y z;2&Y08k>p&B~5Q6yTSVhC%S;gTy`5QCc-&;LC0GR4}$&J+uEJ|X9CnL`^_0r_97hm zVR!Q7<;7pv^AH6rbe^Kh50bZtBybbdcvO_CVUwHJG4KVW^sjWMiYu$-E^AF;6t z@N=!>_HG0IRu8O+!W8N?(MpN<=n!ACj3v(-1WzCJknv%%wQrmV5Q)mlfNKG~)~ zw1LsJEfIKEw!R6Lfn#Bq9zXaY8V0HRbetjRH=_W}4t;N7UbEH9d65En`OPP)$jj-7 zQy0zA(K{-x6Ac(7;6-=4y@Bl>YrE@z660)R=_Y_eB)gO zeR$xrR+sDPt5H_nB9X@$I*2;0kqAa+b!n_yVYdMiX|RXIgFMIT7Ao@)2QOihRY!Nu zi(>$1YrC(ACr7iT65(kMMj2dDSu#J++h4l}dP$?35ceNF1FOQ+B5KZn(F--7#U+H&sBlTNv(Ygfpkg0ACR^2?mKPkY zjYWvVHk|qsE3WS@3E+6Ip#@D>@sxZnCNrC#)GP@17#%h;4RDTXS+nwR1Qs~V>v;gN zrctia$%y7dS|VPEUe?_6B>vq_)&&H6EA2f4>$`)ut?wU;6%;SW3c=ulBgInL0?&)d zgs;-gq!n??Rw3W%o0v6X%YMugU_t5h_`DEJ=n~AK2e+4gEm(Ig{F4l6=iz34k#1n} z2n?b)BQxy)mZE{{bhI=RLliXU4`9G)kbK0Nq;$t)lxiIamTM}Ohg8&TWF3}WhokUg z2Yg6ZMdr7SkXJNsT0h8US2UHU1E5!iB2|65)tsP|mQhw(?hHD^{FX(!G_((-| zm@JqHQ)UTdQ?av8S`c#>R0U(*J9!YQ^-dc9$db!Vr2aV2f8VmlLOR+tRNIglgN_g@6_~^KGyMep`SS*>?&DMYR7-Ov#Rgzjq2AzBY{%p>s#9br(ovJ6j zqTXSH^UTyr9onj%Dd%l<^~N~uz%&!`m22Yi0K`Nrc4`T|a3?0`-WCaC(@Px8;UsRy z27p@~E^bDcqhC#%TL5&7jFN3;2XI5j+h1>Vwcf=af0v*@T<6+RD600wOql}@qBCVy zlX{dFhFjRy#%EreVwB>#y9n-OxMzfdQGaY>JxL(tnt9tZBV}MSu!Hd~Kfz!2w_ld| zclAv5O`!@>Z)>oWn08$z9uKA6`};1=+a+VxT-CY zHOP`#QIx+A+x?zT&}&4{e+efKhi#VePia?L7LCvA%$8a!(kj>YfXIdN15-$ea(c>g z3-iya-v63V_S`+ZDOzLr;(er%9b|(Ox2LdFR%hoNa7S z^U>fv*Nt7SU;r%e$A&~fyX4-h7sbQ02$M$+GIj#jMVD2&C;dqsYMV;$kjsRf@*l{h zol?c9fj}!?HC;48iYdp#OWLRo!E?Gc2N({8gBmXUZf~dT4nMeIU)^>xd$Q!~%-IKy zA5NrQg7{5ywKUS)=%lm*#MVqtD^qN5e5$YoFYKeiehp}OvTOCsxbRZzP3q;{oErg* z$TPK6Wyue=mB&_kA|7Bs+iyVy;1|DSV=}?S(P$THPHLaL2k&VUgonZ1w@*Q%`#nZV zShZw~Ab&Ir^GgaWpRbmaS)m0Bnhu)LPrc1(V7hIBrU+$l4Mr2-Hh4sGuQf*SlSMBD zZBaN;y8ynaCwNI5vp0Ds;Y5vF9AY3sZUqs2t6;sVYdTLbPfvBuP^&` z^9R!D&kUOCeO!t5Y{siHDyDxkXI1X*8f-*vHaw3BMG8DtV;`(p3k8l1WOnnvdc}*P zT>~eO`7JnGW_*XiQ*B$A>xTAC1T0n)R35IsoYd5QOm; z0s#@;f}PY_sT~(=(&vG{J_8p0r~9z20&d|k6T79eRFvs91}gpQ1mRaNV5LTnk5h8y znE>1V?x>|e21B^atvVrGlk?nX z%$B+hpLo#35mC|*wmj2VfTQ$m@e4I&*yv<_k_wvS`+DvjZMlxRG zllPu8Bv8h|bv&=6nlY8_F8JnMVbOG7)1s}GgREbKMTLPm`b^v}2yr9bkf)tFvV8*F z*}Ls`^LuO8-+PC@yHC}8Rfz?|Du>kRK=_jKv^`W6n27B_C()E`E)h6GL)G+@>jABO z!pqikq6Y19Y&CROotgv{nNr<}gHuir0ZyY!jZ$#c8`vCF{NrR4PPX9a=O@}%rYeW5 z6Cob*dHaw;p+y-=DwA!lv$FfrU<)u0nzY@@pw01NUAOwo0G%>Q_?sfJ^Lh@p%9JO2 zY8QdUr=Zq8?^Y|Ix9TBdgi99%e89Ufrm`jvm>XP;iITihyz(II?Fpk@)l*L@uPsrC z*dqsD>!@70)32Q|;R=O|c1^Q?_et-EXj;E=eML=f1~|_&EBKBne&{7gH2_P%U9m%^ zrY#kE(&9X6L zGe6r1*P@&XTXHmUjhcDWC|L19#4ee?ub$(+_ucWP#a1^FqzjP04Q!CZQ*e%+4Vy~c z+c32{w^$LEsU;b->E$FR4*-N6Fyltd(B5ys&W$;+=n5hByE>#r?xAid>!rDUu9UhK zJzr7f1qjEA#7P^>98=mJBDANM3r68M&vxp=q-}yb4HY)ZZ28Wv6r~oAQ&L-|3Eb6X z)+x#^uG8t3WQ9=5dyGh`3zqKi@wCqZtDk&K#> zlj<3^@TjID&(xWc%#1S*oxIPp0<=tuVHl$Je?%Fk_sT(PBa#@}bj{4cTp8pjP?2_{-( zTw^4+WD{ayFRj(0L3u@Y0-NHK24rxSoZZ`u-#>(!>4g)h@IaU-1=187mIB1W3nk#2 zC)3`rIG905K; zqO)#3&)mxo;}$nkFEI~9=gkcP-YbQl5W2}X^v5rrBp+j*OFYl6*}qya6ChQNyOKHN zuin55T`6w?ivWylj^+Z<8CY<9Rx)wX|M^3%&*IQR%~Z;~m3&k$pgU^$1) z@x`dDWGGj&;iJP*s$ip~NdXq1PL%q{O!_Zd zI|c~VOdyx&(3tfx^ef^k4efOiF;Rd8JBJqJ1R~^)DgXzTSOHeH<+cXky{(I+H%445 zJeXNYyIgY+OPcWwn1YL8K+7h>y!j_CJq|ns8CXI7)Y&7 zNOu!{0AR4%Vu4z(xCde>} zJfpBZ#hqrHoUR^7X8m`*k}qIv+v+Wt%a4uI5^zJ2nW6$@W(n~?Iziq3jB;$&S|V?T zHLhJUmmi;bDkXISoMc-ux?p|Ci3w$Ec=LElFK_{5hFI7VP?afEaZwG&H$fAil#ort z&`k;?;=)Hznwfc8#Cl+THxc2URQeW z2XGnt3mFHE>D4oYs*yojVXYRI8(I}*Zi3tIy!v^h*W<|yXIm1uDn$yfcGj0*Y91%h zLjXc4jS7J;gx@H>(^!M>)V_L!p1?pyL}sHVe$Gh>vZ>9sFbYx5{3B3qVlWr2cRLufk(?{2H*ef}(!`e54KWITG3A z+=g(E_j^Pwv7WwuQ-wY?EfnBNPcpz6IX=oLPNX*!R{4&u-&&28)nsS(g1SkcFNL3N zn(2pf5C^Vwp%U2J^Sj!Ky};%2*9nap)qx?M0!7Pxdxk$_(<%J%E*A z`FsPn-NdUkpsfwbMh4sGiAO+tV648VN5-olLEwcA>j&hKC+zEMO)urG*G=*nXi*Q6 z2n!s?YGUF_o&bxZ&8Qe)_5y*cIQcEM;1vSVc5jBHjc3+p%CvYtd5$1)*w|fm^=2ps zMw7VF#K4eE1y?P90loArakV322KcpA2_2UFDJqWksc{tAKB!SWIMF{?w|=LU9rIPp zL=e0uv$YbO6=60^Rzo-~aWUY0bX%s&D+wb$$EqfqL9uoo%(bt-^+T0Pp2wget!(Xa z1s8^)nQR)*Qh>d*%#Tm!_EZSeQZU@-W}s^kU$$r6$?El#YC5s5WAggS2VfssR0$Ke zKUz_*x{NKIC?U5EqXM81ax_$g(|cWM3XV!9c;cRe`&nxqVQLyL$KcwTzZU zUHsbT_9Tm4XEYKPRh+8IcHl zC`ee9G?Puu(G%+c`aOCvdTui-*R8CPtxaHRf`gK4mVHc!qnt z=TANY{dXY?v6aI;Xc!H`2xR%|%ht7LP^0UOt+O|TKu`43$T`vADWIpYW~E;d^hZvC zX$CIboa`JTOW(x?Jy2CjPqALlpFMIGU9WU^)dR?eC*7i#scea!g$<*?hp^vO!mWe$ zKAUXhP!!I>z4Bt`c`7uD8-hl2#H*$*!IfTkSwOgg=8@~r2Xw2NVtd0XU3STI3H)mY zB1WHWr0{ANsMdmP9pGU*Z;xIDh2l=yuVvig*@<*H~^w9<~=d~>$sF4?* zgwFGe0LTp~mQ`S}I<87NLRWu62_vUE*bR+9SuQ;Oz9!E2>;nvKa>*s!jVLpHzp*3l($wk7Z4Rvqz`PLpi1eMj?4wj zO%wJ$d(%R8s8_%&t=U;(!|Q!LNkcq?s7I-96IAk-Lm-$E_>`z9AiOd#km~-OpWeBY z2N={LsW2QgqX!(WEmxiqPt=oLm&_XJbRovXB%1wL4W1pU-6kO@!x9NQ9k*SdR$1m4 zDTP)j2DYG$3-BGDO|ii-)(k<^B4%vNkVYLx_%ZeCxLwF1B3+=yM{!x`TNLShu1X?C z)*w72N>CMqI-Lo!eIc5u;9~lXvJEqT^*d~x1B;s-|7xLMz0QrCeO^;$e&J6}{b&oh zFW(m5rjO4fX6vl{($GtYWdvB=EO}kxO9iX_o*jHHQ(P(Tn^1LHwJ_z4P zLC0e69i_#1N8uKoTgcx01+?)6@p<+c;Jq#u@~$G&=N63RPwI}|m%GCc=+*nbU!fu2?jgUH|#<&dPgGS%9 zA4M@$4-jViasy;V7-4DE+ku$w{88pXQ`5;|kidvx<33nRM3}uZSgWSUsd1Dl|Bzg0 zv)|WL&*9~j7E(6ZPgW;ZMwPnrm0c=IbmK_kq9?{n2KU%<6#>yV@Z*rx+!(w&pPb}6l++V zUU7=?N{formJWr17>xI^{+~6&2zT*ZyYkP&!&9&Y5+?2ZvNt*ijtKC7r6O$N>l_+J zf?kA0Ww(URUu9+N!> zIe?n43VOgfKWM_pjDyx*t5GTpyrmL(spEBcFncfY2Y;8i2Fi(soX!yquNJTGf@cZC zL3=+)b#-WuzdAfy$k6V5W*cQg_M0^W?3}$C>c-xvaj(6pHI!TPHtDK}0*ZrcFLh%5 zgp;vwDQBs*#+a=vb{o^8{aI(A!rcL{BH*NzV1Y)?_8}&glo!ekeao?J?2Nye%0;Qf z*MedG8q^>0fq==b4%LjKEbmf9f#8;A5?Ur3<7apOke2wttoZV(n{y=}Fq@Y5w zlA6!DL|z3)w|WE@J5~dgryu{jjS{gFRb#E4YcHdE3Y9vbYgua8_D9l#kJd9~9w6uD z3DZ{LxoTx7gGML3c<$UI*`wI0r?@CyPO2_`p22uv(Ue59VTk%s(iW4o{mVqib#%Fo zhdXp{M+eEC7K{TU09O_Qu0X2mba~pNHe+Q<@~j{o-6zqs*)`vXH3vcy zFwfe*2e{4Jyl<8A;bK;`tnKO41Xx;cO|j)OdVlY!Nc@}yd;1!`dXc%-fpzrghjDfp zZJzU^p@gCz&e-dy7WIWVCKXU`l}(*q#>vmPv!pHkGKrR^_#2WixiPWss@&rebT*ag z1rAzwJ-W0FWpL{u0rh4T)q|E?KzLlSFXw#&8YSu0n+Q*56JT-)!HS_ z2=pz7NFMzjKvGudCRxZki-$1vKSTbK&%JfrmN7%{(Ntj4R}R?KSgG(eWvyOW#(IfD zHu4$v^y6H*Ak8ar`ytRd`kS$381Ilgvn7I;w4jCpSPE|7+1ZT~Hd|l*ozp9Js$H^7 z;zV&;{BnrP;hWWVv{KjM2RPK<`k;uwEk#{6C_HhO8GYr@n)Z~^!mHM>s_8F{B=LHG zI>Yh2*f3z9sPgaT`93&wthYGJd0rV`L}lQo9z8-{y=R5B#|Ma-Jbe=**?fe*ipM!9 zP?VSFvtb?~gAvF{z5UjJidCTKwm|i*jP%V^r^D->$8F>{*_OH30LT;SIN}}-kKM6m z^X68|19D_oQ@o2f+QqInHXNB?o_BuU3@%^4us7PIiyqm#P>-h`)9d?86FVl&bx_*V z(!1FXPg%#(pIvj|p9Uz+AADzI3AAf<^d9OQW^S@Ma4up@Zu?pHSTTKz8dU3nKgsT# z-u-#q#YT@64Owr_0Dfl2c7UI$`%%5R9|r#^37Q{3OE$3iIUZ%Nh2sKlcw-%R&dlu* z*ei%#VcJ2xiDnw9NsGEpb^p8zMOU)t;WreqoS~q+A_(;ktgl;K7J1WHb{ z#Y;A{1y8m&Mbwt+0y8LZ{Y6gJ44Y43SVA-@V!!j!hF{S%v|*IxB@4<|c#CqJiCdI! zq>j6DObu_&{y1C(4~MhB2euHwdm*!_B=n}amf-vl2c3MvXHu&rPW_kyDNe!tLrw3E-R zt5c=vrgYe5Ac`zwtlPU`451S>dYxxjRSke2{uXg*a=w=Fr{n@c)a$)-GVhl=ak18b zcj0~X5tyqO%3OjK{{+cLk;GXIb6R07kSj~|Fp=YHql=QERRb7;qw(8vMZwthEsXre z17GVHiHV*_nPp0%jBMp9z7}YzS4pXp#FPu%7B}9Rp5z2MHY4rRBL0@Jm@mzrKN8u0^!YhObG?cNBG% z;i7kEZyoOV0SbV0xonM?C^yBR&+-*`^`I{q*SZ&9oZNq1gi9zt)YsKq>4GX|JG`(d z?I+M~vw%_Cav9`fmWxZral+>olxH+#vIrZy{u-3a*ZUjlae|49ebh2gj}0rHTJX%n zWZcQIOF06|azb?+(@G(Fa$L0Tg-8L^&C5QSzrekjCkMb}Pg=w6Yk`~IaAO$V7tDs@ zK?a-Ov9|L(`(UHh^L)6@|KsXOLIve8uU96TXQ+zx$97e%*o1rPti`|cf)!aunV&;K z-al`Zf-txIwSi%nuY?j*kS!UgR;YQ8DQ&lc0XFb+!!@Xn>E8v>e4mjQuVx$1dd@hd z-U`P$9U7p`TH<61k4|dT(z&?`1EI> zWf6yhNt`+6Rv;vq@TT=mayP_r)qLwFct5J?G%Ejb4So;kB@o2b*jMcXezzTSR#Tpt zP&fHVQ9s9IpSy-y4r>xsVC-97X-Wa3gagVYs0QGW^_k=xzQgxbovPA2nv?}3W0U36 zgTn1x)v)xBvDF|nd>2%B^b#WXh{~Tw@FzDHf+@ArhvSLrFiV@=oPtEOpCF&?7?`)m zn*MYIK7VhJzp?6Fj*mQJ)!OoWhwuE)wCy5S!sgwp(b-<;3nr<(SS^1B#&DW6aBx0?Z0jOzoI124(A_l zD+O{%knBK=nQUuK1A;-GoJonF9AyJX^#4M1|NlfFpprmL`hQ5BEC`cQGJ}l(h@nQZ zqm3wtzFu;h4FS=AHY_->u8bov5KsjO5YRsg?|-5s5Z3U&CW2&(_Fv)u=`a7I`?o~5 z(f@KAX62}zDCCKq;9p7)iZhVjcMM>7IbCtS_A1sjox*Oe% z?na}baGfSuPS~o*!>ARCCqD}PJN1xJ_3a}|V)Z?Y|51b)&D3+k)Hhbl(=72RW35G& ztce%QnSToqos9mYpbUnJeplkL*2zzxHKuXdZKPh*I(kK(xY#?QIaQrc;N?iZs{@Wg z=pHY^Ws!M#n8c)-tl7{dCuzw4jpHCq!Z>GLa&~d~)6~7Z8oxXH&pPCcdO1Z})?OSi z1$Ul#vA=4y-f(U@%Pc8Udld!&jfc~$pq*Ag7k>a{9maNN&?4|>Sr&gLGm^yf#LI$S zM$?4+N{Tc99JQx_rctt4BeQ-b0mVs+9=8C9157=T0>_hj8KZ8P_--|d*)Z=MzDV>h z$XOibp%;b!q~w#Ah2A`(j5jSjKa8M_GBP9&kNllqWEl*0W!nZ?E`m{# zZf<(+?XNep*~{Mdw_nXjuMhv<^#1#{)9$n+nk(uBBwtaofZ<|BNk*bD2Gxm)WP`&} zn1|iIiQAGRV(@jIg{hzvNn`*dV|f?h#ed{}73P$so=?jW9PCi1-hoA7x7%Ib)NvRB zv^(Vh9oHS8qU#jciG5kw6fQ`dKF{~0J>*?&OJN9Wh&0QDLKoBJyv6#f-NvKPz^`^vt#|GJ}ipwG($TASUrl7E@q z<-&T^af&phnZ{L9Z)bH#x2VZRXTAhgvo+Yl-QDh;drRnuO5M;1D~*Cdn8eU!c5Adh zet`(ZS|VyK?Ga?H=kTv2di^0~=NG-J?|R?%{#*`|%X5z~O;8}k;a^ddvzz;y-i>qH zEKmb1*u*VPHp_U+Sm zTgOZByWOw=kv>>3iqxHpPEu$ttB&qluIM`XM5Q&=JQxTvUnQVn_aS^1Ie*HJ$uZ;4 zDX@_S%8HR>!TkoT@E)>06V4-yK#^$RHu*)}+=?kwkKngG^f=Wx2i(V+*_y-AEh6?e z7&qW|5v6dO8O@6hZ?6e{1_4g<5DTr&J|I^`93zyr zMA&v5$C3e5o^AAi2)c64$dFeU9xnxLp_0vIX9VU-)(^G4fs+-nZD{F?BL)lC2Hdyi zvX{UmARa!O9di1)>3_A4mYcsXUpGcwmlz$3DOIYXwND|IXP{{7QU&>(87w~(ZKH-@ z1FR6YFTQzeQap{b43>k(h!!Mj@?Piy z7kx7+b}97%d7y}yX4#|F(a1(qpp^A8gG~{k9{8LxE(4q%Fn&XR4<{zn_ zKiMV<)@<9u6tMy6@5+$$!2qSxDf;3@)d`Aq%4`Em7tp}=D<8h@)Q4C%u|>WnR?qtC zyO;RoMlBau-nL*NUrgEBwoVhU_oxZp934!3*+xln2Z{jx&(E!nHWR+#MO!u`v&!7d zowRcf*2-KGR(}O~x=E>JD)$=X?Jeoh`eo(iB!>>@tTbZo!zdE=2D~jP82#R=FOMVy ztr^ZN&_k|4R;RHY*H&5LA44Mzd`+MU2(toG9GCV0??2J!LAKr$Sb*siZ zgIF?zSISz@Qy5y~@}7MLs`8dhhNKPBZ`U}t#XYVgE(RLbR=B{0 zCqj|7sTL~dGgRpwyUgcQaYBbDTb$GJ<@x0AAI2BcP7@4=(cGmnBV+5?8EvF{c5ya6 zJ2`KLfPVo?5c)YzD)lx|;sv%b$>w2Tj9vNNhA?3$1DY;bv*nP-FAbg-wN^`J={ssP zH0r5Sg;JQhv5jD9*c2*hP`U4gH6G@y3U)-^2@O=DoV4t&LMN3S+9#Y&nK~JQhMZHt zu!hJA98V@3rASnPZGr!uaI_HTU^ML~=|+XkIDaPW;Bny|hm?Y=NO z&c<6uZF3kmu}$bi@S^(JTX;(4`3B~bq(vkmU*rd0b-McTRjDmVu>tIwRLm?S*ShWO z9T`yOXJN`?-7Nrm;{iCRV6c=%XcDr}+kb{t?{EMfxZf=KYh2)$MM;a#YWu3ZDJ3~v}KsGDaVtlw-K6>px3)&r=Fu3Zyw6-t@-{si9VW0-ku zzWle_gbxJgM4DEj9?kNxM2%e+U=HS#AZ*<43pmbpMB7Z(P?4osfL+tZeh__QsDJw- z-E51u)_yD3#=Holz)g7Gz~T=R2F~0V?7)(?EgF9cvn1vl1grD7C4;(0Q;_%TWRXQc z>%v;)dCCU;zT^-R)*sKcMfp7UIraH885Pwol8~4X- zW5FZA05eppSdDTK5eftmBC1jv7Wxo&ZI0ty8JF$z->Q>cslJ8yEmG0|Aw;Fh*d_-7 zT+vnJ2_iWbGu}@g%{w10=eJiU7o#8c$mvOPKH!r1{+C#S+5@IXbh=P+L^;W0R0O3j zS+jFVzTrWzBhz3YGkMmF$A7LaKUDmjt9J>HJZ!7?38&HPNo?Fvx{JtLiu4ty4x+_C z#Qt5fqER}uJ|r3D8DQ%ji6|S0x5NpuJSi622S5K@OSsne5F?qhgGtGe5XACW5Z5keirW(mXB|FD*c?W*K(UMVmYHTtaYnWsOz7I6q2;axPgWoh0)JMC*hKA7YDRw? z^9=~ku7*f?`wsE6!PhU4Me-O2AUaz%Q*4IHDd5KD_&=4drD}^2t4yKCqi;NIGD$v> z^kR+%D40$zNd$%`!Yu;4&p7kH*Lcx;DNf-tN{(WHUp-h^nV;yM60Ng=A z;48Zv+>v$x6{8U}pMQ#NU8mF!7aLOU8RR~)nQ++68mCbTKNl?1u$$?Hy(Fs_-kjm5 z2Bbp8=V2zZ^fV{WZ4P*1pYi#Gux$8j+7BhT$2JKtlgCd@kX}7L6jWAOPY7GeqchGZ zy&?n?hKg^z6R_xgnEz1BjflHsmbMo;2#>E#Z9oY`#Ca+Qe}4$fD!E5VionR`XBK?5 zfgkMhEjdKX9wRKo>KXjj#{E7<-V)tb@^VMwvbGPXoQ;vL)WUUK{%ixTXD!6BD`Qz@ zD@8bob`*naEfXoTkhhIHn?1Qlon)E8Ldb3^;&%6rV&OqM?tAScb_@+5_REOxR^$Kz z1D?Qpel|T%K7VWcSDT4ltoLLFCxH;r%Pa0{oX-kgzR}G6tI6oczyAkv|LTYF`CrtR zKdUd_Sz59ZJd{^N`EaJaGo++;D?GKhUrKUfQb14E$DK*^e=ULjOv!VD8UI?sywTlZ zVUzHr;ydPU!MVO5vnv^C+_qkjw;l_9BVUQ9UEFB3gnyZTC{6Zb%d}|^$}~Q9N(S5jf(GJt;7*$mvpq5G_4*GQd=5tCpD&FZJaOh>Vr{*fKZh z&|Y7++tf_AbVa^o12O}3fUqs{x`e9&Mxdw&U4m-RC8ZMFwoD0f78vpuh$oySUUW-P zP~3j6X@9;-03 zZvH7xG|MqWAEQT;O)xd~!fWPouT&zEmIh*Nto$-)vAFXv93 z8Yv7FVp{=)vG?r`hKP%5_6vs}pp_NHEp7KEWAb+}9>Q-02BPm3z?f4Slck(WKv>~p z9Rp5j^QXowoNz0|;{`O#aMww8w}>FlEq{sMao{N&a)XiKHU@puKxK2tX$8MWE;pwi zK$4)m-lo+8uLTekRyPQ7yP^tMxtcSDLJ)yTihzF7SD)qp+o$87+eVTS-3=ZjM_RFB z&OHV0?5P*m!z{CNg*5UbwhJrP_x?s`7oJb^U3lM}jKG*mI=zpIT zdG0NDqVtwjl~5DXTrW@(IMH^-RdHiWOXngQt!8LI_{wXQS`2Sswcr_>TqEUk>tiz4 zh6{Qjtc4z4(BodIhpg+1uVP!!LuCgR+_AnR)?Qz!JnPH+nRXSy*{q{Cm~$(wNAnsW z|Mu`87l~uEkjKYn{cRqBO-)0D?te9p;cZQWl-@KCldaW2l)2s&3ubFjOS=PlfL5pd zj23)b90DhbpxtCT)iLyj*A3@WIa3}!eYJ5IExgNXMXVY<)d+AJ+5Ia~MXS~t7ihnvylt#FW zlWec+QMESZ+%+xGVQN-_7puE07=l$_LeZ0lj-@%TUQO(*S9Y=$gRuk%OBsnSCh$fch~f8>8_VqYkxYKobO{4-+H%B z&QGpBxTDF%yR-M#dph<{A}?Eyctp%_p3kjHYRhoY?myM`>+4k6`dwD|2urM6<3`J) zp?W6!EU3QH3~jaMtDq>W-DD9LR-J5}XO!9&A6LuX8}waksHF`L>e#gLvdkK1b&=%n zk|GYok%EB%&-wUCaessX)~4o9w`X_IX{g?wsO#Ih0a!a-X;;JR^_!Kv^-du3Ov)T) zwq5bb5u$T}RtM+AU)Y+YjQPlmG2+6b%xm#01cr8+%B3!oC{!~(Sig-aT41&&7=BD6 zn^kJzwoaH(eynwP8aM9uaf5S#uLZ#dllB@@4r|*!>8r(1uYUurRsTP+fVZJ!{Y>Sq z;+C9TS%UW=2>T`_kbf_2gpwOPy}3WALbq zcb$!ul0_?-7Hp-i?Z9(A^3+SrI9z^SvIFvNuRdsx zRFxy}_e~M;SAXzFE)$lM>zt;H;PXvPZd$J#aw%?5Voj7f+E;0lG{r?!CFC7G=Cwn9 z68DpomR?L?m+Y)XqDm~FnBL=-M+D872@LaciWvXloH?{_93=xBlA@DSWir@rO|vCc zBlp!&lrVeE z&T|I|xgbHFZ1nu9Dz%x6spv?w^3?-WNYJDNy-kECh)@SEy-bv{HdAmSdl6aidH}rw zN;uGM+=0N2NtK-_PmR*wCre!~3f@K>3dH=psF#ff`2w_?#Z*N-W{($Z6@z;wX@|0kk4J2ByK#)!lc@zQ1b|pzmi($`sLXjf338` z&G;c7e}`g|UyZ{&`L2F|*K`rJUKb_JpJyC`9=Je(6?;`}+tcp4basyv*AR?aIa%dX zy$rF^qj|LX76S}7nA=$05Xd8QamaK8na5NCo`0S0sQ?Uvp+1NG<$Ll1z?YN>nl}LO z>DWsDx)vT)*>C9T{*gx)<{QsWl-!p;cJcqTARl{em)MA(n5hM_&sT}FkKbE20qSV~ zDCSYsD_eTI>k@-FBHyd#f81pFlA8?1jP+7zvkY3gMZ+l`R}B4IhZow$bgzRifB1pC zlYhS$F{qsk;N`_+0ShSh!BqKP!Q}4&++$&6j{8#2_d~ovj^+QP$nlr50td@XW3k>; z`3&DLiA#?1V!cR_x5{6EFs_XUa{?dP#`)uF=I`%n=Kr-@nR@MY<0VTu>u);z3XG%WHycANX$w2Y{XvWocZ%^N^{qJnQ zN`>9YzeaX6M**$>0kggnxdsh7u~A%YI7^yK1ONa)lY|;Uf4f^0g+NP`O@t-|l5%Po z`S%@Cz9?3TZWq{x^@A?-%$b?PnIm37Uy7WqN<|El0&=OqtSO|NdAX7sprYIW+Z0k6 zi167vJnNl4K1%I*DJNP(uV8I$)U~th+p$ zp^QmmrG(B+qKV0$~ZH-<|f5sMCgqye*_cEFv1%wx=TiLJ1ZMv+M4qG8s5Hr zd?IS44+Cs}zV8p6iIX{c7iEk6x&MIfaXk~YDkQd)&*C4C}2sog!SzmuCJ-WElyCp{9Eu(x|bcq zfAfc$7p6-cZr_Lgb%pb)mi`Oa+AbfVol8;)V3IRV3u4w5Hq==ju9PebL=Gv}LocsMs?Rnzr9Vf5CRL{V<&j{A=)Y!Zr0f0hdoywL8EBw0)yW zYX5w1FFUH;&F^?DhqjOg4)}*5#*eu`=x!H!gF95aF8oQ9U}AL({ZR~VoH1D=Q4Y3v zjwz8Mg=l!9NnTdfg?h(ev|}L@lZ5kJRUb-JD3?F9Ix&b}sDsCmmb&LZhoI5(uQ$CG2HGP1(9iZ zsvrX7uu0-qzgDIH4J)X(uovUR~*@ZerKlruJbpu>>f1_4mz<>Tv)2kuInNI0F;Z9FD@v5{de2O zk-zJ&*n^x0&?YH6ZhDOxHYZbbqN^SSumC7oQPscwW@bOIi!V~P zlV1A{@7W@N-PzgM+4YJUsq9~en!dP zR#COr5K!K0X;Wa(9gP1_YS{E!LfU;1os8PR`}BwVIZQsjNMNUa;btvqg|ZbEKC5 z%vg|w^kTNk3+U7`4(_LaX?nxFXwLE_pGEVChdo*RJAm^3^pL6152iuR<-759kX%9c z6KHK7#T+?>rLx;0VL~MVu7{nFG$;^$M2ve-Ggxa8ITgJm9s3pjdtrA}f9^i-|_ECx;;edTZ zO^x?Jfl@*ZPtqk%aO9yAcR?1ibX5SeNFv4evK9%*A)j5R8X&!qV1Rg4n4ZZGSfQ^U zz!4c552{*O*oQaJ9keut;cBtW zJ%dI@GqoBnbBBKg&FszHhnvUI!|kI>%mp;R6>3mb7y_RyaWTuJgZj*Wc|{uw)PWGbeCh$hBS~pdv&imCo>pLn zSpfa?fo1?AC|0?l#qrWNrcBe7QMmc|H1}rLtK`PdqhI*w53j!d(hzHMW?`}2T1PFU z%nOUlS%5!>AxFvNxvOG6_=DSPtOKnm-fE?&#Y+1GG!(e82i4}I(+uAth=pu=1!D|< zeNnSKPJ=M_6g{ej9+b6QV?1f^gwNE|R%ykhn6IebG)na=}`SgBf>wP3_74Pv{T2G@r54 zf{IeMp)`@$>W*)1fI$PqtU*52z*_ZxeohSW_D0Jz2`Gq}awjcp4|mtGQm)X z>0N>hPtMeB#P3MFibf632_GT~Orjw8LKGG9M4RWLaM=S1OjM^**Xe?+b7B8~!?Xh< z1Fh;I|F8r!5Kqtfhod~VF-S)c;z1o|UV0JOF);eVl;??C2p?0*Tq-G@3)K=SW*d(_ zbMkavfcf1(|JfMR3CbNbVUe^#uZcdP5en!7y<;L*@Gm;G#kf!z8`)dcz=B zkq5XbenC|(L_a(Q@xEAAt0+)^J+K_JIq7rfi=PHxECyeM=U;q3_~PB*i!(_@Vjt;; zS~Rebo;zj72jb1(!S43s-~m_+|5s=|g222o=fquv-ZMHMx>caP=2ebuZa?d2AKbu2K%97CqM}TFuSfHL)hG3dkpl0l z-eqCt!j!Jce9a;Rcg_vwm(eZo>C{VfB$z*aVYxJnF5sfxGRi3}+tQSv)~ z9uOghNbxediFc&(s@8$k6Eu))2&HR&%5!P>RT~i`4`NiN_o6$wB3^}V8V!SFPy|B~ zx7>Iu8odHFznc0hv`TbzeeOJ%0rp1~UH>jBzF$p=i-fUUqCS=uEf9%p4`D;#FPKla z0C^4^wk_>{`LlZvBMUY@JYZvUS>@*hScTS3_I(i=`0jiE{n_Mn^kCxo_;a#VEqFFQ z-8&zDKXP{RaK3YurK{ym5bkgu!k+>82s`-6lW<-IoPx74qH(K8QeF+P5G;{SMjx_>ruo;{Rz z7tb#r9r1RI4@S?*-^_n==Hu<*aq6@>Za0`t1;^74-qDblQkNP$2+{AuJ_ zk+)@k3M3n(C^m4+1h?|I3KUuKW1#YRu!@ToprDAOqzmeck@t-HuI&1)kd_{#Kz_OP zxK$ZwA73v3&w|2`B)8sv`buj42={;Eg8hk3-~ zFz<}+Zd>tPV=a`bdS<*?RwTay7mjpctA!5Z3n%XJ5!hax5#YwSuUb%%*u@boh1?VW z)x0V&fW<5KQlbC4$Hv!ub|a7n?*}x02wDzh`T~l#z6hURiRE!+dX|f|H~e0k9XYMN z;y3_E;h)hH9}9u>LU^uf{&%&&lhJUBX&tvb=`*w&P=Y7{Vi{Jt26zq<>_I^xG6p6= zCYAz#F6c4nMV*KX7e?j{fI(M^ahs(0oal<4|D_c!$0ZrmMa}fD1;`CLh;_q%MLl}i z(C!c<2k?!D6)s8`W(e6##vnek#VzQ9+;cT(w;HCRW*V{rw8f+o5Xg>7%~A4-U^-AO z^>q4y9wB3NuEy0OFph@^eJImdKwx+lo%)&xeI0)o*-2JN1fdOoM&gf+j*R?c zOW*~Jg+}gLdTAp@xjrKDa}4#?yvibp&>AtY3>2AbR8Ad-y|7uPY=Fn8F}Hyso7l`m z{|7RY-7<*#=#ucA6PLnN2$FjhLNzDb(CE(RG-gO2S*ieYFqT0^B3#AanY0yu14{)3 zK+RC;G)fMYz!G)lx29p&sZAlQmC9_=OSR|2 zIK9I-6SjAO)%63!gcPBrC3M4=z1H}jB`S>hh78`s8I{@mF<_65&pSZdU|T{@;|d>> zaBl)?B_G;(XmxAjU(NlA1q@ur+DxFx+!c{o0)i`GB5y{l6hjMt+pN~cOf@nK;tiWQ zq;O0-%uIk3ZEuYF8boJ_8k+|JCR^2MOg|DtXx_&`-Pu} zUWI;f1Dz4;d`coD^C(+*&VEW>CB7Fq!4zIS*#FkCENofd7LO`#qBZKvlusj|V)9z2 zycOu90xeOALNH8jf$M^4teoWhT4GzIOI%Y-bIe4*Whcyk8qQe-C=RjCZpR=Pk2yFb zch?a);@r-}z~l=Hz@|xPZ%+4)#@}zSsAJ3OQ9aR{;sNX72$pICV!Z8D`m?cdQC+Rn zqn;anCI%ka4ipgO$Ko<@-y>3`oyC+SWLr!eb{9mgdb}(>{7xq zia{W9&P86z#qL*^Rop$4L72tBvmP6;w~^dsu?Rjyi`9bNMPVWG?xG5YrLei=oJ;Ip_G)0GunlN`6h0M}T(N9{M}N+!$WsBQ-9V4m z0<4UP$ZuB}FFb2?C{InE-K}t|WmG=6+wSf+uOHciOT)1H&4WE^kB{u{@bZlm%c_8) zzkDs}BVU>Xl?9H^)XP-AXvfPLIP5v|UW4ab;h`7y=)b5B;0v4dFWA>T+8pq;U{y?- zX8AIIn91Pa-`k1YF!#to2|x795#z~fL4iom8oNIDd21pH4**DzzG*tN41~etjU&;- zw5_93WyW-L8xQy4p9#%HzlhQSG`72HE@L& zNbOhbn~?$tzi<-Sv!ppa)UXY#;ujLsfW5kZ6m)E^PAM531-v1Xt3{YU z99)4hH*}2o+nG_Xt;*W^{ko9BFbG4xNLAp{b5L*j+LxDJP+hn8)&mj7L?eWnVy6&< zjPa9=h;}Wlk(IWp70!>f%6FH5t(yd*fcp)f1&t_EBur2NV zi#QX(w8A_V!>&}o%x#)Bycf*f5$Q?8`(P2f^{P6{vDz$U(fg{LS8J+o^V}f%>z-WWrk$~+Z)6~U)TjBI ztrD5pEPQf`tQA)Bptg6QpR`5O>~oWUm!grYeyRZ7Mqx5CTI4DvqZP{n{H|4oy8;xz zs*Woe8`}l8&eGY<{nt)|nz4%keZF>@+|$LCP=xmW>kCJ{262>YUT`jf(==dUx&hF5 z$8C7%$6y+uR~XG*tJ&=uL(Cn2_rZGh=-QZCtnN=E+PGKce`gn0BCMzOA{ED2EKg<; z^hd%FxlH-p&aV1lHyq4!zquZ~flBy)rAFveYLwlA&X(HUStP|y(>NGA5}jbV)FCa0 zf8a7Chsh-9qOC_SxbPOBz^&{-8#BbAz^YraGy2}O_$hk>A) z2D2M@WLQ<7Cy?@q@sp1Tn{=CMg!K7OCuEZ(X|@PrL#mleGXlyIH`6wRTl#E~Ux8^< z;4++Pyn)Z-RJ9bD))IDqeXZx>C`SJeoE<3-Da*c(sY;&Ehp@VG5J_XC81dQ`L zF1FzF4@(S`p#_l|G0`i%5h+6}qTq`yTUqJdp^*yBQ@FTfmrd>QGH`3fwA(qeG@U33 zz&ipy1z)2;63oH9!{lAH0~PF?t3koD1-nY6IV=yySY}ZQvIsnXiDFUGy>_gJ*ON5< zms@E0n}7ioXEz(h|NjTeGE{ka1HgplzjuumQEu(7`8ShHSC~{aMx!{_nV{rJvfRB$QI1vkc(;ibY&*E7O$^wdT;7A-L_<0G#x)k|JF z!`iweGAjN}m%Y(OK!OC|s@`H0fnscV^Sb)em(?ZdMKsFT9F*jRv7;1>p$L;7V35-c zoVA8w*6Z(oc)-ZU>+f_L2|C+QFG^QAih9g@Y-(VtS^zDuc?(!rjB+riG)lcqtC57M zXaqBAvnbqD?VXUs6hz#g{9ta#EK-pmkM6~QqC6A{YUrTMH3+l&0r(4>wyZ<-Y7dx5 zUb#zGU{eCmqieS+cqnYkFqJ#0=poiy41WXNFX&N!)Bb9bs{Q)3>sF|I7_rJO{yy2u z@_l7771^lFZNMQ{cR)=asM%;qG#L@*7DY@qUIax1qY8payul2;rLa>;E-85hSkfZ? zjNL*1DlQBK*VmoP4?B{eF-NX8_E_FT+Fj|$ok5G6y^ zpH?G($J)%lfxXkCbM=gElRbpe0;*yLp{_48^eC$UdVy|&FwrWp$_9Ar!j>NyvaH62 zI$Pc>a%q5&5oD_ou>xHdI>&%FEkawtJh?z$0k+wm$z4{3ZzQ+ks^4N+P(r>!tiDxJ zam^6;Mi?CEwyF3sdU{2<9lpiNE`fY$03peLDBo1$``b?h6&d(Yid~6M!$4LoW}7{o ze)r(p5r`I!U%S)z;OOnKN$jTW?Q2s^RrT`RMVVuo-fWnNDe}Ar?4gpLS`GhJ^3^v^ zYZaq)n5Hnvud{S@b#3oSDRmbj$}>u;9E zX;v$5PW7?awXbX=#M)4uPW7~m7BJ#xUfjprlgMAV3XFRR+8BfM?(9BD++H1$*#UWs z0Em(tO)6=Vb}#jh8|$#qpV))O29&6Od)c&mpnf~j4`XTbzebZvP zSCiGyYf!^(%PP94A~7r*t)@Slmt1X!!bWmZ6AUX=iA)~&ugv0ZgD+=;ku8Hwwc}G8 zjDzDbZd&0>)z+gNh-Jed)Hl+jE;k%6JYyEOeS*m{jU^MtQL_4=H>8&*Ckjn}h`Yh% z*=IsuE7#38!0MEE90A3sruONmsfrJCKnoh|8z-%Gwx}zvmP?%lUrMH=y*37W-(w|A z6lG|VmR@M7%3d3)OxUfui{h5}xPe6-bf7Cq{2e_(;%%rG)E-}%4Pb~_-EXvPRc@yA z@H%zIZ?A}};E^;=-(3k>c;Huc&e|5gJWSN^6C0C_Xvf+#{m_tbRPsZA?VV0H`Vr$2 zhK#}!_f!b++s?G3{mBm)kT@J4p5foOd*ca4%$@Ve**V-em-WhWyTIt8;a#tPDLekV zp5&7mc1=s-4J-u3oMoI*rfxyGcDdUmc2{&@f@K#1tesTs=*GxZyR21MfX-fjw2o|W znWeW;h$)B|wCqyzzwhaPBMeofGiM3sp**zFI(k^$_)s)gyNw?-bf+A6XSZDtm4j7P z5W5>NdRZB}wu>D!o{>t}HC2M~QpSm}8S#r=J*pY8@IgacbC|7Qu zrLes?D5S_Zmz({FOtR{5?F>_qHFd^;#26zIZ)v4l;7ll}PbttrzD6RBniQQxrBKx> zLxPqeE3el+b-`6CaDx;=4sZuGHJV2hiSuyLrrbTe49L|{kvde)Zl}E@&I%Qg%hK_# z&8Q1k6!CF<=(zEJN);rPIvE=LB|rxe1w3>KWFqoyKaT5EBVfi(67=H$lQ)3Dj@1Y} z^a;;~gGMz1eHwABY|uu3%E1I-Hw`iylOF;dSit2VgVcgKa!TMJ#syG29RI_GoSj?b zSq%{CA~CTQ!{NZo+=q)fchDH(h;??MUpq##mmLg7XE5Akt5Ohfj zusFEA$L2{vRlLf`=E3neFOQto!6YFLrNWgkYT-)?iW$*Uy)GdGQvG_=fQX?PS?5t^%V4KCqtP&cs@n|lB0EA*(WF3g zu+|D@FpOS6*`|m^w~H61t0|sOuTGf3@ZBO1KHvQ^?by3(KB~%}s?PwVF>`KKc$8VG zLOq&PQIT6`)oNp@xtctQ~1{ z0K1v5;&Ljts)_CJGFY!0nF>PPthWYxXi4CWfdWb{Ec33wF&1f8v0VGo%Ws-(G__k= zZs1eAtOs%r**dM##5UV(9N^}x>)@8NMM`I^1&NI!)X_oF&txT)w!tR$No5*;HGOx+fN1xvU3YW}!(UqvZY%^h7JwTJ26UiF zx~SUC=fCLB&d+vc@BaZV9?F!F|id93?ccnD>Ciq_NYVp z&afP82jZ>ll!2VEAb{6qz@<}v^j4^VO^9YbHY4e2M}|j~>*VFqbo(eLqub7_%z1Nl z&ox<(EylIGc~QL8*`=ZtxSq9o)+!KkQs8Nc}lzntzd)h}d1laDR}Sf~?Pq z>HR^*Qw(QipqJ&zJ0BTr{LDENEwn?%GznN|+w#*TPqMCljeL!bj;PdsEtK`FzJGMi zMdO-TQ`$xCa>0?lx6gdbY@?sRf?_E~d{ z)*!Gp<>(W?2Q@yO?43`4@LM(FgJzY8_C{YN`;2)_tsj(KH{mwOcM|<+wi-KUow}^E zQ95U#NShIH19Zd6GBR9%*;VFO>ngPVxa6xReW(+!kImHjoLO2lF{Lg@ujIk_?c!5> zYfcpvCfimQgQzbj^!3-JRSrA&x(beBmrstrkhpGxr(%^VVA$On4O-53XliqfXpu)g(9p_(73|&Q zLp>Rm)B9huF;V0W1NZ?_vlw8l0SNd3Qd~uJ&Y+XcVLDn)y98gLbSojWvkRXzV5A_+ zLvG*qK0lzz8{T)*!c)rhfWm8-7w(90gjwr+nQtkle5J)K@6aWAK2mts2Qj=j~a0B=OQj^qTO$qn`Qd}p1F@6D)Dq}5w$&#Be z5C-7;JPS4fY8GQ-Hk%72cG>I*+sxC)IZTFBrcx@EZeRcEZjdEYoYwG19K#l( zIDYRJY^ngsus>-|R-FFI??e~iv8Oj7&KOcYJNfC>F!sJT!bqbkcUFCD^9DX8kTtN4 z)2?Yin@uZ^OPfu^w2xUmC8e}~C$+5<42!f2#Zz1vK2+MnKo;iG=nh5_49~308FjzO zzRpp;B0V%kdYf$fZeH#s-Z8O(CQ+`QCu_Z{=Uhfb#FgQsUrvrqE`fDN7|jh|{!qoV+RZ z9+Y{cE>9`zBWgE$gM)E@q_FDYE8DoleFt0g9bDW>JFInheBuYD%d0jB&H@ColBCt) zsuFQ7njv3XGf`p`!%^gyJm$lkPwSt1Zj-QAD&*$GEuD#N%F%spA18mf$Mj?Zs1_oi zHE1j0O_Qto_%f(EuR3>C0>jz%WuBf(FL+vHB{7Cr9{qRy?PMicKUSl* zy?>b|hoNd|_*l%(SLAeEb#nWtA!8Q{&xB*F~I zWGL%wxfvK_fmsg*mNcG~ncOKQKY3HS7E`d|F)lGOE_7jX0PVf$cH2g_Fq+?difX#E zNIE1)YOoTXW+$>FJ34VJeUjYi{$wpSM1m3`65s(q%W6eu-G{hOc%S6%p{h`Yfuub3 z5Hc$k2~_QxckOvQZKwUivHSi<&mDQuSD)q6;ZND$PG@r~{f^JOosI6sSK|FwU*I#3 z6E}k9zxsWCHog_p#GiWo?#|BEcb(0RXC3F+MrW(Dy;1pU{rQjoxTDK>Fr4_Ut^@yV zv_IGR-`U>Azulefj`>%g`R;c2*~a$v&dw&3>ux^V+4@Rsf64Pd3;cNIMPXUFW$*t@ zKh7HeukrsH|F7}C#Q(=Xy=)!6esT1v&;PTntup-I-Pq3J|E-;8J70;;mpuQ!Q~dw4 zm$)N0aa(`!qSz0Ep4f166usK?a}L>74+dcNoH}c-M;dZ>-nWK45w{()FJ?_#EX;mbNqTrpenob&anchorNf(k|67>Mo$R{^e!{Tget*N+>^hz7 z``O){JDv3V&zz3a&A#*l`Wf~6n+`5x=CvEd{^i6QMDrlPLQo{%fGpG+hLMLwx;y!H zUi!)L9n4sO4RxKZ&C32=;7Az0*Sr-UDzzOSf@q4BJP7ZeWe?D-gqc2AP!Is821UT0%- z2kF1vPiNF8-?=yd<-(ktNvFkccr!~9VYz1N9wcOy&xxJo1 zl}gtUC-XpqxQy}Ph9kW9J^n3#jA2R=-*6w_VYRa`*AYJuHE-l6E>JdN8jieLQ~U}m zFGitovpsBi!huJ^HHV7yDUOu;-PYvnov0__OoU^48;A1<=-(lEYHB_ne zSNU)|u@~dE5Qw&tSgcgDUzttZ1coz3PHp~Pv|54*cmeb~FcKS0+1u8)&Ze`4`*D7C zbqB{2r~xe9p2t!9(hu5lJ5+}5@ET4OFk24S9MF?W6ov^sZX=D~R#?+y)7p}Ul} zA+hpjE-Mw+m^K|S&Spja?9r+1_pr?j^n^&iQWC@r}+05Hwxe}u&}QV1+9ojr()#2gRKRq!HZOF zc(E;f=y+VIELz514>$8Z?Lvu2dp)YaJ97|tw}ZsJ8YCfBn?VNwKoAc6a2Nwi8e)f# ziw;GtolIx=|Lwrrc^__Xw8MA^hdZRP)nF`@$eRKN=!t`1K1CKA>xP%VLVsaKzuklt z9YF(WxxH{6*oC^C&ex*8z1iO0Y~)K%XA$nSe1*+t?agPo3TGkUPHb1yN8TiH#byV} zMBY4x>D%~DJ?-wmQ$&F+`D$ke-i@PhDmEIxW)407T|t`ww+;V8-EMco+3tv+{O95~ z6jf}CpZ(|USas*bi^B;)p!PI?Eda1Z0JxmG=n}ju-i0?X0=Q9loy2*qHHHhKcDlL$ z0{@HS(1SbB%pC zF>tbQ?q*?>FiyV&92DLLlMtA+5n{2-=}J*wi>tNF{nFwAv^F{$+pW$v{5|XLv^ra@ z&bQ7aysDgke*p^~jD5flmv?Ye;>8aG2lNNvhyM6ZxD$93;N3KHlk46I_w5>(#vWjC zx_k8yWXBPEn!SL_iu)n30@r#Idr>NH;b(_Oduk=TQBU0ST=vBI#RC^Of}0WVX~2NV z99H;rJ{-bUMJ#G|gBOXqfe>JxE0v1uxG|YA*B;ODwuH6&q%&JN-aS1%*#Bf`1HUr1 zSh9b8+_!K~3|p6*TdjE5={C(@8~FNnvdK3)|4y6SUbO5gZq)vr4uPEcPkjht4{zmx z_uePM@Y5X#8b^1lx-^AI$>Di0jy-JI~ z={=!43_VE;L&1ZyY|(Tu7iK39$K1DYK0&QD98~Jz#7n&P6b?OipZHN%_e_iDhGCGn z!$f2?*1{dZX^$Pf&XuQ6aWP|k%%47mV{!cIVE6PuAj>S}rYU|!(6BLN+tYA(L!yW< z;7uz*`zi|Ov$i{Gd)}x$55n=-ANua3 zJsD2owm0*KaeEOcY6urU4B88*sE=s60Qgh8`F*%!9@BUU&_Ym8E4ubBY;WEXv_uwa zqobRmlJa{{LwgMHHZ`83 zjH?0IYq`8oYy$$1QNRKfzuk1UJF%#DdYx`>W3#bbXowQbwQg*!|6kjGuI)e9pWl=I zU#rJH@%ew8{r~pX=Gy*$ZU42#|7-iN_2-|1{|5tLU6aAUncaO}`!9|E4g0U1?e5zC zYmNWc`2UOI|E*_RJKt?>uJQjG|NCtcX`1rs&xQZDfalyI`oFuqv%S&T`Kkl|JnOFU z|CjjqQ&NP)*Ym`mROBymP*Oi4Pks9}4g>XFxf-e8VXVHz^UGNjk|u`b=yFFn(zQv* zawq&VQ%D=esbYKTL8c(eNy&_kB(<{eEHlcjEuU6Yt!}M|0_zUP)Dm@5Q1o?jPvcknME`N=*W9 z$mr61H+9jHau9i}Kru?l7I$Bt9ttlWx-)4RJaZFNLDFmVMH|SMeb|V!JN$`Pk7{q< zcc0h4@16h9`oC}Awgwl!y*)qgw7$Q1dM;XR`1gm_|6Vj|jf!mM1jrlKxIlFtQ5Y$= zMWuXk;u(yiUV9tV8mW%ui8xInf5tt7t)*|T{ltrBXeO^}5ZJ!idj}3h zy;f_|tA>MSth0JUS1{YUfu_9a45kyy#`={%Ce=GWO#4Pt9im<5+$(~%ckK;tXsCLT z5P(qv&FQ7#wU8F)Waq54a^ltAt5aP;J%)u%hS$6(^c9w5A(*%E)B4-nZyIV2%yHR3 zGo#CIGP}4uSlxy*p8xRb5IbOhDwYA@GzGhaG!ub?1q>VlVW(mX&2 zM?n>>7p?aXAFzacmV`P>3l=g{vj1l>+4y-Dzk1y|*=}vMp6P1xcrI8>8x*W!|IfIT z=WlP{w%$4y#S3bIMRjp@CX3fNhb&AudYxBZ-*Z|WT;}2iK41wBkM@e@9Uk|jK}+Y` zt=4qb*|sKqv(?>dbZ> z2?u8)iJCZ*moVEsaT$gaXz7JJiM^EK*&U5w=L!kP_TsU~HK}Zu8g@~C6MN(NM4ii1 zSfa^YgRHLtwxUqha$*>{Q)LHK-`jn2c6ju%iOVIX(jX@-E35Y0hyFlW-FM2%0OMss1$Atvk zF%sH5q;%IA@6UiOh{+X8?Pkj>uW+;B3pi}_{xUUlAQz57mazZNw^S-ycW7 zUkT5J>r0b((54F$0>i=s^WUdOucbfG%IKA+CXZTY*cx;_H6FXSK$-pIvdHr~qxp0e z*R592*%dgsq`%R~R;j)Xs^S|_ZB?Iccks(wbzA^b)H6qTKZL7;Vx^$XX$}LB*WxgY z(4Vr}Fh*j|!XqXCKUfBh2yY{Jy_5)EK>Qj`Y_PG;7JSBZ6k{-azaT=7A;Ogixbeo?vINl?H9zXPwW?njp138I;n#}cJkntN0d8w*tq31Z5K^zTf zix4A~9RT!VaOL5~p5Y**WIzEKpd<*5+@Y=w>l;yPGuCl1)>6%`Mi{oJIlhHexq7Z0 zy?HiaJmG9UQJ((t)JbYDZMc#>rp5_nE~#mE>%5BnuU<43)*N~9F!EbUMy_bD%!N*F7EL>nn3w+wICMQy$R)^eV<aNKB$x?PT!_l|x(K6Krt?6UNrS%7Q-Rd zy>tN;F@+hCleLHZ3iPK0>E(vnc|aWScfe(~fksPEB8`_%+U^33`! zzMSL~@%ZgKDV;~0bVkL1E&2MeBWpZv;`9Zy2vMm*^^{tyV*6F0`vADIXGrh-Kvn{{ zT$CyMiL8s_u9a(3;YTm?^ON1zdp~~cIxjw-MAJ1zm3zD7Fms{T3P0*WK4y#H>dUDq zJ#RnIZSP3N71m5DdQj&wAdSNNL_G@$qt>gfcQ}kzOST3-{CF^)xL3?@svvkHCUTnM z+MCS!)t}QCB%X4;sj~V=s)?9R8Yb^E(v~c-WcUWjns8gwr3X*4UM&vQf~kmY^rIy( zL~7ydrLvnk>_<(Ep%B%b&0t~}_j5b1kIoKy;&0(xOffJIE7ef65sC0NFz-br-B9c% zNmS%AIL1Ca^*l4UQQLb@;acK0$B^-+7!<{e9Yy+OI5QbHMs~!tdLU&{7~Ez8cw~a4 z4Rw{~vL3J2a%160EQyVQm5SG*j^0%}sTe5Hg-cWv zO498)+Lh8L8UN?(=(u1$zBjmE24r9%B+j@>Uxcv(XmEHts+;8CEL0+Ec#njXg9FA# zbzQk3(H`#mLeMmndi7MgIcnNZ@&m;k2d>1Dw5#@MC&xzXy$p-Apv&rkdl}sEHAZ7DytD{dKBYMlMTd+e9`CqY|Ve0!uD| z$e4~ktQGHflvETF$p-6`C6CoS{0jF;ItfitGb!(e!rAGB781OQPAw@^K%>F|yt_o% zN~SPwz14+W zqJ)=VXsCB)Ga4KAL~Z}zFSUv((7-DfFy77L}#uN9dv^n=G6`>b3nwZjiZWB#0f~!i!V3-iR zAxQ5D5`$HQ_R+;)#qJ0m$nzq9SAGpIjmkYGroaeiR>*4p%HgkD>b%EohfiT!ZS=S; z2~@+-2T$w|NYoN=)L$0weDTNodwDb*>y3DLDBiWjHSkqY72a{hb?9ADCAC|MtI4-% zMO^wP;seTpCr*%Z`Af#1lFVts+Z54zYh ztu>l_?GC~lY3-$eP(;gc<^|a*(2v_%1GOJx`}Q9@v;*rlvTPJEYRdaTtlL z9>hMG%t@zr#`~2g{ZIO-JhA#9UWLqYAdz=)e7JW?j|V{fHRbQ0kM`fZIyh|-ee)bE z@{_?|4o*%Fk6u?;VOhNj<|O$YBEAyyK!pyKf2)c?FxVWZiX?Oz8k2Nhb(4vESvfvE{^{l5 zP*?qNp^7CNt==F=km!}H~ws$9PG^J24S22$B zQ*R{`%^Gs_Qv7Nj!&(t4R6v&Ez(V}77!@kmkHCSJ{g6ZYY<+N30wT&-SFsVb6HSxI z^XgTqm*KihgNai!;tU4`8D$$Ys!Me}4(fH7ya?yPh&e&40k-(fjlsf$BoDwV&%X-7 z$g@hjtUb%wo@RL8T3Wr9VSm#_H4DMQMsi_c0KJ^JkQ&5$0Ny%CPSJz9u^!fVq)8T= z+EQ2+pDj+TomOlGrJ6dY%BCGKzd^3d0;6JH;cI2Pdy(xJ^HnHkUu`yS7tIFE0&RGn z2D|T>NwM~P;ig)&`qhk82uf+nu6f%?Eo;hf81qdAH)5Hr?|aLJK}n$sY{)druLYVb zibtxi!{y>g6>AF`M-1QxLwN~f@5SqbU$XtKHmo^%BKBA+m<&-L+cZH3aD!I+{6h7iOj1zH+RG`4$ zZv*ibqjgL1D4HcH0kV=J%rKU^xK{$12Z!oxIN}YPz^UzsBHvSII%3*~P6|e1Lpq=I z;wTCA6Fo$v$#BdBZPQU}fK_I&-L*0X%T2xL%2PELN$a&_e#nyfR25Vvjn_ggA$1Hh zI8d{sZ+eKJ)sK=jrt(_S+2&ggx#f&{w7BsjQyIHj`VdZ+paTqdcLs z$$d+4zVfP@D)oHBJ~!;g@!V@A5vpmU(jFXQDM6(ON00%jrTQylcWiEa`AF`jgnHprgSwjOSfjiqTlH8P zS*dJEANnJJUtHUMij>4)bXjkl*Zh$*a;vOv;r4iwg2VjXP0Vs5*o#v{J*V7TT8OyVY0S%22u4la2+^ z;VVPP=8H+CV;NTdHG?fJZDZMdW2IxR^Alm>Y_kkPn+pP$Bef*#uIrF5(`EQRB@U}3 zjy{SFYuPDq5bl-Nul|B&gDUk6a4|B^1m7Tv+y`-Gtnkr~nYax1wmQG|W!Nvh zVN2()a5{>qfOT}Lb^Nz={I|~#|E;^Zv$@mhtmD6}rEw*)tMLFqagcOK5+jKfzOKagcIf8}5DTz@oQO8a- zY`6Ek+PglTKFCs0SUr^;F7o7b9B*cTTx6 zkFl<1AJ3`Hi>y`7VKDOE7ntLe?G71QN4>6C`x$9*3;hn>0Yg&P2Fp#6f7_$+_A`QM zlzC_i4z>b7xjJmXqx~Z^uvh*anARF*2VFXpt6*l!M*h_`Ft}+sO8BkZ8ui?3af@Y; zld$qqtT(tYR$oLBlUbW1wHnVf2bUWf|>j zHWu5A9^ETl0VG{10pXFUSAEAM`W&1nD1^<^S2- z-p=KJ*y^nLzc2E6@`v_3j@p-g04!H>9R{0d+%GCen5EI3h`m>brXj3kQ9RUAdK0t< zKvz$x-$HJO85U_`RzYL+o{;;fQbDcgl++sGaE{s>h8cNdigDKy6~+D`i8Yyf!4Pgt zxPy_k2%zbaWcWv~j+~Xj5aT_}N%~=>uQV=p4!vyZnSXxNL#87%c`&-!U z@7v_ZP#E+)%yYu>_awZ!B9B4&yEF{A8_U=M1B#oPE03vM&BFM*xTGD5pTgtO6E1CY z=taq8HIpvsR&Rj1z$T0s;}$cc#0$r^NlmGc!|)l=4RP|sF8qQj+!5750|I7!Z~?EO zm5I!WjNSvYFphmxhg`x0+z3`A02oTRdamf{rtpGyeiR0z_KAXb<~s%m|Y|-PuxGRwXP|DZ42KK5z0b`qiBQ{^e-uf zE$Zi(p`~@43H}ELGWp(p@I0S}q zrL*?FeG(p>y}VMbq)Y*I1&?-J3vXVB38sHOQX_X&Fi|}Rc-AL)5HUD7Nk1a;;Tf?r zdpa<(H&MD=d*e11mQ9U$N}=JlUsA+4xbk2xu0XqWaS=XKi_75YYskqgD}!fpSs9H> z5X&rX(m*AQXcX)>(nKS1FVQ?r^ND~?QNCw!HEb3D;0AD!jOsP0)6?QJ$v8>GiJ>t3 zA^WDKMrhlOiU%xnNYAMAYS@BE3ScrjQ;DCr*L`G;ngB)uVj^;z%Ey>kR-K1ar zx=x_UtTS$XUFR>obMZC#oXMY13WgDcjaXd38)^U6h^x7|t3zAt*3hqA#+YEhM*$>0 z7z{|vG9bEXFpy5Md_w+ZDe5)>-jm_`Y{NI}Y1O6{3==^X_aEbnJduwxt z^FMXAo^8Uxhtt2cv(EqbW%xg_XX*14e+SFYoP`(6r;33%fbTlZ(_L&ZOG>jh^XsIb zz><sC$iX(6Kbob|adN?>qix^wUm4#$v*8ANCkMM{2ZNVC4o=T@&)y(sSv7+Hv{BtR zkF_-2nP7w8c6Qn{kIrE564Q#1>3t}vbiS5 z|IP(A*^xcaZ6jvd_r|D2y$qoh>(Y#YOMWNsQ5|aE)EM@Jb}G?9qDoO(dw3bQ-*wy4 z&8Aw2Dn9_MvC0ZGJI647)7ISxwjGbgZDJPza@+Gpx&hcrSHOHncWpEFr4119@Rb)o z8ep~ZP^lo7_sFUI4Ab~;J%y-ONAXK09s*j{qWeWwAV&!RD}Ia)W+RU8B1@1iyt)hc zn6UEk$7+!wAxDm$o=#ea% zj8OQ|M?Q1eERM? znYSBVTXm}LS%~pWhfRvVmUzcecokuWZ&`rS)jT#ow-mXgPHmPcc!6OzM}-Dzmdsq6 z!eH#v$62#)Nq7a54-i=^{?2|k& ze3CQqX$`Jd!OK`X_ln9|=FPcTQSQl^i7~lrYgQtl&Pl0QueMt8b$HtX2&Bo&#;a4U zkXBc26ky$GLs(0&hXpuRncCkN{s_tzFF5ssp+cFmR#{QZyGOPzw-Vc67)IOHbCM<4 zFZ4dPyUkI~Qfq57m!x~8ya>p5o`Uwe6EQTi8zVoF>k?@yG5cP|06O1C!3E=XO?*@E z+UU)GC>`R-5g%g#kk3EGW|P`}8N7~VGUWKMXznGLdcM_$J&q=Hw4A3vv)$t!g6#wJ6$hVA57ybN);dj8OlI-$nQKcmZ2P3@i@3E z7*Y*UON&~nqHPSOMonAFi~vLIJ)-|ADj$1)+Q# zggioe-26Kox;(bNie#Ce024x`a5~zNp7M~ z-Lc0(SmOCq`b_y_+lfO5GpE3*Dj16Ct(9=x8ds%?iI;@GyR`1D3HsB{Tf>!!i=r$(@oeIw$zDB|)|GR zv%?YAWIMTG8q>0Tv>(uEiEp^awM7e5(9b7QUP)P+HZk2bXHB4d3zUw{!vI5L-9fzpNy4!Ud7^o^;1-7Xr=RFTo`8N3=&tpaeIS)I% zCgLy_=#FH?u2Na3s~eD2e8TgEzx*h`J;fn_@^= z&T)nHs7>=+H8S3g>C~(Ag~gLEchka|KP#Silk)hK^Pgcj{6XstBOfgdxob?rqS`DkNq!*|f#z+=4>N1dhw)Krk-)XUT(C8-aX zxhRj2kMb22lncK*F1**6+|GeFTi0OdT<D)#6lTxqjvu}j^?MEZp?$9*KQzR>?CwLBA4ppm zPmqzxJMR9=OVZc+pSAvHt^Zl;fAabt+nw!Wv_MPrKhL^5o3{REqubrsTI+wlp#F!Q zA8ieeio2neK=kv`YMx94p_KRMvReJ4bV(|p^QxhTOp}tPWx$(txMS}*-q?n5$)3va zjG08v6&?PYj4pnm4N54p(hppHL734?4)!UD{j%tuDt74YwGWM@NnPYO9Q%Si9q!eN zfD=xMxftp&(UDQ7ezGEDDco8LTxInbjaH0%iUDEWKpgz_@D#lujkz&`Kz{BBt5V#? ze^l}a%tuMzc_Im5ems9%fDrz+I7&_2RN5idXKKsZhGOuo9Rz zw2Yhu0_Lk;=0O_CnogMntkOH<{YKegL)oktsj?L#;GByNsFTUS&sS zXjWDk5^8&wj|WP9*kG_XD~*KrnmL%l?sBnOWnpi*kR9Z$o>RM6YK@f}eDa89?U{PA zY_4Pvv(xn?KVddl=?N{7j;|f;&5V1Q4N2k8Mx#P`wi21qsqd%p%&k+7SBX41e9eU8 zss+o;HKLPoyn^1;tzuPkCaZQJX(bNIcgrr9<`mJ?Rh4O>s-#^mGC>E6R=PA}$a&2y zo(ZW|Zbp&D)muelqKY?De3TKeE;HCztr;xaWaN;Knz`^$v9dz%22x?b9Z}8Ne^9r+ z5micD!^8llogCPz4{aCp1c@EFVKck6DKMJ|rhA|uA_zAe8-yRzI+f!6{IQc>(C3mF z$n;t#?6Hq2d$^(3WDXE>6!7X2?#p_rwP(S-ng0h(CuGz-JIN8bF{DuJEo!x#)b;O7 z4%#$KdoT`{M~g3LBTX4)13Ryo384y3P(J07&i0fKOqgGoF~e`&>!Cf=3Qo`R#7>La zsNQD>WoKQgT|Af_sAf%3{(|R-V}ZgFhCpXUw|;D?3xzwu*co>~!oKrt)lAWLRBb7W zd#jN*3rlSawMmXebh#Y zNoMXGLW5DuAC*JeJv%rNhx?+%F>C0^!_Dj`6Lu&w5(**{b>$+)K(B8k%cyp_BuM5B zMOe$ShEjWVI4MCWbf2I-M&a$+hs}lo{Bm(q3q!yuAxMStP#*#Q$GBI&O>S~rG&k1nrHG3WjiL@d z0mLVP5Ul|-Md7;)pHA9^D6ATJ(@=@NXxmKu;0C!=<&Ygl?yYxO=#K5ZZ{uTh_HB>9 zpY^-nZS}T#-*&g2bvK@EKI`o4?DTr@rymjH4A0*Ft8(Az82(97S9)L>A^mkE`cte=h3x>C1

dq?U_A=1FnUF8+36f`OEb;9~(xqsA!dtH=%-Z7ePW+&gWSXAG4?2Q}OgRUD}_a)zyaw68s_qF}c+WzNX$o^+*YiGODeYUp$S=;~k?V>=^A7})$(Eg{}+1lxB z$oPNTn_FFYz5$=^+WzNDd^m9rCZAIN-xJT9Es2SaPRLnn9r+s**knVcE6DRppvZ@Y z+c?@&PyEY@%6;mY9Z|oV)V+U@-7tO|d6UFl*{Z0SF=GA@8>iJxk8Jy+W?mBVsA{4>q~L^6&`5 zXz?+1j^VEXN3k=f6j*@R%ah}uY1){n#3$@B5omBubTtVt>$Rs2bj-Q>N6k{s@1n0E z=>T!()eHv;IShiH^<}^|QW=mLkAS8jng;`kcwk4klL2Cpy1di$Y+$gg6hk@3=$nBn z4}-XMBPC;$lQg+g@_vN3m&8q)okmXKVI0t%>D6#~+!L(U*1zUPHs2J~*0jp4M$8Q5ABTbw1TuQ?S zu-zD?oai}2y-+`agD4r>}eQkfKgX~-yUFg z3^}$mgxq;;_x0)F^H&Fh7e^<12ZOz%S4Stc3o`bBT~MnSy9})}^wiX3M_Q`US~Hbq z)>=ONOnYX$nA9@8)9(}@dXP$d)6UzG0|E?iYP==)E4ZQDh@_wYeR}j7h44r`q{>xQ zcmQu;I7n$Yqxp0e*Nr(cjdHRzYNF=+3O93oT)V${=-&)@o7F78b2FGYwr>*$&7JOQQyBhb%-(ylE()40&A*IQS!gt;;ZwqosO^ zyrMwL{L_;$Hihmd9!$CSjw~D~yfL&!6Lhbdd~h7+ZBRAE#452Llx^aYPkhd`7hvx^ zciJ>G;CNYaqIZNW?OEk~c%y}VUM>{VQG^#KsaHc$V0C^@^ET$L!$cH`w4~*x8QemF zaUvJSIeH-p&!hu8nM``t!HXHC-_6!>B0B5vsX z8c`nDiXrEEp*tL}aj)9Uy3LhZBk9hDR|8@{ z)hS1*YFt|M47SGAn=H8xbJEBklv@662fFW*)k-Fxc3%Kh*kRq zt2aqjjqa!fjmTwViZg53p84>J3u&?=<3t_kIT5z<$=N|65g@o7R5kV8&)lkTDW{N;gP6W<^ETfRd8A zP%Y8LZ1mOTR|J?fe zRL&x8AIXPWb6|CPYy_un@tamQw0i3vwiy1ay7d4E^U6FEwzE043Uhl~C2w8>%n|LeYx*(H?%3k?qXq2)8;BVjkZLu%qDcLEgU;)Ku1}N{)VHPK zuW3(k!rL4>)l;)>+`F=kl{khRW|6SfVFd&do5o{sj_>tYH8z=rlZmmD>*}O7je{f! zhe3%{r&_HZ0~GV*&4a{GFqBfj?k^r&3fqp2zxM+RCbUmOTG43x@~;swPBpGc$MT*r0iTkP#&$A5$#uv8&L#slL+x<}OuS=B zs!4YRSEslX6~oY<3-rylcsbQOYdw`vZKk6XzE_7~r zy4kC}jD@h?u(=t5*5?znth;|`@Do)UZPYSUl!<99I%7}M6zRTjM5Z=n#!QF8ho;+6 zH|)M50t_trk^7$$fvmp&OV5DBFOS{yDgM!Jxv8BdiL|XOkEVmJdcgz}+JMZH>o5ZD zNGFy|&F>7$=>Kh_j|bfxqZJ4fS#~hWkR}!pWPmgb#83vE76*WF-GbIwZt})7uH9v2 zJxCxOB`;Inonb&Z5I6-!b&+r5u@qzDq{O#_F{cD|aK=-KD*mEtHcOFMBSE6fhLDN_ zPP|wWo7qNq%9YhS&ybqD%)IGt7*hsCPz>_UGv0EenfwYY(H~duO`-mSlIXwmlOHkU zE6f-Z=xNvYBoz&lMDz~RE%*&i);qF6s#c%aIaV>}f|Wh%Z2((^^fj5Z4*h$}80l?L z$re1_JJ~(k`?0?$mq$E=W`@_*g6f!nqu;HlQ((Kmuz4}v(ACNS^-MaAClFHi6(U>3 z;fvG$A8T)en*6QVh>H5w|6?8J0`ePSX!Okv<fJTKqtTk(tc9gw@*k$QYfBKWC{xPjx z)$+&lbMZ&*Jq4S$CN3`ii=p;%MzVLafZ|sC5UA`> zTLKjBc0X7I^_zbEkB0I6*sqL8-62tP2XnpH3yoQZF$4lEx1RVGdY#9(k6JH;U0hto zWib9r@3QoGeA6%7a`J3x&xj0G$nXaGXakCInKuBw!sZL)1Id%<4wUi#PoE0Qr^6kM zSe|mP8+#B>pH>S9{9_<>P$d-3fk?5+lO%#JXF$Y}h_5}ik;M#BcQX1{?65yV=9>F_ z?g*D`j<0_O5#rmw`GD3{`?b z27^q*O&MkIidFJ?1u>eXE3$(F$xDl3X8Aa@JQf1%h45;It!qZuWi(7#j>sE^f?Waz zQ3#|sV1zQde;5{>vfmS5>9&<&~Rsje)JMghBM4@>_X~TsjqDM85bR;jB z|C~_Xm)IeO=Qc^~AkQ1F>q8 zhf2=xP764M5k=1tEDdkfm90g9oQ0Z0egHSFH-lEO-8Dd zVVfZ1dMnoK$Vn)b9oSB%Y~Pd~9rU`lrlMho=b+poMcd5mK6xaIS}Hhxs1foV(=LUh zV1&&v51Z*~^(l!Nx{s`@0PQ|zZbT?t$^3<+6~6$bf(Rf-s4OH(UMYmdbO1*^!cL=L zIXi&=bn;{+dSvOPYhJjy8+O^X$;et=nMLXYz`i~@TL9VyTjp(<*~f(3i-1}NkGAbwp4#|#V}B+L19fMsArxsZ z!`3W-xLlb4g|*Yr!V{5eW2hP#x|0=~c}3!wa+nc=vD4=~(C#t}hn8S2}Q08R?|hwhQ-p zAdO!Um%;nd9%df8c##(yGCQM4+nUh04{`{W24P}mPxP~?8Y z2wmR|X@%Tc#yQuDLV)Rw26`I!H`|29P2`FD6L)$!a>e_ec+Y&S(Qu87q!A6mB*z}x z!kqWEFS32FBM!PIr_hFIi5I@~?3lXm{poxvZv9chHveShJq#!FsmROGRM!^J?4mIBPI2;0;v zE1OK{FWcs&{NB`WGJr~8X`o{5U! zM3)!CkwhmOl`;+&w+fTUyP-cvhYI#DF>g$+t#M+|pzgcfEz)x&-@{hO6~TVY^*1{e zwt1YJ@o&;Q+ja->+V+njLiinaMRbR-cQgoOXN#-s{!?0HznkF&c^|}va*atNpcQS$?V@rzq_!(=dJ8Ly9j>dE|y=J!Kz_c zxea845Wjo%i5O?c8OAIB;iw7Amic@%c5DObtK83r#SV?SM3(L2^8Ahswc(Zw zqBk#RSHG>tDBbJ};!b|9+PtWuZ|WG9%E|HRF-E1+`za@+a`tt&;tp9Iv$u8is`ndj zZ>uh|1}a!bhW0rY4JP?AUjv7_295 zUo6oiL=wTx%Vx8(Vi~7zv@R(E!wdb}k3>Tj zq(`6%w>K#gJ|RJXH7fEy>NAx;vOPbxkEX55=C{H!QFfaR3l9yyaRT>>+GA&ODKods zi6yNp4@U?AUHJylB`4qTs9FNkj2L&XgvlKj)F^Vaq-4cK!^1p93C3WatAKyAz98y9 zM#*q;G$E~VBL;K2ZK)tt;kV(9Pq{6SJvw^~;O1W3dF!fFLw+0ZU{Ypc9;|{wPOpM> z8V^loMTN)wjuJz6Kh%hf5Wj)8XL+&d@u*PmX=(G&Q}}B#VC7x!BA2q)!;-F)H(|h| zXFB*s63==JYpcogG<>6mCklSxVH-uc*O!%D92yW=r!~E(*zw3Fxhi(1?=Gaeu_7DZ zP`2s$D{Ox{1*YXq6_6QeMDy#f>9&@E#01m}4civuej#pe+wx=mk% z)6sT#ppE7l>D()z%m9I5dR}XuvNWuNs8Y=0*z=HF1~9C@{HXGSiT$ik*! z=w?NRD)Hz^u&JnIZ-|LBG91KGx>hxtOlPYvKd8N&W6hG;q z9mmN8V6DyUNX<{NHf(wnp z8;tvw`~-3=4BaI~E!?`gRH?P&Wv{2CH&9t&fK~gEsod-vYe6l~J(XXcG~`9R)0aJm z1Gk)A@E4UfVoo9lWcRM7*Haa_bf)1Yb6+waOo{H#r3R?f7IWPWUzF-x73pFgYF7Oa`3 zuBwej_-P_49%1!*kW&tg!PE~c&R^~5b4h@KEU%Dnf&^IT3N?!@c3 zUbU2Gq{L^DxGSFBz+M6Kxn%!8_f;g!Sy0qb#N$jM#pkoE>d7w=1STwT4wAVY1e$rp zQYZ`V(xF6je%-W?_cTe_JAy0I(lNXxyU!r;1~?+vS_Go=CDKEZGIp_HRZ-U^u!l-4ZaDKdBy6rH1wo0)j9bj_GOko7F=ohL)gKQ#flwd zs1At>D5vv^L6sbBgmNS(&~yuk6(@*citT8=>h)0XtO$Q1a`0ybq%uJ=$B$UUL6Cp# zE78Ah&g1a{$*H%FQSmRZzg9)S{p0j%Y;iAN21LfOHq3{=Tt9^8ix+mM6hP>g&Xmzy zntV%W&_uCQWxFsQyGd%E!fQ8$9mPj_PDC*QHtGhF=0u)RXXxpy=`x-$ggZpVz*XdD zh^`r#lT9aEjE(;_bEOUE7FxojeGRMBC%Z_nPPKx<-p2QClK;+Gr0hSdT|zFu$?OUsCGo zxPG)3ba4=k9^?P^LlgVtQr``Go%!-WMaZu>a zrL(fKZ~7m)ZOz3uBrkQMU`L?T?L}2ek3Xa;;mRIjNu=c_KayqHt~~Na09?9wdvhSe zY1rM0?Ak(c3JrC2?=> z<^`d6lslDCl$E)oEOJ|Jlg>;QQpZdOV*F2_RZLGbA*#sNbaY8NQUqVHM5RN^bs2r; zAzb*&|JICZ*dF_t(W>hRAZ^6j;fNP$vk+_{zLNAsn@nZdxKfCu6A&5a;$ytj=>%ON z$;Qs2DB6bHBT3UEYyY_cC)nS-2Es|b!utyS9w_fn`$UcmTy8>+&X$|O7n@z@d&E}L ze?tHr!CnzegwGqLb55cKs{;Gws$H#U{S(A>6sm}PadM}A1}fGZ^Y|@%U0EVD(LCT% zdI$g%si|5i98!s@gn2ezxB4tjLt-Z)v*Gw3MH+vRqC=|#vH0cH-imZq8@qj>_i9v& zN}U}TB?E0D67p3>h@9;}M4J6w^`x}q)RjiS;ON_maI-YOo+Y>yp~$2*B80?Iw1B67 zaYbf&TqgWW+j~=IxECSHCx*QtXTUha^B}%U{+J1_hjj2J zp=?o%gz$Gm`yLF<2mH!st`(WX6#~*glT>!gk)n%Aw1O=qkVSKy^Mjq4?p~nhEYpoB zJ)A&~uZ6MEhFEyKCQ(jn*xJcjfXHQ(r)iJ7wW^O4mF)R(Re-ZN?F(V8?%*p z_Go?e0Kd%WmE$JWwpjy+pL_J3Etqs^1}7KM3ir)B+h{M^{6PxF)>1C#nZIXwPWehF z;gC$WqPMYe0<y<$eeig&vAZ4 zWGfRIVx+cvDoK z8^4=-6jwD%he)ke2gv_U?R$~i@{3J3yZ@%q{qsY^ISgbRB7;*G-CzyG7|PjQ1}6M1 zNb4`w3M@)1!g@EFB?#1VqsTD&^;fJeXHhQH=wljpVMDEYS^Xk%!{J;RXM(!V`S0)V zNMwV9#UWSo_@WZ2m$#--qCG~)DFtcQLt+%hb+mUF&BK*-EB?YWwQ>n@=V@$-^X)>n zg-SwG=L#9He~-)L3*o7#B&f`BLT5oE%8OG%r?aRsGG3B4vUmjW|;k@px; zUr?c%dFI!|?0!`*u97)>E`N4d*@uI=!iwJfnZ9g99T3#jBa*cXFor3tCjPW%Hjx9@ z{^oFu97(}irJCF-u=WAR?eMpjozzt>#U*Fmrtxs{Dp#m_8kbywsw7>}ebY?6&a7h( z|HOsLNp<77>IsfvE}z7CqNQ_+0>h;qcj_eehOO6%epGpR~#Z2uBId%26-0>Uk#(|6aRBo#( zrfgJ1PL{ylFXl5pY1A+Ds2BS_eT-qs!MZiSTZ8FL@WgV_fUWe57|^uIKf|?qu`?jC(oF9^u}NRT z{oywX0HftJ_ARBv?j4NuoSaZKifPRH7gExYqzao~?dw0CL&T@q11cl9Tni)Av!^c$ z+15_#p#KH%jg!Th?UdHbXNzg@p(nIVG}iyyF^CudKY`!6cAqCw%?a(+M=CvWt+G!d zCxh(w+Vs_F*d|$SHBD@s5wB%hS|-Dux+OI4yrgA_xhs({39nAp-D&e{>$u=PWaQRG z8gFP~3T2_6e;@DNPi$sIa;pYIuUM6P9O5>%z%)vl zd24F6)Uss>zH(@%@n*E1clPmXsxrFuI@QPfBW1|e7 zU^@^gCR5|FJflMHb#a0@+f%?k*L`%+JRQEeg(FE&ZfH!H7X(r-UenM}evOO{ok;EY8)-te~JB;rS_SZ&Z@)--A$;(mYE;*6L5 zms6)frsa7keu;&>^n@Bj39jxo%0DDD=@Y_hpjM9}j5Nl&TMi;6A&WWH(`ruEoZm`v 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 I#s&fQKiqdFW&i*H diff --git a/bs_cli/setup.py b/bs_cli/setup.py index df05a7f..37a3bd0 100644 --- a/bs_cli/setup.py +++ b/bs_cli/setup.py @@ -2,7 +2,7 @@ # Avoided using pyproject.toml, becuase can't get an editable version installed (pip install -e .) setup( name='adbs_cli', - version='1.1.12', + version='1.2.0', description="Command line interface for the accelerator directorate build system (software factory)", author="Patrick Nisperos, Jerry Katzung, Claudio Bisegni", author_email="pnispero@slac.stanford.edu, katzung@slac.stanford.edu, bisegni@slac.stanford.edu", diff --git a/build_scripts/README b/build_scripts/README new file mode 100644 index 0000000..d186088 --- /dev/null +++ b/build_scripts/README @@ -0,0 +1,3 @@ +these build_scripts are not in use by the build containers as of 3/30/2026. +the core-build-system-backend just directly cd's into scratch directory, then runs the build command which the user provides in the config.yaml. +Will keep here temporarily. \ No newline at end of file diff --git a/deploy_controller/deployment_controller.py b/deploy_controller/deployment_controller.py index 549a9ff..2c80ad2 100644 --- a/deploy_controller/deployment_controller.py +++ b/deploy_controller/deployment_controller.py @@ -76,7 +76,7 @@ def get_container_secrets(component_name: str) -> dict: } # NOTE - ORDER MATTERS (Last item on the list "wins" if there are overlapping files when deploying for multiple OS) # Please make sure latest OS is the last item. -USED_OS_LIST = ["RHEL7", "ROCKY9"] +USED_OS_LIST = ["rhel7", "rocky9"] FACILITIES_LIST = ["LCLS", "FACET", "TESTFAC", "DEV", "SANDBOX"] diff --git a/examples/firmware_config.yaml b/examples/firmware_config.yaml index efb84ab..21e7d3a 100644 --- a/examples/firmware_config.yaml +++ b/examples/firmware_config.yaml @@ -1,18 +1,17 @@ -# Example config.yaml for a firmware application (LLRF) -# [Required] +# Example config.yaml for a firmware application (LLRF) Multiple tests and build targets with hardware tests triggered after ALL builds pass repo: lcls2_llrf organization: ad-build-test url: https://github.com/ad-build-test/lcls2_llrf description: LCLS-II LLRF firmware -# [Optional] Docker image for build pods +# Docker image for build pods image: ghcr.io/ad-build-test/bookworm-env:latest -# [Optional] Global env vars available to all stages +# Global env vars available to all stages variables: XILINX_VIVADO: /non-free/Xilinx/Vivado/2020.2 -# [Optional] Software tests — each gets its own pod +# Software tests — each gets its own pod test: sel4v_test: command: "cd firmware/prc/sel4v && make && make clean" @@ -53,7 +52,7 @@ build: artifacts: - "firmware/injector/*.bit" -# [Optional] Hardware tests — triggered after ALL builds pass +# Hardware tests — triggered after ALL builds pass hardwareTest: runner: llrf-test-bench prc_qf2_v07_run: diff --git a/examples/ioc_config.yaml b/examples/ioc_config.yaml index 308f634..ef0d846 100644 --- a/examples/ioc_config.yaml +++ b/examples/ioc_config.yaml @@ -1,26 +1,25 @@ # Example config.yaml for an IOC application -# [Required] repo: test-ioc organization: ad-build-test url: https://github.com/ad-build-test/test-ioc description: Test IOC application -# [Optional] Docker image for build pods +# Docker image for build pods image: ghcr.io/ad-build-test/rocky9-env:latest -# [Required] Build command +# Build command build: command: | source /afs/slac/g/lcls/tools/script/ENVS64.bash && make -# [Optional] Files/directories to package for deployment +# Files/directories to package for deployment artifacts: - bin - db - dbd - iocBoot -# [Optional] Deployment playbook +# Deployment playbook deploy: playbook: ioc_module/ioc_deploy.yml diff --git a/examples/ioc_multiple_build_config.yml b/examples/ioc_multiple_build_config.yml new file mode 100644 index 0000000..ab81197 --- /dev/null +++ b/examples/ioc_multiple_build_config.yml @@ -0,0 +1,26 @@ +# Example config.yaml for an IOC application with multiple build configurations (e.g. for different OSes) +repo: test-ioc +organization: ad-build-test +url: https://github.com/ad-build-test/test-ioc +description: Test IOC application + +build: + rhel7: + image: ghcr.io/ad-build-test/rhel7-env:latest + command: | + source /afs/slac/g/lcls/tools/script/ENVS64.bash && + make + rocky9: + image: ghcr.io/ad-build-test/rocky9-env:latest + command: | + source /afs/slac/g/lcls/tools/script/ENVS64.bash && + make + +artifacts: + - bin + - db + - dbd + - iocBoot + +deploy: + playbook: ioc_module/ioc_deploy.yml \ No newline at end of file diff --git a/examples/pydm_config.yaml b/examples/pydm_config.yaml index 18cc360..b9246ee 100644 --- a/examples/pydm_config.yaml +++ b/examples/pydm_config.yaml @@ -1,17 +1,9 @@ # Example config.yaml for a PyDM display application -# [Required] repo: mc-displays organization: slaclab url: https://github.com/slaclab/mc-displays description: mc-displays -# [Optional] Docker image for build pods -# image: ghcr.io/ad-build-test/rocky9-env:latest - -# [Optional] Build command — skip if no build step needed -# build: -# command: "pip install -r requirements.txt" - -# [Optional] Deployment playbook +# Deployment playbook deploy: playbook: pydm_module/pydm_deploy.yml From 49d059c04755171fd04a0f1ac2db083f488faffc Mon Sep 17 00:00:00 2001 From: pnispero Date: Mon, 30 Mar 2026 15:00:37 -0700 Subject: [PATCH 5/6] Added SLAC S3DF .profile.d conf on bashrc if doesn't already exist --- bs_cli/adbs_cli/entry_point_commands.py | 17 +++++++++++++++++ bs_cli/dist/adbs_cli-1.1.12.tar.gz | Bin 25070 -> 0 bytes ...ny.whl => adbs_cli-1.2.0-py3-none-any.whl} | Bin 27391 -> 27605 bytes bs_cli/dist/adbs_cli-1.2.0.tar.gz | Bin 0 -> 25302 bytes 4 files changed, 17 insertions(+) delete mode 100644 bs_cli/dist/adbs_cli-1.1.12.tar.gz rename bs_cli/dist/{adbs_cli-1.1.12-py3-none-any.whl => adbs_cli-1.2.0-py3-none-any.whl} (56%) create mode 100644 bs_cli/dist/adbs_cli-1.2.0.tar.gz diff --git a/bs_cli/adbs_cli/entry_point_commands.py b/bs_cli/adbs_cli/entry_point_commands.py index 435d450..43e8ec3 100644 --- a/bs_cli/adbs_cli/entry_point_commands.py +++ b/bs_cli/adbs_cli/entry_point_commands.py @@ -225,6 +225,23 @@ def configure_user(): click.echo(f"** Successfully added to {conf_file} **") click.echo(f"Please source {conf_file} or reload your shell to apply changes.") + # Ensure ~/.bashrc sources ~/.profile.d/*.conf (required on SLAC S3DF) + bashrc_path = os.path.expanduser("~/.bashrc") + profile_d_snippet = ( + '\n# SLAC S3DF - source all files under ~/.profile.d\n' + 'if [[ -e ~/.profile.d && -n "$(ls -A ~/.profile.d/)" ]]; then\n' + ' source <(cat $(find -L ~/.profile.d -name \'*.conf\' | sort))\n' + 'fi\n' + ) + bashrc_has_snippet = False + if os.path.exists(bashrc_path): + with open(bashrc_path, "r") as f: + bashrc_has_snippet = "source <(cat $(find -L ~/.profile.d" in f.read() + if not bashrc_has_snippet: + with open(bashrc_path, "a") as f: + f.write(profile_d_snippet) + click.echo(f"** Added ~/.profile.d sourcing block to {bashrc_path} **") + @click.command() @click.option("-c", "--component", required=False, help="Component Name") @click.option("-b", "--branch", required=False, help="Branch Name") diff --git a/bs_cli/dist/adbs_cli-1.1.12.tar.gz b/bs_cli/dist/adbs_cli-1.1.12.tar.gz deleted file mode 100644 index e55e1210101927331762dd8c44e6f6b033658f3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25070 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%0DDD=@Y_hpjM9}j5Nl&TMi;6A&WWH(`ruEoZm`v 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 delta 10764 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 XF-`t4S#q5X9!v@t5RjVrzjXft%rXEf diff --git a/bs_cli/dist/adbs_cli-1.2.0.tar.gz b/bs_cli/dist/adbs_cli-1.2.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..643f6e170da3c57fb2325d93f7b5b8519aff17e5 GIT binary patch literal 25302 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 X)vfOTx9ooidJ7^|OnQOiM1cD*D| Date: Mon, 30 Mar 2026 16:29:10 -0700 Subject: [PATCH 6/6] Updated entry point command to show deployment status for github for other apps not just pydm --- bs_cli/adbs_cli/entry_point_commands.py | 4 +- bs_cli/dist/adbs_cli-1.2.0-py3-none-any.whl | Bin 27605 -> 27632 bytes bs_cli/dist/adbs_cli-1.2.0.tar.gz | Bin 25302 -> 25322 bytes examples/hla_config.yaml | 9 ++++ ...fig.yml => ioc_multiple_build_config.yaml} | 0 examples/pydm_deploy.yml | 43 ------------------ examples/tools_config.yaml | 9 ++++ 7 files changed, 20 insertions(+), 45 deletions(-) create mode 100644 examples/hla_config.yaml rename examples/{ioc_multiple_build_config.yml => ioc_multiple_build_config.yaml} (100%) delete mode 100644 examples/pydm_deploy.yml create mode 100644 examples/tools_config.yaml diff --git a/bs_cli/adbs_cli/entry_point_commands.py b/bs_cli/adbs_cli/entry_point_commands.py index 43e8ec3..5e7aae2 100644 --- a/bs_cli/adbs_cli/entry_point_commands.py +++ b/bs_cli/adbs_cli/entry_point_commands.py @@ -711,7 +711,7 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: except Exception: pass - if (deployment_type == 'pydm'): # add github deployment status in progress + if (deployment_type == 'pydm' or deployment_type == 'generic'): # add github deployment status in progress for all except ioc for now deployment_status_request = Request(Component(component), Api.BACKEND) deployment_status_request.add_to_payload("name", deployment_request.component.name) deployment_status_request.add_to_payload("tag", tag) @@ -735,7 +735,7 @@ def deploy(component: str, facility: str, test: bool, ioc: str, tag: str, list: generate_deployment_report(file_content, deployment_request.component.name, tag) click.echo(f"== ADBS == Complete, log for details - {elog_url}") - if (deployment_type == 'pydm'): # add github deployment status success + if (deployment_type != 'ioc' or deployment_type == 'generic'): # add github deployment status success for all except ioc for now deployment_status_request.add_to_payload("status", "SUCCESS") deployment_status_request.add_to_payload("logUrl", elog_url) for facility in user_specified_facilities: diff --git a/bs_cli/dist/adbs_cli-1.2.0-py3-none-any.whl b/bs_cli/dist/adbs_cli-1.2.0-py3-none-any.whl index 075d441467774b24d10462a1037413dd0511020e..1267332133d24076a38a2f38ff6a2e3c60f06e8e 100644 GIT binary patch delta 10083 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 delta 10085 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 diff --git a/examples/hla_config.yaml b/examples/hla_config.yaml new file mode 100644 index 0000000..e0882e8 --- /dev/null +++ b/examples/hla_config.yaml @@ -0,0 +1,9 @@ +# Example config.yaml for a HLA application +repo: slac-devices +organization: slaclab +url: https://github.com/slaclab/slac-devices +description: Repository for accelerator devices used in high level applications (HLA). + +# Deployment playbook +deploy: + playbook: hla_module/hla_deploy.yml diff --git a/examples/ioc_multiple_build_config.yml b/examples/ioc_multiple_build_config.yaml similarity index 100% rename from examples/ioc_multiple_build_config.yml rename to examples/ioc_multiple_build_config.yaml diff --git a/examples/pydm_deploy.yml b/examples/pydm_deploy.yml deleted file mode 100644 index 722c115..0000000 --- a/examples/pydm_deploy.yml +++ /dev/null @@ -1,43 +0,0 @@ -on: - workflow_dispatch: - inputs: - deploy_to_dev: - description: 'DEV' - required: false - type: boolean - default: false - deploy_to_lcls: - description: 'LCLS' - required: false - type: boolean - default: false - deploy_to_facet: - description: 'FACET' - required: false - type: boolean - default: false - deploy_to_testfac: - description: 'TESTFAC' - required: false - type: boolean - default: false - tag: - description: 'Tag to deploy' - required: true - type: string - -permissions: - deployments: write - contents: read - actions: read - -jobs: - deploy: - uses: ad-build-test/build-system-playbooks/.github/workflows/request-deployment.yml@main - with: - deploy_to_dev: ${{ inputs.deploy_to_dev }} - deploy_to_lcls: ${{ inputs.deploy_to_lcls }} - deploy_to_facet: ${{ inputs.deploy_to_facet }} - deploy_to_testfac: ${{ inputs.deploy_to_testfac }} - tag: ${{ inputs.tag }} - deployment_type: 'pydm' \ No newline at end of file diff --git a/examples/tools_config.yaml b/examples/tools_config.yaml new file mode 100644 index 0000000..a3074fe --- /dev/null +++ b/examples/tools_config.yaml @@ -0,0 +1,9 @@ +# Example config.yaml for a TOOLS application +repo: mc-tools-motion +organization: slaclab +url: https://github.com/slaclab/mc-tools-motion +description: mc-tools + +# Deployment playbook +deploy: + playbook: tools_module/tools_deploy.yml