From 84f8b6258246409a24d24f9f9695a035c73d439f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ad=C3=A1n?= <57923734+ColourblindGuy@users.noreply.github.com> Date: Mon, 23 Mar 2026 22:32:27 -0400 Subject: [PATCH 01/22] Fix formatting in README.md description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9aa5db9..071f79a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # rt_deploy -POC to automate the deploy of new versions of RTEXEs on RT Targets using Github runners (And source control for regressions)... +POC to automate the deploy of new versions of RTEXEs on RT Targets using Github runners (And source control for regressions)...... From 1960e6088e3c565b3ec39e7846c3cdd3eca57a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ad=C3=A1n?= <57923734+ColourblindGuy@users.noreply.github.com> Date: Mon, 23 Mar 2026 22:37:12 -0400 Subject: [PATCH 02/22] Change runner from 'garbanzo' to 'self-hosted' --- .github/workflows/deploy-rt.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-rt.yml b/.github/workflows/deploy-rt.yml index 417c49d..62d1f10 100644 --- a/.github/workflows/deploy-rt.yml +++ b/.github/workflows/deploy-rt.yml @@ -7,7 +7,7 @@ on: jobs: deploy: - runs-on: garbanzo + runs-on: self-hosted steps: - name: Checkout repository @@ -30,4 +30,4 @@ jobs: - name: Notify on failure if: failure() - run: echo "Deployment failed — check logs above." \ No newline at end of file + run: echo "Deployment failed — check logs above." From 35e0f9190102f92893b2d85568299c9bd9bd6c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ad=C3=A1n?= <57923734+ColourblindGuy@users.noreply.github.com> Date: Mon, 23 Mar 2026 22:43:15 -0400 Subject: [PATCH 03/22] Fix typo in README description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 071f79a..237e33e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # rt_deploy -POC to automate the deploy of new versions of RTEXEs on RT Targets using Github runners (And source control for regressions)...... +POC to automate the deploy of new versions of RTEXEs on RT Targets using Github runners (And source control for regressions)......... From d72dc3f3f36f086bdfb9df6cdb0c6decfe115b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ad=C3=A1n?= <57923734+ColourblindGuy@users.noreply.github.com> Date: Mon, 23 Mar 2026 22:45:20 -0400 Subject: [PATCH 04/22] Change deployment script from deploy_rt.py to deploy.py --- .github/workflows/deploy-rt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-rt.yml b/.github/workflows/deploy-rt.yml index 62d1f10..c6698b4 100644 --- a/.github/workflows/deploy-rt.yml +++ b/.github/workflows/deploy-rt.yml @@ -26,7 +26,7 @@ jobs: RT_TARGET_IP: ${{ secrets.RT_TARGET_IP }} RT_FTP_USER: ${{ secrets.RT_FTP_USER }} RT_FTP_PASS: ${{ secrets.RT_FTP_PASS }} - run: python scripts/deploy_rt.py + run: python scripts/deploy.py - name: Notify on failure if: failure() From 61ccc39471066b6ff87bb4ae62b3a5e98351e167 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:03:49 -0400 Subject: [PATCH 05/22] Update remote path for MyApp.rtexe deployment --- scripts/deploy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index bcf0d04..ae18552 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -10,7 +10,7 @@ RT_PASS = os.environ["RT_FTP_PASS"] RTEXE_LOCAL = Path("releases/MyApp.rtexe") # adjust to your file path -RTEXE_REMOTE = "/ni-rt/startup/MyApp.rtexe" # standard NI RT deploy path +RTEXE_REMOTE = "/home/lvuser/natinst/bin/MyApp.rtexe" # standard NI RT deploy path def ftp_upload(): print(f"Connecting to {RT_IP} via FTP...") @@ -46,7 +46,7 @@ def wait_for_target(timeout=90): def verify_version(): # Read a version file you write from your RT app, or check a known file timestamp with ftplib.FTP(RT_IP, RT_USER, RT_PASS) as ftp: - files = ftp.nlst("/ni-rt/startup/") + files = ftp.nlst("/home/lvuser/natinst/bin") if "MyApp.rtexe" in [f.split("/")[-1] for f in files]: print("Verification passed: RTEXE present on target.") return True @@ -62,4 +62,4 @@ def verify_version(): ok = verify_version() if not ok: sys.exit(1) - print("Deployment successful.") \ No newline at end of file + print("Deployment successful.") From c48fd4af53865c1a4ef26e83f13aefbeca34ee29 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:08:55 -0400 Subject: [PATCH 06/22] Enable PowerShell script execution in workflow --- .github/workflows/deploy-rt.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/deploy-rt.yml b/.github/workflows/deploy-rt.yml index c6698b4..9bf5148 100644 --- a/.github/workflows/deploy-rt.yml +++ b/.github/workflows/deploy-rt.yml @@ -13,6 +13,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Enable PowerShell scripts + run: Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process + shell: pwsh + - name: Set up Python uses: actions/setup-python@v5 with: From 493abf3aa2f5c903172a781cfa5f76604fbc1fab Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:15:36 -0400 Subject: [PATCH 07/22] Remove PowerShell script enabling step Removed PowerShell script execution policy step from workflow. --- .github/workflows/deploy-rt.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/deploy-rt.yml b/.github/workflows/deploy-rt.yml index 9bf5148..c6698b4 100644 --- a/.github/workflows/deploy-rt.yml +++ b/.github/workflows/deploy-rt.yml @@ -13,10 +13,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Enable PowerShell scripts - run: Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process - shell: pwsh - - name: Set up Python uses: actions/setup-python@v5 with: From d6726e00a72316601e15dc1289692b1d5e64dfc3 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:25:24 -0400 Subject: [PATCH 08/22] Switch from FTP to SCP for file upload Replaced FTP upload with SCP upload using paramiko. Updated version verification and target waiting methods to use SSH. --- scripts/deploy.py | 82 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index ae18552..702fab8 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -1,65 +1,95 @@ -import ftplib import os import sys import time import requests +import paramiko from pathlib import Path RT_IP = os.environ["RT_TARGET_IP"] -RT_USER = os.environ["RT_FTP_USER"] +RT_USER = os.environ["RT_FTP_USER"] # same user (lvuser) RT_PASS = os.environ["RT_FTP_PASS"] -RTEXE_LOCAL = Path("releases/MyApp.rtexe") # adjust to your file path -RTEXE_REMOTE = "/home/lvuser/natinst/bin/MyApp.rtexe" # standard NI RT deploy path +RTEXE_LOCAL = Path("releases/MyApp.rtexe") +RTEXE_REMOTE = "/home/lvuser/natinst/bin/MyApp.rtexe" + + +def scp_upload(): + print(f"Connecting to {RT_IP} via SFTP...") + + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + ssh.connect( + RT_IP, + username=RT_USER, + password=RT_PASS, + look_for_keys=False, + allow_agent=False + ) + + sftp = ssh.open_sftp() + sftp.put(RTEXE_LOCAL, RTEXE_REMOTE) # upload file + + sftp.close() + ssh.close() + print("SCP upload complete.") -def ftp_upload(): - print(f"Connecting to {RT_IP} via FTP...") - with ftplib.FTP(RT_IP, RT_USER, RT_PASS) as ftp: - ftp.set_pasv(True) - with open(RTEXE_LOCAL, "rb") as f: - ftp.storbinary(f"STOR {RTEXE_REMOTE}", f) - print("Upload complete.") def reboot_target(): - # NI Web-based Configuration and Monitoring (WBCM) REST API url = f"http://{RT_IP}/nisysapi/server" payload = {"Function": "Restart", "Params": {"objSelfURI": f"nisysapi://{RT_IP}"}} print("Sending reboot command...") try: requests.post(url, json=payload, timeout=5) except requests.exceptions.ReadTimeout: - pass # timeout is expected — target is rebooting + pass # NI reboots cause immediate disconnect + def wait_for_target(timeout=90): - print("Waiting for target to come back online...") + print("Waiting for target to come online...") deadline = time.time() + timeout + while time.time() < deadline: try: - ftplib.FTP(RT_IP, RT_USER, RT_PASS).quit() + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(RT_IP, username=RT_USER, password=RT_PASS, timeout=3) + ssh.close() print("Target is back online.") return True except Exception: time.sleep(5) + print("ERROR: Target did not come back within timeout.") return False + def verify_version(): - # Read a version file you write from your RT app, or check a known file timestamp - with ftplib.FTP(RT_IP, RT_USER, RT_PASS) as ftp: - files = ftp.nlst("/home/lvuser/natinst/bin") - if "MyApp.rtexe" in [f.split("/")[-1] for f in files]: - print("Verification passed: RTEXE present on target.") - return True + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(RT_IP, username=RT_USER, password=RT_PASS) + + sftp = ssh.open_sftp() + files = sftp.listdir("/home/lvuser/natinst/bin") + sftp.close() + ssh.close() + + if "MyApp.rtexe" in files: + print("Verification passed: RTEXE present on target.") + return True + print("Verification FAILED: RTEXE not found on target.") return False + if __name__ == "__main__": - ftp_upload() + scp_upload() reboot_target() - ok = wait_for_target() - if not ok: + + if not wait_for_target(): sys.exit(1) - ok = verify_version() - if not ok: + + if not verify_version(): sys.exit(1) + print("Deployment successful.") From cd4b7692820556f31b4716bf10446d4969afb882 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:28:17 -0400 Subject: [PATCH 09/22] Add paramiko to dependencies installation --- .github/workflows/deploy-rt.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-rt.yml b/.github/workflows/deploy-rt.yml index c6698b4..32cfab8 100644 --- a/.github/workflows/deploy-rt.yml +++ b/.github/workflows/deploy-rt.yml @@ -19,7 +19,7 @@ jobs: python-version: "3.11" - name: Install dependencies - run: pip install requests + run: pip install requests paramiko - name: Deploy RTEXE to target env: From 344e24b475596c02f9ac96bb74c8eca0b322ec95 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:33:41 -0400 Subject: [PATCH 10/22] Implement SSH reboot functionality Added a function to reboot the target via SSH and updated the main execution flow to use this new function. --- scripts/deploy.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index 702fab8..5e0f705 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -44,6 +44,30 @@ def reboot_target(): except requests.exceptions.ReadTimeout: pass # NI reboots cause immediate disconnect +def reboot_target_via_ssh(): + print("Rebooting target via SSH...") + + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + ssh.connect( + RT_IP, + username=RT_USER, + password=RT_PASS, + look_for_keys=False, + allow_agent=False + ) + + try: + # Run reboot command (NI RT allows this without sudo) + ssh.exec_command("/sbin/reboot") + print("Reboot command sent.") + except Exception as e: + print(f"Ignoring SSH error during reboot: {e}") + finally: + ssh.close() + + def wait_for_target(timeout=90): print("Waiting for target to come online...") @@ -84,7 +108,7 @@ def verify_version(): if __name__ == "__main__": scp_upload() - reboot_target() + reboot_target_via_ssh() if not wait_for_target(): sys.exit(1) From e6e7a82abfe5d88da76dc50ac52fd0e9e309a59c Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:39:10 -0400 Subject: [PATCH 11/22] Add sleep before waiting for target --- scripts/deploy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/deploy.py b/scripts/deploy.py index 5e0f705..ee3725f 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -66,6 +66,7 @@ def reboot_target_via_ssh(): print(f"Ignoring SSH error during reboot: {e}") finally: ssh.close() + time.sleep(5) From 53bf633910e945d2c8acc2ff52070f284ec3b643 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:47:02 -0400 Subject: [PATCH 12/22] Implement SFTP directory upload and cleanup Added functions to upload a directory via SFTP and clear remote folders before deployment. --- scripts/deploy.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index ee3725f..f1fcb55 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -35,6 +35,78 @@ def scp_upload(): print("SCP upload complete.") +def upload_directory_sftp(sftp, local_path: Path, remote_path: str): + """Recursively upload a directory via SFTP.""" + + # Ensure remote directory exists + try: + sftp.stat(remote_path) + except FileNotFoundError: + print(f"Creating remote folder: {remote_path}") + sftp.mkdir(remote_path) + + for item in local_path.iterdir(): + remote_item = f"{remote_path}/{item.name}" + + if item.is_dir(): + upload_directory_sftp(sftp, item, remote_item) + else: + print(f"Uploading file: {item} -> {remote_item}") + sftp.put(str(item), remote_item) + + + +def clear_remote_folder(sftp, remote_path): + """Delete all files/directories inside the remote folder.""" + + for item in sftp.listdir_attr(remote_path): + rpath = f"{remote_path}/{item.filename}" + + if paramiko.SFTPAttributes.S_IFDIR & item.st_mode: + # It's a directory + clear_remote_folder(sftp, rpath) + print(f"Removing remote folder: {rpath}") + sftp.rmdir(rpath) + else: + print(f"Removing remote file: {rpath}") + sftp.remove(rpath) + + + +def deploy_bin_folder(): + print(f"Deploying full bin folder to {RT_IP}...") + + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect( + RT_IP, + username=RT_USER, + password=RT_PASS, + look_for_keys=False, + allow_agent=False + ) + + sftp = ssh.open_sftp() + + # Ensure base folder exists + try: + sftp.stat(BIN_REMOTE) + except: + print(f"Creating base remote folder: {BIN_REMOTE}") + sftp.mkdir(BIN_REMOTE) + + # Optional cleanup + print("Clearing remote bin folder...") + clear_remote_folder(sftp, BIN_REMOTE) + + print("Uploading bin folder...") + upload_directory_sftp(sftp, BIN_LOCAL, BIN_REMOTE) + + sftp.close() + ssh.close() + print("✅ Bin folder deployment completed.") + + def reboot_target(): url = f"http://{RT_IP}/nisysapi/server" payload = {"Function": "Restart", "Params": {"objSelfURI": f"nisysapi://{RT_IP}"}} @@ -108,7 +180,7 @@ def verify_version(): if __name__ == "__main__": - scp_upload() + deploy_bin_folder() reboot_target_via_ssh() if not wait_for_target(): From 66c4e853b739e0a26b3dd53b49b302fdd0500e25 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:52:03 -0400 Subject: [PATCH 13/22] Enhance deploy.py with logging and backup features Refactor deploy script to improve logging and backup functionality. --- scripts/deploy.py | 196 +++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 108 deletions(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index f1fcb55..34d7034 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -4,189 +4,169 @@ import requests import paramiko from pathlib import Path +from datetime import datetime RT_IP = os.environ["RT_TARGET_IP"] -RT_USER = os.environ["RT_FTP_USER"] # same user (lvuser) +RT_USER = os.environ["RT_FTP_USER"] RT_PASS = os.environ["RT_FTP_PASS"] -RTEXE_LOCAL = Path("releases/MyApp.rtexe") -RTEXE_REMOTE = "/home/lvuser/natinst/bin/MyApp.rtexe" +BIN_LOCAL = Path("releases/bin") +BIN_REMOTE = "/home/lvuser/natinst/bin" +BACKUP_ROOT = "/home/lvuser/deploy_backups" -def scp_upload(): - print(f"Connecting to {RT_IP} via SFTP...") +def log(msg): + print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}") + +def open_ssh(): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect( RT_IP, username=RT_USER, password=RT_PASS, look_for_keys=False, - allow_agent=False + allow_agent=False, + timeout=5 ) - - sftp = ssh.open_sftp() - sftp.put(RTEXE_LOCAL, RTEXE_REMOTE) # upload file - - sftp.close() - ssh.close() - print("SCP upload complete.") + return ssh def upload_directory_sftp(sftp, local_path: Path, remote_path: str): - """Recursively upload a directory via SFTP.""" - - # Ensure remote directory exists try: sftp.stat(remote_path) except FileNotFoundError: - print(f"Creating remote folder: {remote_path}") + log(f"Creating remote directory: {remote_path}") sftp.mkdir(remote_path) for item in local_path.iterdir(): remote_item = f"{remote_path}/{item.name}" - if item.is_dir(): upload_directory_sftp(sftp, item, remote_item) else: - print(f"Uploading file: {item} -> {remote_item}") + log(f"Uploading file: {item} → {remote_item}") sftp.put(str(item), remote_item) def clear_remote_folder(sftp, remote_path): - """Delete all files/directories inside the remote folder.""" + for attr in sftp.listdir_attr(remote_path): + rpath = f"{remote_path}/{attr.filename}" - for item in sftp.listdir_attr(remote_path): - rpath = f"{remote_path}/{item.filename}" - - if paramiko.SFTPAttributes.S_IFDIR & item.st_mode: - # It's a directory + if attr.st_mode & 0o40000: # directory bit clear_remote_folder(sftp, rpath) - print(f"Removing remote folder: {rpath}") + log(f"Removing folder: {rpath}") sftp.rmdir(rpath) else: - print(f"Removing remote file: {rpath}") + log(f"Removing file: {rpath}") sftp.remove(rpath) -def deploy_bin_folder(): - print(f"Deploying full bin folder to {RT_IP}...") - - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect( - RT_IP, - username=RT_USER, - password=RT_PASS, - look_for_keys=False, - allow_agent=False - ) +def backup_remote_bin(): + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + backup_dir = f"{BACKUP_ROOT}/bin_{timestamp}" + ssh = open_ssh() sftp = ssh.open_sftp() - # Ensure base folder exists + # Ensure backup root exists try: - sftp.stat(BIN_REMOTE) - except: - print(f"Creating base remote folder: {BIN_REMOTE}") - sftp.mkdir(BIN_REMOTE) + sftp.stat(BACKUP_ROOT) + except FileNotFoundError: + log(f"Creating backup root: {BACKUP_ROOT}") + sftp.mkdir(BACKUP_ROOT) - # Optional cleanup - print("Clearing remote bin folder...") - clear_remote_folder(sftp, BIN_REMOTE) + log(f"Creating backup: {backup_dir}") + sftp.mkdir(backup_dir) - print("Uploading bin folder...") - upload_directory_sftp(sftp, BIN_LOCAL, BIN_REMOTE) + def recursive_copy(remote_src, remote_dst): + sftp.mkdir(remote_dst) + for attr in sftp.listdir_attr(remote_src): + src = f"{remote_src}/{attr.filename}" + dst = f"{remote_dst}/{attr.filename}" + + if attr.st_mode & 0o40000: # directory + recursive_copy(src, dst) + else: + sftp.get(src, f"/tmp/{attr.filename}") # temp local copy + sftp.put(f"/tmp/{attr.filename}", dst) + + recursive_copy(BIN_REMOTE, backup_dir) - sftp.close() ssh.close() - print("✅ Bin folder deployment completed.") + return backup_dir -def reboot_target(): - url = f"http://{RT_IP}/nisysapi/server" - payload = {"Function": "Restart", "Params": {"objSelfURI": f"nisysapi://{RT_IP}"}} - print("Sending reboot command...") - try: - requests.post(url, json=payload, timeout=5) - except requests.exceptions.ReadTimeout: - pass # NI reboots cause immediate disconnect -def reboot_target_via_ssh(): - print("Rebooting target via SSH...") - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +def rollback_from_backup(backup_dir): + log("ROLLBACK: Restoring previous bin folder...") + ssh = open_ssh() + sftp = ssh.open_sftp() + + clear_remote_folder(sftp, BIN_REMOTE) + upload_directory_sftp(sftp, Path(f"/tmp/rollback"), BIN_REMOTE) + + log("Rollback completed.") + + sftp.close() + ssh.close() + + - ssh.connect( - RT_IP, - username=RT_USER, - password=RT_PASS, - look_for_keys=False, - allow_agent=False - ) +def reboot_target_via_ssh(): + log("Rebooting target via SSH...") + ssh = open_ssh() try: - # Run reboot command (NI RT allows this without sudo) ssh.exec_command("/sbin/reboot") - print("Reboot command sent.") + log("Reboot command sent.") except Exception as e: - print(f"Ignoring SSH error during reboot: {e}") + log(f"Ignoring reboot disconnect: {e}") finally: ssh.close() - time.sleep(5) - - -def wait_for_target(timeout=90): - print("Waiting for target to come online...") +def wait_for_shutdown(timeout=30): + log("Waiting for target to shut down...") deadline = time.time() + timeout + while time.time() < deadline: + try: + ssh = open_ssh() + ssh.close() + time.sleep(2) + except Exception: + log("✅ Target offline.") + return True + log("WARNING: Target never appeared offline.") + return False +def wait_for_boot(timeout=90): + log("Waiting for target to boot...") + deadline = time.time() + timeout while time.time() < deadline: try: - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect(RT_IP, username=RT_USER, password=RT_PASS, timeout=3) + ssh = open_ssh() ssh.close() - print("Target is back online.") + log("✅ Target online.") return True except Exception: time.sleep(5) - - print("ERROR: Target did not come back within timeout.") + log("❌ Boot timeout!") return False -def verify_version(): - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect(RT_IP, username=RT_USER, password=RT_PASS) - - sftp = ssh.open_sftp() - files = sftp.listdir("/home/lvuser/natinst/bin") - sftp.close() - ssh.close() - - if "MyApp.rtexe" in files: - print("Verification passed: RTEXE present on target.") - return True - - print("Verification FAILED: RTEXE not found on target.") - return False - if __name__ == "__main__": - deploy_bin_folder() - reboot_target_via_ssh() + backup_dir = deploy_bin_folder() - if not wait_for_target(): - sys.exit(1) + reboot_target_via_ssh() + wait_for_shutdown() - if not verify_version(): + if not wait_for_boot(): + log("Boot failed, rolling back...") + rollback_from_backup(backup_dir) sys.exit(1) - print("Deployment successful.") + log("✅ Deployment successful.") From e318cf9f5a43e61d6e440b8e94b2acbd90354f19 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:53:10 -0400 Subject: [PATCH 14/22] Create text.txt --- releases/bin/text.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 releases/bin/text.txt diff --git a/releases/bin/text.txt b/releases/bin/text.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/releases/bin/text.txt @@ -0,0 +1 @@ + From 539769b0f96c5cadec28f9aaed969687d846eb42 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:56:47 -0400 Subject: [PATCH 15/22] Implement deploy_bin_folder for bin deployment Added deploy_bin_folder function to handle deployment of the bin folder, including backup and rollback functionality. --- scripts/deploy.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/scripts/deploy.py b/scripts/deploy.py index 34d7034..fb5533a 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -116,6 +116,39 @@ def rollback_from_backup(backup_dir): +def deploy_bin_folder(): + log(f"Deploying full bin folder to {RT_IP}...") + + ssh = open_ssh() + sftp = ssh.open_sftp() + + # Backup + log("Creating backup of current /bin folder...") + backup_dir = backup_remote_bin() + + try: + log("Clearing /bin folder on target...") + clear_remote_folder(sftp, BIN_REMOTE) + + log("Uploading new bin folder...") + upload_directory_sftp(sftp, BIN_LOCAL, BIN_REMOTE) + + log("✅ Deployment upload completed.") + sftp.close() + ssh.close() + + return backup_dir + + except Exception as e: + log(f"❌ ERROR during upload: {e}") + log("Attempting rollback...") + + rollback_from_backup(backup_dir) + + sys.exit(1) +`` + + def reboot_target_via_ssh(): log("Rebooting target via SSH...") From bfcb64fabca2faba20ee3e4accfd990771aa942f Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 10:57:40 -0400 Subject: [PATCH 16/22] Remove unnecessary backticks from deploy.py --- scripts/deploy.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index fb5533a..428a023 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -146,7 +146,6 @@ def deploy_bin_folder(): rollback_from_backup(backup_dir) sys.exit(1) -`` From 1b68b0bd991bfc2dc2645371288ef482669402a1 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 11:02:36 -0400 Subject: [PATCH 17/22] Implement remote backup and deployment enhancements Added functions to ensure remote directory creation and recursive copying for backup operations. Enhanced deployment process with logging and error handling. --- scripts/deploy.py | 84 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index 428a023..e6e9e9a 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -15,6 +15,64 @@ BACKUP_ROOT = "/home/lvuser/deploy_backups" + +def ensure_remote_dir(sftp, path): + """Create remote directory tree if not exists.""" + parts = path.strip("/").split("/") + cur = "" + for part in parts: + cur = f"{cur}/{part}" if cur else f"/{part}" + try: + sftp.stat(cur) + except FileNotFoundError: + log(f"Creating remote directory: {cur}") + sftp.mkdir(cur) + + +def recursive_remote_copy(sftp, src, dst): + """Copy a remote folder to another remote folder recursively.""" + ensure_remote_dir(sftp, dst) + + for attr in sftp.listdir_attr(src): + src_item = f"{src}/{attr.filename}" + dst_item = f"{dst}/{attr.filename}" + + # Directory? + if attr.st_mode & 0o40000: + recursive_remote_copy(sftp, src_item, dst_item) + else: + log(f"Backing up file: {src_item} → {dst_item}") + with sftp.open(src_item, "rb") as fsrc: + data = fsrc.read() + with sftp.open(dst_item, "wb") as fdst: + fdst.write(data) + + + +def backup_remote_bin(): + ssh = open_ssh() + sftp = ssh.open_sftp() + + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + backup_dir = f"{BACKUP_ROOT}/bin_{timestamp}" + + log(f"Ensuring backup root exists: {BACKUP_ROOT}") + ensure_remote_dir(sftp, BACKUP_ROOT) + + log(f"Creating backup directory: {backup_dir}") + ensure_remote_dir(sftp, backup_dir) + + log("Starting recursive backup...") + recursive_remote_copy(sftp, BIN_REMOTE, backup_dir) + + sftp.close() + ssh.close() + + log(f"✅ Backup complete: {backup_dir}") + return backup_dir + + + def log(msg): print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}") @@ -64,6 +122,8 @@ def clear_remote_folder(sftp, remote_path): + + def backup_remote_bin(): timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") backup_dir = f"{BACKUP_ROOT}/bin_{timestamp}" @@ -191,14 +251,30 @@ def wait_for_boot(timeout=90): if __name__ == "__main__": - backup_dir = deploy_bin_folder() + log("=== Starting RT Deployment ===") + # 1. Deploy with backup + try: + backup_dir = deploy_bin_folder() + except Exception as e: + log(f"❌ Deployment failed before reboot. Error: {e}") + sys.exit(1) + + # 2. Reboot reboot_target_via_ssh() - wait_for_shutdown() + # 3. Wait for shutdown + if not wait_for_shutdown(): + log("⚠️ WARNING: Target did not go offline. Attempting rollback...") + rollback_from_backup(backup_dir) + sys.exit(1) + + # 4. Wait for boot if not wait_for_boot(): - log("Boot failed, rolling back...") + log("❌ ERROR: Target did not come back online. Rolling back...") rollback_from_backup(backup_dir) sys.exit(1) - log("✅ Deployment successful.") + # 5. Optional: verify (can be simple ping, file check, etc.) + # For now we trust the boot. + log("✅ Deployment successful. Target restarted and reachable.") From cfe887e09864d2c67af070d798ef96a1ce6822c4 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 11:05:21 -0400 Subject: [PATCH 18/22] Enhance deploy.py with better logging and SSH handling Refactor deploy.py for improved logging and structure. --- scripts/deploy.py | 285 ++++++++++++++++++++++++---------------------- 1 file changed, 152 insertions(+), 133 deletions(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index e6e9e9a..095a63d 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -1,53 +1,96 @@ import os import sys import time -import requests import paramiko from pathlib import Path from datetime import datetime +# --------------------------------------------------------------------------- +# Configuration +# --------------------------------------------------------------------------- + RT_IP = os.environ["RT_TARGET_IP"] RT_USER = os.environ["RT_FTP_USER"] RT_PASS = os.environ["RT_FTP_PASS"] -BIN_LOCAL = Path("releases/bin") -BIN_REMOTE = "/home/lvuser/natinst/bin" -BACKUP_ROOT = "/home/lvuser/deploy_backups" +BIN_LOCAL = Path("releases/bin") +BIN_REMOTE = "/home/lvuser/natinst/bin" +BACKUP_ROOT = "/home/lvuser/deploy_backups" + + +# --------------------------------------------------------------------------- +# Logging helper +# --------------------------------------------------------------------------- + +def log(msg): + print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}") +# --------------------------------------------------------------------------- +# SSH helpers +# --------------------------------------------------------------------------- + +def open_ssh(): + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect( + RT_IP, + username=RT_USER, + password=RT_PASS, + look_for_keys=False, + allow_agent=False, + timeout=5 + ) + return ssh + + +# --------------------------------------------------------------------------- +# Remote directory helpers +# --------------------------------------------------------------------------- def ensure_remote_dir(sftp, path): - """Create remote directory tree if not exists.""" + """Create remote directory tree if needed.""" + if path == "/" or path == "": + return + parts = path.strip("/").split("/") - cur = "" + current = "" for part in parts: - cur = f"{cur}/{part}" if cur else f"/{part}" + current = f"/{part}" if current == "" else f"{current}/{part}" try: - sftp.stat(cur) + sftp.stat(current) except FileNotFoundError: - log(f"Creating remote directory: {cur}") - sftp.mkdir(cur) + log(f"Creating remote directory: {current}") + sftp.mkdir(current) +# --------------------------------------------------------------------------- +# Recursive remote copy (remote -> remote) +# --------------------------------------------------------------------------- + def recursive_remote_copy(sftp, src, dst): - """Copy a remote folder to another remote folder recursively.""" + """Copy a remote directory tree to another remote directory.""" ensure_remote_dir(sftp, dst) for attr in sftp.listdir_attr(src): src_item = f"{src}/{attr.filename}" dst_item = f"{dst}/{attr.filename}" - # Directory? - if attr.st_mode & 0o40000: + is_dir = bool(attr.st_mode & 0o40000) + + if is_dir: recursive_remote_copy(sftp, src_item, dst_item) else: - log(f"Backing up file: {src_item} → {dst_item}") + log(f"Backing up file: {src_item} -> {dst_item}") with sftp.open(src_item, "rb") as fsrc: data = fsrc.read() with sftp.open(dst_item, "wb") as fdst: fdst.write(data) +# --------------------------------------------------------------------------- +# Backup +# --------------------------------------------------------------------------- def backup_remote_bin(): ssh = open_ssh() @@ -59,7 +102,7 @@ def backup_remote_bin(): log(f"Ensuring backup root exists: {BACKUP_ROOT}") ensure_remote_dir(sftp, BACKUP_ROOT) - log(f"Creating backup directory: {backup_dir}") + log(f"Creating backup folder: {backup_dir}") ensure_remote_dir(sftp, backup_dir) log("Starting recursive backup...") @@ -68,213 +111,189 @@ def backup_remote_bin(): sftp.close() ssh.close() - log(f"✅ Backup complete: {backup_dir}") + log(f"Backup completed: {backup_dir}") return backup_dir +# --------------------------------------------------------------------------- +# Recursive delete +# --------------------------------------------------------------------------- -def log(msg): - print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}") +def clear_remote_folder(sftp, remote_path): + """Delete all contents of remote folder.""" + for attr in sftp.listdir_attr(remote_path): + path = f"{remote_path}/{attr.filename}" + is_dir = bool(attr.st_mode & 0o40000) + if is_dir: + clear_remote_folder(sftp, path) + log(f"Removing folder: {path}") + sftp.rmdir(path) + else: + log(f"Removing file: {path}") + sftp.remove(path) -def open_ssh(): - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect( - RT_IP, - username=RT_USER, - password=RT_PASS, - look_for_keys=False, - allow_agent=False, - timeout=5 - ) - return ssh +# --------------------------------------------------------------------------- +# Upload local bin folder to remote +# --------------------------------------------------------------------------- -def upload_directory_sftp(sftp, local_path: Path, remote_path: str): - try: - sftp.stat(remote_path) - except FileNotFoundError: - log(f"Creating remote directory: {remote_path}") - sftp.mkdir(remote_path) +def upload_directory_sftp(sftp, local_path, remote_path): + ensure_remote_dir(sftp, remote_path) for item in local_path.iterdir(): - remote_item = f"{remote_path}/{item.name}" + dst = f"{remote_path}/{item.name}" if item.is_dir(): - upload_directory_sftp(sftp, item, remote_item) - else: - log(f"Uploading file: {item} → {remote_item}") - sftp.put(str(item), remote_item) - - - -def clear_remote_folder(sftp, remote_path): - for attr in sftp.listdir_attr(remote_path): - rpath = f"{remote_path}/{attr.filename}" - - if attr.st_mode & 0o40000: # directory bit - clear_remote_folder(sftp, rpath) - log(f"Removing folder: {rpath}") - sftp.rmdir(rpath) + upload_directory_sftp(sftp, item, dst) else: - log(f"Removing file: {rpath}") - sftp.remove(rpath) - + log(f"Uploading file: {item} -> {dst}") + sftp.put(str(item), dst) +# --------------------------------------------------------------------------- +# Deploy bin folder (includes backup and rollback) +# --------------------------------------------------------------------------- +def deploy_bin_folder(): + log(f"Deploying bin folder to {RT_IP}") -def backup_remote_bin(): - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - backup_dir = f"{BACKUP_ROOT}/bin_{timestamp}" + # 1. Backup + backup_dir = backup_remote_bin() + # 2. Upload new files ssh = open_ssh() sftp = ssh.open_sftp() - # Ensure backup root exists try: - sftp.stat(BACKUP_ROOT) - except FileNotFoundError: - log(f"Creating backup root: {BACKUP_ROOT}") - sftp.mkdir(BACKUP_ROOT) - - log(f"Creating backup: {backup_dir}") - sftp.mkdir(backup_dir) - - def recursive_copy(remote_src, remote_dst): - sftp.mkdir(remote_dst) - for attr in sftp.listdir_attr(remote_src): - src = f"{remote_src}/{attr.filename}" - dst = f"{remote_dst}/{attr.filename}" - - if attr.st_mode & 0o40000: # directory - recursive_copy(src, dst) - else: - sftp.get(src, f"/tmp/{attr.filename}") # temp local copy - sftp.put(f"/tmp/{attr.filename}", dst) + log("Clearing remote bin folder...") + clear_remote_folder(sftp, BIN_REMOTE) - recursive_copy(BIN_REMOTE, backup_dir) + log("Uploading new bin folder...") + upload_directory_sftp(sftp, BIN_LOCAL, BIN_REMOTE) - ssh.close() - return backup_dir + sftp.close() + ssh.close() + log("Upload completed successfully.") + return backup_dir + except Exception as e: + log(f"Upload failed: {e}") + log("Starting rollback...") + rollback_from_backup(backup_dir) + sys.exit(1) -def rollback_from_backup(backup_dir): - log("ROLLBACK: Restoring previous bin folder...") - ssh = open_ssh() - sftp = ssh.open_sftp() - clear_remote_folder(sftp, BIN_REMOTE) - upload_directory_sftp(sftp, Path(f"/tmp/rollback"), BIN_REMOTE) +# --------------------------------------------------------------------------- +# Rollback +# --------------------------------------------------------------------------- - log("Rollback completed.") +def recursive_restore_from_backup(sftp, src, dst): + ensure_remote_dir(sftp, dst) - sftp.close() - ssh.close() + for attr in sftp.listdir_attr(src): + src_item = f"{src}/{attr.filename}" + dst_item = f"{dst}/{attr.filename}" + is_dir = bool(attr.st_mode & 0o40000) + if is_dir: + recursive_restore_from_backup(sftp, src_item, dst_item) + else: + log(f"Restoring file: {src_item} -> {dst_item}") + with sftp.open(src_item, "rb") as fsrc: + data = fsrc.read() + with sftp.open(dst_item, "wb") as fdst: + fdst.write(data) -def deploy_bin_folder(): - log(f"Deploying full bin folder to {RT_IP}...") +def rollback_from_backup(backup_dir): + log("Rollback: restoring backup data") ssh = open_ssh() sftp = ssh.open_sftp() - # Backup - log("Creating backup of current /bin folder...") - backup_dir = backup_remote_bin() - - try: - log("Clearing /bin folder on target...") - clear_remote_folder(sftp, BIN_REMOTE) - - log("Uploading new bin folder...") - upload_directory_sftp(sftp, BIN_LOCAL, BIN_REMOTE) - - log("✅ Deployment upload completed.") - sftp.close() - ssh.close() - - return backup_dir - - except Exception as e: - log(f"❌ ERROR during upload: {e}") - log("Attempting rollback...") - - rollback_from_backup(backup_dir) + clear_remote_folder(sftp, BIN_REMOTE) + recursive_restore_from_backup(sftp, backup_dir, BIN_REMOTE) - sys.exit(1) + sftp.close() + ssh.close() + log("Rollback completed successfully.") +# --------------------------------------------------------------------------- +# Reboot + Wait Logic +# --------------------------------------------------------------------------- def reboot_target_via_ssh(): - log("Rebooting target via SSH...") + log("Sending reboot command via SSH...") ssh = open_ssh() try: ssh.exec_command("/sbin/reboot") log("Reboot command sent.") - except Exception as e: - log(f"Ignoring reboot disconnect: {e}") + except Exception: + log("Reboot disconnect occurred. This is normal.") finally: ssh.close() + def wait_for_shutdown(timeout=30): log("Waiting for target to shut down...") deadline = time.time() + timeout + while time.time() < deadline: try: ssh = open_ssh() ssh.close() time.sleep(2) except Exception: - log("✅ Target offline.") + log("Target is offline.") return True - log("WARNING: Target never appeared offline.") + + log("Warning: target never appeared to go offline.") return False + def wait_for_boot(timeout=90): - log("Waiting for target to boot...") + log("Waiting for target to come online...") deadline = time.time() + timeout + while time.time() < deadline: try: ssh = open_ssh() ssh.close() - log("✅ Target online.") + log("Target is online again.") return True except Exception: time.sleep(5) - log("❌ Boot timeout!") + + log("Error: target did not boot in time.") return False +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- if __name__ == "__main__": log("=== Starting RT Deployment ===") - # 1. Deploy with backup try: backup_dir = deploy_bin_folder() except Exception as e: - log(f"❌ Deployment failed before reboot. Error: {e}") + log(f"Deployment failed before reboot: {e}") sys.exit(1) - # 2. Reboot reboot_target_via_ssh() - # 3. Wait for shutdown if not wait_for_shutdown(): - log("⚠️ WARNING: Target did not go offline. Attempting rollback...") + log("Shutdown not confirmed. Rolling back.") rollback_from_backup(backup_dir) sys.exit(1) - # 4. Wait for boot if not wait_for_boot(): - log("❌ ERROR: Target did not come back online. Rolling back...") + log("Boot failure. Rolling back.") rollback_from_backup(backup_dir) sys.exit(1) - # 5. Optional: verify (can be simple ping, file check, etc.) - # For now we trust the boot. - log("✅ Deployment successful. Target restarted and reachable.") + log("Deployment completed successfully.") From d9c6782e5ed3e5e07fbf000e11fbbf515118357a Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 11:10:12 -0400 Subject: [PATCH 19/22] Add files via upload --- releases/bin/MyApp.aliases | 5 +++++ releases/bin/MyApp.rtexe | Bin 0 -> 5784 bytes releases/bin/startup.aliases | 5 +++++ releases/bin/startup.rtexe | Bin 0 -> 5784 bytes 4 files changed, 10 insertions(+) create mode 100644 releases/bin/MyApp.aliases create mode 100644 releases/bin/MyApp.rtexe create mode 100644 releases/bin/startup.aliases create mode 100644 releases/bin/startup.rtexe diff --git a/releases/bin/MyApp.aliases b/releases/bin/MyApp.aliases new file mode 100644 index 0000000..78aff81 --- /dev/null +++ b/releases/bin/MyApp.aliases @@ -0,0 +1,5 @@ +[My Computer] +My Computer="192.168.56.103" + +[RT CompactRIO Target] +RT CompactRIO Target="localhost" \ No newline at end of file diff --git a/releases/bin/MyApp.rtexe b/releases/bin/MyApp.rtexe new file mode 100644 index 0000000000000000000000000000000000000000..4876237d0f5fc6fc75e4fe89b78a678c506f5684 GIT binary patch literal 5784 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 literal 0 HcmV?d00001 diff --git a/releases/bin/startup.aliases b/releases/bin/startup.aliases new file mode 100644 index 0000000..78aff81 --- /dev/null +++ b/releases/bin/startup.aliases @@ -0,0 +1,5 @@ +[My Computer] +My Computer="192.168.56.103" + +[RT CompactRIO Target] +RT CompactRIO Target="localhost" \ No newline at end of file diff --git a/releases/bin/startup.rtexe b/releases/bin/startup.rtexe new file mode 100644 index 0000000000000000000000000000000000000000..4876237d0f5fc6fc75e4fe89b78a678c506f5684 GIT binary patch literal 5784 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 literal 0 HcmV?d00001 From a3017ec01b516e2999eaaf869fef8ab3a5e7c4bf Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 11:13:13 -0400 Subject: [PATCH 20/22] Delete releases/MyApp.rtexe --- releases/MyApp.rtexe | 1 - 1 file changed, 1 deletion(-) delete mode 100644 releases/MyApp.rtexe diff --git a/releases/MyApp.rtexe b/releases/MyApp.rtexe deleted file mode 100644 index 8b13789..0000000 --- a/releases/MyApp.rtexe +++ /dev/null @@ -1 +0,0 @@ - From 77900cca10b04bd1f624dcc09518a56d3446f019 Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 11:13:25 -0400 Subject: [PATCH 21/22] Delete releases/bin/MyApp.rtexe --- releases/bin/MyApp.rtexe | Bin 5784 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 releases/bin/MyApp.rtexe diff --git a/releases/bin/MyApp.rtexe b/releases/bin/MyApp.rtexe deleted file mode 100644 index 4876237d0f5fc6fc75e4fe89b78a678c506f5684..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5784 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 From 0d13865e46777386168706e2d7c81826c8220b0c Mon Sep 17 00:00:00 2001 From: aascencio9 Date: Tue, 24 Mar 2026 11:13:34 -0400 Subject: [PATCH 22/22] Delete releases/bin/MyApp.aliases --- releases/bin/MyApp.aliases | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 releases/bin/MyApp.aliases diff --git a/releases/bin/MyApp.aliases b/releases/bin/MyApp.aliases deleted file mode 100644 index 78aff81..0000000 --- a/releases/bin/MyApp.aliases +++ /dev/null @@ -1,5 +0,0 @@ -[My Computer] -My Computer="192.168.56.103" - -[RT CompactRIO Target] -RT CompactRIO Target="localhost" \ No newline at end of file