Update project description and enhance documentation for clarity
- Revised the project description in `pyproject.toml` to better reflect the functionality of the `oxipy` client. - Improved the README.md by adding detailed explanations of the project structure, installation instructions, and usage examples. - Updated documentation files to enhance clarity and organization, including sections on extending models and writing TTP templates. - Adjusted various TTP templates to ensure consistency and accuracy in the parsing of device configurations.
This commit is contained in:
294
README.md
294
README.md
@@ -1,38 +1,42 @@
|
||||
# oxipy
|
||||
|
||||
Python-клиент для работы с Oxidized API — системой управления конфигурацией сетевых устройств. Предоставляет удобный интерфейс для получения конфигураций узлов, их парсинга и работы с результатами.
|
||||
`oxipy` is a Python client for the [Oxidized](https://github.com/ytti/oxidized) API.
|
||||
It fetches device configurations from Oxidized and parses them into structured
|
||||
Pydantic models using bundled TTP templates.
|
||||
|
||||
## Содержание
|
||||
Oxidized remains responsible for collecting and storing configuration backups.
|
||||
`oxipy` focuses on consuming those backups from Python code and exposing common
|
||||
configuration sections such as system data, interfaces, and VLANs.
|
||||
|
||||
- [Установка](#установка)
|
||||
- [Быстрый старт](#быстрый-старт)
|
||||
## Contents
|
||||
|
||||
- [Installation](#installation)
|
||||
- [Quick Start](#quick-start)
|
||||
- [API Reference](#api-reference)
|
||||
- [OxiAPI](#oxiapi)
|
||||
- [NodeView](#nodeview)
|
||||
- [NodeConfig](#nodeconfig)
|
||||
- [ModelView](#modelview)
|
||||
- [Поддерживаемые устройства](#поддерживаемые-устройства)
|
||||
- [Дополнительно](#дополнительно)
|
||||
- [Supported Devices](#supported-devices)
|
||||
- [Additional Documentation](#additional-documentation)
|
||||
|
||||
---
|
||||
## Installation
|
||||
|
||||
## Установка
|
||||
The package is distributed through a private Gitea Package Registry and from the
|
||||
source repository. It is not published to PyPI.
|
||||
|
||||
> Пакет распространяется через Gitea Package Registry и исходники репозитория.
|
||||
> В PyPI пакет не публикуется.
|
||||
**Requirements:** Python 3.10+
|
||||
|
||||
**Требования:** Python 3.11+
|
||||
### From Gitea Package Registry
|
||||
|
||||
### Из Gitea Package Registry
|
||||
|
||||
Добавьте registry в конфигурацию pip и установите пакет:
|
||||
Install the package by pointing `pip` to the private registry:
|
||||
|
||||
```bash
|
||||
pip install oxipy \
|
||||
--index-url https://gitea.imbastark.ru/api/packages/Netbox/pypi/simple/
|
||||
```
|
||||
|
||||
Или пропишите registry постоянно в `pip.conf` / `pip.ini`, чтобы не указывать `--index-url` каждый раз:
|
||||
You can also configure the registry permanently in `pip.conf` or `pip.ini`:
|
||||
|
||||
```ini
|
||||
# ~/.config/pip/pip.conf (Linux/macOS)
|
||||
@@ -42,35 +46,35 @@ pip install oxipy \
|
||||
extra-index-url = https://gitea.imbastark.ru/api/packages/Netbox/pypi/simple/
|
||||
```
|
||||
|
||||
После этого достаточно:
|
||||
After that, install normally:
|
||||
|
||||
```bash
|
||||
pip install oxipy
|
||||
```
|
||||
|
||||
Если registry требует аутентификации, передайте токен:
|
||||
If the registry requires authentication, pass a token in the index URL:
|
||||
|
||||
```bash
|
||||
pip install oxipy \
|
||||
--index-url https://__token__:<your_token>@gitea.imbastark.ru/api/packages/Netbox/pypi/simple/
|
||||
```
|
||||
|
||||
### Из репозитория Gitea
|
||||
### From Gitea Source
|
||||
|
||||
Установка напрямую через pip без клонирования:
|
||||
Install directly from the repository:
|
||||
|
||||
```bash
|
||||
pip install git+https://gitea.imbastark.ru/Netbox/oxipy.git
|
||||
```
|
||||
|
||||
Конкретный тег или ветка:
|
||||
Install a specific tag or branch:
|
||||
|
||||
```bash
|
||||
pip install git+https://gitea.imbastark.ru/Netbox/oxipy.git@v0.1.0
|
||||
pip install git+https://gitea.imbastark.ru/Netbox/oxipy.git@dev
|
||||
```
|
||||
|
||||
Для разработки (editable install):
|
||||
For local development:
|
||||
|
||||
```bash
|
||||
git clone https://gitea.imbastark.ru/Netbox/oxipy
|
||||
@@ -78,9 +82,7 @@ cd oxipy
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Быстрый старт
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from oxi import OxiAPI
|
||||
@@ -89,39 +91,39 @@ api = OxiAPI(url="https://oxi.example.com", verify=False)
|
||||
|
||||
node = api.node("Router_HOME")
|
||||
|
||||
print(node.ip)
|
||||
print(node.model)
|
||||
print(node.full_name)
|
||||
|
||||
>>> 192.168.1.1
|
||||
>>> keenetic
|
||||
>>> router/HQ
|
||||
print(node.ip)
|
||||
print(node.model)
|
||||
print(node.full_name)
|
||||
|
||||
print(node.config.system.model)
|
||||
print(node.config.interfaces.json())
|
||||
print(node.config.vlans.json())
|
||||
|
||||
>>> Sprinter (KN-3710)
|
||||
>>>
|
||||
[
|
||||
{"name":"Bridge1","ip_address":"192.168.1.1","mask":24,"description":"\"Guest network\""},
|
||||
{"name":"Bridge0","ip_address":"172.16.1.1","mask":24,"description":"\"Home network\""}
|
||||
]
|
||||
>>>
|
||||
[
|
||||
{"vlan_id":1,"name":"Home VLAN"},
|
||||
{"vlan_id":2,"name":"Подключение Ethernet"},
|
||||
{"vlan_id":3,"name":"Home network"}
|
||||
]
|
||||
print(node.config.interfaces.dump_json())
|
||||
print(node.config.vlans.dump_json())
|
||||
```
|
||||
|
||||
---
|
||||
Example output:
|
||||
|
||||
```text
|
||||
192.168.1.1
|
||||
keenetic
|
||||
router/HQ
|
||||
Sprinter (KN-3710)
|
||||
[
|
||||
{"interface": "Bridge1", "ip_address": "192.168.1.1", "mask": 24, "description": "Guest network"},
|
||||
{"interface": "Bridge0", "ip_address": "172.16.1.1", "mask": 24, "description": "Home network"}
|
||||
]
|
||||
[
|
||||
{"vlan_id": 1, "description": "Home VLAN"},
|
||||
{"vlan_id": 2, "description": "Ethernet uplink"},
|
||||
{"vlan_id": 3, "description": "Home network"}
|
||||
]
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### OxiAPI
|
||||
|
||||
Точка входа. Управляет HTTP-сессией и предоставляет доступ к узлам.
|
||||
`OxiAPI` is the entry point. It manages the HTTP session and provides access to
|
||||
Oxidized nodes.
|
||||
|
||||
```python
|
||||
OxiAPI(
|
||||
@@ -132,61 +134,54 @@ OxiAPI(
|
||||
)
|
||||
```
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `url` | `str` | Base URL of the Oxidized API, for example `https://oxi.example.com`. |
|
||||
| `username` | `str | None` | Optional username for HTTP basic authentication. |
|
||||
| `password` | `str | None` | Optional password for HTTP basic authentication. |
|
||||
| `verify` | `bool` | Whether to verify TLS certificates. Defaults to `True`. |
|
||||
|
||||
| Параметр | Тип | Описание |
|
||||
| ---------- | ------ | --------------------------------------------------------- |
|
||||
| `url` | `str` | Базовый URL Oxi API, например `https://oxi.example.com` |
|
||||
| `username` | `str` | Имя пользователя для базовой аутентификации (опционально) |
|
||||
| `password` | `str` | Пароль для базовой аутентификации (опционально) |
|
||||
| `verify` | `bool` | Проверять SSL-сертификат. `True` по умолчанию |
|
||||
|
||||
|
||||
**Пример:**
|
||||
Example:
|
||||
|
||||
```python
|
||||
# Без аутентификации
|
||||
# Without authentication
|
||||
api = OxiAPI(url="https://oxi.example.com")
|
||||
|
||||
# С базовой аутентификацией
|
||||
# With HTTP basic authentication
|
||||
api = OxiAPI(
|
||||
url="https://oxi.example.com",
|
||||
username="admin",
|
||||
password="secret",
|
||||
)
|
||||
|
||||
# Использование как контекстного менеджера (автоматически закрывает сессию)
|
||||
# As a context manager. The HTTP session is closed automatically.
|
||||
with OxiAPI(url="https://oxi.example.com") as api:
|
||||
node = api.node("HQ")
|
||||
print(node.ip)
|
||||
|
||||
>>> 192.168.1.1
|
||||
```
|
||||
|
||||
#### `api.node(name)`
|
||||
|
||||
Возвращает `[NodeView](#nodeview)` для указанного узла.
|
||||
Returns a `NodeView` for the requested Oxidized node.
|
||||
|
||||
```python
|
||||
node = api.node("HQ")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### NodeView
|
||||
|
||||
Представление узла сети. Содержит метаданные и ленивый доступ к конфигурации.
|
||||
`NodeView` represents one network device. It contains metadata returned by
|
||||
Oxidized and lazy access to the fetched configuration.
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `ip` | `str` | Node IP address. |
|
||||
| `full_name` | `str` | Full node name in Oxidized. |
|
||||
| `group` | `str` | Oxidized group the node belongs to. |
|
||||
| `model` | `str` | Device model key used to select a parser. |
|
||||
| `config` | `NodeConfig` | Device configuration, fetched and parsed on first access. |
|
||||
|
||||
| Свойство | Тип | Описание |
|
||||
| ----------- | ------------ | ---------------------------------------------------- |
|
||||
| `ip` | `str` | IP-адрес узла |
|
||||
| `full_name` | `str` | Полное имя узла в Oxi |
|
||||
| `group` | `str` | Группа, к которой принадлежит узел |
|
||||
| `model` | `str` | Модель устройства (используется для парсинга) |
|
||||
| `config` | `NodeConfig` | Конфигурация узла (загружается при первом обращении) |
|
||||
|
||||
|
||||
**Пример:**
|
||||
Example:
|
||||
|
||||
```python
|
||||
node = api.node("HQ")
|
||||
@@ -194,135 +189,106 @@ node = api.node("HQ")
|
||||
print(node.ip)
|
||||
print(node.group)
|
||||
print(node.model)
|
||||
|
||||
>>> 192.168.1.1
|
||||
>>> branch-office
|
||||
>>> keenetic
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### NodeConfig
|
||||
|
||||
Загружает и парсит конфигурацию устройства. Использует TTP-шаблоны, соответствующие модели устройства.
|
||||
`NodeConfig` fetches and parses a device configuration. The parser is selected
|
||||
from the device registry by the node `model` value returned by Oxidized.
|
||||
|
||||
Доступ к секциям конфигурации осуществляется через свойства, возвращающие `[ModelView](#modelview)`.
|
||||
Configuration sections are exposed through properties that return `ModelView`
|
||||
objects.
|
||||
|
||||
| Property | Returns | Description |
|
||||
| --- | --- | --- |
|
||||
| `system` | `ModelView[System]` | System information. |
|
||||
| `interfaces` | `ModelView[list[Interfaces]]` | Parsed interface list. |
|
||||
| `vlans` | `ModelView[list[Vlans]]` | Parsed VLAN list, if the template provides VLAN data. |
|
||||
| `text` | `str` | Raw configuration text fetched from Oxidized. |
|
||||
|
||||
| Свойство | Возвращает | Описание |
|
||||
| ------------ | ----------------------------- | ---------------------------------- |
|
||||
| `system` | `ModelView[System]` | Системная информация об устройстве |
|
||||
| `interfaces` | `ModelView[list[Interfaces]]` | Список интерфейсов |
|
||||
| `vlans` | `ModelView[list[Vlans]]` | Список VLAN (если есть) |
|
||||
| `text` | `str` | Сырой текст конфигурации |
|
||||
|
||||
|
||||
**Пример:**
|
||||
Example:
|
||||
|
||||
```python
|
||||
cfg = node.config
|
||||
|
||||
# Системная информация
|
||||
print(cfg.system.model)
|
||||
print(cfg.system.serial_number)
|
||||
print(cfg.system.version)
|
||||
print(cfg.system.model)
|
||||
print(cfg.system.serial_number)
|
||||
print(cfg.system.version)
|
||||
|
||||
>>> Mikrotik RB951Ui-2nD
|
||||
>>> B88C0B31117B
|
||||
>>> 7.16.1
|
||||
|
||||
# Итерация по интерфейсам
|
||||
for iface in cfg.interfaces:
|
||||
print(iface.name, iface.ip_address, iface.mask)
|
||||
|
||||
# Индексация
|
||||
first_iface = cfg.interfaces[0]
|
||||
print(first_iface.name)
|
||||
|
||||
# Количество интерфейсов
|
||||
print(len(cfg.interfaces))
|
||||
|
||||
# JSON-дамп любой секции
|
||||
print(cfg.interfaces.json())
|
||||
print(cfg.vlans.json())
|
||||
print(cfg.system.json())
|
||||
print(cfg.interfaces.dump_json())
|
||||
print(cfg.vlans.dump_json())
|
||||
print(cfg.system.dump_json())
|
||||
|
||||
# Сырая конфигурация текстом
|
||||
print(cfg.text)
|
||||
```
|
||||
|
||||
---
|
||||
`NodeConfig` also provides `dump()` and `dump_json()` methods for the whole
|
||||
parsed device object.
|
||||
|
||||
### ModelView
|
||||
|
||||
Обёртка над Pydantic-моделью или списком моделей. Обеспечивает сериализацию, итерацию и прозрачный доступ к атрибутам.
|
||||
`ModelView` wraps either a single Pydantic model or a list of Pydantic models.
|
||||
It provides serialization, iteration for list sections, and transparent access
|
||||
to model attributes.
|
||||
|
||||
| Method / operation | Applies to | Description |
|
||||
| --- | --- | --- |
|
||||
| `.dump()` | single model and list | Returns a Python `dict` or `list` using aliases. |
|
||||
| `.dump_json()` | single model and list | Returns a JSON string using aliases. |
|
||||
| `.<attr>` | single model and list | Proxies attribute access to the wrapped model. |
|
||||
| `iter(view)` | list only | Iterates over wrapped models. |
|
||||
| `len(view)` | list only | Returns the number of wrapped models. |
|
||||
| `view[i]` | list only | Returns an item or slice. |
|
||||
|
||||
| Метод / свойство | Применимо к | Описание |
|
||||
| ---------------- | ------------ | ------------------------------------------------- |
|
||||
| `.json()` | оба варианта | Возвращает JSON-строку (с `by_alias=True`) |
|
||||
| `.<attr>` | оба варианта | Проксирует обращение к атрибутам вложенной модели |
|
||||
| `iter(view)` | список | Итерация по элементам списка моделей |
|
||||
| `len(view)` | список | Количество элементов в списке |
|
||||
| `view[i]` | список | Получение элемента по индексу или срез |
|
||||
`__iter__`, `__len__`, and `__getitem__` are available only for list-backed
|
||||
sections such as `interfaces` and `vlans`. Calling them on `system` raises
|
||||
`TypeError`.
|
||||
|
||||
|
||||
> `__iter__`, `__len__` и `__getitem__` доступны только для `interfaces` и `vlans` (они оборачивают список). Вызов этих методов на `system` (одиночная модель) вызовет `TypeError`.
|
||||
|
||||
**Примеры:**
|
||||
Examples:
|
||||
|
||||
```python
|
||||
# Одиночная модель — system
|
||||
view = node.config.system
|
||||
print(view.json())
|
||||
>>> '{"model":"RB951Ui-2nD","serial_number":"B88C0B31117B","version":"7.12.1"}'
|
||||
print(view.model) # 'RB951Ui-2nD'
|
||||
print(view.serial_number) # 'B88C0B31117B'
|
||||
system = node.config.system
|
||||
print(system.dump_json())
|
||||
print(system.model)
|
||||
print(system.serial_number)
|
||||
|
||||
>>> RB951Ui-2nD
|
||||
>>> B88C0B31117B
|
||||
# Список — interfaces
|
||||
interfaces = node.config.interfaces
|
||||
|
||||
# Итерация
|
||||
for iface in interfaces:
|
||||
print(iface.name, iface.ip_address)
|
||||
|
||||
# Длина
|
||||
print(len(interfaces)) # 5
|
||||
|
||||
# Индексация и срезы
|
||||
first = interfaces[0]
|
||||
top3 = interfaces[:3]
|
||||
|
||||
# JSON всего списка
|
||||
print(interfaces.json())
|
||||
print(len(interfaces))
|
||||
print(interfaces[0])
|
||||
print(interfaces[:3])
|
||||
print(interfaces.dump())
|
||||
```
|
||||
|
||||
---
|
||||
## Supported Devices
|
||||
|
||||
## Поддерживаемые устройства
|
||||
Registry keys are compared with the Oxidized node `model` value
|
||||
case-insensitively.
|
||||
|
||||
| Device | Registry keys |
|
||||
| --- | --- |
|
||||
| Keenetic | `ndms`, `keenetic`, `keeneticos` |
|
||||
| MikroTik | `routeros`, `ros`, `mikrotik` |
|
||||
| Qtech | `qtech` |
|
||||
| Huawei | `huawei`, `vrp` |
|
||||
| Eltex | `eltex` |
|
||||
| H3C | `h3c` |
|
||||
| Quasar | `qos`, `quasar` |
|
||||
|
||||
| Устройство | Ключи реестра |
|
||||
| ---------- | -------------------------------- |
|
||||
| Keenetic | `ndms`, `keenetic`, `keeneticos` |
|
||||
| MikroTik | `routeros`, `ros`, `mikrotik` |
|
||||
| Qtech | `qtech` |
|
||||
| Huawei | `huawei`, `vrp` |
|
||||
| Eltex | `eltex` |
|
||||
| H3C | `h3c` |
|
||||
| Quasar | `qos`, `quasar` |
|
||||
You can add support for another device family by creating a new device model
|
||||
and TTP template. See [Extending Device Models](docs/extending-models.md).
|
||||
|
||||
## Additional Documentation
|
||||
|
||||
Ключи реестра — это значения поля `model`, возвращаемого API для узла. Регистр не учитывается.
|
||||
|
||||
Добавить поддержку нового устройства можно самостоятельно — подробнее в разделе [Расширение моделей](docs/extending-models.md).
|
||||
|
||||
---
|
||||
|
||||
## Дополнительно
|
||||
|
||||
- [Написание TTP-шаблонов](docs/templates.md)
|
||||
- [Расширение и переопределение моделей устройств](docs/extending-models.md)
|
||||
|
||||
- [Writing TTP Templates](docs/templates.md)
|
||||
- [Extending Device Models](docs/extending-models.md)
|
||||
|
||||
Reference in New Issue
Block a user