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