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 com.scivicslab.actoriac.NodeGroup;
021import com.scivicslab.actoriac.Node;
022import com.scivicslab.pojoactor.core.ActorRef;
023import com.scivicslab.pojoactor.workflow.IIActorSystem;
024
025import java.io.InputStream;
026import java.util.List;
027import java.util.concurrent.CompletableFuture;
028
029/**
030 * Example demonstrating basic NodeGroup and Node usage.
031 *
032 * <p>This example shows how to:
033 * <ul>
034 * <li>Load an Ansible inventory file</li>
035 * <li>Create node actors for a group</li>
036 * <li>Execute commands on all nodes concurrently using the actor model</li>
037 * </ul>
038 *
039 * @author devteam@scivics-lab.com
040 */
041public class ClusterExample {
042
043    public static void main(String[] args) {
044        System.out.println("=== actor-IaC Cluster Example ===\n");
045
046        try {
047            // Load inventory file
048            InputStream inventoryStream = ClusterExample.class
049                .getResourceAsStream("/example-inventory.ini");
050
051            if (inventoryStream == null) {
052                System.err.println("ERROR: example-inventory.ini not found in resources");
053                System.err.println("Please create an inventory file to run this example");
054                return;
055            }
056
057            // Create node group using Builder pattern (POJO, no ActorSystem dependency)
058            NodeGroup nodeGroup = new NodeGroup.Builder()
059                .withInventory(inventoryStream)
060                .build();
061            System.out.println("Created node group and loaded inventory");
062            System.out.println("Available groups: " +
063                nodeGroup.getInventory().getAllGroups().keySet());
064
065            // Create actor system (using IIActorSystem for workflow support)
066            IIActorSystem actorSystem = new IIActorSystem("iac-system");
067
068            // Create Node objects for webservers group
069            // Note: Nodes are pure POJOs with SSH functionality
070            List<Node> nodes = nodeGroup.createNodesForGroup("webservers");
071            System.out.println("\nCreated " + nodes.size() +
072                " Node objects for webservers group");
073
074            // Convert Node objects to actors
075            List<ActorRef<Node>> webservers = nodes.stream()
076                .map(node -> actorSystem.actorOf("node-" + node.getHostname().replace(".", "-"), node))
077                .toList();
078            System.out.println("Converted to " + webservers.size() + " node actors");
079
080            // Example: Execute 'hostname' command on all webservers concurrently
081            System.out.println("\nExecuting 'echo hello' on all webservers...");
082
083            List<CompletableFuture<Node.CommandResult>> futures = webservers.stream()
084                .map(nodeActor -> nodeActor.ask(node -> {
085                    try {
086                        return node.executeCommand("echo 'Hello from ' && hostname");
087                    } catch (Exception e) {
088                        return new Node.CommandResult("", e.getMessage(), -1);
089                    }
090                }))
091                .toList();
092
093            // Wait for all commands to complete
094            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
095
096            // Display results
097            System.out.println("\nResults:");
098            for (int i = 0; i < futures.size(); i++) {
099                Node.CommandResult result = futures.get(i).get();
100                System.out.println("Node " + (i + 1) + ":");
101                System.out.println("  Exit Code: " + result.getExitCode());
102                System.out.println("  Output: " + result.getStdout());
103                if (!result.getStderr().isEmpty()) {
104                    System.out.println("  Error: " + result.getStderr());
105                }
106            }
107
108            System.out.println("\nNodeGroup info: " + nodeGroup);
109
110            // Clean up
111            actorSystem.terminate();
112            System.out.println("\nActor system terminated");
113
114        } catch (Exception e) {
115            System.err.println("Error: " + e.getMessage());
116            e.printStackTrace();
117        }
118    }
119}