zosmfrestapi 0.1.0__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.
- zosmfrestapi-0.1.0/LICENSE +10 -0
- zosmfrestapi-0.1.0/PKG-INFO +178 -0
- zosmfrestapi-0.1.0/README.md +154 -0
- zosmfrestapi-0.1.0/pyproject.toml +50 -0
- zosmfrestapi-0.1.0/zosmfrestapi/__init__.py +91 -0
- zosmfrestapi-0.1.0/zosmfrestapi/client.py +46 -0
- zosmfrestapi-0.1.0/zosmfrestapi/exceptions/__init__.py +18 -0
- zosmfrestapi-0.1.0/zosmfrestapi/exceptions/authentication.py +17 -0
- zosmfrestapi-0.1.0/zosmfrestapi/exceptions/dataset.py +17 -0
- zosmfrestapi-0.1.0/zosmfrestapi/exceptions/software.py +34 -0
- zosmfrestapi-0.1.0/zosmfrestapi/exceptions/workflow.py +30 -0
- zosmfrestapi-0.1.0/zosmfrestapi/models/__init__.py +1 -0
- zosmfrestapi-0.1.0/zosmfrestapi/models/authentication.py +16 -0
- zosmfrestapi-0.1.0/zosmfrestapi/models/software.py +231 -0
- zosmfrestapi-0.1.0/zosmfrestapi/models/software_updates.py +102 -0
- zosmfrestapi-0.1.0/zosmfrestapi/models/topology.py +31 -0
- zosmfrestapi-0.1.0/zosmfrestapi/models/workflow.py +116 -0
- zosmfrestapi-0.1.0/zosmfrestapi/services/__init__.py +178 -0
- zosmfrestapi-0.1.0/zosmfrestapi/services/authentication.py +53 -0
- zosmfrestapi-0.1.0/zosmfrestapi/services/dataset.py +42 -0
- zosmfrestapi-0.1.0/zosmfrestapi/services/software.py +489 -0
- zosmfrestapi-0.1.0/zosmfrestapi/services/software_updates.py +963 -0
- zosmfrestapi-0.1.0/zosmfrestapi/services/topology.py +49 -0
- zosmfrestapi-0.1.0/zosmfrestapi/services/workflow.py +354 -0
- zosmfrestapi-0.1.0/zosmfrestapi/utils.py +78 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2026 Oscar Curero Sastre
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
10
|
+
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zosmfrestapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python wrapper for the z/OSMF REST API
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: z/OSMF,IBM Z,mainframe,REST API
|
|
8
|
+
Author: Oscar Curero
|
|
9
|
+
Author-email: dev@curero.es
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Requires-Dist: dacite (>=1.9.2,<2.0.0)
|
|
17
|
+
Requires-Dist: httpx2 (>=2.12.0,<3.0.0)
|
|
18
|
+
Requires-Dist: pendulum (>=3.2.0,<4.0.0)
|
|
19
|
+
Project-URL: Homepage, https://sr.ht/~ocurero/zosmfrestapi/
|
|
20
|
+
Project-URL: PyPI, https://pypi.org/project/zosmfrestapi/
|
|
21
|
+
Project-URL: Repository, https://sr.ht/~ocurero/zosmfrestapi/
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
A Python wrapper for the z/OSMF© REST API
|
|
25
|
+
=========================================
|
|
26
|
+
|
|
27
|
+
[](https://www.repostatus.org/#active) [](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml?) 
|
|
28
|
+
|
|
29
|
+
* Open Source: MIT License.
|
|
30
|
+
* Website: <https://sr.ht/~ocurero/zosmfrestapi/>
|
|
31
|
+
* Pypi: <https://pypi.org/project/zosmfrestapi/>
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
Install
|
|
35
|
+
-------
|
|
36
|
+
|
|
37
|
+
**zosmfrestapi** requires Python 3.12 or newer and access to a z/OSMF server.
|
|
38
|
+
You can check your Python version with:
|
|
39
|
+
|
|
40
|
+
```console
|
|
41
|
+
python --version
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
It is a good idea to use a virtual environment so this package does not affect
|
|
45
|
+
other Python projects. From a terminal, create and activate one in your project
|
|
46
|
+
folder:
|
|
47
|
+
|
|
48
|
+
```console
|
|
49
|
+
# Windows (PowerShell)
|
|
50
|
+
py -3.12 -m venv .venv
|
|
51
|
+
.venv\Scripts\Activate.ps1
|
|
52
|
+
|
|
53
|
+
# macOS or Linux
|
|
54
|
+
python3 -m venv .venv
|
|
55
|
+
source .venv/bin/activate
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then install the package from PyPI:
|
|
59
|
+
|
|
60
|
+
```console
|
|
61
|
+
python -m pip install zosmfrestapi
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If you have downloaded or cloned the source code, run this from the project's
|
|
65
|
+
root folder instead:
|
|
66
|
+
|
|
67
|
+
```console
|
|
68
|
+
python -m pip install .
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## First request
|
|
72
|
+
|
|
73
|
+
Save this as `example.py` and run it with `python example.py`. Enter the base
|
|
74
|
+
URL of your z/OSMF server when prompted (for example,
|
|
75
|
+
`https://zosmf.example.com:443`). The URL should include `https://` and any
|
|
76
|
+
required port, but not an API path such as `/zosmf`.
|
|
77
|
+
|
|
78
|
+
The password is requested without displaying it and is not stored in the
|
|
79
|
+
script. Replace the sample operation with one your z/OSMF user is authorized to
|
|
80
|
+
perform.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from getpass import getpass
|
|
84
|
+
|
|
85
|
+
from zosmfrestapi import ZosmfClient, ZosmfError
|
|
86
|
+
|
|
87
|
+
server = input("z/OSMF server URL: ").strip().rstrip("/")
|
|
88
|
+
username = input("User ID: ").strip()
|
|
89
|
+
password = getpass("Password: ")
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
with ZosmfClient(server, username=username, password=password) as client:
|
|
93
|
+
for instance in client.list_swis():
|
|
94
|
+
print(f"{instance.name} ({instance.system})")
|
|
95
|
+
except ZosmfError as error:
|
|
96
|
+
print(f"The z/OSMF request failed: {error}")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The `with` block closes the network connection automatically, even if a request
|
|
100
|
+
fails. `list_swis()` returns Python objects; the example prints each software
|
|
101
|
+
instance's name and system. You can also query systems or read a data set. Put
|
|
102
|
+
these calls inside the `with` block shown above, before it ends:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
systems = client.get_systems()
|
|
106
|
+
contents = client.read_dataset("USER.DATASET")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
These calls must be made inside the `with` block, before the client is closed.
|
|
110
|
+
For a partitioned data set member, use a name such as
|
|
111
|
+
`USER.PDS(MEMBER)`.
|
|
112
|
+
|
|
113
|
+
## Authentication and TLS
|
|
114
|
+
|
|
115
|
+
The client uses the server's normal TLS certificate checks by default. Keep
|
|
116
|
+
those checks enabled for routine use. The HTTP transport is HTTPX2, a fork of
|
|
117
|
+
HTTPX; HTTPX2 uses `truststore` to integrate operating-system certificate
|
|
118
|
+
stores when it creates its default TLS context. This package currently passes
|
|
119
|
+
its own context, created with Python's `ssl.create_default_context()`, so the
|
|
120
|
+
certificates available to Python are used. If the z/OSMF server's CA is not
|
|
121
|
+
trusted in that environment, pass its certificate file with `cafile` below.
|
|
122
|
+
|
|
123
|
+
| Situation | Client option |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| User ID and password | `username="...", password="..."` |
|
|
126
|
+
| Client certificate and key in separate files | `cert=("client.crt", "client.key")` |
|
|
127
|
+
| Client certificate and key in one PEM file | `cert="client.pem"` |
|
|
128
|
+
| Internal certificate authority | `cafile="company-ca.pem"` |
|
|
129
|
+
| Existing LTPA or JWT token | `ltpa_token="..."` or `jwt_token="..."` |
|
|
130
|
+
| Network proxy | `proxy="http://proxy.example.com:8080"` |
|
|
131
|
+
|
|
132
|
+
For example, to trust an internal certificate authority, pass `cafile` when
|
|
133
|
+
creating the client:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
with ZosmfClient(server, username=username, password=password,
|
|
137
|
+
cafile="company-ca.pem") as client:
|
|
138
|
+
systems = client.get_systems()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Avoid putting passwords or tokens directly in scripts, committing them to
|
|
142
|
+
version control, or sharing them in logs. The `insecure=True` option disables
|
|
143
|
+
TLS certificate verification; use it only for temporary diagnostics, never as
|
|
144
|
+
a production fix. It cannot be combined with `cert` or `cafile`.
|
|
145
|
+
|
|
146
|
+
## What you can do
|
|
147
|
+
|
|
148
|
+
The client provides synchronous methods for:
|
|
149
|
+
|
|
150
|
+
* Authentication (`authenticate`).
|
|
151
|
+
* z/OSMF groups and systems (`get_groups`, `get_systems`).
|
|
152
|
+
* Data sets (`read_dataset`).
|
|
153
|
+
* Software instances and SMP/E information (`list_swis`, `get_swi_by_name`,
|
|
154
|
+
`get_swi_by_uuid`, and related query methods).
|
|
155
|
+
* Workflows (list, inspect, create, start, wait for, cancel, and archive).
|
|
156
|
+
* Software updates (search, inspect, start, monitor, and cancel).
|
|
157
|
+
|
|
158
|
+
Some operations change z/OSMF state. Check the method documentation and make
|
|
159
|
+
sure your account has the required permissions before using them.
|
|
160
|
+
|
|
161
|
+
## Troubleshooting
|
|
162
|
+
|
|
163
|
+
* **Python version error:** install Python 3.12 or newer, then recreate the
|
|
164
|
+
virtual environment with that interpreter.
|
|
165
|
+
* **401 / unauthorized:** check the server URL, user ID, password or token, and
|
|
166
|
+
whether the account is authorized for the requested API.
|
|
167
|
+
* **Certificate verification error:** ask your z/OSMF administrator for the
|
|
168
|
+
correct CA certificate and pass its path with `cafile`.
|
|
169
|
+
* **Connection or timeout error:** check that the server and port are reachable
|
|
170
|
+
from your machine and that any required proxy is configured.
|
|
171
|
+
* **PowerShell will not activate the virtual environment:** use the Python
|
|
172
|
+
executable inside `.venv\Scripts\python.exe` to run commands, or follow your
|
|
173
|
+
organization's PowerShell policy guidance. Do not change the machine-wide
|
|
174
|
+
execution policy just to install this package.
|
|
175
|
+
|
|
176
|
+
For the complete API, parameters, and return types, see the docstrings in the
|
|
177
|
+
package source and the project website.
|
|
178
|
+
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
A Python wrapper for the z/OSMF© REST API
|
|
2
|
+
=========================================
|
|
3
|
+
|
|
4
|
+
[](https://www.repostatus.org/#active) [](https://builds.sr.ht/~ocurero/zosmfrestapi/commits/main/.build.yml?) 
|
|
5
|
+
|
|
6
|
+
* Open Source: MIT License.
|
|
7
|
+
* Website: <https://sr.ht/~ocurero/zosmfrestapi/>
|
|
8
|
+
* Pypi: <https://pypi.org/project/zosmfrestapi/>
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
Install
|
|
12
|
+
-------
|
|
13
|
+
|
|
14
|
+
**zosmfrestapi** requires Python 3.12 or newer and access to a z/OSMF server.
|
|
15
|
+
You can check your Python version with:
|
|
16
|
+
|
|
17
|
+
```console
|
|
18
|
+
python --version
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
It is a good idea to use a virtual environment so this package does not affect
|
|
22
|
+
other Python projects. From a terminal, create and activate one in your project
|
|
23
|
+
folder:
|
|
24
|
+
|
|
25
|
+
```console
|
|
26
|
+
# Windows (PowerShell)
|
|
27
|
+
py -3.12 -m venv .venv
|
|
28
|
+
.venv\Scripts\Activate.ps1
|
|
29
|
+
|
|
30
|
+
# macOS or Linux
|
|
31
|
+
python3 -m venv .venv
|
|
32
|
+
source .venv/bin/activate
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then install the package from PyPI:
|
|
36
|
+
|
|
37
|
+
```console
|
|
38
|
+
python -m pip install zosmfrestapi
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If you have downloaded or cloned the source code, run this from the project's
|
|
42
|
+
root folder instead:
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
python -m pip install .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## First request
|
|
49
|
+
|
|
50
|
+
Save this as `example.py` and run it with `python example.py`. Enter the base
|
|
51
|
+
URL of your z/OSMF server when prompted (for example,
|
|
52
|
+
`https://zosmf.example.com:443`). The URL should include `https://` and any
|
|
53
|
+
required port, but not an API path such as `/zosmf`.
|
|
54
|
+
|
|
55
|
+
The password is requested without displaying it and is not stored in the
|
|
56
|
+
script. Replace the sample operation with one your z/OSMF user is authorized to
|
|
57
|
+
perform.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from getpass import getpass
|
|
61
|
+
|
|
62
|
+
from zosmfrestapi import ZosmfClient, ZosmfError
|
|
63
|
+
|
|
64
|
+
server = input("z/OSMF server URL: ").strip().rstrip("/")
|
|
65
|
+
username = input("User ID: ").strip()
|
|
66
|
+
password = getpass("Password: ")
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
with ZosmfClient(server, username=username, password=password) as client:
|
|
70
|
+
for instance in client.list_swis():
|
|
71
|
+
print(f"{instance.name} ({instance.system})")
|
|
72
|
+
except ZosmfError as error:
|
|
73
|
+
print(f"The z/OSMF request failed: {error}")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The `with` block closes the network connection automatically, even if a request
|
|
77
|
+
fails. `list_swis()` returns Python objects; the example prints each software
|
|
78
|
+
instance's name and system. You can also query systems or read a data set. Put
|
|
79
|
+
these calls inside the `with` block shown above, before it ends:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
systems = client.get_systems()
|
|
83
|
+
contents = client.read_dataset("USER.DATASET")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
These calls must be made inside the `with` block, before the client is closed.
|
|
87
|
+
For a partitioned data set member, use a name such as
|
|
88
|
+
`USER.PDS(MEMBER)`.
|
|
89
|
+
|
|
90
|
+
## Authentication and TLS
|
|
91
|
+
|
|
92
|
+
The client uses the server's normal TLS certificate checks by default. Keep
|
|
93
|
+
those checks enabled for routine use. The HTTP transport is HTTPX2, a fork of
|
|
94
|
+
HTTPX; HTTPX2 uses `truststore` to integrate operating-system certificate
|
|
95
|
+
stores when it creates its default TLS context. This package currently passes
|
|
96
|
+
its own context, created with Python's `ssl.create_default_context()`, so the
|
|
97
|
+
certificates available to Python are used. If the z/OSMF server's CA is not
|
|
98
|
+
trusted in that environment, pass its certificate file with `cafile` below.
|
|
99
|
+
|
|
100
|
+
| Situation | Client option |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| User ID and password | `username="...", password="..."` |
|
|
103
|
+
| Client certificate and key in separate files | `cert=("client.crt", "client.key")` |
|
|
104
|
+
| Client certificate and key in one PEM file | `cert="client.pem"` |
|
|
105
|
+
| Internal certificate authority | `cafile="company-ca.pem"` |
|
|
106
|
+
| Existing LTPA or JWT token | `ltpa_token="..."` or `jwt_token="..."` |
|
|
107
|
+
| Network proxy | `proxy="http://proxy.example.com:8080"` |
|
|
108
|
+
|
|
109
|
+
For example, to trust an internal certificate authority, pass `cafile` when
|
|
110
|
+
creating the client:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
with ZosmfClient(server, username=username, password=password,
|
|
114
|
+
cafile="company-ca.pem") as client:
|
|
115
|
+
systems = client.get_systems()
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Avoid putting passwords or tokens directly in scripts, committing them to
|
|
119
|
+
version control, or sharing them in logs. The `insecure=True` option disables
|
|
120
|
+
TLS certificate verification; use it only for temporary diagnostics, never as
|
|
121
|
+
a production fix. It cannot be combined with `cert` or `cafile`.
|
|
122
|
+
|
|
123
|
+
## What you can do
|
|
124
|
+
|
|
125
|
+
The client provides synchronous methods for:
|
|
126
|
+
|
|
127
|
+
* Authentication (`authenticate`).
|
|
128
|
+
* z/OSMF groups and systems (`get_groups`, `get_systems`).
|
|
129
|
+
* Data sets (`read_dataset`).
|
|
130
|
+
* Software instances and SMP/E information (`list_swis`, `get_swi_by_name`,
|
|
131
|
+
`get_swi_by_uuid`, and related query methods).
|
|
132
|
+
* Workflows (list, inspect, create, start, wait for, cancel, and archive).
|
|
133
|
+
* Software updates (search, inspect, start, monitor, and cancel).
|
|
134
|
+
|
|
135
|
+
Some operations change z/OSMF state. Check the method documentation and make
|
|
136
|
+
sure your account has the required permissions before using them.
|
|
137
|
+
|
|
138
|
+
## Troubleshooting
|
|
139
|
+
|
|
140
|
+
* **Python version error:** install Python 3.12 or newer, then recreate the
|
|
141
|
+
virtual environment with that interpreter.
|
|
142
|
+
* **401 / unauthorized:** check the server URL, user ID, password or token, and
|
|
143
|
+
whether the account is authorized for the requested API.
|
|
144
|
+
* **Certificate verification error:** ask your z/OSMF administrator for the
|
|
145
|
+
correct CA certificate and pass its path with `cafile`.
|
|
146
|
+
* **Connection or timeout error:** check that the server and port are reachable
|
|
147
|
+
from your machine and that any required proxy is configured.
|
|
148
|
+
* **PowerShell will not activate the virtual environment:** use the Python
|
|
149
|
+
executable inside `.venv\Scripts\python.exe` to run commands, or follow your
|
|
150
|
+
organization's PowerShell policy guidance. Do not change the machine-wide
|
|
151
|
+
execution policy just to install this package.
|
|
152
|
+
|
|
153
|
+
For the complete API, parameters, and return types, see the docstrings in the
|
|
154
|
+
package source and the project website.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "zosmfrestapi"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A Python wrapper for the z/OSMF REST API"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{name = "Oscar Curero",email = "dev@curero.es"}
|
|
8
|
+
]
|
|
9
|
+
license = "MIT"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
keywords = ["z/OSMF", "IBM Z", "mainframe", "REST API"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Operating System :: OS Independent",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
17
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"httpx2 (>=2.12.0,<3.0.0)",
|
|
21
|
+
"pendulum (>=3.2.0,<4.0.0)",
|
|
22
|
+
"dacite (>=1.9.2,<2.0.0)",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://sr.ht/~ocurero/zosmfrestapi/"
|
|
27
|
+
Repository = "https://sr.ht/~ocurero/zosmfrestapi/"
|
|
28
|
+
PyPI = "https://pypi.org/project/zosmfrestapi/"
|
|
29
|
+
|
|
30
|
+
[dependency-groups]
|
|
31
|
+
dev = [
|
|
32
|
+
"pytest (>=9.1.1,<10.0.0)",
|
|
33
|
+
"black (>=26.5.1,<27.0.0)",
|
|
34
|
+
"pytest-recording (>=0.14.0,<0.15.0)",
|
|
35
|
+
"pytest-httpx2 (>=1.0.0,<2.0.0)",
|
|
36
|
+
"pytest-cov (>=7.1.0,<8.0.0)",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[tool.black]
|
|
40
|
+
line-length = 88
|
|
41
|
+
target-version = ["py312"]
|
|
42
|
+
|
|
43
|
+
[tool.pytest.ini_options]
|
|
44
|
+
testpaths = ["tests"]
|
|
45
|
+
addopts = ["-ra", "--record-mode=none", "--cov-fail-under=100", "--cov=zosmfrestapi"]
|
|
46
|
+
|
|
47
|
+
[build-system]
|
|
48
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
49
|
+
build-backend = "poetry.core.masonry.api"
|
|
50
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Synchronous Python client for the z/OSMF REST API.
|
|
2
|
+
|
|
3
|
+
The package root re-exports :class:`ZosmfClient`, response models, and public
|
|
4
|
+
exceptions. Create one client per server/configuration and use it as a context
|
|
5
|
+
manager to close the shared HTTP session when finished.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from zosmfrestapi.client import ZosmfClient
|
|
9
|
+
from zosmfrestapi.exceptions import ZosmfAuthError, ZosmfError
|
|
10
|
+
from zosmfrestapi.exceptions.authentication import ZosmfLoginError
|
|
11
|
+
from zosmfrestapi.exceptions.dataset import ZosmfDatasetNotFoundError
|
|
12
|
+
from zosmfrestapi.exceptions.software import (
|
|
13
|
+
ZosmfSoftwareInstanceNotFoundError,
|
|
14
|
+
ZosmfSoftwareManagementError,
|
|
15
|
+
ZosmfSoftwareManagementRequestError,
|
|
16
|
+
)
|
|
17
|
+
from zosmfrestapi.exceptions.workflow import ZosmfWorkflowBaseError, ZosmfWorkflowError
|
|
18
|
+
from zosmfrestapi.models.authentication import LoginOk
|
|
19
|
+
from zosmfrestapi.models.software import (
|
|
20
|
+
CsiEntry,
|
|
21
|
+
DataSet,
|
|
22
|
+
Feature,
|
|
23
|
+
Fmid,
|
|
24
|
+
NonSmpeManagedDataset,
|
|
25
|
+
Product,
|
|
26
|
+
SmpeManagedDataset,
|
|
27
|
+
SmpeManagedDatasetZoneDddef,
|
|
28
|
+
SmpeManagedUnixDataset,
|
|
29
|
+
SoftwareInstance,
|
|
30
|
+
SoftwareInstanceWorkflow,
|
|
31
|
+
WorkflowLocation,
|
|
32
|
+
)
|
|
33
|
+
from zosmfrestapi.models.software_updates import (
|
|
34
|
+
MissingFixcat,
|
|
35
|
+
MissingUpdate,
|
|
36
|
+
MissingUpdateResolver,
|
|
37
|
+
SoftwareUpdate,
|
|
38
|
+
SoftwareUpdateZone,
|
|
39
|
+
UpdateErrorResults,
|
|
40
|
+
UpdateProcess,
|
|
41
|
+
UpdateResult,
|
|
42
|
+
UpdateSelection,
|
|
43
|
+
)
|
|
44
|
+
from zosmfrestapi.models.topology import Group, System
|
|
45
|
+
from zosmfrestapi.models.workflow import (
|
|
46
|
+
WorkflowArchivedListItem,
|
|
47
|
+
WorkflowInstance,
|
|
48
|
+
WorkflowItem,
|
|
49
|
+
WorkflowListItem,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
"ZosmfClient",
|
|
54
|
+
"LoginOk",
|
|
55
|
+
"ZosmfDatasetNotFoundError",
|
|
56
|
+
"ZosmfError",
|
|
57
|
+
"ZosmfAuthError",
|
|
58
|
+
"ZosmfLoginError",
|
|
59
|
+
"System",
|
|
60
|
+
"Group",
|
|
61
|
+
"CsiEntry",
|
|
62
|
+
"DataSet",
|
|
63
|
+
"Feature",
|
|
64
|
+
"Fmid",
|
|
65
|
+
"NonSmpeManagedDataset",
|
|
66
|
+
"Product",
|
|
67
|
+
"SmpeManagedDataset",
|
|
68
|
+
"SmpeManagedDatasetZoneDddef",
|
|
69
|
+
"SmpeManagedUnixDataset",
|
|
70
|
+
"SoftwareInstance",
|
|
71
|
+
"SoftwareInstanceWorkflow",
|
|
72
|
+
"WorkflowLocation",
|
|
73
|
+
"ZosmfSoftwareManagementError",
|
|
74
|
+
"ZosmfSoftwareInstanceNotFoundError",
|
|
75
|
+
"ZosmfSoftwareManagementRequestError",
|
|
76
|
+
"MissingFixcat",
|
|
77
|
+
"MissingUpdate",
|
|
78
|
+
"MissingUpdateResolver",
|
|
79
|
+
"SoftwareUpdate",
|
|
80
|
+
"SoftwareUpdateZone",
|
|
81
|
+
"UpdateErrorResults",
|
|
82
|
+
"UpdateProcess",
|
|
83
|
+
"UpdateResult",
|
|
84
|
+
"UpdateSelection",
|
|
85
|
+
"WorkflowArchivedListItem",
|
|
86
|
+
"WorkflowInstance",
|
|
87
|
+
"WorkflowItem",
|
|
88
|
+
"WorkflowListItem",
|
|
89
|
+
"ZosmfWorkflowBaseError",
|
|
90
|
+
"ZosmfWorkflowError",
|
|
91
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from zosmfrestapi.services.authentication import AuthenticationServices
|
|
2
|
+
from zosmfrestapi.services.dataset import DatasetServices
|
|
3
|
+
from zosmfrestapi.services.software import SoftwareServices
|
|
4
|
+
from zosmfrestapi.services.software_updates import SoftwareUpdatesServices
|
|
5
|
+
from zosmfrestapi.services.topology import TopologyServices
|
|
6
|
+
from zosmfrestapi.services.workflow import WorkflowServices
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ZosmfClient(
|
|
10
|
+
AuthenticationServices,
|
|
11
|
+
DatasetServices,
|
|
12
|
+
TopologyServices,
|
|
13
|
+
WorkflowServices,
|
|
14
|
+
SoftwareServices,
|
|
15
|
+
SoftwareUpdatesServices,
|
|
16
|
+
):
|
|
17
|
+
"""Synchronous client for the z/OSMF REST APIs.
|
|
18
|
+
|
|
19
|
+
The client combines authentication, datasets, topology, workflows,
|
|
20
|
+
software-instance management, and software-update operations around one
|
|
21
|
+
reusable HTTP session. Update-start and resume methods can change the
|
|
22
|
+
selected target zone; use them only when those changes are intended.
|
|
23
|
+
|
|
24
|
+
Use it as a context manager to close the underlying HTTP session reliably.
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
Use a context manager when making requests:
|
|
28
|
+
|
|
29
|
+
with ZosmfClient("https://zosmf.example",
|
|
30
|
+
username="demouser", password="DEMOPASS") as client:
|
|
31
|
+
systems = client.get_systems()
|
|
32
|
+
|
|
33
|
+
Use a client without using a context manager:
|
|
34
|
+
|
|
35
|
+
client = ZosmfClient("https://zosmf.example",
|
|
36
|
+
username="demouser", password="DEMOPASS")
|
|
37
|
+
systems = client.get_systems()
|
|
38
|
+
client.close()
|
|
39
|
+
|
|
40
|
+
Use a client with mTLS authentication:
|
|
41
|
+
|
|
42
|
+
with ZosmfClient("https://zosmf.example",
|
|
43
|
+
username="demouser", password="DEMOPASS",
|
|
44
|
+
cert=("/path/to/cert", "/path/to/key")) as client:
|
|
45
|
+
systems = client.get_systems()
|
|
46
|
+
"""
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import httpx2
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ZosmfError(Exception):
|
|
5
|
+
"""Base exception for errors raised by the z/OSMF REST API client."""
|
|
6
|
+
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ZosmfAuthError(ZosmfError):
|
|
11
|
+
"""Raised when z/OSMF rejects a request with HTTP 401.
|
|
12
|
+
|
|
13
|
+
The triggering ``httpx2.HTTPStatusError`` is available as
|
|
14
|
+
:attr:`http_exception`.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, exc: httpx2.HTTPStatusError) -> None:
|
|
18
|
+
self.http_exception = exc
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import httpx2
|
|
2
|
+
|
|
3
|
+
from . import ZosmfError
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ZosmfLoginError(ZosmfError):
|
|
7
|
+
"""Raised when the authentication endpoint rejects a login request.
|
|
8
|
+
|
|
9
|
+
The response's return code, reason code, and message are exposed as
|
|
10
|
+
``return_code``, ``reason_code``, and ``message``.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, response: httpx2.Response) -> None:
|
|
14
|
+
self.http_exception = None
|
|
15
|
+
self.return_code = response.json()["returnCode"]
|
|
16
|
+
self.reason_code = response.json()["reasonCode"]
|
|
17
|
+
self.message = response.json()["message"]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import httpx2
|
|
4
|
+
from zosmfrestapi.exceptions import ZosmfError
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ZosmfDatasetError(ZosmfError):
|
|
10
|
+
"""Raised when a data set REST request fails with an HTTP status error."""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ZosmfDatasetNotFoundError(ZosmfDatasetError):
|
|
14
|
+
"""Raised when z/OSMF reports that the requested data set is not found."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, response: httpx2.Response) -> None:
|
|
17
|
+
pass
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from . import ZosmfError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ZosmfSoftwareManagementError(ZosmfError):
|
|
5
|
+
"""Base exception for z/OSMF Software Management operations."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ZosmfSoftwareManagementRequestError(ZosmfSoftwareManagementError):
|
|
9
|
+
"""Raised when a Software Management request fails with an HTTP status.
|
|
10
|
+
|
|
11
|
+
When the response includes the corresponding fields, ``status_code``,
|
|
12
|
+
``reason_code``, ``messages``, and ``body`` provide response details.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, error=None) -> None:
|
|
16
|
+
self.status_code = error.response.status_code if error else None
|
|
17
|
+
self.reason_code = error.response.json()["reason"] if error else None
|
|
18
|
+
self.messages = error.response.json()["messages"] if error else None
|
|
19
|
+
self.body = error.response.text if error else None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ZosmfSoftwareInstanceNotFoundError(ZosmfSoftwareManagementError):
|
|
23
|
+
"""Raised when a requested software instance does not exist."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, response) -> None:
|
|
26
|
+
super().__init__(response)
|
|
27
|
+
self.messages = (
|
|
28
|
+
response.json().get("messages", [])
|
|
29
|
+
if response.headers.get("Content-Type").startswith("application/json")
|
|
30
|
+
else [response.text]
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def __str__(self) -> str:
|
|
34
|
+
return ", ".join(self.messages) if self.messages else ""
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import httpx2
|
|
2
|
+
|
|
3
|
+
from . import ZosmfError
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ZosmfWorkflowBaseError(ZosmfError):
|
|
7
|
+
"""Base exception for z/OSMF workflow operations."""
|
|
8
|
+
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ZosmfWorkflowError(ZosmfWorkflowBaseError):
|
|
13
|
+
"""Raised when a workflow REST request fails with an HTTP status.
|
|
14
|
+
|
|
15
|
+
When present in the response, ``status_code``, ``message_id``, ``message``,
|
|
16
|
+
and ``body`` expose the z/OSMF error details.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, error: httpx2.HTTPStatusError | None = None) -> None:
|
|
20
|
+
self.exc = error
|
|
21
|
+
self.status_code = error.response.status_code if error else None
|
|
22
|
+
self.message_id = error.response.json()["messageID"] if error else None
|
|
23
|
+
self.message = error.response.json()["messageText"] if error else None
|
|
24
|
+
self.body = error.response.text if error else None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ZosmfWorkflowCanceledError(ZosmfWorkflowBaseError):
|
|
28
|
+
"""Reserved for workflow-specific cancellation failures."""
|
|
29
|
+
|
|
30
|
+
pass
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@dataclass
|
|
5
|
+
class LoginOk:
|
|
6
|
+
"""Successful response from the z/OSMF authentication endpoint.
|
|
7
|
+
|
|
8
|
+
The endpoint return fields are preserved alongside any LTPA or JWT token
|
|
9
|
+
cookies returned by the server.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
returnCode: int
|
|
13
|
+
reasonCode: int
|
|
14
|
+
message: str
|
|
15
|
+
ltpa_token: str | None = None
|
|
16
|
+
jwt_token: str | None = None
|