Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
В нашей компании активно используется платформа для виртуализации VMware vSphere. В ней живут тестовые среды продуктов, демонстрационные стенды, эмуляторы различных инфраструктур заказчиков и прочие не менее важные «виртуалки». Несмотря на достаточную мощность нашей инфраструктуры, доступ большого числа человек к управлению виртуальными машинами постоянно приводит к конфликтам и снижению производительности фермы. Разделение пулов между отделами (инженерами, тестировщиками, сейлами и разработчиками) проблему до конца не решает, поэтому периодически приходится разбираться, кто всем мешает и кто съел все ресурсы. При количестве виртуальных машин далеко за сотню сделать это вручную бывает проблематично, поэтому мы научились использовать API. VMware vSphere имеет довольно богатое API, которое незаслуженно слабо освещено на Хабре, хотя прикладная область применения довольна широка.
В данной статье будут приведены примеры взаимодействия в рамках задач администрирования с помощью Python.
Для Python есть библиотека под названием pyVmomi от самой VMware.
- GitHub
- VMware vSphere API Reference
Подготовка
В папке проекта создадим конфигурационный файл config.txt следующего содержания:
[VSphere]
host=10.10.1.2
user=admin@domain
pwd=password
Для его чтения используем модуль configparser.
config = configparser.ConfigParser()
config.read("config.txt")
Чтобы подключиться к сфере, используются методы pyVim.connect.SmartConnect и pyVim.connect.SmartConnectNoSSL. Второй применяется для самоподписанных сертификатов.
from pyVim.connect import SmartConnectNoSSL
connection = SmartConnectNoSSL(**config["VSphere"])
Список машин по месту на датасторах
Предположим, на датасторах закончилось место. Эту проблему мы сейчас будем решать. Цель — получить список виртуальных машин, отсортированный по убыванию размера занятого места на датасторах. Также выведем максимальный размер файла, до которого может вырасти диск виртуальной машины, и количество места, занятого в гостевой системе.
Получить список виртуальных машин можно следующим образом:
from pyVmomi import vim
def get_all_vms():
content = connection.content
container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
return [VirtualMachine(managed_object_ref) for managed_object_ref in container.view]
Как можно было заметить, возвращается список объектов класса VirtualMachine. Сейчас его и реализуем:
class VirtualMachine:
def __init__(self, machine_object):
self.vm = machine_object
@property
def name(self):
return self.vm.name
@property
def provisioned_space(self):
return int(self.vm.summary.storage.committed + self.vm.summary.storage.uncommitted) / 1024**3
@property
def guest_disk_usage(self):
return sum([int(i.capacity - i.freeSpace) for i in self.по размеру снапшотаvm.summary.vm.guest.disk]) / 1024**3
@property
def usage_storage(self):
return int(self.vm.summary.storage.committed) / 1024**3
def __repr__(self):
return "{} {:.2f} {:.2f} {:.2f}".format(self.name, self.provisioned_space,
self.guest_disk_usage, self.usage_storage)
Вывод данных уже зависит от необходимости. Самое простое — вывести в консоль:
for virtual_machine in sorted(get_all_vms(), key=lambda vm: vm.usage_storage, reverse=True):
print(virtual_machine)
Размеры и количество снапшотов
С размерами виртуальных машин разобрались. Предположим, мы хотим узнать, сколько снапшотов имеет каждая виртуальная машина, и сколько места они занимают.
Логика предыдущего примера сохраняется, только теперь наш класс VirtualMachine будет выглядеть так:
class VirtualMachine:
def __init__(self, machine_object):
self.vm = machine_object
self.snapshot_count, self.snapshot_size = self._snapshot_info()
@property
def name(self):
return self.vm.name
def _snapshot_info(self):
disk_list = self.vm.layoutEx.file
size = 0
count = 0
for disk in disk_list:
if disk.type == 'snapshotData':
size += disk.size
count += 1
ss_disk = re.search('0000\d\d', disk.name)
if ss_disk:
size += disk.size
return count, size / 1024**3
def __repr__(self):
return "{} {:.2f} {}".format(self.name, self.snapshot_size, self.snapshot_count)
И вывод будет отсортирован уже по размеру или по количеству:
for virtual_machine in sorted(get_all_vms(), key=lambda vm: vm.snapshot_size, reverse=True):
print(virtual_machine)
Восстановление снапшота
Раз пошла речь про снапшоты, то поговорим об их восстановлении.
Гипотетическая задача — восстановить последние созданные снапшоты, в названии которых присутствует строка infra.
Для восстановления снапшота необходимо создать задачу RevertToSnapshot_Task().
Сперва получим необходимый список машин:
def get_vms(part_of_name):
content = connection.content
container = content.viewManager.CreateContainerView(content.rootFolder, [vim.VirtualMachine], True)
return [managed_object_ref for managed_object_ref in container.view if part_of_name in managed_object_ref.name]
Для получения последнего созданного снапшота вернем последний элемент списка vm.snapshot.rootSnapshotList, отсортированного по полю createTime:
def get_last_snapshot(vm):
try:
return sorted(vm.snapshot.rootSnapshotList, key=lambda snap: snap.createTime)[-1]
except AttributeError:
return None
Теперь же можем восстановить этот снапшот:
def restore_snapshot(snaphot_obj):
task = snaphot_obj.snapshot.RevertToSnapshot_Task()
WaitForTask(task, connection)
Теперь все объединим:
part_of_name = "infra"
for vm in get_vms(part_of_name):
last_snapshot = get_last_snapshot(vm)
if last_snapshot:
restore_snapshot(last_snapshot)
Включение/выключение по списку
Для выключения виртуальной машины необходимо создать задачу PowerOffVM_Task().
Напишем функцию выключения машины, если она включена:
def poweroff_if_enabled(vm):
if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
vm.PowerOffVM_Task()
Итоговый скрипт:
part_of_name = "infra"
for vm in get_vms(part_of_name):
poweroff_if_enabled(vm)
Такое выключение машины будет принудительным. Гораздо правильнее будет вызвать задачу ShutdownGuest():
def shutdown_guest(vm):
if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
vm.ShutdownGuest()
В конце хотелось бы привести еще несколько полезных ссылок:
- pyvmomi samples — примеры от самой VMware
- pyvmomi community samples — репозиторий с примерами использования библиотеки, написанными сообществом
- govmomi — пакет для языка goland. Его использует kubernetes
- rbvmomi — ruby-интерфейс для vSphere API
Если тема вызовет интерес, мы готовы ее продолжить и рассказать, как автоматизировать развертывание приложения от пуша в Git до создания виртуальной машины с работающим инстансом.