|
1 | 1 | package com.rundeck.plugins.ansible.plugin;
|
2 | 2 |
|
3 | 3 | import com.dtolabs.rundeck.core.common.Framework;
|
| 4 | +import com.dtolabs.rundeck.core.common.INodeEntry; |
4 | 5 | import com.dtolabs.rundeck.core.common.INodeSet;
|
5 | 6 | import com.dtolabs.rundeck.core.common.NodeEntryImpl;
|
6 | 7 | import com.dtolabs.rundeck.core.common.NodeSetImpl;
|
|
48 | 49 | import java.nio.file.SimpleFileVisitor;
|
49 | 50 | import java.nio.file.attribute.BasicFileAttributes;
|
50 | 51 | import java.util.ArrayList;
|
| 52 | +import java.util.Arrays; |
51 | 53 | import java.util.HashMap;
|
52 | 54 | import java.util.HashSet;
|
53 | 55 | import java.util.List;
|
54 | 56 | import java.util.Map;
|
55 | 57 | import java.util.Map.Entry;
|
56 | 58 | import java.util.Properties;
|
57 | 59 | import java.util.Set;
|
| 60 | +import java.util.stream.Collectors; |
58 | 61 |
|
59 | 62 | import static com.rundeck.plugins.ansible.ansible.InventoryList.ALL;
|
60 | 63 | import static com.rundeck.plugins.ansible.ansible.InventoryList.CHILDREN;
|
@@ -132,6 +135,8 @@ public class AnsibleResourceModelSource implements ResourceModelSource, ProxyRun
|
132 | 135 | @Setter
|
133 | 136 | private AnsibleInventoryList.AnsibleInventoryListBuilder ansibleInventoryListBuilder = null;
|
134 | 137 |
|
| 138 | + private Map<String, NodeEntryImpl> ansibleNodes = new HashMap<>(); |
| 139 | + |
135 | 140 | public AnsibleResourceModelSource(final Framework framework) {
|
136 | 141 | this.framework = framework;
|
137 | 142 | }
|
@@ -714,44 +719,134 @@ public void ansibleInventoryList(NodeSetImpl nodes, AnsibleRunner.AnsibleRunnerB
|
714 | 719 |
|
715 | 720 | if (isTagMapValid(all, ALL)) {
|
716 | 721 | Map<String, Object> children = InventoryList.getValue(all, CHILDREN);
|
| 722 | + processChildren(children, new HashSet<>()); |
| 723 | + } |
717 | 724 |
|
718 |
| - if (isTagMapValid(children, CHILDREN)) { |
719 |
| - for (Map.Entry<String, Object> pair : children.entrySet()) { |
720 |
| - String hostGroup = pair.getKey(); |
721 |
| - Map<String, Object> hostNames = InventoryList.getType(pair.getValue()); |
722 |
| - Map<String, Object> hosts = InventoryList.getValue(hostNames, HOSTS); |
723 |
| - |
724 |
| - if (isTagMapValid(hosts, HOSTS)) { |
725 |
| - for (Map.Entry<String, Object> hostNode : hosts.entrySet()) { |
726 |
| - NodeEntryImpl node = new NodeEntryImpl(); |
727 |
| - node.setTags(Set.of(hostGroup)); |
728 |
| - String hostName = hostNode.getKey(); |
729 |
| - node.setHostname(hostName); |
730 |
| - node.setNodename(hostName); |
731 |
| - Map<String, Object> nodeValues = InventoryList.getType(hostNode.getValue()); |
732 |
| - |
733 |
| - InventoryList.tagHandle(NodeTag.HOSTNAME, node, nodeValues); |
734 |
| - InventoryList.tagHandle(NodeTag.USERNAME, node, nodeValues); |
735 |
| - InventoryList.tagHandle(NodeTag.OS_FAMILY, node, nodeValues); |
736 |
| - InventoryList.tagHandle(NodeTag.OS_NAME, node, nodeValues); |
737 |
| - InventoryList.tagHandle(NodeTag.OS_ARCHITECTURE, node, nodeValues); |
738 |
| - InventoryList.tagHandle(NodeTag.OS_VERSION, node, nodeValues); |
739 |
| - InventoryList.tagHandle(NodeTag.DESCRIPTION, node, nodeValues); |
740 |
| - |
741 |
| - nodeValues.forEach((key, value) -> { |
742 |
| - if (value != null) { |
743 |
| - node.setAttribute(key, value.toString()); |
744 |
| - } |
745 |
| - }); |
| 725 | + ansibleNodes.forEach((k, node) -> nodes.putNode(node)); |
| 726 | + ansibleNodes.clear(); |
| 727 | + } |
746 | 728 |
|
747 |
| - nodes.putNode(node); |
748 |
| - } |
749 |
| - } |
750 |
| - } |
| 729 | + /** |
| 730 | + * Processes the given set of nodes and populates the children map with the results. |
| 731 | + * |
| 732 | + * @param children a map to be populated with the processed children nodes |
| 733 | + * @param tags a set of tags to filter the nodes |
| 734 | + * @throws ResourceModelSourceException if an error occurs while processing the nodes |
| 735 | + */ |
| 736 | + public void processChildren(Map<String, Object> children, HashSet<String> tags) throws ResourceModelSourceException { |
| 737 | + if (!isTagMapValid(children, CHILDREN)) { |
| 738 | + return; |
| 739 | + } |
| 740 | + |
| 741 | + for (Map.Entry<String, Object> pair : children.entrySet()) { |
| 742 | + |
| 743 | + String hostGroup = pair.getKey(); |
| 744 | + tags.add(hostGroup); |
| 745 | + Map<String, Object> hostNames = InventoryList.getType(pair.getValue()); |
| 746 | + |
| 747 | + if (hostNames.containsKey(CHILDREN)) { |
| 748 | + Map<String, Object> subChildren = InventoryList.getValue(hostNames, CHILDREN); |
| 749 | + processChildren(subChildren, tags); |
| 750 | + } else { |
| 751 | + processHosts(hostNames, tags); |
| 752 | + tags.clear(); |
751 | 753 | }
|
752 | 754 | }
|
753 | 755 | }
|
754 | 756 |
|
| 757 | + /** |
| 758 | + * Processes the hosts within the given host names map and adds them to the nodes set. |
| 759 | + * |
| 760 | + * @param hostNames the map containing host names and their attributes |
| 761 | + * @param tags the set of tags to apply to the nodes |
| 762 | + * @throws ResourceModelSourceException if an error occurs while processing the nodes |
| 763 | + */ |
| 764 | + public void processHosts(Map<String, Object> hostNames, HashSet<String> tags) throws ResourceModelSourceException { |
| 765 | + Map<String, Object> hosts = InventoryList.getValue(hostNames, HOSTS); |
| 766 | + |
| 767 | + if (!isTagMapValid(hosts, HOSTS)) { |
| 768 | + return; |
| 769 | + } |
| 770 | + |
| 771 | + for (Map.Entry<String, Object> hostNode : hosts.entrySet()) { |
| 772 | + NodeEntryImpl node = createNodeEntry(hostNode); |
| 773 | + addNode(node, tags); |
| 774 | + } |
| 775 | + } |
| 776 | + |
| 777 | + /** |
| 778 | + * Creates a NodeEntryImpl object from the given host node entry and tags. |
| 779 | + * |
| 780 | + * @param hostNode the entry containing the host name and its attributes |
| 781 | + * @return the created NodeEntryImpl object |
| 782 | + */ |
| 783 | + public NodeEntryImpl createNodeEntry(Map.Entry<String, Object> hostNode) throws ResourceModelSourceException { |
| 784 | + NodeEntryImpl node = new NodeEntryImpl(); |
| 785 | + String hostName = hostNode.getKey(); |
| 786 | + node.setHostname(hostName); |
| 787 | + node.setNodename(hostName); |
| 788 | + Map<String, Object> nodeValues = InventoryList.getType(hostNode.getValue()); |
| 789 | + |
| 790 | + applyNodeTags(node, nodeValues); |
| 791 | + nodeValues.forEach((key, value) -> { |
| 792 | + if (value != null) { |
| 793 | + node.setAttribute(key, value.toString()); |
| 794 | + } |
| 795 | + }); |
| 796 | + |
| 797 | + return node; |
| 798 | + } |
| 799 | + |
| 800 | + /** |
| 801 | + * Applies predefined tags to the given node based on the provided node values. |
| 802 | + * |
| 803 | + * @param node the node to which the tags will be applied |
| 804 | + * @param nodeValues the map containing the node's attributes |
| 805 | + */ |
| 806 | + public void applyNodeTags(NodeEntryImpl node, Map<String, Object> nodeValues) throws ResourceModelSourceException { |
| 807 | + InventoryList.tagHandle(NodeTag.HOSTNAME, node, nodeValues); |
| 808 | + InventoryList.tagHandle(NodeTag.USERNAME, node, nodeValues); |
| 809 | + InventoryList.tagHandle(NodeTag.OS_FAMILY, node, nodeValues); |
| 810 | + InventoryList.tagHandle(NodeTag.OS_NAME, node, nodeValues); |
| 811 | + InventoryList.tagHandle(NodeTag.OS_ARCHITECTURE, node, nodeValues); |
| 812 | + InventoryList.tagHandle(NodeTag.OS_VERSION, node, nodeValues); |
| 813 | + InventoryList.tagHandle(NodeTag.DESCRIPTION, node, nodeValues); |
| 814 | + } |
| 815 | + |
| 816 | + /** |
| 817 | + * Adds a node to the ansibleNodes map, merging tags if the node already exists. |
| 818 | + * |
| 819 | + * @param node The node to add. |
| 820 | + * @param tags The tags to associate with the node. |
| 821 | + */ |
| 822 | + public void addNode(NodeEntryImpl node, Set<String> tags) { |
| 823 | + ansibleNodes.compute(node.getNodename(), (key, existingNode) -> { |
| 824 | + if (existingNode != null) { |
| 825 | + Set<String> mergedTags = new HashSet<>(getStringTags(existingNode)); |
| 826 | + mergedTags.addAll(tags); |
| 827 | + existingNode.setTags(Set.copyOf(mergedTags)); |
| 828 | + return existingNode; |
| 829 | + } else { |
| 830 | + node.setTags(Set.copyOf(tags)); |
| 831 | + return node; |
| 832 | + } |
| 833 | + }); |
| 834 | + } |
| 835 | + |
| 836 | + /** |
| 837 | + * Retrieves the tags from a node and converts them to strings. |
| 838 | + * |
| 839 | + * @param node The node whose tags are to be retrieved. |
| 840 | + * @return A set of strings representing the node's tags. Returns an empty set if the node has no tags. |
| 841 | + */ |
| 842 | + public Set<String> getStringTags(NodeEntryImpl node) { |
| 843 | + Set<String> tags = new HashSet<>(); |
| 844 | + for (Object tag : node.getTags()) { |
| 845 | + tags.add(tag.toString()); |
| 846 | + } |
| 847 | + return tags; |
| 848 | + } |
| 849 | + |
755 | 850 | /**
|
756 | 851 | * Gets Ansible nodes from inventory
|
757 | 852 | * @return Ansible nodes
|
|
0 commit comments