Skip to content

Commit

Permalink
Переделал классы
Browse files Browse the repository at this point in the history
  • Loading branch information
Сергей Самойлов committed Aug 10, 2016
1 parent b44be76 commit c584735
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 124 deletions.
79 changes: 45 additions & 34 deletions fab/main.py → fab/serverssh.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,55 @@
# -*- coding: utf-8 -*-

import yaml
import os
from fabric.api import run, env, cd, puts


class ServerSSH(object):
settings = None

# В конструктор класса передается объект класса Settings,
# который содержит в себе все необходимые настройки
def __init__(self, settings):
self.settings = settings
def __init__(self, yaml_file):
with open(yaml_file) as f:
yaml_config = yaml.load(f.read())

# Сразу же необходимо "сказать" библиотеке fabric о создании новой роли
env.roledefs[self.settings.SERVER] = [self.settings.USER + '@' +
self.settings.HOST + ':' +
str(self.settings.PORT)]
env.roledefs[yaml_config['SERVER']] = [yaml_config['USER'] + '@' +
yaml_config['HOST'] + ':' +
str(yaml_config['PORT'])]

# Инициализация окружения
env.key_filename = self.settings.PATH_KEY
env.user = self.settings.USER
env.password = self.settings.PASSWORD
env.project_root = self.settings.PATH
env.python = self.settings.PYTHON
env.pip = self.settings.PIP
env.key_filename = yaml_config['PATH_KEY']
env.user = yaml_config['USER']
env.password = yaml_config['PASSWORD']
env.project_root = yaml_config['PATH']

try:
env.python = yaml_config['PYTHON']
except KeyError:
env.python = os.path.join(env.project_root, 'venv/bin/python')

try:
env.pip = yaml_config['PIP']
except KeyError:
env.pip = os.path.join(env.project_root, 'venv/bin/pip')

self.config_server = yaml_config['WORK_SERVER']
self.repository = yaml_config['REPOSITORY']
self.path = yaml_config['PATH']
self.name = yaml_config['SERVER']

# Создание папки с виртуальным окружением
def create_dir(self):
run('mkdir -p {}'.format(self.settings.PATH))
run('mkdir -p {}'.format(self.path))

def pip_install_requirements(self):
self.pip('install -r requirements.txt')

# Метод для изменения состояния какого-либо сервиса
def control_service(self, action='restart', service=None):
if service is None:
if self.settings.WORK_SERVER is None:
return
service = self.settings.WORK_SERVER
run('echo {password} | sudo -S service {server_name} {action}'.format(server_name=service,
password=self.settings.PASSWORD,
action=action))
service = self.config_server
run('sudo service {server_name} {action}'.format(server_name=service,
action=action))
puts('{service} has been {action}ed'.format(service=service, action=action))

# Метода для выполнения какой-либо программы внутри корневого каталога с проектом
Expand All @@ -43,7 +58,7 @@ def do(self, action):
run(action)
puts('{action} is completed'.format(action=action))

# Метода для выполнения команды "от лица" pip из вируального окружения
# Методы для выполнения команды "от лица" pip из вируального окружения
def pip(self, action):
with cd(env.project_root):
run('{pip} {action}'.format(pip=env.pip, action=action))
Expand All @@ -53,29 +68,20 @@ def python(self, action):
with cd(env.project_root):
run('{python} {action}'.format(python=env.python, action=action))

# Метод для полного обновления вируального окружения
# Подразумевается, что в проекте присутствует файл requirements.txt
# Имя файла можно поменять в объекте с настройками
def venv_update(self):
with cd(env.project_root):
run('rm -rf venv')
run('virtualenv venv')
# run('{pip} install -r {requirements}'.format(pip=env.pip, requirements=self.settings.VENV_REQUIREMENTS))

# Подготовка окружения на удаленном компьютере к работе
def init(self):
with cd(env.project_root):
run('git init')
# run('git remote set-url origin {repository}'.format(repository=REPOSITORY+'.git'))
run('git remote add origin {repository}'.format(repository=self.settings.REPOSITORY))
run('echo {password} | sudo -S apt-get -y install virtualenv'.format(password=self.settings.PASSWORD))
run('git remote add origin {repository}'.format(repository=self.repository))
run('sudo apt-get -y install virtualenv')
run('virtualenv venv')
self.deploy()

# Метод для изменения пути до репозитория
def change_repository(self):
with cd(env.project_root):
run('git remote set-url origin {repository}'.format(repository=self.settings.REPOSITORY))
run('git remote set-url origin {repository}'.format(repository=self.repository))

# Метод для обновления проекта
def deploy(self):
Expand All @@ -87,3 +93,8 @@ def rollback(self):
with cd(env.project_root):
run('git reset --hard HEAD^')
self.control_service(action='restart')

def get_name(self):
return self.name


95 changes: 5 additions & 90 deletions fabfile.py
Original file line number Diff line number Diff line change
@@ -1,95 +1,10 @@
# coding: utf-8
import os
from fabric.state import env

import yaml
from fabric.decorators import roles
from fab.main import ServerSSH
from settings.settings_class import Settings
from fablib import init, deploy, rollback

# Yaml-файл содержит необходимые настройки, в том числе пароли.
# Нужен тут только для того, чтобы не хранить эту информацию в коммите
with open('settings/productionserver.yaml') as f:
prod_yaml = yaml.load(f.read())

# Аналогично
with open('settings/testserver.yaml') as f:
test_yaml = yaml.load(f.read())

# ----------------------------- Настройка продакшена --------------------------#
# Создание объекта с настройками для продакшена
prod_settings = Settings()
prod_settings.USER = prod_yaml['USER']
prod_settings.PASSWORD = prod_yaml['PASSWORD']

# Создание объекта - удаленного сервера
production_server = ServerSSH(prod_settings)


# Инициализация production-сервера
@roles(prod_settings.SERVER)
def init_production():
# Метод create_dir нужен для создания рабочего каталога на сервере
production_server.create_dir()
# Метод init базового класса ServerSSH инициализирует git, устанавливает виртуальное окружение
# и скачивает последнюю версию проекта
production_server.init()
# Метод pip позволяет выполнять команды от имени pip вируального окружения сервера
production_server.pip('install -r requirements.txt')
# Метод python позволяет выполнять команды "от лица" python виртуального окружения сервера
production_server.python('hello.py') # В данном примере запускает скрипт hello.py,
# но вместо него можно было запустить и скрипт с миграцией базы данных

# Метод control_service позволяет совершать операции restart | stop | start с каким - либо сервисом на сервере
# production_server.control_service('restart', 'rabbitmq-server' ) # Сервис можно указать явно
production_server.control_service('restart') # Или просто указать дейтвие,
# которое будете применено к серверу по умолчанию


# Обновление production-сервера
@roles(prod_settings.SERVER)
def deploy_production():
production_server.deploy()


# Обновление виртуального окружения
@roles(prod_settings.SERVER)
def venv_update_production():
production_server.venv_update()


# --------------------------------------------------------------------------------#


# ----------------------------- Настройка тестового сервера ----------------------#

# Изменение настроек по умолчанию. Можно вынести в отдельный файл.
# Для этого можно в отдельном файле создать класс, который будет наследоваться от класса Settings.
# Тут создается класс только для примера.
class TestServerSettings(Settings):
SERVER = 'test'
USER = test_yaml['USER']
PASSWORD = test_yaml['PASSWORD']
REPOSITORY = test_yaml['REPOSITORY']
HOST = test_yaml['HOST']
PATH = test_yaml['PATH']


# Создание еще одного объекта с настройками для тестового сервера
test_settings = TestServerSettings()

# Создание тестового сервера
test_server = ServerSSH(test_settings)


@roles(test_settings.SERVER)
def init_test_server():
test_server.init()


@roles(test_settings.SERVER)
def deploy_test_server():
test_server.deploy()
# --------------------------------------------------------------------------------#
# fablib.before_init = lambda: 'Hello there'

def before_init():
return 'Hello there'


79 changes: 79 additions & 0 deletions fablib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# coding: utf-8
import yaml
from fabric.api import env, run

from fab.serverssh import ServerSSH

env.hosts = []


def before_init():
pass


def after_init():
pass


def before_deploy():
pass


def after_deploy():
pass


def before_rollback():
pass


def after_rollback():
pass


def get_hosts(filename):
with open(filename) as f:
config = yaml.load(f.read())
for host in config['HOSTS']:
yield host
# env.hosts += [host]


def init(service=None):
before_init()
hosts = get_hosts(env.rcfile)
try:
while True:
host = next(hosts)
server = ServerSSH(env.rcfile, host)
server.create_dir()
server.do('sudo apt-get install gcc')
server.do('sudo apt-get install build-essential autoconf libtool pkg-config python-opengl python-imaging ' +
'python-pyrex python-pyside.qtopengl idle-python2.7 qt4-dev-tools qt4-designer libqtgui4 ' +
'libqtcore4 libqt4-xml libqt4-test libqt4-script libqt4-network libqt4-dbus python-qt4 ' +
'python-qt4-gl libgle3 python-dev libxml2-dev libxslt1-dev libevent-dev')
server.init()
server.pip_install_requirements()
if not service:
server.control_service(service=service, action='start')
except StopIteration:
pass
after_init()


def deploy(service=None):
before_deploy()
server = ServerSSH(env.rcfile)
server.deploy()
if not service:
server.control_service(service=service, action='restart')
after_deploy()


def rollback(service=None):
before_rollback()
server = ServerSSH(env.rcfile)
server.rollback()
if not service:
server.control_service(service=service, action='restart')
after_rollback()
12 changes: 12 additions & 0 deletions productionserver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
SERVER: "production"
PORT: 22
BRANCH: "dev"
WORK_SERVER: "rabbitmq-server"
VENV_REQUIREMENTS: "requirements.txt"

USER: "sebuntu-1"
PASSWORD: "njkelfrjq"
HOST: "192.168.56.101"
PATH: "/home/sebuntu-1/work/fabtest/"
REPOSITORY: "https://github.com/faoxis/gittest.git"
PATH_KEY: '~/.ssh/id_rsa'

0 comments on commit c584735

Please sign in to comment.