Disconnect method added, refactoring, added CLI update

This commit is contained in:
Przemyslaw Kaminski 2015-04-17 12:55:29 +02:00
parent d6bbb652e6
commit 1c47ea6ed7
4 changed files with 54 additions and 36 deletions

View File

@ -9,9 +9,9 @@ node1 = resource.create('node1', 'x/resources/ro_node/', 'rs/', {'ip':'10.0.0.3'
node2 = resource.create('node2', 'x/resources/ro_node/', 'rs/', {'ip':'10.0.0.4', 'ssh_key' : '/vagrant/tmp/keys/ssh_private', 'ssh_user':'vagrant'})
keystone_db_data = resource.create('mariadb_keystone_data', 'x/resources/data_container/', 'rs/', {'image' : 'mariadb', 'export_volumes' : ['/var/lib/mysql'], 'host': '', 'ssh_user': '', 'ssh_key': ''}, connections={'host' : 'node2.ip', 'ssh_key':'node2.ssh_key', 'ssh_user':'node2.ssh_user'})
keystone_db_data = resource.create('mariadb_keystone_data', 'x/resources/data_container/', 'rs/', {'image' : 'mariadb', 'export_volumes' : ['/var/lib/mysql'], 'ip': '', 'ssh_user': '', 'ssh_key': ''}, connections={'ip' : 'node2.ip', 'ssh_key':'node2.ssh_key', 'ssh_user':'node2.ssh_user'})
nova_db_data = resource.create('mariadb_nova_data', 'x/resources/data_container/', 'rs/', {'image' : 'mariadb', 'export_volumes' : ['/var/lib/mysql'], 'host': '', 'ssh_user': '', 'ssh_key': ''}, connections={'host' : 'node1.ip', 'ssh_key':'node1.ssh_key', 'ssh_user':'node1.ssh_user'})
nova_db_data = resource.create('mariadb_nova_data', 'x/resources/data_container/', 'rs/', {'image' : 'mariadb', 'export_volumes' : ['/var/lib/mysql'], 'ip': '', 'ssh_user': '', 'ssh_key': ''}, connections={'ip' : 'node1.ip', 'ssh_key':'node1.ssh_key', 'ssh_user':'node1.ssh_user'})
```
to make connection after resource is created use `signal.connect`
@ -62,17 +62,21 @@ python cli.py resource create node1 x/resources/ro_node/ rs/ '{"ip":"10.0.0.3",
python cli.py resource create node2 x/resources/ro_node/ rs/ '{"ip":"10.0.0.4", "ssh_key" : "/vagrant/tmp/keys/ssh_private", "ssh_user":"vagrant"}'
python cli.py resource create mariadb_keystone_data x/resources/data_container/ rs/ '{"image": "mariadb", "export_volumes" : ["/var/lib/mysql"], "host": "", "ssh_user": "", "ssh_key": ""}'
python cli.py resource create mariadb_keystone_data x/resources/data_container/ rs/ '{"image": "mariadb", "export_volumes" : ["/var/lib/mysql"], "ip": "", "ssh_user": "", "ssh_key": ""}'
python cli.py resource create mariadb_nova_data x/resources/data_container/ rs/ '{"image" : "mariadb", "export_volumes" : ["/var/lib/mysql"], "host": "", "ssh_user": "", "ssh_key": ""}'
python cli.py resource create mariadb_nova_data x/resources/data_container/ rs/ '{"image" : "mariadb", "export_volumes" : ["/var/lib/mysql"], "ip": "", "ssh_user": "", "ssh_key": ""}'
# View resources
python cli.py resource show rs/mariadb_keystone_data
# Connect resources
python cli.py connect rs/mariadb_keystone_data rs/node2 --mapping '{"host" : "node2.ip", "ssh_key":"node2.ssh_key", "ssh_user":"node2.ssh_user"}'
python cli.py connect rs/node2 rs/mariadb_keystone_data
python cli.py connect rs/mariadb_nova_data rs/node1 --mapping '{"host" : "node1.ip", "ssh_key":"node1.ssh_key", "ssh_user":"node1.ssh_user"}'
python cli.py connect rs/node1 rs/mariadb_nova_data
# Test update
python cli.py update rs/node2 '{"ip": "1.1.1.1"}'
python cli.py resource show rs/mariadb_keystone_data # --> IP is 1.1.1.1
# View connections
python cli.py connections show

17
cli.py
View File

@ -1,6 +1,7 @@
import click
import json
import networkx as nx
import os
from x import resource as xr
from x import signals as xs
@ -37,6 +38,22 @@ def init_cli_resource():
resource.add_command(show)
@click.command()
@click.argument('path')
@click.argument('args')
def update(args, path):
print 'Update', path, args
args = json.loads(args)
# Need to load all resources for bubbling effect to take place
# TODO: resources can be scattered around, this is a simple
# situation when we assume resources are all in one directory
base_path, name = os.path.split(path)
all = xr.load_all(base_path)
r = all[name]
r.update(args)
resource.add_command(update)
def init_cli_connect():
@click.command()

View File

@ -31,11 +31,11 @@ class Resource(object):
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)
self.args[key] = value
self.changed.append(key)
signals.notify(self, key, value)
self.save()
def action(self, action):
if action in self.actions:
@ -48,6 +48,12 @@ class Resource(object):
if req not in args:
raise Exception('Requirement `{0}` is missing in args'.format(req))
# TODO: versioning
def save(self):
meta_file = os.path.join(self.base_dir, 'meta.yaml')
with open(meta_file, 'w') as f:
f.write(yaml.dump(self.metadata))
def create(name, base_path, dest_path, args, connections={}):
if not os.path.exists(base_path):
@ -77,8 +83,7 @@ def create(name, base_path, dest_path, args, connections={}):
#save
shutil.copytree(base_path, dest_path)
with open(meta_file, 'w') as f:
f.write(yaml.dump(meta))
resource.save()
db.resource_add(name, resource)
return resource

View File

@ -26,34 +26,24 @@ def guess_mapping(emitter, receiver):
'ssh_user': '<receiver>.ssh_user'
}
If receiver accepts inputs that are not present in emitter,
error is thrown -- such cases require manual intervention.
:param emitter:
:param receiver:
:return:
"""
guessed = {}
for key in emitter.requires:
if key in receiver.requires:
guessed[key] = '{}.{}'.format(emitter.name, key)
ret = {}
diff = set(receiver.requires).difference(emitter.requires)
if diff:
raise Exception(
'The following inputs are not provided by emitter: {}.'
'You need to set the connection manually.'.format(diff)
)
for key in receiver.requires:
ret[key] = '{}.{}'.format(emitter.name, key)
return ret
return guessed
def connect(emitter, receiver, mapping=None):
if mapping is None:
mapping = guess_mapping(emitter, receiver)
mapping = mapping or {}
guessed = guess_mapping(emitter, receiver)
guessed.update(mapping)
for src, dst in mapping.items():
for src, dst in guessed.items():
CLIENTS.setdefault(emitter.name, {})
CLIENTS[emitter.name].setdefault(src, [])
CLIENTS[emitter.name][src].append((receiver.name, dst))
@ -73,26 +63,28 @@ def disconnect(emitter, receiver):
def notify(source, key, value):
CLIENTS.setdefault(source.name, [])
print 'Notify', source.name, key, value, CLIENTS[source.name]
if key in CLIENTS[source.name]:
for client, r_key in CLIENTS[source.name][key]:
resource = db.get_resource(client)
print 'Resource found', client
if resource:
resource.update({r_key: value})
else:
#XXX resource deleted?
print 'Resource {} deleted?'.format(client)
pass
def assign_connections(reciver, connections):
def assign_connections(receiver, 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
receiver.args[key] = value
mappings[resource].append((r_key, key))
for resource, r_mappings in mappings.iteritems():
connect(resource, reciver, r_mappings)
connect(resource, receiver, r_mappings)
def connection_graph():