Exemplo n.º 1
1
def main():
    npm_server = 'localhost'
    username = '******'
    password = ''

    swis = SwisClient(npm_server, username, password)
    print("Add an SNMP v2c node:")

    # fill these in for the node you want to add!
    ip_address = '127.0.0.1'
    community = 'public'

    # set up property bag for the new node
    props = {
        'IPAddress': ip_address,
        'EngineID': 1,
        'ObjectSubType': 'SNMP',
        'SNMPVersion': 2,
        'Community': community
    }

    print("Adding node {}... ".format(props['IPAddress']), end="")
    results = swis.create('Orion.Nodes', **props)
    print("DONE!")

    # extract the nodeID from the result
    nodeid = re.search('(\d+)$', results).group(0)

    pollers_enabled = {
        'N.Status.ICMP.Native': True,
        'N.Status.SNMP.Native': False,
        'N.ResponseTime.ICMP.Native': True,
        'N.ResponseTime.SNMP.Native': False,
        'N.Details.SNMP.Generic': True,
        'N.Uptime.SNMP.Generic': True,
        'N.Cpu.SNMP.HrProcessorLoad': True,
        'N.Memory.SNMP.NetSnmpReal': True,
        'N.AssetInventory.Snmp.Generic': True,
        'N.Topology_Layer3.SNMP.ipNetToMedia': False,
        'N.Routing.SNMP.Ipv4CidrRoutingTable': False
    }

    pollers = []
    for k in pollers_enabled:
        pollers.append(
            {
                'PollerType': k,
                'NetObject': 'N:' + nodeid,
                'NetObjectType': 'N',
                'NetObjectID': nodeid,
                'Enabled': pollers_enabled[k]
            }
        )

    for poller in pollers:
        print("  Adding poller type: {} with status {}... ".format(poller['PollerType'], poller['Enabled']), end="")
        response = swis.create('Orion.Pollers', **poller)
        print("DONE!")
Exemplo n.º 2
0
def main():
    npm_server = 'localhost'
    username = '******'
    password = ''

    swis = SwisClient(npm_server, username, password)
    print("Add an SNMP v2c node:")

    # fill these in for the node you want to add!
    ip_address = '127.0.0.1'
    community = 'public'

    # set up property bag for the new node
    props = {
        'IPAddress': ip_address,
        'EngineID': 1,
        'ObjectSubType': 'SNMP',
        'SNMPVersion': 2,
        'Community': community,
        'DNS': '',
        'SysName': ''
    }

    print("Adding node {}... ".format(props['IPAddress']), end="")
    results = swis.create('Orion.Nodes', **props)
    print("DONE!")

    # extract the nodeID from the result
    nodeid = re.search(r'(\d+)$', results).group(0)

    pollers_enabled = {
        'N.Status.ICMP.Native': True,
        'N.Status.SNMP.Native': False,
        'N.ResponseTime.ICMP.Native': True,
        'N.ResponseTime.SNMP.Native': False,
        'N.Details.SNMP.Generic': True,
        'N.Uptime.SNMP.Generic': True,
        'N.Cpu.SNMP.HrProcessorLoad': True,
        'N.Memory.SNMP.NetSnmpReal': True,
        'N.AssetInventory.Snmp.Generic': True,
        'N.Topology_Layer3.SNMP.ipNetToMedia': False,
        'N.Routing.SNMP.Ipv4CidrRoutingTable': False
    }

    pollers = []
    for k in pollers_enabled:
        pollers.append({
            'PollerType': k,
            'NetObject': 'N:' + nodeid,
            'NetObjectType': 'N',
            'NetObjectID': nodeid,
            'Enabled': pollers_enabled[k]
        })

    for poller in pollers:
        print("  Adding poller type: {} with status {}... ".format(
            poller['PollerType'], poller['Enabled']),
              end="")
        response = swis.create('Orion.Pollers', **poller)
        print("DONE!")
Exemplo n.º 3
0
def main():
    # Connect to SWIS
    server = 'localhost'
    username = '******'
    password = ''
    swis = SwisClient(server, username, password)

    engine_id = 1
    node_caption = 'example.com'
    node_props = {
        'IPAddress': '10.0.0.1',
        'EngineID': engine_id,
        'Caption': node_caption,
        'ObjectSubType': 'SNMP',
        'Community': 'public',
        'SNMPVersion': 2,
        'DNS': '',
        'SysName': ''
    }

    # Add node
    swis.create('Orion.Nodes', **node_props)
    query_results = swis.query(
        'SELECT NodeID FROM Orion.Nodes WHERE Caption = @caption_par',
        caption_par=node_caption)
    node_id = query_results['results'][0]['NodeID']
    print('New node with ID {0} created'.format(node_id))

    # Discovere and add interfaces
    results = swis.invoke('Orion.NPM.Interfaces', 'DiscoverInterfacesOnNode',
                          node_id)
    swis.invoke('Orion.NPM.Interfaces', 'AddInterfacesOnNode', node_id,
                results['DiscoveredInterfaces'], 'AddDefaultPollers')
    query_results = swis.query(
        'SELECT InterfaceID FROM Orion.NPM.Interfaces WHERE NodeID = @node_id_par',
        node_id_par=node_id)
    print('Discovered and added {0} interfaces for node with id {1}'.format(
        len(query_results['results']), node_id))
    interface_ids = [r['InterfaceID'] for r in query_results['results']]

    # Add Flow sources for every interface - enable flow collection on every interface
    swis.invoke('Orion.Netflow.Source', 'EnableFlowSources', interface_ids,
                'AddDefaultPollers')
    query_results = swis.query(
        'SELECT NetflowSourceID FROM Orion.Netflow.Source WHERE NodeID = @node_id_par',
        node_id_par=node_id)
    print('Added {0} Flow sources for node with id {1}'.format(
        len(query_results['results']), node_id))
Exemplo n.º 4
0
    def addNodeToOrion(self,orion_server,client_address,service_description='',engine_id=3):

        # disable SSL warnings
        requests.packages.urllib3.disable_warnings()

        # connect to orion API port=17778
        npm = SwisClient(orion_server, self.username, self.password)

        # define node properties
        # EngineID can be found in the solarwind orion database server

        props = {'IPAddress': client_address,
                 'ObjectSubType': 'ICMP',
                 'EngineID': engine_id,
                 'NodeName': service_description}

        # add the node
        try :

            record = npm.create('Orion.Nodes', **props)
            #extract the node id
            nodeid = re.findall(r'(\d+)$',record)[0]
            #enable ICMP polling
            pollers_enabled = {'N.Status.ICMP.Native': True,
                               'N.ResponseTime.ICMP.Native': True}

            # define pollers properties in a dictionary and create a list of those dicts
            pollers_props = []

            for poller in pollers_enabled:
                pollers_props.append({'PollerType': poller,
                                      'NetObject': 'N:' + nodeid,
                                      'NetObjectType': 'N',
                                      'NetObjectID': nodeid,
                                      'Enabled': pollers_enabled[poller]})

            # update the pollers in orion
            for pollers in pollers_props: npm.create('Orion.Pollers', **pollers)

            # poll the node
            npm.invoke('Orion.Nodes', 'PollNow', 'N:' + nodeid)

            return True

        except ConnectionError: return ConnectionError
        except requests.exceptions.HTTPError: return AttributeError # wrong credentials
        except Exception as e: return '%s\n%s' %(str(type(e)),str(e))
Exemplo n.º 5
0
class NodeManager:
    def __init__(self, username, password):

        # Change 'orion' to your Orion NPM server name or IP.
        self._swis = SwisClient('orion', username, password)

    def add_node(self, **node):
        self._node_element(**node)
        self._node_pollers()
        self._node_custom_props(**node)
        self._poll()
        self._node_ncm(**node)

    def _node_element(self, **node):

        # Extract IP Address and node name from node variables
        ip_address = node['IP_Address']
        node_name = node['Caption']

        # Setup properties for the new node
        props = {
            'IPAddress': ip_address,
            'EngineID': 5,
            'ObjectSubType': 'SNMP',
            'SNMPVersion': 3,
            'Caption': node_name,
            'SNMPV3AuthKey': 'YourKey',  # Enter your key here
            'SNMPv3AuthKeyIsPwd': True,
            'SNMPv3AuthMethod': 'SHA1',
            'SNMPv3PrivKey': 'YourKey',  # Enter your key here
            'SNMPv3PrivKeyIsPwd': True,
            'SNMPv3PrivMethod': 'AES128',
            'SNMPV3Username': '******'  # Enter your SNMPv3 Username here
        }

        # Create the node
        print("Adding node {}... ".format(props['IPAddress']), end="")
        self._results = self._swis.create('Orion.Nodes', **props)
        print("DONE!")

        # Extract nodeID from the results
        self._nodeid = self._parse_node(self._results)

    def _parse_node(self, results):
        return re.search('(\d+)$', self._results).group(0)

    def _node_pollers(self):

        # Setup poller status for the node
        pollers_enabled = {
            'N.Status.ICMP.Native': True,
            'N.Status.SNMP.Native': False,
            'N.ResponseTime.ICMP.Native': True,
            'N.ResponseTime.SNMP.Native': False,
            'N.Details.SNMP.Generic': True,
            'N.Uptime.SNMP.Generic': True,
            'N.Cpu.SNMP.HrProcessorLoad': True,
            'N.Memory.SNMP.NetSnmpReal': True,
            'N.AssetInventory.Snmp.Generic': True,
            'N.Topology_Layer3.SNMP.ipNetToMedia': False,
            'N.Routing.SNMP.Ipv4CidrRoutingTable': False
        }

        pollers = []
        for k in pollers_enabled:
            pollers.append({
                'PollerType': k,
                'NetObject': 'N:' + self._nodeid,
                'NetObjectType': 'N',
                'NetObjectID': self._nodeid,
                'Enabled': pollers_enabled[k]
            })

        # Add node to pollers
        for poller in pollers:
            print("  Adding poller type: {} with status {}... ".format(
                poller['PollerType'], poller['Enabled']),
                  end="")
            response = self._swis.create('Orion.Pollers', **poller)
            print("DONE!")

    def _node_custom_props(self, **node):

        # Copy 'node' dict to new dict 'props' and remove keys not relative to custom properties
        props = node
        ignore_keys = ('IPAddress', 'Caption', 'NodeGroup', 'DeviceTemplate',
                       'ConnectionProfile')
        for k in ignore_keys:
            props.pop(k, None)

        # Add custom properties to node
        for k, v in props.items():
            print("  Adding custom property: {} with value {}... ".format(
                k, v),
                  end="")
            self._swis.update(self._results + '/CustomProperties', **{k: v})
            print("DONE!")

    def _poll(self):

        # Poll the node
        print("  Polling node... ", end="")
        self._swis.invoke('Orion.Nodes', 'PollNow', 'N:' + self._nodeid)
        print("DONE!")

    def _node_ncm(self, **node):

        # Add node to NCM
        self._swis.invoke('Cirrus.Nodes', 'AddNodeToNCM', self._nodeid)

        # Lookup the NCM NodeID, which is a Guid
        ncmNodeID = self._swis.query(
            'SELECT NodeID FROM Cirrus.Nodes WHERE CoreNodeID=@node',
            node=self._nodeid)['results'][0]['NodeID']

        # Fetch the NCM Node object
        ncmNode = self._swis.invoke('Cirrus.Nodes', 'GetNode', ncmNodeID)

        # Modify our local copy of the NCM Node object
        ncmNode['ConnectionProfile'] = node['ConnectionProfile']
        ncmNode['DeviceTemplate'] = node['DeviceTemplate']
        ncmNode['NodeGroup'] = node['NodeGroup']

        # Commit our changes
        print("  Adding node to NCM... ", end="")
        self._swis.invoke('Cirrus.Nodes', 'UpdateNode', ncmNode)
        print("DONE!")
Exemplo n.º 6
0
class OrionBaseAction(Action):
    def __init__(self, config):
        super(OrionBaseAction, self).__init__(config)

        self.client = None

        if "orion_host" not in self.config:
            raise ValueError("Orion host details not in the config.yaml")
        elif "orion_user" not in self.config:
            raise ValueError("Orion user details not in the config.yaml")
        elif "orion_password" not in self.config:
            raise ValueError("Orion password details not in the config.yaml")

    def connect(self):
        """
        Connect to the Orion server listed in the config.
        """

        self.client = SwisClient(self.config['orion_host'],
                                 self.config['orion_user'],
                                 self.config['orion_password'])

        return self.config['orion_label']

    def get_node(self, node):
        """
        Get an OrionNode object
        """

        orion_node = OrionNode()

        if is_ip(node):
            query_for_where = "IPAddress"
        else:
            query_for_where = "Caption"

        swql = """SELECT NodeID, Uri, IPAddress, Caption
        FROM Orion.Nodes
        WHERE {}=@query_on""".format(query_for_where)
        kargs = {'query_on': node}
        data = self.query(swql, **kargs)

        if 'results' not in data:
            msg = "No results from Orion: {}".format(data)
            self.logger.info(msg)
            raise Exception(msg)

        if len(data['results']) == 1:
            try:
                orion_node.npm_id = data['results'][0]['NodeID']
                orion_node.uri = data['results'][0]['Uri']
                orion_node.ip_address = data['results'][0]['IPAddress']
                orion_node.caption = data['results'][0]['Caption']
            except IndexError:
                pass
        elif len(data['results']) >= 2:
            self.logger.debug(
                "Muliple Nodes match '{}' Caption: {}".format(
                    node, data))
            raise ValueError("Muliple Nodes match '{}' Caption".format(
                node))

        if orion_node.npm:
            swql = """SELECT NodeID
            FROM Cirrus.Nodes
            WHERE CoreNodeID=@CoreNodeID"""
            kargs = {'CoreNodeID': orion_node.npm_id}
            data = self.query(swql, **kargs)

            # Don't raise an exception if this fails.
            # The platform may not haev NCM installed.
            if 'results' not in data:
                msg = "No results from Orion NCM: {}".format(data)
                self.logger.info(msg)
            elif len(data['results']) == 1:
                try:
                    orion_node.ncm_id = data['results'][0]['NodeID']
                except IndexError:
                    pass

        return orion_node

    def query(self, swql, **kargs):
        """
        Run SWQL against the Orion Platform.
        """
        return self.client.query(swql, **kargs)

    def invoke(self, entity, verb, *args):
        """
        Run an Invoke against the Orion Platform.
        """
        return self.client.invoke(entity, verb, *args)

    def create(self, entity, **kargs):
        """
        Run an Create against the Orion Platform.
        """
        return self.client.create(entity, **kargs)

    def read(self, uri):
        """
        Run an Read against the Orion Platform.
        """
        return self.client.read(uri)

    def update(self, uri, **kargs):
        """
        Run an Update against the Orion Platform.
        """
        return self.client.update(uri, **kargs)

    def delete(self, uri):
        """
        Run an Delete of an URI against the Orion Platform.
        """
        return self.client.delete(uri)

    def get_snmp_community(self, community):
        """
        Return the correct SNMP comminity to use.
        """
        if community == "customer":
            return self.config['snmp_customer']
        elif community == "internal":
            return self.config['snmp_internal']
        elif community is None:
            return self.config['snmp_default']
        else:
            return community

    def get_snmp_cred_id(self, community):
        """
        Look up an SNMP community in the config and then look up
        the Orion ID for the Credential.
        """

        # Check if the community should be replaced.
        name = self.get_snmp_community(community)

        swql = """SELECT ID FROM Orion.Credential
        WHERE CredentialType=@CredentialType and Name=@name"""

        kargs = {'CredentialType':
                 'SolarWinds.Orion.Core.Models.Credentials.SnmpCredentialsV2',
                 'name': name}
        orion_data = self.query(swql, **kargs)

        if len(orion_data['results']) == 1:
            return orion_data['results'][0]['ID']
        else:
            msg = "Could not get ID for community in Orion.Credential: {}".format(
                community)
            send_user_error(msg)
            raise ValueError(msg)

    def get_engine_id(self, poller):
        """
        Takes a poller name (or primary) and returns the EngineID for
        the poller.

        Raises: ValueError on an invaild poller.

        Returns: The EngineID (int)
        """

        if poller == "primary":
            return 1
        else:
            swql = """SELECT EngineID, ServerName, IP, ServerType
            FROM Orion.Engines
            WHERE ServerName=@poller"""
            kargs = {'poller': poller}
            data = self.query(swql, **kargs)

            if len(data['results']) == 1:
                return data['results'][0]['EngineID']
            else:
                send_user_error("Invalid poller name")
                raise ValueError("Invalid poller name")

    def get_ncm_transfer_results(self, transfer_id, sleep_delay=10):
        """
        Gets the completed (waits until finished). NCM job transfer status
        from Orion.

        Retruns: The completed status.
        """
        ts = {}
        while True:
            swql = """SELECT TransferID, NodeID, Action, RequestedConfigType,
            RequestedScript, RequestedReboot, ConfigID, TransferProtocol,
            Status, ErrorMessage, DeviceOutput, DateTime, UserName
            FROM NCM.TransferResults
            WHERE TransferID=@transfer_id"""
            kargs = {'transfer_id': transfer_id}

            transfer_data = self.query(swql, **kargs)
            status = transfer_data['results'][0]['Status']

            if status == 1:
                time.sleep(sleep_delay)
            elif status == 2:
                ts['status'] = "Complete"
                break
            elif status == 3:
                ts['status'] = "Error"
                break
            else:
                ts['status'] = "Unknown"
                break

        ts['RequestedScript'] = transfer_data['results'][0]['RequestedScript']
        ts['RequestedReboot'] = transfer_data['results'][0]['RequestedReboot']
        ts['ErrorMessage'] = transfer_data['results'][0]['ErrorMessage']
        ts['DeviceOutput'] = transfer_data['results'][0]['DeviceOutput']
        ts['UserName'] = transfer_data['results'][0]['UserName']

        return ts
Exemplo n.º 7
0
class OrionBaseAction(Action):
    def __init__(self, config):
        super(OrionBaseAction, self).__init__(config)

        self.client = None

        if "orion_host" not in self.config:
            raise ValueError("Orion host details not in the config.yaml")
        elif "orion_user" not in self.config:
            raise ValueError("Orion user details not in the config.yaml")
        elif "orion_password" not in self.config:
            raise ValueError("Orion password details not in the config.yaml")

    def connect(self):
        """
        Connect to the Orion server listed in the config.
        """

        self.client = SwisClient(self.config['orion_host'],
                                 self.config['orion_user'],
                                 self.config['orion_password'])

        return self.config['orion_label']

    def get_node(self, node):
        """
        Get an OrionNode object
        """

        orion_node = OrionNode()

        if is_ip(node):
            query_for_where = "IPAddress"
        else:
            query_for_where = "Caption"

        swql = """SELECT NodeID, Uri, IPAddress, Caption
        FROM Orion.Nodes
        WHERE {}=@query_on""".format(query_for_where)
        kargs = {'query_on': node}
        data = self.query(swql, **kargs)

        if 'results' not in data:
            msg = "No results from Orion: {}".format(data)
            self.logger.info(msg)
            raise Exception(msg)

        if len(data['results']) == 1:
            try:
                orion_node.npm_id = data['results'][0]['NodeID']
                orion_node.uri = data['results'][0]['Uri']
                orion_node.ip_address = data['results'][0]['IPAddress']
                orion_node.caption = data['results'][0]['Caption']
            except IndexError:
                pass
        elif len(data['results']) >= 2:
            self.logger.debug("Muliple Nodes match '{}' Caption: {}".format(
                node, data))
            raise ValueError("Muliple Nodes match '{}' Caption".format(node))

        if orion_node.npm:
            swql_ncm = """SELECT NodeID
            FROM Cirrus.Nodes
            WHERE CoreNodeID=@CoreNodeID"""
            kargs = {'CoreNodeID': orion_node.npm_id}
            try:
                data_ncm = self.query(swql_ncm, **kargs)
            except requests.exceptions.HTTPError:
                # Create an empty dict to allow remaining code to fail gracefully
                data_ncm = {}
                self.logger.info("Connection to NCM failed. NCM not installed")

            # Don't raise an exception if this fails.
            # The platform may not have NCM installed.
            if 'results' not in data_ncm:
                msg = "No results from Orion NCM: {}".format(data_ncm)
                self.logger.info(msg)
            elif len(data_ncm['results']) == 1:
                try:
                    orion_node.ncm_id = data_ncm['results'][0]['NodeID']
                except IndexError:
                    pass

            data_agent = self.get_agent(orion_node.npm_id)

            if data_agent:
                try:
                    orion_node.agent_id = data_agent['AgentID']
                    orion_node.agent_uri = data_agent['Uri']
                except IndexError:
                    pass

        return orion_node

    def get_agent(self, query_param):
        """ Searches for an agent by the ip address or the
        node_id
        """
        if is_ip(query_param):
            query_for_where = "IP"
        elif isinstance(query_param, int):
            query_for_where = "NodeId"
        else:
            query_for_where = "Name"

        swql_agent = """SELECT AgentID, Uri
        FROM Orion.AgentManagement.Agent
        WHERE {}=@query_on""".format(query_for_where)
        kargs = {'query_on': query_param}
        data_agent = self.query(swql_agent, **kargs)

        # Since there might not always be an agent we
        # will not raise if the results do not return anything
        if 'results' not in data_agent or len(data_agent['results']) == 0:
            msg = "No Orion Agent found: {}".format(data_agent)
            self.logger.info(msg)
            return None

        if len(data_agent['results']) >= 2:
            self.logger.debug("Muliple Agents match '{}' Caption: {}".format(
                query_param, data_agent))
            raise ValueError(
                "Muliple Agents match '{}' Caption".format(query_param))

        return data_agent['results'][0]

    def query(self, swql, **kargs):
        """
        Run SWQL against the Orion Platform.
        """
        return self.client.query(swql, **kargs)

    def invoke(self, entity, verb, *args):
        """
        Run an Invoke against the Orion Platform.
        """
        return self.client.invoke(entity, verb, *args)

    def create(self, entity, **kargs):
        """
        Run an Create against the Orion Platform.
        """
        return self.client.create(entity, **kargs)

    def read(self, uri):
        """
        Run an Read against the Orion Platform.
        """
        return self.client.read(uri)

    def update(self, uri, **kargs):
        """
        Run an Update against the Orion Platform.
        """
        return self.client.update(uri, **kargs)

    def delete(self, uri):
        """
        Run an Delete of an URI against the Orion Platform.
        """
        return self.client.delete(uri)

    def get_snmp_community(self, community):
        """
        Return the correct SNMP comminity to use.
        """
        if community == "customer":
            return self.config['snmp_customer']
        elif community == "internal":
            return self.config['snmp_internal']
        elif community is None:
            return self.config['snmp_default']
        else:
            return community

    def get_snmp_cred_id(self, community):
        """
        Look up an SNMP community in the config and then look up
        the Orion ID for the Credential.
        """

        # Check if the community should be replaced.
        name = self.get_snmp_community(community)

        swql = """SELECT ID FROM Orion.Credential
        WHERE CredentialType=@CredentialType and Name=@name"""

        kargs = {
            'CredentialType':
            'SolarWinds.Orion.Core.Models.Credentials.SnmpCredentialsV2',
            'name': name
        }
        orion_data = self.query(swql, **kargs)

        if len(orion_data['results']) == 1:
            return orion_data['results'][0]['ID']
        else:
            msg = "Could not get ID for community in Orion.Credential: {}".format(
                community)
            send_user_error(msg)
            raise ValueError(msg)

    def get_engine_id(self, poller):
        """
        Takes a poller name (or primary) and returns the EngineID for
        the poller.

        Raises: ValueError on an invaild poller.

        Returns: The EngineID (int)
        """

        if poller == "primary":
            return 1
        else:
            swql = """SELECT EngineID, ServerName, IP, ServerType
            FROM Orion.Engines
            WHERE ServerName=@poller"""
            kargs = {'poller': poller}
            data = self.query(swql, **kargs)

            if len(data['results']) == 1:
                return data['results'][0]['EngineID']
            else:
                send_user_error("Invalid poller name")
                raise ValueError("Invalid poller name")

    def get_ncm_transfer_results(self, transfer_id, sleep_delay=10):
        """
        Gets the completed (waits until finished). NCM job transfer status
        from Orion.

        Retruns: The completed status.
        """
        ts = {}
        while True:
            swql = """SELECT TransferID, NodeID, Action, RequestedConfigType,
            RequestedScript, RequestedReboot, ConfigID, TransferProtocol,
            Status, ErrorMessage, DeviceOutput, DateTime, UserName
            FROM NCM.TransferResults
            WHERE TransferID=@transfer_id"""
            kargs = {'transfer_id': transfer_id}

            transfer_data = self.query(swql, **kargs)
            status = transfer_data['results'][0]['Status']

            if status == 1:
                time.sleep(sleep_delay)
            elif status == 2:
                ts['status'] = "Complete"
                break
            elif status == 3:
                ts['status'] = "Error"
                break
            else:
                ts['status'] = "Unknown"
                break

        ts['RequestedScript'] = transfer_data['results'][0]['RequestedScript']
        ts['RequestedReboot'] = transfer_data['results'][0]['RequestedReboot']
        ts['ErrorMessage'] = transfer_data['results'][0]['ErrorMessage']
        ts['DeviceOutput'] = transfer_data['results'][0]['DeviceOutput']
        ts['UserName'] = transfer_data['results'][0]['UserName']

        return ts
Exemplo n.º 8
0
class OrionBaseAction(Action):
    def __init__(self, config):
        super(OrionBaseAction, self).__init__(config)

        self.client = None

        if "orion" not in self.config:
            raise ValueError("Orion host details not in the config.yaml")

    def connect(self, platform):
        """
        Connect to an Orion platform from the packs config.yaml.
        """
        if platform is None:
            try:
                platform = self.config['defaults']['platform']
            except IndexError:
                send_user_error("No default Orion platform.")
                raise ValueError("No default Orion platform.")

        self.logger.debug("Connecting to Orion platform: {}".format(platform))

        try:
            self.client = SwisClient(
                self.config['orion'][platform]['host'],
                self.config['orion'][platform]['user'],
                self.config['orion'][platform]['password'])
        except KeyError:
            raise ValueError("Orion host details not in the config.yaml")

        return platform

    def get_node(self, node):
        """
        Get an OrionNode object
        """

        orion_node = OrionNode()

        if is_ip(node):
            query_for_where = "IPAddress"
        else:
            query_for_where = "Caption"

        swql = """SELECT NodeID, Uri, IPAddress, Caption
        FROM Orion.Nodes
        WHERE {}=@query_on""".format(query_for_where)
        kargs = {'query_on': node}
        data = self.query(swql, **kargs)

        if 'results' not in data:
            msg = "No results from Orion: {}".format(data)
            self.logger.info(msg)
            raise Exception(msg)

        if len(data['results']) == 1:
            try:
                orion_node.npm_id = data['results'][0]['NodeID']
                orion_node.uri = data['results'][0]['Uri']
                orion_node.ip_address = data['results'][0]['IPAddress']
                orion_node.caption = data['results'][0]['Caption']
            except IndexError:
                pass
        elif len(data['results']) >= 2:
            self.logger.debug(
                "Muliple Nodes match '{}' Caption: {}".format(
                    node, data))
            raise ValueError("Muliple Nodes match '{}' Caption".format(
                node))

        if orion_node.npm:
            swql = """SELECT NodeID
            FROM Cirrus.Nodes
            WHERE CoreNodeID=@CoreNodeID"""
            kargs = {'CoreNodeID': orion_node.npm_id}
            data = self.query(swql, **kargs)

            # Don't raise an exception if this fails.
            # The platform may not haev NCM installed.
            if 'results' not in data:
                msg = "No results from Orion NCM: {}".format(data)
                self.logger.info(msg)
            elif len(data['results']) == 1:
                try:
                    orion_node.ncm_id = data['results'][0]['NodeID']
                except IndexError:
                    pass

        return orion_node

    def query(self, swql, **kargs):
        """
        Run SWQL against the Orion Platform.
        """
        return self.client.query(swql, **kargs)

    def invoke(self, entity, verb, *args):
        """
        Run an Invoke against the Orion Platform.
        """
        return self.client.invoke(entity, verb, *args)

    def create(self, entity, **kargs):
        """
        Run an Create against the Orion Platform.
        """
        return self.client.create(entity, **kargs)

    def read(self, uri):
        """
        Run an Read against the Orion Platform.
        """
        return self.client.read(uri)

    def update(self, uri, **kargs):
        """
        Run an Update against the Orion Platform.
        """
        return self.client.update(uri, **kargs)

    def delete(self, uri):
        """
        Run an Delete of an URI against the Orion Platform.
        """
        return self.client.delete(uri)

    def get_snmp_community(self, community, std_community):
        """
        Return the correct SNMP comminity to use.
        """
        if community is not None:
            return community
        elif std_community is not None:
            try:
                return self.config['defaults']['snmp'][std_community]
            except KeyError:
                raise ValueError("Invalid standard community")
        elif std_community is None:
            raise ValueError("Need one of community or std_community")

    def get_snmp_cred_id(self, community):
        """
        Look up an SNMP community in the config and then look up
        the Orion ID for the Credential.
        """

        # Check if community is a know standard, otherwise
        # use it as the community.
        try:
            name = self.get_snmp_community(None, community)
        except ValueError:
            name = community

        swql = """SELECT ID FROM Orion.Credential
        WHERE CredentialType=@CredentialType and Name=@name"""

        kargs = {'CredentialType':
                 'SolarWinds.Orion.Core.Models.Credentials.SnmpCredentialsV2',
                 'name': name}
        orion_data = self.query(swql, **kargs)

        if len(orion_data['results']) == 1:
            return orion_data['results'][0]['ID']
        else:
            msg = "Could not get ID for community in Orion.Credential: {}".format(
                community)
            send_user_error(msg)
            raise ValueError(msg)

    def get_engine_id(self, poller):
        """
        Takes a poller name (or primary) and returns the EngineID for
        the poller.

        Raises: ValueError on an invaild poller.

        Returns: The EngineID (int)
        """

        if poller == "primary":
            return 1
        else:
            swql = """SELECT EngineID, ServerName, IP, ServerType
            FROM Orion.Engines
            WHERE ServerName=@poller"""
            kargs = {'poller': poller}
            data = self.query(swql, **kargs)

            if len(data['results']) == 1:
                return data['results'][0]['EngineID']
            else:
                send_user_error("Invalid poller name")
                raise ValueError("Invalid poller name")

    def get_ncm_transfer_results(self, transfer_id, sleep_delay=10):
        """
        Gets the completed (waits until finished). NCM job transfer status
        from Orion.

        Retruns: The completed status.
        """
        ts = {}
        while True:
            swql = """SELECT TransferID, NodeID, Action, RequestedConfigType,
            RequestedScript, RequestedReboot, ConfigID, TransferProtocol,
            Status, ErrorMessage, DeviceOutput, DateTime, UserName
            FROM NCM.TransferResults
            WHERE TransferID=@transfer_id"""
            kargs = {'transfer_id': transfer_id}

            transfer_data = self.query(swql, **kargs)
            status = transfer_data['results'][0]['Status']

            if status == 1:
                time.sleep(sleep_delay)
            elif status == 2:
                ts['status'] = "Complete"
                break
            elif status == 3:
                ts['status'] = "Error"
                break
            else:
                ts['status'] = "Unknown"
                break

        ts['RequestedScript'] = transfer_data['results'][0]['RequestedScript']
        ts['RequestedReboot'] = transfer_data['results'][0]['RequestedReboot']
        ts['ErrorMessage'] = transfer_data['results'][0]['ErrorMessage']
        ts['DeviceOutput'] = transfer_data['results'][0]['DeviceOutput']
        ts['UserName'] = transfer_data['results'][0]['UserName']

        return ts
Exemplo n.º 9
0
class Orion():

    def __init__(self):
        
        # start the connection
        self.server = 'server fqdn or ip'
        self.username = '******'
        self.password = '******'

        self.con = SwisClient(self.server,self.username,self.password)

        requests.packages.urllib3.disable_warnings()  

    def get_all_juniper_node_ids(self, **kwargs):

        self.q = self.con.query('SELECT NodeID,Caption FROM Orion.Nodes WHERE Vendor LIKE @vendor', vendor='Juniper%')
        return self.q

    def get_all_cisco_node_ids(self, **kwargs):

        self.q = self.con.query('SELECT NodeID,Caption FROM Orion.Nodes WHERE Vendor LIKE @vendor', vendor='Cisco')
        return self.q

    def npm_add_node(self, **kwargs):

        s = Settings()
        settings = s.get_all_settings()

        # first check this device isn't already in Orion
        self.ip_check = self.con.query('SELECT NodeID FROM Orion.Nodes WHERE IPAddress=@ip_address', ip_address=kwargs.get('ip_address'))
        self.hostname_check = self.con.query('SELECT NodeID FROM Orion.Nodes WHERE Caption=@hostname', hostname=kwargs.get('hostname'))
        if len(self.ip_check['results']) > 0 or len(self.hostname_check['results']) > 0:

            # if this is greater than 0, then the device already exists in orion
            return

        else:

            # assign the device poperties for adding to the database
            # support only for SNMPv2 at this stage
            self.properties = {
                'Caption': kwargs.get('hostname'),
                'IPAddress': kwargs.get('ip_address'),
                'DynamicIP': False,
                'EngineID': kwargs.get('engine_id') or 1, 
                'Status': 1,
                'Allow64BitCounters': 1,
                'ObjectSubType': 'SNMP',
                'SNMPVersion': kwargs.get('snmp_version') or 2,
                'Community': kwargs.get('community'),
                # Set NextRediscovery to now + 2 mins so that rediscovery happens at the next rediscovery interval, default 30mins
                'NextRediscovery': datetime.datetime.now() + datetime.timedelta(minutes = 2)
            }

            # create the node
            self.results = self.con.create('Orion.Nodes', **self.properties)

            # get the NodeID
            self.node_id = re.search('(\d+)$', self.results).group(0)

            # setup device pollers
            self.pollers_enabled = {
                'N.Status.ICMP.Native': True,
                'N.Status.SNMP.Native': False,
                'N.ResponseTime.ICMP.Native': True,
                'N.ResponseTime.SNMP.Native': False,
                'N.Details.SNMP.Generic': True,
                'N.Uptime.SNMP.Generic': True,
                'N.Cpu.SNMP.HrProcessorLoad': True,
                'N.Memory.SNMP.NetSnmpReal': True,
                'N.AssetInventory.Snmp.Generic': True,
                'N.Topology_Layer3.SNMP.ipNetToMedia': False,
                'N.Routing.SNMP.Ipv4CidrRoutingTable': False
            }  

            # create a list of dictionarys for each poller
            self.pollers = []
            for self.k in self.pollers_enabled:
                self.pollers.append(
                    {
                        'PollerType': self.k,
                        'NetObject': 'N:' + self.node_id,
                        'NetObjectType': 'N',
                        'NetObjectID': self.node_id,
                        'Enabled': self.pollers_enabled[self.k]
                    }
                )

            # loop through pollers and turn them on
            for self.poller in self.pollers:
                 self.response = self.con.create('Orion.Pollers', **self.poller)

            # add the custom properties
            self.results = self.con.query(
                "SELECT Uri FROM Orion.Nodes WHERE NodeID=@id",
                id=self.node_id
            )

            # grab the uri - whatever this is
            self.uri = self.results['results'][0]['Uri']

            # update the custom properties
            self.con.update(
                self.uri + '/CustomProperties',
                City = kwargs.get('city'),
                Site = kwargs.get('site'),
                Network = kwargs.get('network')
            )

            return self.node_id

    def npm_add_interfaces(self, node_id):

        # run interface discovery
        self.interfaces = self.con.invoke('Orion.NPM.Interfaces', 'DiscoverInterfacesOnNode', node_id)
        # imports only interfaces with a description
        # alternatively any physical Cisco interfaces with and up status could be added
        self.descr_only = [
            self.x for self.x
            in self.interfaces['DiscoveredInterfaces']
            if re.search('\xb7', self.x['Caption'])
        ]

        # add the interfaces
        self.execute = self.con.invoke(
            'Orion.NPM.Interfaces',
            'AddInterfacesOnNode',
            node_id,
            self.descr_only,
            'AddDefaultPollers'
        )

    def npm_poll_now(self, node_id, **kwargs):
        self.con.invoke('Orion.Nodes', 'PollNow', 'N:%s' % self.node_id)

    def ncm_add_node(self, node_id, **kwargs):

        s = Settings()
        settings = s.get_all_settings()

        # check that device isn't already managed in Orion NCM
        self.ip_check = self.con.query('SELECT NodeID FROM Cirrus.Nodes WHERE AgentIP=@ip_address', ip_address=kwargs.get('ip_address'))
        self.hostname_check = self.con.query('SELECT NodeID FROM Cirrus.Nodes WHERE NodeCaption=@hostname', hostname=kwargs.get('hostname'))
        if len(self.ip_check['results']) > 0 or len(self.hostname_check['results']) > 0:
            
            # if this is greater than 0, then the device already exists in orion
            return

        else:

            self.con.invoke('Cirrus.Nodes', 'AddNodeToNCM', node_id)

            # now update the selected columns to ensure we can log into this device
            # first using rhe NodeID from Orion.NPM get the Guid
            self.ncm_node_id = self.con.query('SELECT NodeID FROM Cirrus.Nodes WHERE CoreNodeID=@node', node=node_id)['results'][0]['NodeID']  

            # fetch the NCM Node Object
            self.ncm_node_data = self.con.invoke('Cirrus.Nodes', 'GetNode', self.ncm_node_id)

            # verfify that the submitted connection_profile exists
            # if it doesn't set the profile to '-1'
            self.profiles = self.con.invoke('Cirrus.Nodes', 'GetAllConnectionProfiles')
            for self.pro in self.profiles:
                if self.pro['ID'] == kwargs.get('connection_profile'):
                    self.connection_profile_id = kwargs.get('connection_profile')
                else:
                    self.connection_profile_id = -1

            # modify the device properties but only if the submitted profile is valid
            if self.connection_profile_id != -1:
                self.ncm_node_data['Username'] = ''
                self.ncm_node_data['Password'] = ''
                self.ncm_node_data['ConnectionProfile'] = self.connection_profile_id 

             # Commit our changes  
            self.con.invoke('Cirrus.Nodes', 'UpdateNode', self.ncm_node_data)

    def ncm_get_guid(self, hostname):
        # used to determine the guid for a hostname as it exists in Orion NCM
        self.node_id = self.con.query("SELECT NodeID FROM Cirrus.Nodes WHERE NodeCaption=@node", node=hostname)
        if self.node_id is not None:
            return self.node_id
        else:
            return False


    def ncm_download_configs(self, hostname):
        # cannot be called until a device has been discovered, this action in Orion depends on a known sysObjectID OID

        # get the System.Guid[] into a list, if submitted as a simple string the API errors out
        # HTTPError: 400 Client Error: Verb Cirrus.ConfigArchive.DownloadConfig cannot unpackage parameter 0 with type System.Guid[] \
        # for url: https://lab-win2012.it-ninja.xyz:17778/SolarWinds/InformationService/v3/Json/Invoke/Cirrus.ConfigArchive/DownloadConfig
        self.node_ids = []
        self.node_data = self.con.query("SELECT NodeID FROM Cirrus.Nodes WHERE NodeCaption=@node", node=hostname)
        self.node_ids.append(self.node_data['results'][0]['NodeID'])

        configs = ['Active', 'Set', 'Rescue']
        for c in configs:
            self.con.invoke("Cirrus.ConfigArchive",  "DownloadConfig", self.node_ids, c)

    def get_connection_profiles(self):
        self.profiles = self.con.invoke('Cirrus.Nodes', 'GetAllConnectionProfiles')
        return self.profiles

    def ncm_remove_node(self, hostname):
        # used to unmange a node from Orion NCM
        # called pre-delete node from Orion NPM
        self.node_id = self.ncm_get_guid(hostname)
        if self.node_id is not False:
            self.con.invoke("Cirrus.Nodes",  "RemoveNode", self.node_id)

    def npm_get_uri(self, hostname):
        # used to get the node_id of a pre-existing node in Orion NPM

        self.node_uri = self.con.query("SELECT Uri FROM Orion.Nodes WHERE Caption=@hostname", hostname=hostname)
        return self.node_uri

    def npm_delete_node(self, hostname):
        
        # get the devices uri.  This is a list of dictionaries
        self.node_uri = self.npm_get_uri(hostname)
        # call swis to delete the node
        if self.node_uri is not False:
            self.con.delete(self.node_uri['results'][0]['Uri'])
def run(job=None, *args, **kwargs):
    # Disable SSL warnings
    verify = False
    if not verify:
        from requests.packages.urllib3.exceptions import InsecureRequestWarning
        requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

    # Get SolarWinds ConnectionInfo
    solarwinds = ConnectionInfo.objects.get(name='SolarWinds')
    swis = SwisClient(solarwinds.ip, solarwinds.username, solarwinds.password)
    if not solarwinds:
        return "FAILURE", "", "Missing required SolarWinds connection info. (Admin -> Connection Info -> New Connection Info)"

    # Get Server
    server = job.server_set.first()

    # Get subnet server.ip
    sep = '.'
    octets = server.ip.split(sep='.')
    network = sep.join(octets[:3] + list('0'))

    # Get next available IP from SW based on subnet
    next_ip = swis.query(
        "SELECT TOP 1 I.Status, I.DisplayName FROM IPAM.IPNode I WHERE Status=2 AND I.Subnet.Address = '{}'"
        .format(network))

    # Set the server ip
    server.ip = next_ip['results'][0]['DisplayName']
    server.save()

    # Setup Node Properties
    props = {
        'IPAddress': server.ip,
        'EngineID': 1,
        'ObjectSubType': 'Agent',
        'Caption': server.hostname,
        'DNS': server.hostname,
        'Description': 'Added by CloudBolt',
        'Contact': server.owner,
    }

    #Create the Node
    job.set_progress("Adding '{}' to SolarWinds".format(server.hostname))
    results = swis.create('Orion.Nodes', **props)

    # Extract NodeID from results
    nodeid = re.search('(\d+)$', results).group(0)

    # Setup Poller Status for the node
    pollers_enabled = {
        'N.Status.ICMP.Native': True,
        'N.Status.SNMP.Native': False,
        'N.ResponseTime.ICMP.Native': True,
        'N.ResponseTime.SNMP.Native': False,
        'N.Details.SNMP.Generic': True,
        'N.Uptime.SNMP.Generic': True,
        'N.Cpu.SNMP.HrProcessorLoad': True,
        'N.Memory.SNMP.NetSnmpReal': True,
        'N.AssetInventory.Snmp.Generic': True,
        'N.Topology_Layer3.SNMP.ipNetToMedia': False,
        'N.Routing.SNMP.Ipv4CidrRoutingTable': False
    }
    # Add Node to Pollers
    pollers = []
    for k in pollers_enabled:
        pollers.append({
            'PollerType': k,
            'NetObject': 'N:' + nodeid,
            'NetObjectType': 'N',
            'NetObjectID': nodeid,
            'Enabled': pollers_enabled[k]
        })

    for poller in pollers:
        job.set_progress("Adding poller type: '{}' with status {}...".format(
            poller['PollerType'], poller['Enabled']))
        response = swis.create('Orion.Pollers', **poller)

    #Poll the node
    swis.invoke('Orion.Nodes', 'PollNow', 'N:' + nodeid)

    return "", "", ""
Exemplo n.º 11
0
class OrionBaseAction(Action):
    def __init__(self, config):
        super(OrionBaseAction, self).__init__(config)

        self.client = None

        if "orion" not in self.config:
            raise ValueError("Orion host details not in the config.yaml")

    def connect(self, platform):
        """
        Connect to an Orion platform from the packs config.yaml.
        """
        try:
            self.client = SwisClient(
                self.config['orion'][platform]['host'],
                self.config['orion'][platform]['user'],
                self.config['orion'][platform]['password'])
        except KeyError:
            raise ValueError("Orion host details not in the config.yaml")

    def query(self, swql, **kargs):
        """
        Run SWQL against the Orion Platform.
        """
        return self.client.query(swql, **kargs)

    def invoke(self, entity, verb, *args):
        """
        Run an Invoke against the Orion Platform.
        """
        return self.client.invoke(entity, verb, *args)

    def create(self, entity, **kargs):
        """
        Run an Create against the Orion Platform.
        """
        return self.client.create(entity, **kargs)

    def node_exists(self, caption, ip_address):
        """
        Check if an Node exists (caption and or ip) on the Orion platform.

        Returns: True or False.
        """
        swql = """SELECT NodeID, IPAddress FROM Orion.Nodes
                  WHERE Caption=@caption"""
        kargs = {'caption': caption}
        caption_data = self.query(swql, **kargs)

        if len(caption_data['results']) >= 1:
            self.logger.debug(
                "One (or more) Nodes match '{}' Caption.".format(caption))
            return True

        swql = """SELECT NodeID, IPAddress FROM Orion.Nodes
                  WHERE IPAddress=@ip_address"""
        kargs = {'ip_address': ip_address}
        ip_data = self.query(swql, **kargs)

        if len(ip_data['results']) >= 1:
            self.logger.debug(
                "One (or more) Nodes match '{}' IP.".format(ip_address))
            return True
        else:
            return False

    def get_node_id(self, caption):
        """
        Gets an NodeID from the Orion platform.

        Raises: ValueError on muliple or no matching caption.

        Returns: the NodeID (int)
        """
        swql = "SELECT NodeID FROM Orion.Nodes WHERE Caption=@caption"
        kargs = {'caption': caption}
        data = self.query(swql, **kargs)

        if len(data['results']) == 1:
            try:
                return data['results'][0]['NodeID']
            except IndexError:
                raise ValueError("Invalid Node")
        elif len(data['results']) >= 2:
            self.logger.debug("Muliple Nodes match '{}' Caption: {}".format(
                caption, data))
            raise ValueError(
                "Muliple Nodes match '{}' Caption".format(caption))
        elif len(data['results']) == 0:
            self.logger.debug("No Nodes match '{}' Caption: {}".format(
                caption, data))
            raise ValueError("No matching Caption for '{}'".format(caption))

    def get_engine_id(self, poller):
        """
        Takes a poller name (or primary) and returns the EngineID for
        the poller.

        Raises: ValueError on an invaild poller.

        Returns: The EngineID (int)
        """

        if poller == "primary":
            return 1
        else:
            swql = """SELECT EngineID, ServerName, IP, ServerType
            FROM Orion.Engines
            WHERE ServerName=@poller"""
            kargs = {'poller': poller}
            data = self.query(swql, **kargs)

            if len(data['results']) == 1:
                return data['results'][0]['EngineID']
            else:
                self.send_user_error("Invalid poller name")
                raise ValueError("Invalid poller name")

    def get_ncm_node_id(self, caption):
        """
        Queries the Network configuration Manager nodes table on the Orion
        platform for the NodeID of a given node name (aka NodeCaption).

        Raises: IndexError on Invalid number of nodes (e.g. 0 or 2+).

        Returns: A single node id.
        """

        swql = "SELECT NodeID FROM Cirrus.Nodes WHERE NodeCaption=@node"
        kargs = {'node': caption}
        data = self.query(swql, **kargs)

        if len(data['results']) == 1:
            try:
                return data['results'][0]['NodeID']
            except IndexError:
                raise IndexError("Invalid Node")
        elif len(data['results']) >= 2:
            raise IndexError(
                "Muliple Nodes match '{}' NodeCaption".format(caption))
        elif len(data['results']) == 0:
            raise IndexError(
                "No matching NodeCaption for '{}'".format(caption))

    def get_ncm_transfer_results(self, transfer_id, sleep_delay=10):
        """
        Gets the completed (waits until finished). NCM job transfer status
        from Orion.

        Retruns: The completed status.
        """
        ts = {}
        while True:
            swql = """SELECT TransferID, Action, Status, ErrorMessage,
            DeviceOutput FROM NCM.TransferResults
            WHERE TransferID=@transfer_id"""
            kargs = {'transfer_id': transfer_id}

            transfer_data = self.query(swql, **kargs)
            status = transfer_data['results'][0]['Status']

            if status == 1:
                time.sleep(sleep_delay)
            elif status == 2:
                ts['status'] = "Complete"
                break
            elif status == 3:
                ts['status'] = "Error"
                ts['ErrorMessage'] = transfer_data['results'][0][
                    'ErrorMessage']
                break
            else:
                ts['status'] = "Unknown"
                ts['ErrorMessage'] = "Invalid stauts: {}".format(status)
                break

        return ts

    def status_code_to_text(self, status):
        """
        Takes an Solarwinds Orion status code and translates it to
        human text and also a colour that can be used in Slack.
        """

        if status == 0:
            return ("Unknown", "grey")
        elif status == 1:
            return ("Up", "good")
        elif status == 2:
            return ("Down", "danger")
        elif status == 3:
            return ("Warning", "warning")
        elif status == 14:
            return ("Critical", "danger")

    def send_user_error(self, message):
        """
        Prints an user error message.
        """
        print(message)
Exemplo n.º 12
0
def main(ip, ctrel, pci, province, sbu, sitename):
    npm_server = ''
    username = ''
    password = ''

    target_node_ip = ip
    snmpv3_credential_id = 6
    orion_engine_id = 1

    swis = SwisClient(npm_server, username, password)
    print("Add an SNMP v3 node:")

    corePluginContext = {
        'BulkList': [{
            'Address': target_node_ip
        }],
        'Credentials': [{
            'CredentialID': snmpv3_credential_id,
            'Order': 1
        }],
        'WmiRetriesCount': 0,
        'WmiRetryIntervalMiliseconds': 1000
    }

    corePluginConfig = swis.invoke('Orion.Discovery',
                                   'CreateCorePluginConfiguration',
                                   corePluginContext)

    discoveryProfile = {
        'Name': 'API discovery',
        'EngineID': orion_engine_id,
        'JobTimeoutSeconds': 3600,
        'SearchTimeoutMiliseconds': 5000,
        'SnmpTimeoutMiliseconds': 5000,
        'SnmpRetries': 2,
        'RepeatIntervalMiliseconds': 1800,
        'SnmpPort': 161,
        'HopCount': 0,
        'PreferredSnmpVersion': 'SNMP3',
        'DisableIcmp': False,
        'AllowDuplicateNodes': False,
        'IsAutoImport': True,
        'IsHidden': True,
        'PluginConfigurations': [{
            'PluginConfigurationItem': corePluginConfig
        }]
    }

    print("Running discovery...")
    discoveryProfileID = swis.invoke('Orion.Discovery', 'StartDiscovery',
                                     discoveryProfile)
    print("Returned discovery profile id {}".format(discoveryProfileID))

    running = True
    while running:
        try:
            query = "SELECT Status FROM Orion.DiscoveryProfiles WHERE ProfileID = " + str(
                discoveryProfileID)
            status = swis.query(query)['results'][0]['Status']
            print("##")
        except:
            running = False
    print('Done with discovery')

    batchresults = swis.query(
        "SELECT Result, ResultDescription, ErrorMessage, BatchID FROM Orion.DiscoveryLogs WHERE ProfileID=@id",
        id=discoveryProfileID)
    batchid = batchresults['results'][0]['BatchID']
    nodeidresults = swis.query(
        "SELECT DisplayName,NetObjectID FROM Orion.DiscoveryLogItems WHERE BatchID=@id",
        id=batchid)
    netobjectid = nodeidresults['results'][0]['NetObjectID']
    nodeid = netobjectid.split(':')[1]
    print(nodeid)

    #enablehardwarehealth
    hardwarehealth = swis.invoke('Orion.HardwareHealth.HardwareInfoBase',
                                 'EnableHardwareHealth', netobjectid, 9)
    #add pollers
    pollers_enabled = {
        'N.Topology_Vlans.SNMP.VtpVlan': True,
        'N.Topology_Layer2.SNMP.Dot1dTpFdbNoVLANs': True,
        'N.Topology_CDP.SNMP.cdpCacheTable': True,
        'N.Topology_STP.SNMP.Dot1dStp': True,
        'N.Topology_PortsMap.SNMP.Dot1dBaseNoVLANs': True,
        'N.Topology_Layer3.SNMP.ipNetToMedia': True,
        'N.VRFRouting.SNMP.MPLSVPNStandard': True,
    }

    pollers = []
    for k in pollers_enabled:
        pollers.append({
            'PollerType': k,
            'NetObject': 'N:' + nodeid,
            'NetObjectType': 'N',
            'NetObjectID': nodeid,
            'Enabled': pollers_enabled[k]
        })

    for poller in pollers:
        print("  Adding poller type: {} with status {}... ".format(
            poller['PollerType'], poller['Enabled']),
              end="")
        response = swis.create('Orion.Pollers', **poller)
        print("DONE!")

    #update custom properties
    customresults = swis.query("SELECT Uri FROM Orion.Nodes WHERE NodeID=@id",
                               id=nodeid)
    uri = customresults['results'][0]['Uri']

    #swis.update(uri + '/CustomProperties', City='Brampton')
    #swis.update(uri + '/CustomProperties', Comments='Test Device')
    swis.update(uri + '/CustomProperties', CTREL_Code=ctrel)
    swis.update(uri + '/CustomProperties', PCI=pci)
    #swis.update(uri + '/CustomProperties', Postal_Code='L7A4B4')
    swis.update(uri + '/CustomProperties', Province=province)
    swis.update(uri + '/CustomProperties', SBU=sbu)
    #swis.update(uri + '/CustomProperties', Site_Contact='Anesh')
    #swis.update(uri + '/CustomProperties', Site_Contact_Number='666-666-666')
    #swis.update(uri + '/CustomProperties', Site_ID='666')
    swis.update(uri + '/CustomProperties', Site_Name=sitename)
    #swis.update(uri + '/CustomProperties', Site_Type='PROD')
    #swis.update(uri + '/CustomProperties', Street_Address='AJ Distrubution')
    swis.update(uri + '/CustomProperties', Support_Team='Corp Network')

    obj = swis.read(uri + '/CustomProperties')
    print(obj)
Exemplo n.º 13
0
class OrionBaseAction(Action):
    def __init__(self, config):
        super(OrionBaseAction, self).__init__(config)

        self.client = None

        if "orion" not in self.config:
            raise ValueError("Orion host details not in the config.yaml")

    def connect(self, platform):
        """
        Connect to an Orion platform from the packs config.yaml.
        """
        try:
            self.client = SwisClient(
                self.config['orion'][platform]['host'],
                self.config['orion'][platform]['user'],
                self.config['orion'][platform]['password'])
        except KeyError:
            raise ValueError("Orion host details not in the config.yaml")

    def query(self, swql, **kargs):
        """
        Run SWQL against the Orion Platform.
        """
        return self.client.query(swql, **kargs)

    def invoke(self, entity, verb, *args):
        """
        Run an Invoke against the Orion Platform.
        """
        return self.client.invoke(entity, verb, *args)

    def create(self, entity, **kargs):
        """
        Run an Create against the Orion Platform.
        """
        return self.client.create(entity, **kargs)

    def node_exists(self, caption, ip_address):
        """
        Check if an Node exists (caption and or ip) on the Orion platform.

        Returns: True or False.
        """
        swql = """SELECT NodeID, IPAddress FROM Orion.Nodes
                  WHERE Caption=@caption"""
        kargs = {'caption': caption}
        caption_data = self.query(swql, **kargs)

        if len(caption_data['results']) >= 1:
            self.logger.debug(
                "One (or more) Nodes match '{}' Caption.".format(caption))
            return True

        swql = """SELECT NodeID, IPAddress FROM Orion.Nodes
                  WHERE IPAddress=@ip_address"""
        kargs = {'ip_address': ip_address}
        ip_data = self.query(swql, **kargs)

        if len(ip_data['results']) >= 1:
            self.logger.debug(
                "One (or more) Nodes match '{}' IP.".format(ip_address))
            return True
        else:
            return False

    def get_node_id(self, caption):
        """
        Gets an NodeID from the Orion platform.

        Raises: ValueError on muliple or no matching caption.

        Returns: the NodeID (int)
        """
        swql = "SELECT NodeID FROM Orion.Nodes WHERE Caption=@caption"
        kargs = {'caption': caption}
        data = self.query(swql, **kargs)

        if len(data['results']) == 1:
            try:
                return data['results'][0]['NodeID']
            except IndexError:
                raise ValueError("Invalid Node")
        elif len(data['results']) >= 2:
            self.logger.debug(
                "Muliple Nodes match '{}' Caption: {}".format(
                    caption, data))
            raise ValueError("Muliple Nodes match '{}' Caption".format(
                caption))
        elif len(data['results']) == 0:
            self.logger.debug(
                "No Nodes match '{}' Caption: {}".format(
                    caption, data))
            raise ValueError("No matching Caption for '{}'".format(
                caption))

    def get_engine_id(self, poller):
        """
        Takes a poller name (or primary) and returns the EngineID for
        the poller.

        Raises: ValueError on an invaild poller.

        Returns: The EngineID (int)
        """

        if poller == "primary":
            return 1
        else:
            swql = """SELECT EngineID, ServerName, IP, ServerType
            FROM Orion.Engines
            WHERE ServerName=@poller"""
            kargs = {'poller': poller}
            data = self.query(swql, **kargs)

            if len(data['results']) == 1:
                return data['results'][0]['EngineID']
            else:
                self.send_user_error("Invalid poller name")
                raise ValueError("Invalid poller name")

    def get_ncm_node_id(self, caption):
        """
        Queries the Network configuration Manager nodes table on the Orion
        platform for the NodeID of a given node name (aka NodeCaption).

        Raises: IndexError on Invalid number of nodes (e.g. 0 or 2+).

        Returns: A single node id.
        """

        swql = "SELECT NodeID FROM Cirrus.Nodes WHERE NodeCaption=@node"
        kargs = {'node': caption}
        data = self.query(swql, **kargs)

        if len(data['results']) == 1:
            try:
                return data['results'][0]['NodeID']
            except IndexError:
                raise IndexError("Invalid Node")
        elif len(data['results']) >= 2:
            raise IndexError("Muliple Nodes match '{}' NodeCaption".format(
                caption))
        elif len(data['results']) == 0:
            raise IndexError("No matching NodeCaption for '{}'".format(
                caption))

    def get_ncm_transfer_results(self, transfer_id, sleep_delay=10):
        """
        Gets the completed (waits until finished). NCM job transfer status
        from Orion.

        Retruns: The completed status.
        """
        ts = {}
        while True:
            swql = """SELECT TransferID, Action, Status, ErrorMessage,
            DeviceOutput FROM NCM.TransferResults
            WHERE TransferID=@transfer_id"""
            kargs = {'transfer_id': transfer_id}

            transfer_data = self.query(swql, **kargs)
            status = transfer_data['results'][0]['Status']

            if status == 1:
                time.sleep(sleep_delay)
            elif status == 2:
                ts['status'] = "Complete"
                break
            elif status == 3:
                ts['status'] = "Error"
                ts['ErrorMessage'] = transfer_data['results'][0][
                    'ErrorMessage']
                break
            else:
                ts['status'] = "Unknown"
                ts['ErrorMessage'] = "Invalid stauts: {}".format(status)
                break

        return ts

    def status_code_to_text(self, status):
        """
        Takes an Solarwinds Orion status code and translates it to
        human text and also a colour that can be used in Slack.
        """

        if status == 0:
            return ("Unknown", "grey")
        elif status == 1:
            return ("Up", "good")
        elif status == 2:
            return ("Down", "danger")
        elif status == 3:
            return ("Warning", "warning")
        elif status == 14:
            return ("Critical", "danger")

    def send_user_error(self, message):
        """
        Prints an user error message.
        """
        print(message)
Exemplo n.º 14
0
def create_node(name_tid, ip_address, oob_ip_address):
    npm_server = 'serverip'
    username = '******'
    password = '******'

    swis = SwisClient(npm_server, username, password)
    print("Adding node with ping..")

    # # fill these in for the node you want to add!
    # name_tid = 'xxxxxxx'
    # ip_address = '1.1.1.1'
    # oob_ip_address = '2.2.2.2'
    #    community = 'public'

    # set up property bag for the new node
    props = {
        'Caption': name_tid,
        'IPAddress': ip_address,
        'EngineID': 1,
        'ObjectSubType': 'ICMP',
    }

    print("Adding node {}... ".format(props['IPAddress']), end="")
    results = swis.create('Orion.Nodes', **props)
    print("DONE!")

    # extract the nodeID from the result
    nodeid = re.search('(\d+)$', results).group(0)

    # add extra custom properites :D
    custom_props = {
        'MY_PROPERTY_1': oob_ip_address,
        'MY_PROPERTY_2': 'client name',
    }

    for k, v in custom_props.items():
        swis.update(results + '/CustomProperties', **{k: v})

    pollers_enabled = {
        'N.Status.ICMP.Native': True,
        'N.Status.SNMP.Native': False,
        'N.ResponseTime.ICMP.Native': True,
        # 'N.ResponseTime.SNMP.Native': False,
        # 'N.Details.SNMP.Generic': False,
        # 'N.Uptime.SNMP.Generic': False,
        # 'N.Cpu.SNMP.HrProcessorLoad': False,
        # 'N.Memory.SNMP.NetSnmpReal': False,
        # 'N.AssetInventory.Snmp.Generic': False,
        # 'N.Topology_Layer3.SNMP.ipNetToMedia': False,
        # 'N.Routing.SNMP.Ipv4CidrRoutingTable': False
    }

    pollers = []
    for k in pollers_enabled:
        pollers.append({
            'PollerType': k,
            'NetObject': 'N:' + nodeid,
            'NetObjectType': 'N',
            'NetObjectID': nodeid,
            'Enabled': pollers_enabled[k]
        })

    for poller in pollers:
        print("  Adding poller type: {} with status {}... ".format(
            poller['PollerType'], poller['Enabled']),
              end="")
        response = swis.create('Orion.Pollers', **poller)
        print("DONE!")
Exemplo n.º 15
0
class SolarWinds:
    def __init__(self, npm_server, username, password, logger=None):

        self.logger = logger or logging.getLogger('__name__')

        # Create the SWIS client for use throughout the instance.
        self.swis = SwisClient(npm_server, username, password)

    def does_node_exist(self, node_name):
        """ Checks to see if a SolarWinds node exists with the given name.  Calls the get_node_id method of the class
            and uses the returned value to determine whether or not the node exists.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.

            Returns:
                True: The node exists.
                False: The node does not exist.

        """

        if self.get_node_id(node_name):
            return True
        else:
            return False

    def get_node_id(self, node_name):
        """ Returns the NodeID for the given NodeName.  Uses a SWIS query to the SolarWinds database to retrieve this
            information.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.

            Returns:
                node_id (string): The node ID that corresponds to the specified node name.

        """

        node_id = self.swis.query(
            "SELECT NodeID, Caption FROM Orion.Nodes WHERE Caption = @caption",
            caption=node_name)

        self.logger.info("get_node_id - node_id query results: %s.", node_id)

        if node_id['results']:
            return node_id['results'][0]['NodeID']
        else:
            return ""

    def get_node_uri(self, node_name):
        """ Returns the NodeURI for the given NodeName.  Uses a SWIS query to the SolarWinds database to retrieve this
            information.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.

            Returns:
                node_id (string): The node URI that corresponds to the specified node name.

        """

        node_uri = self.swis.query(
            "SELECT Caption, Uri FROM Orion.Nodes WHERE Caption = @caption",
            caption=node_name)

        self.logger.info("get_node_uri - node uri query results: %s.",
                         node_uri)
        if node_uri['results']:
            return node_uri['results'][0]['Uri']
        else:
            return ""

    def add_node_using_snmp_v3(self, node_name, ip_address, snmpv3_username,
                               snmpv3_priv_method, snmpv3_priv_pwd,
                               snmpv3_auth_method, snmpv3_auth_pwd):
        """ Creates a new node using the supplied name an IP address.  Configure with our standard SNMPv3 credentials.
            Once created, attached all of the standard Cisco pollers.

            Args:
                node_name(string): A node name to be used for the newly created node object.
                ip_address(string): The IP address that is associated with the supplied node name.
                snmpv3_username(string): The SNMPv3 username that will be associated with the node object.
                snmpv3_priv_method(string): The SNMPv3 privilege method that will be used.
                snmpv3_priv_pwd (string): The SNMPv3 privilege password that will be used.
                snmpv3_auth_method(string): The SNMPv3 authentication method that will be used.
                snmpv3_auth_pwd (string): The SNMPv3 authentication password that will be used.

            Returns:
                None.

        """

        if not self.does_node_exist(node_name):
            # set up property bag for the new node
            node_properties = {
                'IPAddress': ip_address,
                'EngineID': 1,
                'ObjectSubType': 'SNMP',
                'SNMPVersion': 3,
                'SNMPV3Username': snmpv3_username,
                'SNMPV3PrivMethod': snmpv3_priv_method,
                'SNMPV3PrivKeyIsPwd': True,
                'SNMPV3PrivKey': snmpv3_priv_pwd,
                'SNMPV3AuthMethod': snmpv3_auth_method,
                'SNMPV3AuthKeyIsPwd': True,
                'SNMPV3AuthKey': snmpv3_auth_pwd,
                'DNS': '',
                'SysName': '',
                'Caption': node_name
            }

            # Create base node object.
            results = self.swis.create('Orion.Nodes', **node_properties)
            self.logger.info("add_node - add node invoke results: %s", results)

            # Assign pollers to node.
            self.attach_poller_to_node(node_name, 'N.Status.ICMP.Native')
            self.attach_poller_to_node(node_name, 'N.Status.SNMP.Native',
                                       False)
            self.attach_poller_to_node(node_name, 'N.ResponseTime.ICMP.Native')
            self.attach_poller_to_node(node_name, 'N.ResponseTime.SNMP.Native',
                                       False)
            self.attach_poller_to_node(node_name, 'N.Details.SNMP.Generic')
            self.attach_poller_to_node(node_name, 'N.Uptime.SNMP.Generic')

    def is_poller_attached_to_node(self, node_name, poller_name):
        """ Checks to see if the specified poller is attached to the specified node.  Makes a SWIS query to see
            if there's a corresponding entry in the Orion.Pollers table.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                poller_name(string): The name of the poller as represented in the SolarWinds database.

            Returns:
                True: The poller is currently attached to the node.
                False: The poller is not currently attached to the node.

        """

        net_object_id = str(self.get_node_id(node_name))
        net_object = 'N:' + net_object_id

        results = self.swis.query(
            "SELECT PollerType FROM Orion.Pollers WHERE NetObject = @net_object AND PollerType "
            "= @poller_name",
            net_object=net_object,
            poller_name=poller_name)
        self.logger.info(
            "is_poller_attached_to_node - check for poller query results: %s",
            results)

        if results['results']:
            return True
        else:
            return False

    def attach_poller_to_node(self, node_name, poller_name, enabled=True):
        """ Checks to see if the specified poller is attached to the specified node.  If it is not, a SWIS create is
            executed against Orion.Pollers to attach the poller to the node.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                poller_name(string): The name of the poller as represented in the SolarWinds database.
                enabled(boolean): Whether or not to enable the attached poller.

            Returns:
                None.

        """

        if not self.is_poller_attached_to_node(node_name, poller_name):
            net_object_id = str(self.get_node_id(node_name))
            net_object = 'N:' + net_object_id

            poller_properties = {
                'PollerType': poller_name,
                'NetObject': net_object,
                'NetObjectType': 'N',
                'NetObjectID': net_object_id,
                'Enabled': enabled
            }

            results = self.swis.create('Orion.Pollers', **poller_properties)
            self.logger.info(
                "attach_poller_to_node - poller create results: %s", results)

    def enable_hardware_health_on_node(self, node_name):
        """ Enables the hardware health monitoring on the specified node.  Executes a SWIS invoke of the
            'EnableHardwareHealth' verb, passing it the node's net object ID.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.

            Returns:
                None.

        """

        net_object_id = str(self.get_node_id(node_name))
        net_object = 'N:' + net_object_id

        results = self.swis.invoke('Orion.HardwareHealth.HardwareInfo',
                                   'EnableHardwareHealth', net_object, 9)
        self.logger.info(
            "enable_hardware_health - enable hardware health invoke results: %s",
            results)

    def add_node_to_ncm(self, node_name):
        """ Adds the specified node to the SolarWinds NCM module.  Executes a SWIS invoke of the
            'AddNodetoNCM' verb, passing it the node's object ID.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.

            Returns:
                None.

        """

        results = self.swis.invoke('Cirrus.Nodes', 'AddNodeToNCM',
                                   self.get_node_id(node_name))
        self.logger.info(
            "add_node_to_ncm - add node to ncm invoke results: %s", results)

    def add_node_to_udt(self, node_name):
        udt_properties = {
            'NodeID': self.get_node_id(node_name),
            'Capability': '2',
            'Enabled': True
        }

        results = self.swis.create('Orion.UDT.NodeCapability',
                                   **udt_properties)
        self.logger.info(
            "add_node_to_udt - add node at l2 to udt create results: %s",
            results)

        udt_properties = {
            'NodeID': self.get_node_id(node_name),
            'Capability': '3',
            'Enabled': True
        }

        results = self.swis.create('Orion.UDT.NodeCapability',
                                   **udt_properties)
        self.logger.info(
            "add_node_to_udt - add node at l3 to udt create results: %s",
            results)

    def add_node_to_ip_vnqm(self, node_name):
        vnqm_node_properties = {
            'NodeID': self.get_node_id(node_name),
            'Name': node_name,
            'IsHub': False,
            'IsAutoConfigured': True
        }

        results = self.swis.create('Orion.IpSla.Sites', **vnqm_node_properties)
        self.logger.info(
            "add_node_to_vnqm - add node to vnqm create results: %s", results)

    def add_icmp_echo_ip_sla_operation_to_node(self, node_name,
                                               ip_sla_operation_number,
                                               ip_sla_name):
        ip_sla_properties = {
            'NodeID': self.get_node_id(node_name),
            'OperationTypeID': 5,
            'OperationType': "ICMP Echo",
            'IsAutoConfigured': False,
            'Frequency': 10,
            'IpSlaOperationNumber': ip_sla_operation_number,
            'OperationName': ip_sla_name
        }

        results = self.swis.create('Orion.IpSla.Operations',
                                   **ip_sla_properties)
        self.logger.info(
            "add_icmp_echo_ip_sla_operation_to_node - add IP SLA operation to node create results: %s",
            results)

    def set_custom_properties(self, node_name, custom_property_name,
                              custom_property_value):
        """ For a given node, sets the specified custom property to the specified value.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                custom_property_name(string): The custom property who's value we want to change.  The custom property
                    needs to have been previously created or nothing will be changed.
                custom_property_value(string): The desired value that the custom property will be set to.

            Returns:
                None.

        """

        node_uri = self.get_node_uri(node_name)

        custom_property = {custom_property_name: custom_property_value}

        self.swis.update(node_uri + '/CustomProperties', **custom_property)

    def get_custom_properties(self, node_name):
        """ For a given node, gets a list of the custom properties and values associated with it.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.

            Returns:
                custom_properties(list): A list of dictionaries.  Each dictionary is a single key/value pair that contains
                    the custom property name and value.

        """

        node_uri = self.get_node_uri(node_name)

        custom_properties = self.swis.read(node_uri + '/CustomProperties')
        self.logger.info(
            "set_custom_properties - custom_properties read results: %s",
            custom_properties)

        return custom_properties

    def get_list_of_custom_pollers_for_node(self, node_name):
        """ For a given node, gets a list of the currently assigned custom pollers.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.

            Returns:
                custom_pollers(dictionary): Returns a dictionary that represents all of the custom pollers attached to
                    the node.  Each key is the custom property name and the value is the associated custom property
                    value.

        """

        node_id = self.get_node_id(node_name)

        custom_pollers = self.swis.query(
            "SELECT CustomPollerName FROM Orion.NPM.CustomPollerAssignment WHERE NodeID "
            "= @node_id",
            node_id=node_id)
        self.logger.info(
            "get_list_of_custom_pollers_by_name - custom_pollers query results: %s",
            custom_pollers)

        return custom_pollers['results']

    def remove_custom_poller_by_name(self, node_name, poller_name):
        """ For a given node, detaches the specified custom poller.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                poller_name(string): The name of the custom poller that will be removed from the node.

            Returns:
                None.

        """

        node_id = self.get_node_id(node_name)

        custom_poller_id = self.swis.query(
            "SELECT CustomPollerID FROM Orion.NPM.CustomPollers WHERE UniqueName = "
            "@poller_name",
            poller_name=poller_name)
        self.logger.info(
            "remove_custom_poller_by_name - custom_poller_id query results: %s",
            custom_poller_id)

        custom_poller_uri = self.swis.query(
            "SELECT Uri FROM Orion.NPM.CustomPollerAssignmentOnNode WHERE "
            "NodeID=@node_id AND CustomPollerID=@custom_poller_id",
            node_id=node_id,
            custom_poller_id=custom_poller_id['results'][0]['CustomPollerID'])
        self.logger.info(
            "remove_custom_poller_by_name - custom_poller_uri query results: %s",
            custom_poller_uri)

        self.swis.delete(custom_poller_uri['results'][0]['Uri'])

    def add_custom_poller_by_name(self, node_name, poller_name):
        """ For a given node, attaches the specified custom poller.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                poller_name(string): The name of the custom poller which is to be attached to the specified node.

            Returns:
                None.

        """

        node_id = self.get_node_id(node_name)

        custom_poller_id = self.swis.query(
            "SELECT CustomPollerID FROM Orion.NPM.CustomPollers WHERE UniqueName = @poller_name",
            poller_name=poller_name)
        self.logger.info(
            "add_custom_poller_by_name - custom_poller_id query results: %s",
            custom_poller_id)

        poller_properties = {
            'NodeID': node_id,
            'customPollerID': custom_poller_id['results'][0]['CustomPollerID']
        }

        self.swis.create('Orion.NPM.CustomPollerAssignmentOnNode',
                         **poller_properties)

    def does_group_exist(self, group_name):
        """ Checks to see if a SolarWinds group exists with the given name.  Calls the get_group_id method of the class
            and uses the returned value to determine whether or not the group exists.

            Args:
                group_name(string): A group name which should equal the name used in SolarWinds for the container
                    object.

            Returns:
                True: The group exists.
                False: The group does not exist.

        """

        if self.get_group_id(group_name):
            return True
        else:
            return False

    def get_group_id(self, group_name):
        """ Returns the ContainerID for the given Group Name.  Uses a SWIS query to the SolarWinds database to retrieve
            this information.

            Args:
                group_name(string): A group name which should equal the name used in SolarWinds for the container
                    object.

            Returns:
                group_id (string): The group ID that corresponds to the specified group name.

        """

        group_id = self.swis.query(
            "SELECT ContainerID FROM Orion.Container WHERE Name = @group_name",
            group_name=group_name)
        self.logger.info("get_group_id - group_id query results: %s", group_id)

        if group_id['results']:
            return group_id['results'][0]['ContainerID']
        else:
            return ""

    def get_group_uri(self, group_name):
        """ Returns the ContainerUri for the given Group Name.  Uses a SWIS query to the SolarWinds database to retrieve this
            information.

            Args:
                group_name(string): A group name which should equal the name used in SolarWinds for the container object.

            Returns:
                group_uri (string): The group URI that corresponds to the specified group name.

        """

        group_uri = self.swis.query(
            "SELECT Uri FROM Orion.Container WHERE Name = @group_name",
            group_name=group_name)
        self.logger.info("get_group_uri - group_uri query results: %s",
                         group_uri)

        if group_uri['results']:
            return group_uri['results'][0]['Uri']
        else:
            return ""

    def add_group(self,
                  group_name,
                  owner='Core',
                  refresh_frequency=60,
                  status_rollup=0,
                  group_description='',
                  polling_enabled=True,
                  group_members=None):
        """ Creates a new empty group using the supplied name.  Sets all of the additional parameters to the default
            values.

            Args:
                group_name(string): A group name to be used for the newly created container.
                owner(string): Must be 'Core'.
                refresh_frequency(int): How often the group membership is updated.
                status_rollup(int): Status rollup mode.
                    # 0 = Mixed status shows warning
                    # 1 = Show worst status
                    # 2 = Show best status
                group_description(string):
                polling_enabled(boolean): Whether polling of the group is enabled or disabled.
                group_members(list): A list of group members and/or dynamic filters.

            Returns:
                None.

        """

        if group_members is None:
            group_members = []
        if not self.does_group_exist(group_name):
            results = self.swis.invoke('Orion.Container', 'CreateContainer',
                                       group_name, owner, refresh_frequency,
                                       status_rollup, group_description,
                                       polling_enabled, group_members)
            self.logger.info("add_group - add group invoke results: %s",
                             results)

    def is_node_in_group(self, node_name, group_name):
        """ Checks to see if a node is a member of a particular group.  Runs a SWIS query against the ContainerMembers
            table to see if there's a corresponding table entry.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                group_name(string): A group name which should equal the name used in SolarWinds for the container
                    object.

            Returns:
                True: The node is in the group.
                False: The node is not in the group.

        """

        results = self.swis.query(
            "SELECT Name FROM Orion.ContainerMembers WHERE ContainerID = @group_id and FullName "
            "= @node_name",
            group_id=self.get_group_id(group_name),
            node_name=node_name)
        self.logger.info(
            "is_node_in_group - is_node_in_group query results: %s", results)

        if results['results']:
            return True
        else:
            return False

    def add_node_to_group(self, node_name, group_name):
        """ If the specified node is not already in the specified group, a SWIS invoke of Orion.Container.AddDefinition
            is made to add the node to the group.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                group_name(string): A group name which should equal the name used in SolarWinds for the container object.

            Returns:
                None.

        """

        if not self.is_node_in_group(node_name, group_name):
            member_definition = {
                "Name": node_name,
                "Definition": self.get_node_uri(node_name)
            }
            self.swis.invoke('Orion.Container', 'AddDefinition',
                             int(self.get_group_id(group_name)),
                             member_definition)

    def delete_group_by_id(self, group_id):
        """ Delete a group that has the specified group id.

            Args:
                group_id(string): A group id which should equal the ContainerID used in SolarWinds for the container
                    object.

            Returns:
                None.

        """

        self.swis.invoke('Orion.Container', 'DeleteContainer', int(group_id))

    def delete_group_by_name(self, group_name):
        """ Delete a group that has the specified group name.

            Args:
                group_name(string): A group name which should equal the Name used in SolarWinds for the container
                    object.

            Returns:
                None.

        """

        group_id = self.get_group_id(group_name)

        self.delete_group_by_id(group_id)

    def does_dependency_exist(self, dependency_name):
        """ Checks to see if a SolarWinds dependency exists with the given name.  Calls the get_dependency_id method of
            the class and uses the returned value to determine whether or not the dependency exists.

            Args:
                dependency_name(string): A dependency name which should equal the name used in SolarWinds for the
                    dependency object.

            Returns:
                True: The dependency exists.
                False: The dependency does not exist.

        """

        if self.get_dependency_id(dependency_name):
            return True
        else:
            return False

    def get_dependency_id(self, dependency_name):
        """ Returns the DependencyID for the given Dependency Name.  Uses a SWIS query to the SolarWinds database to
            retrieve this information.

            Args:
                dependency_name(string): A dependency name which should equal the name used in SolarWinds for the
                    dependency object.

            Returns:
                dependency_id (string): The dependency ID that corresponds to the specified dependency name.

        """

        dependency_id = self.swis.query(
            "SELECT DependencyId FROM Orion.Dependencies WHERE Name = @dependency_name",
            dependency_name=dependency_name)
        self.logger.info("get_dependency_id - dependency_id query results: %s",
                         dependency_id)

        if dependency_id['results']:
            return dependency_id['results'][0]['DependencyId']
        else:
            return ""

    def add_dependency(self, dependency_name, parent_name, child_name):
        """ Creates a new dependency using the specified parent and child.  Does a SWIS create to the Orion.Dependencies
            table to create the dependency.

            Args:
                dependency_name(string): A dependency name to be used for the newly created dependency.
                parent_name(string): Name of the parent to be used in the dependency definition.
                child_name(string): Name of the child to be used in the dependency definition.

            Returns:
                True: The dependency was successfully created.
                False: The dependency was not created.

        """

        if not self.does_dependency_exist(dependency_name):
            if self.does_node_exist(parent_name):
                self.logger.info("add-dependency - The parent is a node.")
                parent_id = self.get_node_id(parent_name)
                parent_uri = self.get_node_uri(parent_name)
                parent_entity_type = 'Orion.Nodes'
            elif self.does_group_exist(parent_name):
                self.logger.info("add-dependency - The parent is a group.")
                parent_id = self.get_group_id(parent_name)
                parent_uri = self.get_group_uri(parent_name)
                parent_entity_type = 'Orion.Groups'
            else:
                return False

            if self.does_node_exist(child_name):
                self.logger.info("add-dependency - The child is a node.")
                child_id = self.get_node_id(child_name)
                child_uri = self.get_node_uri(child_name)
                child_entity_type = 'Orion.Nodes'
            elif self.does_group_exist(child_name):
                self.logger.info("add-dependency - The child is a group.")
                child_id = self.get_group_id(child_name)
                child_uri = self.get_group_uri(child_name)
                child_entity_type = 'Orion.Groups'
            else:
                return False

            dependency_properties = {
                'Name': dependency_name,
                'ParentUri': parent_uri,
                'ParentEntityType': parent_entity_type,
                'ParentNetObjectId': parent_id,
                'ChildUri': child_uri,
                'ChildEntityType': child_entity_type,
                'ChildNetObjectId': child_id
            }

            self.swis.create('Orion.Dependencies', **dependency_properties)

    def get_list_of_interfaces(self, node_name):
        """ Returns a dictionary of existing Interfaces on a given Node Name. Uses a SWIS query to the SolarWinds
            database to retrieve this information.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
            Returns:
                list_interfaces_names(dictionary): Returns a dictionary that represents all of the interfaces, by name,
                attached to the node.
        """

        node_id = self.get_node_id(node_name)

        list_interfaces_names = self.swis.query(
            "SELECT Name FROM Orion.NPM.Interfaces WHERE NodeID "
            "= @node_id",
            node_id=node_id)

        self.logger.info(
            "get_list_of_interfaces_by_name - list_of_interface_names query results: %s",
            list_interfaces_names)

        if list_interfaces_names['results']:
            return list_interfaces_names['results']
        else:
            return ""

    def remove_interface(self, node_name, interface_name):
        """ For a given node, remove the given interface from the node using the interface name.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                interface_name(string): The name of the interface that will be removed from the node.
            Returns:
                True: Interface was successfully removed.
                False: Interface was not removed.

        """

        interface_uri = self.get_interface_uri(node_name, interface_name)

        if self.does_interface_exist(node_name, interface_name):
            self.logger.info(
                "remove_interface_by_name - interface_uri query results: %s",
                interface_uri)
            self.swis.delete(interface_uri)
        else:
            return False

    def get_interface_uri(self, node_name, interface_name):
        """ Returns the URI for a given interface belonging to a given node. Uses a SWIS query to the SolarWinds
            database to retrieve this information

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                interface_name(string): The name of the interface that you are getting the URI for

            Returns:
                interface_uri(string): The interface URI that corresponds to the specified interface name

        """

        node_id = self.get_node_id(node_name)

        interface_uri = self.swis.query(
            "SELECT Uri FROM Orion.NPM.Interfaces WHERE NodeID=@node_id AND "
            "InterfaceName=@interface_name",
            node_id=node_id,
            interface_name=interface_name)

        if interface_uri['results']:
            return interface_uri['results'][0]['Uri']
        else:
            return ""

    def get_interface_id(self, node_name, interface_name):
        """ Returns the InterfaceID for a given interface belonging to a given node. Uses a SWIS query to the SolarWinds
            database to retrieve this information

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                interface_name(string): The name of the interface that you are getting the ID of.

            Returns:
                interface_id(string): The interface ID that corresponds to the specified interface name

        """

        node_id = self.get_node_id(node_name)

        interface_id = self.swis.query(
            "SELECT InterfaceID FROM Orion.NPM.Interfaces WHERE NodeID=@node_id AND "
            "Name = @interface_name",
            node_id=node_id,
            interface_name=interface_name)

        if interface_id['results']:
            return interface_id['results'][0]['InterfaceID']
        else:
            return ""

    def does_interface_exist(self, node_name, interface_name):
        """ Checks to see if a SolarWinds interface, belonging to a given node, exists with the given name. Calls the
            get_interface_id method of the class and uses the returned value to determine whether or not the interface
            exists.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                interface_name(string): The name of the interface that you are getting the URI for

            Returns:
                True: The interface exists.
                False: THe interface does not exist.

        """

        if self.get_interface_id(node_name, interface_name):
            return True
        else:
            return False

    def get_discovered_interfaces(self, node_name):
        """ Returns a dictionary of Discovered Interfaces on a node given that node's name. Uses a SWIS invoke for
            DiscoverInterfacesOnNode.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.

            Returns:
                discovered_interfaces(Dictionary): The set of discovered interfaces on the node.
        """

        node_id = self.get_node_id(node_name)

        discovered_interfaces = self.swis.invoke('Orion.NPM.Interfaces',
                                                 'DiscoverInterfacesOnNode',
                                                 node_id)

        return discovered_interfaces['DiscoveredInterfaces']

    def add_interface(self, node_name, interface_name):
        """ For a given node, attach the given interface by that interface's name. The given interface must be a
            discovered interface to be attached to the node. Uses a SWIS invoke for AddInterfacesOnNode.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.
                interface_name(string): The name of the interface that will be added to the node.

            Returns:
                True: The interface was added to the node.
                False: The interface was not successfully added to the node.

        """

        node_id = self.get_node_id(node_name)

        discovered_interfaces = self.get_discovered_interfaces(node_name)
        discovered_interface = [
            x for x in discovered_interfaces
            if x['Caption'].startswith(interface_name)
        ]

        if discovered_interface:
            self.swis.invoke('Orion.NPM.Interfaces', 'AddInterfacesOnNode',
                             node_id, discovered_interface,
                             'AddDefaultPollers')

        else:
            return False

    def ncm_download_nodes_running_config(self, node_name):
        """ For a given node, download the node's running configuration. Uses a SWIS query to find the Cirrus node I.
            Uses a Swis invoke of DownloadConfig.

            Args:
                node_name(string): A node name which should equal the caption used in SolarWinds for the node object.

            Returns:
                None.

        """

        results = self.swis.query(
            'SELECT NodeID FROM Cirrus.Nodes WHERE NodeCaption = @node_name',
            node_name=node_name)['results']

        cirrus_node_id = results[0]['NodeID']

        self.swis.invoke('Cirrus.ConfigArchive', 'DownloadConfig',
                         [cirrus_node_id], 'Running')

    def ncm_run_compliance_report(self, report_name):
        """ For a given report name, run the Policy Report. Uses a SWIS query to get the policy report ID. Uses a
            SWIS invoke of StartCaching to run the policy report.

            Args:
                report_name(string): A report name which should equal the Name used in SolarWinds for a Policy
                    Report object

            Returns:
                None.

        """

        results = self.swis.query(
            'SELECT PolicyReportID FROM Cirrus.PolicyReports WHERE Name = @report_name',
            report_name=report_name)

        report_id = results['results'][0]['PolicyReportID']
        self.swis.invoke('Cirrus.PolicyReports', 'StartCaching', [report_id])