besapi 3.8.1__tar.gz → 3.8.2__tar.gz
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.
- {besapi-3.8.1/src/besapi.egg-info → besapi-3.8.2}/PKG-INFO +15 -2
- {besapi-3.8.1 → besapi-3.8.2}/setup.cfg +5 -0
- {besapi-3.8.1 → besapi-3.8.2}/setup.py +4 -9
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi/__init__.py +1 -3
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi/__main__.py +1 -3
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi/besapi.py +119 -57
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi/plugin_utilities.py +10 -7
- {besapi-3.8.1 → besapi-3.8.2/src/besapi.egg-info}/PKG-INFO +15 -2
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi.egg-info/requires.txt +1 -0
- {besapi-3.8.1 → besapi-3.8.2}/src/bescli/__init__.py +1 -3
- {besapi-3.8.1 → besapi-3.8.2}/src/bescli/__main__.py +1 -3
- {besapi-3.8.1 → besapi-3.8.2}/src/bescli/bescli.py +45 -41
- {besapi-3.8.1 → besapi-3.8.2}/tests/tests.py +4 -4
- {besapi-3.8.1 → besapi-3.8.2}/LICENSE.txt +0 -0
- {besapi-3.8.1 → besapi-3.8.2}/MANIFEST.in +0 -0
- {besapi-3.8.1 → besapi-3.8.2}/README.md +0 -0
- {besapi-3.8.1 → besapi-3.8.2}/pyproject.toml +0 -0
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi/schemas/BES.xsd +0 -0
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi/schemas/BESAPI.xsd +0 -0
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi/schemas/BESActionSettings.xsd +0 -0
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi.egg-info/SOURCES.txt +0 -0
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi.egg-info/dependency_links.txt +0 -0
- {besapi-3.8.1 → besapi-3.8.2}/src/besapi.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: besapi
|
|
3
|
-
Version: 3.8.
|
|
3
|
+
Version: 3.8.2
|
|
4
4
|
Summary: Library for working with the BigFix REST API
|
|
5
5
|
Home-page: https://github.com/jgstew/besapi
|
|
6
6
|
Author: Matt Hansen, James Stewart
|
|
@@ -8,14 +8,27 @@ Author-email: hansen.m@psu.edu, james@jgstew.com
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Keywords: bigfix iem tem rest api
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
12
|
Classifier: Operating System :: OS Independent
|
|
12
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Topic :: System :: Systems Administration
|
|
13
18
|
Requires-Python: >=3.7
|
|
14
19
|
Description-Content-Type: text/markdown
|
|
15
20
|
License-File: LICENSE.txt
|
|
16
21
|
Requires-Dist: requests
|
|
17
22
|
Requires-Dist: lxml
|
|
18
23
|
Requires-Dist: cmd2
|
|
24
|
+
Requires-Dist: setuptools
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: keywords
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: summary
|
|
19
32
|
|
|
20
33
|
# besapi
|
|
21
34
|
|
|
@@ -4,8 +4,13 @@ long_description = file: README.md
|
|
|
4
4
|
long_description_content_type = text/markdown
|
|
5
5
|
classifiers =
|
|
6
6
|
Programming Language :: Python :: 3
|
|
7
|
+
Programming Language :: Python :: 3.9
|
|
7
8
|
Operating System :: OS Independent
|
|
8
9
|
License :: OSI Approved :: MIT License
|
|
10
|
+
Development Status :: 5 - Production/Stable
|
|
11
|
+
Intended Audience :: Developers
|
|
12
|
+
Topic :: Software Development :: Libraries :: Python Modules
|
|
13
|
+
Topic :: System :: Systems Administration
|
|
9
14
|
|
|
10
15
|
[options]
|
|
11
16
|
python_requires = >=3.7
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
|
-
"""
|
|
3
|
-
file to configure python build and packaging for pip
|
|
4
|
-
"""
|
|
2
|
+
"""File to configure python build and packaging for pip."""
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
from setuptools import setup
|
|
8
|
-
except (ImportError, ModuleNotFoundError):
|
|
9
|
-
from distutils.core import setup
|
|
4
|
+
import setuptools
|
|
10
5
|
|
|
11
|
-
setup(
|
|
6
|
+
setuptools.setup(
|
|
12
7
|
name="besapi",
|
|
13
8
|
# version= moved to setup.cfg
|
|
14
9
|
author="Matt Hansen, James Stewart",
|
|
@@ -20,7 +15,7 @@ setup(
|
|
|
20
15
|
# long_description= moved to setup.cfg
|
|
21
16
|
packages=["besapi", "bescli"],
|
|
22
17
|
package_data={"besapi": ["schemas/*.xsd"]},
|
|
23
|
-
install_requires=["requests", "lxml", "cmd2"],
|
|
18
|
+
install_requires=["requests", "lxml", "cmd2", "setuptools"],
|
|
24
19
|
include_package_data=True,
|
|
25
20
|
package_dir={"": "src"},
|
|
26
21
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
"""
|
|
3
|
-
besapi.
|
|
3
|
+
This module besapi provides a simple interface to the BigFix REST API.
|
|
4
4
|
|
|
5
5
|
MIT License
|
|
6
6
|
Copyright (c) 2014 Matt Hansen
|
|
@@ -23,19 +23,21 @@ import typing
|
|
|
23
23
|
try:
|
|
24
24
|
from urllib import parse
|
|
25
25
|
except ImportError:
|
|
26
|
-
from urlparse import parse_qs as parse
|
|
26
|
+
from urlparse import parse_qs as parse # type: ignore[no-redef,import-not-found]
|
|
27
27
|
|
|
28
28
|
import requests
|
|
29
29
|
from lxml import etree, objectify
|
|
30
30
|
from pkg_resources import resource_filename
|
|
31
31
|
|
|
32
|
-
__version__ = "3.8.
|
|
32
|
+
__version__ = "3.8.2"
|
|
33
33
|
|
|
34
34
|
besapi_logger = logging.getLogger("besapi")
|
|
35
35
|
|
|
36
|
+
# pylint: disable=consider-using-f-string
|
|
37
|
+
|
|
36
38
|
|
|
37
39
|
def rand_password(length=20):
|
|
38
|
-
"""
|
|
40
|
+
"""Get a random password."""
|
|
39
41
|
|
|
40
42
|
all_safe_chars = string.ascii_letters + string.digits + "!#()*+,-.:;<=>?[]^_|~"
|
|
41
43
|
|
|
@@ -66,6 +68,7 @@ def sanitize_txt(*args):
|
|
|
66
68
|
def elem2dict(node):
|
|
67
69
|
"""
|
|
68
70
|
Convert an lxml.etree node tree into a dict.
|
|
71
|
+
|
|
69
72
|
https://gist.github.com/jacobian/795571?permalink_comment_id=2981870#gistcomment-2981870
|
|
70
73
|
"""
|
|
71
74
|
result = {}
|
|
@@ -94,7 +97,10 @@ def elem2dict(node):
|
|
|
94
97
|
def replace_text_between(
|
|
95
98
|
original_text, first_delimiter, second_delimiter, replacement_text
|
|
96
99
|
):
|
|
97
|
-
"""Replace text between delimiters.
|
|
100
|
+
"""Replace text between delimiters.
|
|
101
|
+
|
|
102
|
+
Each delimiter should only appear once.
|
|
103
|
+
"""
|
|
98
104
|
leading_text = original_text.split(first_delimiter)[0]
|
|
99
105
|
trailing_text = original_text.split(second_delimiter)[1]
|
|
100
106
|
|
|
@@ -109,7 +115,7 @@ def replace_text_between(
|
|
|
109
115
|
|
|
110
116
|
# https://github.com/jgstew/generate_bes_from_template/blob/bcc6c79632dd375c2861608ded3ae5872801a669/src/generate_bes_from_template/generate_bes_from_template.py#L87-L92
|
|
111
117
|
def parse_bes_modtime(string_datetime):
|
|
112
|
-
"""
|
|
118
|
+
"""Parse datetime string to object."""
|
|
113
119
|
# ("%a, %d %b %Y %H:%M:%S %z")
|
|
114
120
|
return datetime.datetime.strptime(string_datetime, "%a, %d %b %Y %H:%M:%S %z")
|
|
115
121
|
|
|
@@ -153,7 +159,9 @@ def parse_bes_modtime(string_datetime):
|
|
|
153
159
|
|
|
154
160
|
|
|
155
161
|
def get_action_combined_relevance(relevances: typing.List[str]):
|
|
156
|
-
"""
|
|
162
|
+
"""Take array of ordered relevance clauses and return relevance string for
|
|
163
|
+
action.
|
|
164
|
+
"""
|
|
157
165
|
|
|
158
166
|
relevance_combined = ""
|
|
159
167
|
|
|
@@ -176,7 +184,7 @@ def get_action_combined_relevance(relevances: typing.List[str]):
|
|
|
176
184
|
|
|
177
185
|
|
|
178
186
|
def get_target_xml(targets=None):
|
|
179
|
-
"""
|
|
187
|
+
"""Get target xml based upon input.
|
|
180
188
|
|
|
181
189
|
Input can be a single string:
|
|
182
190
|
- starts with "<AllComputers>" if all computers should be targeted
|
|
@@ -239,7 +247,7 @@ def get_target_xml(targets=None):
|
|
|
239
247
|
|
|
240
248
|
|
|
241
249
|
def validate_xsd(doc):
|
|
242
|
-
"""
|
|
250
|
+
"""Validate results using XML XSDs."""
|
|
243
251
|
try:
|
|
244
252
|
xmldoc = etree.fromstring(doc)
|
|
245
253
|
except BaseException: # pylint: disable=broad-except
|
|
@@ -262,9 +270,25 @@ def validate_xsd(doc):
|
|
|
262
270
|
return False
|
|
263
271
|
|
|
264
272
|
|
|
273
|
+
def validate_xml_bes_file(file_path):
|
|
274
|
+
"""Take a file path as input,
|
|
275
|
+
read as binary data,.
|
|
276
|
+
|
|
277
|
+
validate against xml schema
|
|
278
|
+
|
|
279
|
+
returns True for valid xml
|
|
280
|
+
returns False for invalid xml (or if file is not xml)
|
|
281
|
+
"""
|
|
282
|
+
with open(file_path, "rb") as file:
|
|
283
|
+
file_data = file.read()
|
|
284
|
+
|
|
285
|
+
return validate_xsd(file_data)
|
|
286
|
+
|
|
287
|
+
|
|
265
288
|
def get_bes_conn_using_config_file(conf_file=None):
|
|
266
289
|
"""
|
|
267
|
-
|
|
290
|
+
Read connection values from config file.
|
|
291
|
+
|
|
268
292
|
return besapi connection
|
|
269
293
|
"""
|
|
270
294
|
config_paths = [
|
|
@@ -305,7 +329,7 @@ def get_bes_conn_using_config_file(conf_file=None):
|
|
|
305
329
|
|
|
306
330
|
|
|
307
331
|
class BESConnection:
|
|
308
|
-
"""BigFix RESTAPI connection abstraction class"""
|
|
332
|
+
"""BigFix RESTAPI connection abstraction class."""
|
|
309
333
|
|
|
310
334
|
def __init__(self, username, password, rootserver, verify=False):
|
|
311
335
|
if not verify:
|
|
@@ -341,7 +365,7 @@ class BESConnection:
|
|
|
341
365
|
self.login()
|
|
342
366
|
|
|
343
367
|
def __repr__(self):
|
|
344
|
-
"""
|
|
368
|
+
"""Object representation."""
|
|
345
369
|
# https://stackoverflow.com/a/2626364/861745
|
|
346
370
|
return f"Object: besapi.BESConnection( username={self.username}, rootserver={self.rootserver} )"
|
|
347
371
|
|
|
@@ -355,16 +379,16 @@ class BESConnection:
|
|
|
355
379
|
return False
|
|
356
380
|
|
|
357
381
|
def __del__(self):
|
|
358
|
-
"""
|
|
382
|
+
"""Cleanup on deletion of instance."""
|
|
359
383
|
self.logout()
|
|
360
384
|
self.session.auth = None
|
|
361
385
|
|
|
362
386
|
def __bool__(self):
|
|
363
|
-
"""
|
|
387
|
+
"""Get true or false."""
|
|
364
388
|
return self.login()
|
|
365
389
|
|
|
366
390
|
def url(self, path):
|
|
367
|
-
"""
|
|
391
|
+
"""Get absolute url."""
|
|
368
392
|
if path.startswith(self.rootserver):
|
|
369
393
|
url = path
|
|
370
394
|
else:
|
|
@@ -373,35 +397,61 @@ class BESConnection:
|
|
|
373
397
|
return url
|
|
374
398
|
|
|
375
399
|
def get(self, path="help", **kwargs):
|
|
376
|
-
"""HTTP GET request"""
|
|
400
|
+
"""HTTP GET request."""
|
|
377
401
|
self.last_connected = datetime.datetime.now()
|
|
378
402
|
return RESTResult(
|
|
379
403
|
self.session.get(self.url(path), verify=self.verify, **kwargs)
|
|
380
404
|
)
|
|
381
405
|
|
|
382
|
-
def post(self, path, data, **kwargs):
|
|
383
|
-
"""HTTP POST request"""
|
|
406
|
+
def post(self, path, data, validate_xml=None, **kwargs):
|
|
407
|
+
"""HTTP POST request."""
|
|
408
|
+
|
|
409
|
+
# if validate_xml is true, data must validate to xml schema
|
|
410
|
+
# if validate_xml is false, no schema check will be made
|
|
411
|
+
if validate_xml:
|
|
412
|
+
if not validate_xsd(data):
|
|
413
|
+
err_msg = "data being posted did not validate to XML schema. If expected, consider setting validate_xml to false."
|
|
414
|
+
if validate_xml:
|
|
415
|
+
logging.error(err_msg)
|
|
416
|
+
raise ValueError(err_msg)
|
|
417
|
+
else:
|
|
418
|
+
# this is intended it validate_xml is None, but not used currently
|
|
419
|
+
logging.warning(err_msg)
|
|
420
|
+
|
|
384
421
|
self.last_connected = datetime.datetime.now()
|
|
385
422
|
return RESTResult(
|
|
386
423
|
self.session.post(self.url(path), data=data, verify=self.verify, **kwargs)
|
|
387
424
|
)
|
|
388
425
|
|
|
389
|
-
def put(self, path, data, **kwargs):
|
|
390
|
-
"""HTTP PUT request"""
|
|
426
|
+
def put(self, path, data, validate_xml=None, **kwargs):
|
|
427
|
+
"""HTTP PUT request."""
|
|
391
428
|
self.last_connected = datetime.datetime.now()
|
|
429
|
+
|
|
430
|
+
# if validate_xml is true, data must validate to xml schema
|
|
431
|
+
# if validate_xml is false, no schema check will be made
|
|
432
|
+
if validate_xml:
|
|
433
|
+
if not validate_xsd(data):
|
|
434
|
+
err_msg = "data being put did not validate to XML schema. If expected, consider setting validate_xml to false."
|
|
435
|
+
if validate_xml:
|
|
436
|
+
logging.error(err_msg)
|
|
437
|
+
raise ValueError(err_msg)
|
|
438
|
+
else:
|
|
439
|
+
# this is intended it validate_xml is None, but not used currently
|
|
440
|
+
logging.warning(err_msg)
|
|
441
|
+
|
|
392
442
|
return RESTResult(
|
|
393
443
|
self.session.put(self.url(path), data=data, verify=self.verify, **kwargs)
|
|
394
444
|
)
|
|
395
445
|
|
|
396
446
|
def delete(self, path, **kwargs):
|
|
397
|
-
"""HTTP DELETE request"""
|
|
447
|
+
"""HTTP DELETE request."""
|
|
398
448
|
self.last_connected = datetime.datetime.now()
|
|
399
449
|
return RESTResult(
|
|
400
450
|
self.session.delete(self.url(path), verify=self.verify, **kwargs)
|
|
401
451
|
)
|
|
402
452
|
|
|
403
453
|
def session_relevance_xml(self, relevance, **kwargs):
|
|
404
|
-
"""Get Session Relevance Results XML"""
|
|
454
|
+
"""Get Session Relevance Results XML."""
|
|
405
455
|
self.last_connected = datetime.datetime.now()
|
|
406
456
|
return RESTResult(
|
|
407
457
|
self.session.post(
|
|
@@ -413,7 +463,7 @@ class BESConnection:
|
|
|
413
463
|
)
|
|
414
464
|
|
|
415
465
|
def session_relevance_array(self, relevance, **kwargs):
|
|
416
|
-
"""Get Session Relevance Results array"""
|
|
466
|
+
"""Get Session Relevance Results array."""
|
|
417
467
|
rel_result = self.session_relevance_xml(relevance, **kwargs)
|
|
418
468
|
# print(rel_result)
|
|
419
469
|
result = []
|
|
@@ -440,14 +490,14 @@ class BESConnection:
|
|
|
440
490
|
return result
|
|
441
491
|
|
|
442
492
|
def session_relevance_string(self, relevance, **kwargs):
|
|
443
|
-
"""Get Session Relevance Results string"""
|
|
493
|
+
"""Get Session Relevance Results string."""
|
|
444
494
|
rel_result_array = self.session_relevance_array(
|
|
445
495
|
"(it as string) of ( " + relevance + " )", **kwargs
|
|
446
496
|
)
|
|
447
497
|
return "\n".join(rel_result_array)
|
|
448
498
|
|
|
449
499
|
def login(self):
|
|
450
|
-
"""
|
|
500
|
+
"""Do login."""
|
|
451
501
|
if bool(self.last_connected):
|
|
452
502
|
duration_obj = datetime.datetime.now() - self.last_connected
|
|
453
503
|
duration_minutes = duration_obj / datetime.timedelta(minutes=1)
|
|
@@ -478,14 +528,14 @@ class BESConnection:
|
|
|
478
528
|
return bool(self.last_connected)
|
|
479
529
|
|
|
480
530
|
def logout(self):
|
|
481
|
-
"""
|
|
531
|
+
"""Clear session and close it."""
|
|
482
532
|
self.session.cookies.clear()
|
|
483
533
|
self.session.close()
|
|
484
534
|
|
|
485
535
|
def set_dashboard_variable_value(
|
|
486
536
|
self, dashboard_name, var_name, var_value, private=False
|
|
487
537
|
):
|
|
488
|
-
"""
|
|
538
|
+
"""Set the variable value from a dashboard datastore."""
|
|
489
539
|
|
|
490
540
|
dash_var_xml = f"""<BESAPI xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="BESAPI.xsd">
|
|
491
541
|
<DashboardData>
|
|
@@ -502,7 +552,7 @@ class BESConnection:
|
|
|
502
552
|
)
|
|
503
553
|
|
|
504
554
|
def get_dashboard_variable_value(self, dashboard_name, var_name):
|
|
505
|
-
"""
|
|
555
|
+
"""Get the variable value from a dashboard datastore."""
|
|
506
556
|
|
|
507
557
|
return str(
|
|
508
558
|
self.get(
|
|
@@ -511,7 +561,7 @@ class BESConnection:
|
|
|
511
561
|
)
|
|
512
562
|
|
|
513
563
|
def validate_site_path(self, site_path, check_site_exists=True, raise_error=False):
|
|
514
|
-
"""
|
|
564
|
+
"""Make sure site_path is valid."""
|
|
515
565
|
|
|
516
566
|
if site_path is None:
|
|
517
567
|
if not raise_error:
|
|
@@ -554,8 +604,9 @@ class BESConnection:
|
|
|
554
604
|
)
|
|
555
605
|
|
|
556
606
|
def get_current_site_path(self, site_path=None):
|
|
557
|
-
"""
|
|
558
|
-
otherwise validate and return provided site_path
|
|
607
|
+
"""If site_path is none, get current instance site_path,
|
|
608
|
+
otherwise validate and return provided site_path.
|
|
609
|
+
"""
|
|
559
610
|
|
|
560
611
|
# use instance site_path context if none provided:
|
|
561
612
|
if site_path is None or str(site_path).strip() == "":
|
|
@@ -569,14 +620,14 @@ class BESConnection:
|
|
|
569
620
|
return self.validate_site_path(site_path, check_site_exists=False)
|
|
570
621
|
|
|
571
622
|
def set_current_site_path(self, site_path):
|
|
572
|
-
"""
|
|
623
|
+
"""Set current site path context."""
|
|
573
624
|
|
|
574
625
|
if self.validate_site_path(site_path):
|
|
575
626
|
self.site_path = site_path
|
|
576
627
|
return self.site_path
|
|
577
628
|
|
|
578
629
|
def import_bes_to_site(self, bes_file_path, site_path=None):
|
|
579
|
-
"""
|
|
630
|
+
"""Import bes file to site."""
|
|
580
631
|
|
|
581
632
|
if not os.access(bes_file_path, os.R_OK):
|
|
582
633
|
besapi_logger.error("%s is not readable", bes_file_path)
|
|
@@ -599,7 +650,7 @@ class BESConnection:
|
|
|
599
650
|
return result
|
|
600
651
|
|
|
601
652
|
def create_site_from_file(self, bes_file_path, site_type="custom"):
|
|
602
|
-
"""
|
|
653
|
+
"""Create new site."""
|
|
603
654
|
xml_parsed = etree.parse(bes_file_path)
|
|
604
655
|
new_site_name = xml_parsed.xpath("/BES/CustomSite/Name/text()")[0]
|
|
605
656
|
|
|
@@ -616,7 +667,7 @@ class BESConnection:
|
|
|
616
667
|
return result_site
|
|
617
668
|
|
|
618
669
|
def get_user(self, user_name):
|
|
619
|
-
"""
|
|
670
|
+
"""Get a user."""
|
|
620
671
|
|
|
621
672
|
result_users = self.get(f"operator/{user_name}")
|
|
622
673
|
|
|
@@ -626,7 +677,7 @@ class BESConnection:
|
|
|
626
677
|
besapi_logger.info("User `%s` Not Found!", user_name)
|
|
627
678
|
|
|
628
679
|
def create_user_from_file(self, bes_file_path):
|
|
629
|
-
"""
|
|
680
|
+
"""Create user from xml."""
|
|
630
681
|
xml_parsed = etree.parse(bes_file_path)
|
|
631
682
|
new_user_name = xml_parsed.xpath("/BESAPI/Operator/Name/text()")[0]
|
|
632
683
|
result_user = self.get_user(new_user_name)
|
|
@@ -640,7 +691,7 @@ class BESConnection:
|
|
|
640
691
|
return self.get_user(new_user_name)
|
|
641
692
|
|
|
642
693
|
def get_computergroup(self, group_name, site_path=None):
|
|
643
|
-
"""
|
|
694
|
+
"""Get computer group resource URI."""
|
|
644
695
|
|
|
645
696
|
site_path = self.get_current_site_path(site_path)
|
|
646
697
|
result_groups = self.get(f"computergroups/{site_path}")
|
|
@@ -655,7 +706,7 @@ class BESConnection:
|
|
|
655
706
|
besapi_logger.info("Group `%s` Not Found!", group_name)
|
|
656
707
|
|
|
657
708
|
def create_group_from_file(self, bes_file_path, site_path=None):
|
|
658
|
-
"""
|
|
709
|
+
"""Create a new group."""
|
|
659
710
|
site_path = self.get_current_site_path(site_path)
|
|
660
711
|
xml_parsed = etree.parse(bes_file_path)
|
|
661
712
|
new_group_name = xml_parsed.xpath("/BES/ComputerGroup/Title/text()")[0]
|
|
@@ -674,7 +725,7 @@ class BESConnection:
|
|
|
674
725
|
|
|
675
726
|
def get_upload(self, file_name, file_hash):
|
|
676
727
|
"""
|
|
677
|
-
|
|
728
|
+
Check for a specific file upload reference.
|
|
678
729
|
|
|
679
730
|
each upload is uniquely identified by sha1 and filename
|
|
680
731
|
|
|
@@ -700,7 +751,8 @@ class BESConnection:
|
|
|
700
751
|
|
|
701
752
|
def upload(self, file_path, file_name=None, file_hash=None):
|
|
702
753
|
"""
|
|
703
|
-
|
|
754
|
+
Upload a single file.
|
|
755
|
+
|
|
704
756
|
https://developer.bigfix.com/rest-api/api/upload.html
|
|
705
757
|
"""
|
|
706
758
|
if not os.access(file_path, os.R_OK):
|
|
@@ -751,7 +803,7 @@ class BESConnection:
|
|
|
751
803
|
def parse_upload_result_to_prefetch(
|
|
752
804
|
self, result_upload, use_localhost=True, use_https=True
|
|
753
805
|
):
|
|
754
|
-
"""
|
|
806
|
+
"""Take a rest response from an upload and parse into prefetch."""
|
|
755
807
|
file_url = str(result_upload.besobj.FileUpload.URL)
|
|
756
808
|
if use_https:
|
|
757
809
|
file_url = file_url.replace("http://", "https://")
|
|
@@ -772,7 +824,7 @@ class BESConnection:
|
|
|
772
824
|
return f"prefetch {file_name} sha1:{file_sha1} size:{file_size} {file_url} sha256:{file_sha256}"
|
|
773
825
|
|
|
774
826
|
def get_content_by_resource(self, resource_url):
|
|
775
|
-
"""
|
|
827
|
+
"""Get a single content item by resource."""
|
|
776
828
|
# Get Specific Content
|
|
777
829
|
content = None
|
|
778
830
|
try:
|
|
@@ -790,7 +842,7 @@ class BESConnection:
|
|
|
790
842
|
return content
|
|
791
843
|
|
|
792
844
|
def update_item_from_file(self, file_path, site_path=None):
|
|
793
|
-
"""
|
|
845
|
+
"""Update an item by name and last modified."""
|
|
794
846
|
site_path = self.get_current_site_path(site_path)
|
|
795
847
|
bes_tree = etree.parse(file_path)
|
|
796
848
|
|
|
@@ -823,7 +875,7 @@ class BESConnection:
|
|
|
823
875
|
export_folder="./",
|
|
824
876
|
name_trim=100,
|
|
825
877
|
):
|
|
826
|
-
"""
|
|
878
|
+
"""Save an xml string to bes file."""
|
|
827
879
|
item_folder = export_folder
|
|
828
880
|
if not os.path.exists(item_folder):
|
|
829
881
|
os.makedirs(item_folder)
|
|
@@ -851,8 +903,10 @@ class BESConnection:
|
|
|
851
903
|
include_item_type_folder=False,
|
|
852
904
|
include_item_id=False,
|
|
853
905
|
):
|
|
854
|
-
"""
|
|
906
|
+
"""Export a single item by resource.
|
|
907
|
+
|
|
855
908
|
example resources:
|
|
909
|
+
|
|
856
910
|
- content_type/site_type/site/id
|
|
857
911
|
- https://localhost:52311/api/content_type/site_type/site/id
|
|
858
912
|
"""
|
|
@@ -899,8 +953,10 @@ class BESConnection:
|
|
|
899
953
|
include_site_folder=True,
|
|
900
954
|
include_item_ids=True,
|
|
901
955
|
):
|
|
902
|
-
"""
|
|
956
|
+
"""Export contents of site.
|
|
957
|
+
|
|
903
958
|
Originally here:
|
|
959
|
+
|
|
904
960
|
- https://gist.github.com/jgstew/1b2da12af59b71c9f88a
|
|
905
961
|
- https://bigfix.me/fixlet/details/21282
|
|
906
962
|
"""
|
|
@@ -976,7 +1032,7 @@ class BESConnection:
|
|
|
976
1032
|
def export_all_sites(
|
|
977
1033
|
self, include_external=False, export_folder="./", name_trim=70, verbose=False
|
|
978
1034
|
):
|
|
979
|
-
"""
|
|
1035
|
+
"""Export all bigfix sites to a folder."""
|
|
980
1036
|
results_sites = self.get("sites")
|
|
981
1037
|
if verbose:
|
|
982
1038
|
print(results_sites)
|
|
@@ -995,11 +1051,12 @@ class BESConnection:
|
|
|
995
1051
|
|
|
996
1052
|
|
|
997
1053
|
class RESTResult:
|
|
998
|
-
"""BigFix REST API Result Abstraction Class"""
|
|
1054
|
+
"""BigFix REST API Result Abstraction Class."""
|
|
999
1055
|
|
|
1000
1056
|
def __init__(self, request):
|
|
1001
1057
|
self.request = request
|
|
1002
1058
|
self.text = request.text
|
|
1059
|
+
self.valid = None
|
|
1003
1060
|
self._besxml = None
|
|
1004
1061
|
self._besobj = None
|
|
1005
1062
|
self._besdict = None
|
|
@@ -1034,7 +1091,9 @@ class RESTResult:
|
|
|
1034
1091
|
if self.validate_xsd(request.text):
|
|
1035
1092
|
self.valid = True
|
|
1036
1093
|
else:
|
|
1037
|
-
|
|
1094
|
+
logging.debug(
|
|
1095
|
+
"INFO: REST API Result does not appear to be XML, this could be expected."
|
|
1096
|
+
)
|
|
1038
1097
|
self.valid = False
|
|
1039
1098
|
|
|
1040
1099
|
def __str__(self):
|
|
@@ -1052,7 +1111,7 @@ class RESTResult:
|
|
|
1052
1111
|
|
|
1053
1112
|
@property
|
|
1054
1113
|
def besxml(self):
|
|
1055
|
-
"""
|
|
1114
|
+
"""Property for parsed xml representation."""
|
|
1056
1115
|
if self.valid and self._besxml is None:
|
|
1057
1116
|
self._besxml = self.xmlparse_text(self.text)
|
|
1058
1117
|
|
|
@@ -1060,7 +1119,7 @@ class RESTResult:
|
|
|
1060
1119
|
|
|
1061
1120
|
@property
|
|
1062
1121
|
def besobj(self):
|
|
1063
|
-
"""
|
|
1122
|
+
"""Property for xml object representation."""
|
|
1064
1123
|
if self.valid and self._besobj is None:
|
|
1065
1124
|
self._besobj = self.objectify_text(self.text)
|
|
1066
1125
|
|
|
@@ -1068,7 +1127,7 @@ class RESTResult:
|
|
|
1068
1127
|
|
|
1069
1128
|
@property
|
|
1070
1129
|
def besdict(self):
|
|
1071
|
-
"""
|
|
1130
|
+
"""Property for python dict representation."""
|
|
1072
1131
|
if self._besdict is None:
|
|
1073
1132
|
if self.valid:
|
|
1074
1133
|
self._besdict = elem2dict(etree.fromstring(self.besxml))
|
|
@@ -1079,18 +1138,21 @@ class RESTResult:
|
|
|
1079
1138
|
|
|
1080
1139
|
@property
|
|
1081
1140
|
def besjson(self):
|
|
1082
|
-
"""
|
|
1141
|
+
"""Property for json representation."""
|
|
1083
1142
|
if self._besjson is None:
|
|
1084
1143
|
self._besjson = json.dumps(self.besdict, indent=2)
|
|
1085
1144
|
|
|
1086
1145
|
return self._besjson
|
|
1087
1146
|
|
|
1088
1147
|
def validate_xsd(self, doc):
|
|
1089
|
-
"""
|
|
1148
|
+
"""Validate results using XML XSDs."""
|
|
1149
|
+
# return self.valid if already set
|
|
1150
|
+
if self.valid is not None and isinstance(self.valid, bool):
|
|
1151
|
+
return self.valid
|
|
1090
1152
|
return validate_xsd(doc)
|
|
1091
1153
|
|
|
1092
1154
|
def xmlparse_text(self, text):
|
|
1093
|
-
"""
|
|
1155
|
+
"""Parse response text as xml."""
|
|
1094
1156
|
if type(text) is str:
|
|
1095
1157
|
root_xml = etree.fromstring(text.encode("utf-8"))
|
|
1096
1158
|
else:
|
|
@@ -1099,7 +1161,7 @@ class RESTResult:
|
|
|
1099
1161
|
return etree.tostring(root_xml, encoding="utf-8", xml_declaration=True)
|
|
1100
1162
|
|
|
1101
1163
|
def objectify_text(self, text):
|
|
1102
|
-
"""
|
|
1164
|
+
"""Parse response text as objectified xml."""
|
|
1103
1165
|
if type(text) is str:
|
|
1104
1166
|
root_xml = text.encode("utf-8")
|
|
1105
1167
|
else:
|
|
@@ -1109,7 +1171,7 @@ class RESTResult:
|
|
|
1109
1171
|
|
|
1110
1172
|
|
|
1111
1173
|
def main():
|
|
1112
|
-
"""
|
|
1174
|
+
"""If invoked directly, run bescli command loop."""
|
|
1113
1175
|
# pylint: disable=import-outside-toplevel
|
|
1114
1176
|
try:
|
|
1115
1177
|
from bescli import bescli
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""This is a set of utility functions for use in multiple plugins
|
|
1
|
+
"""This is a set of utility functions for use in multiple plugins.
|
|
2
2
|
|
|
3
3
|
see example here: https://github.com/jgstew/besapi/blob/master/examples/export_all_sites.py
|
|
4
4
|
"""
|
|
@@ -16,7 +16,7 @@ import besapi
|
|
|
16
16
|
|
|
17
17
|
# NOTE: This does not work as expected when run from plugin_utilities
|
|
18
18
|
def get_invoke_folder(verbose=0):
|
|
19
|
-
"""Get the folder the script was invoked from"""
|
|
19
|
+
"""Get the folder the script was invoked from."""
|
|
20
20
|
# using logging here won't actually log it to the file:
|
|
21
21
|
|
|
22
22
|
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
|
@@ -36,7 +36,7 @@ def get_invoke_folder(verbose=0):
|
|
|
36
36
|
|
|
37
37
|
# NOTE: This does not work as expected when run from plugin_utilities
|
|
38
38
|
def get_invoke_file_name(verbose=0):
|
|
39
|
-
"""Get the filename the script was invoked from"""
|
|
39
|
+
"""Get the filename the script was invoked from."""
|
|
40
40
|
# using logging here won't actually log it to the file:
|
|
41
41
|
|
|
42
42
|
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
|
@@ -56,7 +56,7 @@ def get_invoke_file_name(verbose=0):
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
def setup_plugin_argparse(plugin_args_required=False):
|
|
59
|
-
"""
|
|
59
|
+
"""Setup argparse for plugin use."""
|
|
60
60
|
arg_parser = argparse.ArgumentParser(
|
|
61
61
|
description="Provide command line arguments for REST URL, username, and password"
|
|
62
62
|
)
|
|
@@ -92,9 +92,10 @@ def setup_plugin_argparse(plugin_args_required=False):
|
|
|
92
92
|
|
|
93
93
|
|
|
94
94
|
def get_plugin_logging_config(log_file_path="", verbose=0, console=True):
|
|
95
|
-
"""
|
|
95
|
+
"""Get config for logging for plugin use.
|
|
96
96
|
|
|
97
|
-
use this like: logging.basicConfig(**logging_config)
|
|
97
|
+
use this like: logging.basicConfig(**logging_config)
|
|
98
|
+
"""
|
|
98
99
|
|
|
99
100
|
if not log_file_path or log_file_path == "":
|
|
100
101
|
log_file_path = os.path.join(
|
|
@@ -131,7 +132,9 @@ def get_plugin_logging_config(log_file_path="", verbose=0, console=True):
|
|
|
131
132
|
|
|
132
133
|
|
|
133
134
|
def get_besapi_connection(args):
|
|
134
|
-
"""
|
|
135
|
+
"""Get connection to besapi using either args or config file if args not
|
|
136
|
+
provided.
|
|
137
|
+
"""
|
|
135
138
|
|
|
136
139
|
password = args.password
|
|
137
140
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: besapi
|
|
3
|
-
Version: 3.8.
|
|
3
|
+
Version: 3.8.2
|
|
4
4
|
Summary: Library for working with the BigFix REST API
|
|
5
5
|
Home-page: https://github.com/jgstew/besapi
|
|
6
6
|
Author: Matt Hansen, James Stewart
|
|
@@ -8,14 +8,27 @@ Author-email: hansen.m@psu.edu, james@jgstew.com
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Keywords: bigfix iem tem rest api
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
12
|
Classifier: Operating System :: OS Independent
|
|
12
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Topic :: System :: Systems Administration
|
|
13
18
|
Requires-Python: >=3.7
|
|
14
19
|
Description-Content-Type: text/markdown
|
|
15
20
|
License-File: LICENSE.txt
|
|
16
21
|
Requires-Dist: requests
|
|
17
22
|
Requires-Dist: lxml
|
|
18
23
|
Requires-Dist: cmd2
|
|
24
|
+
Requires-Dist: setuptools
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: keywords
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: summary
|
|
19
32
|
|
|
20
33
|
# besapi
|
|
21
34
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
"""
|
|
3
|
-
bescli.
|
|
3
|
+
This bescli module provides a command line interface to interact with besapi.
|
|
4
4
|
|
|
5
5
|
MIT License
|
|
6
6
|
Copyright (c) 2014 Matt Hansen
|
|
@@ -27,12 +27,12 @@ except ModuleNotFoundError:
|
|
|
27
27
|
from besapi import besapi
|
|
28
28
|
except ImportError:
|
|
29
29
|
# this is for the case in which we are calling bescli from besapi
|
|
30
|
-
import besapi
|
|
30
|
+
import besapi # type: ignore[no-redef]
|
|
31
31
|
|
|
32
32
|
try:
|
|
33
33
|
from besapi.besapi import __version__
|
|
34
34
|
except ImportError:
|
|
35
|
-
from besapi import __version__
|
|
35
|
+
from besapi import __version__ # type: ignore
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
class BESCLInterface(Cmd):
|
|
@@ -62,7 +62,7 @@ class BESCLInterface(Cmd):
|
|
|
62
62
|
self.do_conf()
|
|
63
63
|
|
|
64
64
|
def parse_help_resources(self):
|
|
65
|
-
"""
|
|
65
|
+
"""Get api resources from help."""
|
|
66
66
|
if self.bes_conn:
|
|
67
67
|
help_result = self.bes_conn.get("help")
|
|
68
68
|
help_result = help_result.text.split("\n")
|
|
@@ -89,7 +89,7 @@ class BESCLInterface(Cmd):
|
|
|
89
89
|
]
|
|
90
90
|
|
|
91
91
|
def complete_api_resources(self, text, line, begidx, endidx):
|
|
92
|
-
"""
|
|
92
|
+
"""Define completion for apis."""
|
|
93
93
|
|
|
94
94
|
# only initialize once
|
|
95
95
|
if not self.api_resources:
|
|
@@ -102,7 +102,9 @@ class BESCLInterface(Cmd):
|
|
|
102
102
|
complete_get = complete_api_resources
|
|
103
103
|
|
|
104
104
|
def do_get(self, line):
|
|
105
|
-
"""Perform get request to BigFix server using provided api endpoint
|
|
105
|
+
"""Perform get request to BigFix server using provided api endpoint
|
|
106
|
+
argument.
|
|
107
|
+
"""
|
|
106
108
|
|
|
107
109
|
# remove any extra whitespace
|
|
108
110
|
line = line.strip()
|
|
@@ -136,7 +138,9 @@ class BESCLInterface(Cmd):
|
|
|
136
138
|
complete_delete = complete_api_resources
|
|
137
139
|
|
|
138
140
|
def do_delete(self, line):
|
|
139
|
-
"""Perform delete request to BigFix server using provided api endpoint
|
|
141
|
+
"""Perform delete request to BigFix server using provided api endpoint
|
|
142
|
+
argument.
|
|
143
|
+
"""
|
|
140
144
|
|
|
141
145
|
# remove any extra whitespace
|
|
142
146
|
line = line.strip()
|
|
@@ -158,20 +162,20 @@ class BESCLInterface(Cmd):
|
|
|
158
162
|
complete_post = complete_api_resources
|
|
159
163
|
|
|
160
164
|
def do_post(self, statement):
|
|
161
|
-
"""
|
|
165
|
+
"""Post file as data to path."""
|
|
162
166
|
self.poutput(statement)
|
|
163
167
|
self.poutput("not yet implemented")
|
|
164
168
|
|
|
165
169
|
def do_config(self, conf_file=None):
|
|
166
|
-
"""Attempt to load config info from file and login"""
|
|
170
|
+
"""Attempt to load config info from file and login."""
|
|
167
171
|
self.do_conf(conf_file)
|
|
168
172
|
|
|
169
173
|
def do_loadconfig(self, conf_file=None):
|
|
170
|
-
"""Attempt to load config info from file and login"""
|
|
174
|
+
"""Attempt to load config info from file and login."""
|
|
171
175
|
self.do_conf(conf_file)
|
|
172
176
|
|
|
173
177
|
def do_conf(self, conf_file=None):
|
|
174
|
-
"""Attempt to load config info from file and login"""
|
|
178
|
+
"""Attempt to load config info from file and login."""
|
|
175
179
|
config_path = [
|
|
176
180
|
"/etc/besapi.conf",
|
|
177
181
|
os.path.expanduser("~/besapi.conf"),
|
|
@@ -213,7 +217,7 @@ class BESCLInterface(Cmd):
|
|
|
213
217
|
self.do_login()
|
|
214
218
|
|
|
215
219
|
def do_login(self, user=None):
|
|
216
|
-
"""Login to BigFix Server"""
|
|
220
|
+
"""Login to BigFix Server."""
|
|
217
221
|
|
|
218
222
|
if not user:
|
|
219
223
|
if self.BES_USER_NAME:
|
|
@@ -292,7 +296,7 @@ class BESCLInterface(Cmd):
|
|
|
292
296
|
self.perror("Login Error!")
|
|
293
297
|
|
|
294
298
|
def do_logout(self, _=None):
|
|
295
|
-
"""Logout and clear session"""
|
|
299
|
+
"""Logout and clear session."""
|
|
296
300
|
if self.bes_conn:
|
|
297
301
|
self.bes_conn.logout()
|
|
298
302
|
# del self.bes_conn
|
|
@@ -300,7 +304,7 @@ class BESCLInterface(Cmd):
|
|
|
300
304
|
self.pfeedback("Logout Complete!")
|
|
301
305
|
|
|
302
306
|
def do_debug(self, setting):
|
|
303
|
-
"""Enable or Disable Debug Mode"""
|
|
307
|
+
"""Enable or Disable Debug Mode."""
|
|
304
308
|
self.poutput(bool(setting))
|
|
305
309
|
self.debug = bool(setting)
|
|
306
310
|
self.echo = bool(setting)
|
|
@@ -312,7 +316,7 @@ class BESCLInterface(Cmd):
|
|
|
312
316
|
logging.getLogger("besapi").setLevel(logging.WARNING)
|
|
313
317
|
|
|
314
318
|
def do_clear(self, arg=None):
|
|
315
|
-
"""
|
|
319
|
+
"""Clear current config and logout."""
|
|
316
320
|
if self.bes_conn:
|
|
317
321
|
self.bes_conn.logout()
|
|
318
322
|
# self.bes_conn = None
|
|
@@ -332,11 +336,11 @@ class BESCLInterface(Cmd):
|
|
|
332
336
|
self.BES_PASSWORD = None
|
|
333
337
|
|
|
334
338
|
def do_saveconfig(self, arg=None):
|
|
335
|
-
"""
|
|
339
|
+
"""Save current config to file."""
|
|
336
340
|
self.do_saveconf(arg)
|
|
337
341
|
|
|
338
342
|
def do_saveconf(self, _=None):
|
|
339
|
-
"""
|
|
343
|
+
"""Save current config to file."""
|
|
340
344
|
if not self.bes_conn:
|
|
341
345
|
self.do_login()
|
|
342
346
|
if not self.bes_conn:
|
|
@@ -348,11 +352,11 @@ class BESCLInterface(Cmd):
|
|
|
348
352
|
self.CONFPARSER.write(configfile)
|
|
349
353
|
|
|
350
354
|
def do_showconfig(self, arg=None):
|
|
351
|
-
"""List the current settings and connection status"""
|
|
355
|
+
"""List the current settings and connection status."""
|
|
352
356
|
self.do_ls(arg)
|
|
353
357
|
|
|
354
358
|
def do_ls(self, _=None):
|
|
355
|
-
"""List the current settings and connection status"""
|
|
359
|
+
"""List the current settings and connection status."""
|
|
356
360
|
self.poutput(" Connected: " + str(bool(self.bes_conn)))
|
|
357
361
|
self.poutput(
|
|
358
362
|
" BES_ROOT_SERVER: "
|
|
@@ -372,17 +376,17 @@ class BESCLInterface(Cmd):
|
|
|
372
376
|
)
|
|
373
377
|
|
|
374
378
|
def do_error_count(self, _=None):
|
|
375
|
-
"""Output the number of errors"""
|
|
379
|
+
"""Output the number of errors."""
|
|
376
380
|
self.poutput(f"Error Count: {self.num_errors}")
|
|
377
381
|
|
|
378
382
|
def do_exit(self, _=None):
|
|
379
|
-
"""Exit this application"""
|
|
383
|
+
"""Exit this application."""
|
|
380
384
|
self.exit_code = self.num_errors
|
|
381
385
|
# no matter what I try I can't get anything but exit code 0 on windows
|
|
382
386
|
return self.do_quit("")
|
|
383
387
|
|
|
384
388
|
def do_query(self, statement):
|
|
385
|
-
"""Get Session Relevance Results"""
|
|
389
|
+
"""Get Session Relevance Results."""
|
|
386
390
|
if not self.bes_conn:
|
|
387
391
|
self.do_login()
|
|
388
392
|
if not self.bes_conn:
|
|
@@ -397,53 +401,53 @@ class BESCLInterface(Cmd):
|
|
|
397
401
|
self.poutput(rel_result)
|
|
398
402
|
|
|
399
403
|
def do_version(self, _=None):
|
|
400
|
-
"""
|
|
404
|
+
"""Output version of besapi."""
|
|
401
405
|
self.poutput(f"besapi version: {__version__}")
|
|
402
406
|
|
|
403
407
|
def do_get_action(self, statement=None):
|
|
404
|
-
"""
|
|
408
|
+
"""Usage: get_action 123."""
|
|
405
409
|
result_op = self.bes_conn.get(f"action/{statement}")
|
|
406
410
|
self.poutput(result_op)
|
|
407
411
|
|
|
408
412
|
def do_get_operator(self, statement=None):
|
|
409
|
-
"""
|
|
413
|
+
"""Usage: get_operator ExampleOperatorName."""
|
|
410
414
|
result_op = self.bes_conn.get_user(statement)
|
|
411
415
|
self.poutput(result_op)
|
|
412
416
|
|
|
413
417
|
def do_get_current_site(self, _=None):
|
|
414
|
-
"""
|
|
418
|
+
"""Output current site path context."""
|
|
415
419
|
self.poutput(
|
|
416
|
-
f"Current Site Path: `{
|
|
420
|
+
f"Current Site Path: `{self.bes_conn.get_current_site_path(None)}`"
|
|
417
421
|
)
|
|
418
422
|
|
|
419
423
|
def do_set_current_site(self, statement=None):
|
|
420
|
-
"""
|
|
424
|
+
"""Set current site path context."""
|
|
421
425
|
self.poutput(
|
|
422
|
-
f"New Site Path: `{
|
|
426
|
+
f"New Site Path: `{self.bes_conn.set_current_site_path(statement)}`"
|
|
423
427
|
)
|
|
424
428
|
|
|
425
429
|
def do_get_content(self, resource_url):
|
|
426
|
-
"""
|
|
430
|
+
"""Get a specific item by resource url."""
|
|
427
431
|
self.poutput(self.bes_conn.get_content_by_resource(resource_url))
|
|
428
432
|
|
|
429
433
|
def do_export_item_by_resource(self, statement):
|
|
430
|
-
"""
|
|
434
|
+
"""Export content itemb to current folder."""
|
|
431
435
|
self.poutput(self.bes_conn.export_item_by_resource(statement))
|
|
432
436
|
|
|
433
437
|
def do_export_site(self, site_path):
|
|
434
|
-
"""
|
|
438
|
+
"""Export site contents to current folder."""
|
|
435
439
|
self.bes_conn.export_site_contents(
|
|
436
440
|
site_path, verbose=True, include_site_folder=False, include_item_ids=False
|
|
437
441
|
)
|
|
438
442
|
|
|
439
443
|
def do_export_all_sites(self, _=None):
|
|
440
|
-
"""
|
|
444
|
+
"""Export site contents to current folder."""
|
|
441
445
|
self.bes_conn.export_all_sites(verbose=False)
|
|
442
446
|
|
|
443
447
|
complete_import_bes = Cmd.path_complete
|
|
444
448
|
|
|
445
449
|
def do_import_bes(self, statement):
|
|
446
|
-
"""
|
|
450
|
+
"""Import bes file."""
|
|
447
451
|
|
|
448
452
|
bes_file_path = str(statement.args).strip()
|
|
449
453
|
|
|
@@ -456,7 +460,7 @@ class BESCLInterface(Cmd):
|
|
|
456
460
|
complete_upload = Cmd.path_complete
|
|
457
461
|
|
|
458
462
|
def do_upload(self, file_path):
|
|
459
|
-
"""
|
|
463
|
+
"""Upload file to root server."""
|
|
460
464
|
if not os.access(file_path, os.R_OK):
|
|
461
465
|
self.poutput(file_path, "is not a readable file")
|
|
462
466
|
else:
|
|
@@ -467,7 +471,7 @@ class BESCLInterface(Cmd):
|
|
|
467
471
|
complete_create_group = Cmd.path_complete
|
|
468
472
|
|
|
469
473
|
def do_create_group(self, file_path):
|
|
470
|
-
"""
|
|
474
|
+
"""Create bigfix group from bes file."""
|
|
471
475
|
if not os.access(file_path, os.R_OK):
|
|
472
476
|
self.poutput(file_path, "is not a readable file")
|
|
473
477
|
else:
|
|
@@ -476,7 +480,7 @@ class BESCLInterface(Cmd):
|
|
|
476
480
|
complete_create_user = Cmd.path_complete
|
|
477
481
|
|
|
478
482
|
def do_create_user(self, file_path):
|
|
479
|
-
"""
|
|
483
|
+
"""Create bigfix user from bes file."""
|
|
480
484
|
if not os.access(file_path, os.R_OK):
|
|
481
485
|
self.poutput(file_path, "is not a readable file")
|
|
482
486
|
else:
|
|
@@ -485,7 +489,7 @@ class BESCLInterface(Cmd):
|
|
|
485
489
|
complete_create_site = Cmd.path_complete
|
|
486
490
|
|
|
487
491
|
def do_create_site(self, file_path):
|
|
488
|
-
"""
|
|
492
|
+
"""Create bigfix site from bes file."""
|
|
489
493
|
if not os.access(file_path, os.R_OK):
|
|
490
494
|
self.poutput(file_path, "is not a readable file")
|
|
491
495
|
else:
|
|
@@ -494,14 +498,14 @@ class BESCLInterface(Cmd):
|
|
|
494
498
|
complete_update_item = Cmd.path_complete
|
|
495
499
|
|
|
496
500
|
def do_update_item(self, file_path):
|
|
497
|
-
"""
|
|
501
|
+
"""Update bigfix content item from bes file."""
|
|
498
502
|
if not os.access(file_path, os.R_OK):
|
|
499
503
|
self.poutput(file_path, "is not a readable file")
|
|
500
504
|
else:
|
|
501
505
|
self.poutput(self.bes_conn.update_item_from_file(file_path))
|
|
502
506
|
|
|
503
507
|
def do_serverinfo(self, _=None):
|
|
504
|
-
"""
|
|
508
|
+
"""Get server info and return formatted."""
|
|
505
509
|
|
|
506
510
|
# not sure what the minimum version for this is:
|
|
507
511
|
result = self.bes_conn.get("serverinfo")
|
|
@@ -513,7 +517,7 @@ class BESCLInterface(Cmd):
|
|
|
513
517
|
|
|
514
518
|
|
|
515
519
|
def main():
|
|
516
|
-
"""Run the command loop if invoked"""
|
|
520
|
+
"""Run the command loop if invoked."""
|
|
517
521
|
BESCLInterface().cmdloop()
|
|
518
522
|
|
|
519
523
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
|
-
"""
|
|
3
|
-
Test besapi
|
|
4
|
-
"""
|
|
2
|
+
"""Test besapi."""
|
|
5
3
|
|
|
6
4
|
import argparse
|
|
7
5
|
import os
|
|
@@ -9,6 +7,8 @@ import random
|
|
|
9
7
|
import subprocess
|
|
10
8
|
import sys
|
|
11
9
|
|
|
10
|
+
# mypy: disable-error-code="arg-type"
|
|
11
|
+
|
|
12
12
|
# check for --test_pip arg
|
|
13
13
|
parser = argparse.ArgumentParser()
|
|
14
14
|
parser.add_argument(
|
|
@@ -79,7 +79,7 @@ assert raised_errors == 4
|
|
|
79
79
|
|
|
80
80
|
class RequestResult(object):
|
|
81
81
|
text = "this is just a test"
|
|
82
|
-
headers = []
|
|
82
|
+
headers = [] # type: ignore
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
request_result = RequestResult()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|