Completed
Pull Request — master (#466)
by
unknown
02:28
created

OrionBaseAction.query()   A

Complexity

Conditions 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 5
rs 9.4285
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
22
class OrionBaseAction(Action):
23
    def __init__(self, config):
24
        super(OrionBaseAction, self).__init__(config)
25
26
        self.client = None
27
28
        if "orion" not in self.config:
29
            raise ValueError("Orion host details not in the config.yaml")
30
31
    def connect(self, platform):
32
        """
33
        Connect to an Orion platform from the packs config.yaml.
34
        """
35
        try:
36
            self.client = SwisClient(
37
                self.config['orion'][platform]['host'],
38
                self.config['orion'][platform]['user'],
39
                self.config['orion'][platform]['password'])
40
        except KeyError:
41
            raise ValueError("Orion host details not in the config.yaml")
42
43
    def query(self, swql, **kargs):
44
        """
45
        Run SWQL against the Orion Platform.
46
        """
47
        return self.client.query(swql, **kargs)
48
49
    def invoke(self, entity, verb, *args):
50
        """
51
        Run an Invoke against the Orion Platform.
52
        """
53
        return self.client.invoke(entity, verb, *args)
54
55
    def create(self, entity, **kargs):
56
        """
57
        Run an Create against the Orion Platform.
58
        """
59
        return self.client.create(entity, **kargs)
60
61
    def node_exists(self, caption, ip_address):
62
        """
63
        Check if an Node exists (caption and or ip) on the Orion platform.
64
65
        Returns: True or False.
66
        """
67
        swql = """SELECT NodeID, IPAddress FROM Orion.Nodes
68
                  WHERE Caption=@caption"""
69
        kargs = {'caption': caption}
70
        caption_data = self.query(swql, **kargs)
71
72
        swql = """SELECT NodeID, IPAddress FROM Orion.Nodes
73
                  WHERE IPAddress=@ip_address"""
74
        kargs = {'ip_address': ip_address}
75
        ip_data = self.query(swql, **kargs)
76
77
        if len(caption_data['results']) >= 1 or len(ip_data['results']) >= 1:
78
            return True
79
        else:
80
            return False
81
82
    def get_node_id(self, caption):
83
        """
84
        Gets an NodeID from the Orion platform.
85
86
        Raises: ValueError on muliple or no matching caption.
87
88
        Returns: the NodeID (int)
89
        """
90
        swql = "SELECT NodeID FROM Orion.Nodes WHERE Caption=@caption"
91
        kargs = {'caption': caption}
92
        data = self.query(swql, **kargs)
93
94
        if len(data['results']) == 1:
95
            try:
96
                return data['results'][0]['NodeID']
97
            except IndexError:
98
                raise ValueError("Invalid Node")
99
        elif len(data['results']) >= 2:
100
            raise ValueError("Muliple Nodes match '{}' Caption".format(
101
                caption))
102
        elif len(data['results']) == 0:
103
            raise ValueError("No matching Caption for '{}'".format(
104
                caption))
105
106
    def get_engine_id(self, poller):
107
        """
108
        Takes a poller name (or primary) and returns the EngineID for
109
        the poller.
110
111
        Raises: ValueError on an invaild poller.
112
113
        Returns: The EngineID (int)
114
        """
115
116
        if poller == "primary":
117
            return 1
118
        else:
119
            swql = """SELECT EngineID, ServerName, IP, ServerType
120
            FROM Orion.Engines
121
            WHERE ServerName=@poller"""
122
            kargs = {'poller': poller}
123
            data = self.query(swql, **kargs)
124
125
            if len(data['results']) == 1:
126
                return data['results'][0]['EngineID']
127
            else:
128
                self.send_user_error("Invalid poller name")
129
                raise ValueError("Invalid poller name")
130
131
    def get_ncm_node_id(self, caption):
132
        """
133
        Queries the Network configuration Manager nodes table on the Orion
134
        platform for the NodeID of a given node name (aka NodeCaption).
135
136
        Raises: IndexError on Invalid number of nodes (e.g. 0 or 2+).
137
138
        Returns: A single node id.
139
        """
140
141
        swql = "SELECT NodeID FROM Cirrus.Nodes WHERE NodeCaption=@node"
142
        kargs = {'node': caption}
143
        data = self.query(swql, **kargs)
144
145
        if len(data['results']) == 1:
146
            try:
147
                return data['results'][0]['NodeID']
148
            except IndexError:
149
                raise IndexError("Invalid Node")
150
        elif len(data['results']) >= 2:
151
            raise IndexError("Muliple Nodes match '{}' NodeCaption".format(
152
                caption))
153
        elif len(data['results']) == 0:
154
            raise IndexError("No matching NodeCaption for '{}'".format(
155
                caption))
156
157
    def get_ncm_transfer_results(self, transfer_id):
158
        """
159
        Gets the completed (waits until finished). NCM job transfer status
160
        from Orion.
161
162
        Retruns: The completed status.
163
        """
164
        ts = {}
165
        while True:
166
            swql = """SELECT TransferID, Action, Status, ErrorMessage,
167
            DeviceOutput FROM NCM.TransferResults
168
            WHERE TransferID=@transfer_id"""
169
            kargs = {'transfer_id': transfer_id}
170
171
            transfer_data = self.query(swql, **kargs)
172
            status = transfer_data['results'][0]['Status']
173
174
            if status == 1:
175
                time.sleep(10)
176
            elif status == 2:
177
                ts['status'] = "Complete"
178
                break
179
            elif status == 3:
180
                ts['status'] = "Error"
181
                ts['ErrorMessage'] = transfer_data['results'][0][
182
                    'ErrorMessage']
183
                break
184
            else:
185
                ts['status'] = "Unknown"
186
                ts['ErrorMessage'] = "Invalid stauts: {}".format(status)
187
                break
188
189
        return ts
190
191
    def status_code_to_text(self, status):
192
        """
193
        Takes an Solarwinds Orion status code and translates it to
194
        human text and also a colour that can be used in Slack.
195
        """
196
197
        if status == 0:
198
            return ("Unknown", "grey")
199
        elif status == 1:
200
            return ("Up", "good")
201
        elif status == 2:
202
            return ("Down", "danger")
203
        elif status == 3:
204
            return ("Warning", "warning")
205
        elif status == 14:
206
            return ("Critical", "danger")
207
208
    def send_user_error(self, message):
209
        """
210
        Prints an user error message.
211
        """
212
        print(message)
213