Merge pull request #116 from pigmej/jnowak/pluggable_transports
Pluggable transports
This commit is contained in:
commit
f4a23916c8
@ -1,5 +1,5 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: echo `/sbin/ifconfig`
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: docker stop {{ resource_name }}
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- docker:
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: docker --version
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: docker stop {{ resource_name }}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- docker:
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: glance api container
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- docker:
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: echo 'removed'
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
vars:
|
||||
ip: {{ ip }}
|
||||
@ -26,12 +26,12 @@
|
||||
- file: path={{ config_dir.value['src'] }}/policy.json state=touch
|
||||
- file: path={{ config_dir.value['src'] }}/schema-image.json state=touch
|
||||
- file: path={{ config_dir.value['src'] }}/exports state=touch
|
||||
- template: src={{ resource_dir }}/templates/glance-api.conf dest={{ config_dir.value['src'] }}/glance-api.conf
|
||||
- template: src={{ resource_dir }}/templates/glance-api-paste.ini dest={{ config_dir.value['src'] }}/glance-api-paste.ini
|
||||
- template: src={{ resource_dir }}/templates/glance-cache.conf dest={{ config_dir.value['src'] }}/glance-cache.conf
|
||||
- template: src={{ resource_dir }}/templates/glance-registry.conf dest={{ config_dir.value['src'] }}/glance-registry.conf
|
||||
- template: src={{ resource_dir }}/templates/glance-registry-paste.ini dest={{ config_dir.value['src'] }}/glance-registry-paste.ini
|
||||
- template: src={{ resource_dir }}/templates/glance-scrubber.conf dest={{ config_dir.value['src'] }}/glance-scrubber.conf
|
||||
- template: src={{ resource_dir }}/templates/policy.json dest={{ config_dir.value['src'] }}/policy.json
|
||||
- template: src={{ resource_dir }}/templates/schema-image.json dest={{ config_dir.value['src'] }}/schema-image.json
|
||||
- template: src={{ resource_dir }}/templates/exports dest={{ config_dir.value['src'] }}/glance-export
|
||||
- template: src={{templates_dir}}/glance-api.conf dest={{ config_dir.value['src'] }}/glance-api.conf
|
||||
- template: src={{templates_dir}}/glance-api-paste.ini dest={{ config_dir.value['src'] }}/glance-api-paste.ini
|
||||
- template: src={{templates_dir}}/glance-cache.conf dest={{ config_dir.value['src'] }}/glance-cache.conf
|
||||
- template: src={{templates_dir}}/glance-registry.conf dest={{ config_dir.value['src'] }}/glance-registry.conf
|
||||
- template: src={{templates_dir}}/glance-registry-paste.ini dest={{ config_dir.value['src'] }}/glance-registry-paste.ini
|
||||
- template: src={{templates_dir}}/glance-scrubber.conf dest={{ config_dir.value['src'] }}/glance-scrubber.conf
|
||||
- template: src={{templates_dir}}/policy.json dest={{ config_dir.value['src'] }}/policy.json
|
||||
- template: src={{templates_dir}}/schema-image.json dest={{ config_dir.value['src'] }}/schema-image.json
|
||||
- template: src={{templates_dir}}/exports dest={{ config_dir.value['src'] }}/glance-export
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: glance registry container
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- docker:
|
||||
|
@ -1,5 +1,5 @@
|
||||
# TODO
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- file: path={{ config_dir.value['src'] }} state=absent
|
||||
|
@ -1,5 +1,5 @@
|
||||
# TODO
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
vars:
|
||||
config_dir: {src: {{ config_dir.value['src'] }}, dst: {{ config_dir.value['dst'] }}}
|
||||
@ -19,4 +19,4 @@
|
||||
tasks:
|
||||
- file: path={{ config_dir.value['src'] }}/ state=directory
|
||||
- file: path={{ config_dir.value['src'] }}/haproxy.cfg state=touch
|
||||
- template: src={{ resource_dir }}/templates/haproxy.cfg dest=/etc/haproxy/haproxy.cfg
|
||||
- template: src={{templates_dir}}/haproxy.cfg dest=/etc/haproxy/haproxy.cfg
|
||||
|
@ -19,4 +19,4 @@
|
||||
tasks:
|
||||
- file: path={{ config_dir.value['src'] }}/ state=directory
|
||||
- file: path={{ config_dir.value['src'] }}/haproxy.cfg state=touch
|
||||
- template: src={{ resource_dir }}/templates/haproxy.cfg dest=/etc/haproxy/haproxy.cfg
|
||||
- template: src={{templates_dir}}/haproxy.cfg dest=/etc/haproxy/haproxy.cfg
|
||||
|
10
resources/haproxy_service/actions/install.yml
Normal file
10
resources/haproxy_service/actions/install.yml
Normal file
@ -0,0 +1,10 @@
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- apt:
|
||||
name: haproxy
|
||||
state: present
|
||||
- replace:
|
||||
dest: '/etc/default/haproxy'
|
||||
regexp: ENABLED=0
|
||||
replace: ENABLED=1
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: haproxy container
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- apt:
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- service:
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: {{ip}}
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
{% for ip, host in zip(hosts_ips.value, hosts_names.value) %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- file: path={{config_dir}} state=absent
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
vars:
|
||||
admin_token: {{admin_token}}
|
||||
@ -10,8 +10,8 @@
|
||||
db_name: {{db_name}}
|
||||
tasks:
|
||||
- file: path={{config_dir}} state=directory
|
||||
- template: src={{resource_dir}}/templates/keystone.conf dest={{config_dir}}/keystone.conf
|
||||
- template: src={{resource_dir}}/templates/default_catalog.templates dest={{config_dir}}/default_catalog.templates
|
||||
- template: src={{resource_dir}}/templates/logging.conf dest={{config_dir}}/logging.conf
|
||||
- template: src={{resource_dir}}/templates/policy.json dest={{config_dir}}/policy.json
|
||||
- template: src={{resource_dir}}/templates/exports dest={{ config_dir }}/keystone-exports
|
||||
- template: src={{templates_dir}}/keystone.conf dest={{config_dir}}/keystone.conf
|
||||
- template: src={{templates_dir}}/default_catalog.templates dest={{config_dir}}/default_catalog.templates
|
||||
- template: src={{templates_dir}}/logging.conf dest={{config_dir}}/logging.conf
|
||||
- template: src={{templates_dir}}/policy.json dest={{config_dir}}/policy.json
|
||||
- template: src={{templates_dir}}/exports dest={{ config_dir }}/keystone-exports
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: keystone role
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: install python-keystoneclient
|
||||
|
@ -1,5 +1,5 @@
|
||||
# TODO
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: keystone container
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: keystone container
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: keystone tenant
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: install python-keystoneclient
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: keystone user
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: install python-keystoneclient
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: mariadb db
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: mariadb db
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: mariadb container
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: mariadb container
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: mariadb user
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- name: mariadb user
|
||||
|
@ -7,4 +7,4 @@
|
||||
keystone_host: {{keystone_host}}
|
||||
keystone_port: {{keystone_port}}
|
||||
tasks:
|
||||
- template: src={{resource_dir}}/templates/openrc.template dest=/root/openrc
|
||||
- template: src={{templates_dir}}/openrc.template dest=/root/openrc
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- file: path={{config_dir}} state=absent
|
||||
|
@ -1,8 +1,8 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
vars:
|
||||
admin_user: {{admin_user}}
|
||||
admin_password: {{admin_password}}
|
||||
tasks:
|
||||
- file: path={{config_dir}} state=directory
|
||||
- template: src={{resource_dir}}/templates/rabbitmq.conf dest={{config_dir}}/rabbitmq.conf
|
||||
- template: src={{templates_dir}}/rabbitmq.conf dest={{config_dir}}/rabbitmq.conf
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- rabbitmq_user: user={{user_name}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- rabbitmq_user: user={{user_name}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- rabbitmq_vhost: name={{vhost_name}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ ip }}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- rabbitmq_vhost: name={{vhost_name}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ip}}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: riak-admin cluster join {{join_to}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ip}}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
# - shell: sleep 30
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ip}}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: riak-admin cluster join {{join_to}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ip}}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- apt:
|
||||
|
@ -1,4 +1,4 @@
|
||||
- hosts: [{{ip}}]
|
||||
- hosts: [{{host}}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
# those below are mostly for tests
|
||||
@ -18,7 +18,7 @@
|
||||
state: stopped
|
||||
- file: path=/etc/riak/riak.conf state=touch
|
||||
- template:
|
||||
src: {{ resource_dir }}/templates/riak.conf
|
||||
src: {{templates_dir}}/riak.conf
|
||||
dest: /etc/riak/riak.conf
|
||||
- shell: rm -fr /var/lib/riak/kv_vnode/*
|
||||
- shell: rm -fr /var/lib/riak/ring/*
|
||||
|
@ -5,7 +5,7 @@
|
||||
name: riak
|
||||
state: stopped
|
||||
- template:
|
||||
src: {{ resource_dir }}/templates/riak.conf
|
||||
src: {{templates_dir}}/riak.conf
|
||||
dest: /etc/riak/riak.conf
|
||||
- service:
|
||||
name: riak
|
||||
|
@ -15,3 +15,6 @@ input:
|
||||
ssh_user:
|
||||
schema: str!
|
||||
value:
|
||||
name:
|
||||
schema: str
|
||||
value: a node
|
||||
|
@ -1,10 +1,18 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
import handlers
|
||||
|
||||
from solar.core.transports.ssh import SSHSyncTransport, SSHRunTransport
|
||||
# from solar.core.transports.rsync import RsyncSyncTransport
|
||||
|
||||
_default_transports = {
|
||||
'sync': SSHSyncTransport,
|
||||
# 'sync': RsyncSyncTransport,
|
||||
'run': SSHRunTransport
|
||||
}
|
||||
|
||||
def resource_action(resource, action):
|
||||
handler = resource.metadata.get('handler', 'none')
|
||||
with handlers.get(handler)([resource]) as h:
|
||||
with handlers.get(handler)([resource], _default_transports) as h:
|
||||
return h.action(resource, action)
|
||||
|
||||
|
||||
|
@ -28,6 +28,8 @@ class AnsiblePlaybook(base.BaseHandler):
|
||||
provider.directory, ROLES_PATH))
|
||||
|
||||
def action(self, resource, action):
|
||||
# This would require to put this file to remote and execute it (mostly)
|
||||
log.debug("Ansible playbook is not ported to pluggable transports")
|
||||
action_file = os.path.join(
|
||||
resource.metadata['actions_path'],
|
||||
resource.metadata['actions'][action])
|
||||
|
@ -11,20 +11,35 @@ from solar import errors
|
||||
# otherwise fabric will sys.exit(1) in case of errors
|
||||
env.warn_only = True
|
||||
|
||||
# if we would have something like solard that would render this then
|
||||
# we would not need to render it there
|
||||
# for now we redender it locally, sync to remote, run ansible on remote host as local
|
||||
class AnsibleTemplate(TempFileHandler):
|
||||
def action(self, resource, action_name):
|
||||
inventory_file = self._create_inventory(resource)
|
||||
playbook_file = self._create_playbook(resource, action_name)
|
||||
log.debug('inventory_file: %s', inventory_file)
|
||||
log.debug('playbook_file: %s', playbook_file)
|
||||
call_args = ['ansible-playbook', '--module-path', '/vagrant/library', '-i', inventory_file, playbook_file]
|
||||
|
||||
# self.transport_sync.copy(resource, self.dirs[resource.name], self.dirs[resource.name])
|
||||
self._copy_templates_and_scripts(resource, action_name)
|
||||
self.transport_sync.copy(resource, self.dst, '/tmp')
|
||||
self.transport_sync.copy(resource, '/vagrant/library', '/tmp')
|
||||
self.transport_sync.sync_all()
|
||||
|
||||
call_args = ['ansible-playbook', '--module-path', '/tmp/library', '-i', inventory_file, playbook_file]
|
||||
log.debug('EXECUTING: %s', ' '.join(call_args))
|
||||
|
||||
with fabric_api.shell_env(ANSIBLE_HOST_KEY_CHECKING='False'):
|
||||
out = fabric_api.local(' '.join(call_args), capture=True)
|
||||
out = self.transport_run.run(resource, *call_args)
|
||||
log.debug(out)
|
||||
if out.failed:
|
||||
raise errors.SolarError(out)
|
||||
|
||||
# with fabric_api.shell_env(ANSIBLE_HOST_KEY_CHECKING='False'):
|
||||
# out = fabric_api.local(' '.join(call_args), capture=True)
|
||||
# if out.failed:
|
||||
# raise errors.SolarError(out)
|
||||
|
||||
|
||||
def _create_inventory(self, r):
|
||||
directory = self.dirs[r.name]
|
||||
@ -34,15 +49,25 @@ class AnsibleTemplate(TempFileHandler):
|
||||
return inventory_path
|
||||
|
||||
def _render_inventory(self, r):
|
||||
inventory = '{0} ansible_ssh_host={1} ansible_connection=ssh ansible_ssh_user={2} ansible_ssh_private_key_file={3} {4}'
|
||||
host, user, ssh_key = r.args['ip'].value, r.args['ssh_user'].value, r.args['ssh_key'].value
|
||||
# inventory = '{0} ansible_ssh_host={1} ansible_connection=ssh ansible_ssh_user={2} ansible_ssh_private_key_file={3} {4}'
|
||||
# host, user, ssh_key = r.args['ip'].value, r.args['ssh_user'].value, r.args['ssh_key'].value
|
||||
|
||||
# XXX: r.args['ssh_user'] should be something different in this case probably
|
||||
inventory = '{0} ansible_connection=local user={1} {2}'
|
||||
host, user = 'localhost', r.args['ssh_user'].value
|
||||
args = []
|
||||
for arg in r.args:
|
||||
args.append('{0}="{1}"'.format(arg, r.args[arg].value))
|
||||
args = ' '.join(args)
|
||||
inventory = inventory.format(host, host, user, ssh_key, args)
|
||||
inventory = inventory.format(host, user, args)
|
||||
log.debug(inventory)
|
||||
return inventory
|
||||
|
||||
def _create_playbook(self, resource, action):
|
||||
return self._compile_action_file(resource, action)
|
||||
|
||||
def _make_args(self, resource):
|
||||
args = super(AnsibleTemplate, self)._make_args(resource)
|
||||
args['host'] = 'localhost'
|
||||
return args
|
||||
|
||||
|
@ -6,12 +6,21 @@ import tempfile
|
||||
from jinja2 import Template
|
||||
|
||||
from solar.core.log import log
|
||||
from solar.core.transports.ssh import SSHSyncTransport, SSHRunTransport
|
||||
|
||||
|
||||
class BaseHandler(object):
|
||||
|
||||
def __init__(self, resources):
|
||||
def __init__(self, resources, handlers=None):
|
||||
self.resources = resources
|
||||
if handlers is None:
|
||||
self.transport_sync = SSHSyncTransport()
|
||||
self.transport_run = SSHRunTransport()
|
||||
else:
|
||||
self.transport_run = handlers['run']()
|
||||
self.transport_sync = handlers['sync']()
|
||||
self.transport_sync.bind_with(self.transport_run)
|
||||
self.transport_run.bind_with(self.transport_sync)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
@ -21,9 +30,9 @@ class BaseHandler(object):
|
||||
|
||||
|
||||
class TempFileHandler(BaseHandler):
|
||||
def __init__(self, resources):
|
||||
def __init__(self, resources, handlers=None):
|
||||
super(TempFileHandler, self).__init__(resources, handlers)
|
||||
self.dst = tempfile.mkdtemp()
|
||||
self.resources = resources
|
||||
|
||||
def __enter__(self):
|
||||
self.dirs = {}
|
||||
@ -58,9 +67,39 @@ class TempFileHandler(BaseHandler):
|
||||
tpl = Template(f.read())
|
||||
return tpl.render(str=str, zip=zip, **args)
|
||||
|
||||
def _copy_templates_and_scripts(self, resource, action):
|
||||
# TODO: we might need to optimize it later, like provide list
|
||||
# templates/scripts per action
|
||||
log.debug("Adding templates for %s %s", resource.name, action)
|
||||
trg_templates_dir = None
|
||||
trg_scripts_dir = None
|
||||
|
||||
base_path = resource.metadata['base_path']
|
||||
src_templates_dir = os.path.join(base_path, 'templates')
|
||||
if os.path.exists(src_templates_dir):
|
||||
trg_templates_dir = os.path.join(self.dirs[resource.name], 'templates')
|
||||
shutil.copytree(src_templates_dir, trg_templates_dir)
|
||||
|
||||
src_scripts_dir = os.path.join(base_path, 'scripts')
|
||||
if os.path.exists(src_scripts_dir):
|
||||
trg_scripts_dir = os.path.join(self.dirs[resource.name], 'scripts')
|
||||
shutil.copytree(src_scripts_dir, trg_scripts_dir)
|
||||
|
||||
return (trg_templates_dir, trg_scripts_dir)
|
||||
|
||||
def prepare_templates_and_scripts(self, resource, action, target_dir=None):
|
||||
target_dir = target_dir or self.dirs[resource.name]
|
||||
templates, scripts = self._copy_templates_and_scripts(resource, action)
|
||||
if templates:
|
||||
self.transport_sync.copy(resource, templates, target_dir)
|
||||
if scripts:
|
||||
self.transport_sync.copy(resource, scripts, target_dir)
|
||||
|
||||
def _make_args(self, resource):
|
||||
args = {'resource_name': resource.name}
|
||||
args['resource_dir'] = resource.metadata['base_path']
|
||||
args['templates_dir'] = 'templates/'
|
||||
args['scripts_dir'] = 'scripts/'
|
||||
args.update(resource.args)
|
||||
return args
|
||||
|
||||
|
@ -12,74 +12,12 @@ from solar.core.provider import GitProvider
|
||||
from solar import errors
|
||||
|
||||
|
||||
class ResourceSSHMixin(object):
|
||||
@staticmethod
|
||||
def _ssh_command(resource, *args, **kwargs):
|
||||
log.debug('SSH: %s', args)
|
||||
|
||||
executor = fabric_api.run
|
||||
if kwargs.get('use_sudo', False):
|
||||
executor = fabric_api.sudo
|
||||
|
||||
managers = [
|
||||
fabric_api.settings(**ResourceSSHMixin._fabric_settings(resource)),
|
||||
]
|
||||
|
||||
if 'cwd' in kwargs:
|
||||
managers.append(
|
||||
fabric_api.cd(kwargs['cwd'])
|
||||
)
|
||||
|
||||
if 'env' in kwargs:
|
||||
managers.append(
|
||||
fabric_api.shell_env(**kwargs['env'])
|
||||
)
|
||||
|
||||
if 'warn_only' in kwargs:
|
||||
managers.append(
|
||||
fabric_api.warn_only())
|
||||
|
||||
with nested(*managers):
|
||||
return executor(' '.join(args))
|
||||
|
||||
@staticmethod
|
||||
def _scp_command(resource, _from, _to, use_sudo=False):
|
||||
log.debug('SCP: %s -> %s', _from, _to)
|
||||
|
||||
executor = partial(
|
||||
fabric_project.upload_project,
|
||||
remote_dir=_to,
|
||||
local_dir=_from,
|
||||
use_sudo=use_sudo
|
||||
)
|
||||
if os.path.isfile(_from):
|
||||
executor = partial(
|
||||
fabric_project.put,
|
||||
remote_path=_to,
|
||||
local_path=_from,
|
||||
use_sudo=use_sudo
|
||||
)
|
||||
|
||||
with fabric_api.settings(**ResourceSSHMixin._fabric_settings(resource)):
|
||||
return executor()
|
||||
|
||||
@staticmethod
|
||||
def _fabric_settings(resource):
|
||||
return {
|
||||
'host_string': ResourceSSHMixin._ssh_command_host(resource),
|
||||
'key_filename': resource.args['ssh_key'].value,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _ssh_command_host(resource):
|
||||
return '{}@{}'.format(resource.args['ssh_user'].value,
|
||||
resource.args['ip'].value)
|
||||
|
||||
|
||||
class LibrarianPuppet(ResourceSSHMixin):
|
||||
def __init__(self, resource, organization='openstack'):
|
||||
class LibrarianPuppet(object):
|
||||
def __init__(self, resource, organization='openstack', transport_sync=None, transport_run=None):
|
||||
self.resource = resource
|
||||
self.organization = organization
|
||||
self.transport_sync = transport_sync
|
||||
self.transport_run = transport_run
|
||||
|
||||
def install(self):
|
||||
puppet_module = '{}-{}'.format(
|
||||
@ -87,7 +25,7 @@ class LibrarianPuppet(ResourceSSHMixin):
|
||||
self.resource.metadata['puppet_module']
|
||||
)
|
||||
|
||||
puppetlabs = self._ssh_command(
|
||||
puppetlabs = self.transport_run.run(
|
||||
self.resource,
|
||||
'sudo', 'cat', '/var/tmp/puppet/Puppetfile'
|
||||
)
|
||||
@ -123,14 +61,16 @@ class LibrarianPuppet(ResourceSSHMixin):
|
||||
f.write('\n'.join(modules))
|
||||
f.write('\n')
|
||||
|
||||
self._scp_command(
|
||||
self.transport_sync.copy(
|
||||
self.resource,
|
||||
'/tmp/Puppetfile',
|
||||
'/var/tmp/puppet/Puppetfile',
|
||||
use_sudo=True
|
||||
)
|
||||
|
||||
self._ssh_command(
|
||||
self.transport_sync.sync_all()
|
||||
|
||||
self.transport_run.run(
|
||||
self.resource,
|
||||
'sudo', 'librarian-puppet', 'install',
|
||||
cwd='/var/tmp/puppet'
|
||||
@ -142,7 +82,7 @@ class LibrarianPuppet(ResourceSSHMixin):
|
||||
# - hiera-redis is installed with the 2.0 fix (https://github.com/GGenie/hiera-redis)
|
||||
# - redis is installed and cluster set up with master (on slaves set up 'slaveof 10.0.0.2 6379')
|
||||
# - redis keys are separated by colon (same as in hiera-redis backend)
|
||||
class Puppet(ResourceSSHMixin, TempFileHandler):
|
||||
class Puppet(TempFileHandler):
|
||||
def action(self, resource, action_name):
|
||||
log.debug('Executing Puppet manifest %s %s', action_name, resource)
|
||||
|
||||
@ -151,9 +91,11 @@ class Puppet(ResourceSSHMixin, TempFileHandler):
|
||||
|
||||
self.upload_manifests(resource)
|
||||
|
||||
self._scp_command(resource, action_file, '/tmp/action.pp')
|
||||
self.prepare_templates_and_scripts(resource, action_file, '')
|
||||
self.transport_sync.copy(resource, action_file, '/tmp/action.pp')
|
||||
self.transport_sync.sync_all()
|
||||
|
||||
cmd = self._ssh_command(
|
||||
cmd = self.transport_run.run(
|
||||
resource,
|
||||
'puppet', 'apply', '-vd', '/tmp/action.pp', '--detailed-exitcodes',
|
||||
env={
|
||||
@ -185,7 +127,7 @@ class Puppet(ResourceSSHMixin, TempFileHandler):
|
||||
forge = resource.args['forge'].value
|
||||
|
||||
# Check if module already installed
|
||||
modules = self._ssh_command(
|
||||
modules = self.transport_run.run(
|
||||
resource,
|
||||
'sudo', 'puppet', 'module', 'list'
|
||||
)
|
||||
@ -197,7 +139,7 @@ class Puppet(ResourceSSHMixin, TempFileHandler):
|
||||
break
|
||||
|
||||
if not module_installed:
|
||||
self._ssh_command(
|
||||
self.transport_run.run(
|
||||
resource,
|
||||
'sudo', 'puppet', 'module', 'install', forge
|
||||
)
|
||||
@ -205,7 +147,9 @@ class Puppet(ResourceSSHMixin, TempFileHandler):
|
||||
log.debug('Skipping module installation, already installed')
|
||||
|
||||
def upload_manifests_librarian(self, resource):
|
||||
librarian = LibrarianPuppet(resource)
|
||||
librarian = LibrarianPuppet(resource,
|
||||
transport_run=self.transport_run,
|
||||
transport_sync=self.transport_sync)
|
||||
librarian.install()
|
||||
|
||||
def upload_manifests_git(self, resource):
|
||||
@ -214,16 +158,18 @@ class Puppet(ResourceSSHMixin, TempFileHandler):
|
||||
module_directory = '/etc/puppet/modules/{}'.format(
|
||||
resource.metadata['puppet_module']
|
||||
)
|
||||
self._ssh_command(
|
||||
self.transport_run.run(
|
||||
resource,
|
||||
'sudo', 'rm', '-Rf', module_directory
|
||||
)
|
||||
self._ssh_command(
|
||||
self.transport_run.run(
|
||||
resource, 'sudo', 'mkdir', '-p', module_directory
|
||||
)
|
||||
|
||||
self._scp_command(resource, manifests_path, '/tmp')
|
||||
self._ssh_command(
|
||||
self.transport_sync.copy(resource, manifests_path, '/tmp')
|
||||
self.transport_sync.sync_all()
|
||||
|
||||
self.transport_run.run(
|
||||
resource,
|
||||
'sudo', 'mv',
|
||||
'/tmp/{}/*'.format(os.path.split(manifests_path)[1]),
|
||||
|
0
solar/solar/core/transports/__init__.py
Normal file
0
solar/solar/core/transports/__init__.py
Normal file
90
solar/solar/core/transports/base.py
Normal file
90
solar/solar/core/transports/base.py
Normal file
@ -0,0 +1,90 @@
|
||||
class Executor(object):
|
||||
|
||||
def __init__(self, resource, executor, params=None):
|
||||
"""
|
||||
:param resource: solar resource
|
||||
:param executor: callable executor, that will perform action
|
||||
:param params: optional argument
|
||||
that migth be used later for decomposition etc
|
||||
"""
|
||||
self.resource = resource
|
||||
self.params = params
|
||||
self._executor = executor
|
||||
self._valid = True
|
||||
|
||||
@property
|
||||
def valid(self):
|
||||
return self._valid
|
||||
|
||||
@valid.setter
|
||||
def valid(self, value):
|
||||
self._valid = value
|
||||
|
||||
def run(self, transport):
|
||||
if self.valid:
|
||||
self._executor(transport)
|
||||
|
||||
|
||||
class SyncTransport(object):
|
||||
"""
|
||||
Transport that is responsible for file / directory syncing.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.executors = []
|
||||
|
||||
def bind_with(self, other):
|
||||
# we migth add there something later
|
||||
# like compat checking etc
|
||||
self.other = other
|
||||
|
||||
def copy(self, resource, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def preprocess(self, executor):
|
||||
# we can check there if we need to run sync executor or not
|
||||
# ideally would be to do so on other side
|
||||
# it may set executor.valid to False then executor will be skipped
|
||||
pass
|
||||
|
||||
def preprocess_all(self):
|
||||
# we cat use there md5 for big files to check if we need to sync it
|
||||
# or if remote is still valid
|
||||
# we can run that in parallell also
|
||||
# can be also used to prepare files for further transfer
|
||||
for executor in self.executors:
|
||||
self.preprocess(executor)
|
||||
|
||||
def run_all(self):
|
||||
for executor in self.executors:
|
||||
executor.run(self)
|
||||
|
||||
def sync_all(self):
|
||||
"""
|
||||
It checks if action is required first,
|
||||
then runs all sequentially.
|
||||
Could be someday changed to parallel thing.
|
||||
"""
|
||||
self.preprocess_all()
|
||||
self.run_all()
|
||||
self.executors = [] # clear after all
|
||||
|
||||
|
||||
class RunTransport(object):
|
||||
"""
|
||||
Transport that is responsible for executing remote commands, rpc like thing.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def bind_with(self, other):
|
||||
# we migth add there something later
|
||||
# like compat checking etc
|
||||
self.other = other
|
||||
|
||||
def run(self, resource, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.run(*args, **kwargs)
|
48
solar/solar/core/transports/rsync.py
Normal file
48
solar/solar/core/transports/rsync.py
Normal file
@ -0,0 +1,48 @@
|
||||
import os
|
||||
from functools import partial
|
||||
from contextlib import nested
|
||||
|
||||
from fabric import api as fabric_api
|
||||
|
||||
from solar.core.log import log
|
||||
from solar.core.transports.base import SyncTransport, Executor
|
||||
|
||||
|
||||
class RsyncSyncTransport(SyncTransport):
|
||||
|
||||
def _rsync_props(self, resource):
|
||||
return {
|
||||
'ssh_key': resource.args['ssh_key'].value,
|
||||
'ssh_user': resource.args['ssh_user'].value
|
||||
}
|
||||
|
||||
def _rsync_command_host(self, resource):
|
||||
return '{}@{}'.format(resource.args['ssh_user'].value,
|
||||
resource.args['ip'].value)
|
||||
|
||||
def copy(self, resource, _from, _to, use_sudo=False):
|
||||
log.debug("RSYNC: %s -> %s", _from, _to)
|
||||
if use_sudo:
|
||||
rsync_path = "sudo rsync"
|
||||
else:
|
||||
rsync_path = "rsync"
|
||||
rsync_props = self._rsync_props(resource)
|
||||
rsync_cmd = ('rsync -az -e "ssh -i %(ssh_key)s" '
|
||||
'--rsync-path="%(rsync_path)s" %(_from)s '
|
||||
'%(rsync_host)s:%(_to)s') % dict(
|
||||
rsync_path=rsync_path,
|
||||
ssh_key=rsync_props['ssh_key'],
|
||||
rsync_host=self._rsync_command_host(resource),
|
||||
_from=_from,
|
||||
_to=_to)
|
||||
|
||||
rsync_executor = lambda transport: fabric_api.local(
|
||||
rsync_cmd
|
||||
)
|
||||
|
||||
log.debug("RSYNC CMD: %r" % rsync_cmd)
|
||||
|
||||
executor = Executor(resource=resource,
|
||||
executor=rsync_executor,
|
||||
params=(_from, _to, use_sudo))
|
||||
self.executors.append(executor)
|
95
solar/solar/core/transports/ssh.py
Normal file
95
solar/solar/core/transports/ssh.py
Normal file
@ -0,0 +1,95 @@
|
||||
import os
|
||||
from functools import partial
|
||||
from contextlib import nested
|
||||
|
||||
from fabric import api as fabric_api
|
||||
from fabric.contrib import project as fabric_project
|
||||
|
||||
from solar.core.log import log
|
||||
from solar.core.transports.base import RunTransport, SyncTransport, Executor
|
||||
|
||||
|
||||
class _SSHTransport(object):
|
||||
|
||||
# TODO: maybe static/class method ?
|
||||
def _fabric_settings(self, resource):
|
||||
return {
|
||||
'host_string': self._ssh_command_host(resource),
|
||||
'key_filename': resource.args['ssh_key'].value,
|
||||
}
|
||||
|
||||
# TODO: maybe static/class method ?
|
||||
def _ssh_command_host(self, resource):
|
||||
return '{}@{}'.format(resource.args['ssh_user'].value,
|
||||
resource.args['ip'].value)
|
||||
|
||||
|
||||
class SSHSyncTransport(SyncTransport, _SSHTransport):
|
||||
|
||||
def __init__(self):
|
||||
SyncTransport.__init__(self)
|
||||
|
||||
def _copy_file(self, resource, _from, _to, use_sudo=False):
|
||||
executor = lambda transport: fabric_project.put(
|
||||
remote_path=_to,
|
||||
local_path=_from,
|
||||
use_sudo=use_sudo
|
||||
)
|
||||
return executor
|
||||
|
||||
def _copy_directory(self, resource, _from, _to, use_sudo=False):
|
||||
executor = lambda transport: fabric_project.upload_project(
|
||||
remote_dir=_to,
|
||||
local_dir=_from,
|
||||
use_sudo=use_sudo
|
||||
)
|
||||
return executor
|
||||
|
||||
def copy(self, resource, _from, _to, use_sudo=False):
|
||||
log.debug('SCP: %s -> %s', _from, _to)
|
||||
|
||||
if os.path.isfile(_from):
|
||||
executor = self._copy_file(resource, _from, _to, use_sudo)
|
||||
else:
|
||||
executor = self._copy_directory(resource, _from, _to, use_sudo)
|
||||
|
||||
# with fabric_api.settings(**self._fabric_settings(resource)):
|
||||
# return executor()
|
||||
executor = Executor(resource=resource,
|
||||
executor=executor,
|
||||
params=(_from, _to, use_sudo))
|
||||
self.executors.append(executor)
|
||||
|
||||
def run_all(self):
|
||||
for executor in self.executors:
|
||||
resource = executor.resource
|
||||
with fabric_api.settings(**self._fabric_settings(resource)):
|
||||
executor.run(self)
|
||||
|
||||
|
||||
class SSHRunTransport(RunTransport, _SSHTransport):
|
||||
|
||||
def run(self, resource, *args, **kwargs):
|
||||
log.debug('SSH: %s', args)
|
||||
|
||||
executor = fabric_api.run
|
||||
if kwargs.get('use_sudo', False):
|
||||
executor = fabric_api.sudo
|
||||
|
||||
managers = [
|
||||
fabric_api.settings(**self._fabric_settings(resource)),
|
||||
]
|
||||
|
||||
cwd = kwargs.get('cwd')
|
||||
if cwd:
|
||||
managers.append(fabric_api.cd(kwargs['cwd']))
|
||||
|
||||
env = kwargs.get('env')
|
||||
if env:
|
||||
managers.append(fabric_api.shell_env(**kwargs['env']))
|
||||
|
||||
if kwargs.get('warn_only', False):
|
||||
managers.append(fabric_api.warn_only())
|
||||
|
||||
with nested(*managers):
|
||||
return executor(' '.join(args))
|
Loading…
x
Reference in New Issue
Block a user