Init x
This commit is contained in:
parent
56baf73d05
commit
a50f0933c7
15
README
Normal file
15
README
Normal file
@ -0,0 +1,15 @@
|
||||
Usage:
|
||||
Creating resources:
|
||||
|
||||
from x import resource
|
||||
node1 = resource.create('node1', 'x/resources/ro_node/', 'rs/', {'ip':'10.0.0.3', 'ssh_key' : '/vagrant/tmp/keys/ssh_private', 'user':'vagrant'})
|
||||
node2 = resource.create('node2', 'x/resources/ro_node/', 'rs/', {'ip':'10.0.0.4', 'ssh_key' : '/vagrant/tmp/keys/ssh_private', 'user':'vagrant'})
|
||||
keystone_db_data = resource.create('mariadb_keystone_data', 'x/resources/data_container/', 'rs/', {'image' : 'mariadb', 'export_volumes' : ['/var/lib/mysql'], 'host': '', 'remote_user': '', 'ssh_key': ''}, connections={'host' : 'node2.ip', 'ssh_key':'node2.ssh_key', 'remote_user':'node2.user'})
|
||||
nova_db_data = resource.create('mariadb_nova_data', 'x/resources/data_container/', 'rs/', {'image' : 'mariadb', 'export_volumes' : ['/var/lib/mysql'], 'host': '', 'remote_user': '', 'ssh_key': ''}, connections={'host' : 'node1.ip', 'ssh_key':'node1.ssh_key', 'remote_user':'node1.user'})
|
||||
|
||||
to make connection after resource is created use signal.connect
|
||||
|
||||
*** WARNNING ***
|
||||
Resource DB is stored only in memory, if you close python interpretet you will lost it.
|
||||
It can be recreated from resources but it's not done yet.
|
||||
Connections are stored only in memory. It can be easly dumped as JSON file
|
0
__init__.py
Normal file
0
__init__.py
Normal file
11
actions.py
Normal file
11
actions.py
Normal file
@ -0,0 +1,11 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
import handlers
|
||||
|
||||
def resource_action(resource, action):
|
||||
handler = resource.metadata['handler']
|
||||
handler = handlers.get(handler)
|
||||
handler().action(resource, action)
|
||||
|
||||
def tag_action(tag, action):
|
||||
#TODO
|
||||
pass
|
11
db.py
Normal file
11
db.py
Normal file
@ -0,0 +1,11 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
RESOURCE_DB = {}
|
||||
|
||||
def resource_add(key, value):
|
||||
if key in RESOURCE_DB:
|
||||
raise Exception('Key `{0}` already exists'.format(key))
|
||||
RESOURCE_DB[key] = value
|
||||
|
||||
def get_resource(key):
|
||||
return RESOURCE_DB.get(key, None)
|
62
handlers.py
Normal file
62
handlers.py
Normal file
@ -0,0 +1,62 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from jinja2 import Template
|
||||
|
||||
|
||||
def get(handler_name):
|
||||
handler = HANDLERS.get(handler_name, None)
|
||||
if handler:
|
||||
return handler
|
||||
raise Exception('Handler {0} does not exist'.format(handler_name))
|
||||
|
||||
|
||||
class Ansible(object):
|
||||
"""TODO"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def action(self, resource, action):
|
||||
pass
|
||||
|
||||
def _get_connection(self, resource):
|
||||
return {'ssh_user': '',
|
||||
'ssh_key': '',
|
||||
'host': ''}
|
||||
|
||||
def _create_inventory(self, dest_dir):
|
||||
pass
|
||||
|
||||
def _create_playbook(self, dest_dir):
|
||||
pass
|
||||
|
||||
|
||||
class Shell(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def action(self, resource, action):
|
||||
action_file = resource.metadata['actions'][action]
|
||||
action_file = os.path.join(resource.base_dir, action_file)
|
||||
with open(action_file) as f:
|
||||
tpl = Template(f.read())
|
||||
tpl = tpl.render(resource.args)
|
||||
|
||||
tmp_file = tempfile.mkstemp(text=True)[1]
|
||||
with open(tmp_file, 'w') as f:
|
||||
f.write(tpl)
|
||||
|
||||
subprocess.call(['bash', tmp_file])
|
||||
|
||||
|
||||
class Empty(object):
|
||||
def action(self, resource, action):
|
||||
pass
|
||||
|
||||
|
||||
HANDLERS = {'ansible' : Ansible,
|
||||
'shell': Shell,
|
||||
'none': Empty}
|
||||
|
73
resource.py
Normal file
73
resource.py
Normal file
@ -0,0 +1,73 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import yaml
|
||||
|
||||
import actions
|
||||
import signals
|
||||
import db
|
||||
|
||||
|
||||
class Resource(object):
|
||||
def __init__(self, name, metadata, args, base_dir):
|
||||
self.name = name
|
||||
self.base_dir = base_dir
|
||||
self.metadata = metadata
|
||||
self.actions = metadata['actions'].keys() if metadata['actions'] else None
|
||||
self.requires = metadata['input'].keys()
|
||||
self._validate_args(args)
|
||||
self.args = args
|
||||
self.changed = []
|
||||
|
||||
def __repr__(self):
|
||||
return "Resource('name={0}', metadata={1}, args={2}, base_dir='{3}')".format(self.name,
|
||||
self.metadata,
|
||||
self.args,
|
||||
self.base_dir)
|
||||
|
||||
def update(self, args):
|
||||
for key, value in args.iteritems():
|
||||
resource_key = self.args.get(key, None)
|
||||
if resource_key:
|
||||
self.args[key] = value
|
||||
self.changed.append(key)
|
||||
signals.notify(self, key, value)
|
||||
|
||||
def action(self, action):
|
||||
if action in self.actions:
|
||||
actions.resource_action(self, action)
|
||||
else:
|
||||
raise Exception('Uuups, action is not available')
|
||||
|
||||
def _validate_args(self, args):
|
||||
for req in self.requires:
|
||||
if not req in args:
|
||||
raise Exception('Requirement `{0}` is missing in args'.format(req))
|
||||
|
||||
|
||||
def create(name, base_path, dest_path, args, connections={}):
|
||||
if not os.path.exists(base_path):
|
||||
raise Exception('Base resource does not exist: {0}'.format(dest_path))
|
||||
if not os.path.exists(dest_path):
|
||||
raise Exception('Dest dir does not exist: {0}'.format(dest_path))
|
||||
if not os.path.isdir(dest_path):
|
||||
raise Exception('Dest path is not a directory: {0}'.format(dest_path))
|
||||
|
||||
dest_path = os.path.join(dest_path, name)
|
||||
base_meta_file = os.path.join(base_path, 'meta.yaml')
|
||||
meta_file = os.path.join(dest_path, 'meta.yaml')
|
||||
|
||||
meta = yaml.load(open(base_meta_file).read())
|
||||
meta['id'] = name
|
||||
meta['version'] = '1.0.0'
|
||||
|
||||
resource = Resource(name, meta, args, dest_path)
|
||||
signals.assign_connections(resource, connections)
|
||||
|
||||
#save
|
||||
shutil.copytree(base_path, dest_path)
|
||||
with open(meta_file, 'w') as f:
|
||||
f.write(yaml.dump(meta))
|
||||
db.resource_add(name, resource)
|
||||
return resource
|
10
resources/data_container/meta.yaml
Normal file
10
resources/data_container/meta.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
id: data_container
|
||||
handler: ansible
|
||||
version: 1.0.0
|
||||
actions:
|
||||
run: run.yml
|
||||
remove: remove.yml
|
||||
input:
|
||||
host:
|
||||
image:
|
||||
export_volumes:
|
6
resources/data_container/remove.yml
Normal file
6
resources/data_container/remove.yml
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: docker stop {{ name }}
|
||||
- shell: docker rm {{ name }}
|
6
resources/data_container/run.yml
Normal file
6
resources/data_container/run.yml
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: docker run -d --net="host" --privileged \
|
||||
--name {{ name }} {{ image }} /bin/sh
|
10
resources/docker/docker.yml
Normal file
10
resources/docker/docker.yml
Normal file
@ -0,0 +1,10 @@
|
||||
id: docker
|
||||
type: resource
|
||||
handler: ansible
|
||||
version: v1
|
||||
actions:
|
||||
run: simple/docker/run.yml
|
||||
remove: simple/docker/remove.yml
|
||||
input:
|
||||
base_image: ubuntu
|
||||
tags: [n/1]
|
9
resources/docker_container/meta.yaml
Normal file
9
resources/docker_container/meta.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
id: container
|
||||
handler: ansible
|
||||
version: 1.0.0
|
||||
actions:
|
||||
run: run.yml
|
||||
remove: remove.yml
|
||||
input:
|
||||
image:
|
||||
volume_binds:
|
6
resources/docker_container/remove.yml
Normal file
6
resources/docker_container/remove.yml
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: docker stop {{ name }}
|
||||
- shell: docker rm {{ name }}
|
6
resources/docker_container/run.yml
Normal file
6
resources/docker_container/run.yml
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: docker run -d --net="host" --privileged \
|
||||
--name {{ name }} {{ image }}
|
8
resources/file/meta.yaml
Normal file
8
resources/file/meta.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
id: file
|
||||
handler: shell
|
||||
version: 1.0.0
|
||||
actions:
|
||||
run: run.sh
|
||||
remove: remove.sh
|
||||
input:
|
||||
path: /tmp/test_file
|
3
resources/file/remove.sh
Normal file
3
resources/file/remove.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm {{ path }}
|
3
resources/file/run.sh
Normal file
3
resources/file/run.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
touch {{ path }}
|
9
resources/mariadb/meta.yaml
Normal file
9
resources/mariadb/meta.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
id: mariadb
|
||||
handler: ansible
|
||||
version: 1.0.0
|
||||
actions:
|
||||
run: run.yml
|
||||
remove: remove.yml
|
||||
input:
|
||||
image: tutum/mariadq
|
||||
tags: [n/1]
|
6
resources/mariadb/remove.yml
Normal file
6
resources/mariadb/remove.yml
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: docker stop {{ name }}
|
||||
- shell: docker rm {{ name }}
|
6
resources/mariadb/run.yml
Normal file
6
resources/mariadb/run.yml
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
- hosts: [{{ ip }}]
|
||||
sudo: yes
|
||||
tasks:
|
||||
- shell: docker run -d --net="host" --privileged \
|
||||
--name {{ name }} {{ image }}
|
10
resources/mariadb_table/meta.yaml
Normal file
10
resources/mariadb_table/meta.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
id: mariadb_user
|
||||
handler: ansible
|
||||
version: 1.0.0
|
||||
actions:
|
||||
run: run.yml
|
||||
remove: remove.yml
|
||||
input:
|
||||
name: name
|
||||
password: password
|
||||
users: []
|
9
resources/mariadb_user/meta.yaml
Normal file
9
resources/mariadb_user/meta.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
id: mariadb_user
|
||||
handler: ansible
|
||||
version: 1.0.0
|
||||
actions:
|
||||
run: run.yml
|
||||
remove: remove.yml
|
||||
input:
|
||||
name: name
|
||||
password: password
|
8
resources/ro_node/meta.yaml
Normal file
8
resources/ro_node/meta.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
id: mariadb
|
||||
handler: none
|
||||
version: 1.0.0
|
||||
actions:
|
||||
input:
|
||||
ip:
|
||||
ssh_key:
|
||||
user:
|
34
signals.py
Normal file
34
signals.py
Normal file
@ -0,0 +1,34 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
from collections import defaultdict
|
||||
|
||||
import db
|
||||
|
||||
CLIENTS = defaultdict(lambda: defaultdict(list))
|
||||
|
||||
def connect(emitter, reciver, mappings):
|
||||
for src, dst in mappings:
|
||||
CLIENTS[emitter.name][src].append((reciver.name, dst))
|
||||
|
||||
def notify(source, key, value):
|
||||
if key in CLIENTS[source.name]:
|
||||
for client, r_key in CLIENTS[source.name][key]:
|
||||
resource = db.get_resource(client)
|
||||
if resource:
|
||||
resource.update({r_key: value})
|
||||
else:
|
||||
#XXX resource deleted?
|
||||
pass
|
||||
|
||||
def assign_connections(reciver, connections):
|
||||
mappings = defaultdict(list)
|
||||
for key, dest in connections.iteritems():
|
||||
resource, r_key = dest.split('.')
|
||||
resource = db.get_resource(resource)
|
||||
value = resource.args[r_key]
|
||||
reciver.args[key] = value
|
||||
mappings[resource].append((r_key, key))
|
||||
for resource, r_mappings in mappings.iteritems():
|
||||
connect(resource, reciver, r_mappings)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user