В случае отсутствия expression, повторно возбуждается последнее исключение, которое было активно в данной области. Если такого исключения нет, то возбуждается исключение RuntimeError, чтобы сообщить о данной ошибке.
В противном случае raise выполняет первый expression и получает объект исключения. Он должен являться либо подклассом либо экземпляром BaseException. Если первый expression является именем класса, то создается объект путём вызова класса без передачи аргументов. Читать →
Вызывается когда экземпляр должен быть уничтожен (другими словами — это деструктор). Если родительский класс тоже имеет метод __del__(), то производный класс в своём методе __del__(), если он определён, должен явно вызывать метод родительского класса, чтобы гарантированно уничтожить методы родительского класса. Стоит отметить, что возможно (хотя и не рекомендуется) сделать так, чтобы в методе __del__() было отложено уничтожение самого объекта. Это достигается созданием на него другой ссылки перед удалением текущей, и уже при уничтожении последней ссылки надо будет уничтожить сам объект. Гарантии того, что метод __del__() будет вызван для существующих объектов при завершении работы интерпретатора нет.
Заметка
del x не является прямым вызовом x.__del__() — первая форма сокращает количество ссылок на объект x на одну, тогда как последний метод вызывается только когда количество ссылок достигает нуля. В некоторых часто встречающихся случаях могут возникнуть ситуации, мешающие обнулению счётчика, как то:
взаимные ссылки между объектами (в списках или в деревьях)
ссылки на объекты в стеке функции, где было вызвано исключение, так как в таком случае ссылки на объекты этого стека сохранены в sys.exc_traceback
ссылки на объекты в стеке, если было вызвано не перехваченное исключение в интерактивном режиме (так как в таком случае ссылки на объекты сохранены в sys.last_traceback)
В первом случае необходимо явно разрушить циклические ссылки; во втором и третьем — сохранить None в sys.exc_traceback или sys.last_traceback. Циклические ссылки определяются сборщиком мусора, если активирована соответствующая опция (как оно и есть по умолчанию), однако, если вызывается метод __del__() в коде, такие ссылки не будут обработаны автоматически. Обратитесь к документации модуля gc для более подробной информации, особенно к разделу, описывающему значение garbage.
Предупреждение
В связи с неопределёнными обстоятельствами, когда вызывается метод __del__(), исключения, возникающие в процессе выполнения этого метода игнорируются, а предупреждения об этом выводятся в sys.stderr. Кроме того, когда вызывается метод __del__(), относящийся к удалению модуля (например, когда завершено выполнение программы) другие объекты, определённые в этом методе могут быть уже уничтожены или быть в процессе уничтожения (например, когда происходит выключение механизма импортирования). По этой причине метод __del__() должен содержать минимум внешних зависимостей. Начиная с версии 1.5 Python гарантирует, что глобальные имена, начинающиеся с _ удаляются из модуля прежде остальных глобальных имён; поэтому если нет других ссылок на эти переменные, по их наличию можно определить доступность импортированного модуля в процессе вызова метода __del__().
В python есть негласное правило — никогда не повторяйся. Чаще всего если в программе приходиться писать почти одно и то-же два раза, значит вы что-то сделали не так. Я приведу пример, как можно автоматизировать генерацию внешних API таким образом, что достаточно будет в одном месте в удобной и универсальной форме описать поддерживаемые вызовы, а все внешнее API для этих вызовов сделает написаный один раз код. Читать →
Функционирование виртуальных сетей обеспечивается различными технологиями, которые я бегло опишу:
bridges — сетевые мосты — программные аналоги свичей, позволяют соединить вместе несколько сетевых интерфейсов и передавать между ними пакеты, как если бы они были включены в один свич. Бриджи управляются с помощью команды brctl:
Перед работой с бриджами лучше ознакомиться с документацией, они содержат некоторое количество нетривиальных моментов.
tun (tap) — виртуальные сетевые интерфейсы. В отличии от аппаратных привязаны к определенному процессу пользовательского режима, а не к сетевой карте. Родительский процесс может писать/читать данные из виртуального интерфейса имитируя работу сети. В остальном они не отличаются от обычных интерфейсов. С помощью tun/tap работают многие VNP программы, например openvpn, которая создает tun/tap, вычитывает из него данные, шифрует и переправляет по обычной сети на другой компьютер, где второй процесс openvpn принимает данные, расшифровывает и записывает в свой tun/tap, имитируя прямое сетевое соединение между удаленными компьютерами. Как и 95% всех сетевых возможностей linux tun/tap можно управлять с помошью утилиты ip. Пример использования tun из python можно найти тут kharkovpromenade. Tun используются для создания сетевых интерфейсов виртуальынх машин.
iptables — система управления сетевым трафиком в linux. Обеспечивает фильтрация и модификацию трафика, управление сетевыми соединениями, etc. Возможности iptables чрезвычайно обширные и описывать даже примерно я их не буду, приведу только команды, позволяющие увидеть все правила на компьютере:
Все правила легко читаются даже без знания iptables.
Ок, с этим багажом уже можно разбираться с виртуальными сетями. Для большинства случаев нам не придется делать сети самостоятельно — libvirt берет эту работу на себя, предоставляя нам готовый результат. Начнем с устройства простейшей сети, которую со старта создает libvirt — defaults.
conn = libvirt.open("qemu:///system") net = conn.networkLookupByName('default') xml = fromstring(net.XMLDesc(0)) print"default net addr =", xml.find('ip').attrib['address'] print"default net mask =", xml.find('ip').attrib['netmask'] print"default net bridge =", xml.find('bridge').attrib['name']
import libvirt from xml.etree.ElementTree import fromstring
conn = libvirt.open("qemu:///system") net = conn.networkLookupByName('default') xml = fromstring(net.XMLDesc(0)) print "default net addr =", xml.find('ip').attrib['address'] print "default net mask =", xml.find('ip').attrib['netmask'] print "default net bridge =", xml.find('bridge').attrib['name
9;]
Подключила eth0 нашей виртуальной машины к бриджу virbr0 сети default. Эта сеть имеет маску 192.168.122.0/24, подключена через NAT к внешнему миру и обслуживается dhcp сервером. Причем сам virbr0 имеет ip 192.168.122.1 и служит гейтом для этой сети. Адреса из диапазона 192.168.122.2-192.168.122.40 я ранее зарезервировал для ручного распределения, отредактировав и перезапустив сеть.
Теперь вернемся к начальному вопросу — как программно узнать ip адрес, выданный нашей виртуалке? Есть три основных способа:
Если с виртуальной машиной уже был обмен данными, то можно посмотреть в кеше маршрутизации 'ip route show cache | grep virbr0' или в кеше аппаратных адресов — 'arp -na'. Способ наименее надежный, так как если обмена не было кеши будут пустые.
Достать информацию из базы dhcp сервера — leases. Для dnsmasq это по умолчанию файл /var/lib/libvirt/dnsmasq/default.leases: