ucmdb-rest 2.0.1__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.
- ucmdb_rest-2.0.1/LICENSE +19 -0
- ucmdb_rest-2.0.1/PKG-INFO +131 -0
- ucmdb_rest-2.0.1/README.md +116 -0
- ucmdb_rest-2.0.1/pyproject.toml +37 -0
- ucmdb_rest-2.0.1/setup.cfg +4 -0
- ucmdb_rest-2.0.1/tests/__init__.py +3 -0
- ucmdb_rest-2.0.1/tests/conftest.py +27 -0
- ucmdb_rest-2.0.1/tests/test_client.py +40 -0
- ucmdb_rest-2.0.1/tests/test_dataflowmanagement.py +149 -0
- ucmdb_rest-2.0.1/tests/test_datamodel.py +67 -0
- ucmdb_rest-2.0.1/tests/test_discovery.py +80 -0
- ucmdb_rest-2.0.1/tests/test_exposeCI.py +29 -0
- ucmdb_rest-2.0.1/tests/test_integration.py +56 -0
- ucmdb_rest-2.0.1/tests/test_ldap.py +15 -0
- ucmdb_rest-2.0.1/tests/test_mgmtzone.py +74 -0
- ucmdb_rest-2.0.1/tests/test_packages.py +50 -0
- ucmdb_rest-2.0.1/tests/test_policies.py +61 -0
- ucmdb_rest-2.0.1/tests/test_report.py +82 -0
- ucmdb_rest-2.0.1/tests/test_settings.py +67 -0
- ucmdb_rest-2.0.1/tests/test_system.py +17 -0
- ucmdb_rest-2.0.1/tests/test_topology.py +29 -0
- ucmdb_rest-2.0.1/ucmdb_rest/__init__.py +6 -0
- ucmdb_rest-2.0.1/ucmdb_rest/client.py +236 -0
- ucmdb_rest-2.0.1/ucmdb_rest/data_flow_management.py +969 -0
- ucmdb_rest-2.0.1/ucmdb_rest/datamodel.py +229 -0
- ucmdb_rest-2.0.1/ucmdb_rest/discovery.py +608 -0
- ucmdb_rest-2.0.1/ucmdb_rest/expose_ci.py +119 -0
- ucmdb_rest-2.0.1/ucmdb_rest/integration.py +308 -0
- ucmdb_rest-2.0.1/ucmdb_rest/ldap.py +43 -0
- ucmdb_rest-2.0.1/ucmdb_rest/management_zone.py +188 -0
- ucmdb_rest-2.0.1/ucmdb_rest/packages.py +428 -0
- ucmdb_rest-2.0.1/ucmdb_rest/policies.py +318 -0
- ucmdb_rest-2.0.1/ucmdb_rest/report.py +230 -0
- ucmdb_rest-2.0.1/ucmdb_rest/settings.py +235 -0
- ucmdb_rest-2.0.1/ucmdb_rest/system.py +163 -0
- ucmdb_rest-2.0.1/ucmdb_rest/topology.py +218 -0
- ucmdb_rest-2.0.1/ucmdb_rest/utils.py +43 -0
- ucmdb_rest-2.0.1/ucmdb_rest.egg-info/PKG-INFO +131 -0
- ucmdb_rest-2.0.1/ucmdb_rest.egg-info/SOURCES.txt +40 -0
- ucmdb_rest-2.0.1/ucmdb_rest.egg-info/dependency_links.txt +1 -0
- ucmdb_rest-2.0.1/ucmdb_rest.egg-info/requires.txt +1 -0
- ucmdb_rest-2.0.1/ucmdb_rest.egg-info/top_level.txt +1 -0
ucmdb_rest-2.0.1/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026 Keith Paschal
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ucmdb_rest
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: A modular Python client for the UCMDB REST API
|
|
5
|
+
Author-email: Keith Paschal <kw.paschal@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/kwpaschal/ucmdb_rest
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.6
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: requests>=2.25.0
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# UCMDB REST Python Library
|
|
17
|
+
|
|
18
|
+
A modern, object-oriented Python 3.6+ wrapper for the OpenText Universal Configuration Management Database (UCMDB) REST API. This library centralizes UCMDB interactions through a unified client, providing type-safe Enums and automated pagination.
|
|
19
|
+
## Setup and Authentication
|
|
20
|
+
This library contains some examples that assume a `credentials.json` file is in the same direcory as the code.
|
|
21
|
+
|
|
22
|
+
1. Copy `credentials.json.example` to `credentials.json`
|
|
23
|
+
2. Update the values with your UCMDB server details
|
|
24
|
+
|
|
25
|
+
| Key | Description |
|
|
26
|
+
| :--- | :--- |
|
|
27
|
+
| **user** | UCMDB Username |
|
|
28
|
+
| **password** | UCMDB Password |
|
|
29
|
+
| **server** | FQDN or IP of the UCMDB Server |
|
|
30
|
+
| **port** | REST API port (Default 8443) |
|
|
31
|
+
| **ssl_validation** | Boolean (false to skip certificate checks) |
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
The library uses a central `UCMDBServer` to manage authentication and session persistence.
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from ucmdb_rest import UCMDBServer
|
|
39
|
+
|
|
40
|
+
# Initialize client (assumes credentials.json exists)
|
|
41
|
+
client = UCMDBServer.from_json('credentials.json')
|
|
42
|
+
|
|
43
|
+
# Quick connectivity check
|
|
44
|
+
print(f"Connected to: {client.server_version}")
|
|
45
|
+
|
|
46
|
+
# Get detailed version info
|
|
47
|
+
version = client.system.getUCMDBVersion().json()
|
|
48
|
+
print(f"Product: {version['productName']}")
|
|
49
|
+
print(f"Content Pack: {version['contentPackVersion']}")
|
|
50
|
+
```
|
|
51
|
+
## Practical Examples
|
|
52
|
+
To help you get started quickly, here are some example standalone scripts
|
|
53
|
+
* **`add_cis.py`**: Create CIs and Relationships with custom properties
|
|
54
|
+
* **`delete_cis.py`**: Delete CIs by their UCMDB ID
|
|
55
|
+
* **`get_recon_rule.py`**: Display a reconciliation rule for a CI Type
|
|
56
|
+
* **`initialize_get_version.py`**: Display version information about the UCMDB Server
|
|
57
|
+
* **`query_topology`**: Run a UCMDB View and get the information
|
|
58
|
+
* **`search_and_expose_ci.py`**: Search for a CI by name and get specific properties
|
|
59
|
+
* **`show_content_packs.py`**: Display current content pack information
|
|
60
|
+
* **`show_license_report.py`**: Display a license report from UCMDB
|
|
61
|
+
|
|
62
|
+
see [Examplese Documentation](./examples/index.md) for detailed setup and usage.
|
|
63
|
+
## Functional Modules
|
|
64
|
+
|
|
65
|
+
The library is organized into specialized modules to mirror the UCMDB API ecosystem:
|
|
66
|
+
|
|
67
|
+
| Module | Description |
|
|
68
|
+
| :--- | :--- |
|
|
69
|
+
| **client** | `UCMDBServer` class which acts as the entry point. |
|
|
70
|
+
| **data_flow_management** | Operations affecting Data Flow Probes. |
|
|
71
|
+
| **datamodel** | CRUD operations for Configuration Items (CIs) and Relations. |
|
|
72
|
+
| **discovery** | Management of discovery jobs, probe status, and results. |
|
|
73
|
+
| **expose_ci** | On-demand queries of the UCMDB database. |
|
|
74
|
+
| **integration** | Operations affecting integration points. |
|
|
75
|
+
| **ldap** | Operations affecting LDAP integration in UCMDB. |
|
|
76
|
+
| **management_zone** | Operations affecting UCMDB UI zone-based discovery. |
|
|
77
|
+
| **packages** | Deployment and management of UCMDB Content Packs. |
|
|
78
|
+
| **policies** | Policy calculation and automated result chunking. |
|
|
79
|
+
| **report** | Operations involving reports and data exports. |
|
|
80
|
+
| **settings** | Operations involving infrastructure settings and recipients. |
|
|
81
|
+
| **system** | Licensing, versioning, and ping operations. |
|
|
82
|
+
| **topology** | TQL execution, ad-hoc queries, and fetching CI attributes. |
|
|
83
|
+
| **utils** | Shared helper functions and internal constants. |
|
|
84
|
+
|
|
85
|
+
## Documentation
|
|
86
|
+
|
|
87
|
+
For detailed API references, view our [Interactive Documentation](reference/data_flow_management.md).
|
|
88
|
+
|
|
89
|
+
### Documentation Workflow
|
|
90
|
+
The docs are powered by `mkdocs` and `mkdocstrings`.
|
|
91
|
+
- **Source**: Python Docstrings (numpy Style)
|
|
92
|
+
- **Theme**: Material for MkDocs
|
|
93
|
+
- **Customization**: Located in `docs/stylesheets/extra.css`
|
|
94
|
+
|
|
95
|
+
## Development and Testing
|
|
96
|
+
|
|
97
|
+
We use `pytest` for functional validation. To run the suite:
|
|
98
|
+
```bash
|
|
99
|
+
# Run all tests with coverage
|
|
100
|
+
pytest --cov=ucmdb_rest
|
|
101
|
+
|
|
102
|
+
# Preview documentation locally
|
|
103
|
+
mkdocs serve
|
|
104
|
+
|
|
105
|
+
## Release History
|
|
106
|
+
|
|
107
|
+
## Release History
|
|
108
|
+
* **2.0.1 (Current)**
|
|
109
|
+
* Fixed a bunch of failing tests
|
|
110
|
+
* Beginning to add Examples
|
|
111
|
+
* **2.0.0**
|
|
112
|
+
* **Major Architecture Milestone**: Completed the migration of all legacy `rest.py` components.
|
|
113
|
+
* Re-engineered core modules into a modular, object-oriented framework.
|
|
114
|
+
* Standardized response handling using `requests.Response` objects across all modules.
|
|
115
|
+
* Enhanced code discoverability via the unified `UCMDBServer` entry point.
|
|
116
|
+
* **1.7.0**
|
|
117
|
+
* (Internal version alignment release)
|
|
118
|
+
* **1.6.0**
|
|
119
|
+
* Added Settings and Recipients management.
|
|
120
|
+
* **1.5.0**
|
|
121
|
+
* Added Reports functionality and tests.
|
|
122
|
+
* **1.4.0**
|
|
123
|
+
* Added Management Zone functionality and tests.
|
|
124
|
+
* **1.3.0**
|
|
125
|
+
* Added LDAP configuration retrieval.
|
|
126
|
+
* **1.2.0**
|
|
127
|
+
* Added integration point retrieval.
|
|
128
|
+
* **1.1.0**
|
|
129
|
+
* Added ExposeCI ad-hoc query support.
|
|
130
|
+
* **1.0.0**
|
|
131
|
+
* Initial stable release: Topology and Discovery modules complete.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# UCMDB REST Python Library
|
|
2
|
+
|
|
3
|
+
A modern, object-oriented Python 3.6+ wrapper for the OpenText Universal Configuration Management Database (UCMDB) REST API. This library centralizes UCMDB interactions through a unified client, providing type-safe Enums and automated pagination.
|
|
4
|
+
## Setup and Authentication
|
|
5
|
+
This library contains some examples that assume a `credentials.json` file is in the same direcory as the code.
|
|
6
|
+
|
|
7
|
+
1. Copy `credentials.json.example` to `credentials.json`
|
|
8
|
+
2. Update the values with your UCMDB server details
|
|
9
|
+
|
|
10
|
+
| Key | Description |
|
|
11
|
+
| :--- | :--- |
|
|
12
|
+
| **user** | UCMDB Username |
|
|
13
|
+
| **password** | UCMDB Password |
|
|
14
|
+
| **server** | FQDN or IP of the UCMDB Server |
|
|
15
|
+
| **port** | REST API port (Default 8443) |
|
|
16
|
+
| **ssl_validation** | Boolean (false to skip certificate checks) |
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
The library uses a central `UCMDBServer` to manage authentication and session persistence.
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from ucmdb_rest import UCMDBServer
|
|
24
|
+
|
|
25
|
+
# Initialize client (assumes credentials.json exists)
|
|
26
|
+
client = UCMDBServer.from_json('credentials.json')
|
|
27
|
+
|
|
28
|
+
# Quick connectivity check
|
|
29
|
+
print(f"Connected to: {client.server_version}")
|
|
30
|
+
|
|
31
|
+
# Get detailed version info
|
|
32
|
+
version = client.system.getUCMDBVersion().json()
|
|
33
|
+
print(f"Product: {version['productName']}")
|
|
34
|
+
print(f"Content Pack: {version['contentPackVersion']}")
|
|
35
|
+
```
|
|
36
|
+
## Practical Examples
|
|
37
|
+
To help you get started quickly, here are some example standalone scripts
|
|
38
|
+
* **`add_cis.py`**: Create CIs and Relationships with custom properties
|
|
39
|
+
* **`delete_cis.py`**: Delete CIs by their UCMDB ID
|
|
40
|
+
* **`get_recon_rule.py`**: Display a reconciliation rule for a CI Type
|
|
41
|
+
* **`initialize_get_version.py`**: Display version information about the UCMDB Server
|
|
42
|
+
* **`query_topology`**: Run a UCMDB View and get the information
|
|
43
|
+
* **`search_and_expose_ci.py`**: Search for a CI by name and get specific properties
|
|
44
|
+
* **`show_content_packs.py`**: Display current content pack information
|
|
45
|
+
* **`show_license_report.py`**: Display a license report from UCMDB
|
|
46
|
+
|
|
47
|
+
see [Examplese Documentation](./examples/index.md) for detailed setup and usage.
|
|
48
|
+
## Functional Modules
|
|
49
|
+
|
|
50
|
+
The library is organized into specialized modules to mirror the UCMDB API ecosystem:
|
|
51
|
+
|
|
52
|
+
| Module | Description |
|
|
53
|
+
| :--- | :--- |
|
|
54
|
+
| **client** | `UCMDBServer` class which acts as the entry point. |
|
|
55
|
+
| **data_flow_management** | Operations affecting Data Flow Probes. |
|
|
56
|
+
| **datamodel** | CRUD operations for Configuration Items (CIs) and Relations. |
|
|
57
|
+
| **discovery** | Management of discovery jobs, probe status, and results. |
|
|
58
|
+
| **expose_ci** | On-demand queries of the UCMDB database. |
|
|
59
|
+
| **integration** | Operations affecting integration points. |
|
|
60
|
+
| **ldap** | Operations affecting LDAP integration in UCMDB. |
|
|
61
|
+
| **management_zone** | Operations affecting UCMDB UI zone-based discovery. |
|
|
62
|
+
| **packages** | Deployment and management of UCMDB Content Packs. |
|
|
63
|
+
| **policies** | Policy calculation and automated result chunking. |
|
|
64
|
+
| **report** | Operations involving reports and data exports. |
|
|
65
|
+
| **settings** | Operations involving infrastructure settings and recipients. |
|
|
66
|
+
| **system** | Licensing, versioning, and ping operations. |
|
|
67
|
+
| **topology** | TQL execution, ad-hoc queries, and fetching CI attributes. |
|
|
68
|
+
| **utils** | Shared helper functions and internal constants. |
|
|
69
|
+
|
|
70
|
+
## Documentation
|
|
71
|
+
|
|
72
|
+
For detailed API references, view our [Interactive Documentation](reference/data_flow_management.md).
|
|
73
|
+
|
|
74
|
+
### Documentation Workflow
|
|
75
|
+
The docs are powered by `mkdocs` and `mkdocstrings`.
|
|
76
|
+
- **Source**: Python Docstrings (numpy Style)
|
|
77
|
+
- **Theme**: Material for MkDocs
|
|
78
|
+
- **Customization**: Located in `docs/stylesheets/extra.css`
|
|
79
|
+
|
|
80
|
+
## Development and Testing
|
|
81
|
+
|
|
82
|
+
We use `pytest` for functional validation. To run the suite:
|
|
83
|
+
```bash
|
|
84
|
+
# Run all tests with coverage
|
|
85
|
+
pytest --cov=ucmdb_rest
|
|
86
|
+
|
|
87
|
+
# Preview documentation locally
|
|
88
|
+
mkdocs serve
|
|
89
|
+
|
|
90
|
+
## Release History
|
|
91
|
+
|
|
92
|
+
## Release History
|
|
93
|
+
* **2.0.1 (Current)**
|
|
94
|
+
* Fixed a bunch of failing tests
|
|
95
|
+
* Beginning to add Examples
|
|
96
|
+
* **2.0.0**
|
|
97
|
+
* **Major Architecture Milestone**: Completed the migration of all legacy `rest.py` components.
|
|
98
|
+
* Re-engineered core modules into a modular, object-oriented framework.
|
|
99
|
+
* Standardized response handling using `requests.Response` objects across all modules.
|
|
100
|
+
* Enhanced code discoverability via the unified `UCMDBServer` entry point.
|
|
101
|
+
* **1.7.0**
|
|
102
|
+
* (Internal version alignment release)
|
|
103
|
+
* **1.6.0**
|
|
104
|
+
* Added Settings and Recipients management.
|
|
105
|
+
* **1.5.0**
|
|
106
|
+
* Added Reports functionality and tests.
|
|
107
|
+
* **1.4.0**
|
|
108
|
+
* Added Management Zone functionality and tests.
|
|
109
|
+
* **1.3.0**
|
|
110
|
+
* Added LDAP configuration retrieval.
|
|
111
|
+
* **1.2.0**
|
|
112
|
+
* Added integration point retrieval.
|
|
113
|
+
* **1.1.0**
|
|
114
|
+
* Added ExposeCI ad-hoc query support.
|
|
115
|
+
* **1.0.0**
|
|
116
|
+
* Initial stable release: Topology and Discovery modules complete.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ucmdb_rest"
|
|
7
|
+
version = "2.0.1"
|
|
8
|
+
description = "A modular Python client for the UCMDB REST API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Keith Paschal", email = "kw.paschal@gmail.com" }
|
|
13
|
+
]
|
|
14
|
+
requires-python = ">=3.6"
|
|
15
|
+
dependencies = [
|
|
16
|
+
"requests>=2.25.0",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://github.com/kwpaschal/ucmdb_rest"
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.packages.find]
|
|
27
|
+
include = ["ucmdb_rest*"]
|
|
28
|
+
|
|
29
|
+
[tool.ruff]
|
|
30
|
+
src = ["ucmdb_rest"]
|
|
31
|
+
line-length = 100
|
|
32
|
+
|
|
33
|
+
[tool.ruff.lint]
|
|
34
|
+
select = ["E", "F", "I"]
|
|
35
|
+
|
|
36
|
+
[tool.ruff.lint.per-file-ignores]
|
|
37
|
+
"tests/*" = ["F401"]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
import urllib3
|
|
6
|
+
from ucmdb_rest.client import UCMDBServer
|
|
7
|
+
|
|
8
|
+
# Suppress SSL warnings globally for all tests
|
|
9
|
+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
10
|
+
|
|
11
|
+
@pytest.fixture(scope="session")
|
|
12
|
+
def creds():
|
|
13
|
+
"""Load credentials from JSON."""
|
|
14
|
+
cred_path = os.path.join(os.path.dirname(__file__), 'credentials.json')
|
|
15
|
+
with open(cred_path, 'r') as f:
|
|
16
|
+
return json.load(f)
|
|
17
|
+
|
|
18
|
+
@pytest.fixture(scope="session")
|
|
19
|
+
def ucmdb_client(creds):
|
|
20
|
+
"""Pass the 'creds' fixture into the client fixture."""
|
|
21
|
+
return UCMDBServer(
|
|
22
|
+
user=creds['user'],
|
|
23
|
+
password=creds['password'],
|
|
24
|
+
server=creds['server'],
|
|
25
|
+
port=creds.get('port', 8443),
|
|
26
|
+
ssl_validation=creds.get('ssl_validation', False)
|
|
27
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from ucmdb_rest.client import UCMDBAuthError, UCMDBServer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_connection_and_auth(ucmdb_client):
|
|
6
|
+
"""
|
|
7
|
+
This test verifies that the fixture in conftest.py successfully
|
|
8
|
+
authenticated and returned a working client object.
|
|
9
|
+
"""
|
|
10
|
+
# Verify the base URL was built
|
|
11
|
+
assert ucmdb_client.base_url.startswith("https://")
|
|
12
|
+
|
|
13
|
+
# Verify the token is present in the session headers
|
|
14
|
+
auth_header = ucmdb_client.session.headers.get('Authorization')
|
|
15
|
+
assert auth_header is not None
|
|
16
|
+
assert auth_header.startswith("Bearer ")
|
|
17
|
+
|
|
18
|
+
# Optional: Verify the token isn't just an empty string
|
|
19
|
+
assert len(auth_header) > 20
|
|
20
|
+
|
|
21
|
+
def test_failed_connection_bad_server():
|
|
22
|
+
with pytest.raises(UCMDBAuthError) as excinfo:
|
|
23
|
+
UCMDBServer(
|
|
24
|
+
user="admin",
|
|
25
|
+
password="ucmdbadmin",
|
|
26
|
+
server="bad.server.local"
|
|
27
|
+
)
|
|
28
|
+
assert "Failed to resolve" in str(excinfo.value)
|
|
29
|
+
|
|
30
|
+
# def test_failed_auth_bad_password(creds):
|
|
31
|
+
# with pytest.raises(UCMDBAuthError) as excinfo:
|
|
32
|
+
# UCMDBServer(
|
|
33
|
+
# user=creds['user'],
|
|
34
|
+
# password="wrong_password",
|
|
35
|
+
# server=creds['server']
|
|
36
|
+
# )
|
|
37
|
+
#
|
|
38
|
+
# error_msg = str(excinfo.value)
|
|
39
|
+
# assert "Auth Failed" in error_msg
|
|
40
|
+
# assert "401" in error_msg
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@pytest.fixture(scope="module")
|
|
5
|
+
def active_probe_name(ucmdb_client):
|
|
6
|
+
"""Fetches the first available probe name from the server."""
|
|
7
|
+
probes = ucmdb_client.data_flow.getProbeInfo()
|
|
8
|
+
probe_list = probes.json()
|
|
9
|
+
items = probe_list.get('items',[])
|
|
10
|
+
if not items:
|
|
11
|
+
pytest.skip("No probes found on the UCMDB server; skipping dependent tests.")
|
|
12
|
+
return items[0]['probeName']
|
|
13
|
+
|
|
14
|
+
def test_getProbeRanges(ucmdb_client, active_probe_name):
|
|
15
|
+
ranges = ucmdb_client.data_flow.getProbeRanges(active_probe_name)
|
|
16
|
+
assert ranges.status_code == 200
|
|
17
|
+
|
|
18
|
+
def test_addRange(ucmdb_client,active_probe_name):
|
|
19
|
+
RANGE_TO_ADD = [{
|
|
20
|
+
'range': '15.1.1.1-15.1.1.2',
|
|
21
|
+
'definitionType': 'IP_RANGE',
|
|
22
|
+
'ipVersion': 'IPV4',
|
|
23
|
+
'isIncluded': True,
|
|
24
|
+
'rangeType': 'DATA_CENTER',
|
|
25
|
+
'description': 'Test Range'
|
|
26
|
+
}]
|
|
27
|
+
result = ucmdb_client.data_flow.addRange(RANGE_TO_ADD, active_probe_name)
|
|
28
|
+
assert result.status_code == 200
|
|
29
|
+
|
|
30
|
+
def test_updateRange(ucmdb_client, active_probe_name):
|
|
31
|
+
RANGE_TO_UPDATE = {
|
|
32
|
+
"oldRanges": [{
|
|
33
|
+
"probe": active_probe_name,
|
|
34
|
+
"range": "15.1.1.1-15.1.1.2",
|
|
35
|
+
"definitionType": "IP_RANGE",
|
|
36
|
+
"ipVersion": "IPV4",
|
|
37
|
+
"isIncluded": True
|
|
38
|
+
}],
|
|
39
|
+
"newRanges": [{
|
|
40
|
+
"probe": active_probe_name,
|
|
41
|
+
"range": "15.1.1.1-15.1.1.3",
|
|
42
|
+
"definitionType": "IP_RANGE",
|
|
43
|
+
"ipVersion": "IPV4",
|
|
44
|
+
"isIncluded": True,
|
|
45
|
+
"rangeType": "DATA_CENTER",
|
|
46
|
+
"description": "Updated via Test"
|
|
47
|
+
}]
|
|
48
|
+
}
|
|
49
|
+
result = ucmdb_client.data_flow.updateRange(RANGE_TO_UPDATE, active_probe_name)
|
|
50
|
+
assert result.status_code == 200
|
|
51
|
+
|
|
52
|
+
def test_deleteRange(ucmdb_client,active_probe_name):
|
|
53
|
+
RANGE_TO_DELETE = [
|
|
54
|
+
{
|
|
55
|
+
"range": "15.1.1.1-15.1.1.3",
|
|
56
|
+
"definitionType": "IP_RANGE",
|
|
57
|
+
"ipVersion": "IPV4",
|
|
58
|
+
"isIncluded": True
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
result = ucmdb_client.data_flow.deleteRange(RANGE_TO_DELETE, active_probe_name)
|
|
62
|
+
assert result.status_code == 200
|
|
63
|
+
|
|
64
|
+
def test_getAllDomains(ucmdb_client):
|
|
65
|
+
result = ucmdb_client.data_flow.getAllDomains()
|
|
66
|
+
assert result.status_code == 200
|
|
67
|
+
|
|
68
|
+
def test_getAllCredentials(ucmdb_client):
|
|
69
|
+
result = ucmdb_client.data_flow.getAllCredentials()
|
|
70
|
+
assert result.status_code == 200
|
|
71
|
+
|
|
72
|
+
def test_getProbeInfo(ucmdb_client):
|
|
73
|
+
result = ucmdb_client.data_flow.getProbeInfo()
|
|
74
|
+
assert result.status_code == 200
|
|
75
|
+
|
|
76
|
+
def test_getProtocol(ucmdb_client):
|
|
77
|
+
result = ucmdb_client.data_flow.getProtocol('ntadminprotocol')
|
|
78
|
+
assert result.status_code == 200
|
|
79
|
+
|
|
80
|
+
def test_probeStatusDetails(ucmdb_client,active_probe_name):
|
|
81
|
+
result = ucmdb_client.data_flow.probeStatusDetails('DefaultDomain', active_probe_name)
|
|
82
|
+
assert result.status_code == 200
|
|
83
|
+
|
|
84
|
+
def test_checkCredential_ad_hoc(ucmdb_client, active_probe_name):
|
|
85
|
+
query_body = {
|
|
86
|
+
"nodes": [
|
|
87
|
+
{
|
|
88
|
+
"type": "ntcmd",
|
|
89
|
+
"queryIdentifier": "ntcmd",
|
|
90
|
+
"visible": True,
|
|
91
|
+
"includeSubtypes": True,
|
|
92
|
+
"layout": ["display_label", "application_ip", "last_discovered_by_probe", "credentials_id"], # noqa: E501
|
|
93
|
+
"attributesConditions": [
|
|
94
|
+
{
|
|
95
|
+
"attributeName": "last_discovered_by_probe",
|
|
96
|
+
"operator": "equals",
|
|
97
|
+
"value": active_probe_name
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
"relations": []
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
response = ucmdb_client.topology.queryCIs(query_body)
|
|
106
|
+
all_cis = response.json().get("cis", [])
|
|
107
|
+
|
|
108
|
+
matching_cis = [
|
|
109
|
+
ci for ci in all_cis
|
|
110
|
+
if ci.get("properties", {}).get("last_discovered_by_probe") == active_probe_name
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
assert len(matching_cis) > 0, (
|
|
114
|
+
f"Filtered out all {len(all_cis)} CIs because none matched probe: {active_probe_name}"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
target_ci = matching_cis[0]
|
|
118
|
+
props = target_ci.get("properties", {})
|
|
119
|
+
|
|
120
|
+
cred_id = props.get("credentials_id")
|
|
121
|
+
ip_addr = props.get("application_ip")
|
|
122
|
+
probe_name = props.get("last_discovered_by_probe")
|
|
123
|
+
|
|
124
|
+
print(f"Found {len(matching_cis)} matches. Testing Credential: {cred_id} on {ip_addr}")
|
|
125
|
+
|
|
126
|
+
result = ucmdb_client.data_flow.checkCredential(cred_id, probe_name, ip_addr)
|
|
127
|
+
|
|
128
|
+
assert result.status_code == 200
|
|
129
|
+
print(f"Successfully validated credential for {ip_addr} via {probe_name}")
|
|
130
|
+
|
|
131
|
+
def test_getAllProtocols(ucmdb_client):
|
|
132
|
+
result = ucmdb_client.data_flow.getAllProtocols()
|
|
133
|
+
assert result.status_code == 200
|
|
134
|
+
|
|
135
|
+
def test_getCredentialProfiles(ucmdb_client):
|
|
136
|
+
result = ucmdb_client.data_flow.getCredentialProfiles()
|
|
137
|
+
assert result.status_code == 200
|
|
138
|
+
|
|
139
|
+
def test_probeStatus(ucmdb_client):
|
|
140
|
+
result = ucmdb_client.data_flow.probeStatus()
|
|
141
|
+
assert result.status_code == 200
|
|
142
|
+
|
|
143
|
+
def test_queryIPs(ucmdb_client):
|
|
144
|
+
result = ucmdb_client.data_flow.queryIPs('10.1.1.')
|
|
145
|
+
assert result.status_code == 200
|
|
146
|
+
|
|
147
|
+
def test_queryProbe(ucmdb_client):
|
|
148
|
+
result = ucmdb_client.data_flow.queryProbe()
|
|
149
|
+
assert result.status_code == 200
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import pytest #noqa
|
|
2
|
+
|
|
3
|
+
myCI = {
|
|
4
|
+
"cis": [
|
|
5
|
+
{
|
|
6
|
+
"ucmdbId": "1",
|
|
7
|
+
"type": "node",
|
|
8
|
+
"properties": {"name":"Test6",
|
|
9
|
+
"os_family":"windows"}
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"relations": []
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
ci_list = []
|
|
16
|
+
node_global_id = None
|
|
17
|
+
|
|
18
|
+
def test_addCIs(ucmdb_client):
|
|
19
|
+
global ci_list, node_global_id
|
|
20
|
+
result = ucmdb_client.data_model.addCIs(myCI, returnIdsMap=True)
|
|
21
|
+
|
|
22
|
+
assert result.status_code == 200
|
|
23
|
+
data = result.json()
|
|
24
|
+
print(data)
|
|
25
|
+
|
|
26
|
+
if "idsMap" in data:
|
|
27
|
+
ci_list = list(data["idsMap"].values())
|
|
28
|
+
node_global_id = data["idsMap"].get("1")
|
|
29
|
+
else:
|
|
30
|
+
ci_list = data.get("addedCis", []) + data.get("ignoredCis", [])
|
|
31
|
+
if ci_list:
|
|
32
|
+
node_global_id = ci_list[0]
|
|
33
|
+
|
|
34
|
+
assert len(ci_list) > 0
|
|
35
|
+
assert node_global_id is not None
|
|
36
|
+
|
|
37
|
+
def test_updateCI(ucmdb_client):
|
|
38
|
+
global node_global_id
|
|
39
|
+
updatedCI = {"ucmdbId":node_global_id,
|
|
40
|
+
"type":"node",
|
|
41
|
+
"properties" : {"data_note":"Updated by REST"}}
|
|
42
|
+
response = ucmdb_client.data_model.updateCI(node_global_id, updatedCI)
|
|
43
|
+
|
|
44
|
+
assert response.status_code == 200
|
|
45
|
+
data = response.json()
|
|
46
|
+
assert node_global_id in data.get("updatedCis", []) or node_global_id in data.get("ignoredCis", []) # noqa: E501
|
|
47
|
+
|
|
48
|
+
def test_deleteCIs(ucmdb_client):
|
|
49
|
+
global ci_list
|
|
50
|
+
for ci_id in ci_list:
|
|
51
|
+
response = ucmdb_client.data_model.deleteCIs(ci_id, isGlobalId=True)
|
|
52
|
+
assert response.status_code == 200
|
|
53
|
+
|
|
54
|
+
def test_getClass(ucmdb_client):
|
|
55
|
+
response = ucmdb_client.data_model.getClass("node")
|
|
56
|
+
assert response.status_code == 200
|
|
57
|
+
|
|
58
|
+
def test_retrieveIdentificationRule(ucmdb_client):
|
|
59
|
+
response = ucmdb_client.data_model.retrieveIdentificationRule("node")
|
|
60
|
+
assert response.status_code == 200
|
|
61
|
+
|
|
62
|
+
def test_convertFromBase64_logic(ucmdb_client):
|
|
63
|
+
sample_input = "SGVsbG8gVUNNREI="
|
|
64
|
+
expected_output = "Hello UCMDB"
|
|
65
|
+
|
|
66
|
+
result = ucmdb_client.data_model.convertFromBase64(sample_input)
|
|
67
|
+
assert result == expected_output
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# 1. Metadata Tests
|
|
5
|
+
def test_get_module_tree(ucmdb_client):
|
|
6
|
+
response = ucmdb_client.discovery.getModuleTree()
|
|
7
|
+
assert response.status_code == 200
|
|
8
|
+
assert "children" in response.json()
|
|
9
|
+
|
|
10
|
+
def test_get_use_cases(ucmdb_client):
|
|
11
|
+
response = ucmdb_client.discovery.getDiscoveryUseCases()
|
|
12
|
+
assert response.status_code == 200
|
|
13
|
+
data = response.json()
|
|
14
|
+
assert isinstance(data, dict)
|
|
15
|
+
assert "children" in data
|
|
16
|
+
|
|
17
|
+
def test_get_job_metadata(ucmdb_client):
|
|
18
|
+
response = ucmdb_client.discovery.getJobMetaData()
|
|
19
|
+
assert response.status_code == 200
|
|
20
|
+
assert "items" in response.json()
|
|
21
|
+
|
|
22
|
+
# 2. IP Range Tests
|
|
23
|
+
def test_get_ip_ranges(ucmdb_client):
|
|
24
|
+
response = ucmdb_client.discovery.getIPRange()
|
|
25
|
+
assert response.status_code == 200
|
|
26
|
+
assert "items" in response.json()
|
|
27
|
+
|
|
28
|
+
def test_get_ip_range_for_specific_ip(ucmdb_client):
|
|
29
|
+
# Testing with a common loopback or local IP
|
|
30
|
+
response = ucmdb_client.discovery.getIPRangeForIP("127.0.0.1")
|
|
31
|
+
assert response.status_code == 200
|
|
32
|
+
|
|
33
|
+
# 3. Job Group & Parameter Tests
|
|
34
|
+
def test_get_job_group_with_fields(ucmdb_client):
|
|
35
|
+
# This specifically tests the fix you just made
|
|
36
|
+
response = ucmdb_client.discovery.getJobGroup(fields="name,id")
|
|
37
|
+
assert response.status_code == 200
|
|
38
|
+
data = response.json()
|
|
39
|
+
if data.get("items"):
|
|
40
|
+
assert "name" in data["items"][0]
|
|
41
|
+
assert "id" in data["items"][0]
|
|
42
|
+
|
|
43
|
+
def test_get_questions(ucmdb_client):
|
|
44
|
+
job_name = "Host Connection by Shell"
|
|
45
|
+
response = ucmdb_client.discovery.getQuestions(job_name)
|
|
46
|
+
assert response.status_code == 200
|
|
47
|
+
|
|
48
|
+
def test_get_schedules(ucmdb_client):
|
|
49
|
+
response = ucmdb_client.discovery.getSchedules()
|
|
50
|
+
assert response.status_code == 200
|
|
51
|
+
|
|
52
|
+
# 4. Lifecycle Test
|
|
53
|
+
def test_job_group_lifecycle(ucmdb_client):
|
|
54
|
+
name = "Pytest_Discovery_Test"
|
|
55
|
+
payload = {
|
|
56
|
+
"name": name,
|
|
57
|
+
"type": "CMS",
|
|
58
|
+
"description": "Test Group",
|
|
59
|
+
# discoveryType often defaults to null on the server
|
|
60
|
+
"discoveryType": None,
|
|
61
|
+
"jobs": [
|
|
62
|
+
{
|
|
63
|
+
"jobName": "Call Home Processing",
|
|
64
|
+
"jobDisplayName": "Call Home Processing",
|
|
65
|
+
"adapterName": "CallHomeProcessing",
|
|
66
|
+
"inputCI": "callhome_event",
|
|
67
|
+
"jobType": "DynamicService",
|
|
68
|
+
"protocols": [],
|
|
69
|
+
"jobParameters": {},
|
|
70
|
+
"triggerQueries": [],
|
|
71
|
+
"jobInvokeOnNewTrigger": True
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
# Create
|
|
76
|
+
assert ucmdb_client.discovery.createJobGroup(payload).status_code in [200, 201]
|
|
77
|
+
# Get Specific
|
|
78
|
+
assert ucmdb_client.discovery.getSpecificJobGroup(name).status_code == 200
|
|
79
|
+
# Delete
|
|
80
|
+
assert ucmdb_client.discovery.deleteSpecificJobGroup(name).status_code == 200
|