Completed
Push — master ( 32acac...19ae40 )
by Lakshmi
11:34
created

OrionBaseAction   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 232
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 232
rs 8.3999
c 2
b 0
f 0
wmc 38

13 Methods

Rating   Name   Duplication   Size   Complexity  
A update() 0 5 1
A delete() 0 5 1
A create() 0 5 1
A read() 0 5 1
A __init__() 0 7 2
A invoke() 0 5 1
A query() 0 5 1
B connect() 0 22 4
B get_snmp_cred_id() 0 28 3
B get_ncm_transfer_results() 0 38 5
B get_snmp_community() 0 13 5
B get_engine_id() 0 24 3
C get_node() 0 57 10
1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
import time
17
18
from st2actions.runners.pythonrunner import Action
19
from orionsdk import SwisClient
20
21
from lib.node import OrionNode
22
from lib.utils import send_user_error, is_ip
23
24
25
class OrionBaseAction(Action):
26
    def __init__(self, config):
27
        super(OrionBaseAction, self).__init__(config)
28
29
        self.client = None
30
31
        if "orion" not in self.config:
32
            raise ValueError("Orion host details not in the config.yaml")
33
34
    def connect(self, platform):
35
        """
36
        Connect to an Orion platform from the packs config.yaml.
37
        """
38
        if platform is None:
39
            try:
40
                platform = self.config['defaults']['platform']
41
            except IndexError:
42
                send_user_error("No default Orion platform.")
43
                raise ValueError("No default Orion platform.")
44
45
        self.logger.debug("Connecting to Orion platform: {}".format(platform))
46
47
        try:
48
            self.client = SwisClient(
49
                self.config['orion'][platform]['host'],
50
                self.config['orion'][platform]['user'],
51
                self.config['orion'][platform]['password'])
52
        except KeyError:
53
            raise ValueError("Orion host details not in the config.yaml")
54
55
        return platform
56
57
    def get_node(self, node):
58
        """
59
        Get an OrionNode object
60
        """
61
62
        orion_node = OrionNode()
63
64
        if is_ip(node):
65
            query_for_where = "IPAddress"
66
        else:
67
            query_for_where = "Caption"
68
69
        swql = """SELECT NodeID, Uri, IPAddress, Caption
70
        FROM Orion.Nodes
71
        WHERE {}=@query_on""".format(query_for_where)
72
        kargs = {'query_on': node}
73
        data = self.query(swql, **kargs)
74
75
        if 'results' not in data:
76
            msg = "No results from Orion: {}".format(data)
77
            self.logger.info(msg)
78
            raise Exception(msg)
79
80
        if len(data['results']) == 1:
81
            try:
82
                orion_node.npm_id = data['results'][0]['NodeID']
83
                orion_node.uri = data['results'][0]['Uri']
84
                orion_node.ip_address = data['results'][0]['IPAddress']
85
                orion_node.caption = data['results'][0]['Caption']
86
            except IndexError:
87
                pass
88
        elif len(data['results']) >= 2:
89
            self.logger.debug(
90
                "Muliple Nodes match '{}' Caption: {}".format(
91
                    node, data))
92
            raise ValueError("Muliple Nodes match '{}' Caption".format(
93
                node))
94
95
        if orion_node.npm:
96
            swql = """SELECT NodeID
97
            FROM Cirrus.Nodes
98
            WHERE CoreNodeID=@CoreNodeID"""
99
            kargs = {'CoreNodeID': orion_node.npm_id}
100
            data = self.query(swql, **kargs)
101
102
            # Don't raise an exception if this fails.
103
            # The platform may not haev NCM installed.
104
            if 'results' not in data:
105
                msg = "No results from Orion NCM: {}".format(data)
106
                self.logger.info(msg)
107
            elif len(data['results']) == 1:
108
                try:
109
                    orion_node.ncm_id = data['results'][0]['NodeID']
110
                except IndexError:
111
                    pass
112
113
        return orion_node
114
115
    def query(self, swql, **kargs):
116
        """
117
        Run SWQL against the Orion Platform.
118
        """
119
        return self.client.query(swql, **kargs)
120
121
    def invoke(self, entity, verb, *args):
122
        """
123
        Run an Invoke against the Orion Platform.
124
        """
125
        return self.client.invoke(entity, verb, *args)
126
127
    def create(self, entity, **kargs):
128
        """
129
        Run an Create against the Orion Platform.
130
        """
131
        return self.client.create(entity, **kargs)
132
133
    def read(self, uri):
134
        """
135
        Run an Read against the Orion Platform.
136
        """
137
        return self.client.read(uri)
138
139
    def update(self, uri, **kargs):
140
        """
141
        Run an Update against the Orion Platform.
142
        """
143
        return self.client.update(uri, **kargs)
144
145
    def delete(self, uri):
146
        """
147
        Run an Delete of an URI against the Orion Platform.
148
        """
149
        return self.client.delete(uri)
150
151
    def get_snmp_community(self, community, std_community):
152
        """
153
        Return the correct SNMP comminity to use.
154
        """
155
        if community is not None:
156
            return community
157
        elif std_community is not None:
158
            try:
159
                return self.config['defaults']['snmp'][std_community]
160
            except KeyError:
161
                raise ValueError("Invalid standard community")
162
        elif std_community is None:
163
            raise ValueError("Need one of community or std_community")
164
165
    def get_snmp_cred_id(self, community):
166
        """
167
        Look up an SNMP community in the config and then look up
168
        the Orion ID for the Credential.
169
        """
170
171
        # Check if community is a know standard, otherwise
172
        # use it as the community.
173
        try:
174
            name = self.get_snmp_community(None, community)
175
        except ValueError:
176
            name = community
177
178
        swql = """SELECT ID FROM Orion.Credential
179
        WHERE CredentialType=@CredentialType and Name=@name"""
180
181
        kargs = {'CredentialType':
182
                 'SolarWinds.Orion.Core.Models.Credentials.SnmpCredentialsV2',
183
                 'name': name}
184
        orion_data = self.query(swql, **kargs)
185
186
        if len(orion_data['results']) == 1:
187
            return orion_data['results'][0]['ID']
188
        else:
189
            msg = "Could not get ID for community in Orion.Credential: {}".format(
190
                community)
191
            send_user_error(msg)
192
            raise ValueError(msg)
193
194
    def get_engine_id(self, poller):
195
        """
196
        Takes a poller name (or primary) and returns the EngineID for
197
        the poller.
198
199
        Raises: ValueError on an invaild poller.
200
201
        Returns: The EngineID (int)
202
        """
203
204
        if poller == "primary":
205
            return 1
206
        else:
207
            swql = """SELECT EngineID, ServerName, IP, ServerType
208
            FROM Orion.Engines
209
            WHERE ServerName=@poller"""
210
            kargs = {'poller': poller}
211
            data = self.query(swql, **kargs)
212
213
            if len(data['results']) == 1:
214
                return data['results'][0]['EngineID']
215
            else:
216
                send_user_error("Invalid poller name")
217
                raise ValueError("Invalid poller name")
218
219
    def get_ncm_transfer_results(self, transfer_id, sleep_delay=10):
220
        """
221
        Gets the completed (waits until finished). NCM job transfer status
222
        from Orion.
223
224
        Retruns: The completed status.
225
        """
226
        ts = {}
227
        while True:
228
            swql = """SELECT TransferID, NodeID, Action, RequestedConfigType,
229
            RequestedScript, RequestedReboot, ConfigID, TransferProtocol,
230
            Status, ErrorMessage, DeviceOutput, DateTime, UserName
231
            FROM NCM.TransferResults
232
            WHERE TransferID=@transfer_id"""
233
            kargs = {'transfer_id': transfer_id}
234
235
            transfer_data = self.query(swql, **kargs)
236
            status = transfer_data['results'][0]['Status']
237
238
            if status == 1:
239
                time.sleep(sleep_delay)
240
            elif status == 2:
241
                ts['status'] = "Complete"
242
                break
243
            elif status == 3:
244
                ts['status'] = "Error"
245
                break
246
            else:
247
                ts['status'] = "Unknown"
248
                break
249
250
        ts['RequestedScript'] = transfer_data['results'][0]['RequestedScript']
251
        ts['RequestedReboot'] = transfer_data['results'][0]['RequestedReboot']
252
        ts['ErrorMessage'] = transfer_data['results'][0]['ErrorMessage']
253
        ts['DeviceOutput'] = transfer_data['results'][0]['DeviceOutput']
254
        ts['UserName'] = transfer_data['results'][0]['UserName']
255
256
        return ts
257