diff --git a/src/main/groovy/com/rundeck/plugins/ansible/plugin/AnsibleResourceModelSource.java b/src/main/groovy/com/rundeck/plugins/ansible/plugin/AnsibleResourceModelSource.java index ea1afa8..c50253a 100644 --- a/src/main/groovy/com/rundeck/plugins/ansible/plugin/AnsibleResourceModelSource.java +++ b/src/main/groovy/com/rundeck/plugins/ansible/plugin/AnsibleResourceModelSource.java @@ -1,6 +1,7 @@ package com.rundeck.plugins.ansible.plugin; import com.dtolabs.rundeck.core.common.Framework; +import com.dtolabs.rundeck.core.common.INodeEntry; import com.dtolabs.rundeck.core.common.INodeSet; import com.dtolabs.rundeck.core.common.NodeEntryImpl; import com.dtolabs.rundeck.core.common.NodeSetImpl; @@ -48,6 +49,7 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -132,6 +134,8 @@ public class AnsibleResourceModelSource implements ResourceModelSource, ProxyRun @Setter private AnsibleInventoryList.AnsibleInventoryListBuilder ansibleInventoryListBuilder = null; + private Map ansibleNodes = new HashMap<>(); + public AnsibleResourceModelSource(final Framework framework) { this.framework = framework; } @@ -714,42 +718,121 @@ public void ansibleInventoryList(NodeSetImpl nodes, AnsibleRunner.AnsibleRunnerB if (isTagMapValid(all, ALL)) { Map children = InventoryList.getValue(all, CHILDREN); + processChildren(nodes, children, new HashSet<>()); + } - if (isTagMapValid(children, CHILDREN)) { - for (Map.Entry pair : children.entrySet()) { - String hostGroup = pair.getKey(); - Map hostNames = InventoryList.getType(pair.getValue()); - Map hosts = InventoryList.getValue(hostNames, HOSTS); - - if (isTagMapValid(hosts, HOSTS)) { - for (Map.Entry hostNode : hosts.entrySet()) { - NodeEntryImpl node = new NodeEntryImpl(); - node.setTags(Set.of(hostGroup)); - String hostName = hostNode.getKey(); - node.setHostname(hostName); - node.setNodename(hostName); - Map nodeValues = InventoryList.getType(hostNode.getValue()); - - InventoryList.tagHandle(NodeTag.HOSTNAME, node, nodeValues); - InventoryList.tagHandle(NodeTag.USERNAME, node, nodeValues); - InventoryList.tagHandle(NodeTag.OS_FAMILY, node, nodeValues); - InventoryList.tagHandle(NodeTag.OS_NAME, node, nodeValues); - InventoryList.tagHandle(NodeTag.OS_ARCHITECTURE, node, nodeValues); - InventoryList.tagHandle(NodeTag.OS_VERSION, node, nodeValues); - InventoryList.tagHandle(NodeTag.DESCRIPTION, node, nodeValues); - - nodeValues.forEach((key, value) -> { - if (value != null) { - node.setAttribute(key, value.toString()); - } - }); + ansibleNodes.forEach((k, node) -> nodes.putNode(node)); + ansibleNodes.clear(); + } - nodes.putNode(node); - } - } - } + /** + * Processes the given set of nodes and populates the children map with the results. + * + * @param nodes the set of nodes to process + * @param children a map to be populated with the processed children nodes + * @param tags a set of tags to filter the nodes + * @throws ResourceModelSourceException if an error occurs while processing the nodes + */ + public void processChildren(NodeSetImpl nodes, Map children, HashSet tags) throws ResourceModelSourceException { + if (!isTagMapValid(children, CHILDREN)) { + return; + } + + for (Map.Entry pair : children.entrySet()) { + + String hostGroup = pair.getKey(); + tags.add(hostGroup); + Map hostNames = InventoryList.getType(pair.getValue()); + + if (hostNames.containsKey(CHILDREN)) { + Map subChildren = InventoryList.getValue(hostNames, CHILDREN); + processChildren(nodes, subChildren, tags); + } else { + processHosts(nodes, hostNames, tags); + tags.clear(); + } + } + } + + /** + * Processes the hosts within the given host names map and adds them to the nodes set. + * + * @param nodes the set of nodes to populate + * @param hostNames the map containing host names and their attributes + * @param tags the set of tags to apply to the nodes + * @throws ResourceModelSourceException if an error occurs while processing the nodes + */ + public void processHosts(NodeSetImpl nodes, Map hostNames, HashSet tags) throws ResourceModelSourceException { + Map hosts = InventoryList.getValue(hostNames, HOSTS); + + if (!isTagMapValid(hosts, HOSTS)) { + return; + } + + for (Map.Entry hostNode : hosts.entrySet()) { + NodeEntryImpl node = createNodeEntry(hostNode); + addNode(node, tags); + } + } + + /** + * Creates a NodeEntryImpl object from the given host node entry and tags. + * + * @param hostNode the entry containing the host name and its attributes + * @return the created NodeEntryImpl object + */ + public NodeEntryImpl createNodeEntry(Map.Entry hostNode) throws ResourceModelSourceException { + NodeEntryImpl node = new NodeEntryImpl(); + //node.setTags(Set.copyOf(tags)); + String hostName = hostNode.getKey(); + node.setHostname(hostName); + node.setNodename(hostName); + Map nodeValues = InventoryList.getType(hostNode.getValue()); + + applyNodeTags(node, nodeValues); + nodeValues.forEach((key, value) -> { + if (value != null) { + node.setAttribute(key, value.toString()); } + }); + + return node; + } + + /** + * Applies predefined tags to the given node based on the provided node values. + * + * @param node the node to which the tags will be applied + * @param nodeValues the map containing the node's attributes + */ + public void applyNodeTags(NodeEntryImpl node, Map nodeValues) throws ResourceModelSourceException { + InventoryList.tagHandle(NodeTag.HOSTNAME, node, nodeValues); + InventoryList.tagHandle(NodeTag.USERNAME, node, nodeValues); + InventoryList.tagHandle(NodeTag.OS_FAMILY, node, nodeValues); + InventoryList.tagHandle(NodeTag.OS_NAME, node, nodeValues); + InventoryList.tagHandle(NodeTag.OS_ARCHITECTURE, node, nodeValues); + InventoryList.tagHandle(NodeTag.OS_VERSION, node, nodeValues); + InventoryList.tagHandle(NodeTag.DESCRIPTION, node, nodeValues); + } + + public void addNode(NodeEntryImpl node, Set tags) { + if (ansibleNodes.containsKey(node.getNodename())) { + NodeEntryImpl oldNode = ansibleNodes.get(node.getNodename()); + Set currentTags = getStringTags(oldNode); + currentTags.addAll(tags); + oldNode.setTags(Set.copyOf(currentTags)); + } else { + node.setTags(Set.copyOf(tags)); + ansibleNodes.put(node.getNodename(), node); + } + } + + public Set getStringTags(NodeEntryImpl node) { + Set tags = new HashSet<>(); + for (Object tag : node.getTags()) { + tags.add(tag.toString()); } + return tags; } /**