Пишем плагин для fuel 8.0. Часть 2

В предыдущей части мы создали первую версию плагина из шаблона.

На текущий момент она умеет только создавать файл на ноде.

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

  • создание python окружения
  • установка всех зависимостей
  • создание django проекта на ноде

Исходники этого урока выложены на github

Создадим простое django приложение

Поставим в окружение django

$ pip install django

Создадим приложение

$ cd deployment_scripts
$ django-admin startproject blog

Допишем в settings.py загрузку параметров из settings.yaml и STATIC_ROOT

STATIC_ROOT = os.path.join(BASE_DIR, 'static')

import yaml

settings_json = os.path.join(BASE_DIR, 'settings.yaml')

if os.path.exists(settings_json):
    globals().update(yaml.load(open(settings_json)))

Создаем файл с зависимостями deployments_scripts/blog/requirements

django
gunicorn
pyyaml
psycopg2

Создаем задачу в плагине для создания python окружения и копирования деплоя нашего приложения

Приводим файл deployment_tasks.yaml, к следующему виду:

- id: fuel-plugin-django-app_role
  type: group
  role: [fuel-plugin-django-app_role]
  tasks: [hiera, globals] 
  parameters:
    strategy:
      type: parallel

- id: fuel-plugin-django-app_postgres
  type: puppet
  groups: [fuel-plugin-django-app_role]
  requires: [hiera, globals]
  parameters:      
    puppet_manifest: "postgres.pp"
    puppet_modules: "/etc/puppet/modules/"
    timeout: 1800

- id: fuel-plugin-django-app_create-env
  type: puppet  
  groups: [fuel-plugin-django-app_role]
  requires: [fuel-plugin-django-app_postgres]
  parameters:
    puppet_manifest: "create_env.pp"
    puppet_modules: "."
    timeout: 3600

- id: fuel-plugin-django-app_deploy-app
  type: puppet  
  groups: [fuel-plugin-django-app_role]
  requires: [fuel-plugin-django-app_create-env]
  parameters:
    puppet_manifest: "deploy_django_app.pp"
    puppet_modules: "."
    timeout: 3600

Также мы добавили задачу по установке базы данных postgres

Создаем сопутствующие файлы

Удаляем файлы deployment_scripts/deploy.sh и deployment_scripts/deploy.pp.

Создаем файл deployment_scripts/create_env.pp, который будет создавать окружение для нашего приложения

$www_dir     = "/var/www/"
$blog_dir    = "${www_dir}blog/"
$blog_logs   = "${blog_dir}logs/"
$blog_python = "${www_dir}env/bin/python"

file {
    [$www_dir, $blog_dir, $blog_logs]:
        ensure => 'directory',
}

package {
    ['python-pip', 'python-dev', 'libpq-dev']:
        ensure => 'present',
}

exec {
    'install virtualenv':
        command => 'pip install virtualenv',
        path    => '/usr/bin/',
        require => Package['python-pip'],
}

exec {
    'create environment':
        command => 'virtualenv --no-site-packages env',
        path    => '/usr/local/bin/',
        cwd     => $blog_dir,
        require => [
            Package['python-pip'],
            File[$blog_dir]
        ],
}

Создаем файл deployment_scripts/deploy_django_app.pp, который будет создавать наше приложение

# папка на ноде, куда копируется deployments_scripts с мастер ноды
$plugin_source_dir = '/etc/fuel/plugins/fuel-plugin-django-app-1.0/'

$blog_path   = "/var/www/blog/"
$blog_python = "${blog_path}env/bin/python"
$blog_pip    = "${blog_path}env/bin/pip"

# вытаскиваем из хиеры наши параметры
$django_app             = hiera_hash('fuel-plugin-django-app')
$database_engine        = $django_app['django_db_engine']
$database_name          = $django_app['django_db_name']
$database_password      = $django_app['django_db_user_password']
$database_role          = $django_app['django_db_user_name']
$database_role_password = $django_app['django_db_user_password']
$database_host          = $django_app['django_db_host']
$database_port          = $django_app['django_db_port']

# копируем django приложение
file {
    "${blog_path}":
        ensure  => 'directory',
        recurse => true,
        source  => "${plugin_source_dir}blog/"
}

# ставим зависимости
exec {
    "${blog_pip} install -r ${blog_path}requirements":
}

# создаем конфиг для приложения, с параметрами которые настроил пользователь
file {
    "${blog_path}settings.yaml":
        ensure  => present,
        content => template("${plugin_source_dir}blog/settings.yaml.rb")
}

# генерируем питон файл, который создаст суперпользователя
file {
    "${blog_path}create_superuser.py":
        ensure  => present,
        content => template("${blog_path}create_superuser.py.rb")
}

exec {
    ["${blog_python} manage.py migrate --noinput",
     "${blog_python} manage.py collectstatic --noinput",
     "${blog_python} create_superuser.py"]:
        cwd => "${blog_path}"
}

Создаем файл deployment_scripts/postgres.pp, который будет ставить базу данных postgres и создавать базу данных и роль

# ставим постгрес

notice('PLUGIN: django_deploy - install postgress')

$django_app             = hiera_hash('fuel-plugin-django-app')
$database_name          = $django_app['django_db_name']
$database_password      = $django_app['django_db_user_password']
$database_role          = $django_app['django_db_user_name']
$database_role_password = $django_app['django_db_user_password']

class { 'postgresql::server': }

# создадим роль
postgresql::server::role { 
    $database_role:
        password_hash => postgresql_password($database_role, $database_role_password),
}

# создадим базу
postgresql::server::db { 
    $database_name:
        user     => $database_role,
        password => postgresql_password($database_role, $database_role_password),
}

Создаем шаблон python скрипта, который создаст суперпользователя, deployment_scripts/blog/create_superuser.py.rb

# coding: utf-8

import django 
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "blog.settings")
django.setup()

from django.contrib.auth.models import User

username = '<%= @database_role %>'
password = '<%= @database_password %>'
if not User.objects.filter(username=username).exists():
    u = User(username=username)
    u.set_password(password)
    u.is_superuser = True
    u.is_staff = True
    u.save()

Создаем шаблон для настроек, deployment_scripts/blog/settings.yaml.rb

DATABASES:
    default:
        ENGINE: <%= @database_engine %>
        NAME: <%= @database_name %>
        USER: <%= @database_role %>
        PASSWORD: <%= @database_password %>
        HOST: <%= @database_host %>
        PORT: <%= @database_port %>

Параметры плагина

Добавим в плагин параметры, которые пользователь может отредактировать через fuel-web

Приведем файл environment_config.yaml, к следующему виду:

attributes:
  metadata:
    group: 'other'
  django_db_engine: 
    type: 'radio'
    weight: 25
    label: 'db engine'
    value: 'django.db.backends.postgresql_psycopg2'
    values:
        - data: 'django.db.backends.postgresql_psycopg2'
          label: 'django.db.backends.postgresql_psycopg2'

  django_db_name:
    value: 'website'
    label: 'Имя БД'
    type: 'text'
    weight: 25

  django_db_user_name:
    value: 'website'
    label: 'Пользователь БД'
    type: 'text'
    weight: 25

  django_db_user_password:
    value: 'website'
    label: 'Пароль пользователя БД'
    type: 'text'
    weight: 25

  django_db_host:
    value: '127.0.0.1'
    label: 'Адрес БД'
    type: 'text'
    weight: 25

  django_db_port:  
    value: '5432'
    label: 'Порт БД'
    type: 'text'
    weight: 25

Доработаем описания нашего плагина

node_roles.yaml

fuel-plugin-django-app_role:
  name: "Django app"
  description: "Django app role"
  has_primary: false
  public_ip_required: false
  weight: 1000

Деплой

  • инкрементим версию пакета
  • устанавливаем пакет на мастер ноду
  • настраиваем параметры в fuel-web, environmnet->settings->other
  • деплоим роль на новую ноду