various improvements

This commit is contained in:
ge 2023-11-23 02:35:32 +03:00
parent be85f3e83c
commit 1332697461
170 changed files with 0 additions and 14347 deletions

View File

@ -1,81 +0,0 @@
Metadata-Version: 2.1
Name: compute
Version: 0.1.0.dev1
Summary: Compute instances management library and tools
Author: ge
Author-email: ge@nixhacks.net
Requires-Python: >=3.11,<4.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Requires-Dist: libvirt-python (==9.0.0)
Requires-Dist: lxml (>=4.9.2,<5.0.0)
Requires-Dist: pydantic (==1.10.4)
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
Description-Content-Type: text/markdown
# Compute
Compute instances management library and tools.
## Docs
Run `make serve-docs`. See [Development](#development) below.
## Roadmap
- [x] Create instances
- [ ] CDROM
- [ ] cloud-init for provisioning instances
- [x] Instance power management
- [x] Instance pause and resume
- [x] vCPU hotplug
- [x] Memory hotplug
- [x] Hot disk resize [not tested]
- [ ] CPU topology customization
- [x] CPU customization (emulation mode, model, vendor, features)
- [ ] BIOS/UEFI settings
- [x] Device attaching
- [x] Device detaching
- [ ] GPU passthrough
- [ ] CPU guarantied resource percent support
- [x] QEMU Guest Agent management
- [ ] Instance resources usage stats
- [ ] SSH-keys management
- [x] Setting user passwords in guest
- [x] QCOW2 disks support
- [ ] ZVOL support
- [ ] Network disks support
- [ ] Images service integration (Images service is not implemented yet)
- [ ] Manage storage pools
- [ ] Idempotency
- [ ] CLI [in progress]
- [ ] HTTP API
- [ ] Instance migrations
- [ ] Instance snapshots
- [ ] Instance backups
- [ ] LXC
## Development
Python 3.11+ is required.
Install [poetry](https://python-poetry.org/), clone this repository and run:
```
poetry install --with dev --with docs
```
# Build Debian package
Install Docker first, then run:
```
make build-deb
```
`compute` and `compute-doc` packages will built. See packaging/build directory. Packages can be installed via `dpkg` or `apt-get`:
```
apt-get install ./compute*.deb
```

View File

@ -1,23 +0,0 @@
../scripts/compute,sha256=b-Gj6H6ssfbGalpouUMSX5pmsjqDnN9xMdTwnU-UfZY,216
compute/__init__.py,sha256=x4zp_CoVPKgDT6AqhometspAyinGxJUXO48duJ5aHUM,873
compute/__main__.py,sha256=zJyKJul6pCbguFPtVLZBoAuZl9RXibn4CCMn46jIgUQ,745
compute/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
compute/cli/control.py,sha256=83wnR21pHOPyyk1i1n_YBIDz6dCFB6hmuIFguIk68rs,14634
compute/common.py,sha256=G1qwC1EybG5LEJtyoux9ymiqB2ZOsgKXlCpbuhHv55Y,948
compute/exceptions.py,sha256=Ga59L55qSAPeyDfjANPuMh4yVSRWHDYi9xqq5o4_7-0,2452
compute/instance/__init__.py,sha256=kHN8jVamyrBZYZgi62tPtJ7rS73gUPhfswLalmPA5Zs,772
compute/instance/guest_agent.py,sha256=fq89kQbcV5X5eFCsMmujRuwTOSghWO4ZhAjvxyUu84M,7018
compute/instance/instance.py,sha256=WP6oTJfdAf6QlefwVLqdC8J6XoKHum6nZhwwHOEtjNk,23297
compute/instance/schemas.py,sha256=B51ytPlxhnx0MrkR2WYhd49RaRT7Is7NsIM9OrMUpvI,4288
compute/session.py,sha256=znYOIzoiCbSG62k-ViaXti_lOnw88wD8Syp3nCXAJ28,10050
compute/storage/__init__.py,sha256=zNaVjZ2925DxrVUFWwVRsGU6bSYbF46sb4L6NsaiKbw,736
compute/storage/pool.py,sha256=9z99bBDbb4ATGpfMkEWpxAO4fEQHNVOxxf0iUln9cN0,4197
compute/storage/volume.py,sha256=_TbK9Y4d3NAeknPUiuhldAT3ZaN1sZgjy4QzC-Sw4Io,4110
compute/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
compute/utils/config_loader.py,sha256=ul1J3sZg0D9R0HbOz5Pg9JmL4nFaMahAzQEdGaWFABU,1989
compute/utils/ids.py,sha256=fg6Xsg4OMM-BIaU3DPu0L91ICwx-L3qNoELEwQZz2s0,1007
compute/utils/units.py,sha256=UkwD0zQ-rlpSpkbfezCcvJx4D8iZlI9M-oXXvdVEvy0,1549
compute-0.1.0.dev1.dist-info/METADATA,sha256=tbX8xp92Jwqf44sOwPB-HqKHLezab5dU9DrQDYFitDQ,1944
compute-0.1.0.dev1.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
compute-0.1.0.dev1.dist-info/entry_points.txt,sha256=xHhg-Fo9Z5gJnIahbG8pVIGNDqlH5Eordn8hnXUwscw,51
compute-0.1.0.dev1.dist-info/RECORD,,

View File

@ -1,4 +0,0 @@
Wheel-Version: 1.0
Generator: poetry-core 1.4.0
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -1,3 +0,0 @@
[console_scripts]
compute=compute.cli.control:cli

View File

@ -1,22 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Compute instances management library."""
__version__ = '0.1.0-dev1'
from .instance import Instance, InstanceConfig, InstanceSchema
from .session import Session
from .storage import StoragePool, Volume, VolumeConfig

View File

@ -1,21 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Command line interface for compute module."""
from compute.cli import main
main.cli()

View File

@ -1,501 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Command line interface."""
import argparse
import io
import logging
import os
import shlex
import sys
from collections import UserDict
from typing import Any
from uuid import uuid4
import libvirt
import yaml
from pydantic import ValidationError
from compute import __version__
from compute.exceptions import ComputeError, GuestAgentTimeoutExceededError
from compute.instance import GuestAgent
from compute.session import Session
from compute.utils import ids
log = logging.getLogger(__name__)
log_levels = [lv.lower() for lv in logging.getLevelNamesMapping()]
libvirt.registerErrorHandler(
lambda userdata, err: None, # noqa: ARG005
ctx=None,
)
class Table:
"""Minimalistic text table constructor."""
def __init__(self, whitespace: str | None = None):
"""Initialise Table."""
self.whitespace = whitespace or '\t'
self.header = []
self.rows = []
self.table = ''
def add_row(self, row: list) -> None:
"""Add table row."""
self.rows.append([str(col) for col in row])
def add_rows(self, rows: list[list]) -> None:
"""Add multiple rows."""
for row in rows:
self.add_row(row)
def __str__(self) -> str:
"""Build table and return."""
widths = [max(map(len, col)) for col in zip(*self.rows, strict=True)]
self.rows.insert(0, [str(h).upper() for h in self.header])
for row in self.rows:
self.table += self.whitespace.join(
(
val.ljust(width)
for val, width in zip(row, widths, strict=True)
)
)
self.table += '\n'
return self.table.strip()
def _list_instances(session: Session) -> None:
table = Table()
table.header = ['NAME', 'STATE']
for instance in session.list_instances():
table.add_row(
[
instance.name,
instance.get_status(),
]
)
print(table)
sys.exit()
def _exec_guest_agent_command(
session: Session, args: argparse.Namespace
) -> None:
instance = session.get_instance(args.instance)
ga = GuestAgent(instance.domain, timeout=args.timeout)
arguments = args.arguments.copy()
if len(arguments) > 1 and not args.no_join_args:
arguments = [shlex.join(arguments)]
if not args.no_join_args:
arguments.insert(0, '-c')
stdin = None
if not sys.stdin.isatty():
stdin = sys.stdin.read()
try:
output = ga.guest_exec(
path=args.executable,
args=arguments,
env=args.env,
stdin=stdin,
capture_output=True,
decode_output=True,
poll=True,
)
except GuestAgentTimeoutExceededError as e:
sys.exit(
f'{e}. NOTE: command may still running in guest, '
f'PID={ga.last_pid}'
)
if output.stderr:
print(output.stderr.strip(), file=sys.stderr)
if output.stdout:
print(output.stdout.strip(), file=sys.stdout)
sys.exit(output.exitcode)
class _NotPresent:
"""
Type for representing non-existent dictionary keys.
See :class:`_FillableDict`.
"""
class _FillableDict(UserDict):
"""Use :method:`fill` to add key if not present."""
def __init__(self, data: dict):
self.data = data
def fill(self, key: str, value: Any) -> None: # noqa: ANN401
if self.data.get(key, _NotPresent) is _NotPresent:
self.data[key] = value
def _merge_dicts(a: dict, b: dict, path: list[str] | None = None) -> dict:
"""Merge `b` into `a`. Return modified `a`."""
if path is None:
path = []
for key in b:
if key in a:
if isinstance(a[key], dict) and isinstance(b[key], dict):
_merge_dicts(a[key], b[key], [path + str(key)])
elif a[key] == b[key]:
pass # same leaf value
else:
a[key] = b[key] # replace existing key's values
else:
a[key] = b[key]
return a
def _create_instance(session: Session, file: io.TextIOWrapper) -> None:
try:
data = _FillableDict(yaml.load(file.read(), Loader=yaml.SafeLoader))
log.debug('Read from file: %s', data)
except yaml.YAMLError as e:
sys.exit(f'error: cannot parse YAML: {e}')
capabilities = session.get_capabilities()
node_info = session.get_node_info()
data.fill('name', uuid4().hex)
data.fill('title', None)
data.fill('description', None)
data.fill('arch', capabilities.arch)
data.fill('machine', capabilities.machine)
data.fill('emulator', capabilities.emulator)
data.fill('max_vcpus', node_info.cpus)
data.fill('max_memory', node_info.memory)
data.fill('cpu', {})
cpu = {
'emulation_mode': 'host-passthrough',
'model': None,
'vendor': None,
'topology': None,
'features': None,
}
data['cpu'] = _merge_dicts(data['cpu'], cpu)
data.fill(
'network_interfaces',
[{'source': 'default', 'mac': ids.random_mac()}],
)
data.fill('boot', {'order': ['cdrom', 'hd']})
try:
log.debug('Input data: %s', data)
session.create_instance(**data)
except ValidationError as e:
for error in e.errors():
fields = '.'.join([str(lc) for lc in error['loc']])
print(
f"validation error: {fields}: {error['msg']}",
file=sys.stderr,
)
sys.exit()
def _shutdown_instance(session: Session, args: argparse.Namespace) -> None:
instance = session.get_instance(args.instance)
if args.soft:
method = 'SOFT'
elif args.hard:
method = 'HARD'
elif args.unsafe:
method = 'UNSAFE'
else:
method = 'NORMAL'
instance.shutdown(method)
def main(session: Session, args: argparse.Namespace) -> None:
"""Perform actions."""
match args.command:
case 'init':
_create_instance(session, args.file)
case 'exec':
_exec_guest_agent_command(session, args)
case 'ls':
_list_instances(session)
case 'start':
instance = session.get_instance(args.instance)
instance.start()
case 'shutdown':
_shutdown_instance(session, args)
case 'reboot':
instance = session.get_instance(args.instance)
instance.reboot()
case 'reset':
instance = session.get_instance(args.instance)
instance.reset()
case 'powrst':
instance = session.get_instance(args.instance)
instance.power_reset()
case 'pause':
instance = session.get_instance(args.instance)
instance.pause()
case 'resume':
instance = session.get_instance(args.instance)
instance.resume()
case 'status':
instance = session.get_instance(args.instance)
print(instance.status)
case 'setvcpus':
instance = session.get_instance(args.instance)
instance.set_vcpus(args.nvcpus, live=True)
case 'setmem':
instance = session.get_instance(args.instance)
instance.set_memory(args.memory, live=True)
case 'setpass':
instance = session.get_instance(args.instance)
instance.set_user_password(
args.username,
args.password,
encrypted=args.encrypted,
)
def cli() -> None: # noqa: PLR0915
"""Return command line arguments parser."""
root = argparse.ArgumentParser(
prog='compute',
description='manage compute instances',
formatter_class=argparse.RawTextHelpFormatter,
)
root.add_argument(
'-v',
'--verbose',
action='store_true',
default=False,
help='enable verbose mode',
)
root.add_argument(
'-c',
'--connect',
metavar='URI',
help='libvirt connection URI',
)
root.add_argument(
'-l',
'--log-level',
type=str.lower,
metavar='LEVEL',
choices=log_levels,
help='log level',
)
root.add_argument(
'-V',
'--version',
action='version',
version=__version__,
)
subparsers = root.add_subparsers(dest='command', metavar='COMMAND')
# init command
init = subparsers.add_parser(
'init', help='initialise instance using YAML config file'
)
init.add_argument(
'file',
type=argparse.FileType('r', encoding='UTF-8'),
nargs='?',
default='instance.yaml',
help='instance config [default: instance.yaml]',
)
# exec subcommand
execute = subparsers.add_parser(
'exec',
help='execute command in guest via guest agent',
description=(
'NOTE: any argument after instance name will be passed into '
'guest as shell command.'
),
)
execute.add_argument('instance')
execute.add_argument('arguments', nargs=argparse.REMAINDER)
execute.add_argument(
'-t',
'--timeout',
type=int,
default=60,
help=(
'waiting time in seconds for a command to be executed '
'in guest [default: 60]'
),
)
execute.add_argument(
'-x',
'--executable',
default='/bin/sh',
help='path to executable in guest [default: /bin/sh]',
)
execute.add_argument(
'-e',
'--env',
type=str,
nargs='?',
action='append',
help='environment variables to pass to executable in guest',
)
execute.add_argument(
'-n',
'--no-join-args',
action='store_true',
default=False,
help=(
"do not join arguments list and add '-c' option, suitable "
'for non-shell executables and other specific cases.'
),
)
# ls subcommand
listall = subparsers.add_parser('ls', help='list instances')
listall.add_argument(
'-a',
'--all',
action='store_true',
default=False,
help='list all instances including inactive',
)
# start subcommand
start = subparsers.add_parser('start', help='start instance')
start.add_argument('instance')
# shutdown subcommand
shutdown = subparsers.add_parser('shutdown', help='shutdown instance')
shutdown.add_argument('instance')
shutdown_opts = shutdown.add_mutually_exclusive_group()
shutdown_opts.add_argument(
'-s',
'--soft',
action='store_true',
help='normal guest OS shutdown, guest agent is used',
)
shutdown_opts.add_argument(
'-n',
'--normal',
action='store_true',
help='shutdown with hypervisor selected method [default]',
)
shutdown_opts.add_argument(
'-H',
'--hard',
action='store_true',
help=(
"gracefully destroy instance, it's like long "
'pressing the power button'
),
)
shutdown_opts.add_argument(
'-u',
'--unsafe',
action='store_true',
help=(
'destroy instance, this is similar to a power outage '
'and may result in data loss or corruption'
),
)
# reboot subcommand
reboot = subparsers.add_parser('reboot', help='reboot instance')
reboot.add_argument('instance')
# reset subcommand
reset = subparsers.add_parser('reset', help='reset instance')
reset.add_argument('instance')
# powrst subcommand
powrst = subparsers.add_parser('powrst', help='power reset instance')
powrst.add_argument('instance')
# pause subcommand
pause = subparsers.add_parser('pause', help='pause instance')
pause.add_argument('instance')
# resume subcommand
resume = subparsers.add_parser('resume', help='resume paused instance')
resume.add_argument('instance')
# status subcommand
status = subparsers.add_parser('status', help='display instance status')
status.add_argument('instance')
# setvcpus subcommand
setvcpus = subparsers.add_parser('setvcpus', help='set vCPU number')
setvcpus.add_argument('instance')
setvcpus.add_argument('nvcpus', type=int)
# setmem subcommand
setmem = subparsers.add_parser('setmem', help='set memory size')
setmem.add_argument('instance')
setmem.add_argument('memory', type=int, help='memory in MiB')
# setpass subcommand
setpass = subparsers.add_parser(
'setpass',
help='set user password in guest',
)
setpass.add_argument('instance')
setpass.add_argument('username')
setpass.add_argument('password')
setpass.add_argument(
'-e',
'--encrypted',
action='store_true',
default=False,
help='set it if password is already encrypted',
)
args = root.parse_args()
if args.command is None:
root.print_help()
sys.exit()
log_level = args.log_level or os.getenv('CMP_LOG')
if isinstance(log_level, str) and log_level.lower() in log_levels:
logging.basicConfig(
level=logging.getLevelNamesMapping()[log_level.upper()]
)
log.debug('CLI started with args: %s', args)
connect_uri = (
args.connect
or os.getenv('CMP_LIBVIRT_URI')
or os.getenv('LIBVIRT_DEFAULT_URI')
or 'qemu:///system'
)
try:
with Session(connect_uri) as session:
main(session, args)
except ComputeError as e:
sys.exit(f'error: {e}')
except KeyboardInterrupt:
sys.exit()
except SystemExit as e:
sys.exit(e)
except Exception as e: # noqa: BLE001
sys.exit(f'unexpected error {type(e)}: {e}')
if __name__ == '__main__':
cli()

View File

@ -1,30 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Common symbols."""
from abc import ABC, abstractmethod
class EntityConfig(ABC):
"""An abstract entity XML config builder class."""
@abstractmethod
def to_xml(self) -> str:
"""Return device XML config."""
raise NotImplementedError
DeviceConfig = EntityConfig

View File

@ -1,80 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Exceptions."""
class ComputeError(Exception):
"""Basic exception class."""
class ConfigLoaderError(ComputeError):
"""Something went wrong when loading configuration."""
class SessionError(ComputeError):
"""Something went wrong while connecting to libvirtd."""
class GuestAgentError(ComputeError):
"""Something went wring when QEMU Guest Agent call."""
class GuestAgentUnavailableError(GuestAgentError):
"""Guest agent is not connected or is unavailable."""
class GuestAgentTimeoutExceededError(GuestAgentError):
"""QEMU timeout exceeded."""
def __init__(self, msg: int):
"""Initialise GuestAgentTimeoutExceededError."""
super().__init__(f'QEMU timeout ({msg} sec) exceeded')
class GuestAgentCommandNotSupportedError(GuestAgentError):
"""Guest agent command is not supported or blacklisted on guest."""
class StoragePoolError(ComputeError):
"""Something went wrong when operating with storage pool."""
class StoragePoolNotFoundError(StoragePoolError):
"""Storage pool not found."""
def __init__(self, msg: str):
"""Initialise StoragePoolNotFoundError."""
super().__init__(f"storage pool named '{msg}' not found")
class VolumeNotFoundError(StoragePoolError):
"""Storage volume not found."""
def __init__(self, msg: str):
"""Initialise VolumeNotFoundError."""
super().__init__(f"storage volume '{msg}' not found")
class InstanceError(ComputeError):
"""Something went wrong while interacting with the domain."""
class InstanceNotFoundError(InstanceError):
"""Virtual machine or container not found on compute node."""
def __init__(self, msg: str):
"""Initialise InstanceNotFoundError."""
super().__init__(f"compute instance '{msg}' not found")

View File

@ -1,18 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from .guest_agent import GuestAgent
from .instance import Instance, InstanceConfig
from .schemas import InstanceSchema

View File

@ -1,208 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Interacting with the QEMU Guest Agent."""
import json
import logging
from base64 import b64decode, standard_b64encode
from time import sleep, time
from typing import NamedTuple
import libvirt
import libvirt_qemu
from compute.exceptions import (
GuestAgentCommandNotSupportedError,
GuestAgentError,
GuestAgentTimeoutExceededError,
GuestAgentUnavailableError,
)
log = logging.getLogger(__name__)
class GuestExecOutput(NamedTuple):
"""QEMU guest-exec command output."""
exited: bool | None = None
exitcode: int | None = None
stdout: str | None = None
stderr: str | None = None
class GuestAgent:
"""Class for interacting with QEMU guest agent."""
def __init__(self, domain: libvirt.virDomain, timeout: int = 60):
"""
Initialise GuestAgent.
:param domain: Libvirt domain object
:param timeout: QEMU timeout
"""
self.domain = domain
self.timeout = timeout
self.flags = libvirt_qemu.VIR_DOMAIN_QEMU_MONITOR_COMMAND_DEFAULT
self.last_pid = None
def execute(self, command: dict) -> dict:
"""
Execute QEMU guest agent command.
See: https://qemu-project.gitlab.io/qemu/interop/qemu-ga-ref.html
:param command: QEMU guest agent command as dict
:return: Command output
:rtype: dict
"""
log.debug(command)
try:
output = libvirt_qemu.qemuAgentCommand(
self.domain, json.dumps(command), self.timeout, self.flags
)
return json.loads(output)
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_AGENT_UNRESPONSIVE:
raise GuestAgentUnavailableError(e) from e
raise GuestAgentError(e) from e
def is_available(self) -> bool:
"""
Execute guest-ping.
:return: True or False if guest agent is unreachable.
:rtype: bool
"""
try:
if self.execute({'execute': 'guest-ping', 'arguments': {}}):
return True
except GuestAgentError:
return False
def get_supported_commands(self) -> set[str]:
"""Return set of supported guest agent commands."""
output = self.execute({'execute': 'guest-info', 'arguments': {}})
return {
cmd['name']
for cmd in output['return']['supported_commands']
if cmd['enabled'] is True
}
def raise_for_commands(self, commands: list[str]) -> None:
"""
Raise exception if QEMU GA command is not available.
:param commands: List of required commands
:raise: GuestAgentCommandNotSupportedError
"""
supported = self.get_supported_commands()
for command in commands:
if command not in supported:
raise GuestAgentCommandNotSupportedError(command)
def guest_exec( # noqa: PLR0913
self,
path: str,
args: list[str] | None = None,
env: list[str] | None = None,
stdin: str | None = None,
*,
capture_output: bool = False,
decode_output: bool = False,
poll: bool = False,
) -> GuestExecOutput:
"""
Execute qemu-exec command and return output.
:param path: Path ot executable on guest.
:param arg: List of arguments to pass to executable.
:param env: List of environment variables to pass to executable.
For example: ``['LANG=C', 'TERM=xterm']``
:param stdin: Data to pass to executable STDIN.
:param capture_output: Capture command output.
:param decode_output: Use base64_decode() to decode command output.
Affects only if `capture_output` is True.
:param poll: Poll command output. Uses `self.timeout` and
POLL_INTERVAL constant.
:return: Command output
:rtype: GuestExecOutput
"""
self.raise_for_commands(['guest-exec', 'guest-exec-status'])
command = {
'execute': 'guest-exec',
'arguments': {
'path': path,
**({'arg': args} if args else {}),
**({'env': env} if env else {}),
**(
{
'input-data': standard_b64encode(
stdin.encode('utf-8')
).decode('utf-8')
}
if stdin
else {}
),
'capture-output': capture_output,
},
}
output = self.execute(command)
self.last_pid = pid = output['return']['pid']
command_status = self.guest_exec_status(pid, poll=poll)['return']
exited = command_status['exited']
exitcode = command_status['exitcode']
stdout = command_status.get('out-data', None)
stderr = command_status.get('err-data', None)
if decode_output:
stdout = b64decode(stdout or '').decode('utf-8')
stderr = b64decode(stderr or '').decode('utf-8')
return GuestExecOutput(exited, exitcode, stdout, stderr)
def guest_exec_status(
self, pid: int, *, poll: bool = False, poll_interval: float = 0.3
) -> dict:
"""
Execute guest-exec-status and return output.
:param pid: PID in guest.
:param poll: If True poll command status.
:param poll_interval: Time between attempts to obtain command status.
:return: Command output
:rtype: dict
"""
self.raise_for_commands(['guest-exec-status'])
command = {
'execute': 'guest-exec-status',
'arguments': {'pid': pid},
}
if not poll:
return self.execute(command)
start_time = time()
while True:
command_status = self.execute(command)
if command_status['return']['exited']:
break
sleep(poll_interval)
now = time()
if now - start_time > self.timeout:
raise GuestAgentTimeoutExceededError(self.timeout)
log.debug(
'Polling command pid=%s finished, time taken: %s seconds',
pid,
int(time() - start_time),
)
return command_status

View File

@ -1,675 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Manage compute instances."""
__all__ = ['Instance', 'InstanceConfig', 'InstanceInfo']
import logging
from typing import NamedTuple
import libvirt
from lxml import etree
from lxml.builder import E
from compute.common import DeviceConfig, EntityConfig
from compute.exceptions import (
GuestAgentCommandNotSupportedError,
InstanceError,
)
from compute.storage import DiskConfig
from compute.utils import units
from .guest_agent import GuestAgent
from .schemas import (
CPUEmulationMode,
CPUSchema,
InstanceSchema,
NetworkInterfaceSchema,
)
log = logging.getLogger(__name__)
class InstanceConfig(EntityConfig):
"""Compute instance XML config builder."""
def __init__(self, schema: InstanceSchema):
"""
Initialise InstanceConfig.
:param schema: InstanceSchema object
"""
self.name = schema.name
self.title = schema.title
self.description = schema.description
self.memory = schema.memory
self.max_memory = schema.max_memory
self.vcpus = schema.vcpus
self.max_vcpus = schema.max_vcpus
self.cpu = schema.cpu
self.machine = schema.machine
self.emulator = schema.emulator
self.arch = schema.arch
self.boot = schema.boot
self.network_interfaces = schema.network_interfaces
def _gen_cpu_xml(self, cpu: CPUSchema) -> etree.Element:
options = {
'mode': cpu.emulation_mode,
'match': 'exact',
'check': 'partial',
}
if cpu.emulation_mode == CPUEmulationMode.HOST_PASSTHROUGH:
options['check'] = 'none'
options['migratable'] = 'on'
xml = E.cpu(**options)
if cpu.model:
xml.append(E.model(cpu.model, fallback='forbid'))
if cpu.vendor:
xml.append(E.vendor(cpu.vendor))
if cpu.topology:
xml.append(
E.topology(
sockets=str(cpu.topology.sockets),
dies=str(cpu.topology.dies),
cores=str(cpu.topology.cores),
threads=str(cpu.topology.threads),
)
)
if cpu.features:
for feature in cpu.features.require:
xml.append(E.feature(policy='require', name=feature))
for feature in cpu.features.disable:
xml.append(E.feature(policy='disable', name=feature))
return xml
def _gen_vcpus_xml(self, vcpus: int, max_vcpus: int) -> etree.Element:
xml = E.vcpus()
xml.append(E.vcpu(id='0', enabled='yes', hotpluggable='no', order='1'))
for i in range(max_vcpus - 1):
enabled = 'yes' if (i + 2) <= vcpus else 'no'
xml.append(
E.vcpu(
id=str(i + 1),
enabled=enabled,
hotpluggable='yes',
order=str(i + 2),
)
)
return xml
def _gen_network_interface_xml(
self, interface: NetworkInterfaceSchema
) -> etree.Element:
return E.interface(
E.source(network=interface.source),
E.mac(address=interface.mac),
type='network',
)
def to_xml(self) -> str:
"""Return XML config for libvirt."""
xml = E.domain(type='kvm')
xml.append(E.name(self.name))
if self.title:
xml.append(E.title(self.title))
if self.description:
xml.append(E.description(self.description))
xml.append(E.metadata())
xml.append(E.memory(str(self.max_memory * 1024), unit='KiB'))
xml.append(E.currentMemory(str(self.memory * 1024), unit='KiB'))
xml.append(
E.vcpu(
str(self.max_vcpus),
placement='static',
current=str(self.vcpus),
)
)
xml.append(self._gen_cpu_xml(self.cpu))
os = E.os(E.type('hvm', machine=self.machine, arch=self.arch))
for dev in self.boot.order:
os.append(E.boot(dev=dev))
xml.append(os)
xml.append(E.features(E.acpi(), E.apic()))
xml.append(E.on_poweroff('destroy'))
xml.append(E.on_reboot('restart'))
xml.append(E.on_crash('restart'))
xml.append(
E.pm(
E('suspend-to-mem', enabled='no'),
E('suspend-to-disk', enabled='no'),
)
)
devices = E.devices()
devices.append(E.emulator(str(self.emulator)))
for interface in self.network_interfaces:
devices.append(self._gen_network_interface_xml(interface))
devices.append(E.graphics(type='vnc', port='-1', autoport='yes'))
devices.append(E.input(type='tablet', bus='usb'))
devices.append(
E.channel(
E.source(mode='bind'),
E.target(type='virtio', name='org.qemu.guest_agent.0'),
E.address(
type='virtio-serial', controller='0', bus='0', port='1'
),
type='unix',
)
)
devices.append(
E.console(E.target(type='serial', port='0'), type='pty')
)
devices.append(
E.video(
E.model(type='vga', vram='16384', heads='1', primary='yes')
)
)
xml.append(devices)
return etree.tostring(xml, encoding='unicode', pretty_print=True)
class InstanceInfo(NamedTuple):
"""
Store compute instance info.
Reference:
https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainInfo
"""
state: str
max_memory: int
memory: int
nproc: int
cputime: int
class Instance:
"""Manage compute instances."""
def __init__(self, domain: libvirt.virDomain):
"""
Initialise Instance.
:ivar libvirt.virDomain domain: domain object
:ivar libvirt.virConnect connection: connection object
:ivar str name: domain name
:ivar GuestAgent guest_agent: :class:`GuestAgent` object
:param domain: libvirt domain object
"""
self.domain = domain
self.connection = domain.connect()
self.name = domain.name()
self.guest_agent = GuestAgent(domain)
def _expand_instance_state(self, state: int) -> str:
states = {
libvirt.VIR_DOMAIN_NOSTATE: 'nostate',
libvirt.VIR_DOMAIN_RUNNING: 'running',
libvirt.VIR_DOMAIN_BLOCKED: 'blocked',
libvirt.VIR_DOMAIN_PAUSED: 'paused',
libvirt.VIR_DOMAIN_SHUTDOWN: 'shutdown',
libvirt.VIR_DOMAIN_SHUTOFF: 'shutoff',
libvirt.VIR_DOMAIN_CRASHED: 'crashed',
libvirt.VIR_DOMAIN_PMSUSPENDED: 'pmsuspended',
}
return states[state]
def get_info(self) -> InstanceInfo:
"""Return instance info."""
info = self.domain.info()
return InstanceInfo(
state=self._expand_instance_state(info[0]),
max_memory=info[1],
memory=info[2],
nproc=info[3],
cputime=info[4],
)
def get_status(self) -> str:
"""
Return instance state: 'running', 'shutoff', etc.
Reference:
https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState
"""
try:
state, _ = self.domain.state()
except libvirt.libvirtError as e:
raise InstanceError(
'Cannot fetch status of ' f'instance={self.name}: {e}'
) from e
return self._expand_instance_state(state)
def is_running(self) -> bool:
"""Return True if instance is running, else return False."""
if self.domain.isActive() != 1:
# 0 - is inactive, -1 - is error
return False
return True
def is_autostart(self) -> bool:
"""Return True if instance autostart is enabled, else return False."""
try:
return bool(self.domain.autostart())
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot get autostart status for '
f'instance={self.name}: {e}'
) from e
def get_max_memory(self) -> int:
"""Maximum memory value for domain in KiB."""
return self.domain.maxMemory()
def get_max_vcpus(self) -> int:
"""Maximum vCPUs number for domain."""
return self.domain.maxVcpus()
def start(self) -> None:
"""Start defined instance."""
log.info('Starting instnce=%s', self.name)
if self.is_running():
log.warning(
'Already started, nothing to do instance=%s', self.name
)
return
try:
self.domain.create()
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot start instance={self.name}: {e}'
) from e
def shutdown(self, method: str | None = None) -> None:
"""
Shutdown instance.
Shutdown methods:
SOFT
Use guest agent to shutdown. If guest agent is unavailable
NORMAL method will be used.
NORMAL
Use method choosen by hypervisor to shutdown. Usually send ACPI
signal to guest OS. OS may ignore ACPI e.g. if guest is hanged.
HARD
Shutdown instance without any guest OS shutdown. This is simular
to unplugging machine from power. Internally send SIGTERM to
instance process and destroy it gracefully.
UNSAFE
Force shutdown. Internally send SIGKILL to instance process.
There is high data corruption risk!
If method is None NORMAL method will used.
:param method: Method used to shutdown instance
"""
methods = {
'SOFT': libvirt.VIR_DOMAIN_SHUTDOWN_GUEST_AGENT,
'NORMAL': libvirt.VIR_DOMAIN_SHUTDOWN_DEFAULT,
'HARD': libvirt.VIR_DOMAIN_DESTROY_GRACEFUL,
'UNSAFE': libvirt.VIR_DOMAIN_DESTROY_DEFAULT,
}
if method is None:
method = 'NORMAL'
if not isinstance(method, str):
raise TypeError(
f"Shutdown method must be a 'str', not {type(method)}"
)
method = method.upper()
if method not in methods:
raise ValueError(f"Unsupported shutdown method: '{method}'")
try:
if method in ['SOFT', 'NORMAL']:
self.domain.shutdownFlags(flags=methods[method])
elif method in ['HARD', 'UNSAFE']:
self.domain.destroyFlags(flags=methods[method])
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot shutdown instance={self.name} ' f'{method=}: {e}'
) from e
def reboot(self) -> None:
"""Send ACPI signal to guest OS to reboot. OS may ignore this."""
try:
self.domain.reboot()
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot reboot instance={self.name}: {e}'
) from e
def reset(self) -> None:
"""
Reset instance.
Copypaste from libvirt doc:
Reset a domain immediately without any guest OS shutdown.
Reset emulates the power reset button on a machine, where all
hardware sees the RST line set and reinitializes internal state.
Note that there is a risk of data loss caused by reset without any
guest OS shutdown.
"""
try:
self.domain.reset()
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot reset instance={self.name}: {e}'
) from e
def power_reset(self) -> None:
"""
Shutdown instance and start.
By analogy with real hardware, this is a normal server shutdown,
and then turning off from the power supply and turning it on again.
This method is applicable in cases where there has been a
configuration change in libvirt and you need to restart the
instance to apply the new configuration.
"""
self.shutdown(method='NORMAL')
self.start()
def set_autostart(self, *, enabled: bool) -> None:
"""
Set autostart flag for instance.
:param enabled: Bool argument to set or unset autostart flag.
"""
autostart = 1 if enabled else 0
try:
self.domain.setAutostart(autostart)
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot set autostart flag for instance={self.name} '
f'{autostart=}: {e}'
) from e
def set_vcpus(self, nvcpus: int, *, live: bool = False) -> None:
"""
Set vCPU number.
If `live` is True and instance is not currently running vCPUs
will set in config and will applied when instance boot.
NB: Note that if this call is executed before the guest has
finished booting, the guest may fail to process the change.
:param nvcpus: Number of vCPUs
:param live: Affect a running instance
"""
if nvcpus <= 0:
raise InstanceError('Cannot set zero vCPUs')
if nvcpus > self.get_max_vcpus():
raise InstanceError('vCPUs count is greather than max_vcpus')
if nvcpus == self.get_info().nproc:
log.warning(
'Instance instance=%s already have %s vCPUs, nothing to do',
self.name,
nvcpus,
)
return
try:
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
self.domain.setVcpusFlags(nvcpus, flags=flags)
if live is True:
if not self.is_running():
log.warning(
'Instance is not running, changes applied in '
'instance config.'
)
return
flags = libvirt.VIR_DOMAIN_AFFECT_LIVE
self.domain.setVcpusFlags(nvcpus, flags=flags)
if self.guest_agent.is_available():
try:
self.guest_agent.raise_for_commands(
['guest-set-vcpus']
)
flags = libvirt.VIR_DOMAIN_VCPU_GUEST
self.domain.setVcpusFlags(nvcpus, flags=flags)
except GuestAgentCommandNotSupportedError:
log.warning(
'Cannot set vCPUs in guest via agent, you may '
'need to apply changes in guest manually.'
)
else:
log.warning(
'Cannot set vCPUs in guest OS on instance=%s. '
'You may need to apply CPUs in guest manually.',
self.name,
)
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot set vCPUs for instance={self.name}: {e}'
) from e
def set_memory(self, memory: int, *, live: bool = False) -> None:
"""
Set memory.
If `live` is True and instance is not currently running set memory
in config and will applied when instance boot.
:param memory: Memory value in mebibytes
:param live: Affect a running instance
"""
if memory <= 0:
raise InstanceError('Cannot set zero memory')
if (memory * 1024) > self.get_max_memory():
raise InstanceError('Memory is greather than max_memory')
if (memory * 1024) == self.get_info().memory:
log.warning(
"Instance '%s' already have %s memory, nothing to do",
self.name,
memory,
)
return
if live and self.is_running():
flags = (
libvirt.VIR_DOMAIN_AFFECT_LIVE
| libvirt.VIR_DOMAIN_AFFECT_CONFIG
)
else:
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
try:
self.domain.setMemoryFlags(memory * 1024, flags=flags)
except libvirt.libvirtError as e:
msg = f'Cannot set memory for instance={self.name} {memory=}: {e}'
raise InstanceError(msg) from e
def _get_disk_by_target(self, target: str) -> etree.Element:
xml = etree.fromstring(self.dump_xml()) # noqa: S320
child = xml.xpath(f'/domain/devices/disk/target[@dev="{target}"]')
return child[0].getparent() if child else None
def attach_device(
self, device: DeviceConfig, *, live: bool = False
) -> None:
"""
Attach device to compute instance.
:param device: Object with device description e.g. DiskConfig
:param live: Affect a running instance
"""
if live and self.is_running():
flags = (
libvirt.VIR_DOMAIN_AFFECT_LIVE
| libvirt.VIR_DOMAIN_AFFECT_CONFIG
)
else:
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
if isinstance(device, DiskConfig): # noqa: SIM102
if self._get_disk_by_target(device.target):
log.warning(
"Volume with target '%s' is already attached",
device.target,
)
return
self.domain.attachDeviceFlags(device.to_xml(), flags=flags)
def detach_device(
self, device: DeviceConfig, *, live: bool = False
) -> None:
"""
Dettach device from compute instance.
:param device: Object with device description e.g. DiskConfig
:param live: Affect a running instance
"""
if live and self.is_running():
flags = (
libvirt.VIR_DOMAIN_AFFECT_LIVE
| libvirt.VIR_DOMAIN_AFFECT_CONFIG
)
else:
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
if isinstance(device, DiskConfig): # noqa: SIM102
if self._get_disk_by_target(device.target) is None:
log.warning(
"Volume with target '%s' is already detached",
device.target,
)
return
self.domain.detachDeviceFlags(device.to_xml(), flags=flags)
def detach_disk(self, name: str) -> None:
"""
Detach disk device by target name.
There is no ``attach_disk()`` method. Use :func:`attach_device`
with :class:`DiskConfig` as argument.
:param name: Disk name e.g. 'vda', 'sda', etc. This name may
not match the name of the disk inside the guest OS.
"""
xml = self._get_disk_by_target(name)
if xml is None:
log.warning(
"Volume with target '%s' is already detached",
name,
)
return
disk_params = {
'disk_type': xml.get('type'),
'source': xml.find('source').get('file'),
'target': xml.find('target').get('dev'),
'readonly': False if xml.find('readonly') is None else True, # noqa: SIM211
}
for param in disk_params:
if disk_params[param] is None:
msg = (
f"Cannot detach volume with target '{name}': "
f"parameter '{param}' is not defined in libvirt XML "
'config on host.'
)
raise InstanceError(msg)
self.detach_device(DiskConfig(**disk_params), live=True)
def resize_disk(
self, name: str, capacity: int, unit: units.DataUnit
) -> None:
"""
Resize attached block device.
:param name: Disk device name e.g. `vda`, `sda`, etc.
:param capacity: New capacity.
:param unit: Capacity unit.
"""
self.domain.blockResize(
name,
units.to_bytes(capacity, unit=unit),
flags=libvirt.VIR_DOMAIN_BLOCK_RESIZE_BYTES,
)
def get_disks(self) -> list[DiskConfig]:
"""Return list of attached disks."""
raise NotImplementedError
def pause(self) -> None:
"""Pause instance."""
if not self.is_running():
raise InstanceError('Cannot pause inactive instance')
self.domain.suspend()
def resume(self) -> None:
"""Resume paused instance."""
self.domain.resume()
def get_ssh_keys(self, user: str) -> list[str]:
"""
Return list of SSH keys on guest for specific user.
:param user: Username.
"""
raise NotImplementedError
def set_ssh_keys(self, user: str, ssh_keys: list[str]) -> None:
"""
Add SSH keys to guest for specific user.
:param user: Username.
:param ssh_keys: List of public SSH keys.
"""
raise NotImplementedError
def delete_ssh_keys(self, user: str, ssh_keys: list[str]) -> None:
"""
Remove SSH keys from guest for specific user.
:param user: Username.
:param ssh_keys: List of public SSH keys.
"""
raise NotImplementedError
def set_user_password(
self, user: str, password: str, *, encrypted: bool = False
) -> None:
"""
Set new user password in guest OS.
This action performs by guest agent inside the guest.
:param user: Username.
:param password: Password.
:param encrypted: Set it to True if password is already encrypted.
Right encryption method depends on guest OS.
"""
if not self.guest_agent.is_available():
raise InstanceError(
'Cannot change password: guest agent is unavailable'
)
self.guest_agent.raise_for_commands(['guest-set-user-password'])
flags = libvirt.VIR_DOMAIN_PASSWORD_ENCRYPTED if encrypted else 0
self.domain.setUserPassword(user, password, flags=flags)
def dump_xml(self, *, inactive: bool = False) -> str:
"""Return instance XML description."""
flags = libvirt.VIR_DOMAIN_XML_INACTIVE if inactive else 0
return self.domain.XMLDesc(flags)
def delete(self) -> None:
"""Undefine instance."""
# TODO @ge: delete local disks
self.shutdown(method='HARD')
self.domain.undefine()

View File

@ -1,165 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Compute instance related objects schemas."""
import re
from enum import StrEnum
from pathlib import Path
from pydantic import BaseModel, Extra, validator
from compute.utils.units import DataUnit
class EntityModel(BaseModel):
"""Basic entity model."""
class Config:
"""Do not allow extra fields."""
extra = Extra.forbid
class CPUEmulationMode(StrEnum):
"""CPU emulation mode enumerated."""
HOST_PASSTHROUGH = 'host-passthrough'
HOST_MODEL = 'host-model'
CUSTOM = 'custom'
MAXIMUM = 'maximum'
class CPUTopologySchema(EntityModel):
"""CPU topology model."""
sockets: int
cores: int
threads: int
dies: int = 1
class CPUFeaturesSchema(EntityModel):
"""CPU features model."""
require: list[str]
disable: list[str]
class CPUSchema(EntityModel):
"""CPU model."""
emulation_mode: CPUEmulationMode
model: str | None
vendor: str | None
topology: CPUTopologySchema | None
features: CPUFeaturesSchema | None
class VolumeType(StrEnum):
"""Storage volume types enumeration."""
FILE = 'file'
class VolumeCapacitySchema(EntityModel):
"""Storage volume capacity field model."""
value: int
unit: DataUnit
class VolumeSchema(EntityModel):
"""Storage volume model."""
type: VolumeType # noqa: A003
target: str
capacity: VolumeCapacitySchema
source: str | None = None
is_readonly: bool = False
is_system: bool = False
class NetworkInterfaceSchema(EntityModel):
"""Network inerface model."""
source: str
mac: str
class BootOptionsSchema(EntityModel):
"""Instance boot settings."""
order: tuple
class InstanceSchema(EntityModel):
"""Compute instance model."""
name: str
title: str | None
description: str | None
memory: int
max_memory: int
vcpus: int
max_vcpus: int
cpu: CPUSchema
machine: str
emulator: Path
arch: str
boot: BootOptionsSchema
volumes: list[VolumeSchema]
network_interfaces: list[NetworkInterfaceSchema]
image: str | None = None
@validator('name')
def _check_name(cls, value: str) -> str: # noqa: N805
if not re.match(r'^[a-z0-9_]+$', value):
msg = (
'Name can contain only lowercase letters, numbers '
'and underscore.'
)
raise ValueError(msg)
return value
@validator('cpu')
def _check_topology(cls, cpu: int, values: dict) -> CPUSchema: # noqa: N805
topo = cpu.topology
max_vcpus = values['max_vcpus']
if topo and topo.sockets * topo.cores * topo.threads != max_vcpus:
msg = f'CPU topology does not match with {max_vcpus=}'
raise ValueError(msg)
return cpu
@validator('volumes')
def _check_volumes(cls, volumes: list) -> list: # noqa: N805
if len([v for v in volumes if v.is_system is True]) != 1:
msg = 'volumes list must contain one system volume'
raise ValueError(msg)
vol_with_source = 0
for vol in volumes:
if vol.is_system is True and vol.is_readonly is True:
msg = 'volume marked as system cannot be readonly'
raise ValueError(msg)
if vol.source is not None:
vol_with_source += 1
return volumes
@validator('network_interfaces')
def _check_network_interfaces(cls, value: list) -> list: # noqa: N805
if not value:
msg = 'Network interfaces list must contain at least one element'
raise ValueError(msg)
return value

View File

@ -1,286 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Hypervisor session manager."""
import logging
import os
from contextlib import AbstractContextManager
from types import TracebackType
from typing import Any, NamedTuple
from uuid import uuid4
import libvirt
from lxml import etree
from .exceptions import (
InstanceNotFoundError,
SessionError,
StoragePoolNotFoundError,
)
from .instance import Instance, InstanceConfig, InstanceSchema
from .storage import DiskConfig, StoragePool, VolumeConfig
from .utils import units
log = logging.getLogger(__name__)
class Capabilities(NamedTuple):
"""Store domain capabilities info."""
arch: str
virt_type: str
emulator: str
machine: str
max_vcpus: int
cpu_vendor: str
cpu_model: str
cpu_features: dict
usable_cpus: list[dict]
class NodeInfo(NamedTuple):
"""
Store compute node info.
See https://libvirt.org/html/libvirt-libvirt-host.html#virNodeInfo
NOTE: memory unit in libvirt docs is wrong! Actual unit is MiB.
"""
arch: str
memory: int
cpus: int
mhz: int
nodes: int
sockets: int
cores: int
threads: int
class Session(AbstractContextManager):
"""
Hypervisor session context manager.
:cvar IMAGES_POOL: images storage pool name taken from env
:cvar VOLUMES_POOL: volumes storage pool name taken from env
"""
IMAGES_POOL = os.getenv('CMP_IMAGES_POOL')
VOLUMES_POOL = os.getenv('CMP_VOLUMES_POOL')
def __init__(self, uri: str | None = None):
"""
Initialise session with hypervisor.
:ivar str uri: libvirt connection URI.
:ivar libvirt.virConnect connection: libvirt connection object.
:param uri: libvirt connection URI.
"""
self.uri = uri or 'qemu:///system'
self.connection = libvirt.open(self.uri)
def __enter__(self):
"""Return Session object."""
return self
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_value: BaseException | None,
exc_traceback: TracebackType | None,
):
"""Close the connection when leaving the context."""
self.close()
def close(self) -> None:
"""Close connection to libvirt daemon."""
self.connection.close()
def get_node_info(self) -> NodeInfo:
"""Return information about compute node."""
info = self.connection.getInfo()
return NodeInfo(
arch=info[0],
memory=info[1],
cpus=info[2],
mhz=info[3],
nodes=info[4],
sockets=info[5],
cores=info[6],
threads=info[7],
)
def _cap_get_usable_cpus(self, xml: etree.Element) -> list[dict]:
x = xml.xpath('/domainCapabilities/cpu/mode[@name="custom"]')[0]
cpus = []
for cpu in x.findall('model'):
if cpu.get('usable') == 'yes':
cpus.append( # noqa: PERF401
{
'vendor': cpu.get('vendor'),
'model': cpu.text,
}
)
return cpus
def _cap_get_cpu_features(self, xml: etree.Element) -> dict:
x = xml.xpath('/domainCapabilities/cpu/mode[@name="host-model"]')[0]
require = []
disable = []
for feature in x.findall('feature'):
policy = feature.get('policy')
name = feature.get('name')
if policy == 'require':
require.append(name)
if policy == 'disable':
disable.append(name)
return {'require': require, 'disable': disable}
def get_capabilities(self) -> Capabilities:
"""Return capabilities e.g. arch, virt, emulator, etc."""
prefix = '/domainCapabilities'
hprefix = f'{prefix}/cpu/mode[@name="host-model"]'
caps = etree.fromstring(self.connection.getDomainCapabilities()) # noqa: S320
return Capabilities(
arch=caps.xpath(f'{prefix}/arch/text()')[0],
virt_type=caps.xpath(f'{prefix}/domain/text()')[0],
emulator=caps.xpath(f'{prefix}/path/text()')[0],
machine=caps.xpath(f'{prefix}/machine/text()')[0],
max_vcpus=int(caps.xpath(f'{prefix}/vcpu/@max')[0]),
cpu_vendor=caps.xpath(f'{hprefix}/vendor/text()')[0],
cpu_model=caps.xpath(f'{hprefix}/model/text()')[0],
cpu_features=self._cap_get_cpu_features(caps),
usable_cpus=self._cap_get_cpus(caps),
)
def create_instance(self, **kwargs: Any) -> Instance:
"""
Create and return new compute instance.
:param name: Instance name.
:type name: str
:param title: Instance title for humans.
:type title: str
:param description: Some information about instance.
:type description: str
:param memory: Memory in MiB.
:type memory: int
:param max_memory: Maximum memory in MiB.
:type max_memory: int
:param vcpus: Number of vCPUs.
:type vcpus: int
:param max_vcpus: Maximum vCPUs.
:type max_vcpus: int
:param cpu: CPU configuration. See :class:`CPUSchema` for info.
:type cpu: dict
:param machine: QEMU emulated machine.
:type machine: str
:param emulator: Path to emulator.
:type emulator: str
:param arch: CPU architecture to virtualization.
:type arch: str
:param boot: Boot settings. See :class:`BootOptionsSchema`.
:type boot: dict
:param image: Source disk image name for system disk.
:type image: str
:param volumes: List of storage volume configs. For more info
see :class:`VolumeSchema`.
:type volumes: list[dict]
:param network_interfaces: List of virtual network interfaces
configs. See :class:`NetworkInterfaceSchema` for more info.
:type network_interfaces: list[dict]
"""
data = InstanceSchema(**kwargs)
config = InstanceConfig(data)
log.info('Define XML...')
log.info(config.to_xml())
self.connection.defineXML(config.to_xml())
log.info('Getting instance...')
instance = self.get_instance(config.name)
log.info('Creating volumes...')
for volume in data.volumes:
log.info('Creating volume=%s', volume)
capacity = units.to_bytes(
volume.capacity.value, volume.capacity.unit
)
log.info('Connecting to images pool...')
images_pool = self.get_storage_pool(self.IMAGES_POOL)
log.info('Connecting to volumes pool...')
volumes_pool = self.get_storage_pool(self.VOLUMES_POOL)
log.info('Building volume configuration...')
if not volume.source:
vol_name = f'{uuid4()}.qcow2'
else:
vol_name = volume.source
vol_conf = VolumeConfig(
name=vol_name,
path=str(volumes_pool.path.joinpath(vol_name)),
capacity=capacity,
)
log.info('Volume configuration is:\n %s', vol_conf.to_xml())
if volume.is_system is True and data.image:
log.info(
"Volume is marked as 'system', start cloning image..."
)
log.info('Get image %s', data.image)
image = images_pool.get_volume(data.image)
log.info('Cloning image into volumes pool...')
vol = volumes_pool.clone_volume(image, vol_conf)
log.info(
'Resize cloned volume to specified size: %s',
capacity,
)
vol.resize(capacity, unit=units.DataUnit.BYTES)
else:
log.info('Create volume...')
volumes_pool.create_volume(vol_conf)
log.info('Attaching volume to instance...')
instance.attach_device(
DiskConfig(
disk_type=volume.type,
source=vol_conf.path,
target=volume.target,
readonly=volume.is_readonly,
)
)
return instance
def get_instance(self, name: str) -> Instance:
"""Get compute instance by name."""
try:
return Instance(self.connection.lookupByName(name))
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
raise InstanceNotFoundError(name) from e
raise SessionError(e) from e
def list_instances(self) -> list[Instance]:
"""List all instances."""
return [Instance(dom) for dom in self.connection.listAllDomains()]
def get_storage_pool(self, name: str) -> StoragePool:
"""Get storage pool by name."""
try:
return StoragePool(self.connection.storagePoolLookupByName(name))
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL:
raise StoragePoolNotFoundError(name) from e
raise SessionError(e) from e
def list_storage_pools(self) -> list[StoragePool]:
"""List all strage pools."""
return [StoragePool(p) for p in self.connection.listStoragePools()]

View File

@ -1,17 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from .pool import StoragePool
from .volume import DiskConfig, Volume, VolumeConfig

View File

@ -1,124 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Manage storage pools."""
import logging
from pathlib import Path
from typing import NamedTuple
import libvirt
from lxml import etree
from compute.exceptions import StoragePoolError, VolumeNotFoundError
from .volume import Volume, VolumeConfig
log = logging.getLogger(__name__)
class StoragePoolUsageInfo(NamedTuple):
"""Storage pool usage info."""
capacity: int
allocation: int
available: int
class StoragePool:
"""Storage pool manipulating class."""
def __init__(self, pool: libvirt.virStoragePool):
"""Initislise StoragePool."""
self.pool = pool
self.name = pool.name()
self.path = self._get_path()
def _get_path(self) -> Path:
"""Return storage pool path."""
xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320
return Path(xml.xpath('/pool/target/path/text()')[0])
def get_usage_info(self) -> StoragePoolUsageInfo:
"""Return info about storage pool usage."""
xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320
return StoragePoolUsageInfo(
capacity=int(xml.xpath('/pool/capacity/text()')[0]),
allocation=int(xml.xpath('/pool/allocation/text()')[0]),
available=int(xml.xpath('/pool/available/text()')[0]),
)
def dump_xml(self) -> str:
"""Return storage pool XML description as string."""
return self.pool.XMLDesc()
def refresh(self) -> None:
"""Refresh storage pool."""
# TODO @ge: handle libvirt asynchronous job related exceptions
self.pool.refresh()
def create_volume(self, vol_conf: VolumeConfig) -> Volume:
"""Create storage volume and return Volume instance."""
log.info(
'Create storage volume vol=%s in pool=%s', vol_conf.name, self.name
)
vol = self.pool.createXML(
vol_conf.to_xml(),
flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA,
)
return Volume(self.pool, vol)
def clone_volume(self, src: Volume, dst: VolumeConfig) -> Volume:
"""
Make storage volume copy.
:param src: Input volume
:param dst: Output volume config
"""
log.info(
'Start volume cloning '
'src_pool=%s src_vol=%s dst_pool=%s dst_vol=%s',
src.pool_name,
src.name,
self.pool.name,
dst.name,
)
vol = self.pool.createXMLFrom(
dst.to_xml(), # new volume XML description
src.vol, # source volume virStorageVol object
flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA,
)
if vol is None:
raise StoragePoolError
return Volume(self.pool, vol)
def get_volume(self, name: str) -> Volume | None:
"""Lookup and return Volume instance or None."""
log.info(
'Lookup for storage volume vol=%s in pool=%s', name, self.pool.name
)
try:
vol = self.pool.storageVolLookupByName(name)
return Volume(self.pool, vol)
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL:
raise VolumeNotFoundError(name) from e
log.exception('unexpected error from libvirt')
raise StoragePoolError(e) from e
def list_volumes(self) -> list[Volume]:
"""Return list of volumes in storage pool."""
return [Volume(self.pool, vol) for vol in self.pool.listAllVolumes()]

View File

@ -1,138 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Manage storage volumes."""
from dataclasses import dataclass
from pathlib import Path
from time import time
import libvirt
from lxml import etree
from lxml.builder import E
from compute.common import DeviceConfig, EntityConfig
from compute.utils import units
@dataclass
class VolumeConfig(EntityConfig):
"""
Storage volume XML config builder.
Generate XML config for creating a volume in a libvirt
storage pool.
"""
name: str
path: str
capacity: int
def to_xml(self) -> str:
"""Return XML config for libvirt."""
unixtime = str(int(time()))
xml = E.volume(type='file')
xml.append(E.name(self.name))
xml.append(E.key(self.path))
xml.append(E.source())
xml.append(E.capacity(str(self.capacity), unit='bytes'))
xml.append(E.allocation('0'))
xml.append(
E.target(
E.path(self.path),
E.format(type='qcow2'),
E.timestamps(
E.atime(unixtime), E.mtime(unixtime), E.ctime(unixtime)
),
E.compat('1.1'),
E.features(E.lazy_refcounts()),
)
)
return etree.tostring(xml, encoding='unicode', pretty_print=True)
@dataclass
class DiskConfig(DeviceConfig):
"""
Disk XML config builder.
Generate XML config for attaching or detaching storage volumes
to compute instances.
"""
disk_type: str
source: str | Path
target: str
readonly: bool = False
def to_xml(self) -> str:
"""Return XML config for libvirt."""
xml = E.disk(type=self.disk_type, device='disk')
xml.append(E.driver(name='qemu', type='qcow2', cache='writethrough'))
if self.disk_type == 'file':
xml.append(E.source(file=str(self.source)))
xml.append(E.target(dev=self.target, bus='virtio'))
if self.readonly:
xml.append(E.readonly())
return etree.tostring(xml, encoding='unicode', pretty_print=True)
class Volume:
"""Storage volume manipulating class."""
def __init__(
self, pool: libvirt.virStoragePool, vol: libvirt.virStorageVol
):
"""
Initialise Volume.
:param pool: libvirt virStoragePool object
:param vol: libvirt virStorageVol object
"""
self.pool = pool
self.pool_name = pool.name()
self.vol = vol
self.name = vol.name()
self.path = Path(vol.path())
def dump_xml(self) -> str:
"""Return volume XML description as string."""
return self.vol.XMLDesc()
def clone(self, vol_conf: VolumeConfig) -> None:
"""
Make a copy of volume to the same storage pool.
:param vol_info VolumeInfo: New storage volume dataclass object
"""
self.pool.createXMLFrom(
vol_conf.to_xml(),
self.vol,
flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA,
)
def resize(self, capacity: int, unit: units.DataUnit) -> None:
"""
Resize volume.
:param capacity int: Volume new capacity.
:param unit DataUnit: Data unit. Internally converts into bytes.
"""
# TODO @ge: Check actual volume size before resize
self.vol.resize(units.to_bytes(capacity, unit=unit))
def delete(self) -> None:
"""Delete volume from storage pool."""
self.vol.delete()

View File

@ -1,56 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Configuration loader."""
import tomllib
from collections import UserDict
from pathlib import Path
from compute.exceptions import ConfigLoaderError
DEFAULT_CONFIGURATION = {}
DEFAULT_CONFIG_FILE = '/etc/computed/computed.toml'
class ConfigLoader(UserDict):
"""UserDict for storing configuration."""
def __init__(self, file: Path | None = None):
"""
Initialise ConfigLoader.
:param file: Path to configuration file. If `file` is None
use default path from DEFAULT_CONFIG_FILE constant.
"""
# TODO @ge: load deafult configuration
self.file = Path(file) if file else Path(DEFAULT_CONFIG_FILE)
super().__init__(self.load())
def load(self) -> dict:
"""Load confguration object from TOML file."""
try:
with Path(self.file).open('rb') as configfile:
return tomllib.load(configfile)
# TODO @ge: add config schema validation
except tomllib.TOMLDecodeError as tomlerr:
raise ConfigLoaderError(
f'Bad TOML syntax in config file: {self.file}: {tomlerr}'
) from tomlerr
except (OSError, ValueError) as readerr:
raise ConfigLoaderError(
f'Cannot read config file: {self.file}: {readerr}'
) from readerr

View File

@ -1,33 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Random identificators."""
# ruff: noqa: S311, C417
import random
def random_mac() -> str:
"""Retrun random MAC address."""
mac = [
0x00,
0x16,
0x3E,
random.randint(0x00, 0x7F),
random.randint(0x00, 0xFF),
random.randint(0x00, 0xFF),
]
return ':'.join(map(lambda x: '%02x' % x, mac))

View File

@ -1,54 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Tools for data units convertion."""
from enum import StrEnum
class DataUnit(StrEnum):
"""Data units enumerated."""
BYTES = 'bytes'
KIB = 'KiB'
MIB = 'MiB'
GIB = 'GiB'
TIB = 'TiB'
class InvalidDataUnitError(ValueError):
"""Data unit is not valid."""
def __init__(self, msg: str):
"""Initialise InvalidDataUnitError."""
super().__init__(
f'{msg}, valid units are: {", ".join(list(DataUnit))}'
)
def to_bytes(value: int, unit: DataUnit = DataUnit.BYTES) -> int:
"""Convert value to bytes. See :class:`DataUnit`."""
try:
_ = DataUnit(unit)
except ValueError as e:
raise InvalidDataUnitError(e) from e
powers = {
DataUnit.BYTES: 0,
DataUnit.KIB: 1,
DataUnit.MIB: 2,
DataUnit.GIB: 3,
DataUnit.TIB: 4,
}
return value * pow(1024, powers[unit])

View File

@ -1,8 +0,0 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from compute.cli.control import cli
if __name__ == "__main__":
sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0])
sys.exit(cli())

View File

@ -1,81 +0,0 @@
Metadata-Version: 2.1
Name: compute
Version: 0.1.0.dev1
Summary: Compute instances management library and tools
Author: ge
Author-email: ge@nixhacks.net
Requires-Python: >=3.11,<4.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Requires-Dist: libvirt-python (==9.0.0)
Requires-Dist: lxml (>=4.9.2,<5.0.0)
Requires-Dist: pydantic (==1.10.4)
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
Description-Content-Type: text/markdown
# Compute
Compute instances management library and tools.
## Docs
Run `make serve-docs`. See [Development](#development) below.
## Roadmap
- [x] Create instances
- [ ] CDROM
- [ ] cloud-init for provisioning instances
- [x] Instance power management
- [x] Instance pause and resume
- [x] vCPU hotplug
- [x] Memory hotplug
- [x] Hot disk resize [not tested]
- [ ] CPU topology customization
- [x] CPU customization (emulation mode, model, vendor, features)
- [ ] BIOS/UEFI settings
- [x] Device attaching
- [x] Device detaching
- [ ] GPU passthrough
- [ ] CPU guarantied resource percent support
- [x] QEMU Guest Agent management
- [ ] Instance resources usage stats
- [ ] SSH-keys management
- [x] Setting user passwords in guest
- [x] QCOW2 disks support
- [ ] ZVOL support
- [ ] Network disks support
- [ ] Images service integration (Images service is not implemented yet)
- [ ] Manage storage pools
- [ ] Idempotency
- [ ] CLI [in progress]
- [ ] HTTP API
- [ ] Instance migrations
- [ ] Instance snapshots
- [ ] Instance backups
- [ ] LXC
## Development
Python 3.11+ is required.
Install [poetry](https://python-poetry.org/), clone this repository and run:
```
poetry install --with dev --with docs
```
# Build Debian package
Install Docker first, then run:
```
make build-deb
```
`compute` and `compute-doc` packages will built. See packaging/build directory. Packages can be installed via `dpkg` or `apt-get`:
```
apt-get install ./compute*.deb
```

View File

@ -1,65 +0,0 @@
# Compute
Compute instances management library and tools.
## Docs
Run `make serve-docs`. See [Development](#development) below.
## Roadmap
- [x] Create instances
- [ ] CDROM
- [ ] cloud-init for provisioning instances
- [x] Instance power management
- [x] Instance pause and resume
- [x] vCPU hotplug
- [x] Memory hotplug
- [x] Hot disk resize [not tested]
- [ ] CPU topology customization
- [x] CPU customization (emulation mode, model, vendor, features)
- [ ] BIOS/UEFI settings
- [x] Device attaching
- [x] Device detaching
- [ ] GPU passthrough
- [ ] CPU guarantied resource percent support
- [x] QEMU Guest Agent management
- [ ] Instance resources usage stats
- [ ] SSH-keys management
- [x] Setting user passwords in guest
- [x] QCOW2 disks support
- [ ] ZVOL support
- [ ] Network disks support
- [ ] Images service integration (Images service is not implemented yet)
- [ ] Manage storage pools
- [ ] Idempotency
- [ ] CLI [in progress]
- [ ] HTTP API
- [ ] Instance migrations
- [ ] Instance snapshots
- [ ] Instance backups
- [ ] LXC
## Development
Python 3.11+ is required.
Install [poetry](https://python-poetry.org/), clone this repository and run:
```
poetry install --with dev --with docs
```
# Build Debian package
Install Docker first, then run:
```
make build-deb
```
`compute` and `compute-doc` packages will built. See packaging/build directory. Packages can be installed via `dpkg` or `apt-get`:
```
apt-get install ./compute*.deb
```

View File

@ -1,22 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Compute instances management library."""
__version__ = '0.1.0-dev1'
from .instance import Instance, InstanceConfig, InstanceSchema
from .session import Session
from .storage import StoragePool, Volume, VolumeConfig

View File

@ -1,21 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Command line interface for compute module."""
from compute.cli import main
main.cli()

View File

@ -1,501 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Command line interface."""
import argparse
import io
import logging
import os
import shlex
import sys
from collections import UserDict
from typing import Any
from uuid import uuid4
import libvirt
import yaml
from pydantic import ValidationError
from compute import __version__
from compute.exceptions import ComputeError, GuestAgentTimeoutExceededError
from compute.instance import GuestAgent
from compute.session import Session
from compute.utils import ids
log = logging.getLogger(__name__)
log_levels = [lv.lower() for lv in logging.getLevelNamesMapping()]
libvirt.registerErrorHandler(
lambda userdata, err: None, # noqa: ARG005
ctx=None,
)
class Table:
"""Minimalistic text table constructor."""
def __init__(self, whitespace: str | None = None):
"""Initialise Table."""
self.whitespace = whitespace or '\t'
self.header = []
self.rows = []
self.table = ''
def add_row(self, row: list) -> None:
"""Add table row."""
self.rows.append([str(col) for col in row])
def add_rows(self, rows: list[list]) -> None:
"""Add multiple rows."""
for row in rows:
self.add_row(row)
def __str__(self) -> str:
"""Build table and return."""
widths = [max(map(len, col)) for col in zip(*self.rows, strict=True)]
self.rows.insert(0, [str(h).upper() for h in self.header])
for row in self.rows:
self.table += self.whitespace.join(
(
val.ljust(width)
for val, width in zip(row, widths, strict=True)
)
)
self.table += '\n'
return self.table.strip()
def _list_instances(session: Session) -> None:
table = Table()
table.header = ['NAME', 'STATE']
for instance in session.list_instances():
table.add_row(
[
instance.name,
instance.get_status(),
]
)
print(table)
sys.exit()
def _exec_guest_agent_command(
session: Session, args: argparse.Namespace
) -> None:
instance = session.get_instance(args.instance)
ga = GuestAgent(instance.domain, timeout=args.timeout)
arguments = args.arguments.copy()
if len(arguments) > 1 and not args.no_join_args:
arguments = [shlex.join(arguments)]
if not args.no_join_args:
arguments.insert(0, '-c')
stdin = None
if not sys.stdin.isatty():
stdin = sys.stdin.read()
try:
output = ga.guest_exec(
path=args.executable,
args=arguments,
env=args.env,
stdin=stdin,
capture_output=True,
decode_output=True,
poll=True,
)
except GuestAgentTimeoutExceededError as e:
sys.exit(
f'{e}. NOTE: command may still running in guest, '
f'PID={ga.last_pid}'
)
if output.stderr:
print(output.stderr.strip(), file=sys.stderr)
if output.stdout:
print(output.stdout.strip(), file=sys.stdout)
sys.exit(output.exitcode)
class _NotPresent:
"""
Type for representing non-existent dictionary keys.
See :class:`_FillableDict`.
"""
class _FillableDict(UserDict):
"""Use :method:`fill` to add key if not present."""
def __init__(self, data: dict):
self.data = data
def fill(self, key: str, value: Any) -> None: # noqa: ANN401
if self.data.get(key, _NotPresent) is _NotPresent:
self.data[key] = value
def _merge_dicts(a: dict, b: dict, path: list[str] | None = None) -> dict:
"""Merge `b` into `a`. Return modified `a`."""
if path is None:
path = []
for key in b:
if key in a:
if isinstance(a[key], dict) and isinstance(b[key], dict):
_merge_dicts(a[key], b[key], [path + str(key)])
elif a[key] == b[key]:
pass # same leaf value
else:
a[key] = b[key] # replace existing key's values
else:
a[key] = b[key]
return a
def _create_instance(session: Session, file: io.TextIOWrapper) -> None:
try:
data = _FillableDict(yaml.load(file.read(), Loader=yaml.SafeLoader))
log.debug('Read from file: %s', data)
except yaml.YAMLError as e:
sys.exit(f'error: cannot parse YAML: {e}')
capabilities = session.get_capabilities()
node_info = session.get_node_info()
data.fill('name', uuid4().hex)
data.fill('title', None)
data.fill('description', None)
data.fill('arch', capabilities.arch)
data.fill('machine', capabilities.machine)
data.fill('emulator', capabilities.emulator)
data.fill('max_vcpus', node_info.cpus)
data.fill('max_memory', node_info.memory)
data.fill('cpu', {})
cpu = {
'emulation_mode': 'host-passthrough',
'model': None,
'vendor': None,
'topology': None,
'features': None,
}
data['cpu'] = _merge_dicts(data['cpu'], cpu)
data.fill(
'network_interfaces',
[{'source': 'default', 'mac': ids.random_mac()}],
)
data.fill('boot', {'order': ['cdrom', 'hd']})
try:
log.debug('Input data: %s', data)
session.create_instance(**data)
except ValidationError as e:
for error in e.errors():
fields = '.'.join([str(lc) for lc in error['loc']])
print(
f"validation error: {fields}: {error['msg']}",
file=sys.stderr,
)
sys.exit()
def _shutdown_instance(session: Session, args: argparse.Namespace) -> None:
instance = session.get_instance(args.instance)
if args.soft:
method = 'SOFT'
elif args.hard:
method = 'HARD'
elif args.unsafe:
method = 'UNSAFE'
else:
method = 'NORMAL'
instance.shutdown(method)
def main(session: Session, args: argparse.Namespace) -> None:
"""Perform actions."""
match args.command:
case 'init':
_create_instance(session, args.file)
case 'exec':
_exec_guest_agent_command(session, args)
case 'ls':
_list_instances(session)
case 'start':
instance = session.get_instance(args.instance)
instance.start()
case 'shutdown':
_shutdown_instance(session, args)
case 'reboot':
instance = session.get_instance(args.instance)
instance.reboot()
case 'reset':
instance = session.get_instance(args.instance)
instance.reset()
case 'powrst':
instance = session.get_instance(args.instance)
instance.power_reset()
case 'pause':
instance = session.get_instance(args.instance)
instance.pause()
case 'resume':
instance = session.get_instance(args.instance)
instance.resume()
case 'status':
instance = session.get_instance(args.instance)
print(instance.status)
case 'setvcpus':
instance = session.get_instance(args.instance)
instance.set_vcpus(args.nvcpus, live=True)
case 'setmem':
instance = session.get_instance(args.instance)
instance.set_memory(args.memory, live=True)
case 'setpass':
instance = session.get_instance(args.instance)
instance.set_user_password(
args.username,
args.password,
encrypted=args.encrypted,
)
def cli() -> None: # noqa: PLR0915
"""Return command line arguments parser."""
root = argparse.ArgumentParser(
prog='compute',
description='manage compute instances',
formatter_class=argparse.RawTextHelpFormatter,
)
root.add_argument(
'-v',
'--verbose',
action='store_true',
default=False,
help='enable verbose mode',
)
root.add_argument(
'-c',
'--connect',
metavar='URI',
help='libvirt connection URI',
)
root.add_argument(
'-l',
'--log-level',
type=str.lower,
metavar='LEVEL',
choices=log_levels,
help='log level',
)
root.add_argument(
'-V',
'--version',
action='version',
version=__version__,
)
subparsers = root.add_subparsers(dest='command', metavar='COMMAND')
# init command
init = subparsers.add_parser(
'init', help='initialise instance using YAML config file'
)
init.add_argument(
'file',
type=argparse.FileType('r', encoding='UTF-8'),
nargs='?',
default='instance.yaml',
help='instance config [default: instance.yaml]',
)
# exec subcommand
execute = subparsers.add_parser(
'exec',
help='execute command in guest via guest agent',
description=(
'NOTE: any argument after instance name will be passed into '
'guest as shell command.'
),
)
execute.add_argument('instance')
execute.add_argument('arguments', nargs=argparse.REMAINDER)
execute.add_argument(
'-t',
'--timeout',
type=int,
default=60,
help=(
'waiting time in seconds for a command to be executed '
'in guest [default: 60]'
),
)
execute.add_argument(
'-x',
'--executable',
default='/bin/sh',
help='path to executable in guest [default: /bin/sh]',
)
execute.add_argument(
'-e',
'--env',
type=str,
nargs='?',
action='append',
help='environment variables to pass to executable in guest',
)
execute.add_argument(
'-n',
'--no-join-args',
action='store_true',
default=False,
help=(
"do not join arguments list and add '-c' option, suitable "
'for non-shell executables and other specific cases.'
),
)
# ls subcommand
listall = subparsers.add_parser('ls', help='list instances')
listall.add_argument(
'-a',
'--all',
action='store_true',
default=False,
help='list all instances including inactive',
)
# start subcommand
start = subparsers.add_parser('start', help='start instance')
start.add_argument('instance')
# shutdown subcommand
shutdown = subparsers.add_parser('shutdown', help='shutdown instance')
shutdown.add_argument('instance')
shutdown_opts = shutdown.add_mutually_exclusive_group()
shutdown_opts.add_argument(
'-s',
'--soft',
action='store_true',
help='normal guest OS shutdown, guest agent is used',
)
shutdown_opts.add_argument(
'-n',
'--normal',
action='store_true',
help='shutdown with hypervisor selected method [default]',
)
shutdown_opts.add_argument(
'-H',
'--hard',
action='store_true',
help=(
"gracefully destroy instance, it's like long "
'pressing the power button'
),
)
shutdown_opts.add_argument(
'-u',
'--unsafe',
action='store_true',
help=(
'destroy instance, this is similar to a power outage '
'and may result in data loss or corruption'
),
)
# reboot subcommand
reboot = subparsers.add_parser('reboot', help='reboot instance')
reboot.add_argument('instance')
# reset subcommand
reset = subparsers.add_parser('reset', help='reset instance')
reset.add_argument('instance')
# powrst subcommand
powrst = subparsers.add_parser('powrst', help='power reset instance')
powrst.add_argument('instance')
# pause subcommand
pause = subparsers.add_parser('pause', help='pause instance')
pause.add_argument('instance')
# resume subcommand
resume = subparsers.add_parser('resume', help='resume paused instance')
resume.add_argument('instance')
# status subcommand
status = subparsers.add_parser('status', help='display instance status')
status.add_argument('instance')
# setvcpus subcommand
setvcpus = subparsers.add_parser('setvcpus', help='set vCPU number')
setvcpus.add_argument('instance')
setvcpus.add_argument('nvcpus', type=int)
# setmem subcommand
setmem = subparsers.add_parser('setmem', help='set memory size')
setmem.add_argument('instance')
setmem.add_argument('memory', type=int, help='memory in MiB')
# setpass subcommand
setpass = subparsers.add_parser(
'setpass',
help='set user password in guest',
)
setpass.add_argument('instance')
setpass.add_argument('username')
setpass.add_argument('password')
setpass.add_argument(
'-e',
'--encrypted',
action='store_true',
default=False,
help='set it if password is already encrypted',
)
args = root.parse_args()
if args.command is None:
root.print_help()
sys.exit()
log_level = args.log_level or os.getenv('CMP_LOG')
if isinstance(log_level, str) and log_level.lower() in log_levels:
logging.basicConfig(
level=logging.getLevelNamesMapping()[log_level.upper()]
)
log.debug('CLI started with args: %s', args)
connect_uri = (
args.connect
or os.getenv('CMP_LIBVIRT_URI')
or os.getenv('LIBVIRT_DEFAULT_URI')
or 'qemu:///system'
)
try:
with Session(connect_uri) as session:
main(session, args)
except ComputeError as e:
sys.exit(f'error: {e}')
except KeyboardInterrupt:
sys.exit()
except SystemExit as e:
sys.exit(e)
except Exception as e: # noqa: BLE001
sys.exit(f'unexpected error {type(e)}: {e}')
if __name__ == '__main__':
cli()

View File

@ -1,30 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Common symbols."""
from abc import ABC, abstractmethod
class EntityConfig(ABC):
"""An abstract entity XML config builder class."""
@abstractmethod
def to_xml(self) -> str:
"""Return device XML config."""
raise NotImplementedError
DeviceConfig = EntityConfig

View File

@ -1,80 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Exceptions."""
class ComputeError(Exception):
"""Basic exception class."""
class ConfigLoaderError(ComputeError):
"""Something went wrong when loading configuration."""
class SessionError(ComputeError):
"""Something went wrong while connecting to libvirtd."""
class GuestAgentError(ComputeError):
"""Something went wring when QEMU Guest Agent call."""
class GuestAgentUnavailableError(GuestAgentError):
"""Guest agent is not connected or is unavailable."""
class GuestAgentTimeoutExceededError(GuestAgentError):
"""QEMU timeout exceeded."""
def __init__(self, msg: int):
"""Initialise GuestAgentTimeoutExceededError."""
super().__init__(f'QEMU timeout ({msg} sec) exceeded')
class GuestAgentCommandNotSupportedError(GuestAgentError):
"""Guest agent command is not supported or blacklisted on guest."""
class StoragePoolError(ComputeError):
"""Something went wrong when operating with storage pool."""
class StoragePoolNotFoundError(StoragePoolError):
"""Storage pool not found."""
def __init__(self, msg: str):
"""Initialise StoragePoolNotFoundError."""
super().__init__(f"storage pool named '{msg}' not found")
class VolumeNotFoundError(StoragePoolError):
"""Storage volume not found."""
def __init__(self, msg: str):
"""Initialise VolumeNotFoundError."""
super().__init__(f"storage volume '{msg}' not found")
class InstanceError(ComputeError):
"""Something went wrong while interacting with the domain."""
class InstanceNotFoundError(InstanceError):
"""Virtual machine or container not found on compute node."""
def __init__(self, msg: str):
"""Initialise InstanceNotFoundError."""
super().__init__(f"compute instance '{msg}' not found")

View File

@ -1,18 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from .guest_agent import GuestAgent
from .instance import Instance, InstanceConfig
from .schemas import InstanceSchema

View File

@ -1,208 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Interacting with the QEMU Guest Agent."""
import json
import logging
from base64 import b64decode, standard_b64encode
from time import sleep, time
from typing import NamedTuple
import libvirt
import libvirt_qemu
from compute.exceptions import (
GuestAgentCommandNotSupportedError,
GuestAgentError,
GuestAgentTimeoutExceededError,
GuestAgentUnavailableError,
)
log = logging.getLogger(__name__)
class GuestExecOutput(NamedTuple):
"""QEMU guest-exec command output."""
exited: bool | None = None
exitcode: int | None = None
stdout: str | None = None
stderr: str | None = None
class GuestAgent:
"""Class for interacting with QEMU guest agent."""
def __init__(self, domain: libvirt.virDomain, timeout: int = 60):
"""
Initialise GuestAgent.
:param domain: Libvirt domain object
:param timeout: QEMU timeout
"""
self.domain = domain
self.timeout = timeout
self.flags = libvirt_qemu.VIR_DOMAIN_QEMU_MONITOR_COMMAND_DEFAULT
self.last_pid = None
def execute(self, command: dict) -> dict:
"""
Execute QEMU guest agent command.
See: https://qemu-project.gitlab.io/qemu/interop/qemu-ga-ref.html
:param command: QEMU guest agent command as dict
:return: Command output
:rtype: dict
"""
log.debug(command)
try:
output = libvirt_qemu.qemuAgentCommand(
self.domain, json.dumps(command), self.timeout, self.flags
)
return json.loads(output)
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_AGENT_UNRESPONSIVE:
raise GuestAgentUnavailableError(e) from e
raise GuestAgentError(e) from e
def is_available(self) -> bool:
"""
Execute guest-ping.
:return: True or False if guest agent is unreachable.
:rtype: bool
"""
try:
if self.execute({'execute': 'guest-ping', 'arguments': {}}):
return True
except GuestAgentError:
return False
def get_supported_commands(self) -> set[str]:
"""Return set of supported guest agent commands."""
output = self.execute({'execute': 'guest-info', 'arguments': {}})
return {
cmd['name']
for cmd in output['return']['supported_commands']
if cmd['enabled'] is True
}
def raise_for_commands(self, commands: list[str]) -> None:
"""
Raise exception if QEMU GA command is not available.
:param commands: List of required commands
:raise: GuestAgentCommandNotSupportedError
"""
supported = self.get_supported_commands()
for command in commands:
if command not in supported:
raise GuestAgentCommandNotSupportedError(command)
def guest_exec( # noqa: PLR0913
self,
path: str,
args: list[str] | None = None,
env: list[str] | None = None,
stdin: str | None = None,
*,
capture_output: bool = False,
decode_output: bool = False,
poll: bool = False,
) -> GuestExecOutput:
"""
Execute qemu-exec command and return output.
:param path: Path ot executable on guest.
:param arg: List of arguments to pass to executable.
:param env: List of environment variables to pass to executable.
For example: ``['LANG=C', 'TERM=xterm']``
:param stdin: Data to pass to executable STDIN.
:param capture_output: Capture command output.
:param decode_output: Use base64_decode() to decode command output.
Affects only if `capture_output` is True.
:param poll: Poll command output. Uses `self.timeout` and
POLL_INTERVAL constant.
:return: Command output
:rtype: GuestExecOutput
"""
self.raise_for_commands(['guest-exec', 'guest-exec-status'])
command = {
'execute': 'guest-exec',
'arguments': {
'path': path,
**({'arg': args} if args else {}),
**({'env': env} if env else {}),
**(
{
'input-data': standard_b64encode(
stdin.encode('utf-8')
).decode('utf-8')
}
if stdin
else {}
),
'capture-output': capture_output,
},
}
output = self.execute(command)
self.last_pid = pid = output['return']['pid']
command_status = self.guest_exec_status(pid, poll=poll)['return']
exited = command_status['exited']
exitcode = command_status['exitcode']
stdout = command_status.get('out-data', None)
stderr = command_status.get('err-data', None)
if decode_output:
stdout = b64decode(stdout or '').decode('utf-8')
stderr = b64decode(stderr or '').decode('utf-8')
return GuestExecOutput(exited, exitcode, stdout, stderr)
def guest_exec_status(
self, pid: int, *, poll: bool = False, poll_interval: float = 0.3
) -> dict:
"""
Execute guest-exec-status and return output.
:param pid: PID in guest.
:param poll: If True poll command status.
:param poll_interval: Time between attempts to obtain command status.
:return: Command output
:rtype: dict
"""
self.raise_for_commands(['guest-exec-status'])
command = {
'execute': 'guest-exec-status',
'arguments': {'pid': pid},
}
if not poll:
return self.execute(command)
start_time = time()
while True:
command_status = self.execute(command)
if command_status['return']['exited']:
break
sleep(poll_interval)
now = time()
if now - start_time > self.timeout:
raise GuestAgentTimeoutExceededError(self.timeout)
log.debug(
'Polling command pid=%s finished, time taken: %s seconds',
pid,
int(time() - start_time),
)
return command_status

View File

@ -1,675 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Manage compute instances."""
__all__ = ['Instance', 'InstanceConfig', 'InstanceInfo']
import logging
from typing import NamedTuple
import libvirt
from lxml import etree
from lxml.builder import E
from compute.common import DeviceConfig, EntityConfig
from compute.exceptions import (
GuestAgentCommandNotSupportedError,
InstanceError,
)
from compute.storage import DiskConfig
from compute.utils import units
from .guest_agent import GuestAgent
from .schemas import (
CPUEmulationMode,
CPUSchema,
InstanceSchema,
NetworkInterfaceSchema,
)
log = logging.getLogger(__name__)
class InstanceConfig(EntityConfig):
"""Compute instance XML config builder."""
def __init__(self, schema: InstanceSchema):
"""
Initialise InstanceConfig.
:param schema: InstanceSchema object
"""
self.name = schema.name
self.title = schema.title
self.description = schema.description
self.memory = schema.memory
self.max_memory = schema.max_memory
self.vcpus = schema.vcpus
self.max_vcpus = schema.max_vcpus
self.cpu = schema.cpu
self.machine = schema.machine
self.emulator = schema.emulator
self.arch = schema.arch
self.boot = schema.boot
self.network_interfaces = schema.network_interfaces
def _gen_cpu_xml(self, cpu: CPUSchema) -> etree.Element:
options = {
'mode': cpu.emulation_mode,
'match': 'exact',
'check': 'partial',
}
if cpu.emulation_mode == CPUEmulationMode.HOST_PASSTHROUGH:
options['check'] = 'none'
options['migratable'] = 'on'
xml = E.cpu(**options)
if cpu.model:
xml.append(E.model(cpu.model, fallback='forbid'))
if cpu.vendor:
xml.append(E.vendor(cpu.vendor))
if cpu.topology:
xml.append(
E.topology(
sockets=str(cpu.topology.sockets),
dies=str(cpu.topology.dies),
cores=str(cpu.topology.cores),
threads=str(cpu.topology.threads),
)
)
if cpu.features:
for feature in cpu.features.require:
xml.append(E.feature(policy='require', name=feature))
for feature in cpu.features.disable:
xml.append(E.feature(policy='disable', name=feature))
return xml
def _gen_vcpus_xml(self, vcpus: int, max_vcpus: int) -> etree.Element:
xml = E.vcpus()
xml.append(E.vcpu(id='0', enabled='yes', hotpluggable='no', order='1'))
for i in range(max_vcpus - 1):
enabled = 'yes' if (i + 2) <= vcpus else 'no'
xml.append(
E.vcpu(
id=str(i + 1),
enabled=enabled,
hotpluggable='yes',
order=str(i + 2),
)
)
return xml
def _gen_network_interface_xml(
self, interface: NetworkInterfaceSchema
) -> etree.Element:
return E.interface(
E.source(network=interface.source),
E.mac(address=interface.mac),
type='network',
)
def to_xml(self) -> str:
"""Return XML config for libvirt."""
xml = E.domain(type='kvm')
xml.append(E.name(self.name))
if self.title:
xml.append(E.title(self.title))
if self.description:
xml.append(E.description(self.description))
xml.append(E.metadata())
xml.append(E.memory(str(self.max_memory * 1024), unit='KiB'))
xml.append(E.currentMemory(str(self.memory * 1024), unit='KiB'))
xml.append(
E.vcpu(
str(self.max_vcpus),
placement='static',
current=str(self.vcpus),
)
)
xml.append(self._gen_cpu_xml(self.cpu))
os = E.os(E.type('hvm', machine=self.machine, arch=self.arch))
for dev in self.boot.order:
os.append(E.boot(dev=dev))
xml.append(os)
xml.append(E.features(E.acpi(), E.apic()))
xml.append(E.on_poweroff('destroy'))
xml.append(E.on_reboot('restart'))
xml.append(E.on_crash('restart'))
xml.append(
E.pm(
E('suspend-to-mem', enabled='no'),
E('suspend-to-disk', enabled='no'),
)
)
devices = E.devices()
devices.append(E.emulator(str(self.emulator)))
for interface in self.network_interfaces:
devices.append(self._gen_network_interface_xml(interface))
devices.append(E.graphics(type='vnc', port='-1', autoport='yes'))
devices.append(E.input(type='tablet', bus='usb'))
devices.append(
E.channel(
E.source(mode='bind'),
E.target(type='virtio', name='org.qemu.guest_agent.0'),
E.address(
type='virtio-serial', controller='0', bus='0', port='1'
),
type='unix',
)
)
devices.append(
E.console(E.target(type='serial', port='0'), type='pty')
)
devices.append(
E.video(
E.model(type='vga', vram='16384', heads='1', primary='yes')
)
)
xml.append(devices)
return etree.tostring(xml, encoding='unicode', pretty_print=True)
class InstanceInfo(NamedTuple):
"""
Store compute instance info.
Reference:
https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainInfo
"""
state: str
max_memory: int
memory: int
nproc: int
cputime: int
class Instance:
"""Manage compute instances."""
def __init__(self, domain: libvirt.virDomain):
"""
Initialise Instance.
:ivar libvirt.virDomain domain: domain object
:ivar libvirt.virConnect connection: connection object
:ivar str name: domain name
:ivar GuestAgent guest_agent: :class:`GuestAgent` object
:param domain: libvirt domain object
"""
self.domain = domain
self.connection = domain.connect()
self.name = domain.name()
self.guest_agent = GuestAgent(domain)
def _expand_instance_state(self, state: int) -> str:
states = {
libvirt.VIR_DOMAIN_NOSTATE: 'nostate',
libvirt.VIR_DOMAIN_RUNNING: 'running',
libvirt.VIR_DOMAIN_BLOCKED: 'blocked',
libvirt.VIR_DOMAIN_PAUSED: 'paused',
libvirt.VIR_DOMAIN_SHUTDOWN: 'shutdown',
libvirt.VIR_DOMAIN_SHUTOFF: 'shutoff',
libvirt.VIR_DOMAIN_CRASHED: 'crashed',
libvirt.VIR_DOMAIN_PMSUSPENDED: 'pmsuspended',
}
return states[state]
def get_info(self) -> InstanceInfo:
"""Return instance info."""
info = self.domain.info()
return InstanceInfo(
state=self._expand_instance_state(info[0]),
max_memory=info[1],
memory=info[2],
nproc=info[3],
cputime=info[4],
)
def get_status(self) -> str:
"""
Return instance state: 'running', 'shutoff', etc.
Reference:
https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState
"""
try:
state, _ = self.domain.state()
except libvirt.libvirtError as e:
raise InstanceError(
'Cannot fetch status of ' f'instance={self.name}: {e}'
) from e
return self._expand_instance_state(state)
def is_running(self) -> bool:
"""Return True if instance is running, else return False."""
if self.domain.isActive() != 1:
# 0 - is inactive, -1 - is error
return False
return True
def is_autostart(self) -> bool:
"""Return True if instance autostart is enabled, else return False."""
try:
return bool(self.domain.autostart())
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot get autostart status for '
f'instance={self.name}: {e}'
) from e
def get_max_memory(self) -> int:
"""Maximum memory value for domain in KiB."""
return self.domain.maxMemory()
def get_max_vcpus(self) -> int:
"""Maximum vCPUs number for domain."""
return self.domain.maxVcpus()
def start(self) -> None:
"""Start defined instance."""
log.info('Starting instnce=%s', self.name)
if self.is_running():
log.warning(
'Already started, nothing to do instance=%s', self.name
)
return
try:
self.domain.create()
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot start instance={self.name}: {e}'
) from e
def shutdown(self, method: str | None = None) -> None:
"""
Shutdown instance.
Shutdown methods:
SOFT
Use guest agent to shutdown. If guest agent is unavailable
NORMAL method will be used.
NORMAL
Use method choosen by hypervisor to shutdown. Usually send ACPI
signal to guest OS. OS may ignore ACPI e.g. if guest is hanged.
HARD
Shutdown instance without any guest OS shutdown. This is simular
to unplugging machine from power. Internally send SIGTERM to
instance process and destroy it gracefully.
UNSAFE
Force shutdown. Internally send SIGKILL to instance process.
There is high data corruption risk!
If method is None NORMAL method will used.
:param method: Method used to shutdown instance
"""
methods = {
'SOFT': libvirt.VIR_DOMAIN_SHUTDOWN_GUEST_AGENT,
'NORMAL': libvirt.VIR_DOMAIN_SHUTDOWN_DEFAULT,
'HARD': libvirt.VIR_DOMAIN_DESTROY_GRACEFUL,
'UNSAFE': libvirt.VIR_DOMAIN_DESTROY_DEFAULT,
}
if method is None:
method = 'NORMAL'
if not isinstance(method, str):
raise TypeError(
f"Shutdown method must be a 'str', not {type(method)}"
)
method = method.upper()
if method not in methods:
raise ValueError(f"Unsupported shutdown method: '{method}'")
try:
if method in ['SOFT', 'NORMAL']:
self.domain.shutdownFlags(flags=methods[method])
elif method in ['HARD', 'UNSAFE']:
self.domain.destroyFlags(flags=methods[method])
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot shutdown instance={self.name} ' f'{method=}: {e}'
) from e
def reboot(self) -> None:
"""Send ACPI signal to guest OS to reboot. OS may ignore this."""
try:
self.domain.reboot()
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot reboot instance={self.name}: {e}'
) from e
def reset(self) -> None:
"""
Reset instance.
Copypaste from libvirt doc:
Reset a domain immediately without any guest OS shutdown.
Reset emulates the power reset button on a machine, where all
hardware sees the RST line set and reinitializes internal state.
Note that there is a risk of data loss caused by reset without any
guest OS shutdown.
"""
try:
self.domain.reset()
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot reset instance={self.name}: {e}'
) from e
def power_reset(self) -> None:
"""
Shutdown instance and start.
By analogy with real hardware, this is a normal server shutdown,
and then turning off from the power supply and turning it on again.
This method is applicable in cases where there has been a
configuration change in libvirt and you need to restart the
instance to apply the new configuration.
"""
self.shutdown(method='NORMAL')
self.start()
def set_autostart(self, *, enabled: bool) -> None:
"""
Set autostart flag for instance.
:param enabled: Bool argument to set or unset autostart flag.
"""
autostart = 1 if enabled else 0
try:
self.domain.setAutostart(autostart)
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot set autostart flag for instance={self.name} '
f'{autostart=}: {e}'
) from e
def set_vcpus(self, nvcpus: int, *, live: bool = False) -> None:
"""
Set vCPU number.
If `live` is True and instance is not currently running vCPUs
will set in config and will applied when instance boot.
NB: Note that if this call is executed before the guest has
finished booting, the guest may fail to process the change.
:param nvcpus: Number of vCPUs
:param live: Affect a running instance
"""
if nvcpus <= 0:
raise InstanceError('Cannot set zero vCPUs')
if nvcpus > self.get_max_vcpus():
raise InstanceError('vCPUs count is greather than max_vcpus')
if nvcpus == self.get_info().nproc:
log.warning(
'Instance instance=%s already have %s vCPUs, nothing to do',
self.name,
nvcpus,
)
return
try:
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
self.domain.setVcpusFlags(nvcpus, flags=flags)
if live is True:
if not self.is_running():
log.warning(
'Instance is not running, changes applied in '
'instance config.'
)
return
flags = libvirt.VIR_DOMAIN_AFFECT_LIVE
self.domain.setVcpusFlags(nvcpus, flags=flags)
if self.guest_agent.is_available():
try:
self.guest_agent.raise_for_commands(
['guest-set-vcpus']
)
flags = libvirt.VIR_DOMAIN_VCPU_GUEST
self.domain.setVcpusFlags(nvcpus, flags=flags)
except GuestAgentCommandNotSupportedError:
log.warning(
'Cannot set vCPUs in guest via agent, you may '
'need to apply changes in guest manually.'
)
else:
log.warning(
'Cannot set vCPUs in guest OS on instance=%s. '
'You may need to apply CPUs in guest manually.',
self.name,
)
except libvirt.libvirtError as e:
raise InstanceError(
f'Cannot set vCPUs for instance={self.name}: {e}'
) from e
def set_memory(self, memory: int, *, live: bool = False) -> None:
"""
Set memory.
If `live` is True and instance is not currently running set memory
in config and will applied when instance boot.
:param memory: Memory value in mebibytes
:param live: Affect a running instance
"""
if memory <= 0:
raise InstanceError('Cannot set zero memory')
if (memory * 1024) > self.get_max_memory():
raise InstanceError('Memory is greather than max_memory')
if (memory * 1024) == self.get_info().memory:
log.warning(
"Instance '%s' already have %s memory, nothing to do",
self.name,
memory,
)
return
if live and self.is_running():
flags = (
libvirt.VIR_DOMAIN_AFFECT_LIVE
| libvirt.VIR_DOMAIN_AFFECT_CONFIG
)
else:
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
try:
self.domain.setMemoryFlags(memory * 1024, flags=flags)
except libvirt.libvirtError as e:
msg = f'Cannot set memory for instance={self.name} {memory=}: {e}'
raise InstanceError(msg) from e
def _get_disk_by_target(self, target: str) -> etree.Element:
xml = etree.fromstring(self.dump_xml()) # noqa: S320
child = xml.xpath(f'/domain/devices/disk/target[@dev="{target}"]')
return child[0].getparent() if child else None
def attach_device(
self, device: DeviceConfig, *, live: bool = False
) -> None:
"""
Attach device to compute instance.
:param device: Object with device description e.g. DiskConfig
:param live: Affect a running instance
"""
if live and self.is_running():
flags = (
libvirt.VIR_DOMAIN_AFFECT_LIVE
| libvirt.VIR_DOMAIN_AFFECT_CONFIG
)
else:
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
if isinstance(device, DiskConfig): # noqa: SIM102
if self._get_disk_by_target(device.target):
log.warning(
"Volume with target '%s' is already attached",
device.target,
)
return
self.domain.attachDeviceFlags(device.to_xml(), flags=flags)
def detach_device(
self, device: DeviceConfig, *, live: bool = False
) -> None:
"""
Dettach device from compute instance.
:param device: Object with device description e.g. DiskConfig
:param live: Affect a running instance
"""
if live and self.is_running():
flags = (
libvirt.VIR_DOMAIN_AFFECT_LIVE
| libvirt.VIR_DOMAIN_AFFECT_CONFIG
)
else:
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
if isinstance(device, DiskConfig): # noqa: SIM102
if self._get_disk_by_target(device.target) is None:
log.warning(
"Volume with target '%s' is already detached",
device.target,
)
return
self.domain.detachDeviceFlags(device.to_xml(), flags=flags)
def detach_disk(self, name: str) -> None:
"""
Detach disk device by target name.
There is no ``attach_disk()`` method. Use :func:`attach_device`
with :class:`DiskConfig` as argument.
:param name: Disk name e.g. 'vda', 'sda', etc. This name may
not match the name of the disk inside the guest OS.
"""
xml = self._get_disk_by_target(name)
if xml is None:
log.warning(
"Volume with target '%s' is already detached",
name,
)
return
disk_params = {
'disk_type': xml.get('type'),
'source': xml.find('source').get('file'),
'target': xml.find('target').get('dev'),
'readonly': False if xml.find('readonly') is None else True, # noqa: SIM211
}
for param in disk_params:
if disk_params[param] is None:
msg = (
f"Cannot detach volume with target '{name}': "
f"parameter '{param}' is not defined in libvirt XML "
'config on host.'
)
raise InstanceError(msg)
self.detach_device(DiskConfig(**disk_params), live=True)
def resize_disk(
self, name: str, capacity: int, unit: units.DataUnit
) -> None:
"""
Resize attached block device.
:param name: Disk device name e.g. `vda`, `sda`, etc.
:param capacity: New capacity.
:param unit: Capacity unit.
"""
self.domain.blockResize(
name,
units.to_bytes(capacity, unit=unit),
flags=libvirt.VIR_DOMAIN_BLOCK_RESIZE_BYTES,
)
def get_disks(self) -> list[DiskConfig]:
"""Return list of attached disks."""
raise NotImplementedError
def pause(self) -> None:
"""Pause instance."""
if not self.is_running():
raise InstanceError('Cannot pause inactive instance')
self.domain.suspend()
def resume(self) -> None:
"""Resume paused instance."""
self.domain.resume()
def get_ssh_keys(self, user: str) -> list[str]:
"""
Return list of SSH keys on guest for specific user.
:param user: Username.
"""
raise NotImplementedError
def set_ssh_keys(self, user: str, ssh_keys: list[str]) -> None:
"""
Add SSH keys to guest for specific user.
:param user: Username.
:param ssh_keys: List of public SSH keys.
"""
raise NotImplementedError
def delete_ssh_keys(self, user: str, ssh_keys: list[str]) -> None:
"""
Remove SSH keys from guest for specific user.
:param user: Username.
:param ssh_keys: List of public SSH keys.
"""
raise NotImplementedError
def set_user_password(
self, user: str, password: str, *, encrypted: bool = False
) -> None:
"""
Set new user password in guest OS.
This action performs by guest agent inside the guest.
:param user: Username.
:param password: Password.
:param encrypted: Set it to True if password is already encrypted.
Right encryption method depends on guest OS.
"""
if not self.guest_agent.is_available():
raise InstanceError(
'Cannot change password: guest agent is unavailable'
)
self.guest_agent.raise_for_commands(['guest-set-user-password'])
flags = libvirt.VIR_DOMAIN_PASSWORD_ENCRYPTED if encrypted else 0
self.domain.setUserPassword(user, password, flags=flags)
def dump_xml(self, *, inactive: bool = False) -> str:
"""Return instance XML description."""
flags = libvirt.VIR_DOMAIN_XML_INACTIVE if inactive else 0
return self.domain.XMLDesc(flags)
def delete(self) -> None:
"""Undefine instance."""
# TODO @ge: delete local disks
self.shutdown(method='HARD')
self.domain.undefine()

View File

@ -1,165 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Compute instance related objects schemas."""
import re
from enum import StrEnum
from pathlib import Path
from pydantic import BaseModel, Extra, validator
from compute.utils.units import DataUnit
class EntityModel(BaseModel):
"""Basic entity model."""
class Config:
"""Do not allow extra fields."""
extra = Extra.forbid
class CPUEmulationMode(StrEnum):
"""CPU emulation mode enumerated."""
HOST_PASSTHROUGH = 'host-passthrough'
HOST_MODEL = 'host-model'
CUSTOM = 'custom'
MAXIMUM = 'maximum'
class CPUTopologySchema(EntityModel):
"""CPU topology model."""
sockets: int
cores: int
threads: int
dies: int = 1
class CPUFeaturesSchema(EntityModel):
"""CPU features model."""
require: list[str]
disable: list[str]
class CPUSchema(EntityModel):
"""CPU model."""
emulation_mode: CPUEmulationMode
model: str | None
vendor: str | None
topology: CPUTopologySchema | None
features: CPUFeaturesSchema | None
class VolumeType(StrEnum):
"""Storage volume types enumeration."""
FILE = 'file'
class VolumeCapacitySchema(EntityModel):
"""Storage volume capacity field model."""
value: int
unit: DataUnit
class VolumeSchema(EntityModel):
"""Storage volume model."""
type: VolumeType # noqa: A003
target: str
capacity: VolumeCapacitySchema
source: str | None = None
is_readonly: bool = False
is_system: bool = False
class NetworkInterfaceSchema(EntityModel):
"""Network inerface model."""
source: str
mac: str
class BootOptionsSchema(EntityModel):
"""Instance boot settings."""
order: tuple
class InstanceSchema(EntityModel):
"""Compute instance model."""
name: str
title: str | None
description: str | None
memory: int
max_memory: int
vcpus: int
max_vcpus: int
cpu: CPUSchema
machine: str
emulator: Path
arch: str
boot: BootOptionsSchema
volumes: list[VolumeSchema]
network_interfaces: list[NetworkInterfaceSchema]
image: str | None = None
@validator('name')
def _check_name(cls, value: str) -> str: # noqa: N805
if not re.match(r'^[a-z0-9_]+$', value):
msg = (
'Name can contain only lowercase letters, numbers '
'and underscore.'
)
raise ValueError(msg)
return value
@validator('cpu')
def _check_topology(cls, cpu: int, values: dict) -> CPUSchema: # noqa: N805
topo = cpu.topology
max_vcpus = values['max_vcpus']
if topo and topo.sockets * topo.cores * topo.threads != max_vcpus:
msg = f'CPU topology does not match with {max_vcpus=}'
raise ValueError(msg)
return cpu
@validator('volumes')
def _check_volumes(cls, volumes: list) -> list: # noqa: N805
if len([v for v in volumes if v.is_system is True]) != 1:
msg = 'volumes list must contain one system volume'
raise ValueError(msg)
vol_with_source = 0
for vol in volumes:
if vol.is_system is True and vol.is_readonly is True:
msg = 'volume marked as system cannot be readonly'
raise ValueError(msg)
if vol.source is not None:
vol_with_source += 1
return volumes
@validator('network_interfaces')
def _check_network_interfaces(cls, value: list) -> list: # noqa: N805
if not value:
msg = 'Network interfaces list must contain at least one element'
raise ValueError(msg)
return value

View File

@ -1,286 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Hypervisor session manager."""
import logging
import os
from contextlib import AbstractContextManager
from types import TracebackType
from typing import Any, NamedTuple
from uuid import uuid4
import libvirt
from lxml import etree
from .exceptions import (
InstanceNotFoundError,
SessionError,
StoragePoolNotFoundError,
)
from .instance import Instance, InstanceConfig, InstanceSchema
from .storage import DiskConfig, StoragePool, VolumeConfig
from .utils import units
log = logging.getLogger(__name__)
class Capabilities(NamedTuple):
"""Store domain capabilities info."""
arch: str
virt_type: str
emulator: str
machine: str
max_vcpus: int
cpu_vendor: str
cpu_model: str
cpu_features: dict
usable_cpus: list[dict]
class NodeInfo(NamedTuple):
"""
Store compute node info.
See https://libvirt.org/html/libvirt-libvirt-host.html#virNodeInfo
NOTE: memory unit in libvirt docs is wrong! Actual unit is MiB.
"""
arch: str
memory: int
cpus: int
mhz: int
nodes: int
sockets: int
cores: int
threads: int
class Session(AbstractContextManager):
"""
Hypervisor session context manager.
:cvar IMAGES_POOL: images storage pool name taken from env
:cvar VOLUMES_POOL: volumes storage pool name taken from env
"""
IMAGES_POOL = os.getenv('CMP_IMAGES_POOL')
VOLUMES_POOL = os.getenv('CMP_VOLUMES_POOL')
def __init__(self, uri: str | None = None):
"""
Initialise session with hypervisor.
:ivar str uri: libvirt connection URI.
:ivar libvirt.virConnect connection: libvirt connection object.
:param uri: libvirt connection URI.
"""
self.uri = uri or 'qemu:///system'
self.connection = libvirt.open(self.uri)
def __enter__(self):
"""Return Session object."""
return self
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_value: BaseException | None,
exc_traceback: TracebackType | None,
):
"""Close the connection when leaving the context."""
self.close()
def close(self) -> None:
"""Close connection to libvirt daemon."""
self.connection.close()
def get_node_info(self) -> NodeInfo:
"""Return information about compute node."""
info = self.connection.getInfo()
return NodeInfo(
arch=info[0],
memory=info[1],
cpus=info[2],
mhz=info[3],
nodes=info[4],
sockets=info[5],
cores=info[6],
threads=info[7],
)
def _cap_get_usable_cpus(self, xml: etree.Element) -> list[dict]:
x = xml.xpath('/domainCapabilities/cpu/mode[@name="custom"]')[0]
cpus = []
for cpu in x.findall('model'):
if cpu.get('usable') == 'yes':
cpus.append( # noqa: PERF401
{
'vendor': cpu.get('vendor'),
'model': cpu.text,
}
)
return cpus
def _cap_get_cpu_features(self, xml: etree.Element) -> dict:
x = xml.xpath('/domainCapabilities/cpu/mode[@name="host-model"]')[0]
require = []
disable = []
for feature in x.findall('feature'):
policy = feature.get('policy')
name = feature.get('name')
if policy == 'require':
require.append(name)
if policy == 'disable':
disable.append(name)
return {'require': require, 'disable': disable}
def get_capabilities(self) -> Capabilities:
"""Return capabilities e.g. arch, virt, emulator, etc."""
prefix = '/domainCapabilities'
hprefix = f'{prefix}/cpu/mode[@name="host-model"]'
caps = etree.fromstring(self.connection.getDomainCapabilities()) # noqa: S320
return Capabilities(
arch=caps.xpath(f'{prefix}/arch/text()')[0],
virt_type=caps.xpath(f'{prefix}/domain/text()')[0],
emulator=caps.xpath(f'{prefix}/path/text()')[0],
machine=caps.xpath(f'{prefix}/machine/text()')[0],
max_vcpus=int(caps.xpath(f'{prefix}/vcpu/@max')[0]),
cpu_vendor=caps.xpath(f'{hprefix}/vendor/text()')[0],
cpu_model=caps.xpath(f'{hprefix}/model/text()')[0],
cpu_features=self._cap_get_cpu_features(caps),
usable_cpus=self._cap_get_cpus(caps),
)
def create_instance(self, **kwargs: Any) -> Instance:
"""
Create and return new compute instance.
:param name: Instance name.
:type name: str
:param title: Instance title for humans.
:type title: str
:param description: Some information about instance.
:type description: str
:param memory: Memory in MiB.
:type memory: int
:param max_memory: Maximum memory in MiB.
:type max_memory: int
:param vcpus: Number of vCPUs.
:type vcpus: int
:param max_vcpus: Maximum vCPUs.
:type max_vcpus: int
:param cpu: CPU configuration. See :class:`CPUSchema` for info.
:type cpu: dict
:param machine: QEMU emulated machine.
:type machine: str
:param emulator: Path to emulator.
:type emulator: str
:param arch: CPU architecture to virtualization.
:type arch: str
:param boot: Boot settings. See :class:`BootOptionsSchema`.
:type boot: dict
:param image: Source disk image name for system disk.
:type image: str
:param volumes: List of storage volume configs. For more info
see :class:`VolumeSchema`.
:type volumes: list[dict]
:param network_interfaces: List of virtual network interfaces
configs. See :class:`NetworkInterfaceSchema` for more info.
:type network_interfaces: list[dict]
"""
data = InstanceSchema(**kwargs)
config = InstanceConfig(data)
log.info('Define XML...')
log.info(config.to_xml())
self.connection.defineXML(config.to_xml())
log.info('Getting instance...')
instance = self.get_instance(config.name)
log.info('Creating volumes...')
for volume in data.volumes:
log.info('Creating volume=%s', volume)
capacity = units.to_bytes(
volume.capacity.value, volume.capacity.unit
)
log.info('Connecting to images pool...')
images_pool = self.get_storage_pool(self.IMAGES_POOL)
log.info('Connecting to volumes pool...')
volumes_pool = self.get_storage_pool(self.VOLUMES_POOL)
log.info('Building volume configuration...')
if not volume.source:
vol_name = f'{uuid4()}.qcow2'
else:
vol_name = volume.source
vol_conf = VolumeConfig(
name=vol_name,
path=str(volumes_pool.path.joinpath(vol_name)),
capacity=capacity,
)
log.info('Volume configuration is:\n %s', vol_conf.to_xml())
if volume.is_system is True and data.image:
log.info(
"Volume is marked as 'system', start cloning image..."
)
log.info('Get image %s', data.image)
image = images_pool.get_volume(data.image)
log.info('Cloning image into volumes pool...')
vol = volumes_pool.clone_volume(image, vol_conf)
log.info(
'Resize cloned volume to specified size: %s',
capacity,
)
vol.resize(capacity, unit=units.DataUnit.BYTES)
else:
log.info('Create volume...')
volumes_pool.create_volume(vol_conf)
log.info('Attaching volume to instance...')
instance.attach_device(
DiskConfig(
disk_type=volume.type,
source=vol_conf.path,
target=volume.target,
readonly=volume.is_readonly,
)
)
return instance
def get_instance(self, name: str) -> Instance:
"""Get compute instance by name."""
try:
return Instance(self.connection.lookupByName(name))
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
raise InstanceNotFoundError(name) from e
raise SessionError(e) from e
def list_instances(self) -> list[Instance]:
"""List all instances."""
return [Instance(dom) for dom in self.connection.listAllDomains()]
def get_storage_pool(self, name: str) -> StoragePool:
"""Get storage pool by name."""
try:
return StoragePool(self.connection.storagePoolLookupByName(name))
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL:
raise StoragePoolNotFoundError(name) from e
raise SessionError(e) from e
def list_storage_pools(self) -> list[StoragePool]:
"""List all strage pools."""
return [StoragePool(p) for p in self.connection.listStoragePools()]

View File

@ -1,17 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from .pool import StoragePool
from .volume import DiskConfig, Volume, VolumeConfig

View File

@ -1,124 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Manage storage pools."""
import logging
from pathlib import Path
from typing import NamedTuple
import libvirt
from lxml import etree
from compute.exceptions import StoragePoolError, VolumeNotFoundError
from .volume import Volume, VolumeConfig
log = logging.getLogger(__name__)
class StoragePoolUsageInfo(NamedTuple):
"""Storage pool usage info."""
capacity: int
allocation: int
available: int
class StoragePool:
"""Storage pool manipulating class."""
def __init__(self, pool: libvirt.virStoragePool):
"""Initislise StoragePool."""
self.pool = pool
self.name = pool.name()
self.path = self._get_path()
def _get_path(self) -> Path:
"""Return storage pool path."""
xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320
return Path(xml.xpath('/pool/target/path/text()')[0])
def get_usage_info(self) -> StoragePoolUsageInfo:
"""Return info about storage pool usage."""
xml = etree.fromstring(self.pool.XMLDesc()) # noqa: S320
return StoragePoolUsageInfo(
capacity=int(xml.xpath('/pool/capacity/text()')[0]),
allocation=int(xml.xpath('/pool/allocation/text()')[0]),
available=int(xml.xpath('/pool/available/text()')[0]),
)
def dump_xml(self) -> str:
"""Return storage pool XML description as string."""
return self.pool.XMLDesc()
def refresh(self) -> None:
"""Refresh storage pool."""
# TODO @ge: handle libvirt asynchronous job related exceptions
self.pool.refresh()
def create_volume(self, vol_conf: VolumeConfig) -> Volume:
"""Create storage volume and return Volume instance."""
log.info(
'Create storage volume vol=%s in pool=%s', vol_conf.name, self.name
)
vol = self.pool.createXML(
vol_conf.to_xml(),
flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA,
)
return Volume(self.pool, vol)
def clone_volume(self, src: Volume, dst: VolumeConfig) -> Volume:
"""
Make storage volume copy.
:param src: Input volume
:param dst: Output volume config
"""
log.info(
'Start volume cloning '
'src_pool=%s src_vol=%s dst_pool=%s dst_vol=%s',
src.pool_name,
src.name,
self.pool.name,
dst.name,
)
vol = self.pool.createXMLFrom(
dst.to_xml(), # new volume XML description
src.vol, # source volume virStorageVol object
flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA,
)
if vol is None:
raise StoragePoolError
return Volume(self.pool, vol)
def get_volume(self, name: str) -> Volume | None:
"""Lookup and return Volume instance or None."""
log.info(
'Lookup for storage volume vol=%s in pool=%s', name, self.pool.name
)
try:
vol = self.pool.storageVolLookupByName(name)
return Volume(self.pool, vol)
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL:
raise VolumeNotFoundError(name) from e
log.exception('unexpected error from libvirt')
raise StoragePoolError(e) from e
def list_volumes(self) -> list[Volume]:
"""Return list of volumes in storage pool."""
return [Volume(self.pool, vol) for vol in self.pool.listAllVolumes()]

View File

@ -1,138 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Manage storage volumes."""
from dataclasses import dataclass
from pathlib import Path
from time import time
import libvirt
from lxml import etree
from lxml.builder import E
from compute.common import DeviceConfig, EntityConfig
from compute.utils import units
@dataclass
class VolumeConfig(EntityConfig):
"""
Storage volume XML config builder.
Generate XML config for creating a volume in a libvirt
storage pool.
"""
name: str
path: str
capacity: int
def to_xml(self) -> str:
"""Return XML config for libvirt."""
unixtime = str(int(time()))
xml = E.volume(type='file')
xml.append(E.name(self.name))
xml.append(E.key(self.path))
xml.append(E.source())
xml.append(E.capacity(str(self.capacity), unit='bytes'))
xml.append(E.allocation('0'))
xml.append(
E.target(
E.path(self.path),
E.format(type='qcow2'),
E.timestamps(
E.atime(unixtime), E.mtime(unixtime), E.ctime(unixtime)
),
E.compat('1.1'),
E.features(E.lazy_refcounts()),
)
)
return etree.tostring(xml, encoding='unicode', pretty_print=True)
@dataclass
class DiskConfig(DeviceConfig):
"""
Disk XML config builder.
Generate XML config for attaching or detaching storage volumes
to compute instances.
"""
disk_type: str
source: str | Path
target: str
readonly: bool = False
def to_xml(self) -> str:
"""Return XML config for libvirt."""
xml = E.disk(type=self.disk_type, device='disk')
xml.append(E.driver(name='qemu', type='qcow2', cache='writethrough'))
if self.disk_type == 'file':
xml.append(E.source(file=str(self.source)))
xml.append(E.target(dev=self.target, bus='virtio'))
if self.readonly:
xml.append(E.readonly())
return etree.tostring(xml, encoding='unicode', pretty_print=True)
class Volume:
"""Storage volume manipulating class."""
def __init__(
self, pool: libvirt.virStoragePool, vol: libvirt.virStorageVol
):
"""
Initialise Volume.
:param pool: libvirt virStoragePool object
:param vol: libvirt virStorageVol object
"""
self.pool = pool
self.pool_name = pool.name()
self.vol = vol
self.name = vol.name()
self.path = Path(vol.path())
def dump_xml(self) -> str:
"""Return volume XML description as string."""
return self.vol.XMLDesc()
def clone(self, vol_conf: VolumeConfig) -> None:
"""
Make a copy of volume to the same storage pool.
:param vol_info VolumeInfo: New storage volume dataclass object
"""
self.pool.createXMLFrom(
vol_conf.to_xml(),
self.vol,
flags=libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA,
)
def resize(self, capacity: int, unit: units.DataUnit) -> None:
"""
Resize volume.
:param capacity int: Volume new capacity.
:param unit DataUnit: Data unit. Internally converts into bytes.
"""
# TODO @ge: Check actual volume size before resize
self.vol.resize(units.to_bytes(capacity, unit=unit))
def delete(self) -> None:
"""Delete volume from storage pool."""
self.vol.delete()

View File

@ -1,56 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Configuration loader."""
import tomllib
from collections import UserDict
from pathlib import Path
from compute.exceptions import ConfigLoaderError
DEFAULT_CONFIGURATION = {}
DEFAULT_CONFIG_FILE = '/etc/computed/computed.toml'
class ConfigLoader(UserDict):
"""UserDict for storing configuration."""
def __init__(self, file: Path | None = None):
"""
Initialise ConfigLoader.
:param file: Path to configuration file. If `file` is None
use default path from DEFAULT_CONFIG_FILE constant.
"""
# TODO @ge: load deafult configuration
self.file = Path(file) if file else Path(DEFAULT_CONFIG_FILE)
super().__init__(self.load())
def load(self) -> dict:
"""Load confguration object from TOML file."""
try:
with Path(self.file).open('rb') as configfile:
return tomllib.load(configfile)
# TODO @ge: add config schema validation
except tomllib.TOMLDecodeError as tomlerr:
raise ConfigLoaderError(
f'Bad TOML syntax in config file: {self.file}: {tomlerr}'
) from tomlerr
except (OSError, ValueError) as readerr:
raise ConfigLoaderError(
f'Cannot read config file: {self.file}: {readerr}'
) from readerr

View File

@ -1,33 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Random identificators."""
# ruff: noqa: S311, C417
import random
def random_mac() -> str:
"""Retrun random MAC address."""
mac = [
0x00,
0x16,
0x3E,
random.randint(0x00, 0x7F),
random.randint(0x00, 0xFF),
random.randint(0x00, 0xFF),
]
return ':'.join(map(lambda x: '%02x' % x, mac))

View File

@ -1,54 +0,0 @@
# This file is part of Compute
#
# Compute is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
"""Tools for data units convertion."""
from enum import StrEnum
class DataUnit(StrEnum):
"""Data units enumerated."""
BYTES = 'bytes'
KIB = 'KiB'
MIB = 'MiB'
GIB = 'GiB'
TIB = 'TiB'
class InvalidDataUnitError(ValueError):
"""Data unit is not valid."""
def __init__(self, msg: str):
"""Initialise InvalidDataUnitError."""
super().__init__(
f'{msg}, valid units are: {", ".join(list(DataUnit))}'
)
def to_bytes(value: int, unit: DataUnit = DataUnit.BYTES) -> int:
"""Convert value to bytes. See :class:`DataUnit`."""
try:
_ = DataUnit(unit)
except ValueError as e:
raise InvalidDataUnitError(e) from e
powers = {
DataUnit.BYTES: 0,
DataUnit.KIB: 1,
DataUnit.MIB: 2,
DataUnit.GIB: 3,
DataUnit.TIB: 4,
}
return value * pow(1024, powers[unit])

View File

@ -1,5 +0,0 @@
compute (0.1.0.dev1-1) UNRELEASED; urgency=medium
* This is the development build, see commits in upstream repo for info.
-- ge <ge@nixhacks.net> Wed, 22 Nov 2023 23:06:43 +0000

View File

@ -1,5 +0,0 @@
compute (0.1.0.dev1-1) UNRELEASED; urgency=medium
* This is the development build, see commits in upstream repo for info.
-- ge <ge@nixhacks.net> Wed, 22 Nov 2023 23:06:43 +0000

View File

@ -1,5 +0,0 @@
compute (0.1.0.dev1-1) UNRELEASED; urgency=medium
* This is the development build, see commits in upstream repo for info.
-- ge <ge@nixhacks.net> Wed, 22 Nov 2023 23:06:43 +0000

View File

@ -1,4 +0,0 @@
sphinxdoc:Depends=libjs-sphinxdoc (>= 1.0), libjs-sphinxdoc (>= 2.4.3-5~), libjs-sphinxdoc (>= 5.0), libjs-sphinxdoc (>= 5.2)
sphinxdoc:Built-Using=alabaster (= 0.7.12-1), sphinx (= 5.3.0-4)
misc:Depends=
misc:Pre-Depends=

View File

@ -1,11 +0,0 @@
Package: compute-doc
Source: compute
Version: 0.1.0.dev1-1
Architecture: all
Maintainer: ge <ge@nixhacks.net>
Installed-Size: 376
Depends: libjs-sphinxdoc (>= 5.2)
Section: doc
Priority: optional
Homepage: https://git.lulzette.ru/hstack/compute
Description: Compute instances management library and tools (documentation)

View File

@ -1,40 +0,0 @@
6845278a102bd147f30f770ed1134ce5 usr/share/doc/compute-doc/changelog.Debian.gz
fb1a6c11d7a8fa5f238617c20b13b6a1 usr/share/doc/compute-doc/copyright
705113edf19bbf7f9d406fccd98ebef9 usr/share/doc/compute-doc/html/_sources/index.rst.txt
91934f7b742b8395043e25cfa73682af usr/share/doc/compute-doc/html/_sources/pyapi/exceptions.rst.txt
de8bc1c2c00774ddee5363aef80c0775 usr/share/doc/compute-doc/html/_sources/pyapi/index.rst.txt
2a0040e0a150de53ed929e963af635a8 usr/share/doc/compute-doc/html/_sources/pyapi/instance/guest_agent.rst.txt
dd6324cb85dc57ef37c4f8161aa2d233 usr/share/doc/compute-doc/html/_sources/pyapi/instance/index.rst.txt
c594567565cc48a247932409d9adcc4a usr/share/doc/compute-doc/html/_sources/pyapi/instance/instance.rst.txt
e6a69ab447e455dba6e7b865a3d872d2 usr/share/doc/compute-doc/html/_sources/pyapi/instance/schemas.rst.txt
ba27654c086857e64d58468b13bc31c4 usr/share/doc/compute-doc/html/_sources/pyapi/session.rst.txt
801ccc953fc57199b06ec122e10f784c usr/share/doc/compute-doc/html/_sources/pyapi/storage/index.rst.txt
324ae7c877f3cf7895b2a5d3af579345 usr/share/doc/compute-doc/html/_sources/pyapi/storage/pool.rst.txt
db91c0d83c2c80e9f9323a8943eeeff4 usr/share/doc/compute-doc/html/_sources/pyapi/storage/volume.rst.txt
572ed749dd8924c36f1afe9e8e14d4d3 usr/share/doc/compute-doc/html/_sources/pyapi/utils.rst.txt
4fc9d553e40384beedf38e21f205d2a7 usr/share/doc/compute-doc/html/_static/alabaster.css
23ffe661f835b08e157d492a86aae74d usr/share/doc/compute-doc/html/_static/basic.css
dad0c9b31e59069c83018ce87594ed65 usr/share/doc/compute-doc/html/_static/custom.css
5e103d51310d4e0c065325d795cc9def usr/share/doc/compute-doc/html/_static/documentation_options.js
ba0c95766a77a6c598a7ca542f1db738 usr/share/doc/compute-doc/html/_static/file.png
5b6b3233153feca50a94aa6c60873a5f usr/share/doc/compute-doc/html/_static/forkme_right_darkblue_121621.png
36b1a4b05451c7acde7ced60b2f6bc21 usr/share/doc/compute-doc/html/_static/minus.png
0d7849fd4d4148b7f78cab60a087633a usr/share/doc/compute-doc/html/_static/plus.png
4f81be1c1dd97a6ec76af15b8f926189 usr/share/doc/compute-doc/html/_static/pygments.css
fd297228a19ece7e38824d0704f3635d usr/share/doc/compute-doc/html/genindex.html
3e038e6169c721ebacf889ea4ac5c1bf usr/share/doc/compute-doc/html/index.html
b8e4906e5136e907ab0d7ae826720603 usr/share/doc/compute-doc/html/objects.inv
2658558520c0c9f209dd4c69516facfd usr/share/doc/compute-doc/html/py-modindex.html
4254a2ecc3e154f52646febebd0ef6e6 usr/share/doc/compute-doc/html/pyapi/exceptions.html
bf4609f321d2c60399574c3e52dd6a44 usr/share/doc/compute-doc/html/pyapi/index.html
730aab71986cb938e9aff03ba203c9a9 usr/share/doc/compute-doc/html/pyapi/instance/guest_agent.html
fad8eba8a9cb9b1befd8e0ecdf1bbe5f usr/share/doc/compute-doc/html/pyapi/instance/index.html
781272676f0b35c52f43b99f2ca86647 usr/share/doc/compute-doc/html/pyapi/instance/instance.html
ede88501ec628083bb1ad1cb86cdec9f usr/share/doc/compute-doc/html/pyapi/instance/schemas.html
4c8d372d298068aba7272d11feb2cc52 usr/share/doc/compute-doc/html/pyapi/session.html
000f86f6184a455843017772ff2fec9d usr/share/doc/compute-doc/html/pyapi/storage/index.html
a2b63c0194a1e55be8d7036b46851986 usr/share/doc/compute-doc/html/pyapi/storage/pool.html
8d4e9081b213585aad36b4daadc37e26 usr/share/doc/compute-doc/html/pyapi/storage/volume.html
307d7a44f4343b0f34ee758e4ab20d88 usr/share/doc/compute-doc/html/pyapi/utils.html
5999199d4710213969f7fb1b50647f4a usr/share/doc/compute-doc/html/search.html
148b182d3691ae88c629783c3623007d usr/share/doc/compute-doc/html/searchindex.js

View File

@ -1,32 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Source: https://git.lulzette.ru/hstack/compute
Upstream-Name: compute
Files:
*
Copyright:
2023 ge <ge@nixhacks.net>
License: GPL-3.0+
Files:
debian/*
Copyright:
2023 ge <ge@nixhacks.net>
License: GPL-3.0+
License: GPL-3.0+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Comment:
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".

View File

@ -1,16 +0,0 @@
Compute
=======
Compute instances management library.
.. toctree::
:maxdepth: 1
pyapi/index
Indices and tables
------------------
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1,5 +0,0 @@
``exceptions``
==============
.. automodule:: compute.exceptions
:members:

View File

@ -1,49 +0,0 @@
Python API
==========
The API allows you to perform actions on instances programmatically. Below is
an example of changing parameters and launching the `myinstance` instance.
.. code-block:: python
import logging
from compute import Session
logging.basicConfig(level=logging.DEBUG)
with Session() as session:
instance = session.get_instance('myinstance')
instance.set_vcpus(4)
instance.start()
instance.set_autostart(enabled=True)
:class:`Session` context manager provides an abstraction over :class:`libvirt.virConnect`
and returns objects of other classes of the present library.
Entity representation
---------------------
Entities such as a compute-instance are represented as classes. These classes directly
call libvirt methods to perform operations on the hypervisor. An example class is
:class:`Volume`.
The configuration files of various libvirt objects in `compute` are described by special
dataclasses. The dataclass stores object parameters in its properties and can return an
XML config for libvirt using the ``to_xml()`` method. For example :class:`VolumeConfig`.
`Pydantic <https://docs.pydantic.dev/>`_ models are used to validate input data.
For example :class:`VolumeSchema`.
Modules documentation
---------------------
.. toctree::
:maxdepth: 4
session
instance/index
storage/index
utils
exceptions

View File

@ -1,6 +0,0 @@
``guest_agent``
===============
.. automodule:: compute.instance.guest_agent
:members:
:special-members: __init__

View File

@ -1,10 +0,0 @@
``instance``
============
.. toctree::
:maxdepth: 1
:caption: Contents:
instance
guest_agent
schemas

View File

@ -1,6 +0,0 @@
``instance``
============
.. automodule:: compute.instance.instance
:members:
:special-members: __init__

View File

@ -1,5 +0,0 @@
``schemas``
===========
.. automodule:: compute.instance.schemas
:members:

View File

@ -1,6 +0,0 @@
``session``
===========
.. automodule:: compute.session
:members:
:special-members: __init__

View File

@ -1,9 +0,0 @@
``storage``
============
.. toctree::
:maxdepth: 1
:caption: Contents:
pool
volume

View File

@ -1,6 +0,0 @@
``pool``
========
.. automodule:: compute.storage.pool
:members:
:special-members: __init__

View File

@ -1,6 +0,0 @@
``volume``
==========
.. automodule:: compute.storage.volume
:members:
:special-members: __init__

View File

@ -1,14 +0,0 @@
``utils``
=========
``utils.units``
---------------
.. automodule:: compute.utils.units
:members:
``utils.ids``
-------------
.. automodule:: compute.utils.ids
:members:

View File

@ -1 +0,0 @@
../../../../javascript/sphinxdoc/1.0/_sphinx_javascript_frameworks_compat.js

View File

@ -1,701 +0,0 @@
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: Georgia, serif;
font-size: 17px;
background-color: #fff;
color: #000;
margin: 0;
padding: 0;
}
div.document {
width: 940px;
margin: 30px auto 0 auto;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 220px;
}
div.sphinxsidebar {
width: 220px;
font-size: 14px;
line-height: 1.5;
}
hr {
border: 1px solid #B1B4B6;
}
div.body {
background-color: #fff;
color: #3E4349;
padding: 0 30px 0 30px;
}
div.body > .section {
text-align: left;
}
div.footer {
width: 940px;
margin: 20px auto 30px auto;
font-size: 14px;
color: #888;
text-align: right;
}
div.footer a {
color: #888;
}
p.caption {
font-family: inherit;
font-size: inherit;
}
div.relations {
display: none;
}
div.sphinxsidebar a {
color: #444;
text-decoration: none;
border-bottom: 1px dotted #999;
}
div.sphinxsidebar a:hover {
border-bottom: 1px solid #999;
}
div.sphinxsidebarwrapper {
padding: 18px 10px;
}
div.sphinxsidebarwrapper p.logo {
padding: 0;
margin: -10px 0 0 0px;
text-align: center;
}
div.sphinxsidebarwrapper h1.logo {
margin-top: -10px;
text-align: center;
margin-bottom: 5px;
text-align: left;
}
div.sphinxsidebarwrapper h1.logo-name {
margin-top: 0px;
}
div.sphinxsidebarwrapper p.blurb {
margin-top: 0;
font-style: normal;
}
div.sphinxsidebar h3,
div.sphinxsidebar h4 {
font-family: Georgia, serif;
color: #444;
font-size: 24px;
font-weight: normal;
margin: 0 0 5px 0;
padding: 0;
}
div.sphinxsidebar h4 {
font-size: 20px;
}
div.sphinxsidebar h3 a {
color: #444;
}
div.sphinxsidebar p.logo a,
div.sphinxsidebar h3 a,
div.sphinxsidebar p.logo a:hover,
div.sphinxsidebar h3 a:hover {
border: none;
}
div.sphinxsidebar p {
color: #555;
margin: 10px 0;
}
div.sphinxsidebar ul {
margin: 10px 0;
padding: 0;
color: #000;
}
div.sphinxsidebar ul li.toctree-l1 > a {
font-size: 120%;
}
div.sphinxsidebar ul li.toctree-l2 > a {
font-size: 110%;
}
div.sphinxsidebar input {
border: 1px solid #CCC;
font-family: Georgia, serif;
font-size: 1em;
}
div.sphinxsidebar hr {
border: none;
height: 1px;
color: #AAA;
background: #AAA;
text-align: left;
margin-left: 0;
width: 50%;
}
div.sphinxsidebar .badge {
border-bottom: none;
}
div.sphinxsidebar .badge:hover {
border-bottom: none;
}
/* To address an issue with donation coming after search */
div.sphinxsidebar h3.donation {
margin-top: 10px;
}
/* -- body styles ----------------------------------------------------------- */
a {
color: #004B6B;
text-decoration: underline;
}
a:hover {
color: #6D4100;
text-decoration: underline;
}
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: Georgia, serif;
font-weight: normal;
margin: 30px 0px 10px 0px;
padding: 0;
}
div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; }
div.body h2 { font-size: 180%; }
div.body h3 { font-size: 150%; }
div.body h4 { font-size: 130%; }
div.body h5 { font-size: 100%; }
div.body h6 { font-size: 100%; }
a.headerlink {
color: #DDD;
padding: 0 4px;
text-decoration: none;
}
a.headerlink:hover {
color: #444;
background: #EAEAEA;
}
div.body p, div.body dd, div.body li {
line-height: 1.4em;
}
div.admonition {
margin: 20px 0px;
padding: 10px 30px;
background-color: #EEE;
border: 1px solid #CCC;
}
div.admonition tt.xref, div.admonition code.xref, div.admonition a tt {
background-color: #FBFBFB;
border-bottom: 1px solid #fafafa;
}
div.admonition p.admonition-title {
font-family: Georgia, serif;
font-weight: normal;
font-size: 24px;
margin: 0 0 10px 0;
padding: 0;
line-height: 1;
}
div.admonition p.last {
margin-bottom: 0;
}
div.highlight {
background-color: #fff;
}
dt:target, .highlight {
background: #FAF3E8;
}
div.warning {
background-color: #FCC;
border: 1px solid #FAA;
}
div.danger {
background-color: #FCC;
border: 1px solid #FAA;
-moz-box-shadow: 2px 2px 4px #D52C2C;
-webkit-box-shadow: 2px 2px 4px #D52C2C;
box-shadow: 2px 2px 4px #D52C2C;
}
div.error {
background-color: #FCC;
border: 1px solid #FAA;
-moz-box-shadow: 2px 2px 4px #D52C2C;
-webkit-box-shadow: 2px 2px 4px #D52C2C;
box-shadow: 2px 2px 4px #D52C2C;
}
div.caution {
background-color: #FCC;
border: 1px solid #FAA;
}
div.attention {
background-color: #FCC;
border: 1px solid #FAA;
}
div.important {
background-color: #EEE;
border: 1px solid #CCC;
}
div.note {
background-color: #EEE;
border: 1px solid #CCC;
}
div.tip {
background-color: #EEE;
border: 1px solid #CCC;
}
div.hint {
background-color: #EEE;
border: 1px solid #CCC;
}
div.seealso {
background-color: #EEE;
border: 1px solid #CCC;
}
div.topic {
background-color: #EEE;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre, tt, code {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
font-size: 0.9em;
}
.hll {
background-color: #FFC;
margin: 0 -12px;
padding: 0 12px;
display: block;
}
img.screenshot {
}
tt.descname, tt.descclassname, code.descname, code.descclassname {
font-size: 0.95em;
}
tt.descname, code.descname {
padding-right: 0.08em;
}
img.screenshot {
-moz-box-shadow: 2px 2px 4px #EEE;
-webkit-box-shadow: 2px 2px 4px #EEE;
box-shadow: 2px 2px 4px #EEE;
}
table.docutils {
border: 1px solid #888;
-moz-box-shadow: 2px 2px 4px #EEE;
-webkit-box-shadow: 2px 2px 4px #EEE;
box-shadow: 2px 2px 4px #EEE;
}
table.docutils td, table.docutils th {
border: 1px solid #888;
padding: 0.25em 0.7em;
}
table.field-list, table.footnote {
border: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
}
table.footnote {
margin: 15px 0;
width: 100%;
border: 1px solid #EEE;
background: #FDFDFD;
font-size: 0.9em;
}
table.footnote + table.footnote {
margin-top: -15px;
border-top: none;
}
table.field-list th {
padding: 0 0.8em 0 0;
}
table.field-list td {
padding: 0;
}
table.field-list p {
margin-bottom: 0.8em;
}
/* Cloned from
* https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68
*/
.field-name {
-moz-hyphens: manual;
-ms-hyphens: manual;
-webkit-hyphens: manual;
hyphens: manual;
}
table.footnote td.label {
width: .1px;
padding: 0.3em 0 0.3em 0.5em;
}
table.footnote td {
padding: 0.3em 0.5em;
}
dl {
margin: 0;
padding: 0;
}
dl dd {
margin-left: 30px;
}
blockquote {
margin: 0 0 0 30px;
padding: 0;
}
ul, ol {
/* Matches the 30px from the narrow-screen "li > ul" selector below */
margin: 10px 0 10px 30px;
padding: 0;
}
pre {
background: #EEE;
padding: 7px 30px;
margin: 15px 0px;
line-height: 1.3em;
}
div.viewcode-block:target {
background: #ffd;
}
dl pre, blockquote pre, li pre {
margin-left: 0;
padding-left: 30px;
}
tt, code {
background-color: #ecf0f3;
color: #222;
/* padding: 1px 2px; */
}
tt.xref, code.xref, a tt {
background-color: #FBFBFB;
border-bottom: 1px solid #fff;
}
a.reference {
text-decoration: none;
border-bottom: 1px dotted #004B6B;
}
/* Don't put an underline on images */
a.image-reference, a.image-reference:hover {
border-bottom: none;
}
a.reference:hover {
border-bottom: 1px solid #6D4100;
}
a.footnote-reference {
text-decoration: none;
font-size: 0.7em;
vertical-align: top;
border-bottom: 1px dotted #004B6B;
}
a.footnote-reference:hover {
border-bottom: 1px solid #6D4100;
}
a:hover tt, a:hover code {
background: #EEE;
}
@media screen and (max-width: 870px) {
div.sphinxsidebar {
display: none;
}
div.document {
width: 100%;
}
div.documentwrapper {
margin-left: 0;
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
}
div.bodywrapper {
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: 0;
}
ul {
margin-left: 0;
}
li > ul {
/* Matches the 30px from the "ul, ol" selector above */
margin-left: 30px;
}
.document {
width: auto;
}
.footer {
width: auto;
}
.bodywrapper {
margin: 0;
}
.footer {
width: auto;
}
.github {
display: none;
}
}
@media screen and (max-width: 875px) {
body {
margin: 0;
padding: 20px 30px;
}
div.documentwrapper {
float: none;
background: #fff;
}
div.sphinxsidebar {
display: block;
float: none;
width: 102.5%;
margin: 50px -30px -20px -30px;
padding: 10px 20px;
background: #333;
color: #FFF;
}
div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p,
div.sphinxsidebar h3 a {
color: #fff;
}
div.sphinxsidebar a {
color: #AAA;
}
div.sphinxsidebar p.logo {
display: none;
}
div.document {
width: 100%;
margin: 0;
}
div.footer {
display: none;
}
div.bodywrapper {
margin: 0;
}
div.body {
min-height: 0;
padding: 0;
}
.rtd_doc_footer {
display: none;
}
.document {
width: auto;
}
.footer {
width: auto;
}
.footer {
width: auto;
}
.github {
display: none;
}
}
/* misc. */
.revsys-inline {
display: none!important;
}
/* Make nested-list/multi-paragraph items look better in Releases changelog
* pages. Without this, docutils' magical list fuckery causes inconsistent
* formatting between different release sub-lists.
*/
div#changelog > div.section > ul > li > p:only-child {
margin-bottom: 0;
}
/* Hide fugly table cell borders in ..bibliography:: directive output */
table.docutils.citation, table.docutils.citation td, table.docutils.citation th {
border: none;
/* Below needed in some edge cases; if not applied, bottom shadows appear */
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
}
/* relbar */
.related {
line-height: 30px;
width: 100%;
font-size: 0.9rem;
}
.related.top {
border-bottom: 1px solid #EEE;
margin-bottom: 20px;
}
.related.bottom {
border-top: 1px solid #EEE;
}
.related ul {
padding: 0;
margin: 0;
list-style: none;
}
.related li {
display: inline;
}
nav#rellinks {
float: right;
}
nav#rellinks li+li:before {
content: "|";
}
nav#breadcrumbs li+li:before {
content: "\00BB";
}
/* Hide certain items when printing */
@media print {
div.related {
display: none;
}
}

View File

@ -1,900 +0,0 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
div.section::after {
display: block;
content: '';
clear: left;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
word-wrap: break-word;
overflow-wrap : break-word;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar #searchbox form.search {
overflow: hidden;
}
div.sphinxsidebar #searchbox input[type="text"] {
float: left;
width: 80%;
padding: 0.25em;
box-sizing: border-box;
}
div.sphinxsidebar #searchbox input[type="submit"] {
float: left;
width: 20%;
border-left: none;
padding: 0.25em;
box-sizing: border-box;
}
img {
border: 0;
max-width: 100%;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li p.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
margin-left: auto;
margin-right: auto;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable ul {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
table.indextable > tbody > tr > td > ul {
padding-left: 0em;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- domain module index --------------------------------------------------- */
table.modindextable td {
padding: 2px;
border-collapse: collapse;
}
/* -- general body styles --------------------------------------------------- */
div.body {
min-width: 360px;
max-width: 800px;
}
div.body p, div.body dd, div.body li, div.body blockquote {
-moz-hyphens: auto;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink,
caption:hover > a.headerlink,
p.caption:hover > a.headerlink,
div.code-block-caption:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, figure.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, figure.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, figure.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
img.align-default, figure.align-default, .figure.align-default {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-default {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar,
aside.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px;
background-color: #ffe;
width: 40%;
float: right;
clear: right;
overflow-x: auto;
}
p.sidebar-title {
font-weight: bold;
}
nav.contents,
aside.topic,
div.admonition, div.topic, blockquote {
clear: left;
}
/* -- topics ---------------------------------------------------------------- */
nav.contents,
aside.topic,
div.topic {
border: 1px solid #ccc;
padding: 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- content of sidebars/topics/admonitions -------------------------------- */
div.sidebar > :last-child,
aside.sidebar > :last-child,
nav.contents > :last-child,
aside.topic > :last-child,
div.topic > :last-child,
div.admonition > :last-child {
margin-bottom: 0;
}
div.sidebar::after,
aside.sidebar::after,
nav.contents::after,
aside.topic::after,
div.topic::after,
div.admonition::after,
blockquote::after {
display: block;
content: '';
clear: both;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
margin-top: 10px;
margin-bottom: 10px;
border: 0;
border-collapse: collapse;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
table.align-default {
margin-left: auto;
margin-right: auto;
}
table caption span.caption-number {
font-style: italic;
}
table caption span.caption-text {
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
th > :first-child,
td > :first-child {
margin-top: 0px;
}
th > :last-child,
td > :last-child {
margin-bottom: 0px;
}
/* -- figures --------------------------------------------------------------- */
div.figure, figure {
margin: 0.5em;
padding: 0.5em;
}
div.figure p.caption, figcaption {
padding: 0.3em;
}
div.figure p.caption span.caption-number,
figcaption span.caption-number {
font-style: italic;
}
div.figure p.caption span.caption-text,
figcaption span.caption-text {
}
/* -- field list styles ----------------------------------------------------- */
table.field-list td, table.field-list th {
border: 0 !important;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.field-name {
-moz-hyphens: manual;
-ms-hyphens: manual;
-webkit-hyphens: manual;
hyphens: manual;
}
/* -- hlist styles ---------------------------------------------------------- */
table.hlist {
margin: 1em 0;
}
table.hlist td {
vertical-align: top;
}
/* -- object description styles --------------------------------------------- */
.sig {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
}
.sig-name, code.descname {
background-color: transparent;
font-weight: bold;
}
.sig-name {
font-size: 1.1em;
}
code.descname {
font-size: 1.2em;
}
.sig-prename, code.descclassname {
background-color: transparent;
}
.optional {
font-size: 1.3em;
}
.sig-paren {
font-size: larger;
}
.sig-param.n {
font-style: italic;
}
/* C++ specific styling */
.sig-inline.c-texpr,
.sig-inline.cpp-texpr {
font-family: unset;
}
.sig.c .k, .sig.c .kt,
.sig.cpp .k, .sig.cpp .kt {
color: #0033B3;
}
.sig.c .m,
.sig.cpp .m {
color: #1750EB;
}
.sig.c .s, .sig.c .sc,
.sig.cpp .s, .sig.cpp .sc {
color: #067D17;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
:not(li) > ol > li:first-child > :first-child,
:not(li) > ul > li:first-child > :first-child {
margin-top: 0px;
}
:not(li) > ol > li:last-child > :last-child,
:not(li) > ul > li:last-child > :last-child {
margin-bottom: 0px;
}
ol.simple ol p,
ol.simple ul p,
ul.simple ol p,
ul.simple ul p {
margin-top: 0;
}
ol.simple > li:not(:first-child) > p,
ul.simple > li:not(:first-child) > p {
margin-top: 0;
}
ol.simple p,
ul.simple p {
margin-bottom: 0;
}
aside.footnote > span,
div.citation > span {
float: left;
}
aside.footnote > span:last-of-type,
div.citation > span:last-of-type {
padding-right: 0.5em;
}
aside.footnote > p {
margin-left: 2em;
}
div.citation > p {
margin-left: 4em;
}
aside.footnote > p:last-of-type,
div.citation > p:last-of-type {
margin-bottom: 0em;
}
aside.footnote > p:last-of-type:after,
div.citation > p:last-of-type:after {
content: "";
clear: both;
}
dl.field-list {
display: grid;
grid-template-columns: fit-content(30%) auto;
}
dl.field-list > dt {
font-weight: bold;
word-break: break-word;
padding-left: 0.5em;
padding-right: 5px;
}
dl.field-list > dd {
padding-left: 0.5em;
margin-top: 0em;
margin-left: 0em;
margin-bottom: 0em;
}
dl {
margin-bottom: 15px;
}
dd > :first-child {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dl > dd:last-child,
dl > dd:last-child > :last-child {
margin-bottom: 0;
}
dt:target, span.highlighted {
background-color: #fbe54e;
}
rect.highlighted {
fill: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
.classifier:before {
font-style: normal;
margin: 0 0.5em;
content: ":";
display: inline-block;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
pre, div[class*="highlight-"] {
clear: both;
}
span.pre {
-moz-hyphens: none;
-ms-hyphens: none;
-webkit-hyphens: none;
hyphens: none;
white-space: nowrap;
}
div[class*="highlight-"] {
margin: 1em 0;
}
td.linenos pre {
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
display: block;
}
table.highlighttable tbody {
display: block;
}
table.highlighttable tr {
display: flex;
}
table.highlighttable td {
margin: 0;
padding: 0;
}
table.highlighttable td.linenos {
padding-right: 0.5em;
}
table.highlighttable td.code {
flex: 1;
overflow: hidden;
}
.highlight .hll {
display: block;
}
div.highlight pre,
table.highlighttable pre {
margin: 0;
}
div.code-block-caption + div {
margin-top: 0;
}
div.code-block-caption {
margin-top: 1em;
padding: 2px 5px;
font-size: small;
}
div.code-block-caption code {
background-color: transparent;
}
table.highlighttable td.linenos,
span.linenos,
div.highlight span.gp { /* gp: Generic.Prompt */
user-select: none;
-webkit-user-select: text; /* Safari fallback only */
-webkit-user-select: none; /* Chrome/Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+ */
}
div.code-block-caption span.caption-number {
padding: 0.1em 0.3em;
font-style: italic;
}
div.code-block-caption span.caption-text {
}
div.literal-block-wrapper {
margin: 1em 0;
}
code.xref, a code {
background-color: transparent;
font-weight: bold;
}
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
span.eqno a.headerlink {
position: absolute;
z-index: 1;
}
div.math:hover a.headerlink {
visibility: visible;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

View File

@ -1 +0,0 @@
/* This file intentionally left blank. */

View File

@ -1 +0,0 @@
../../../../javascript/sphinxdoc/1.0/doctools.js

View File

@ -1,14 +0,0 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.1.0',
LANGUAGE: 'en',
COLLAPSE_INDEX: false,
BUILDER: 'html',
FILE_SUFFIX: '.html',
LINK_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt',
NAVIGATION_WITH_KEYS: false,
SHOW_SEARCH_SUMMARY: true,
ENABLE_SEARCH_SHORTCUTS: true,
};

View File

@ -1 +0,0 @@
../../../../javascript/sphinxdoc/1.0/jquery.js

View File

@ -1 +0,0 @@
../../../../javascript/sphinxdoc/1.0/language_data.js

View File

@ -1,83 +0,0 @@
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight { background: #f8f8f8; }
.highlight .c { color: #8f5902; font-style: italic } /* Comment */
.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */
.highlight .g { color: #000000 } /* Generic */
.highlight .k { color: #004461; font-weight: bold } /* Keyword */
.highlight .l { color: #000000 } /* Literal */
.highlight .n { color: #000000 } /* Name */
.highlight .o { color: #582800 } /* Operator */
.highlight .x { color: #000000 } /* Other */
.highlight .p { color: #000000; font-weight: bold } /* Punctuation */
.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #8f5902 } /* Comment.Preproc */
.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */
.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */
.highlight .gd { color: #a40000 } /* Generic.Deleted */
.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
.highlight .gr { color: #ef2929 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #745334 } /* Generic.Prompt */
.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */
.highlight .ld { color: #000000 } /* Literal.Date */
.highlight .m { color: #990000 } /* Literal.Number */
.highlight .s { color: #4e9a06 } /* Literal.String */
.highlight .na { color: #c4a000 } /* Name.Attribute */
.highlight .nb { color: #004461 } /* Name.Builtin */
.highlight .nc { color: #000000 } /* Name.Class */
.highlight .no { color: #000000 } /* Name.Constant */
.highlight .nd { color: #888888 } /* Name.Decorator */
.highlight .ni { color: #ce5c00 } /* Name.Entity */
.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #000000 } /* Name.Function */
.highlight .nl { color: #f57900 } /* Name.Label */
.highlight .nn { color: #000000 } /* Name.Namespace */
.highlight .nx { color: #000000 } /* Name.Other */
.highlight .py { color: #000000 } /* Name.Property */
.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #000000 } /* Name.Variable */
.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */
.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */
.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */
.highlight .mb { color: #990000 } /* Literal.Number.Bin */
.highlight .mf { color: #990000 } /* Literal.Number.Float */
.highlight .mh { color: #990000 } /* Literal.Number.Hex */
.highlight .mi { color: #990000 } /* Literal.Number.Integer */
.highlight .mo { color: #990000 } /* Literal.Number.Oct */
.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */
.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */
.highlight .sc { color: #4e9a06 } /* Literal.String.Char */
.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */
.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */
.highlight .se { color: #4e9a06 } /* Literal.String.Escape */
.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */
.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */
.highlight .sx { color: #4e9a06 } /* Literal.String.Other */
.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */
.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */
.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */
.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #000000 } /* Name.Function.Magic */
.highlight .vc { color: #000000 } /* Name.Variable.Class */
.highlight .vg { color: #000000 } /* Name.Variable.Global */
.highlight .vi { color: #000000 } /* Name.Variable.Instance */
.highlight .vm { color: #000000 } /* Name.Variable.Magic */
.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */

View File

@ -1 +0,0 @@
../../../../javascript/sphinxdoc/1.0/searchtools.js

View File

@ -1 +0,0 @@
../../../../javascript/sphinxdoc/1.0/sphinx_highlight.js

View File

@ -1 +0,0 @@
../../../../javascript/sphinxdoc/1.0/underscore.js

View File

@ -1,614 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Index &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="#" />
<link rel="search" title="Search" href="search.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<h1 id="index">Index</h1>
<div class="genindex-jumpbox">
<a href="#_"><strong>_</strong></a>
| <a href="#A"><strong>A</strong></a>
| <a href="#B"><strong>B</strong></a>
| <a href="#C"><strong>C</strong></a>
| <a href="#D"><strong>D</strong></a>
| <a href="#E"><strong>E</strong></a>
| <a href="#G"><strong>G</strong></a>
| <a href="#I"><strong>I</strong></a>
| <a href="#L"><strong>L</strong></a>
| <a href="#M"><strong>M</strong></a>
| <a href="#N"><strong>N</strong></a>
| <a href="#P"><strong>P</strong></a>
| <a href="#R"><strong>R</strong></a>
| <a href="#S"><strong>S</strong></a>
| <a href="#T"><strong>T</strong></a>
| <a href="#U"><strong>U</strong></a>
| <a href="#V"><strong>V</strong></a>
</div>
<h2 id="_">_</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.__init__">__init__() (compute.instance.guest_agent.GuestAgent method)</a>
<ul>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.__init__">(compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.InstanceConfig.__init__">(compute.instance.instance.InstanceConfig method)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Session.__init__">(compute.session.Session method)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePool.__init__">(compute.storage.pool.StoragePool method)</a>
</li>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.DiskConfig.__init__">(compute.storage.volume.DiskConfig method)</a>
</li>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.Volume.__init__">(compute.storage.volume.Volume method)</a>
</li>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.VolumeConfig.__init__">(compute.storage.volume.VolumeConfig method)</a>
</li>
</ul></li>
</ul></td>
</tr></table>
<h2 id="A">A</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePoolUsageInfo.allocation">allocation (compute.storage.pool.StoragePoolUsageInfo attribute)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Capabilities.arch">arch (compute.session.Capabilities attribute)</a>
<ul>
<li><a href="pyapi/session.html#compute.session.NodeInfo.arch">(compute.session.NodeInfo attribute)</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.attach_device">attach_device() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePoolUsageInfo.available">available (compute.storage.pool.StoragePoolUsageInfo attribute)</a>
</li>
</ul></td>
</tr></table>
<h2 id="B">B</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.BootOptionsSchema">BootOptionsSchema (class in compute.instance.schemas)</a>
</li>
</ul></td>
</tr></table>
<h2 id="C">C</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.Capabilities">Capabilities (class in compute.session)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePoolUsageInfo.capacity">capacity (compute.storage.pool.StoragePoolUsageInfo attribute)</a>
</li>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.Volume.clone">clone() (compute.storage.volume.Volume method)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePool.clone_volume">clone_volume() (compute.storage.pool.StoragePool method)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Session.close">close() (compute.session.Session method)</a>
</li>
<li>
compute.exceptions
<ul>
<li><a href="pyapi/exceptions.html#module-compute.exceptions">module</a>
</li>
</ul></li>
<li>
compute.instance.guest_agent
<ul>
<li><a href="pyapi/instance/guest_agent.html#module-compute.instance.guest_agent">module</a>
</li>
</ul></li>
<li>
compute.instance.instance
<ul>
<li><a href="pyapi/instance/instance.html#module-compute.instance.instance">module</a>
</li>
</ul></li>
<li>
compute.instance.schemas
<ul>
<li><a href="pyapi/instance/schemas.html#module-compute.instance.schemas">module</a>
</li>
</ul></li>
<li>
compute.session
<ul>
<li><a href="pyapi/session.html#module-compute.session">module</a>
</li>
</ul></li>
<li>
compute.storage.pool
<ul>
<li><a href="pyapi/storage/pool.html#module-compute.storage.pool">module</a>
</li>
</ul></li>
<li>
compute.storage.volume
<ul>
<li><a href="pyapi/storage/volume.html#module-compute.storage.volume">module</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li>
compute.utils.ids
<ul>
<li><a href="pyapi/utils.html#module-compute.utils.ids">module</a>
</li>
</ul></li>
<li>
compute.utils.units
<ul>
<li><a href="pyapi/utils.html#module-compute.utils.units">module</a>
</li>
</ul></li>
<li><a href="pyapi/exceptions.html#compute.exceptions.ComputeError">ComputeError</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.ConfigLoaderError">ConfigLoaderError</a>
</li>
<li><a href="pyapi/session.html#compute.session.NodeInfo.cores">cores (compute.session.NodeInfo attribute)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Capabilities.cpu_features">cpu_features (compute.session.Capabilities attribute)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Capabilities.cpu_model">cpu_model (compute.session.Capabilities attribute)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Capabilities.cpu_vendor">cpu_vendor (compute.session.Capabilities attribute)</a>
</li>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.CPUEmulationMode">CPUEmulationMode (class in compute.instance.schemas)</a>
</li>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.CPUFeaturesSchema">CPUFeaturesSchema (class in compute.instance.schemas)</a>
</li>
<li><a href="pyapi/session.html#compute.session.NodeInfo.cpus">cpus (compute.session.NodeInfo attribute)</a>
</li>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.CPUSchema">CPUSchema (class in compute.instance.schemas)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.InstanceInfo.cputime">cputime (compute.instance.instance.InstanceInfo attribute)</a>
</li>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.CPUTopologySchema">CPUTopologySchema (class in compute.instance.schemas)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Session.create_instance">create_instance() (compute.session.Session method)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePool.create_volume">create_volume() (compute.storage.pool.StoragePool method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="D">D</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/utils.html#compute.utils.units.DataUnit">DataUnit (class in compute.utils.units)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.delete">delete() (compute.instance.instance.Instance method)</a>
<ul>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.Volume.delete">(compute.storage.volume.Volume method)</a>
</li>
</ul></li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.delete_ssh_keys">delete_ssh_keys() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.detach_device">detach_device() (compute.instance.instance.Instance method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.detach_disk">detach_disk() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.DiskConfig">DiskConfig (class in compute.storage.volume)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.dump_xml">dump_xml() (compute.instance.instance.Instance method)</a>
<ul>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePool.dump_xml">(compute.storage.pool.StoragePool method)</a>
</li>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.Volume.dump_xml">(compute.storage.volume.Volume method)</a>
</li>
</ul></li>
</ul></td>
</tr></table>
<h2 id="E">E</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.Capabilities.emulator">emulator (compute.session.Capabilities attribute)</a>
</li>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.EntityModel">EntityModel (class in compute.instance.schemas)</a>
</li>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.EntityModel.Config">EntityModel.Config (class in compute.instance.schemas)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.execute">execute() (compute.instance.guest_agent.GuestAgent method)</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput.exitcode">exitcode (compute.instance.guest_agent.GuestExecOutput attribute)</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput.exited">exited (compute.instance.guest_agent.GuestExecOutput attribute)</a>
</li>
</ul></td>
</tr></table>
<h2 id="G">G</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.Session.get_capabilities">get_capabilities() (compute.session.Session method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.get_disks">get_disks() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.get_info">get_info() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Session.get_instance">get_instance() (compute.session.Session method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.get_max_memory">get_max_memory() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.get_max_vcpus">get_max_vcpus() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Session.get_node_info">get_node_info() (compute.session.Session method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.get_ssh_keys">get_ssh_keys() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.get_status">get_status() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Session.get_storage_pool">get_storage_pool() (compute.session.Session method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.get_supported_commands">get_supported_commands() (compute.instance.guest_agent.GuestAgent method)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePool.get_usage_info">get_usage_info() (compute.storage.pool.StoragePool method)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePool.get_volume">get_volume() (compute.storage.pool.StoragePool method)</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.guest_exec">guest_exec() (compute.instance.guest_agent.GuestAgent method)</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.guest_exec_status">guest_exec_status() (compute.instance.guest_agent.GuestAgent method)</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestAgent">GuestAgent (class in compute.instance.guest_agent)</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.GuestAgentCommandNotSupportedError">GuestAgentCommandNotSupportedError</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.GuestAgentError">GuestAgentError</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.GuestAgentTimeoutExceededError">GuestAgentTimeoutExceededError</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.GuestAgentUnavailableError">GuestAgentUnavailableError</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput">GuestExecOutput (class in compute.instance.guest_agent)</a>
</li>
</ul></td>
</tr></table>
<h2 id="I">I</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance">Instance (class in compute.instance.instance)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.InstanceConfig">InstanceConfig (class in compute.instance.instance)</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.InstanceError">InstanceError</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.InstanceInfo">InstanceInfo (class in compute.instance.instance)</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.InstanceNotFoundError">InstanceNotFoundError</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.InstanceSchema">InstanceSchema (class in compute.instance.schemas)</a>
</li>
<li><a href="pyapi/utils.html#compute.utils.units.InvalidDataUnitError">InvalidDataUnitError</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.is_autostart">is_autostart() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.is_available">is_available() (compute.instance.guest_agent.GuestAgent method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.is_running">is_running() (compute.instance.instance.Instance method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="L">L</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.Session.list_instances">list_instances() (compute.session.Session method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.Session.list_storage_pools">list_storage_pools() (compute.session.Session method)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePool.list_volumes">list_volumes() (compute.storage.pool.StoragePool method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="M">M</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.Capabilities.machine">machine (compute.session.Capabilities attribute)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.InstanceInfo.max_memory">max_memory (compute.instance.instance.InstanceInfo attribute)</a>
</li>
<li><a href="pyapi/session.html#compute.session.Capabilities.max_vcpus">max_vcpus (compute.session.Capabilities attribute)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.InstanceInfo.memory">memory (compute.instance.instance.InstanceInfo attribute)</a>
<ul>
<li><a href="pyapi/session.html#compute.session.NodeInfo.memory">(compute.session.NodeInfo attribute)</a>
</li>
</ul></li>
<li><a href="pyapi/session.html#compute.session.NodeInfo.mhz">mhz (compute.session.NodeInfo attribute)</a>
</li>
<li>
module
<ul>
<li><a href="pyapi/exceptions.html#module-compute.exceptions">compute.exceptions</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#module-compute.instance.guest_agent">compute.instance.guest_agent</a>
</li>
<li><a href="pyapi/instance/instance.html#module-compute.instance.instance">compute.instance.instance</a>
</li>
<li><a href="pyapi/instance/schemas.html#module-compute.instance.schemas">compute.instance.schemas</a>
</li>
<li><a href="pyapi/session.html#module-compute.session">compute.session</a>
</li>
<li><a href="pyapi/storage/pool.html#module-compute.storage.pool">compute.storage.pool</a>
</li>
<li><a href="pyapi/storage/volume.html#module-compute.storage.volume">compute.storage.volume</a>
</li>
<li><a href="pyapi/utils.html#module-compute.utils.ids">compute.utils.ids</a>
</li>
<li><a href="pyapi/utils.html#module-compute.utils.units">compute.utils.units</a>
</li>
</ul></li>
</ul></td>
</tr></table>
<h2 id="N">N</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.NetworkInterfaceSchema">NetworkInterfaceSchema (class in compute.instance.schemas)</a>
</li>
<li><a href="pyapi/session.html#compute.session.NodeInfo">NodeInfo (class in compute.session)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.NodeInfo.nodes">nodes (compute.session.NodeInfo attribute)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.InstanceInfo.nproc">nproc (compute.instance.instance.InstanceInfo attribute)</a>
</li>
</ul></td>
</tr></table>
<h2 id="P">P</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.pause">pause() (compute.instance.instance.Instance method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.power_reset">power_reset() (compute.instance.instance.Instance method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="R">R</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.raise_for_commands">raise_for_commands() (compute.instance.guest_agent.GuestAgent method)</a>
</li>
<li><a href="pyapi/utils.html#compute.utils.ids.random_mac">random_mac() (in module compute.utils.ids)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.reboot">reboot() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePool.refresh">refresh() (compute.storage.pool.StoragePool method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.reset">reset() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.Volume.resize">resize() (compute.storage.volume.Volume method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.resize_disk">resize_disk() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.resume">resume() (compute.instance.instance.Instance method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="S">S</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.Session">Session (class in compute.session)</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.SessionError">SessionError</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.set_autostart">set_autostart() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.set_memory">set_memory() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.set_ssh_keys">set_ssh_keys() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.set_user_password">set_user_password() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.set_vcpus">set_vcpus() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.shutdown">shutdown() (compute.instance.instance.Instance method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.NodeInfo.sockets">sockets (compute.session.NodeInfo attribute)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.Instance.start">start() (compute.instance.instance.Instance method)</a>
</li>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.InstanceInfo.state">state (compute.instance.instance.InstanceInfo attribute)</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput.stderr">stderr (compute.instance.guest_agent.GuestExecOutput attribute)</a>
</li>
<li><a href="pyapi/instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput.stdout">stdout (compute.instance.guest_agent.GuestExecOutput attribute)</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePool">StoragePool (class in compute.storage.pool)</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.StoragePoolError">StoragePoolError</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.StoragePoolNotFoundError">StoragePoolNotFoundError</a>
</li>
<li><a href="pyapi/storage/pool.html#compute.storage.pool.StoragePoolUsageInfo">StoragePoolUsageInfo (class in compute.storage.pool)</a>
</li>
</ul></td>
</tr></table>
<h2 id="T">T</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.NodeInfo.threads">threads (compute.session.NodeInfo attribute)</a>
</li>
<li><a href="pyapi/utils.html#compute.utils.units.to_bytes">to_bytes() (in module compute.utils.units)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/instance/instance.html#compute.instance.instance.InstanceConfig.to_xml">to_xml() (compute.instance.instance.InstanceConfig method)</a>
<ul>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.DiskConfig.to_xml">(compute.storage.volume.DiskConfig method)</a>
</li>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.VolumeConfig.to_xml">(compute.storage.volume.VolumeConfig method)</a>
</li>
</ul></li>
</ul></td>
</tr></table>
<h2 id="U">U</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.Capabilities.usable_cpus">usable_cpus (compute.session.Capabilities attribute)</a>
</li>
</ul></td>
</tr></table>
<h2 id="V">V</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/session.html#compute.session.Capabilities.virt_type">virt_type (compute.session.Capabilities attribute)</a>
</li>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.Volume">Volume (class in compute.storage.volume)</a>
</li>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.VolumeCapacitySchema">VolumeCapacitySchema (class in compute.instance.schemas)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="pyapi/storage/volume.html#compute.storage.volume.VolumeConfig">VolumeConfig (class in compute.storage.volume)</a>
</li>
<li><a href="pyapi/exceptions.html#compute.exceptions.VolumeNotFoundError">VolumeNotFoundError</a>
</li>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.VolumeSchema">VolumeSchema (class in compute.instance.schemas)</a>
</li>
<li><a href="pyapi/instance/schemas.html#compute.instance.schemas.VolumeType">VolumeType (class in compute.instance.schemas)</a>
</li>
</ul></td>
</tr></table>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul>
<li class="toctree-l1"><a class="reference internal" href="pyapi/index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
</div>
</body>
</html>

View File

@ -1,122 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>Compute &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Python API" href="pyapi/index.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="compute">
<h1>Compute<a class="headerlink" href="#compute" title="Permalink to this heading"></a></h1>
<p>Compute instances management library.</p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="pyapi/index.html">Python API</a></li>
</ul>
</div>
<section id="indices-and-tables">
<h2>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this heading"></a></h2>
<ul class="simple">
<li><p><a class="reference internal" href="genindex.html"><span class="std std-ref">Index</span></a></p></li>
<li><p><a class="reference internal" href="py-modindex.html"><span class="std std-ref">Module Index</span></a></p></li>
<li><p><a class="reference internal" href="search.html"><span class="std std-ref">Search Page</span></a></p></li>
</ul>
</section>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="#">Compute</a></h1>
<h3>Navigation</h3>
<ul>
<li class="toctree-l1"><a class="reference internal" href="pyapi/index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="#">Documentation overview</a><ul>
<li>Next: <a href="pyapi/index.html" title="next chapter">Python API</a></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="_sources/index.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,165 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Python Module Index &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<h1>Python Module Index</h1>
<div class="modindex-jumpbox">
<a href="#cap-c"><strong>c</strong></a>
</div>
<table class="indextable modindextable">
<tr class="pcap"><td></td><td>&#160;</td><td></td></tr>
<tr class="cap" id="cap-c"><td></td><td>
<strong>c</strong></td><td></td></tr>
<tr>
<td><img src="_static/minus.png" class="toggler"
id="toggle-1" style="display: none" alt="-" /></td>
<td>
<code class="xref">compute</code></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="pyapi/exceptions.html#module-compute.exceptions"><code class="xref">compute.exceptions</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="pyapi/instance/guest_agent.html#module-compute.instance.guest_agent"><code class="xref">compute.instance.guest_agent</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="pyapi/instance/instance.html#module-compute.instance.instance"><code class="xref">compute.instance.instance</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="pyapi/instance/schemas.html#module-compute.instance.schemas"><code class="xref">compute.instance.schemas</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="pyapi/session.html#module-compute.session"><code class="xref">compute.session</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="pyapi/storage/pool.html#module-compute.storage.pool"><code class="xref">compute.storage.pool</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="pyapi/storage/volume.html#module-compute.storage.volume"><code class="xref">compute.storage.volume</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="pyapi/utils.html#module-compute.utils.ids"><code class="xref">compute.utils.ids</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="pyapi/utils.html#module-compute.utils.units"><code class="xref">compute.utils.units</code></a></td><td>
<em></em></td></tr>
</table>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul>
<li class="toctree-l1"><a class="reference internal" href="pyapi/index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
</div>
</body>
</html>

View File

@ -1,183 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>exceptions &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/alabaster.css" />
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="prev" title="utils" href="utils.html" />
<link rel="stylesheet" href="../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="module-compute.exceptions">
<span id="exceptions"></span><h1><code class="docutils literal notranslate"><span class="pre">exceptions</span></code><a class="headerlink" href="#module-compute.exceptions" title="Permalink to this heading"></a></h1>
<p>Exceptions.</p>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.ComputeError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">ComputeError</span></span><a class="headerlink" href="#compute.exceptions.ComputeError" title="Permalink to this definition"></a></dt>
<dd><p>Basic exception class.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.ConfigLoaderError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">ConfigLoaderError</span></span><a class="headerlink" href="#compute.exceptions.ConfigLoaderError" title="Permalink to this definition"></a></dt>
<dd><p>Something went wrong when loading configuration.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.GuestAgentCommandNotSupportedError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">GuestAgentCommandNotSupportedError</span></span><a class="headerlink" href="#compute.exceptions.GuestAgentCommandNotSupportedError" title="Permalink to this definition"></a></dt>
<dd><p>Guest agent command is not supported or blacklisted on guest.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.GuestAgentError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">GuestAgentError</span></span><a class="headerlink" href="#compute.exceptions.GuestAgentError" title="Permalink to this definition"></a></dt>
<dd><p>Something went wring when QEMU Guest Agent call.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.GuestAgentTimeoutExceededError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">GuestAgentTimeoutExceededError</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">msg</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.exceptions.GuestAgentTimeoutExceededError" title="Permalink to this definition"></a></dt>
<dd><p>QEMU timeout exceeded.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.GuestAgentUnavailableError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">GuestAgentUnavailableError</span></span><a class="headerlink" href="#compute.exceptions.GuestAgentUnavailableError" title="Permalink to this definition"></a></dt>
<dd><p>Guest agent is not connected or is unavailable.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.InstanceError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">InstanceError</span></span><a class="headerlink" href="#compute.exceptions.InstanceError" title="Permalink to this definition"></a></dt>
<dd><p>Something went wrong while interacting with the domain.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.InstanceNotFoundError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">InstanceNotFoundError</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">msg</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.exceptions.InstanceNotFoundError" title="Permalink to this definition"></a></dt>
<dd><p>Virtual machine or container not found on compute node.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.SessionError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">SessionError</span></span><a class="headerlink" href="#compute.exceptions.SessionError" title="Permalink to this definition"></a></dt>
<dd><p>Something went wrong while connecting to libvirtd.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.StoragePoolError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">StoragePoolError</span></span><a class="headerlink" href="#compute.exceptions.StoragePoolError" title="Permalink to this definition"></a></dt>
<dd><p>Something went wrong when operating with storage pool.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.StoragePoolNotFoundError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">StoragePoolNotFoundError</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">msg</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.exceptions.StoragePoolNotFoundError" title="Permalink to this definition"></a></dt>
<dd><p>Storage pool not found.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.exceptions.VolumeNotFoundError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.exceptions.</span></span><span class="sig-name descname"><span class="pre">VolumeNotFoundError</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">msg</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.exceptions.VolumeNotFoundError" title="Permalink to this definition"></a></dt>
<dd><p>Storage volume not found.</p>
</dd></dl>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../index.html">Documentation overview</a><ul>
<li><a href="index.html">Python API</a><ul>
<li>Previous: <a href="utils.html" title="previous chapter"><code class="docutils literal notranslate"><span class="pre">utils</span></code></a></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../_sources/pyapi/exceptions.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,342 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>Python API &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/alabaster.css" />
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="session" href="session.html" />
<link rel="prev" title="Compute" href="../index.html" />
<link rel="stylesheet" href="../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="python-api">
<h1>Python API<a class="headerlink" href="#python-api" title="Permalink to this heading"></a></h1>
<p>The API allows you to perform actions on instances programmatically. Below is
an example of changing parameters and launching the <cite>myinstance</cite> instance.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">from</span> <span class="nn">compute</span> <span class="kn">import</span> <span class="n">Session</span>
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="k">with</span> <span class="n">Session</span><span class="p">()</span> <span class="k">as</span> <span class="n">session</span><span class="p">:</span>
<span class="n">instance</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">get_instance</span><span class="p">(</span><span class="s1">&#39;myinstance&#39;</span><span class="p">)</span>
<span class="n">instance</span><span class="o">.</span><span class="n">set_vcpus</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">instance</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">instance</span><span class="o">.</span><span class="n">set_autostart</span><span class="p">(</span><span class="n">enabled</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p><code class="xref py py-class docutils literal notranslate"><span class="pre">Session</span></code> context manager provides an abstraction over <code class="xref py py-class docutils literal notranslate"><span class="pre">libvirt.virConnect</span></code>
and returns objects of other classes of the present library.</p>
<section id="entity-representation">
<h2>Entity representation<a class="headerlink" href="#entity-representation" title="Permalink to this heading"></a></h2>
<p>Entities such as a compute-instance are represented as classes. These classes directly
call libvirt methods to perform operations on the hypervisor. An example class is
<code class="xref py py-class docutils literal notranslate"><span class="pre">Volume</span></code>.</p>
<p>The configuration files of various libvirt objects in <cite>compute</cite> are described by special
dataclasses. The dataclass stores object parameters in its properties and can return an
XML config for libvirt using the <code class="docutils literal notranslate"><span class="pre">to_xml()</span></code> method. For example <code class="xref py py-class docutils literal notranslate"><span class="pre">VolumeConfig</span></code>.</p>
<p><a class="reference external" href="https://docs.pydantic.dev/">Pydantic</a> models are used to validate input data.
For example <code class="xref py py-class docutils literal notranslate"><span class="pre">VolumeSchema</span></code>.</p>
</section>
<section id="modules-documentation">
<h2>Modules documentation<a class="headerlink" href="#modules-documentation" title="Permalink to this heading"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="session.html"><code class="docutils literal notranslate"><span class="pre">session</span></code></a><ul>
<li class="toctree-l2"><a class="reference internal" href="session.html#compute.session.Capabilities"><code class="docutils literal notranslate"><span class="pre">Capabilities</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Capabilities.arch"><code class="docutils literal notranslate"><span class="pre">Capabilities.arch</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Capabilities.cpu_features"><code class="docutils literal notranslate"><span class="pre">Capabilities.cpu_features</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Capabilities.cpu_model"><code class="docutils literal notranslate"><span class="pre">Capabilities.cpu_model</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Capabilities.cpu_vendor"><code class="docutils literal notranslate"><span class="pre">Capabilities.cpu_vendor</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Capabilities.emulator"><code class="docutils literal notranslate"><span class="pre">Capabilities.emulator</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Capabilities.machine"><code class="docutils literal notranslate"><span class="pre">Capabilities.machine</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Capabilities.max_vcpus"><code class="docutils literal notranslate"><span class="pre">Capabilities.max_vcpus</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Capabilities.usable_cpus"><code class="docutils literal notranslate"><span class="pre">Capabilities.usable_cpus</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Capabilities.virt_type"><code class="docutils literal notranslate"><span class="pre">Capabilities.virt_type</span></code></a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="session.html#compute.session.NodeInfo"><code class="docutils literal notranslate"><span class="pre">NodeInfo</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.NodeInfo.arch"><code class="docutils literal notranslate"><span class="pre">NodeInfo.arch</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.NodeInfo.cores"><code class="docutils literal notranslate"><span class="pre">NodeInfo.cores</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.NodeInfo.cpus"><code class="docutils literal notranslate"><span class="pre">NodeInfo.cpus</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.NodeInfo.memory"><code class="docutils literal notranslate"><span class="pre">NodeInfo.memory</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.NodeInfo.mhz"><code class="docutils literal notranslate"><span class="pre">NodeInfo.mhz</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.NodeInfo.nodes"><code class="docutils literal notranslate"><span class="pre">NodeInfo.nodes</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.NodeInfo.sockets"><code class="docutils literal notranslate"><span class="pre">NodeInfo.sockets</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.NodeInfo.threads"><code class="docutils literal notranslate"><span class="pre">NodeInfo.threads</span></code></a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="session.html#compute.session.Session"><code class="docutils literal notranslate"><span class="pre">Session</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Session.__init__"><code class="docutils literal notranslate"><span class="pre">Session.__init__()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Session.close"><code class="docutils literal notranslate"><span class="pre">Session.close()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Session.create_instance"><code class="docutils literal notranslate"><span class="pre">Session.create_instance()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Session.get_capabilities"><code class="docutils literal notranslate"><span class="pre">Session.get_capabilities()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Session.get_instance"><code class="docutils literal notranslate"><span class="pre">Session.get_instance()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Session.get_node_info"><code class="docutils literal notranslate"><span class="pre">Session.get_node_info()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Session.get_storage_pool"><code class="docutils literal notranslate"><span class="pre">Session.get_storage_pool()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Session.list_instances"><code class="docutils literal notranslate"><span class="pre">Session.list_instances()</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="session.html#compute.session.Session.list_storage_pools"><code class="docutils literal notranslate"><span class="pre">Session.list_storage_pools()</span></code></a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="instance/index.html"><code class="docutils literal notranslate"><span class="pre">instance</span></code></a><ul>
<li class="toctree-l2"><a class="reference internal" href="instance/instance.html"><code class="docutils literal notranslate"><span class="pre">instance</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance"><code class="docutils literal notranslate"><span class="pre">Instance</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.__init__"><code class="docutils literal notranslate"><span class="pre">Instance.__init__()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.attach_device"><code class="docutils literal notranslate"><span class="pre">Instance.attach_device()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.delete"><code class="docutils literal notranslate"><span class="pre">Instance.delete()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.delete_ssh_keys"><code class="docutils literal notranslate"><span class="pre">Instance.delete_ssh_keys()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.detach_device"><code class="docutils literal notranslate"><span class="pre">Instance.detach_device()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.detach_disk"><code class="docutils literal notranslate"><span class="pre">Instance.detach_disk()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.dump_xml"><code class="docutils literal notranslate"><span class="pre">Instance.dump_xml()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.get_disks"><code class="docutils literal notranslate"><span class="pre">Instance.get_disks()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.get_info"><code class="docutils literal notranslate"><span class="pre">Instance.get_info()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.get_max_memory"><code class="docutils literal notranslate"><span class="pre">Instance.get_max_memory()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.get_max_vcpus"><code class="docutils literal notranslate"><span class="pre">Instance.get_max_vcpus()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.get_ssh_keys"><code class="docutils literal notranslate"><span class="pre">Instance.get_ssh_keys()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.get_status"><code class="docutils literal notranslate"><span class="pre">Instance.get_status()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.is_autostart"><code class="docutils literal notranslate"><span class="pre">Instance.is_autostart()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.is_running"><code class="docutils literal notranslate"><span class="pre">Instance.is_running()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.pause"><code class="docutils literal notranslate"><span class="pre">Instance.pause()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.power_reset"><code class="docutils literal notranslate"><span class="pre">Instance.power_reset()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.reboot"><code class="docutils literal notranslate"><span class="pre">Instance.reboot()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.reset"><code class="docutils literal notranslate"><span class="pre">Instance.reset()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.resize_disk"><code class="docutils literal notranslate"><span class="pre">Instance.resize_disk()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.resume"><code class="docutils literal notranslate"><span class="pre">Instance.resume()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.set_autostart"><code class="docutils literal notranslate"><span class="pre">Instance.set_autostart()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.set_memory"><code class="docutils literal notranslate"><span class="pre">Instance.set_memory()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.set_ssh_keys"><code class="docutils literal notranslate"><span class="pre">Instance.set_ssh_keys()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.set_user_password"><code class="docutils literal notranslate"><span class="pre">Instance.set_user_password()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.set_vcpus"><code class="docutils literal notranslate"><span class="pre">Instance.set_vcpus()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.shutdown"><code class="docutils literal notranslate"><span class="pre">Instance.shutdown()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance.start"><code class="docutils literal notranslate"><span class="pre">Instance.start()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="instance/instance.html#compute.instance.instance.InstanceConfig"><code class="docutils literal notranslate"><span class="pre">InstanceConfig</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.InstanceConfig.__init__"><code class="docutils literal notranslate"><span class="pre">InstanceConfig.__init__()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.InstanceConfig.to_xml"><code class="docutils literal notranslate"><span class="pre">InstanceConfig.to_xml()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="instance/instance.html#compute.instance.instance.InstanceInfo"><code class="docutils literal notranslate"><span class="pre">InstanceInfo</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.InstanceInfo.cputime"><code class="docutils literal notranslate"><span class="pre">InstanceInfo.cputime</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.InstanceInfo.max_memory"><code class="docutils literal notranslate"><span class="pre">InstanceInfo.max_memory</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.InstanceInfo.memory"><code class="docutils literal notranslate"><span class="pre">InstanceInfo.memory</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.InstanceInfo.nproc"><code class="docutils literal notranslate"><span class="pre">InstanceInfo.nproc</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/instance.html#compute.instance.instance.InstanceInfo.state"><code class="docutils literal notranslate"><span class="pre">InstanceInfo.state</span></code></a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="instance/guest_agent.html"><code class="docutils literal notranslate"><span class="pre">guest_agent</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestAgent"><code class="docutils literal notranslate"><span class="pre">GuestAgent</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.__init__"><code class="docutils literal notranslate"><span class="pre">GuestAgent.__init__()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.execute"><code class="docutils literal notranslate"><span class="pre">GuestAgent.execute()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.get_supported_commands"><code class="docutils literal notranslate"><span class="pre">GuestAgent.get_supported_commands()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.guest_exec"><code class="docutils literal notranslate"><span class="pre">GuestAgent.guest_exec()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.guest_exec_status"><code class="docutils literal notranslate"><span class="pre">GuestAgent.guest_exec_status()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.is_available"><code class="docutils literal notranslate"><span class="pre">GuestAgent.is_available()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestAgent.raise_for_commands"><code class="docutils literal notranslate"><span class="pre">GuestAgent.raise_for_commands()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput"><code class="docutils literal notranslate"><span class="pre">GuestExecOutput</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput.exitcode"><code class="docutils literal notranslate"><span class="pre">GuestExecOutput.exitcode</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput.exited"><code class="docutils literal notranslate"><span class="pre">GuestExecOutput.exited</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput.stderr"><code class="docutils literal notranslate"><span class="pre">GuestExecOutput.stderr</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="instance/guest_agent.html#compute.instance.guest_agent.GuestExecOutput.stdout"><code class="docutils literal notranslate"><span class="pre">GuestExecOutput.stdout</span></code></a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="instance/schemas.html"><code class="docutils literal notranslate"><span class="pre">schemas</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.BootOptionsSchema"><code class="docutils literal notranslate"><span class="pre">BootOptionsSchema</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.CPUEmulationMode"><code class="docutils literal notranslate"><span class="pre">CPUEmulationMode</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.CPUFeaturesSchema"><code class="docutils literal notranslate"><span class="pre">CPUFeaturesSchema</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.CPUSchema"><code class="docutils literal notranslate"><span class="pre">CPUSchema</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.CPUTopologySchema"><code class="docutils literal notranslate"><span class="pre">CPUTopologySchema</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.EntityModel"><code class="docutils literal notranslate"><span class="pre">EntityModel</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.EntityModel.Config"><code class="docutils literal notranslate"><span class="pre">EntityModel.Config</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.InstanceSchema"><code class="docutils literal notranslate"><span class="pre">InstanceSchema</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.NetworkInterfaceSchema"><code class="docutils literal notranslate"><span class="pre">NetworkInterfaceSchema</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.VolumeCapacitySchema"><code class="docutils literal notranslate"><span class="pre">VolumeCapacitySchema</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.VolumeSchema"><code class="docutils literal notranslate"><span class="pre">VolumeSchema</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="instance/schemas.html#compute.instance.schemas.VolumeType"><code class="docutils literal notranslate"><span class="pre">VolumeType</span></code></a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="storage/index.html"><code class="docutils literal notranslate"><span class="pre">storage</span></code></a><ul>
<li class="toctree-l2"><a class="reference internal" href="storage/pool.html"><code class="docutils literal notranslate"><span class="pre">pool</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool"><code class="docutils literal notranslate"><span class="pre">StoragePool</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool.__init__"><code class="docutils literal notranslate"><span class="pre">StoragePool.__init__()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool.clone_volume"><code class="docutils literal notranslate"><span class="pre">StoragePool.clone_volume()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool.create_volume"><code class="docutils literal notranslate"><span class="pre">StoragePool.create_volume()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool.dump_xml"><code class="docutils literal notranslate"><span class="pre">StoragePool.dump_xml()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool.get_usage_info"><code class="docutils literal notranslate"><span class="pre">StoragePool.get_usage_info()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool.get_volume"><code class="docutils literal notranslate"><span class="pre">StoragePool.get_volume()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool.list_volumes"><code class="docutils literal notranslate"><span class="pre">StoragePool.list_volumes()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool.refresh"><code class="docutils literal notranslate"><span class="pre">StoragePool.refresh()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePoolUsageInfo"><code class="docutils literal notranslate"><span class="pre">StoragePoolUsageInfo</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePoolUsageInfo.allocation"><code class="docutils literal notranslate"><span class="pre">StoragePoolUsageInfo.allocation</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePoolUsageInfo.available"><code class="docutils literal notranslate"><span class="pre">StoragePoolUsageInfo.available</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePoolUsageInfo.capacity"><code class="docutils literal notranslate"><span class="pre">StoragePoolUsageInfo.capacity</span></code></a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="storage/volume.html"><code class="docutils literal notranslate"><span class="pre">volume</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="storage/volume.html#compute.storage.volume.DiskConfig"><code class="docutils literal notranslate"><span class="pre">DiskConfig</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="storage/volume.html#compute.storage.volume.DiskConfig.__init__"><code class="docutils literal notranslate"><span class="pre">DiskConfig.__init__()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/volume.html#compute.storage.volume.DiskConfig.to_xml"><code class="docutils literal notranslate"><span class="pre">DiskConfig.to_xml()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="storage/volume.html#compute.storage.volume.Volume"><code class="docutils literal notranslate"><span class="pre">Volume</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="storage/volume.html#compute.storage.volume.Volume.__init__"><code class="docutils literal notranslate"><span class="pre">Volume.__init__()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/volume.html#compute.storage.volume.Volume.clone"><code class="docutils literal notranslate"><span class="pre">Volume.clone()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/volume.html#compute.storage.volume.Volume.delete"><code class="docutils literal notranslate"><span class="pre">Volume.delete()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/volume.html#compute.storage.volume.Volume.dump_xml"><code class="docutils literal notranslate"><span class="pre">Volume.dump_xml()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/volume.html#compute.storage.volume.Volume.resize"><code class="docutils literal notranslate"><span class="pre">Volume.resize()</span></code></a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="storage/volume.html#compute.storage.volume.VolumeConfig"><code class="docutils literal notranslate"><span class="pre">VolumeConfig</span></code></a><ul>
<li class="toctree-l4"><a class="reference internal" href="storage/volume.html#compute.storage.volume.VolumeConfig.__init__"><code class="docutils literal notranslate"><span class="pre">VolumeConfig.__init__()</span></code></a></li>
<li class="toctree-l4"><a class="reference internal" href="storage/volume.html#compute.storage.volume.VolumeConfig.to_xml"><code class="docutils literal notranslate"><span class="pre">VolumeConfig.to_xml()</span></code></a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="utils.html"><code class="docutils literal notranslate"><span class="pre">utils</span></code></a><ul>
<li class="toctree-l2"><a class="reference internal" href="utils.html#module-compute.utils.units"><code class="docutils literal notranslate"><span class="pre">utils.units</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="utils.html#compute.utils.units.DataUnit"><code class="docutils literal notranslate"><span class="pre">DataUnit</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="utils.html#compute.utils.units.InvalidDataUnitError"><code class="docutils literal notranslate"><span class="pre">InvalidDataUnitError</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="utils.html#compute.utils.units.to_bytes"><code class="docutils literal notranslate"><span class="pre">to_bytes()</span></code></a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="utils.html#module-compute.utils.ids"><code class="docutils literal notranslate"><span class="pre">utils.ids</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="utils.html#compute.utils.ids.random_mac"><code class="docutils literal notranslate"><span class="pre">random_mac()</span></code></a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="exceptions.html"><code class="docutils literal notranslate"><span class="pre">exceptions</span></code></a><ul>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.ComputeError"><code class="docutils literal notranslate"><span class="pre">ComputeError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.ConfigLoaderError"><code class="docutils literal notranslate"><span class="pre">ConfigLoaderError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.GuestAgentCommandNotSupportedError"><code class="docutils literal notranslate"><span class="pre">GuestAgentCommandNotSupportedError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.GuestAgentError"><code class="docutils literal notranslate"><span class="pre">GuestAgentError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.GuestAgentTimeoutExceededError"><code class="docutils literal notranslate"><span class="pre">GuestAgentTimeoutExceededError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.GuestAgentUnavailableError"><code class="docutils literal notranslate"><span class="pre">GuestAgentUnavailableError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.InstanceError"><code class="docutils literal notranslate"><span class="pre">InstanceError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.InstanceNotFoundError"><code class="docutils literal notranslate"><span class="pre">InstanceNotFoundError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.SessionError"><code class="docutils literal notranslate"><span class="pre">SessionError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.StoragePoolError"><code class="docutils literal notranslate"><span class="pre">StoragePoolError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.StoragePoolNotFoundError"><code class="docutils literal notranslate"><span class="pre">StoragePoolNotFoundError</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="exceptions.html#compute.exceptions.VolumeNotFoundError"><code class="docutils literal notranslate"><span class="pre">VolumeNotFoundError</span></code></a></li>
</ul>
</li>
</ul>
</div>
</section>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="current reference internal" href="#">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../index.html">Documentation overview</a><ul>
<li>Previous: <a href="../index.html" title="previous chapter">Compute</a></li>
<li>Next: <a href="session.html" title="next chapter"><code class="docutils literal notranslate"><span class="pre">session</span></code></a></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../_sources/pyapi/index.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,266 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>guest_agent &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/alabaster.css" />
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/jquery.js"></script>
<script src="../../_static/underscore.js"></script>
<script src="../../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
<link rel="next" title="schemas" href="schemas.html" />
<link rel="prev" title="instance" href="instance.html" />
<link rel="stylesheet" href="../../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="module-compute.instance.guest_agent">
<span id="guest-agent"></span><h1><code class="docutils literal notranslate"><span class="pre">guest_agent</span></code><a class="headerlink" href="#module-compute.instance.guest_agent" title="Permalink to this heading"></a></h1>
<p>Interacting with the QEMU Guest Agent.</p>
<dl class="py class">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestAgent">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.instance.guest_agent.</span></span><span class="sig-name descname"><span class="pre">GuestAgent</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">domain</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virDomain</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">timeout</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">60</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.instance.guest_agent.GuestAgent" title="Permalink to this definition"></a></dt>
<dd><p>Class for interacting with QEMU guest agent.</p>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestAgent.__init__">
<span class="sig-name descname"><span class="pre">__init__</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">domain</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virDomain</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">timeout</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">60</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.instance.guest_agent.GuestAgent.__init__" title="Permalink to this definition"></a></dt>
<dd><p>Initialise GuestAgent.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>domain</strong> Libvirt domain object</p></li>
<li><p><strong>timeout</strong> QEMU timeout</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestAgent.execute">
<span class="sig-name descname"><span class="pre">execute</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">command</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">dict</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">dict</span></span></span><a class="headerlink" href="#compute.instance.guest_agent.GuestAgent.execute" title="Permalink to this definition"></a></dt>
<dd><p>Execute QEMU guest agent command.</p>
<p>See: <a class="reference external" href="https://qemu-project.gitlab.io/qemu/interop/qemu-ga-ref.html">https://qemu-project.gitlab.io/qemu/interop/qemu-ga-ref.html</a></p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>command</strong> QEMU guest agent command as dict</p>
</dd>
<dt class="field-even">Returns<span class="colon">:</span></dt>
<dd class="field-even"><p>Command output</p>
</dd>
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p>dict</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestAgent.get_supported_commands">
<span class="sig-name descname"><span class="pre">get_supported_commands</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">set</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span></span><a class="headerlink" href="#compute.instance.guest_agent.GuestAgent.get_supported_commands" title="Permalink to this definition"></a></dt>
<dd><p>Return set of supported guest agent commands.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestAgent.guest_exec">
<span class="sig-name descname"><span class="pre">guest_exec</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">path</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">args</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">env</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">stdin</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">capture_output</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">decode_output</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">poll</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="#compute.instance.guest_agent.GuestExecOutput" title="compute.instance.guest_agent.GuestExecOutput"><span class="pre">GuestExecOutput</span></a></span></span><a class="headerlink" href="#compute.instance.guest_agent.GuestAgent.guest_exec" title="Permalink to this definition"></a></dt>
<dd><p>Execute qemu-exec command and return output.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>path</strong> Path ot executable on guest.</p></li>
<li><p><strong>arg</strong> List of arguments to pass to executable.</p></li>
<li><p><strong>env</strong> List of environment variables to pass to executable.
For example: <code class="docutils literal notranslate"><span class="pre">['LANG=C',</span> <span class="pre">'TERM=xterm']</span></code></p></li>
<li><p><strong>stdin</strong> Data to pass to executable STDIN.</p></li>
<li><p><strong>capture_output</strong> Capture command output.</p></li>
<li><p><strong>decode_output</strong> Use base64_decode() to decode command output.
Affects only if <cite>capture_output</cite> is True.</p></li>
<li><p><strong>poll</strong> Poll command output. Uses <cite>self.timeout</cite> and
POLL_INTERVAL constant.</p></li>
</ul>
</dd>
<dt class="field-even">Returns<span class="colon">:</span></dt>
<dd class="field-even"><p>Command output</p>
</dd>
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p><a class="reference internal" href="#compute.instance.guest_agent.GuestExecOutput" title="compute.instance.guest_agent.GuestExecOutput">GuestExecOutput</a></p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestAgent.guest_exec_status">
<span class="sig-name descname"><span class="pre">guest_exec_status</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pid</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">poll</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">poll_interval</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">float</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">0.3</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">dict</span></span></span><a class="headerlink" href="#compute.instance.guest_agent.GuestAgent.guest_exec_status" title="Permalink to this definition"></a></dt>
<dd><p>Execute guest-exec-status and return output.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pid</strong> PID in guest.</p></li>
<li><p><strong>poll</strong> If True poll command status.</p></li>
<li><p><strong>poll_interval</strong> Time between attempts to obtain command status.</p></li>
</ul>
</dd>
<dt class="field-even">Returns<span class="colon">:</span></dt>
<dd class="field-even"><p>Command output</p>
</dd>
<dt class="field-odd">Return type<span class="colon">:</span></dt>
<dd class="field-odd"><p>dict</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestAgent.is_available">
<span class="sig-name descname"><span class="pre">is_available</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">bool</span></span></span><a class="headerlink" href="#compute.instance.guest_agent.GuestAgent.is_available" title="Permalink to this definition"></a></dt>
<dd><p>Execute guest-ping.</p>
<dl class="field-list simple">
<dt class="field-odd">Returns<span class="colon">:</span></dt>
<dd class="field-odd"><p>True or False if guest agent is unreachable.</p>
</dd>
<dt class="field-even">Return type<span class="colon">:</span></dt>
<dd class="field-even"><p>bool</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestAgent.raise_for_commands">
<span class="sig-name descname"><span class="pre">raise_for_commands</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">commands</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.guest_agent.GuestAgent.raise_for_commands" title="Permalink to this definition"></a></dt>
<dd><p>Raise exception if QEMU GA command is not available.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>commands</strong> List of required commands</p>
</dd>
<dt class="field-even">Raise<span class="colon">:</span></dt>
<dd class="field-even"><p>GuestAgentCommandNotSupportedError</p>
</dd>
</dl>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestExecOutput">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.instance.guest_agent.</span></span><span class="sig-name descname"><span class="pre">GuestExecOutput</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">exited</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">exitcode</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">stdout</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">stderr</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.instance.guest_agent.GuestExecOutput" title="Permalink to this definition"></a></dt>
<dd><p>QEMU guest-exec command output.</p>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestExecOutput.exitcode">
<span class="sig-name descname"><span class="pre">exitcode</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></em><a class="headerlink" href="#compute.instance.guest_agent.GuestExecOutput.exitcode" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 1</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestExecOutput.exited">
<span class="sig-name descname"><span class="pre">exited</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">bool</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></em><a class="headerlink" href="#compute.instance.guest_agent.GuestExecOutput.exited" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 0</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestExecOutput.stderr">
<span class="sig-name descname"><span class="pre">stderr</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></em><a class="headerlink" href="#compute.instance.guest_agent.GuestExecOutput.stderr" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 3</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.instance.guest_agent.GuestExecOutput.stdout">
<span class="sig-name descname"><span class="pre">stdout</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></em><a class="headerlink" href="#compute.instance.guest_agent.GuestExecOutput.stdout" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 2</p>
</dd></dl>
</dd></dl>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../../index.html">Documentation overview</a><ul>
<li><a href="../index.html">Python API</a><ul>
<li><a href="index.html"><code class="docutils literal notranslate"><span class="pre">instance</span></code></a><ul>
<li>Previous: <a href="instance.html" title="previous chapter"><code class="docutils literal notranslate"><span class="pre">instance</span></code></a></li>
<li>Next: <a href="schemas.html" title="next chapter"><code class="docutils literal notranslate"><span class="pre">schemas</span></code></a></li>
</ul></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../../_sources/pyapi/instance/guest_agent.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,120 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>instance &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/alabaster.css" />
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/jquery.js"></script>
<script src="../../_static/underscore.js"></script>
<script src="../../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
<link rel="next" title="instance" href="instance.html" />
<link rel="prev" title="session" href="../session.html" />
<link rel="stylesheet" href="../../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="instance">
<h1><code class="docutils literal notranslate"><span class="pre">instance</span></code><a class="headerlink" href="#instance" title="Permalink to this heading"></a></h1>
<div class="toctree-wrapper compound">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="instance.html"><code class="docutils literal notranslate"><span class="pre">instance</span></code></a></li>
<li class="toctree-l1"><a class="reference internal" href="guest_agent.html"><code class="docutils literal notranslate"><span class="pre">guest_agent</span></code></a></li>
<li class="toctree-l1"><a class="reference internal" href="schemas.html"><code class="docutils literal notranslate"><span class="pre">schemas</span></code></a></li>
</ul>
</div>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../../index.html">Documentation overview</a><ul>
<li><a href="../index.html">Python API</a><ul>
<li>Previous: <a href="../session.html" title="previous chapter"><code class="docutils literal notranslate"><span class="pre">session</span></code></a></li>
<li>Next: <a href="instance.html" title="next chapter"><code class="docutils literal notranslate"><span class="pre">instance</span></code></a></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../../_sources/pyapi/instance/index.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,490 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>instance &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/alabaster.css" />
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/jquery.js"></script>
<script src="../../_static/underscore.js"></script>
<script src="../../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
<link rel="next" title="guest_agent" href="guest_agent.html" />
<link rel="prev" title="instance" href="index.html" />
<link rel="stylesheet" href="../../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="module-compute.instance.instance">
<span id="instance"></span><h1><code class="docutils literal notranslate"><span class="pre">instance</span></code><a class="headerlink" href="#module-compute.instance.instance" title="Permalink to this heading"></a></h1>
<p>Manage compute instances.</p>
<dl class="py class">
<dt class="sig sig-object py" id="compute.instance.instance.Instance">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.instance.instance.</span></span><span class="sig-name descname"><span class="pre">Instance</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">domain</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virDomain</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.instance.instance.Instance" title="Permalink to this definition"></a></dt>
<dd><p>Manage compute instances.</p>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.__init__">
<span class="sig-name descname"><span class="pre">__init__</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">domain</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virDomain</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.instance.instance.Instance.__init__" title="Permalink to this definition"></a></dt>
<dd><p>Initialise Instance.</p>
<dl class="field-list simple">
<dt class="field-odd">Variables<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>domain</strong> (<em>libvirt.virDomain</em>) domain object</p></li>
<li><p><strong>connection</strong> (<em>libvirt.virConnect</em>) connection object</p></li>
<li><p><strong>name</strong> (<em>str</em>) domain name</p></li>
<li><p><strong>guest_agent</strong> (<a class="reference internal" href="guest_agent.html#compute.instance.guest_agent.GuestAgent" title="compute.instance.guest_agent.GuestAgent"><em>GuestAgent</em></a>) <code class="xref py py-class docutils literal notranslate"><span class="pre">GuestAgent</span></code> object</p></li>
</ul>
</dd>
<dt class="field-even">Parameters<span class="colon">:</span></dt>
<dd class="field-even"><p><strong>domain</strong> libvirt domain object</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.attach_device">
<span class="sig-name descname"><span class="pre">attach_device</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">device</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">EntityConfig</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">live</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.attach_device" title="Permalink to this definition"></a></dt>
<dd><p>Attach device to compute instance.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>device</strong> Object with device description e.g. DiskConfig</p></li>
<li><p><strong>live</strong> Affect a running instance</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.delete">
<span class="sig-name descname"><span class="pre">delete</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.delete" title="Permalink to this definition"></a></dt>
<dd><p>Undefine instance.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.delete_ssh_keys">
<span class="sig-name descname"><span class="pre">delete_ssh_keys</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">user</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">ssh_keys</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.delete_ssh_keys" title="Permalink to this definition"></a></dt>
<dd><p>Remove SSH keys from guest for specific user.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>user</strong> Username.</p></li>
<li><p><strong>ssh_keys</strong> List of public SSH keys.</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.detach_device">
<span class="sig-name descname"><span class="pre">detach_device</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">device</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">EntityConfig</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">live</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.detach_device" title="Permalink to this definition"></a></dt>
<dd><p>Dettach device from compute instance.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>device</strong> Object with device description e.g. DiskConfig</p></li>
<li><p><strong>live</strong> Affect a running instance</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.detach_disk">
<span class="sig-name descname"><span class="pre">detach_disk</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">name</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.detach_disk" title="Permalink to this definition"></a></dt>
<dd><p>Detach disk device by target name.</p>
<p>There is no <code class="docutils literal notranslate"><span class="pre">attach_disk()</span></code> method. Use <a class="reference internal" href="#compute.instance.instance.Instance.attach_device" title="compute.instance.instance.Instance.attach_device"><code class="xref py py-func docutils literal notranslate"><span class="pre">attach_device()</span></code></a>
with <code class="xref py py-class docutils literal notranslate"><span class="pre">DiskConfig</span></code> as argument.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>name</strong> Disk name e.g. vda, sda, etc. This name may
not match the name of the disk inside the guest OS.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.dump_xml">
<span class="sig-name descname"><span class="pre">dump_xml</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">inactive</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">str</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.dump_xml" title="Permalink to this definition"></a></dt>
<dd><p>Return instance XML description.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.get_disks">
<span class="sig-name descname"><span class="pre">get_disks</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><a class="reference internal" href="../storage/volume.html#compute.storage.volume.DiskConfig" title="compute.storage.volume.DiskConfig"><span class="pre">compute.storage.volume.DiskConfig</span></a><span class="p"><span class="pre">]</span></span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.get_disks" title="Permalink to this definition"></a></dt>
<dd><p>Return list of attached disks.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.get_info">
<span class="sig-name descname"><span class="pre">get_info</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="#compute.instance.instance.InstanceInfo" title="compute.instance.instance.InstanceInfo"><span class="pre">InstanceInfo</span></a></span></span><a class="headerlink" href="#compute.instance.instance.Instance.get_info" title="Permalink to this definition"></a></dt>
<dd><p>Return instance info.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.get_max_memory">
<span class="sig-name descname"><span class="pre">get_max_memory</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">int</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.get_max_memory" title="Permalink to this definition"></a></dt>
<dd><p>Maximum memory value for domain in KiB.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.get_max_vcpus">
<span class="sig-name descname"><span class="pre">get_max_vcpus</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">int</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.get_max_vcpus" title="Permalink to this definition"></a></dt>
<dd><p>Maximum vCPUs number for domain.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.get_ssh_keys">
<span class="sig-name descname"><span class="pre">get_ssh_keys</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">user</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.get_ssh_keys" title="Permalink to this definition"></a></dt>
<dd><p>Return list of SSH keys on guest for specific user.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>user</strong> Username.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.get_status">
<span class="sig-name descname"><span class="pre">get_status</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">str</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.get_status" title="Permalink to this definition"></a></dt>
<dd><p>Return instance state: running, shutoff, etc.</p>
<p>Reference:
<a class="reference external" href="https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState">https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState</a></p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.is_autostart">
<span class="sig-name descname"><span class="pre">is_autostart</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">bool</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.is_autostart" title="Permalink to this definition"></a></dt>
<dd><p>Return True if instance autostart is enabled, else return False.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.is_running">
<span class="sig-name descname"><span class="pre">is_running</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">bool</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.is_running" title="Permalink to this definition"></a></dt>
<dd><p>Return True if instance is running, else return False.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.pause">
<span class="sig-name descname"><span class="pre">pause</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.pause" title="Permalink to this definition"></a></dt>
<dd><p>Pause instance.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.power_reset">
<span class="sig-name descname"><span class="pre">power_reset</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.power_reset" title="Permalink to this definition"></a></dt>
<dd><p>Shutdown instance and start.</p>
<p>By analogy with real hardware, this is a normal server shutdown,
and then turning off from the power supply and turning it on again.</p>
<p>This method is applicable in cases where there has been a
configuration change in libvirt and you need to restart the
instance to apply the new configuration.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.reboot">
<span class="sig-name descname"><span class="pre">reboot</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.reboot" title="Permalink to this definition"></a></dt>
<dd><p>Send ACPI signal to guest OS to reboot. OS may ignore this.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.reset">
<span class="sig-name descname"><span class="pre">reset</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.reset" title="Permalink to this definition"></a></dt>
<dd><p>Reset instance.</p>
<p>Copypaste from libvirt doc:</p>
<p>Reset a domain immediately without any guest OS shutdown.
Reset emulates the power reset button on a machine, where all
hardware sees the RST line set and reinitializes internal state.</p>
<p>Note that there is a risk of data loss caused by reset without any
guest OS shutdown.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.resize_disk">
<span class="sig-name descname"><span class="pre">resize_disk</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">name</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">capacity</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">unit</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="../utils.html#compute.utils.units.DataUnit" title="compute.utils.units.DataUnit"><span class="pre">DataUnit</span></a></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.resize_disk" title="Permalink to this definition"></a></dt>
<dd><p>Resize attached block device.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>name</strong> Disk device name e.g. <cite>vda</cite>, <cite>sda</cite>, etc.</p></li>
<li><p><strong>capacity</strong> New capacity.</p></li>
<li><p><strong>unit</strong> Capacity unit.</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.resume">
<span class="sig-name descname"><span class="pre">resume</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.resume" title="Permalink to this definition"></a></dt>
<dd><p>Resume paused instance.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.set_autostart">
<span class="sig-name descname"><span class="pre">set_autostart</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">enabled</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.set_autostart" title="Permalink to this definition"></a></dt>
<dd><p>Set autostart flag for instance.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>enabled</strong> Bool argument to set or unset autostart flag.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.set_memory">
<span class="sig-name descname"><span class="pre">set_memory</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">memory</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">live</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.set_memory" title="Permalink to this definition"></a></dt>
<dd><p>Set memory.</p>
<p>If <cite>live</cite> is True and instance is not currently running set memory
in config and will applied when instance boot.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>memory</strong> Memory value in mebibytes</p></li>
<li><p><strong>live</strong> Affect a running instance</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.set_ssh_keys">
<span class="sig-name descname"><span class="pre">set_ssh_keys</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">user</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">ssh_keys</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.set_ssh_keys" title="Permalink to this definition"></a></dt>
<dd><p>Add SSH keys to guest for specific user.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>user</strong> Username.</p></li>
<li><p><strong>ssh_keys</strong> List of public SSH keys.</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.set_user_password">
<span class="sig-name descname"><span class="pre">set_user_password</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">user</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">password</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">encrypted</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.set_user_password" title="Permalink to this definition"></a></dt>
<dd><p>Set new user password in guest OS.</p>
<p>This action performs by guest agent inside the guest.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>user</strong> Username.</p></li>
<li><p><strong>password</strong> Password.</p></li>
<li><p><strong>encrypted</strong> Set it to True if password is already encrypted.
Right encryption method depends on guest OS.</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.set_vcpus">
<span class="sig-name descname"><span class="pre">set_vcpus</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">nvcpus</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">live</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.set_vcpus" title="Permalink to this definition"></a></dt>
<dd><p>Set vCPU number.</p>
<p>If <cite>live</cite> is True and instance is not currently running vCPUs
will set in config and will applied when instance boot.</p>
<p>NB: Note that if this call is executed before the guest has
finished booting, the guest may fail to process the change.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>nvcpus</strong> Number of vCPUs</p></li>
<li><p><strong>live</strong> Affect a running instance</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.shutdown">
<span class="sig-name descname"><span class="pre">shutdown</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">method</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.shutdown" title="Permalink to this definition"></a></dt>
<dd><p>Shutdown instance.</p>
<p>Shutdown methods:</p>
<dl class="simple">
<dt>SOFT</dt><dd><p>Use guest agent to shutdown. If guest agent is unavailable
NORMAL method will be used.</p>
</dd>
<dt>NORMAL</dt><dd><p>Use method choosen by hypervisor to shutdown. Usually send ACPI
signal to guest OS. OS may ignore ACPI e.g. if guest is hanged.</p>
</dd>
<dt>HARD</dt><dd><p>Shutdown instance without any guest OS shutdown. This is simular
to unplugging machine from power. Internally send SIGTERM to
instance process and destroy it gracefully.</p>
</dd>
<dt>UNSAFE</dt><dd><p>Force shutdown. Internally send SIGKILL to instance process.
There is high data corruption risk!</p>
</dd>
</dl>
<p>If method is None NORMAL method will used.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>method</strong> Method used to shutdown instance</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.Instance.start">
<span class="sig-name descname"><span class="pre">start</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.instance.instance.Instance.start" title="Permalink to this definition"></a></dt>
<dd><p>Start defined instance.</p>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt class="sig sig-object py" id="compute.instance.instance.InstanceConfig">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.instance.instance.</span></span><span class="sig-name descname"><span class="pre">InstanceConfig</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">schema</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="schemas.html#compute.instance.schemas.InstanceSchema" title="compute.instance.schemas.InstanceSchema"><span class="pre">InstanceSchema</span></a></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.instance.instance.InstanceConfig" title="Permalink to this definition"></a></dt>
<dd><p>Compute instance XML config builder.</p>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.InstanceConfig.__init__">
<span class="sig-name descname"><span class="pre">__init__</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">schema</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="schemas.html#compute.instance.schemas.InstanceSchema" title="compute.instance.schemas.InstanceSchema"><span class="pre">InstanceSchema</span></a></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.instance.instance.InstanceConfig.__init__" title="Permalink to this definition"></a></dt>
<dd><p>Initialise InstanceConfig.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>schema</strong> InstanceSchema object</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.instance.instance.InstanceConfig.to_xml">
<span class="sig-name descname"><span class="pre">to_xml</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">str</span></span></span><a class="headerlink" href="#compute.instance.instance.InstanceConfig.to_xml" title="Permalink to this definition"></a></dt>
<dd><p>Return XML config for libvirt.</p>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt class="sig sig-object py" id="compute.instance.instance.InstanceInfo">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.instance.instance.</span></span><span class="sig-name descname"><span class="pre">InstanceInfo</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">state</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">max_memory</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">memory</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">nproc</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cputime</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.instance.instance.InstanceInfo" title="Permalink to this definition"></a></dt>
<dd><p>Store compute instance info.</p>
<p>Reference:
<a class="reference external" href="https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainInfo">https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainInfo</a></p>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.instance.instance.InstanceInfo.cputime">
<span class="sig-name descname"><span class="pre">cputime</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.instance.instance.InstanceInfo.cputime" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 4</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.instance.instance.InstanceInfo.max_memory">
<span class="sig-name descname"><span class="pre">max_memory</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.instance.instance.InstanceInfo.max_memory" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 1</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.instance.instance.InstanceInfo.memory">
<span class="sig-name descname"><span class="pre">memory</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.instance.instance.InstanceInfo.memory" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 2</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.instance.instance.InstanceInfo.nproc">
<span class="sig-name descname"><span class="pre">nproc</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.instance.instance.InstanceInfo.nproc" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 3</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.instance.instance.InstanceInfo.state">
<span class="sig-name descname"><span class="pre">state</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><a class="headerlink" href="#compute.instance.instance.InstanceInfo.state" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 0</p>
</dd></dl>
</dd></dl>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../../index.html">Documentation overview</a><ul>
<li><a href="../index.html">Python API</a><ul>
<li><a href="index.html"><code class="docutils literal notranslate"><span class="pre">instance</span></code></a><ul>
<li>Previous: <a href="index.html" title="previous chapter"><code class="docutils literal notranslate"><span class="pre">instance</span></code></a></li>
<li>Next: <a href="guest_agent.html" title="next chapter"><code class="docutils literal notranslate"><span class="pre">guest_agent</span></code></a></li>
</ul></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../../_sources/pyapi/instance/instance.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,331 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>session &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/alabaster.css" />
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="instance" href="instance/index.html" />
<link rel="prev" title="Python API" href="index.html" />
<link rel="stylesheet" href="../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="module-compute.session">
<span id="session"></span><h1><code class="docutils literal notranslate"><span class="pre">session</span></code><a class="headerlink" href="#module-compute.session" title="Permalink to this heading"></a></h1>
<p>Hypervisor session manager.</p>
<dl class="py class">
<dt class="sig sig-object py" id="compute.session.Capabilities">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.session.</span></span><span class="sig-name descname"><span class="pre">Capabilities</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">arch</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">virt_type</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">emulator</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">machine</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">max_vcpus</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cpu_vendor</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cpu_model</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cpu_features</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">dict</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">usable_cpus</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><span class="pre">dict</span><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.session.Capabilities" title="Permalink to this definition"></a></dt>
<dd><p>Store domain capabilities info.</p>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.Capabilities.arch">
<span class="sig-name descname"><span class="pre">arch</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><a class="headerlink" href="#compute.session.Capabilities.arch" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 0</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.Capabilities.cpu_features">
<span class="sig-name descname"><span class="pre">cpu_features</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">dict</span></em><a class="headerlink" href="#compute.session.Capabilities.cpu_features" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 7</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.Capabilities.cpu_model">
<span class="sig-name descname"><span class="pre">cpu_model</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><a class="headerlink" href="#compute.session.Capabilities.cpu_model" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 6</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.Capabilities.cpu_vendor">
<span class="sig-name descname"><span class="pre">cpu_vendor</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><a class="headerlink" href="#compute.session.Capabilities.cpu_vendor" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 5</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.Capabilities.emulator">
<span class="sig-name descname"><span class="pre">emulator</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><a class="headerlink" href="#compute.session.Capabilities.emulator" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 2</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.Capabilities.machine">
<span class="sig-name descname"><span class="pre">machine</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><a class="headerlink" href="#compute.session.Capabilities.machine" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 3</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.Capabilities.max_vcpus">
<span class="sig-name descname"><span class="pre">max_vcpus</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.session.Capabilities.max_vcpus" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 4</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.Capabilities.usable_cpus">
<span class="sig-name descname"><span class="pre">usable_cpus</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">list</span><span class="p"><span class="pre">[</span></span><span class="pre">dict</span><span class="p"><span class="pre">]</span></span></em><a class="headerlink" href="#compute.session.Capabilities.usable_cpus" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 8</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.Capabilities.virt_type">
<span class="sig-name descname"><span class="pre">virt_type</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><a class="headerlink" href="#compute.session.Capabilities.virt_type" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 1</p>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt class="sig sig-object py" id="compute.session.NodeInfo">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.session.</span></span><span class="sig-name descname"><span class="pre">NodeInfo</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">arch</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">memory</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cpus</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">mhz</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">nodes</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">sockets</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">cores</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">threads</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.session.NodeInfo" title="Permalink to this definition"></a></dt>
<dd><p>Store compute node info.</p>
<p>See <a class="reference external" href="https://libvirt.org/html/libvirt-libvirt-host.html#virNodeInfo">https://libvirt.org/html/libvirt-libvirt-host.html#virNodeInfo</a>
NOTE: memory unit in libvirt docs is wrong! Actual unit is MiB.</p>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.NodeInfo.arch">
<span class="sig-name descname"><span class="pre">arch</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><a class="headerlink" href="#compute.session.NodeInfo.arch" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 0</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.NodeInfo.cores">
<span class="sig-name descname"><span class="pre">cores</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.session.NodeInfo.cores" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 6</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.NodeInfo.cpus">
<span class="sig-name descname"><span class="pre">cpus</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.session.NodeInfo.cpus" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 2</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.NodeInfo.memory">
<span class="sig-name descname"><span class="pre">memory</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.session.NodeInfo.memory" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 1</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.NodeInfo.mhz">
<span class="sig-name descname"><span class="pre">mhz</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.session.NodeInfo.mhz" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 3</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.NodeInfo.nodes">
<span class="sig-name descname"><span class="pre">nodes</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.session.NodeInfo.nodes" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 4</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.NodeInfo.sockets">
<span class="sig-name descname"><span class="pre">sockets</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.session.NodeInfo.sockets" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 5</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.session.NodeInfo.threads">
<span class="sig-name descname"><span class="pre">threads</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.session.NodeInfo.threads" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 7</p>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt class="sig sig-object py" id="compute.session.Session">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.session.</span></span><span class="sig-name descname"><span class="pre">Session</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">uri</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.session.Session" title="Permalink to this definition"></a></dt>
<dd><p>Hypervisor session context manager.</p>
<dl class="field-list simple">
<dt class="field-odd">Variables<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>IMAGES_POOL</strong> images storage pool name taken from env</p></li>
<li><p><strong>VOLUMES_POOL</strong> volumes storage pool name taken from env</p></li>
</ul>
</dd>
</dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.session.Session.__init__">
<span class="sig-name descname"><span class="pre">__init__</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">uri</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.session.Session.__init__" title="Permalink to this definition"></a></dt>
<dd><p>Initialise session with hypervisor.</p>
<dl class="field-list simple">
<dt class="field-odd">Variables<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>uri</strong> (<em>str</em>) libvirt connection URI.</p></li>
<li><p><strong>connection</strong> (<em>libvirt.virConnect</em>) libvirt connection object.</p></li>
</ul>
</dd>
<dt class="field-even">Parameters<span class="colon">:</span></dt>
<dd class="field-even"><p><strong>uri</strong> libvirt connection URI.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.session.Session.close">
<span class="sig-name descname"><span class="pre">close</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.session.Session.close" title="Permalink to this definition"></a></dt>
<dd><p>Close connection to libvirt daemon.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.session.Session.create_instance">
<span class="sig-name descname"><span class="pre">create_instance</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">kwargs</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Any</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance" title="compute.instance.instance.Instance"><span class="pre">Instance</span></a></span></span><a class="headerlink" href="#compute.session.Session.create_instance" title="Permalink to this definition"></a></dt>
<dd><p>Create and return new compute instance.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>name</strong> (<em>str</em>) Instance name.</p></li>
<li><p><strong>title</strong> (<em>str</em>) Instance title for humans.</p></li>
<li><p><strong>description</strong> (<em>str</em>) Some information about instance.</p></li>
<li><p><strong>memory</strong> (<em>int</em>) Memory in MiB.</p></li>
<li><p><strong>max_memory</strong> (<em>int</em>) Maximum memory in MiB.</p></li>
<li><p><strong>vcpus</strong> (<em>int</em>) Number of vCPUs.</p></li>
<li><p><strong>max_vcpus</strong> (<em>int</em>) Maximum vCPUs.</p></li>
<li><p><strong>cpu</strong> (<em>dict</em>) CPU configuration. See <code class="xref py py-class docutils literal notranslate"><span class="pre">CPUSchema</span></code> for info.</p></li>
<li><p><strong>machine</strong> (<em>str</em>) QEMU emulated machine.</p></li>
<li><p><strong>emulator</strong> (<em>str</em>) Path to emulator.</p></li>
<li><p><strong>arch</strong> (<em>str</em>) CPU architecture to virtualization.</p></li>
<li><p><strong>boot</strong> (<em>dict</em>) Boot settings. See <code class="xref py py-class docutils literal notranslate"><span class="pre">BootOptionsSchema</span></code>.</p></li>
<li><p><strong>image</strong> (<em>str</em>) Source disk image name for system disk.</p></li>
<li><p><strong>volumes</strong> (<em>list</em><em>[</em><em>dict</em><em>]</em>) List of storage volume configs. For more info
see <code class="xref py py-class docutils literal notranslate"><span class="pre">VolumeSchema</span></code>.</p></li>
<li><p><strong>network_interfaces</strong> (<em>list</em><em>[</em><em>dict</em><em>]</em>) List of virtual network interfaces
configs. See <code class="xref py py-class docutils literal notranslate"><span class="pre">NetworkInterfaceSchema</span></code> for more info.</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.session.Session.get_capabilities">
<span class="sig-name descname"><span class="pre">get_capabilities</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="#compute.session.Capabilities" title="compute.session.Capabilities"><span class="pre">Capabilities</span></a></span></span><a class="headerlink" href="#compute.session.Session.get_capabilities" title="Permalink to this definition"></a></dt>
<dd><p>Return capabilities e.g. arch, virt, emulator, etc.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.session.Session.get_instance">
<span class="sig-name descname"><span class="pre">get_instance</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">name</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance" title="compute.instance.instance.Instance"><span class="pre">Instance</span></a></span></span><a class="headerlink" href="#compute.session.Session.get_instance" title="Permalink to this definition"></a></dt>
<dd><p>Get compute instance by name.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.session.Session.get_node_info">
<span class="sig-name descname"><span class="pre">get_node_info</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="#compute.session.NodeInfo" title="compute.session.NodeInfo"><span class="pre">NodeInfo</span></a></span></span><a class="headerlink" href="#compute.session.Session.get_node_info" title="Permalink to this definition"></a></dt>
<dd><p>Return information about compute node.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.session.Session.get_storage_pool">
<span class="sig-name descname"><span class="pre">get_storage_pool</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">name</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool" title="compute.storage.pool.StoragePool"><span class="pre">StoragePool</span></a></span></span><a class="headerlink" href="#compute.session.Session.get_storage_pool" title="Permalink to this definition"></a></dt>
<dd><p>Get storage pool by name.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.session.Session.list_instances">
<span class="sig-name descname"><span class="pre">list_instances</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><a class="reference internal" href="instance/instance.html#compute.instance.instance.Instance" title="compute.instance.instance.Instance"><span class="pre">compute.instance.instance.Instance</span></a><span class="p"><span class="pre">]</span></span></span></span><a class="headerlink" href="#compute.session.Session.list_instances" title="Permalink to this definition"></a></dt>
<dd><p>List all instances.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.session.Session.list_storage_pools">
<span class="sig-name descname"><span class="pre">list_storage_pools</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><a class="reference internal" href="storage/pool.html#compute.storage.pool.StoragePool" title="compute.storage.pool.StoragePool"><span class="pre">compute.storage.pool.StoragePool</span></a><span class="p"><span class="pre">]</span></span></span></span><a class="headerlink" href="#compute.session.Session.list_storage_pools" title="Permalink to this definition"></a></dt>
<dd><p>List all strage pools.</p>
</dd></dl>
</dd></dl>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../index.html">Documentation overview</a><ul>
<li><a href="index.html">Python API</a><ul>
<li>Previous: <a href="index.html" title="previous chapter">Python API</a></li>
<li>Next: <a href="instance/index.html" title="next chapter"><code class="docutils literal notranslate"><span class="pre">instance</span></code></a></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../_sources/pyapi/session.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,119 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>storage &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/alabaster.css" />
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/jquery.js"></script>
<script src="../../_static/underscore.js"></script>
<script src="../../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
<link rel="next" title="pool" href="pool.html" />
<link rel="prev" title="schemas" href="../instance/schemas.html" />
<link rel="stylesheet" href="../../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="storage">
<h1><code class="docutils literal notranslate"><span class="pre">storage</span></code><a class="headerlink" href="#storage" title="Permalink to this heading"></a></h1>
<div class="toctree-wrapper compound">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="pool.html"><code class="docutils literal notranslate"><span class="pre">pool</span></code></a></li>
<li class="toctree-l1"><a class="reference internal" href="volume.html"><code class="docutils literal notranslate"><span class="pre">volume</span></code></a></li>
</ul>
</div>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../../index.html">Documentation overview</a><ul>
<li><a href="../index.html">Python API</a><ul>
<li>Previous: <a href="../instance/schemas.html" title="previous chapter"><code class="docutils literal notranslate"><span class="pre">schemas</span></code></a></li>
<li>Next: <a href="pool.html" title="next chapter"><code class="docutils literal notranslate"><span class="pre">pool</span></code></a></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../../_sources/pyapi/storage/index.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,201 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>pool &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/alabaster.css" />
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/jquery.js"></script>
<script src="../../_static/underscore.js"></script>
<script src="../../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
<link rel="next" title="volume" href="volume.html" />
<link rel="prev" title="storage" href="index.html" />
<link rel="stylesheet" href="../../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="module-compute.storage.pool">
<span id="pool"></span><h1><code class="docutils literal notranslate"><span class="pre">pool</span></code><a class="headerlink" href="#module-compute.storage.pool" title="Permalink to this heading"></a></h1>
<p>Manage storage pools.</p>
<dl class="py class">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePool">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.storage.pool.</span></span><span class="sig-name descname"><span class="pre">StoragePool</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pool</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virStoragePool</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.storage.pool.StoragePool" title="Permalink to this definition"></a></dt>
<dd><p>Storage pool manipulating class.</p>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePool.__init__">
<span class="sig-name descname"><span class="pre">__init__</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pool</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virStoragePool</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.storage.pool.StoragePool.__init__" title="Permalink to this definition"></a></dt>
<dd><p>Initislise StoragePool.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePool.clone_volume">
<span class="sig-name descname"><span class="pre">clone_volume</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">src</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="volume.html#compute.storage.volume.Volume" title="compute.storage.volume.Volume"><span class="pre">Volume</span></a></span></em>, <em class="sig-param"><span class="n"><span class="pre">dst</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="volume.html#compute.storage.volume.VolumeConfig" title="compute.storage.volume.VolumeConfig"><span class="pre">VolumeConfig</span></a></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="volume.html#compute.storage.volume.Volume" title="compute.storage.volume.Volume"><span class="pre">Volume</span></a></span></span><a class="headerlink" href="#compute.storage.pool.StoragePool.clone_volume" title="Permalink to this definition"></a></dt>
<dd><p>Make storage volume copy.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>src</strong> Input volume</p></li>
<li><p><strong>dst</strong> Output volume config</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePool.create_volume">
<span class="sig-name descname"><span class="pre">create_volume</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">vol_conf</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="volume.html#compute.storage.volume.VolumeConfig" title="compute.storage.volume.VolumeConfig"><span class="pre">VolumeConfig</span></a></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="volume.html#compute.storage.volume.Volume" title="compute.storage.volume.Volume"><span class="pre">Volume</span></a></span></span><a class="headerlink" href="#compute.storage.pool.StoragePool.create_volume" title="Permalink to this definition"></a></dt>
<dd><p>Create storage volume and return Volume instance.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePool.dump_xml">
<span class="sig-name descname"><span class="pre">dump_xml</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">str</span></span></span><a class="headerlink" href="#compute.storage.pool.StoragePool.dump_xml" title="Permalink to this definition"></a></dt>
<dd><p>Return storage pool XML description as string.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePool.get_usage_info">
<span class="sig-name descname"><span class="pre">get_usage_info</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="#compute.storage.pool.StoragePoolUsageInfo" title="compute.storage.pool.StoragePoolUsageInfo"><span class="pre">StoragePoolUsageInfo</span></a></span></span><a class="headerlink" href="#compute.storage.pool.StoragePool.get_usage_info" title="Permalink to this definition"></a></dt>
<dd><p>Return info about storage pool usage.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePool.get_volume">
<span class="sig-name descname"><span class="pre">get_volume</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">name</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><a class="reference internal" href="volume.html#compute.storage.volume.Volume" title="compute.storage.volume.Volume"><span class="pre">compute.storage.volume.Volume</span></a><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span></span><a class="headerlink" href="#compute.storage.pool.StoragePool.get_volume" title="Permalink to this definition"></a></dt>
<dd><p>Lookup and return Volume instance or None.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePool.list_volumes">
<span class="sig-name descname"><span class="pre">list_volumes</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">list</span><span class="p"><span class="pre">[</span></span><a class="reference internal" href="volume.html#compute.storage.volume.Volume" title="compute.storage.volume.Volume"><span class="pre">compute.storage.volume.Volume</span></a><span class="p"><span class="pre">]</span></span></span></span><a class="headerlink" href="#compute.storage.pool.StoragePool.list_volumes" title="Permalink to this definition"></a></dt>
<dd><p>Return list of volumes in storage pool.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePool.refresh">
<span class="sig-name descname"><span class="pre">refresh</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.storage.pool.StoragePool.refresh" title="Permalink to this definition"></a></dt>
<dd><p>Refresh storage pool.</p>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePoolUsageInfo">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.storage.pool.</span></span><span class="sig-name descname"><span class="pre">StoragePoolUsageInfo</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">capacity</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">allocation</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">available</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.storage.pool.StoragePoolUsageInfo" title="Permalink to this definition"></a></dt>
<dd><p>Storage pool usage info.</p>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePoolUsageInfo.allocation">
<span class="sig-name descname"><span class="pre">allocation</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.storage.pool.StoragePoolUsageInfo.allocation" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 1</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePoolUsageInfo.available">
<span class="sig-name descname"><span class="pre">available</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.storage.pool.StoragePoolUsageInfo.available" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 2</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="compute.storage.pool.StoragePoolUsageInfo.capacity">
<span class="sig-name descname"><span class="pre">capacity</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">int</span></em><a class="headerlink" href="#compute.storage.pool.StoragePoolUsageInfo.capacity" title="Permalink to this definition"></a></dt>
<dd><p>Alias for field number 0</p>
</dd></dl>
</dd></dl>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../../index.html">Documentation overview</a><ul>
<li><a href="../index.html">Python API</a><ul>
<li><a href="index.html"><code class="docutils literal notranslate"><span class="pre">storage</span></code></a><ul>
<li>Previous: <a href="index.html" title="previous chapter"><code class="docutils literal notranslate"><span class="pre">storage</span></code></a></li>
<li>Next: <a href="volume.html" title="next chapter"><code class="docutils literal notranslate"><span class="pre">volume</span></code></a></li>
</ul></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../../_sources/pyapi/storage/pool.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,210 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>volume &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../_static/alabaster.css" />
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/jquery.js"></script>
<script src="../../_static/underscore.js"></script>
<script src="../../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
<link rel="next" title="utils" href="../utils.html" />
<link rel="prev" title="pool" href="pool.html" />
<link rel="stylesheet" href="../../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="module-compute.storage.volume">
<span id="volume"></span><h1><code class="docutils literal notranslate"><span class="pre">volume</span></code><a class="headerlink" href="#module-compute.storage.volume" title="Permalink to this heading"></a></h1>
<p>Manage storage volumes.</p>
<dl class="py class">
<dt class="sig sig-object py" id="compute.storage.volume.DiskConfig">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.storage.volume.</span></span><span class="sig-name descname"><span class="pre">DiskConfig</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">disk_type</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">source</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">pathlib.Path</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">target</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">readonly</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.storage.volume.DiskConfig" title="Permalink to this definition"></a></dt>
<dd><p>Disk XML config builder.</p>
<p>Generate XML config for attaching or detaching storage volumes
to compute instances.</p>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.volume.DiskConfig.__init__">
<span class="sig-name descname"><span class="pre">__init__</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">disk_type</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">source</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">pathlib.Path</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">target</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">readonly</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.storage.volume.DiskConfig.__init__" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.volume.DiskConfig.to_xml">
<span class="sig-name descname"><span class="pre">to_xml</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">str</span></span></span><a class="headerlink" href="#compute.storage.volume.DiskConfig.to_xml" title="Permalink to this definition"></a></dt>
<dd><p>Return XML config for libvirt.</p>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt class="sig sig-object py" id="compute.storage.volume.Volume">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.storage.volume.</span></span><span class="sig-name descname"><span class="pre">Volume</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pool</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virStoragePool</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">vol</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virStorageVol</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.storage.volume.Volume" title="Permalink to this definition"></a></dt>
<dd><p>Storage volume manipulating class.</p>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.volume.Volume.__init__">
<span class="sig-name descname"><span class="pre">__init__</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pool</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virStoragePool</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">vol</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">virStorageVol</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.storage.volume.Volume.__init__" title="Permalink to this definition"></a></dt>
<dd><p>Initialise Volume.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pool</strong> libvirt virStoragePool object</p></li>
<li><p><strong>vol</strong> libvirt virStorageVol object</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.volume.Volume.clone">
<span class="sig-name descname"><span class="pre">clone</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">vol_conf</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="#compute.storage.volume.VolumeConfig" title="compute.storage.volume.VolumeConfig"><span class="pre">VolumeConfig</span></a></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.storage.volume.Volume.clone" title="Permalink to this definition"></a></dt>
<dd><p>Make a copy of volume to the same storage pool.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><p><strong>VolumeInfo</strong> (<em>vol_info</em>) New storage volume dataclass object</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.volume.Volume.delete">
<span class="sig-name descname"><span class="pre">delete</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.storage.volume.Volume.delete" title="Permalink to this definition"></a></dt>
<dd><p>Delete volume from storage pool.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.volume.Volume.dump_xml">
<span class="sig-name descname"><span class="pre">dump_xml</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">str</span></span></span><a class="headerlink" href="#compute.storage.volume.Volume.dump_xml" title="Permalink to this definition"></a></dt>
<dd><p>Return volume XML description as string.</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.volume.Volume.resize">
<span class="sig-name descname"><span class="pre">resize</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">capacity</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">unit</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="../utils.html#compute.utils.units.DataUnit" title="compute.utils.units.DataUnit"><span class="pre">DataUnit</span></a></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.storage.volume.Volume.resize" title="Permalink to this definition"></a></dt>
<dd><p>Resize volume.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>int</strong> (<em>capacity</em>) Volume new capacity.</p></li>
<li><p><strong>DataUnit</strong> (<em>unit</em>) Data unit. Internally converts into bytes.</p></li>
</ul>
</dd>
</dl>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt class="sig sig-object py" id="compute.storage.volume.VolumeConfig">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.storage.volume.</span></span><span class="sig-name descname"><span class="pre">VolumeConfig</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">name</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">path</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">capacity</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.storage.volume.VolumeConfig" title="Permalink to this definition"></a></dt>
<dd><p>Storage volume XML config builder.</p>
<p>Generate XML config for creating a volume in a libvirt
storage pool.</p>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.volume.VolumeConfig.__init__">
<span class="sig-name descname"><span class="pre">__init__</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">name</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">path</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">capacity</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="headerlink" href="#compute.storage.volume.VolumeConfig.__init__" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="compute.storage.volume.VolumeConfig.to_xml">
<span class="sig-name descname"><span class="pre">to_xml</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">str</span></span></span><a class="headerlink" href="#compute.storage.volume.VolumeConfig.to_xml" title="Permalink to this definition"></a></dt>
<dd><p>Return XML config for libvirt.</p>
</dd></dl>
</dd></dl>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="../index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../../index.html">Documentation overview</a><ul>
<li><a href="../index.html">Python API</a><ul>
<li><a href="index.html"><code class="docutils literal notranslate"><span class="pre">storage</span></code></a><ul>
<li>Previous: <a href="pool.html" title="previous chapter"><code class="docutils literal notranslate"><span class="pre">pool</span></code></a></li>
<li>Next: <a href="../utils.html" title="next chapter"><code class="docutils literal notranslate"><span class="pre">utils</span></code></a></li>
</ul></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../../_sources/pyapi/storage/volume.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,144 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<title>utils &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../_static/alabaster.css" />
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/sphinx_highlight.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="exceptions" href="exceptions.html" />
<link rel="prev" title="volume" href="storage/volume.html" />
<link rel="stylesheet" href="../_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="utils">
<h1><code class="docutils literal notranslate"><span class="pre">utils</span></code><a class="headerlink" href="#utils" title="Permalink to this heading"></a></h1>
<section id="module-compute.utils.units">
<span id="utils-units"></span><h2><code class="docutils literal notranslate"><span class="pre">utils.units</span></code><a class="headerlink" href="#module-compute.utils.units" title="Permalink to this heading"></a></h2>
<p>Tools for data units convertion.</p>
<dl class="py class">
<dt class="sig sig-object py" id="compute.utils.units.DataUnit">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.utils.units.</span></span><span class="sig-name descname"><span class="pre">DataUnit</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">value</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">names</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">module</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">qualname</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">type</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">start</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">boundary</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.utils.units.DataUnit" title="Permalink to this definition"></a></dt>
<dd><p>Data units enumerated.</p>
</dd></dl>
<dl class="py exception">
<dt class="sig sig-object py" id="compute.utils.units.InvalidDataUnitError">
<em class="property"><span class="pre">exception</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">compute.utils.units.</span></span><span class="sig-name descname"><span class="pre">InvalidDataUnitError</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">msg</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#compute.utils.units.InvalidDataUnitError" title="Permalink to this definition"></a></dt>
<dd><p>Data unit is not valid.</p>
</dd></dl>
<dl class="py function">
<dt class="sig sig-object py" id="compute.utils.units.to_bytes">
<span class="sig-prename descclassname"><span class="pre">compute.utils.units.</span></span><span class="sig-name descname"><span class="pre">to_bytes</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">value</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">unit</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="#compute.utils.units.DataUnit" title="compute.utils.units.DataUnit"><span class="pre">DataUnit</span></a></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">DataUnit.BYTES</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">int</span></span></span><a class="headerlink" href="#compute.utils.units.to_bytes" title="Permalink to this definition"></a></dt>
<dd><p>Convert value to bytes. See <a class="reference internal" href="#compute.utils.units.DataUnit" title="compute.utils.units.DataUnit"><code class="xref py py-class docutils literal notranslate"><span class="pre">DataUnit</span></code></a>.</p>
</dd></dl>
</section>
<section id="module-compute.utils.ids">
<span id="utils-ids"></span><h2><code class="docutils literal notranslate"><span class="pre">utils.ids</span></code><a class="headerlink" href="#module-compute.utils.ids" title="Permalink to this heading"></a></h2>
<p>Random identificators.</p>
<dl class="py function">
<dt class="sig sig-object py" id="compute.utils.ids.random_mac">
<span class="sig-prename descclassname"><span class="pre">compute.utils.ids.</span></span><span class="sig-name descname"><span class="pre">random_mac</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">str</span></span></span><a class="headerlink" href="#compute.utils.ids.random_mac" title="Permalink to this definition"></a></dt>
<dd><p>Retrun random MAC address.</p>
</dd></dl>
</section>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="../index.html">Documentation overview</a><ul>
<li><a href="index.html">Python API</a><ul>
<li>Previous: <a href="storage/volume.html" title="previous chapter"><code class="docutils literal notranslate"><span class="pre">volume</span></code></a></li>
<li>Next: <a href="exceptions.html" title="next chapter"><code class="docutils literal notranslate"><span class="pre">exceptions</span></code></a></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
<a href="../_sources/pyapi/utils.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>

View File

@ -1,124 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Search &#8212; Compute 0.1.0 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/sphinx_highlight.js"></script>
<script src="_static/searchtools.js"></script>
<script src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="#" />
<script src="searchindex.js" defer></script>
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<h1 id="search-documentation">Search</h1>
<noscript>
<div class="admonition warning">
<p>
Please activate JavaScript to enable the search
functionality.
</p>
</div>
</noscript>
<p>
Searching for multiple words only shows matches that contain
all words.
</p>
<form action="" method="get">
<input type="text" name="q" aria-labelledby="search-documentation" value="" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="search" />
<span id="search-progress" style="padding-left: 10px"></span>
</form>
<div id="search-results">
</div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="index.html">Compute</a></h1>
<h3>Navigation</h3>
<ul>
<li class="toctree-l1"><a class="reference internal" href="pyapi/index.html">Python API</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
</ul></li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy;2023, Compute Authors.
|
Powered by <a href="http://sphinx-doc.org/">Sphinx 5.3.0</a>
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
</div>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More