diff --git a/.gitignore b/.gitignore index 72364f9..72f474c 100644 --- a/.gitignore +++ b/.gitignore @@ -87,3 +87,4 @@ ENV/ # Rope project settings .ropeproject +/.idea/.gitignore diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..8e3905d --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..7e73c7f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/stackstorm-orion.iml b/.idea/stackstorm-orion.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/stackstorm-orion.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index 289e60d..400bc89 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,13 @@ # Changelog +## 1.0.3 + +- Added Action + + - add_custom_poller_to_node + +- Updated node_create_snmpv3 action to include the option to specify which default pollers to enable when adding the Node + ## 1.0.2 - Fixed small linting error and pushing a new version. diff --git a/README.md b/README.md index 89c20ef..f1b5085 100755 --- a/README.md +++ b/README.md @@ -34,28 +34,29 @@ snmp_internal: "SNMP community to use if internal specified" ## Actions +* `add_custom_pollers_to_node` - Add a list of custom (Universal Device) pollers to a Node * `add_node_to_ncm` - Add an Orion Node to NCM * `drain_poller` - Drain nodes from one Orion poller to another. * `get_discovery_progress` - Get the progress of an SolarWinds Orion Discovery. * `list_node_custom_properties` - List the custom properties for a SolarWinds Orion nodes * `list_nodes_by_poller` - List the nodes on a SolarWinds Orion poller * `list_nodes_by_status` - List the nodes by status -* `list_sdk_verb_args` - List all the arguments for a entity and verb that can be invoked via SolarWinds Orion. +* `list_sdk_verb_args` - List all the arguments for an entity and verb that can be invoked via SolarWinds Orion. * `list_sdk_verbs` - List all the verbs that can be invoked via SolarWinds Orion * `ncm_config_download` - Download config(s) from SolarWinds NCM Orion module. * `ncm_execute_script` - Execute an script on an Orion NCM Node. -* `node_create` - Create an node in SolarWinds Orion. -* `node_create_snmpv3` - Create an node in SolarWinds Orion with SNMPv3. +* `node_create` - Create a node in SolarWinds Orion. +* `node_create_snmpv3` - Create a node in SolarWinds Orion with SNMPv3. * `node_discover_and_add_interfaces` - Discover and add Interfaces for a SolarWinds Orion node. * `node_discover_and_add_interfaces_by_name_and_type` - Discover and add Interfaces for a SolarWinds Orion node based upon the ifName, ifType, and (optional) ifAdminStatus * `node_remanage` - Re-manage a SolarWinds Orion nodes * `node_status` - Query SolarWinds Orion for a node's status (i.e. Up/Down) -* `node_unmanage` - Unmanage an SolarWinds Orion node +* `node_unmanage` - Unmanage a SolarWinds Orion node * `nodes_pollnow` - Force multiple polls of a list of SolarWinds Orion nodes. * `query` - Execute generic SWQL queries. * `start_discovery` - Create a discovery profile in SolarWinds Orion. -* `update_interface_custom_properties` - Update an the custom properties of an interface on an Orion Node -* `update_interface_properties` - Update an the "standard" properties (e.g. Unpluggable) on an interface of an Orion Nodes +* `update_interface_custom_properties` - Update the custom properties of an interface on an Orion Node +* `update_interface_properties` - Update the "standard" properties (e.g. Unpluggable) on an interface of an Orion Nodes * `update_node_custom_properties` - Update an Orion Nodes custom properties * `update_node_poller` - Update an Orion Nodes poller diff --git a/actions/add_custom_pollers_to_node.py b/actions/add_custom_pollers_to_node.py new file mode 100644 index 0000000..4ccf2f5 --- /dev/null +++ b/actions/add_custom_pollers_to_node.py @@ -0,0 +1,110 @@ +# Licensed to the StackStorm, Inc ('StackStorm') under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from lib.actions import OrionBaseAction +from lib.utils import send_user_error + + +class AddCustomPollersToNode(OrionBaseAction): + def run(self, node, custompollers): + """ + Add list of SNMP Pollers to Node + + Args: + - node: The caption in Orion of the node to poll. + - custompollers: The list of Orion Custom SNMP pollers to add to the Node + + Returns + - List of custom pollers that were added to the Node, a list of Custom pollers that were + already assigned to the Node, and a list of Custom pollers that were not found in the system + + Raises: + - ValueError: When a node is not found. + + """ + # Create empty results dict to hold action output data + results = {'added': [], 'existing': [], 'not_found': []} + + # Establish a connection to the Orion Server + self.connect() + + # Find the Node in the system + orion_node = self.get_node(node) + + if not orion_node.npm: + error_msg = "Node not found" + send_user_error(error_msg) + raise ValueError(error_msg) + + # Create a query string needed to pull the custom poller data assigned to the Node + # from the Orion DB + + self.logger.info('Querying list of custom pollers already configured on Node...') + + nodequery = 'SELECT NodeID, CustomPollerID FROM Orion.NPM.CustomPollerAssignmentOnNode ' \ + 'WHERE NodeID=' + str(orion_node.npm_id) + + # Execute the query for the custom Node pollers + nodeassignedpollers = self.query(nodequery) + + # Create an empty list of CustomPollerIDs used to hold the ID for each of the pollers + # passed as input to the action + + custompollerids = [] + + # Loop through all the pollers provided as input to the action and query the Orion DB + # for the CustomPollerID. + + for entry in custompollers: + pollerquery = 'SELECT CustomPollerID, UniqueName FROM Orion.NPM.CustomPollers where ' \ + 'UniqueName=\'' + str(entry) + '\'' + entrypollerid = self.query(pollerquery) + + # Check if the Custom Poller query returned exactly 1 result as expected + if len(entrypollerid['results']) == 1: + # Check if Custom Poller ID is included in the list returned from the existing + # poller query + if any(element for element in nodeassignedpollers['results'] if + element['CustomPollerID'] == entrypollerid['results'][0]['CustomPollerID']): + self.logger.info('Custom Poller {} already assigned to Node. Skipping...' + ''.format(entry)) + # Update results data with matching poller name + results['existing'].append(entry) + else: + # Add Custom Poller ID to list if not found to have already been assigned to the + # Node + custompollerids.append(entrypollerid['results'][0]) + + # Check if the Custom poller query returned either 0 or more than the expected 1 + if len(entrypollerid['results']) > 1 or len(entrypollerid['results']) == 0: + self.logger.info('Custom poller {} not found in Orion DB or the text query returned' + ' multiple entries and will be ignored...'.format(entry)) + results['not_found'].append(entry) + + # After validating all the pollers have not already been assigned to the Node, loop + # through all the entries and assign them to the Node + + for entry in custompollerids: + entrydata = { + "NodeID": str(orion_node.npm_id), + "CustomPollerID": entry['CustomPollerID'] + } + response = self.create('Orion.NPM.CustomPollerAssignmentOnNode', **entrydata) + self.logger.info('Custom poller {} successfully assigned to Node: {}'.format( + entry['UniqueName'], response)) + # Update results data with matching poller name + results['added'].append(entry['UniqueName']) + return results + diff --git a/actions/add_custom_pollers_to_node.yaml b/actions/add_custom_pollers_to_node.yaml new file mode 100644 index 0000000..893f59f --- /dev/null +++ b/actions/add_custom_pollers_to_node.yaml @@ -0,0 +1,17 @@ +--- +description: "Add custom NPM Universal Device Pollers to a Node in SolarWinds" +enabled: true +entry_point: 'add_custom_pollers_to_node.py' +name: "add_custom_pollers_to_node" +pack: "orion" +runner_type: "python-script" + +parameters: + node: + type: "string" + description: The Node which will have the custom pollers assigned to it + required: true + custompollers: + type: "array" + description: List of custom (Universal Device) pollers to be added to Node + required: true diff --git a/actions/node_create_snmpv3.py b/actions/node_create_snmpv3.py index 976b0ae..bae5a32 100644 --- a/actions/node_create_snmpv3.py +++ b/actions/node_create_snmpv3.py @@ -29,7 +29,8 @@ def run(self, privacy_password, auth_protocol, auth_password, - status): + status, + additional_pollers): """ Create an node in Orion. """ @@ -117,6 +118,12 @@ def run(self, pollers_to_add['N.ResponseTime.ICMP.Native'] = False pollers_to_add['N.ResponseTime.SNMP.Native'] = True + # Check to see if any additional pollers were passed as input + if additional_pollers: + # Enable all the pollers passed as input + for entry in additional_pollers: + pollers_to_add[entry] = True + pollers = [] for p in pollers_to_add: pollers.append({ diff --git a/actions/node_create_snmpv3.yaml b/actions/node_create_snmpv3.yaml index debd144..f78b5e6 100644 --- a/actions/node_create_snmpv3.yaml +++ b/actions/node_create_snmpv3.yaml @@ -1,5 +1,5 @@ --- -description: "Create an node using SNMPv3 in Solarwinds Orion." +description: "Create an node using SNMPv3 in SolarWinds Orion." enabled: true entry_point: 'node_create_snmpv3.py' name: "node_create_snmpv3" @@ -35,6 +35,7 @@ parameters: privacy_password: type: "string" required: true + secret: true description: "The SNMPv3 Privacy password used to poll SNMP from remote device." auth_protocol: type: "string" @@ -42,10 +43,13 @@ parameters: enum: - "MD5" - "SHA1" + - "SHA256" + - "SHA512" default: "SHA1" auth_password: type: "string" required: true + secret: true description: "The SNMPv3 Authentication password used to poll SNMP from remote device." status: type: "string" @@ -54,3 +58,7 @@ parameters: - "icmp" description: "Protocol to use for Status and Response Time checks." default: "snmp" + additional_pollers: + type: "array" + required: false + description: "List of Orion pollers to enable when creating Node. ** Must be specified using the correct Orion DB naming syntax." diff --git a/pack.yaml b/pack.yaml index cef5d3c..cb11015 100755 --- a/pack.yaml +++ b/pack.yaml @@ -8,7 +8,7 @@ keywords: - ncm - npm - monitoring -version: 1.0.2 +version: 1.0.3 python_versions: - "3" author: Encore Technologies