Completed
Push — master ( 772307...2b2f12 )
by Tomaz
31s
created

OrionBaseAction.__init__()   A

Complexity

Conditions 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 2
dl 0
loc 7
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
        if len(caption_data['results']) >= 1:
73
            self.logger.debug(
74
                "One (or more) Nodes match '{}' Caption.".format(caption))
75
            return True
76
77
        swql = """SELECT NodeID, IPAddress FROM Orion.Nodes
78
                  WHERE IPAddress=@ip_address"""
79
        kargs = {'ip_address': ip_address}
80
        ip_data = self.query(swql, **kargs)
81
82
        if len(ip_data['results']) >= 1:
83
            self.logger.debug(
84
                "One (or more) Nodes match '{}' IP.".format(ip_address))
85
            return True
86
        else:
87
            return False
88
89
    def get_node_id(self, caption):
90
        """
91
        Gets an NodeID from the Orion platform.
92
93
        Raises: ValueError on muliple or no matching caption.
94
95
        Returns: the NodeID (int)
96
        """
97
        swql = "SELECT NodeID FROM Orion.Nodes WHERE Caption=@caption"
98
        kargs = {'caption': caption}
99
        data = self.query(swql, **kargs)
100
101
        if len(data['results']) == 1:
102
            try:
103
                return data['results'][0]['NodeID']
104
            except IndexError:
105
                raise ValueError("Invalid Node")
106
        elif len(data['results']) >= 2:
107
            self.logger.debug(
108
                "Muliple Nodes match '{}' Caption: {}".format(
109
                    caption, data))
110
            raise ValueError("Muliple Nodes match '{}' Caption".format(
111
                caption))
112
        elif len(data['results']) == 0:
113
            self.logger.debug(
114
                "No Nodes match '{}' Caption: {}".format(
115
                    caption, data))
116
            raise ValueError("No matching Caption for '{}'".format(
117
                caption))
118
119
    def get_engine_id(self, poller):
120
        """
121
        Takes a poller name (or primary) and returns the EngineID for
122
        the poller.
123
124
        Raises: ValueError on an invaild poller.
125
126
        Returns: The EngineID (int)
127
        """
128
129
        if poller == "primary":
130
            return 1
131
        else:
132
            swql = """SELECT EngineID, ServerName, IP, ServerType
133
            FROM Orion.Engines
134
            WHERE ServerName=@poller"""
135
            kargs = {'poller': poller}
136
            data = self.query(swql, **kargs)
137
138
            if len(data['results']) == 1:
139
                return data['results'][0]['EngineID']
140
            else:
141
                self.send_user_error("Invalid poller name")
142
                raise ValueError("Invalid poller name")
143
144
    def get_ncm_node_id(self, caption):
145
        """
146
        Queries the Network configuration Manager nodes table on the Orion
147
        platform for the NodeID of a given node name (aka NodeCaption).
148
149
        Raises: IndexError on Invalid number of nodes (e.g. 0 or 2+).
150
151
        Returns: A single node id.
152
        """
153
154
        swql = "SELECT NodeID FROM Cirrus.Nodes WHERE NodeCaption=@node"
155
        kargs = {'node': caption}
156
        data = self.query(swql, **kargs)
157
158
        if len(data['results']) == 1:
159
            try:
160
                return data['results'][0]['NodeID']
161
            except IndexError:
162
                raise IndexError("Invalid Node")
163
        elif len(data['results']) >= 2:
164
            raise IndexError("Muliple Nodes match '{}' NodeCaption".format(
165
                caption))
166
        elif len(data['results']) == 0:
167
            raise IndexError("No matching NodeCaption for '{}'".format(
168
                caption))
169
170
    def get_ncm_transfer_results(self, transfer_id, sleep_delay=10):
171
        """
172
        Gets the completed (waits until finished). NCM job transfer status
173
        from Orion.
174
175
        Retruns: The completed status.
176
        """
177
        ts = {}
178
        while True:
179
            swql = """SELECT TransferID, Action, Status, ErrorMessage,
180
            DeviceOutput FROM NCM.TransferResults
181
            WHERE TransferID=@transfer_id"""
182
            kargs = {'transfer_id': transfer_id}
183
184
            transfer_data = self.query(swql, **kargs)
185
            status = transfer_data['results'][0]['Status']
186
187
            if status == 1:
188
                time.sleep(sleep_delay)
189
            elif status == 2:
190
                ts['status'] = "Complete"
191
                break
192
            elif status == 3:
193
                ts['status'] = "Error"
194
                ts['ErrorMessage'] = transfer_data['results'][0][
195
                    'ErrorMessage']
196
                break
197
            else:
198
                ts['status'] = "Unknown"
199
                ts['ErrorMessage'] = "Invalid stauts: {}".format(status)
200
                break
201
202
        return ts
203
204
    def status_code_to_text(self, status):
205
        """
206
        Takes an Solarwinds Orion status code and translates it to
207
        human text and also a colour that can be used in Slack.
208
        """
209
210
        if status == 0:
211
            return ("Unknown", "grey")
212
        elif status == 1:
213
            return ("Up", "good")
214
        elif status == 2:
215
            return ("Down", "danger")
216
        elif status == 3:
217
            return ("Warning", "warning")
218
        elif status == 14:
219
            return ("Critical", "danger")
220
221
    def send_user_error(self, message):
222
        """
223
        Prints an user error message.
224
        """
225
        print(message)
226