Pydantic library code generator for Redfish targets
Project description
o le o
/^^^^^7
' ' ,oO))))))))Oo,
,'))))))))))))))), /{
' ,'o ))))))))))))))))={
> )))Sebastes)))))={
`, ))))))\ \)))))))={
',))))))))\/)))))' \{
'*O))))))))O*'
Sebastes
Hey hey people! Sebastes is simple code generator for Redfish compatible targets (i.e. server, storage systems, network equipment). It recursively scans target Redfish endpoints and creates organized python modules with Pydantic models. Forget about spending hours on boilerplate code, just make it within a couple of minutes!
Getting started
Confirmed support
- Dell:
- Х2-740Х
- Huawei:
- 2288H V5
- YADRO:
- Vegman N110
Prerequisites
sebastes requires python 3.9 or newer versions to run. Currently, only UNIX os is supported.
Installing
Cloning project from git repository
git clone https://github.com/YADRO-KNS/sebastes.git
Installing from PyPi
pip3 install sebastes
Usage
The sebastes
command:
usage: sebastes [-h] -a HOSTNAME -u USERNAME -p PASSWORD -o OUTPUT [-e [ENTRY_POINT]] [-m [MAX_MODELS]] [-c [MAX_COLLECTION]]
optional arguments:
-h, --help show this help message and exit
-a HOSTNAME DNS name or IP address of Redfish target
-u USERNAME Target username
-p PASSWORD Target password
-o OUTPUT Output directory
-e [ENTRY_POINT] Redfish entry point | optional default is '/redfish/v1/'
-m [MAX_MODELS] Max Models to scan | optional default is 500
-c [MAX_COLLECTION] Max Collection elements to sample from | optional default is 50
Example
Scanning target
# Generate library code from remote server Redfish data.
$ sebastes -a 192.168.1.3 -u admin -p le-pass -o /tmp/output/lib
Generated lib structure
After scanning, Sebastes will create a python module in the output folder with the following structure:
.
└── models
├── __init__.py
├── common.py
├── service_root.py
├── some_other_resourse.py
└── ...
Working with generated code
Init file will be created automatically. It will contain imports from common script and root models from all of the scanned endpoints.
Redfish have a limited list of model types. Matching models will be re-inherited from respective classes defined in common script:
- Link - the simplest type of model containing a link to some resource.
- Action - similar to Link but contains URI of some possible action.
- Resource - main model type, contains a set of mandatory fields defined in parent class, all other fields will be created based on response data. Also for root model resources _url field will be filled with model location data.
- Collection - similar to Resource, has a couple of specific fields with links to its members. For root model collections _url field will be filled with model location data.
Regardless of what type of data you want to access in Redfish, the first thing you need to do is to create a DataManager instance. This class provides methods for interaction with pydantic models.
Getting Resource
To get Resource data you need to call get_resource method of DataManager object and pass required model class to map data into. Models _url field will be used as default data location, you can manually replace it with your own value.
def get_resource(self, resource: typing.Type[T], url: typing.Optional[str] = None) -> T:
"""
Gets resource data from passed model class.
:param resource: Model to get data for.
:param url: Resource URL | optional
:return: resource object
"""
...
from .models import DataManager, ServiceRoot
if __name__ == '__main__':
manager = DataManager('192.168.1.3', 'admin', 'le-pass')
service_root = manager.get_resource(ServiceRoot)
print(service_root.host_name)
Getting Collection members
To get a collection you need to provide not only a collection model class but also a model for collection elements. For some root models elements classes will be available via resource class method.
def get_collection(self,
collection: typing.Type[Collection],
resource: typing.Type[T],
url: typing.Optional[str] = None
) -> typing.List[T]:
"""
Gets collection data from endpoint and returns list of all member resources
:param collection: Collection class
:param resource: Target resource to map data
:param url: collection URL | optional
:return: list of resource objects
"""
...
from .models import DataManager, LogServiceEntries
if __name__ == '__main__':
manager = DataManager('192.168.1.3', 'admin', 'le-pass')
for log in manager.get_collection(LogServiceEntries, LogServiceEntries.resource()):
print(log.created, log.message, log.severity)
And just as with Resource you can provide your own URL value to get data from. For nested collections it is the only way:
from .models import DataManager, NetworkInterfaces, NetworkPorts
if __name__ == '__main__':
manager = DataManager('192.168.1.3', 'admin', 'le-pass')
for interface in manager.get_collection(NetworkInterfaces, NetworkInterfaces.resource()):
url = interface.network_ports.odata_id
for port in manager.get_collection(NetworkPorts, NetworkPorts.resource(), url=url):
print(interface.name, port.name, port.mac)
Calling Action request
When you need to activate some Redfish action all you have to do is pass an Action object. Payload is optional.
def action_post(self, action: Action, payload: typing.Optional[dict] = None) -> dict:
"""
Call action request for specific model.
:param action: Model to call
:param payload: Calls data.
:return: JSON response data
"""
...
from .models import DataManager, ComputerSystem
if __name__ == '__main__':
manager = DataManager('192.168.1.3', 'admin', 'le-pass')
computer_system = manager.get_resource(ComputerSystem)
manager.action_post(computer_system.actions.computer_system_reset, payload={'ResetType': 'On'})
Patching Resource
Some Redfish endpoints support patching. The link_patch method will call a passed link object and get it’s Etag value (if there is any) and then will perform a patch request with passed payload data.
def link_patch(self,
link: Link,
payload: typing.Optional[dict] = None,
pass_etag: bool = True
) -> dict:
"""
Call Patch request on specific link model
:param link: Model to patch
:param payload: Patch data
:param pass_etag: boolean flag, is set as true, will attempt to
use resource ETag value in PATCH request.
:return: JSON response data
"""
...
from .models import DataManager, Bios
if __name__ == '__main__':
manager = DataManager('192.168.1.3', 'admin', 'le-pass')
bios = manager.get_resource(Bios)
payload = {
'Attributes': {
'BootType': 'UEFIBoot'
}
}
manager.link_patch(bios.redfish_settings.settings_object, payload)
Versioning
We use SemVer for versioning.
Authors
See also the list of contributors who participated in this project.
Acknowledgments
- sebastes inspired and based on datamodel-code-generator by Koudai Aono
License
The code is available as open source under the terms of the MIT License.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file sebastes-0.1.4.tar.gz
.
File metadata
- Download URL: sebastes-0.1.4.tar.gz
- Upload date:
- Size: 20.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.9.11
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | d0e8adb9dfb72bee5f3599d9448c646c0d8117625d9ed459497a91cc045c81a5 |
|
MD5 | 4d57ab9a7aa10991bd11ac1d76ac59ad |
|
BLAKE2b-256 | fa390602863dcd79c91b6cd975d4d7b88a49ddbe6e7dcf7515c3b43b459c73c1 |
File details
Details for the file sebastes-0.1.4-py3-none-any.whl
.
File metadata
- Download URL: sebastes-0.1.4-py3-none-any.whl
- Upload date:
- Size: 18.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.9.11
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9ab692b8ae8f255c4616307682f4a47f9987b2164ef4f7937f99f6909aa55e0f |
|
MD5 | 2797a098030db6dd18aa39c29f3980d4 |
|
BLAKE2b-256 | fe09e7293f394224037a75b9e886a443159e052f4c8d107642b68845853b91c3 |