001/* 002 * Copyright 2025 devteam@scivics-lab.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, 011 * software distributed under the License is distributed on an 012 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the 014 * specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package com.scivicslab.actoriac.example; 019 020import java.io.FileInputStream; 021import java.util.logging.Level; 022import java.util.logging.Logger; 023 024import com.scivicslab.actoriac.NodeGroup; 025import com.scivicslab.actoriac.NodeGroupIIAR; 026import com.scivicslab.actoriac.NodeGroupInterpreter; 027import com.scivicslab.pojoactor.core.ActionResult; 028import com.scivicslab.pojoactor.workflow.IIActorSystem; 029 030/** 031 * Generic workflow runner for actor-IaC (Level 3). 032 * 033 * <p>This class provides a reusable entry point for executing workflows 034 * on infrastructure nodes. The actual operations are defined in external 035 * YAML/JSON/XML workflow files, not in Java code.</p> 036 * 037 * <h2>Usage</h2> 038 * <pre> 039 * java -jar actor-IaC.jar inventory.ini webservers workflow.yaml 040 * </pre> 041 * 042 * <h2>Actor Hierarchy</h2> 043 * <pre> 044 * IIActorSystem 045 * └─ NodeGroupIIAR (parent) 046 * ├─ NodeIIAR (child, autonomous agent) 047 * ├─ NodeIIAR (child, autonomous agent) 048 * └─ NodeIIAR (child, autonomous agent) 049 * </pre> 050 * 051 * <h2>Design Principle</h2> 052 * <p>This Java code is generic and does not need modification when 053 * changing targets or operations. All customization is done through:</p> 054 * <ul> 055 * <li><strong>inventory.ini</strong> - Define hosts and groups</li> 056 * <li><strong>workflow.yaml</strong> - Define operations to execute</li> 057 * </ul> 058 * 059 * @author devteam@scivics-lab.com 060 */ 061public class WorkflowRunner { 062 063 private static final Logger LOG = Logger.getLogger(WorkflowRunner.class.getName()); 064 065 private final IIActorSystem system; 066 private final NodeGroupIIAR nodeGroupActor; 067 068 /** 069 * Constructs a WorkflowRunner with the specified system and parent actor. 070 * 071 * @param system the IIActorSystem for workflow execution 072 * @param nodeGroupActor the NodeGroupIIAR parent actor 073 */ 074 public WorkflowRunner(IIActorSystem system, NodeGroupIIAR nodeGroupActor) { 075 this.system = system; 076 this.nodeGroupActor = nodeGroupActor; 077 } 078 079 /** 080 * Main entry point for workflow execution. 081 * 082 * <p>Arguments:</p> 083 * <ol> 084 * <li>inventory - Path to Ansible inventory file</li> 085 * <li>group - Name of the host group to target</li> 086 * <li>workflow - Path to workflow file (YAML/JSON/XML)</li> 087 * </ol> 088 * 089 * @param args command line arguments 090 * @throws Exception if execution fails 091 */ 092 public static void main(String[] args) throws Exception { 093 if (args.length < 3) { 094 System.out.println("Usage: java -jar actor-IaC.jar <inventory> <group> <workflow>"); 095 System.out.println(); 096 System.out.println("Arguments:"); 097 System.out.println(" inventory - Path to Ansible inventory file (e.g., inventory.ini)"); 098 System.out.println(" group - Name of the host group to target (e.g., webservers)"); 099 System.out.println(" workflow - Path to workflow file (e.g., deploy.yaml)"); 100 System.out.println(); 101 System.out.println("Example:"); 102 System.out.println(" java -jar actor-IaC.jar inventory.ini webservers deploy.yaml"); 103 return; 104 } 105 106 String inventoryPath = args[0]; 107 String groupName = args[1]; 108 String workflowPath = args[2]; 109 110 LOG.info("=== actor-IaC Workflow Runner ==="); 111 LOG.log(Level.INFO, "Inventory: {0}", inventoryPath); 112 LOG.log(Level.INFO, "Group: {0}", groupName); 113 LOG.log(Level.INFO, "Workflow: {0}", workflowPath); 114 115 IIActorSystem system = new IIActorSystem("actor-iac-workflow"); 116 117 try { 118 // Step 1: Create NodeGroup POJO (Level 1 functionality) 119 // Pure POJO creation, independent of IIActorSystem 120 NodeGroup nodeGroup = new NodeGroup.Builder() 121 .withInventory(new FileInputStream(inventoryPath)) 122 .build(); 123 LOG.info("NodeGroup POJO created"); 124 125 // Step 2: Wrap NodeGroup with Interpreter (Level 3 functionality) 126 NodeGroupInterpreter nodeGroupInterpreter = new NodeGroupInterpreter(nodeGroup, system); 127 LOG.info("NodeGroupInterpreter created"); 128 129 // Step 3: Convert to IIActor 130 NodeGroupIIAR nodeGroupActor = new NodeGroupIIAR("nodeGroup", nodeGroupInterpreter, system); 131 system.addIIActor(nodeGroupActor); 132 LOG.info("NodeGroupIIAR actor created"); 133 134 // Run the workflow 135 WorkflowRunner runner = new WorkflowRunner(system, nodeGroupActor); 136 runner.run(groupName, workflowPath); 137 138 LOG.info("=== Complete ==="); 139 } finally { 140 system.terminate(); 141 } 142 } 143 144 /** 145 * Executes the workflow on the specified group. 146 * 147 * <p>Uses the apply method with runWorkflow to load and run workflows 148 * on all matching child actors in a single step.</p> 149 * 150 * @param groupName the name of the host group 151 * @param workflowPath the path to the workflow file 152 * @throws Exception if execution fails 153 */ 154 public void run(String groupName, String workflowPath) throws Exception { 155 // Step 1: Create child NodeIIARs for the group 156 LOG.log(Level.INFO, "Creating node actors for group: {0}", groupName); 157 ActionResult createResult = nodeGroupActor.callByActionName( 158 "createNodeActors", "[\"" + groupName + "\"]"); 159 160 if (!createResult.isSuccess()) { 161 LOG.log(Level.SEVERE, "Failed to create node actors: {0}", createResult.getResult()); 162 return; 163 } 164 LOG.log(Level.INFO, "Create result: {0}", createResult.getResult()); 165 166 // Step 2: Run workflow on all nodes using apply + runWorkflow 167 LOG.log(Level.INFO, "Running workflow on all nodes: {0}", workflowPath); 168 String runAction = String.format( 169 "{\"actor\": \"node-*\", \"method\": \"runWorkflow\", \"arguments\": [\"%s\"]}", 170 workflowPath); 171 ActionResult result = nodeGroupActor.callByActionName("apply", runAction); 172 173 LOG.info("Workflow execution result:"); 174 LOG.log(Level.INFO, " Success: {0}", result.isSuccess()); 175 LOG.log(Level.INFO, " Message: {0}", result.getResult()); 176 } 177 178 /** 179 * Executes a single command on all nodes in the group. 180 * 181 * <p>This is a convenience method for simple use cases where 182 * a full workflow is not needed.</p> 183 * 184 * @param groupName the name of the host group 185 * @param command the command to execute 186 * @throws Exception if execution fails 187 */ 188 public void executeCommand(String groupName, String command) throws Exception { 189 // Create child NodeIIARs if not already created 190 ActionResult createResult = nodeGroupActor.callByActionName( 191 "createNodeActors", "[\"" + groupName + "\"]"); 192 193 if (!createResult.isSuccess()) { 194 LOG.log(Level.SEVERE, "Failed to create node actors: {0}", createResult.getResult()); 195 return; 196 } 197 198 // Execute command on all nodes 199 LOG.log(Level.INFO, "Executing command on all nodes: {0}", command); 200 ActionResult result = nodeGroupActor.callByActionName( 201 "executeCommandOnAllNodes", "[\"" + command + "\"]"); 202 203 LOG.log(Level.INFO, "Command result: {0}", result.getResult()); 204 } 205}