Глава 15. Индивидуальная настройка

OpenStack не может выполнять все что вам нужно делать нетривиальным способом. Чтобы добавить новую функцию, вы можете следовать разными путями.

Первый способ- вы можете напрямую изменить код OpenStack. Ознакомьтесь: как внести свой вклад, следуйте рабочим потоком пересмотра кода, сделайте необходимые изменения и внесите их в назад вверх по течению проекта OpenStack. Этот путь рекомендуется, если необходимое вам свойство требует глубокой интеграции с уже существующим проектом. Сообщество всегда открыто для вклада и приветствует новую функциональность, которая следует руководством развития новых свойств. Этот путь все еще требует от вас использования DevStack для тестирования дополняемых вами функций, так что это глава ознакомит вас со средой DevStack.

Следуя вторым подходом, вы можете написать новые функции и подключить их при помощи изменения в файле конфигурации. Если проект, в котором ваша функциональная особенность для своего размещения будет нуждаться в использовании инфраструктуры Python Paste, вы можете создать программное обеспечение промежуточного уровня для него и подключить его при помощи настройки. Также могут существовать особые способы настройки проекта, например, создание нового драйвера планировщика для вычислительной среды или пользовательские вкладки для приборной панели.

В этой главе основное внимание уделено второму способу настройки OpenStack путем демонстрации двух примеров для написания новых функциональных особенностей. Первый пример показывает как внести изменения в программное обеспечение промежуточного уровня хранилища объектов (swift) добавив новую функцию, а второй пример предоставляет новую функцию планировщика для вычислительной среды OpenStack Compute (nova). Для подобной настройки OpenStack вам вы понадобится среда разработки. Лучший способ быстро получить среду и приступить к работе- это запустить DevStack в вашем облаке.

 Создание среды разработки OpenStack

Для создания среды разработки вы можете воспользоваться DevStack. DevStack по- существу является набором скриптов оболочки и файлами настройки, которые создают для вас среду разработки OpenStack. Вы используете их для создания подобной среды для разработки нового свойства.

Всю документацию вы можете найти на веб-сайте DevStack.

 

Чтобы запустить DevStack для стабильной ветви Havana в экземпляре вашего облака OpenStack:

  1. Загрузите экземпляр из инструментальной панели или при помощи интерфейса командной строки (CLI) со следующими параметрами:

    • Имя: devstack-havana

    • Образ: Ubuntu 12.04 LTS

    • Объем оперативной памяти: 4ГБ

    • Дисковый размер: минимум 5ГБ

    Если вы используете клиент nova, установите --flavor 3 для команды nova boot для получения отвечающих требованиям объема оперативной памяти и дискового пространства.

  2. Войдите в систему и установите DevStack. Приведем пример команд, которые вы можете использовать для установки DevStack на виртуальную машину:

    1. Зарегистрируйтесь в экземпляре:

      $ ssh username@my.instance.ip.address
    2. Обновите операционную систему виртуальной машины:

      # apt-get -y update
    3. Установите git:

      # apt-get -y install git
    4. Склонируйте стабильную ветвь havana из репозитория devstack:

      $ git clone https://github.com/openstack-dev/devstack.git -b
      stable/havana devstack/
    5. Переместитесь в свой репозиторий devstack:

      $ cd devstack
  3. (Не обязательно) Ксли вы зарегистрировались в системе как пользователь root, вы должны создать пользователя "stack"; в противном случае вы можете испытывать проблемы с разрешениями. Если вы зарегистрировались как пользователь, отличный от root, вы можете пропустить эти шаги:

    1. Выполните сценарий DevStack для создания пользователя stack:

      # tools/create-stack-user.sh
    2. Предоставьте пользователю stack права владельца на каталог devstack:

      # chown -R stack:stack /root/devstack
    3. Установите некоторые разрешения, которыми вы позже сможете воспользоваться для просмотра экрана DevStack:

      # chmod o+rwx /dev/pts/0
    4. Переключитесь на пользователя stack:

      $ su stack
  4. Отредактируйте файл настройки localrc, который управляет размещением DevStack. Скопируйте пример файла localrc в конце данного раздела (Пример 15.1, “localrc”):

    $ vim localrc
  5. Выполните сценарий stack, который установит OpenStack:

    $ ./stack.sh
  6. Когда сценарий stack завершится, вы можете открыть окно стартовавшего сеанса для просмотра всех запущенных служб OpenStack:

    $ screen -r stack
  7. Нажмите Ctrl+A с последующим 0 для перехода к первому окну screen.

[Замечание]Замечание
  • Сценарию stack.sh для запуска потребуется некоторое время. Возможно вы воспользуетесь этим удобным случаем чтобы присоединится к Фонду OpenStack.

  • Screen является удобной программой для просмотра за раз многих взаимосвязанных служб. Для получения дополнительной информации обратитесь к Быстрому руководству GNU screen.

Тепер, когда вы получили среду разработки OpenStack, вы может свободно заняться хакерством без беспокойства о том, что вы можете что-то разрушить в вашем развернутом продукте. Пример 15.1, “localrc” предоставляет работающее окружение для выполнения служб OpenStack идентификации, вычислительной среды, блочного хранения, образов, инструментальной панели и хранилища объектов со стабильной ветвью havana в качестве исходной точки.

 

Пример 15.1. localrc

# Credentials
ADMIN_PASSWORD=devstack
MYSQL_PASSWORD=devstack
RABBIT_PASSWORD=devstack
SERVICE_PASSWORD=devstack
SERVICE_TOKEN=devstack

# OpenStack Identity Service branch
KEYSTONE_BRANCH=stable/havana

# OpenStack Compute branch
NOVA_BRANCH=stable/havana

# OpenStack Block Storage branch
CINDER_BRANCH=stable/havana

# OpenStack Image Service branch
GLANCE_BRANCH=stable/havana

# OpenStack Dashboard branch
HORIZON_BRANCH=stable/havana

# OpenStack Object Storage branch
SWIFT_BRANCH=stable/havana

enable_service swift

# Object Storage Settings
SWIFT_HASH=66a3d6b56c1f479c8b4e70ab5c2000f5
SWIFT_REPLICAS=1

# Block Storage Setting
VOLUME_BACKING_FILE_SIZE=20480M

# Output
LOGFILE=/opt/stack/logs/stack.sh.log
VERBOSE=True
LOG_COLOR=False
SCREEN_LOGDIR=/opt/stack/logs

 Настройка ПО промежуточного уровня хранилища объектов (Swift)

Хранилище объектов OpenStack, известное как swift при чтении кодов, основано на инфраструктуре Python Paste. Лучшим введениев в ее архитектуру является A Do-It-Yourself Framework (Создайте собственную инфраструктуру). Поскольку проект swift использует эту инфраструктуру, вы можете добавлять новые функции в проект путем размещения пользовательского кода в конвейере проекта без каких- либо изменений в код ядра.

Представьте себе ситуацию, при которой у вас есть общественный доступ к одной из ваших контейнеров, однако в действительности вы хотите ограничить доступ к этому набору IP-адресов на основе белого списка. В данном примере мы создадим часть программного обеспечения промежуточного уровня для swift, которая позволяет получить доступ к контейнеру только из набора IP-адресов, которые определены элементами метаданных контейнера. Только те IP-адреса, которые вы явно занесли в белый список при помощи метаданных контейнера, смогут получить доступ к контейнеру.

[Предостережение]Предостережение

Данный пример приводится исключительно в демонстрационных целях. Он не может использоваться для решения белого списка IP контейнера без дальнейшей проработки и интенсивного тестирования безопасности.

Когда вы присоединитесь к экрану сеанса, который запустил stack.sh при помощи screen -r stack, вы увидите по экрану для каждой работающей службы, которых может быть немного или определенное количество: в зависимости от того как много служб настроен выполнять ваш DevStack.

Звездочка * обозначает какое окно экрана вы наблюдаете. Данный пример демонстрирует, что мы просмативаем окно экрана key (для keystone):

0$ shell  1$ key*  2$ horizon  3$ s-proxy  4$ s-object  5$ s-container  6$ s-account

Цели для окон экрана следующие:

shell

Оболочка, в которой вы можете выполнять некую работу

key*

Служба keystone

horizon

Веб-приложение инструментальной панели horizon

s-{name}

Службы swift

 

Чтобы создать программное обеспечение промежуточного уровня и подключить его при помощи настройки Paste:

Все коды для OpenStack размещаются в /opt/stack. Перейдите в каталог swift в оболочке экрана и отредактируйте ваш модуль ПО промежуточного уровя.

  1. Перейдите в каталог, в котором установлено хранилище объектов:

    $ cd /opt/stack/swift
  2. Создайте файл кода Python ip_whitelist.py :

    $ vim swift/common/middleware/ip_whitelist.py
  3. Скопируйте код из Примера 15.2, “ip_whitelist.py” в ваш ip_whitelist.py. Следующий код является образцом промежуточного программного обеспечения, которое ограничивает доступ к контейнеру на основе IP адресов, как это объяснялось в начале данного раздела. Промежуточное ПО передает запросы другому приложению. Данный пример использует библиотеку swift "swob" для обертывания запросов и ответов Web Server Gateway Interface (WSGI) к объектам для взаимодействия со swift. По окончанию сохраните и закройте файл.

     

    Пример 15.2. ip_whitelist.py

    # vim: tabstop=4 shiftwidth=4 softtabstop=4
    # Copyright (c) 2014 OpenStack Foundation
    # All Rights Reserved.
    #
    #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    #    not use this file except in compliance with the License. You may obtain
    #    a copy of the License at
    #
    #         http://www.apache.org/licenses/LICENSE-2.0
    #
    #    Unless required by applicable law or agreed to in writing, software
    #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    #    License for the specific language governing permissions and limitations
    #    under the License.
    
    import socket
    
    from swift.common.utils import get_logger
    from swift.proxy.controllers.base import get_container_info
    from swift.common.swob import Request, Response
    
    class IPWhitelistMiddleware(object):
        """
        IP Whitelist Middleware
    
        Middleware that allows access to a container from only a set of IP
        addresses as determined by the container's metadata items that start
        with the prefix 'allow'. E.G. allow-dev=192.168.0.20
        """
    
        def __init__(self, app, conf, logger=None):
            self.app = app
    
            if logger:
                self.logger = logger
            else:
                self.logger = get_logger(conf, log_route='ip_whitelist')
    
            self.deny_message = conf.get('deny_message', "IP Denied")
            self.local_ip = socket.gethostbyname(socket.gethostname())
    
        def __call__(self, env, start_response):
            """
            WSGI entry point.
            Wraps env in swob.Request object and passes it down.
    
            :param env: WSGI environment dictionary
            :param start_response: WSGI callable
            """
            req = Request(env)
    
            try:
                version, account, container, obj = req.split_path(1, 4, True)
            except ValueError:
                return self.app(env, start_response)
    
            container_info = get_container_info(
                req.environ, self.app, swift_source='IPWhitelistMiddleware')
    
            remote_ip = env['REMOTE_ADDR']
            self.logger.debug("Remote IP: %(remote_ip)s",
                              {'remote_ip': remote_ip})
    
            meta = container_info['meta']
            allow = {k:v for k,v in meta.iteritems() if k.startswith('allow')}
            allow_ips = set(allow.values())
            allow_ips.add(self.local_ip)
            self.logger.debug("Allow IPs: %(allow_ips)s",
                              {'allow_ips': allow_ips})
    
            if remote_ip in allow_ips:
                return self.app(env, start_response)
            else:
                self.logger.debug(
                    "IP %(remote_ip)s denied access to Account=%(account)s "
                    "Container=%(container)s. Not in %(allow_ips)s", locals())
                return Response(
                    status=403,
                    body=self.deny_message,
                    request=req)(env, start_response)
    
    
    def filter_factory(global_conf, **local_conf):
        """
        paste.deploy app factory for creating WSGI proxy apps.
        """
        conf = global_conf.copy()
        conf.update(local_conf)
    
        def ip_whitelist(app):
            return IPWhitelistMiddleware(app, conf)
        return ip_whitelist

    Вenv и conf существует много полезной информации которую вы можете использовать для принятия решения о том что делать с запросом. Для поиска того какие еще свойства доступны, вы можете вставить следующий оператор в метод __init__:

    self.logger.debug("conf = %(conf)s", locals())

    и следующий оператор протоколирования в метод __call__:

    self.logger.debug("env = %(env)s", locals())
  4. Чтобы вставить это промежуточное по в конвейер swift Paste, вы редактируете один файл настройки, /etc/swift/proxy-server.conf:

    $ vim /etc/swift/proxy-server.conf
  5. Найдите раздел [filter:ratelimit] в /etc/swift/proxy-server.conf, и скопируйте следующий сегмент настройки после него:

    [filter:ip_whitelist]
    paste.filter_factory = swift.common.middleware.ip_whitelist:filter_factory
    # You can override the default log routing for this filter here:
    # set log_name = ratelimit
    # set log_facility = LOG_LOCAL0
    # set log_level = INFO
    # set log_headers = False
    # set log_address = /dev/log
    deny_message = You shall not pass!
  6. Найдите раздел [pipeline:main] в /etc/swift/proxy-server.conf, и добавьте вперечень после ratelimit ip_whitelist подобный приведенному ниже. Когда завершите редактирование, сохраните и закройте файл:

    [pipeline:main]
    pipeline = catch_errors healthcheck proxy-logging cache bulk slo ratelimit ip_whitelist ...
  7. Перезапустите службу swift proxy позволив swift использовать ваше промежуточное ПО. Начните с переключения на экран swift-proxy:

    1. Нажмите Ctrl+A с последующим 3.

    2. Нажмите Ctrl+C для прекращения службы.

    3. Нажмитена клавишу стрелки Вверх для отображения последней команды.

    4. Нажмите Enter для еевыполнения.

  8. Проверьте свое промежуточное ПО с CLI swift.  Начните с переключения на экран оболочки завершите переключением назад на экран swift-proxy для проверки выдачи протокола:

    1. Нажмите Ctrl+A с последующим 0.

    2. Убедитесь, что вы находитесь в каталоге devstack:

      $ cd /root/devstack
    3. Чтобы установить переменные окружения для CLI, получите openrc:

      $ source openrc
    4. Создайте контейнер с названием middleware-test:

      $ swift post middleware-test
    5. Нажмите Ctrl+A с последующим 3 для проверки выдачи протокола.

  9. Среди предложений журнала вы можете увидеть строки:

    proxy-server Remote IP: my.instance.ip.address (txn: ...)
    proxy-server Allow IPs: set(['my.instance.ip.address']) (txn: ...)

    Эти два предложения выполнены нашим промежуточным ПО и показывают, что запрос был отослан из нашего экземпляра DevStack и был разрешен.

  10.  

    Проверьте наше промежуточное ПО извне DevStack на удаленной машине, которая имеет доступ к вашему экземпляру DevStack:

    1. Установите клиентов keystone и swift на вашу локальную машину:

      # pip install python-keystoneclient python-swiftclient
    2. Попробуйте отобразить список объектов в контейнере middleware-test:

      $ swift --os-auth-url=http://my.instance.ip.address:5000/v2.0/ \
      --os-region-name=RegionOne --os-username=demo:demo \
      --os-password=devstack list middleware-test
      Container GET failed: http://my.instance.ip.address:8080/v1/AUTH_.../
          middleware-test?format=json 403 Forbidden   You shall not pass!
  11. Нажмите Ctrl+A с последующим 3для проверки выдачи протокола. Взгляните снова на предложения swift в журнале, вы увидите строки:

    proxy-server Authorizing from an overriding middleware (i.e: tempurl) (txn: ...)
    proxy-server ... IPWhitelistMiddleware
    proxy-server Remote IP: my.local.ip.address (txn: ...)
    proxy-server Allow IPs: set(['my.instance.ip.address']) (txn: ...)
    proxy-server IP my.local.ip.address denied access to Account=AUTH_... \
       Container=None. Not in set(['my.instance.ip.address']) (txn: ...)

    Здест вы можете увидеть, что запрос был запрещен, поскольку IP удаленного узла не был установлен в список разрешенных.

  12. Вернитесь в ваш экземпляр DevStack на экран оболочки, дабавьте немного метаданных в ваш контейнер для разрешения запросов с удаленной машины:

    1. Нажмите Ctrl+A с последующим 0.

    2. Добавьте метаданные в контейнер для разрешения данного IP:

      $ swift post --meta allow-dev:my.local.ip.address middleware-test
    3. Теперь попробуйте снова повторить команды начиная с шага 10 и далее. В контейнере нет объектов, следовательно нечего отображать; однако также отсутствуют сообщения об ошибках.

[Предостережение]Предостережение

Функциональное тестирование подобное приведенному не замещает надлежащего тестирования блоков и интеграции, однако служит началом для вас.

Вы можете следовать подобному шаблону в других проектах, которые используют инфраструктуру Python Paste. Просто создайте модуль промежуточного ПО и подключите его при помощи настройки. Промежуточное программное обеспечение работает в последовательности как часть конвейера проекта по необходимости может вызывать другие службы. Не затрагивается никакой код ядра проекта. Найдите значение pipeline в файлах настройки проекта conf или ini в /etc/<project> для выявления проектов, использующих.

Когда ваше промежуточное программное обеспечение готово, мы советуем вам сделать его код открытым и и оповестить о нем сообщество через список электронной почтовой рассылки OpenStack. Возможно кому-то еще требуется подобная функциональность. Люди смогут воспользоваться вашим кодом и снабдить вас обратной связью, а также, возможно, сделать пожертвования. Если для вашего кода окажется достаточно поддержки, вы сможете предложить добавить его в официальное программное обеспечение промежуточного уровня swift middleware.

 Настройка планировщика вычислительной среды OpenStack (nova)

Многие проекты OpenStack допускабт настройку под индивидуальные требования пользователя особенных свойств с использованием архитектуры драйверов. Вы можете написать драйвер, который соответствует определенному интерфейсу и подключить его с использованием настроек. Например, вы легко можете подключить новый планировщик к вычислительной среде. Существующие планировщики для вычислительной среды функционально полны и хорошо документированы на странице Scheduling. Однако, в зависимости от случаев использования вашими пользователями, существующие планировщики могут не отвечать вашим требованиям. Возможно, вам потребуется создать новый планировщик.

Для создания планировщика вы должны наследовать из класса nova.scheduler.driver.Scheduler. Из пяти методов, которые вы можете переписывать, вы должны переписать два метода, помеченных ниже звездочкой (*):

  • update_service_capabilities

  • hosts_up

  • group_hosts

  • * schedule_run_instance

  • * select_destinations

Для демонстрации настройки OpenStack под индивидуального пользователя, мы создадим пример планировщика вычислительных ресурсов, который случайным образом размещает экземпляры в подмножестве хостов в зависимости от IP адреса инициации запроса и префикса имени хоста. Данный пример может оказаться полезным для случая, когда у вас есть группа пользователей подсети и вы хотите чтобы все их экземпляры запускались в пределах некоторого подмножества ваших хостов.

[Предостережение]Предостережение

Данный пример приводится исключеительно для иллюстрации. Он не должен использоваться в планировщике для вычислительной среды без дальнейшей доработки и тестирования.

Когда вы присоединяетесь к сеансу, который запустил stack.sh при помощи screen -r stack, вас встречает множество окон экрана:

0$ shell*  1$ key  2$ horizon  ...  9$ n-api  ...  14$ n-sch ...
shell

Оболочка, в которой вы можете выполнять некоторую работу

key

Служба keystone

horizon

Веб- приложение инструментальной панели horizon

n-{name}

Службы nova

n-sch

Служба планировщика nova

 

Чтобы создать планировщик и вставить его в конфигурацию:

  1. Код для OpenStack расположен в /opt/stack, следовательно, перейдите в каталог nova и отредактируйте ваш модуль планировщика. Перейдитев каталог, в котором установлен nova:

    $ cd /opt/stack/nova
  2. Создайте исходный файл кода Python ip_scheduler.py:

    $ vim nova/scheduler/ip_scheduler.py
  3. Код в Примере 15.3, “ip_scheduler.py” является драйвером, который будет управлять серверами для размещения на основе IP адресов, как это объяснялось в начале раздела. Скопируйте код в ip_scheduler.py. По окончанию сохраните и закройте файл.

     

    Пример 15.3. ip_scheduler.py

    # vim: tabstop=4 shiftwidth=4 softtabstop=4
    # Copyright (c) 2014 OpenStack Foundation
    # All Rights Reserved.
    #
    #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    #    not use this file except in compliance with the License. You may obtain
    #    a copy of the License at
    #
    #         http://www.apache.org/licenses/LICENSE-2.0
    #
    #    Unless required by applicable law or agreed to in writing, software
    #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    #    License for the specific language governing permissions and limitations
    #    under the License.
    
    """
    IP Scheduler implementation
    """
    
    import random
    
    from oslo.config import cfg
    
    from nova.compute import rpcapi as compute_rpcapi
    from nova import exception
    from nova.openstack.common import log as logging
    from nova.openstack.common.gettextutils import _
    from nova.scheduler import driver
    
    CONF = cfg.CONF
    CONF.import_opt('compute_topic', 'nova.compute.rpcapi')
    LOG = logging.getLogger(__name__)
    
    class IPScheduler(driver.Scheduler):
        """
        Implements Scheduler as a random node selector based on
        IP address and hostname prefix.
        """
    
        def __init__(self, *args, **kwargs):
            super(IPScheduler, self).__init__(*args, **kwargs)
            self.compute_rpcapi = compute_rpcapi.ComputeAPI()
    
        def _filter_hosts(self, request_spec, hosts, filter_properties,
            hostname_prefix):
            """Filter a list of hosts based on hostname prefix."""
    
            hosts = [host for host in hosts if host.startswith(hostname_prefix)]
            return hosts
    
        def _schedule(self, context, topic, request_spec, filter_properties):
            """Picks a host that is up at random."""
    
            elevated = context.elevated()
            hosts = self.hosts_up(elevated, topic)
            if not hosts:
                msg = _("Is the appropriate service running?")
                raise exception.NoValidHost(reason=msg)
    
            remote_ip = context.remote_address
    
            if remote_ip.startswith('10.1'):
                hostname_prefix = 'doc'
            elif remote_ip.startswith('10.2'):
                hostname_prefix = 'ops'
            else:
                hostname_prefix = 'dev'
    
            hosts = self._filter_hosts(request_spec, hosts, filter_properties,
                hostname_prefix)
            if not hosts:
                msg = _("Could not find another compute")
                raise exception.NoValidHost(reason=msg)
    
            host = random.choice(hosts)
            LOG.debug("Request from %(remote_ip)s scheduled to %(host)s" % locals())
    
            return host
    
        def select_destinations(self, context, request_spec, filter_properties):
            """Selects random destinations."""
            num_instances = request_spec['num_instances']
            # NOTE(timello): Returns a list of dicts with 'host', 'nodename' and
            # 'limits' as keys for compatibility with filter_scheduler.
            dests = []
            for i in range(num_instances):
                host = self._schedule(context, CONF.compute_topic,
                        request_spec, filter_properties)
                host_state = dict(host=host, nodename=None, limits=None)
                dests.append(host_state)
    
            if len(dests) < num_instances:
                raise exception.NoValidHost(reason='')
            return dests
    
        def schedule_run_instance(self, context, request_spec,
                                  admin_password, injected_files,
                                  requested_networks, is_first_time,
                                  filter_properties, legacy_bdm_in_spec):
            """Create and run an instance or instances."""
            instance_uuids = request_spec.get('instance_uuids')
            for num, instance_uuid in enumerate(instance_uuids):
                request_spec['instance_properties']['launch_index'] = num
                try:
                    host = self._schedule(context, CONF.compute_topic,
                                          request_spec, filter_properties)
                    updated_instance = driver.instance_update_db(context,
                            instance_uuid)
                    self.compute_rpcapi.run_instance(context,
                            instance=updated_instance, host=host,
                            requested_networks=requested_networks,
                            injected_files=injected_files,
                            admin_password=admin_password,
                            is_first_time=is_first_time,
                            request_spec=request_spec,
                            filter_properties=filter_properties,
                            legacy_bdm_in_spec=legacy_bdm_in_spec)
                except Exception as ex:
                    # NOTE(vish): we don't reraise the exception here to make sure
                    #             that all instances in the request get set to
                    #             error properly
                    driver.handle_schedule_error(context, ex, instance_uuid,
                                                 request_spec)

    Существует много полезной информации в context, request_spec и filter_properties, которую вы можете использовать для принятия решения о том где запланировать экземпляр. Для ознакомления с дополнительной информацией о доступных свойствах вы можете вставить следующие операторы протоколирования в метод schedule_run_instance приведенного выше планировщика:

    LOG.debug("context = %(context)s" % {'context': context.__dict__})
    LOG.debug("request_spec = %(request_spec)s" % locals())
    LOG.debug("filter_properties = %(filter_properties)s" % locals())
  4. Для вставки этого планировщика в nova, отредактируйте один файл настройки, а именно, /etc/nova/nova.conf:

    $ vim /etc/nova/nova.conf
  5. Найдите настройку scheduler_driver и змените ее примерно так:

    scheduler_driver=nova.scheduler.ip_scheduler.IPScheduler
  6. Перезапустите службу планировщика nova, чтобы позволить nova использовать ваш планировщик. Начните с переключения на экран n-sch:

    1. Нажмите Ctrl+A с последующим 9.

    2. Нажимайте Ctrl+A с последующим N пока не достигните экрана n-sch.

    3. Нажмите Ctrl+C для прекращения службы.

    4. Нажмите клавишу со стрелкой Вверх для вызова последней команды.

    5. Yf;vbnt Enter для ее запуска.

  7. Проверьте свой новый планировщик с применением nova CLI. Начните со переключения на экран shell и завершите переключением на экран n-sch для проверки выдачи протоколов:

    1. Нажмите Ctrl+A с последующим 0.

    2. Убедитесь что вы находитесь в каталоге devstack:

      $ cd /root/devstack
    3. Чтобы получить переменные окружения для CLI, установите источник openrc:

      $ source openrc
    4. Поместите ID образа для единственного установленного образа в переменную окружения:

      $ IMAGE_ID=`nova image-list | egrep cirros | egrep -v "kernel|ramdisk" | awk '{print $2}'`
    5. Загрузите пробный сервер:

      $ nova boot --flavor 1 --image $IMAGE_ID scheduler-test
  8. Переключитесь назад на экран n-sch. Среди предложений журнала вы увидите строку:

    2014-01-23 19:57:47.262 DEBUG nova.scheduler.ip_scheduler \
    [req-... demo demo] Request from 162.242.221.84 \
    scheduled to devstack-havana \
    _schedule /opt/stack/nova/nova/scheduler/ip_scheduler.py:76
[Предостережение]Предостережение

Функциональное тестирование подобно приведенному не подменяет соответствующее тестирование блоков и интеграции, однако служит отправной точкой.

Аналогичным образом можно следовать в других проектах, которые используют архитектуру драйвера. Просто создайте модуль и класс, которые соответствуют интерфейсу драйвера и вставьте его при помощи настройки. Ваш код работает при использовании данной функциональной особенности и, по необходимости, может вызывать другие службы. Никакой код ядра проекта не затрагивается. Осуществите поиск значения "driver" в файлах настройки .conf проекта в /etc/<project> для выявления проектов, которые используют архитектуру драйвера.

Когда ваш планировщик завершен, мы рекомендуем вам открытьего код и дать знать о нем сообществу через список рассылки электронной почты OpenStack. Возможно кому-то еще требуется подобная функциональность. Люди смогут воспользоваться вашим кодом и снабдить вас обратной связью, а также, возможно, сделать пожертвования. Если для вашего кода окажется достаточно поддержки, возможно, вы сможете предложить его добавление в официальное программное обеспечение промежуточного уровня вычислительной среды schedulers.

 Настройка инструментальной панели(Horizon)

Инструментальная панель основана на инфраструктуре веб-приложения Python Django Лучшееруководствопо индивидуальной настройке ужебыло написано и его можно найти по ссылке Building on Horizon (Построение Horizon).

 Выводы

При эксплуатации облака OpenStack, вы можете обнаружить, что ваши пользователи могут оказаться довольно требовательными. Если OpenStack не выполняет что-то, в чем нуждаются ваши пользователи, по вашему усмотрению, можно выполнить эти требования. Данная глава предоставляет вам некоторые параметры для индивидуальной настройки и снабжает вас инструментарием, необходимым вам для начала.