from esu.base import BaseAPI, Field, FieldList, ObjectAlreadyHasId, \
ObjectHasNoId
[документация]class Vm(BaseAPI):
"""
Args:
id (str): Идентификатор
name (str): Имя
description (str): Описание. Любой произвольный пользовательский текст
cpu (int): Количество ядер
ram (int): Количество ОЗУ в ГБ
power (bool): Текущее состояние питания. Включен или выключен
vdc (object): Объект класса :class:`esu.Vdc`. ВЦОД, к которому
относится данный виртуальный сервер
template (object): Объект класса :class:`esu.Template`. Шаблон
операционной системы
metadata (list): Список объектов класса :class:`esu.VmMetadata`.
Список полей, необходимых для создания виртуального
выделенного сервера. Например, пароль или имя
пользователя.
ports (list): Список объектов класса :class:`esu.Port`. Список сетей,
к которым подключен данный виртуальный сервер
disks (list): Список объектов класса :class:`esu.Disk`. Список дисков,
подключенных к данному виртуальному серверу
floating (object): Объект класса :class:`esu.Port`. Порт подключения
виртаульаного выделенного сервера к внешней сети.
Если None, сервер не имеет подключения к внешней
сети.
token (str): Токен для доступа к API. Если не передан, будет
использована переменная окружения **ESU_API_TOKEN**
.. note:: Поля ``name``, ``cpu``, ``ram``, ``template``, ``ports``,
``disks`` и ``vdc`` необходимы для создания.
Поля ``metadata``, ``description`` и ``floating`` опциональны
при создании.
Поля ``name``, ``description``, ``cpu``, ``ram``, ``floating``
могут быть изменены для существующего объекта.
"""
class Meta:
id = Field()
name = Field()
description = Field()
cpu = Field()
ram = Field()
power = Field()
vdc = Field('esu.Vdc')
template = Field('esu.Template')
metadata = FieldList('esu.VmMetadata')
ports = FieldList('esu.Port')
disks = FieldList('esu.Disk')
floating = Field('esu.Port', allow_none=True)
hotadd_feature = Field()
cdrom = Field('esu.Image', allow_none=True)
[документация] @classmethod
def get_object(cls, id, token=None):
"""
Получить объект виртуального сервера по его ID
Args:
id (str): Идентификатор виртуального сервера
token (str): Токен для доступа к API. Если не передан, будет
использована переменная окружения **ESU_API_TOKEN**
Returns:
object: Возвращает объект виртуального сервера :class:`esu.Vm`
"""
vm = cls(token=token, id=id)
vm._get_object('v1/vm', vm.id)
for disk in vm.disks:
disk.vm = vm
return vm
[документация] def create(self):
"""
Создать объект
Raises:
ObjectAlreadyHasId: Если производится попытка создать объект,
который уже существует
"""
if self.id is not None:
raise ObjectAlreadyHasId
self._commit()
[документация] def save(self):
"""
Сохранить изменения
"""
if self.id is None:
raise ObjectHasNoId
self._commit()
return self
def _commit(self):
vm = {
'vdc': self.vdc.id,
'template': self.template.id,
'name': self.name,
'cpu': self.cpu,
'ram': self.ram,
'description': self.description or '',
'ports': [{
'id': o.id,
} if o.id else {
'network': o.network.id,
'fw_templates': [o2.id for o2 in o.fw_templates or []]
} for o in self.ports],
'disks': [{
'name': o.name,
'size': o.size,
'storage_profile': o.storage_profile.id
} for o in self.disks]
}
if self.id is None:
vm['metadata'] = [{
'field': o.field.id,
'value': o.value
} for o in self.metadata]
floating = None
if self.floating:
# keep/change or get a new IP
floating = self.floating.id or '0.0.0.0'
vm['floating'] = floating
if self.hotadd_feature:
vm['hotadd_feature'] = True
self._commit_object('v1/vm', **vm)
[документация] def destroy(self):
"""
Удалить объект
Raises:
ObjectHasNoId: Когда производится попытка удалить несуществующий
объект
"""
if self.id is None:
raise ObjectHasNoId
self._destroy_object('v1/vm', self.id)
self.id = None
[документация] def add_disk(self, disk):
"""
Создать и присоединить к виртуальному серверу новый диск
Args:
disk (object): Объект диска :class:`esu.Disk`
"""
if disk.id:
raise ValueError('You must pass a new Disk object')
disk.vm = self
disk._commit()
self.disks.append(disk)
[документация] def attach_disk(self, disk):
"""
Присоединить существующий во ВЦОДе диск к виртуальному серверу
Args:
disk (object): Объект диска :class:`esu.Disk`
"""
if not disk.id:
raise ValueError('Disk is not exists')
if disk.vm is not None:
raise ValueError('Disk must be unattached')
disk.vm = self
disk.save()
self.disks.append(disk)
[документация] def detach_disk(self, disk):
"""
Отсоединить диск от виртуального сервера
Args:
disk (object): Объект диска :class:`esu.Disk`
"""
self._call('POST', 'v1/disk/{}/detach'.format(disk.id))
disk.vm = None
self.disks = [d for d in self.disks if d.id != disk.id]
[документация] def add_port(self, port):
"""
Добавить подключение
Args:
port (object): Новый объект :class:`esu.Port`
"""
port = self._call('POST', 'v1/port', vm=self.id,
network=port.network.id)
self.ports.append(port)
self._fill()
[документация] def remove_port(self, port):
"""
Удалить подключение
Args:
port (object): Существующий объект :class:`esu.Port`
"""
self._call('DELETE', 'v1/port/{}'.format(port.id))
self.ports = [o for o in self.ports if o.id != port.id]
[документация] def power_on(self):
"""
Включить виртуальный сервер
"""
self._call('POST', 'v1/vm/{}/state'.format(self.id), state='power_on')
self.power = True
[документация] def power_off(self):
"""
Выключить виртуальный сервер
"""
self._call('POST', 'v1/vm/{}/state'.format(self.id), state='power_off')
self.power = False
[документация] def reboot(self):
"""
Перезагрузить виртуальный сервер
"""
self._call('POST', 'v1/vm/{}/state'.format(self.id), state='reboot')
[документация] def get_vnc_url(self):
"""
Получить ссылку на VNC для открытия консоли управления сервером
Returns:
str: Адрес VNC консоли
"""
vnc = self._call('POST', 'v1/vm/{}/vnc'.format(self.id))
uri = vnc['url']
return '{}{}'.format(self.endpoint_url, uri)
[документация] def revert(self, snapshot):
"""
Восстановить сервер из снапшота
Args:
snapshot (object): объект снапшота :class:`esu.Snapshot`
"""
vm = self._call('POST', 'v2/snapshot/{}/revert'.format(snapshot.id))
return vm
[документация] def mount_iso(self, image):
"""
Примонтировать iso к серверу как CD-ROM.
После перезагрузки сервера он будет загружен с этого
диска если он загрузочный
Args:
image (object): объект образа :class:`esu.Image`
"""
image = {'image': image.id}
self._call('POST', 'v1/vm/{}/mount_iso'.format(self.id), **image)
[документация] def unmount_iso(self):
"""
Отмонтировать iso от сервера
После перезагрузки сервера он будет загружен с основного диска
"""
self._call('POST', 'v1/vm/{}/unmount_iso'.format(self.id))