OpenStack Cinder provides an API to attach/detach volume to Nova instances. This is public, but not documented API which is used only by Nova now.  In scope of “Attach/detach volumes without Nova” [1] blueprint we introduce new python-cinderclient extension to provide attach/detach API not only for Nova called python-brick-cinderclient-ext. Before Mitaka release everybody who want to use Cinder volumes not only with Nova instances have to create hardening scripts based on python-cinderclient and os-brick [3] projects to make it done.

Since Mitaka, Cinder opens attach/detach API for any users. It will allow to:

 

  • Attach volume to Ironic instance
  • Attach volume to any virtual/baremetal host which is not provisioned by Nova or Ironic

 

It means, Cinder becomes stand-alone project that could be used outside OpenStack cloud with one limitation: Keystone is still required.

For now, python-brick-cinderclient-ext has only ‘get-connector’ API. Attach/detach features are under development and any feedback are welcome to get implemented in the best way. I hope, it will be implemented and documented as well in scope of Mitaka release cycle.

I will show you how it works in current proof-of-concept code [4]. Anybody is welcome to review and test it:).

To demonstrate this feature I will use virtual Devstack environment with Ironic+Cinder. Here is my local.conf [5].

Current limitations are:

 

  • Ironic instance must have access to API and storage networks (it works on Devstack with a default configuration
  • Users inside instance must have root permissions and be able to install required software

 

Detailed manual how to setup Ironic using Devstack could be found here [6]. Since volumes attach/detach operations require python, open-iscsi, udev and other packages I will use Ubuntu-based image for Ironic instances. You can use Ubuntu cloud image [7] or build your own using ‘disk-image-builder’ tool [8]. I’ve built my Ubuntu image with disk-image-builder:

$  disk-image-create ubuntu vm dhcp-all-interfaces grub2 -o ubuntu-image
$  glance image-create --name ubuntu-image --visibility public \
--disk-format qcow2 \
--container-format bare < ubuntu-image.qcow2

After it we need to run Ironic instance:

#  query the image id of the default cirros image
$  image=$(nova image-list | egrep "ubuntu" | awk '{ print $2 }')
#  create keypair
$  ssh-keygen
$  nova keypair-add default --pub-key ~/.ssh/id_rsa.pub # spawn instance $ prv_net_id=$(neutron net-list | egrep "$PRIVATE_NETWORK_NAME"'[^-]' | awk '{ print $2 }') $ nova boot --flavor baremetal --nic net-id=$prv_net_id --image $image --key-name default testing

Wait until instance is booted and ready [9]:

$  nova list
$ ironic node-list

Now you can connect to the instance using SSH:

$  ssh ubuntu@10.1.0.13

By default, in Devstack both Nova and Ironic instances have access to OpenStack APIs.

To attach volume you need to install required packages inside you instance:

$  sudo apt-get install -y open-iscsi udev python-dev python-pip git

NOTE: if you can't acces Internet inside your instance, try the following command on the DevStack host:

$  sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERAD

Clone and install the latest python-cinderclient (the latests version from PyPi will also work but you'll need to pass --os-volume-api-version explicit):

$  git clone https://github.com/openstack/python-cinderclient.git
$  cd python-cinderclient
$  sudo pip install .

Clone the python-brick-cinderclient-ext and apply the patch:

$  git clone https://github.com/openstack/python-brick-cinderclient-ext.git
$  cd python-brick-cinderclient-ext
$  git fetch https://review.openstack.org/openstack/python-brick-cinderclient-ext refs/changes/44/263744/8 && git checkout FETCH_HEAD
$  sudo pip install .

That’s all! Now, you can attach/detach volumes inside your instance. Because it is still PoC implementation you need few additional steps:

$  PATH=$PATH:/lib/udev
$  export PATH

The steps above is needed until python-brick-cinderclient-ext will use oslo.rootwrap or privsep libraries.

Verify, that python-brick-cinderclient-ext works well [10] (you need to setup your own credentiala and auth_url):

$  cat << EOF >> ~/openrc
 #!/usr/bin/env bash
export OS_AUTH_URL="http://10.12.0.26:5000/v2.0"
export OS_IDENTITY_API_VERSION="2.0"
export OS_NO_CACHE="1"
export OS_PASSWORD="password"
export OS_REGION_NAME="RegionOne"
export OS_TENANT_NAME="admin"
export OS_USERNAME="admin"
export OS_VOLUME_API_VERSION="2"
 EOF
$  source ~/openrc
$  sudo -E cinder get-connector

You should get something this: [11].

Finally, create and attach volume to your Ironic instance:

$ cinder create 1
$ sudo -E PATH=$PATH cinder local-attach 0a946c67-2d5c-4413-b8ec-350240e967d2

You should get something like: [12]

Now you can verify that volume is attached via iSCSI protocol [13]:

$  sudo iscsiadm -m session
$  ls -al /dev/disk/by-path/ip-192.168.122.32:3260-iscsi-iqn.2010-10.org.openstack:volume-625e9acc-d5d8-4e7b-84c6-3b55ed98e3f3-lun-1

Detach is also easy:

$  sudo -E PATH=$PATH cinder local-detach 0a946c67-2d5c-4413-b8ec-350240e967d2

That’s all! You’ve got attached your Cinder volume to an Ironic instance without Nova! You can do the same steps to attach volumes inside Nova instance or your desktop. It will work too. I will show you a demo with Nova instance and cloud config scrips in the next post.

 

[1] https://github.com/openstack/cinder-specs/blob/master/specs/mitaka/use-cinder-without-nova.rst
[2] https://github.com/openstack/python-brick-cinderclient-ext
[3] https://github.com/openstack/os-brick
[4] https://review.openstack.org/263744
[5] https://gist.github.com/e0ne/2579921aba839322decc
[6] http://docs.openstack.org/developer/ironic/dev/dev-quickstart.html#deploying-ironic-with-devstack
[7] https://cloud-images.ubuntu.com/
[8] http://docs.openstack.org/developer/ironic/deploy/install-guide.html#image-requirements
[9] http://paste.openstack.org/show/483734/
[11] http://paste.openstack.org/show/483742/
[12] http://paste.openstack.org/show/483743/


Other useful links:

Didn't google "how to run horizon integration tests" unswer in 10 seconds. Making note how to do it.

My development environment usually looks like: macbook + VM with Ubuntu Server or CentOS without GUI. I try to run all tests inside VMs. In case of Selenium tests, I need some preparation for it:

  1. $ sudo apt-get install firefox
    this command will install FireFox. Selenium has WebDriver for it out of the box
  2. $ sudo apt-get install xvfb
    install Virtual Frame Buffer for X Server (https://en.wikipedia.org/wiki/Xvfb)
  3. Run tests:
    • Simple way for OpenStack Horizon:
      ./run_tests.sh --integration --selenium-headless
    • Hard way for any project:
      • Start xvfb:
        $ sudo Xvfb :10 -ac
      • Start headless FireFox:
        DISPLAY=:10 firefox
      • run tests
Useful links:

В очередной раз чуть не наткнулся на давнюю проблему, но вовремя опомнился. При pylint “радостно” сообщил, что в некоторых модулях есть unused imports и их можно(нужно) удалить. Все было бы хорошо, если б не одно но: python очень даже динамический язык, а pylint ничего не знает о том, что будет происходить с кодом во время выполнения. Исходя из этого, уже можно представить какие проблемы могут быть. В моем случае, код был такой:

from quantum.openstack.common import cfg
...
from quantum.plugins.openvswitch.common import config

И pylint “ругался” на 2-й импорт, который нигде больше не использовался. Но если посмотреть на код этого модуля (https://github.com/openstack/quantum/blob/master/quantum/plugins/openvswitch/common/config.py) и вспомнить как работает механизм импорта в Python’е, то становится ясно, какие проблемы могут быть: при загрузке модуля config, он устанавливает значения по умолчанию настроек. А так, как со всемы настройками принято работать через общий интерфейс cfg, и не импортировать можуль config, то, с большой вероятностью, где-то в runtime у нас произойдет исключение. 

Описанный выше пример простой и банальный, но приводит нас к двум простым правилам:

  • нельзя слепо доверять анализаторам кода, особенно, если этот код динамический;
  • при проведении review кода нужно смотреть не только на новый/измененный фрагмент, а следует держать в голове полную картину и представлять как этот код будет работать с остальными частями приложения.

Вот интересно, если бы не unit-тесты и понимание работы import’ов, сколько бы времени потратил на фикс бага, после такого “улучшения” кода?


 

Из wiki.openstack.org:

Quantum is an OpenStack project to provide "network connectivity as a service" between interface devices (e.g., vNICs) managed by other Openstack services (e.g., nova).

Из описания можно предположить, что в будущем это станет заменой nova network, что не далеко от правды. Ниже я расскажу об установки OpenStack + Quantum и немного о самом Quantum.

Установка OpenStack c помощью скриптов devstack является одной из самых простых и быстрых. В простейшем случае, это выглядит так:

$ git clone https://github.com/openstack-dev/devstack.git
$ cd devstack && ./stack.sh

После этого нужно будет лишь ввести свой root-пароль, пароль к MySql серверу и пароли к Openstack’у. При установке Quantum нужно создать и/или отредактировать файл localrc в каталоге с Devstack’ом и добавить туда следующие строчки:

disable_service n-net
enable_service q-svc
enable_service q-agt
enable_service q-dhcp
enable_service quantum
LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver
Q_PLUGIN=openvswitch

Разберем эти строчуки подробнее:

 

  • LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver - настраивваем libvirt для корректной работы файрволла с Quantum
  • Q_PLUGIN=openvswitch - указываем, что в качестве плагина (back-end’а) использовать Open vSwitch.
  • disable_service n-net - отключение nova-network, теперь вместо этого компонента будет работать Quantum.
  • enable_service q-svc - включаем Quantum Server. По сути, после скачивания исходников и первоначальной настройки выполнится такая команда: “/opt/stack/quantum/bin/quantum-server --config-file /etc/quantum/quantum.conf --config-file /etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini”. На момент написания этого поста есть баг, в котором описано что Quantum plugins должны использовать тот жу конфигурационный файл, что и Quantum. Но пока это не пофикшено.
  • enable_service q-agt - запустить Quantum agent. Т.к. в качестве плагина был выбран Open vSwitch, то и запустится, соответственно, Open vSwitch Plugin: $ sudo python /opt/stack/quantum/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py --config-file /etc/quantum/quantum.conf --config-file /etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini
  • enable_service q-dhcp - Quantum DHCP Agent, который управляет DHCP сервером внутри нашей виртуальной сети. Запускается он следующей командой:  sudo python /opt/stack/quantum/bin/quantum-dhcp-agent --config-file /etc/quantum/quantum.conf --config-file=/etc/quantum/dhcp_agent.ini.  Из коробки это dnsmasq, но можно написать поддержку любого сервера.

 

После правки localrc можно запускать stack.sh и подождать пока все будет установленно.

Кроме установки самого OpenStack’а, devstack так же создает тестовых пользователей, проектов и сети. Т.к. говорим о Quantum, то о сетях подробнее.

Сам по себе Quantum (так сказать, его core) предоставляет только API для создания и управления сетями. Самим управлением занимаются его плагины (plugins), которые, imho, правильнее было бы назвать бэк-ендами (back-ends). В текущей версии (Folsom) возможна одновременная работа только одного плагина. Т.к. мы установили Open vSwitch, то далее буду описывать работу Quantum с ним.

Основные понятия в Quantum:

 

  • network - изолированный L2 сегмент сети, аналог VLAN;
  • subnet - блок IPv4 или IPv6 адресов и их конфигурация (маршрутизатор, DNS-сервер)
  • port - точка подключения устройств (vNICs) в сеть Quantum.

 

Если смотреть на взаимодействие Quantum Network и OpenStack, то это выглядит так:

У каждого тенанта может быть одна и более сетей. У каждой сети может быть от 1 до n подсетей (конечно, может быть и 0 сетей/подсетей, по смысла в этом нет). Если смотреть на то, как все рабтало без Quantum, то теперьешине subnets это аналоги nova networks. При замуске виртуалки (инстанса), ей нужног передать к какой из сетей тенанта она подключена. Для каждой подсети будет создан отдельный vNIC у инстанса, который будет подключен к какому-либо порту. В нашем случае - это порт в Open vSwitch.

Посмотрим как это работает на практики:

Open vSwitch работает поверх бриджей (bridge), поэтому посмотрим какие “мосты” у нас есть:

$ sudo ovs-vsctl list-br
br-int
br-tun

Сейчас нас интересует br-int, поэтому посмотрим какие у него есть порты:

$ sudo ovs-vsctl list-ports br-int

patch-tun
tap6d98326d-5a
tap6e1a8612-27
tapf842abe0-27

В данной конфигурации, у меня запущено два инстанса, которые подключены к портам tap6e1a8612-27 и tapf842abe0-27. Порт patch-tun служит для “проброса” трафика между виртуальной сетью и физической через TUN-интерфейс. К порту tap6d98326d-5a подключен DHCP-сервер(dnsmasq) для инстансов внутри subnet.

Посмотрим, какие у нас есть сети в Quantum:

$ quantum net-list

 

И подсети:

$ quantum subnet-list

 

Порты:

$ quantum port-list

 

Тут мы видем, что у нашего DHCP-сервера адрес 10.0.1.2, а у инстансов 10.0.1.3 и 10.0.1.4.

 

Теперь, когда мы хоть немного имеем представление о сети, попробуем запустить новый инстанс:

$ nova boot --flavor 1 --image 4032fc9c-4688-4e71-ba2d-5a90e7698230 --nic net-id=3d5a9b8d-40cf-4f7b-a344-3db20f1a4783 test_vm_3

Синтаксис стандартный за исключением того, что я явно передал к какой сети подключать инстанс “--nic net-id=3d5a9b8d-40cf-4f7b-a344-3db20f1a4783”

Убедимся, что инстанс запустился командой “nova list”. И если у него статус ACTIVE, то можно попробовать попинговать или зайти по SSH:

Тут мы обнаруживае, что из хоста у нас нет доступа к виртуалкам :(. Хотя, если зайти через VNC на виртуалки, то они нормально будут видет другие инстансы в той же подсети.

 

Все дело в том, что Quantum организует работу с сетями через network netspace (http://stuff.onse.fi/man?program=ip-netns&section=8), поэтому, алгоритм работы немного усложняется:

смотрим список текущих неймспейсов:

$ ip netns

Выполняем ping/ssh внутри нужного неймспейса:

~$ sudo ip netns exec qdhcp-3d5a9b8d-40cf-4f7b-a344-3db20f1a4783 ssh 10.0.1.4

 

Ссылки по теме:

 

Продолжение следует...


 

Никогда не знаешь, где упадет OpenStack(c) 
Я, в процессе очередного дебагга.

Те, кто читает мой твиттер (@e0ne), должны знать, что в последнее время я работаю с OpenStack’ом, а именно занимаюсь(конечно, не один я) попытками его запуска на Red Hat Enterprise Linux (RHEL), CentOS, Scientific Linux, etc. Т.к. все это построено на базе полной и непросветной enterpise в виде RHEL, то сборка нового дистрибутива, как правило, у меня начинается со сборки именно под эту ОС. 

Вот я и хочу поделиться своими впечатлениями от сборки последней версии OpenStack’а под RHEL. Началось все с попытки запустить чуть менее чем полностью поломанную версию essex-1. Потом все продолжилось с версией essex-2. Основные моменты, которые мешали мне радоваться жизни - переделки в glance, связанные и security, которые на время поломали работоспособность EC2 API. 

Проект Glance - это услуги по отбору, регистрации и поиску виртуальных «machine images» (VMI). В рамках Glance используется RESTful API, что позволяет делать запрос метаданных VMI и выполнять поиск фактического образа (VMI). (http://openstack.ru/openstack_glance.html)

И тут я решил попробовать запустить все из последней версии исходников, с master’а...

После небольших усилий инстансы (виртуалки) начали запускаться, но были проблемы с сетью. Команда “killall dnsmasq”, подсказанная моим коллегой, решила часть проблем, а именно - выдачу IP адреса виртуальной машине. Далее в логах при загрузке неворуженым глазом были замечены такие проблемы:

 

Что означало, что запущенный инстанс не может получить данный от Metadata Server’а. Т.к. Metadata Server нормально работал в Diablo, то сразу вспомнились 2 вещи:

 

 

Далее по аналогии с Nova API был создан файл /etc/init.d/openstack-nova-api-metadata, который предназначался для запуске сервиса Metadata Server’а. Metadata Server, на первый взгляд, успешно запустился, то я попытался запустить снова инстанс, что мне привело к предыдущей ошибке. Логи Metadata Server’а немного испугали:

 

Мозг сразу начал представлять кошмары, связанные с выводом strace, linux kernel debugger’ом и так далее. Вовремя опомнившись, я полез в Google. Поиск по “exit code 134” ничего полезного не дал. А вот поиск по “iptables-restore buffer overflow” дал нужный результат в виде двух багов iptables: http://bugzilla.netfilter.org/show_bug.cgi?id=641 иhttps://bugzilla.redhat.com/show_bug.cgi?id=545600. Довольно-таки стандартное, на сколько мне известно, переполнение буфера, вызванное функцией strcpy, которую, к слову, не очень-то и рекомендуют использовать. Подробности в этом комментарии: https://bugzilla.redhat.com/show_bug.cgi?id=545600#c6

 

 

Т.к. обновление iptables в RHEL 6.1 - не самая приоритетная для меня задача, то я решил зайти с другой стороны - посмотреть что же делает OpenStack для получения такого результата.

 

 

https://github.com/openstack/nova/blob/master/bin/nova-api-metadata

Metadata Server запускается таким же способом, как и другие REST-сервисы Nova, поэтому проблему нужно было искать где-то дальше. Об этом же говорили и логи, и ошибка, связанная с iptables.

https://github.com/openstack/nova/blob/master/nova/network/linux_net.py

 

Метод metadata_accept() отрабатывает без ошибок и падает все в iptables_manager.apply().

 

Т.к. данный метод используется далеко не в одном месте

 

 

то ошибка где-то в передаваемых параметрах. В качестве параметров к iptables-restore у меня передавалось такое:

 ip-restore-full.jpg

 

 

Зная о баге в iptables и то, что падало все только при запуске Metadata Server’а, то получилось быстро найти нужную команду, которая все ломала:

iptables-restore <<EOF
*nat
:nova-api-metadata-POSTROUTING - [0:0]
-A POSTROUTING -j nova-api-metadata-POSTROUTING
COMMIT
EOF

len(‘nova-api-metadata-POSTROUTING’)==29, что вместе с символом конца строки в языке С давало нам 30 символов и при копировании их в массив из 29 символов давало нам переполнение буффера (см. ссылки на баги выше). Хорошо, проблема найдена, теперь нужно ее устранить. Для этого находим код, где у нас генерируется имя chain’а:

chain1.jpg, chain2.jpg

 

где:

binary_name = os.path.basename(inspect.stack()[-1][1])

Таким образом проблема была в имени исполняемого файла. Переименовав “/usr/bin/nova-api-metadata” в “/usr/bin/nova-metadata ” все заработало. Вопрос лишь в том, насколько долго оно будет работать с таким “фиксом”? 

Более правильное решение нужно делать исправляя код OpenStack’а и/или обновляя iptables. Также интересно как это себя ведет на других RHEL-based дистрибутивах(версия iptables) и ubuntu, но это уже проверю завтра, а пока поставил качаться нужные образы дистрибутивов...

[Update]

Баг с iptables проверен после установки чистой ОС после установки всех апдейтов с помощью команды "yum update" на следующих ОС:

  • RHEL 6.1 x86_64 - iptables v1.4.7, buffer overflow detected
  • RHEL 6.2 x86_64 - iptables v1.4.7, buffer overflow detected
  • CentOS 6.1 x86_64 - iptables v1.4.7 buffer overflow detected
  • CentOS 6.2 x86_64 - iptables v1.4.7 buffer overflow detected
  • Scientific Linux 6.1 x86_64 - iptables v1.4.7 buffer overflow detected
  • Fedora 15 x86_64 - testing in process
  • Fedora 16 x86_64 - testing in process

 


Git: создаем branch из tag'а

Published 12/21/2011 by e0ne in Python
Tags: ,

 

Любая source control система (TFS, SVN, Git и т.д.) умеет работать с такими вещами, как branch (ветка) и tag (метка). Ветки нужны для разработки каких-то фич, исправления багов и т.д., что бы в это время не ломать уже работающий код. Тэги, в свою очередь, нужны для заморозки какой-то версии кода без возможности последующих исправлений. Грязные хаки вроде залезть в базу данных source control чтобы поменять файл с каким-то тэгом я не рассматриваю по понятным причинам.

В моем случае, изменения в код с каким-то тэгом было связано с задачей сборки новой версии Openstack essex-2 под Red Hat Enterprise Linux (RHEL). Алгоритм работы был, примерно такой:

 

  • забираем исходники Openstack’а: $ git clone https://github.com/openstack/nova.git
  • переключаемся на нужный тэг: $ git checkout essex-2
  • делаем необходимые изменения в коде и пытаемся запушить в новый бранч: $ git push myrepo essex-2.

 

После данных действий, в моем репозитории, к удивлению, вместо нового бранча с нужными изменениями появился тэг essex-2, который был идентичен такому тэгу с официального репозитория Openstack’а. Чтение Pro Git расставило все на свои места и стало ясно почему так случилось.

Далее, для выполнения нужных мне действий понадобилось выполнить команды: 

 

  • $ git checkout -b branchname tag
  • $ git push myrepo essex-2

 

Что эквивалентно такому:

 

  • $ git branch branchname tag
  • $ git checkout branchname
  • $ git push myrepo essex-2

 

Надеюсь что мой пост не помешает правильному использованию тэгов.

 


 

Сейчас только ленивый не писал об облаках. То, что раньше было просто веб-сервисом - сайчас SaaS. Вот раньше я пользовался gmail просто как почтой, теперь мне навязывают что это SaaS и поэтому это еще лучше. Как пользователю - мне все-равно как оно устроено.  Но вернемся ближе к теме поста и посмотрим какие облака вообще бывают.

Наиболее распространенные типы облаков (clouds) это (точные определения можно найти на Википедии, я говорю так, как выглядит это для меня):

  • SaaS (Software as a Service) - софт, как правило, веб-приложения, который работает где-то там на на сервере и не требует установки и/или мощного клиента. Такое себе арендованное ПО.
  • PaaS (Platform as a Service) - платформа для разработки ПО (Google App Engine, Azure). Позволяет с минимальными усилиями писать масштабируемые приложения. Тут провайдер PaaS берет на себя все или почти заботы по масштабированию приложения, обеспечению беспрерывной работы, администрированию серверов и т.д.
  • IaaS (Infrastructure as a Service) - грубо говоря, вам в аренду даются n-е количество серверов(облако), где при необходимости можно быстренько добавить и/или уменьшить количество серверов, памяти на них, объем винчестеров и т.д. Как пример IaaS - Amazon EC2.

Разработка любого облака - достаточно сложное и интересное занятие. Создать с нуля можно, но много уже есть готового. Opensource проектов для создания своего приватного клауда становится все больше. Openstack - один из таких проектов. Это IaaS платформа, написанная на Python. Если немного погуглить, то можно найти нечто похожее на Java и Ruby.

Описывать архитектуру и как работает Openstack я сейчас не буду. Я расскажу лишь о том, что нужно знать для комфортной работы с Openstack’ом. Мне, как веб-разработчику было достаточно быстро войти в процесс, т.к. проект требует спецефических знаний. Один лишь список модулей питона, которые необходимы для запуска одного из компонентов Openstack’а nova содержит 35 пунктов.

  • Python - ведь на нем все написано. Как правило, код достаточно простой и понятный, много комментариев. При написании кода соблюдается PEP8.
  • Знание linux-подобных ОС. Прежде всего, Openstack разрабатывался для работы под Ubuntu, но есть сборки и для других ОС. Под другими ОС имеется в виду Red Hat, CentOS, Fedora и т.д. И врядли он когда-нибудь будет работать под Windows - уж слишком много OS-specific мест наподобии работы с образами виртуальных машин, работа с сетью и т.д. Так же количество гипервизоров по linux значительно больше. Комфортная работа с консолью и понимание того как устроена ОС - навыки, без которых сложно будет работать.
  • Так как одной из основных задач Openstack’a является запуск виртуальных машин(серверов), то знание того как работает виртуализация будут большим плюсом.
  • Работа с сетью, понимание как что работает (VLAN, bridge-интерфейсы, маршрутизация и т.д.), уметь пользоваться iptables.
  • Git - проект хостится на GitHub’е.

Openstack в сети: http://openstack.org
GitHub: https://github.com/openstack