check-netscaler 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- check_netscaler/__init__.py +10 -0
- check_netscaler/__main__.py +10 -0
- check_netscaler/cli.py +314 -0
- check_netscaler/client/__init__.py +25 -0
- check_netscaler/client/exceptions.py +48 -0
- check_netscaler/client/nitro.py +195 -0
- check_netscaler/client/session.py +149 -0
- check_netscaler/commands/__init__.py +1 -0
- check_netscaler/commands/base.py +62 -0
- check_netscaler/commands/debug.py +67 -0
- check_netscaler/commands/hastatus.py +177 -0
- check_netscaler/commands/hwinfo.py +98 -0
- check_netscaler/commands/interfaces.py +179 -0
- check_netscaler/commands/license.py +225 -0
- check_netscaler/commands/matches.py +194 -0
- check_netscaler/commands/nsconfig.py +74 -0
- check_netscaler/commands/ntp.py +295 -0
- check_netscaler/commands/perfdata.py +142 -0
- check_netscaler/commands/servicegroup.py +202 -0
- check_netscaler/commands/sslcert.py +175 -0
- check_netscaler/commands/staserver.py +151 -0
- check_netscaler/commands/state.py +226 -0
- check_netscaler/commands/threshold.py +256 -0
- check_netscaler/constants.py +25 -0
- check_netscaler/output/__init__.py +1 -0
- check_netscaler/output/nagios.py +154 -0
- check_netscaler/utils/__init__.py +1 -0
- check_netscaler-2.0.0.dist-info/METADATA +211 -0
- check_netscaler-2.0.0.dist-info/RECORD +33 -0
- check_netscaler-2.0.0.dist-info/WHEEL +5 -0
- check_netscaler-2.0.0.dist-info/entry_points.txt +2 -0
- check_netscaler-2.0.0.dist-info/licenses/LICENSE +21 -0
- check_netscaler-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
check_netscaler - Nagios/Icinga monitoring plugin for Citrix NetScaler ADC
|
|
3
|
+
|
|
4
|
+
A monitoring plugin for Citrix NetScaler Application Delivery Controllers
|
|
5
|
+
using the NITRO REST API.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "2.0.0"
|
|
9
|
+
__author__ = "slauger"
|
|
10
|
+
__license__ = "MIT"
|
check_netscaler/cli.py
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command-line interface for check_netscaler
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
from typing import List, Optional
|
|
9
|
+
|
|
10
|
+
from check_netscaler import __version__
|
|
11
|
+
from check_netscaler.constants import (
|
|
12
|
+
DEFAULT_API_VERSION,
|
|
13
|
+
DEFAULT_PASSWORD,
|
|
14
|
+
DEFAULT_TIMEOUT,
|
|
15
|
+
DEFAULT_USERNAME,
|
|
16
|
+
STATE_UNKNOWN,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def create_parser() -> argparse.ArgumentParser:
|
|
21
|
+
"""Create and configure argument parser"""
|
|
22
|
+
parser = argparse.ArgumentParser(
|
|
23
|
+
prog="check_netscaler",
|
|
24
|
+
description="Nagios/Icinga monitoring plugin for Citrix NetScaler ADC",
|
|
25
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Version
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"-V",
|
|
31
|
+
"--version",
|
|
32
|
+
action="version",
|
|
33
|
+
version=f"%(prog)s {__version__}",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Connection arguments
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
"-H",
|
|
39
|
+
"--hostname",
|
|
40
|
+
default=os.getenv("NETSCALER_HOST"),
|
|
41
|
+
help="Hostname or IP address of the NetScaler appliance (env: NETSCALER_HOST)",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
parser.add_argument(
|
|
45
|
+
"-u",
|
|
46
|
+
"--username",
|
|
47
|
+
default=os.getenv("NETSCALER_USER", DEFAULT_USERNAME),
|
|
48
|
+
help=f"Username for authentication (env: NETSCALER_USER, default: {DEFAULT_USERNAME})",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"-p",
|
|
53
|
+
"--password",
|
|
54
|
+
default=os.getenv("NETSCALER_PASS", DEFAULT_PASSWORD),
|
|
55
|
+
help=f"Password for authentication (env: NETSCALER_PASS, default: {DEFAULT_PASSWORD})",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
parser.add_argument(
|
|
59
|
+
"--no-ssl",
|
|
60
|
+
dest="ssl",
|
|
61
|
+
action="store_false",
|
|
62
|
+
default=True,
|
|
63
|
+
help="Use HTTP instead of HTTPS (default: HTTPS)",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
parser.add_argument(
|
|
67
|
+
"-P",
|
|
68
|
+
"--port",
|
|
69
|
+
type=int,
|
|
70
|
+
help="TCP port to connect to (default: 80 for HTTP, 443 for HTTPS)",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
parser.add_argument(
|
|
74
|
+
"-a",
|
|
75
|
+
"--api",
|
|
76
|
+
default=DEFAULT_API_VERSION,
|
|
77
|
+
help=f"NITRO API version (default: {DEFAULT_API_VERSION})",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"-t",
|
|
82
|
+
"--timeout",
|
|
83
|
+
type=int,
|
|
84
|
+
default=DEFAULT_TIMEOUT,
|
|
85
|
+
help=f"Connection timeout in seconds (default: {DEFAULT_TIMEOUT})",
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Check command arguments
|
|
89
|
+
parser.add_argument(
|
|
90
|
+
"-C",
|
|
91
|
+
"--command",
|
|
92
|
+
required=True,
|
|
93
|
+
choices=[
|
|
94
|
+
"state",
|
|
95
|
+
"sslcert",
|
|
96
|
+
"above",
|
|
97
|
+
"below",
|
|
98
|
+
"matches",
|
|
99
|
+
"matches_not",
|
|
100
|
+
"nsconfig",
|
|
101
|
+
"hastatus",
|
|
102
|
+
"servicegroup",
|
|
103
|
+
"hwinfo",
|
|
104
|
+
"interfaces",
|
|
105
|
+
"perfdata",
|
|
106
|
+
"license",
|
|
107
|
+
"staserver",
|
|
108
|
+
"ntp",
|
|
109
|
+
"debug",
|
|
110
|
+
],
|
|
111
|
+
help="Check command to execute",
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
parser.add_argument(
|
|
115
|
+
"-o",
|
|
116
|
+
"--objecttype",
|
|
117
|
+
help="Object type to check (e.g., lbvserver, service, servicegroup)",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
parser.add_argument(
|
|
121
|
+
"-n",
|
|
122
|
+
"--objectname",
|
|
123
|
+
help="Filter by specific object name",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
parser.add_argument(
|
|
127
|
+
"-e",
|
|
128
|
+
"--endpoint",
|
|
129
|
+
choices=["stat", "config"],
|
|
130
|
+
help="API endpoint type (stat or config)",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Threshold arguments
|
|
134
|
+
parser.add_argument(
|
|
135
|
+
"-w",
|
|
136
|
+
"--warning",
|
|
137
|
+
help="Warning threshold",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
parser.add_argument(
|
|
141
|
+
"-c",
|
|
142
|
+
"--critical",
|
|
143
|
+
help="Critical threshold",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Additional options
|
|
147
|
+
parser.add_argument(
|
|
148
|
+
"-f",
|
|
149
|
+
"--filter",
|
|
150
|
+
help="Filter objects using regular expression",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
parser.add_argument(
|
|
154
|
+
"-l",
|
|
155
|
+
"--limit",
|
|
156
|
+
help="Limit check to objects matching pattern (regex)",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
parser.add_argument(
|
|
160
|
+
"-L",
|
|
161
|
+
"--label",
|
|
162
|
+
help="Field name to use as label in output",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
parser.add_argument(
|
|
166
|
+
"--separator",
|
|
167
|
+
default=".",
|
|
168
|
+
help="Separator for performance data labels (default: .)",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
parser.add_argument(
|
|
172
|
+
"-x",
|
|
173
|
+
"--urlopts",
|
|
174
|
+
help="Additional URL options for API requests",
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
parser.add_argument(
|
|
178
|
+
"-v",
|
|
179
|
+
"--verbose",
|
|
180
|
+
action="count",
|
|
181
|
+
default=0,
|
|
182
|
+
help="Increase output verbosity (can be repeated)",
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
return parser
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def main(args: Optional[List[str]] = None) -> int:
|
|
189
|
+
"""Main entry point for CLI"""
|
|
190
|
+
parser = create_parser()
|
|
191
|
+
parsed_args = parser.parse_args(args)
|
|
192
|
+
|
|
193
|
+
# Validate required arguments
|
|
194
|
+
if not parsed_args.hostname:
|
|
195
|
+
parser.error("argument -H/--hostname is required (or set NETSCALER_HOST)")
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
# Import here to avoid circular dependencies
|
|
199
|
+
from check_netscaler.client import NITROClient
|
|
200
|
+
from check_netscaler.commands.state import StateCommand
|
|
201
|
+
from check_netscaler.output.nagios import NagiosOutput
|
|
202
|
+
|
|
203
|
+
# Create NITRO client
|
|
204
|
+
client = NITROClient(
|
|
205
|
+
hostname=parsed_args.hostname,
|
|
206
|
+
username=parsed_args.username,
|
|
207
|
+
password=parsed_args.password,
|
|
208
|
+
ssl=parsed_args.ssl,
|
|
209
|
+
port=parsed_args.port,
|
|
210
|
+
timeout=parsed_args.timeout,
|
|
211
|
+
verify_ssl=not parsed_args.ssl, # TODO: Add --insecure flag
|
|
212
|
+
api_version=parsed_args.api,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Execute command
|
|
216
|
+
with client:
|
|
217
|
+
if parsed_args.command == "state":
|
|
218
|
+
command = StateCommand(client, parsed_args)
|
|
219
|
+
result = command.execute()
|
|
220
|
+
elif parsed_args.command in ["above", "below"]:
|
|
221
|
+
from check_netscaler.commands.threshold import ThresholdCommand
|
|
222
|
+
|
|
223
|
+
command = ThresholdCommand(client, parsed_args)
|
|
224
|
+
result = command.execute()
|
|
225
|
+
elif parsed_args.command == "nsconfig":
|
|
226
|
+
from check_netscaler.commands.nsconfig import NSConfigCommand
|
|
227
|
+
|
|
228
|
+
command = NSConfigCommand(client, parsed_args)
|
|
229
|
+
result = command.execute()
|
|
230
|
+
elif parsed_args.command == "hwinfo":
|
|
231
|
+
from check_netscaler.commands.hwinfo import HWInfoCommand
|
|
232
|
+
|
|
233
|
+
command = HWInfoCommand(client, parsed_args)
|
|
234
|
+
result = command.execute()
|
|
235
|
+
elif parsed_args.command == "sslcert":
|
|
236
|
+
from check_netscaler.commands.sslcert import SSLCertCommand
|
|
237
|
+
|
|
238
|
+
command = SSLCertCommand(client, parsed_args)
|
|
239
|
+
result = command.execute()
|
|
240
|
+
elif parsed_args.command == "servicegroup":
|
|
241
|
+
from check_netscaler.commands.servicegroup import ServiceGroupCommand
|
|
242
|
+
|
|
243
|
+
command = ServiceGroupCommand(client, parsed_args)
|
|
244
|
+
result = command.execute()
|
|
245
|
+
elif parsed_args.command in ["matches", "matches_not"]:
|
|
246
|
+
from check_netscaler.commands.matches import MatchesCommand
|
|
247
|
+
|
|
248
|
+
command = MatchesCommand(client, parsed_args)
|
|
249
|
+
result = command.execute()
|
|
250
|
+
elif parsed_args.command == "staserver":
|
|
251
|
+
from check_netscaler.commands.staserver import STAServerCommand
|
|
252
|
+
|
|
253
|
+
command = STAServerCommand(client, parsed_args)
|
|
254
|
+
result = command.execute()
|
|
255
|
+
elif parsed_args.command == "hastatus":
|
|
256
|
+
from check_netscaler.commands.hastatus import HAStatusCommand
|
|
257
|
+
|
|
258
|
+
command = HAStatusCommand(client, parsed_args)
|
|
259
|
+
result = command.execute()
|
|
260
|
+
elif parsed_args.command == "license":
|
|
261
|
+
from check_netscaler.commands.license import LicenseCommand
|
|
262
|
+
|
|
263
|
+
command = LicenseCommand(client, parsed_args)
|
|
264
|
+
result = command.execute()
|
|
265
|
+
elif parsed_args.command == "interfaces":
|
|
266
|
+
from check_netscaler.commands.interfaces import InterfacesCommand
|
|
267
|
+
|
|
268
|
+
command = InterfacesCommand(client, parsed_args)
|
|
269
|
+
result = command.execute()
|
|
270
|
+
elif parsed_args.command == "perfdata":
|
|
271
|
+
from check_netscaler.commands.perfdata import PerfdataCommand
|
|
272
|
+
|
|
273
|
+
command = PerfdataCommand(client, parsed_args)
|
|
274
|
+
result = command.execute()
|
|
275
|
+
elif parsed_args.command == "ntp":
|
|
276
|
+
from check_netscaler.commands.ntp import NTPCommand
|
|
277
|
+
|
|
278
|
+
command = NTPCommand(client, parsed_args)
|
|
279
|
+
result = command.execute()
|
|
280
|
+
elif parsed_args.command == "debug":
|
|
281
|
+
from check_netscaler.commands.debug import DebugCommand
|
|
282
|
+
|
|
283
|
+
command = DebugCommand(client, parsed_args)
|
|
284
|
+
result = command.execute()
|
|
285
|
+
else:
|
|
286
|
+
print(f"UNKNOWN - Command '{parsed_args.command}' not yet implemented")
|
|
287
|
+
return STATE_UNKNOWN
|
|
288
|
+
|
|
289
|
+
# Format and print output
|
|
290
|
+
output = NagiosOutput.format_output(
|
|
291
|
+
status=result.status,
|
|
292
|
+
message=result.message,
|
|
293
|
+
perfdata=result.perfdata,
|
|
294
|
+
long_output=result.long_output,
|
|
295
|
+
separator=parsed_args.separator,
|
|
296
|
+
)
|
|
297
|
+
print(output)
|
|
298
|
+
|
|
299
|
+
return result.status
|
|
300
|
+
|
|
301
|
+
except KeyboardInterrupt:
|
|
302
|
+
print("UNKNOWN - Interrupted by user")
|
|
303
|
+
return STATE_UNKNOWN
|
|
304
|
+
except Exception as e:
|
|
305
|
+
print(f"UNKNOWN - Unexpected error: {e}")
|
|
306
|
+
if parsed_args.verbose > 0:
|
|
307
|
+
import traceback
|
|
308
|
+
|
|
309
|
+
traceback.print_exc()
|
|
310
|
+
return STATE_UNKNOWN
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
if __name__ == "__main__":
|
|
314
|
+
sys.exit(main())
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""NITRO API client for NetScaler ADC"""
|
|
2
|
+
|
|
3
|
+
from check_netscaler.client.exceptions import (
|
|
4
|
+
NITROAPIError,
|
|
5
|
+
NITROAuthenticationError,
|
|
6
|
+
NITROConnectionError,
|
|
7
|
+
NITROException,
|
|
8
|
+
NITROPermissionError,
|
|
9
|
+
NITROResourceNotFoundError,
|
|
10
|
+
NITROTimeoutError,
|
|
11
|
+
)
|
|
12
|
+
from check_netscaler.client.nitro import NITROClient
|
|
13
|
+
from check_netscaler.client.session import NITROSession
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"NITROClient",
|
|
17
|
+
"NITROSession",
|
|
18
|
+
"NITROException",
|
|
19
|
+
"NITROAuthenticationError",
|
|
20
|
+
"NITROConnectionError",
|
|
21
|
+
"NITROTimeoutError",
|
|
22
|
+
"NITROAPIError",
|
|
23
|
+
"NITROResourceNotFoundError",
|
|
24
|
+
"NITROPermissionError",
|
|
25
|
+
]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Exceptions for NITRO API client
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NITROException(Exception):
|
|
7
|
+
"""Base exception for all NITRO client errors"""
|
|
8
|
+
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class NITROAuthenticationError(NITROException):
|
|
13
|
+
"""Authentication failed (login error)"""
|
|
14
|
+
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class NITROConnectionError(NITROException):
|
|
19
|
+
"""Connection to NetScaler failed"""
|
|
20
|
+
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class NITROTimeoutError(NITROException):
|
|
25
|
+
"""Request timed out"""
|
|
26
|
+
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class NITROAPIError(NITROException):
|
|
31
|
+
"""API returned an error response"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, message: str, error_code: int = None, response: dict = None):
|
|
34
|
+
super().__init__(message)
|
|
35
|
+
self.error_code = error_code
|
|
36
|
+
self.response = response
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class NITROResourceNotFoundError(NITROAPIError):
|
|
40
|
+
"""Requested resource not found (404)"""
|
|
41
|
+
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class NITROPermissionError(NITROAPIError):
|
|
46
|
+
"""Insufficient permissions (403)"""
|
|
47
|
+
|
|
48
|
+
pass
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NITRO API client for NetScaler
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from check_netscaler.client.exceptions import (
|
|
10
|
+
NITROAPIError,
|
|
11
|
+
NITROConnectionError,
|
|
12
|
+
NITROPermissionError,
|
|
13
|
+
NITROResourceNotFoundError,
|
|
14
|
+
NITROTimeoutError,
|
|
15
|
+
)
|
|
16
|
+
from check_netscaler.client.session import NITROSession
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class NITROClient:
|
|
20
|
+
"""Client for NetScaler NITRO REST API"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
hostname: str,
|
|
25
|
+
username: str,
|
|
26
|
+
password: str,
|
|
27
|
+
ssl: bool = True,
|
|
28
|
+
port: Optional[int] = None,
|
|
29
|
+
timeout: int = 15,
|
|
30
|
+
verify_ssl: bool = True,
|
|
31
|
+
api_version: str = "v1",
|
|
32
|
+
):
|
|
33
|
+
"""
|
|
34
|
+
Initialize NITRO API client
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
hostname: NetScaler hostname or IP address
|
|
38
|
+
username: Username for authentication
|
|
39
|
+
password: Password for authentication
|
|
40
|
+
ssl: Use HTTPS (default: True)
|
|
41
|
+
port: Custom port (default: 80 for HTTP, 443 for HTTPS)
|
|
42
|
+
timeout: Request timeout in seconds
|
|
43
|
+
verify_ssl: Verify SSL certificates (default: True)
|
|
44
|
+
api_version: API version (default: v1)
|
|
45
|
+
"""
|
|
46
|
+
self.session = NITROSession(
|
|
47
|
+
hostname=hostname,
|
|
48
|
+
username=username,
|
|
49
|
+
password=password,
|
|
50
|
+
ssl=ssl,
|
|
51
|
+
port=port,
|
|
52
|
+
timeout=timeout,
|
|
53
|
+
verify_ssl=verify_ssl,
|
|
54
|
+
)
|
|
55
|
+
self.api_version = api_version
|
|
56
|
+
|
|
57
|
+
def login(self) -> None:
|
|
58
|
+
"""Authenticate with NetScaler"""
|
|
59
|
+
self.session.login()
|
|
60
|
+
|
|
61
|
+
def logout(self) -> None:
|
|
62
|
+
"""Logout from NetScaler"""
|
|
63
|
+
self.session.logout()
|
|
64
|
+
|
|
65
|
+
def get(
|
|
66
|
+
self,
|
|
67
|
+
resource_type: str,
|
|
68
|
+
resource_name: Optional[str] = None,
|
|
69
|
+
endpoint: str = "stat",
|
|
70
|
+
url_options: Optional[str] = None,
|
|
71
|
+
) -> Dict[str, Any]:
|
|
72
|
+
"""
|
|
73
|
+
Perform GET request to NITRO API
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
resource_type: Type of resource (e.g., 'lbvserver', 'service')
|
|
77
|
+
resource_name: Specific resource name (optional)
|
|
78
|
+
endpoint: API endpoint type ('stat' or 'config')
|
|
79
|
+
url_options: Additional URL options (e.g., 'args=detail:true')
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
API response as dictionary
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
NITROAPIError: If API returns an error
|
|
86
|
+
NITROResourceNotFoundError: If resource not found (404)
|
|
87
|
+
NITROPermissionError: If insufficient permissions (403)
|
|
88
|
+
NITROConnectionError: If connection fails
|
|
89
|
+
NITROTimeoutError: If request times out
|
|
90
|
+
"""
|
|
91
|
+
if not self.session.is_logged_in:
|
|
92
|
+
raise NITROAPIError("Not logged in. Call login() first.")
|
|
93
|
+
|
|
94
|
+
# Build URL
|
|
95
|
+
url_parts = [self.session.base_url, endpoint, resource_type]
|
|
96
|
+
if resource_name:
|
|
97
|
+
url_parts.append(resource_name)
|
|
98
|
+
|
|
99
|
+
url = "/".join(url_parts)
|
|
100
|
+
|
|
101
|
+
if url_options:
|
|
102
|
+
url = f"{url}?{url_options}"
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
response = self.session.session.get(
|
|
106
|
+
url,
|
|
107
|
+
timeout=self.session.timeout,
|
|
108
|
+
verify=self.session.verify_ssl,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Handle HTTP errors
|
|
112
|
+
if response.status_code == 404:
|
|
113
|
+
raise NITROResourceNotFoundError(
|
|
114
|
+
f"Resource not found: {resource_type}"
|
|
115
|
+
+ (f"/{resource_name}" if resource_name else "")
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
if response.status_code == 403:
|
|
119
|
+
raise NITROPermissionError(f"Insufficient permissions to access {resource_type}")
|
|
120
|
+
|
|
121
|
+
if response.status_code >= 400:
|
|
122
|
+
raise NITROAPIError(
|
|
123
|
+
f"API error {response.status_code}: {response.text}",
|
|
124
|
+
error_code=response.status_code,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Parse JSON response
|
|
128
|
+
data = response.json()
|
|
129
|
+
|
|
130
|
+
# Check for NITRO error in response
|
|
131
|
+
if "errorcode" in data and data["errorcode"] != 0:
|
|
132
|
+
error_msg = data.get("message", "Unknown error")
|
|
133
|
+
error_code = data.get("errorcode")
|
|
134
|
+
raise NITROAPIError(
|
|
135
|
+
f"NITRO API error {error_code}: {error_msg}",
|
|
136
|
+
error_code=error_code,
|
|
137
|
+
response=data,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
return data
|
|
141
|
+
|
|
142
|
+
except requests.exceptions.Timeout as e:
|
|
143
|
+
raise NITROTimeoutError(f"Request timed out: {e}") from e
|
|
144
|
+
except requests.exceptions.ConnectionError as e:
|
|
145
|
+
raise NITROConnectionError(f"Connection failed: {e}") from e
|
|
146
|
+
except requests.exceptions.RequestException as e:
|
|
147
|
+
raise NITROConnectionError(f"Request failed: {e}") from e
|
|
148
|
+
|
|
149
|
+
def get_stat(
|
|
150
|
+
self,
|
|
151
|
+
resource_type: str,
|
|
152
|
+
resource_name: Optional[str] = None,
|
|
153
|
+
url_options: Optional[str] = None,
|
|
154
|
+
) -> Dict[str, Any]:
|
|
155
|
+
"""
|
|
156
|
+
Get statistics for a resource
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
resource_type: Type of resource
|
|
160
|
+
resource_name: Specific resource name (optional)
|
|
161
|
+
url_options: Additional URL options
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
Statistics data
|
|
165
|
+
"""
|
|
166
|
+
return self.get(resource_type, resource_name, endpoint="stat", url_options=url_options)
|
|
167
|
+
|
|
168
|
+
def get_config(
|
|
169
|
+
self,
|
|
170
|
+
resource_type: str,
|
|
171
|
+
resource_name: Optional[str] = None,
|
|
172
|
+
url_options: Optional[str] = None,
|
|
173
|
+
) -> Dict[str, Any]:
|
|
174
|
+
"""
|
|
175
|
+
Get configuration for a resource
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
resource_type: Type of resource
|
|
179
|
+
resource_name: Specific resource name (optional)
|
|
180
|
+
url_options: Additional URL options
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Configuration data
|
|
184
|
+
"""
|
|
185
|
+
return self.get(resource_type, resource_name, endpoint="config", url_options=url_options)
|
|
186
|
+
|
|
187
|
+
def __enter__(self):
|
|
188
|
+
"""Context manager entry"""
|
|
189
|
+
self.login()
|
|
190
|
+
return self
|
|
191
|
+
|
|
192
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
193
|
+
"""Context manager exit"""
|
|
194
|
+
self.logout()
|
|
195
|
+
return False
|