diff --git a/deployment/core/tasks.py b/deployment/core/tasks.py index ba93992..9b9ee17 100644 --- a/deployment/core/tasks.py +++ b/deployment/core/tasks.py @@ -24,32 +24,19 @@ config_path = self.get_arg("config") with open(config_path, "r") as f: - module = lua.execute(f.read()) - - # 2. Determine environment key from branch - # Mapping 'main' to 'release' as per lua schema - branch = self.get_arg("branch").split("/")[-1] - target_env = "release" if branch == "main" else branch - - if target_env not in module: - self.fail(f"Environment '{target_env}' not defined in {config_path}") - - # 3. Extract environment specific sub-table - cfg = module[target_env] + cfg = lua.execute(f.read()) # 4. Hydrate self.env self.env.lua_cfg = cfg # Store the lua object for functional calls later - self.env.app_name = module.app_name - self.env.repo = module.repo - self.env.timestamp_format = module.timestamp_format + self.env.app_name = cfg.app_name + self.env.repo = cfg.repo + self.env.timestamp_format = cfg.timestamp_format - self.env.deploy_path = Path(cfg.deploy_link) - self.env.service_name = cfg.service_name - self.env.config_file_source = Path(cfg.config_file) - self.env.retention_count = cfg.count - self.env.deploy_branch = branch + self.env.deploy_branch = self.get_arg("branch").split("/")[-1] + self.env.release = cfg.release + self.env.testing = cfg.testing - self.print(f"✅ Context hydrated for {self.env.app_name}:{target_env}") + self.print(f"✅ Context hydrated for {self.env.app_name}") # self.env.build_dir = Path(config.paths.build) return True @@ -65,13 +52,13 @@ def _run(self): # 1. Physical existence check - config_path = self.env.config_file_source + config_path = self.env.testing.config_file self.print(f" [CHECK] Verifying configuration: {config_path}") if not os.path.exists(config_path): self.fail( f"CRITICAL: Configuration file not found at {config_path}. " - "Pipeline terminated to prevent application misbehavior." + "Pipeline terminated." ) # 2. Parse TOML for internal deployment metadata @@ -119,11 +106,8 @@ # Use a temporary build directory with -BUILDING suffix # This is finalized in AtomicDeploy timestamp = time.strftime(self.env.timestamp_format) - self.env.release_dir = Path(self.env.lua_cfg.get_release_dir(timestamp)) - self.env.build_dir = self.env.release_dir.with_name( - self.env.release_dir.name + "-BUILDING" - ) - + self.env.release_dir = f"{Path(self.env.testing.deploy_link)}-{timestamp}" + self.env.build_dir = os.getcwd() self.print(f" [BUILD] Target: {self.env.build_dir}") self.sh( @@ -147,18 +131,44 @@ self.name = "Executing atomic symlink swap" def _run(self): - # 1. Finalize the directory name (remove -BUILDING) - self.sh(f"mv {self.env.build_dir} {self.env.release_dir}") + # Determine success from the TestRunner flag + test_success = getattr(self.env, "test_success", False) - # 2. Atomic Symlink Swap - temp_link = self.env.deploy_path.with_name(self.env.deploy_path.name + "_tmp") - self.sh(f"ln -sfn {self.env.release_dir} {temp_link}") - self.sh(f"mv -Tf {temp_link} {self.env.deploy_path}") + # Select appropriate Lua config table + cfg = self.env.release if test_success else self.env.testing - # 3. Restart Service - self.sh(f"sudo systemctl restart {self.env.service_name}") + # Generate the versioned directory path using Lua function + # Note: Use the actual formatted timestamp, not the format string + timestamp = time.strftime(self.env.timestamp_format) + final_release_dir = Path(cfg.get_release_dir(timestamp)) - self.print(f"🚀 Deployed to {self.env.deploy_path} -> {self.env.release_dir}") + self.print(f" [MOVE] Finalizing build to: {final_release_dir}") + + # 1. Finalize the directory (Rename from -BUILDING to versioned path) + self.sh(f"mv {self.env.build_dir} {final_release_dir}") + + # 2. Atomic Symlink Swap - ONLY if tests passed + if test_success: + deploy_link = Path(cfg.deploy_link) + # Create a temporary symlink name in the same parent directory + temp_link = deploy_link.with_name(deploy_link.name + "_tmp") + + self.print( + f" [LINK] Swapping symlink: {deploy_link} -> {final_release_dir}" + ) + + # Create temporary symlink pointing to the new version + self.sh(f"ln -sfn {final_release_dir} {temp_link}") + + # Atomic rename of the symlink itself (overwrites the old link) + self.sh(f"mv -Tf {temp_link} {deploy_link}") + + # Restart service + self.sh(f"sudo systemctl restart {cfg.service_name}") + else: + self.print(" [SKIP] Test failure detected. Symlink swap bypassed.") + self.print(f" [INFO] Artifact preserved at: {final_release_dir}") + return True @@ -185,5 +195,7 @@ if res.returncode == 0: self.print("✅ Service is healthy") return True + else: + print(res) time.sleep(2) self.fail("Service failed health check after 30 seconds") diff --git a/deployment/core/tests.py b/deployment/core/tests.py index 65aba72..272d955 100644 --- a/deployment/core/tests.py +++ b/deployment/core/tests.py @@ -56,7 +56,8 @@ if res: self.print(" [OK] Service is UP.") return True - except Exception: + except Exception as e: + self.print(e) time.sleep(2) self.sh(f"cat '{self.env.test_log}'") @@ -151,5 +152,4 @@ self.print(" [CLEAN] Ensuring test environment teardown...") cleanup = StopTestApp(parent=self, owner=self._owner) cleanup.run() - - return success + self.env.test_success = success