Merge pull request #62 from xarses/fix-resources-assignment-rebased

Fix resources assignment
This commit is contained in:
Łukasz Oleś 2015-05-29 14:06:18 +02:00
commit 394a24a821
14 changed files with 96 additions and 268 deletions

View File

@ -1,4 +1,4 @@
clients-data-file: /vagrant/clients.json clients-data-file: /vagrant/tmp/connections.yaml
tmp: /vagrant/tmp tmp: /vagrant/tmp
@ -7,9 +7,8 @@ examples-dir: /vagrant/examples
extensions-dir: /vagrant/solar/solar/extensions extensions-dir: /vagrant/solar/solar/extensions
file-system-db: file-system-db:
resources-path: ./schema/resources
storage-path: /vagrant/tmp/storage storage-path: /vagrant/tmp/storage
template-dir: /vagrant/templates template-dir: /vagrant/templates
resources-files-mask: /vagrant/x/resources/*/*.yaml resources-files-mask: /vagrant/resources/*/*.yaml
resource-instances-path: /vagrant/tmp/resource-instances node_resource_template: /vagrant/resources/ro_node/

View File

@ -6,6 +6,10 @@ import time
from solar.core import resource from solar.core import resource
from solar.core import signals from solar.core import signals
from solar.interfaces.db import get_db
db = get_db()
db.clear()
signals.Connections.clear() signals.Connections.clear()
@ -13,23 +17,23 @@ if os.path.exists('rs'):
shutil.rmtree('rs') shutil.rmtree('rs')
os.mkdir('rs') os.mkdir('rs')
node1 = resource.create('node1', 'resources/ro_node/', 'rs/', {'ip':'10.0.0.3', 'ssh_key' : '/vagrant/.vagrant/machines/solar-dev2/virtualbox/private_key', 'ssh_user':'vagrant'}) node1 = resource.create('node1', 'resources/ro_node/', {'ip':'10.0.0.3', 'ssh_key' : '/vagrant/.vagrant/machines/solar-dev2/virtualbox/private_key', 'ssh_user':'vagrant'})
node2 = resource.create('node2', 'resources/ro_node/', 'rs/', {'ip':'10.0.0.4', 'ssh_key' : '/vagrant/.vagrant/machines/solar-dev3/virtualbox/private_key', 'ssh_user':'vagrant'}) node2 = resource.create('node2', 'resources/ro_node/', {'ip':'10.0.0.4', 'ssh_key' : '/vagrant/.vagrant/machines/solar-dev3/virtualbox/private_key', 'ssh_user':'vagrant'})
mariadb_service1 = resource.create('mariadb_service1', 'resources/mariadb_service', 'rs/', {'image':'mariadb', 'root_password' : 'mariadb', 'port' : '3306', 'ip': '', 'ssh_user': '', 'ssh_key': ''}) mariadb_service1 = resource.create('mariadb_service1', 'resources/mariadb_service', {'image':'mariadb', 'root_password' : 'mariadb', 'port' : '3306', 'ip': '', 'ssh_user': '', 'ssh_key': ''})
keystone_db = resource.create('keystone_db', 'resources/mariadb_db/', 'rs/', {'db_name':'keystone_db', 'login_password':'', 'login_user':'root', 'login_port': '', 'ip':'', 'ssh_user':'', 'ssh_key':''}) keystone_db = resource.create('keystone_db', 'resources/mariadb_db/', {'db_name':'keystone_db', 'login_password':'', 'login_user':'root', 'login_port': '', 'ip':'', 'ssh_user':'', 'ssh_key':''})
keystone_db_user = resource.create('keystone_db_user', 'resources/mariadb_user/', 'rs/', {'new_user_name' : 'keystone', 'new_user_password' : 'keystone', 'db_name':'', 'login_password':'', 'login_user':'root', 'login_port': '', 'ip':'', 'ssh_user':'', 'ssh_key':''}) keystone_db_user = resource.create('keystone_db_user', 'resources/mariadb_user/', {'new_user_name' : 'keystone', 'new_user_password' : 'keystone', 'db_name':'', 'login_password':'', 'login_user':'root', 'login_port': '', 'ip':'', 'ssh_user':'', 'ssh_key':''})
keystone_config1 = resource.create('keystone_config1', 'resources/keystone_config/', 'rs/', {'config_dir' : '/etc/solar/keystone', 'ip':'', 'ssh_user':'', 'ssh_key':'', 'admin_token':'admin', 'db_password':'', 'db_name':'', 'db_user':'', 'db_host':''}) keystone_config1 = resource.create('keystone_config1', 'resources/keystone_config/', {'config_dir' : '/etc/solar/keystone', 'ip':'', 'ssh_user':'', 'ssh_key':'', 'admin_token':'admin', 'db_password':'', 'db_name':'', 'db_user':'', 'db_host':''})
keystone_service1 = resource.create('keystone_service1', 'resources/keystone_service/', 'rs/', {'port':'5001', 'admin_port':'35357', 'image': '', 'ip':'', 'ssh_key':'', 'ssh_user':'', 'config_dir':''}) keystone_service1 = resource.create('keystone_service1', 'resources/keystone_service/', {'port':'5001', 'admin_port':'35357', 'image': '', 'ip':'', 'ssh_key':'', 'ssh_user':'', 'config_dir':''})
keystone_config2 = resource.create('keystone_config2', 'resources/keystone_config/', 'rs/', {'config_dir' : '/etc/solar/keystone', 'ip':'', 'ssh_user':'', 'ssh_key':'', 'admin_token':'admin', 'db_password':'', 'db_name':'', 'db_user':'', 'db_host':''}) keystone_config2 = resource.create('keystone_config2', 'resources/keystone_config/', {'config_dir' : '/etc/solar/keystone', 'ip':'', 'ssh_user':'', 'ssh_key':'', 'admin_token':'admin', 'db_password':'', 'db_name':'', 'db_user':'', 'db_host':''})
keystone_service2 = resource.create('keystone_service2', 'resources/keystone_service/', 'rs/', {'port':'5002', 'admin_port':'35357', 'image': '', 'ip':'', 'ssh_key':'', 'ssh_user':'', 'config_dir':''}) keystone_service2 = resource.create('keystone_service2', 'resources/keystone_service/', {'port':'5002', 'admin_port':'35357', 'image': '', 'ip':'', 'ssh_key':'', 'ssh_user':'', 'config_dir':''})
haproxy_keystone_config = resource.create('haproxy_keystone1_config', 'resources/haproxy_keystone_config/', 'rs/', {'name':'keystone_config', 'listen_port':'5000', 'servers':[], 'ports':[]}) haproxy_keystone_config = resource.create('haproxy_keystone1_config', 'resources/haproxy_keystone_config/', {'name':'keystone_config', 'listen_port':'5000', 'servers':[], 'ports':[]})
haproxy_config = resource.create('haproxy_config', 'resources/haproxy', 'rs/', {'ip':'', 'ssh_key':'', 'ssh_user':'', 'configs_names':[], 'configs_ports':[], 'listen_ports':[], 'configs':[], 'config_dir': ''}) haproxy_config = resource.create('haproxy_config', 'resources/haproxy', {'ip':'', 'ssh_key':'', 'ssh_user':'', 'configs_names':[], 'configs_ports':[], 'listen_ports':[], 'configs':[], 'config_dir': ''})
haproxy_service = resource.create('haproxy_service', 'resources/docker_container/', 'rs/', {'image' : 'tutum/haproxy', 'ports': [], 'host_binds': [], 'volume_binds':[], 'ip':'', 'ssh_key':'', 'ssh_user':''}) haproxy_service = resource.create('haproxy_service', 'resources/docker_container/', {'image' : 'tutum/haproxy', 'ports': [], 'host_binds': [], 'volume_binds':[], 'ip':'', 'ssh_key':'', 'ssh_user':''})
#### ####

View File

@ -1,9 +1,9 @@
- id: node_1 - id: node_1
ip: 10.0.0.2 ip: 10.0.0.2
ssh_user: vagrant ssh_user: vagrant
ssh_private_key_path: /vagrant/tmp/keys/ssh_private ssh_key: /vagrant/tmp/keys/ssh_private
- id: node_2 - id: node_2
ip: 10.0.0.3 ip: 10.0.0.3
ssh_user: vagrant ssh_user: vagrant
ssh_private_key_path: /vagrant/tmp/keys/ssh_private ssh_key: /vagrant/tmp/keys/ssh_private

View File

@ -1 +1 @@
clients-data-file: /tmp/clients.json clients-data-file: /tmp/connections.yaml

View File

@ -4,3 +4,4 @@ networkx==1.9.1
PyYAML==3.11 PyYAML==3.11
jsonschema==2.4.0 jsonschema==2.4.0
requests==2.7.0 requests==2.7.0
mock

View File

@ -4,6 +4,7 @@ set -e
VENV=x-venv VENV=x-venv
WORKSPACE=${WORKSPACE:-"/vagrant"}
CONFIG_FILE=$WORKSPACE/jenkins-config.yaml CONFIG_FILE=$WORKSPACE/jenkins-config.yaml
# Setup a proper path, I call my virtualenv dir "$VENV" and # Setup a proper path, I call my virtualenv dir "$VENV" and

View File

@ -107,12 +107,7 @@ class Cmd(object):
lambda r: Expression(args.resources, r.get('tags', [])).evaluate(), lambda r: Expression(args.resources, r.get('tags', [])).evaluate(),
self._get_resources_list()) self._get_resources_list())
resource_instances_path = utils.read_config()['resource-instances-path'] assign_resources_to_nodes(resources, nodes)
utils.create_dir(resource_instances_path)
assign_resources_to_nodes(
resources,
nodes,
resource_instances_path)
def _get_resources_list(self): def _get_resources_list(self):
result = [] result = []
@ -128,3 +123,7 @@ class Cmd(object):
def main(): def main():
api = Cmd() api = Cmd()
api.parse(sys.argv[1:]) api.parse(sys.argv[1:])
if __name__ == '__main__':
main()

View File

@ -1,19 +0,0 @@
# -*- 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)
def clear():
global RESOURCE_DB
RESOURCE_DB = {}

View File

@ -1,4 +1,4 @@
# -*- coding: UTF-8 -*- # -*- coding: utf-8 -*-
import os import os
import shutil import shutil
import tempfile import tempfile
@ -25,7 +25,7 @@ class BaseHandler(object):
def _compile_action_file(self, resource, action): def _compile_action_file(self, resource, action):
action_file = resource.metadata['actions'][action] action_file = resource.metadata['actions'][action]
action_file = os.path.join(resource.base_dir, 'actions', action_file) action_file = os.path.join(resource.metadata['actions_path'], action_file)
dir_path = self.dirs[resource.name] dir_path = self.dirs[resource.name]
dest_file = tempfile.mkstemp(text=True, prefix=action, dir=dir_path)[1] dest_file = tempfile.mkstemp(text=True, prefix=action, dir=dir_path)[1]
args = self._make_args(resource) args = self._make_args(resource)
@ -43,7 +43,7 @@ class BaseHandler(object):
def _make_args(self, resource): def _make_args(self, resource):
args = {'name': resource.name} args = {'name': resource.name}
args['resource_dir'] = resource.base_dir args['resource_dir'] = resource.metadata['actions_path']
args.update(resource.args) args.update(resource.args)
return args return args

View File

@ -8,23 +8,27 @@ from copy import deepcopy
import yaml import yaml
import solar
from solar.core import actions from solar.core import actions
from solar.core import db
from solar.core import observer from solar.core import observer
from solar.core import signals from solar.core import signals
from solar import utils from solar import utils
from solar.core import validation from solar.core import validation
from solar.core.connections import ResourcesConnectionGraph from solar.core.connections import ResourcesConnectionGraph
from solar.interfaces.db import get_db
db = get_db()
class Resource(object): class Resource(object):
def __init__(self, name, metadata, args, base_dir, tags=None): def __init__(self, name, metadata, args, tags=None):
self.name = name self.name = name
self.base_dir = base_dir
self.metadata = metadata self.metadata = metadata
self.actions = metadata['actions'].keys() if metadata['actions'] else None self.actions = metadata['actions'].keys() if metadata['actions'] else None
self.args = {} self.args = {}
for arg_name, arg_value in args.items(): for arg_name, arg_value in args.items():
if not self.metadata['input'].get(arg_name): if not self.metadata['input'].get(arg_name):
continue continue
@ -42,11 +46,10 @@ class Resource(object):
def __repr__(self): def __repr__(self):
return ("Resource(name='{0}', metadata={1}, args={2}, " return ("Resource(name='{0}', metadata={1}, args={2}, "
"base_dir='{3}', tags={4})").format(self.name, "tags={3})").format(self.name,
json.dumps(self.metadata), json.dumps(self.metadata),
json.dumps(self.args_show()), json.dumps(self.args_show()),
self.base_dir, self.tags)
self.tags)
def args_show(self): def args_show(self):
def formatter(v): def formatter(v):
@ -111,20 +114,13 @@ class Resource(object):
for k, v in self.args_dict().items(): for k, v in self.args_dict().items():
metadata['input'][k]['value'] = v metadata['input'][k]['value'] = v
meta_file = os.path.join(self.base_dir, 'meta.yaml') db.add_resource(self.name, metadata)
with open(meta_file, 'w') as f:
f.write(yaml.dump(metadata, default_flow_style=False))
def create(name, base_path, dest_path, args, connections={}): def create(name, base_path, args, tags=[], connections={}):
if not os.path.exists(base_path): if not os.path.exists(base_path):
raise Exception('Base resource does not exist: {0}'.format(base_path)) raise Exception('Base resource does not exist: {0}'.format(base_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.abspath(os.path.join(dest_path, name))
base_meta_file = os.path.join(base_path, 'meta.yaml') base_meta_file = os.path.join(base_path, 'meta.yaml')
actions_path = os.path.join(base_path, 'actions') actions_path = os.path.join(base_path, 'actions')
@ -132,42 +128,32 @@ def create(name, base_path, dest_path, args, connections={}):
meta['id'] = name meta['id'] = name
meta['version'] = '1.0.0' meta['version'] = '1.0.0'
meta['actions'] = {} meta['actions'] = {}
meta['actions_path'] = actions_path
if os.path.exists(actions_path): if os.path.exists(actions_path):
for f in os.listdir(actions_path): for f in os.listdir(actions_path):
meta['actions'][os.path.splitext(f)[0]] = f meta['actions'][os.path.splitext(f)[0]] = f
resource = Resource(name, meta, args, dest_path, tags=args.get('tags', [])) resource = Resource(name, meta, args, tags=tags)
signals.assign_connections(resource, connections) signals.assign_connections(resource, connections)
# save
shutil.copytree(base_path, dest_path)
resource.save() resource.save()
db.resource_add(name, resource)
return resource return resource
def load(dest_path): def wrap_resource(raw_resource):
meta_file = os.path.join(dest_path, 'meta.yaml') name = raw_resource['id']
meta = utils.load_file(meta_file) args = raw_resource['input']
name = meta['id'] tags = raw_resource.get('tags', [])
args = meta['input']
tags = meta.get('tags', [])
resource = Resource(name, meta, args, dest_path, tags=tags) return Resource(name, raw_resource, args, tags=tags)
db.resource_add(name, resource)
return resource
def load_all(dest_path): def load_all():
ret = {} ret = {}
for name in os.listdir(dest_path): for raw_resource in db.get_list('resource'):
resource_path = os.path.join(dest_path, name) resource = wrap_resource(raw_resource)
resource = load(resource_path)
ret[resource.name] = resource ret[resource.name] = resource
signals.Connections.reconnect_all() signals.Connections.reconnect_all()
@ -175,26 +161,28 @@ def load_all(dest_path):
return ret return ret
def assign_resources_to_nodes(resources, nodes, dst_dir): def assign_resources_to_nodes(resources, nodes):
for node in nodes: for node in nodes:
for resource in resources: for resource in resources:
merged = deepcopy(resource) res = deepcopy(resource)
# Node specific setting should override resource's res['tags'] = list(set(node.get('tags', [])) |
merged.update(deepcopy(node)) set(resource.get('tags', [])))
merged['tags'] = list(set(node.get('tags', [])) | resource_uuid = solar.utils.generate_uuid()
set(resource.get('tags', []))) # We should not generate here any uuid's, because
# a single node should be represented with a single
# resource
node_uuid = node['id']
create( node_resource_template = solar.utils.read_config()['node_resource_template']
format('{0}-{1}'.format(node['id'], resource['id'])), created_resource = create(resource_uuid, resource['dir_path'], res['input'], tags=res['tags'])
resource['dir_path'], created_node = create(node_uuid, node_resource_template, node, tags=node.get('tags', []))
dst_dir,
merged) signals.connect(created_node, created_resource)
def connect_resources(profile): def connect_resources(profile):
connections = profile.get('connections', []) connections = profile.get('connections', [])
resources = load_all('/vagrant/tmp/resource-instances/') graph = ResourcesConnectionGraph(connections, load_all().values())
graph = ResourcesConnectionGraph(connections, resources.values())
for connection in graph.iter_connections(): for connection in graph.iter_connections():
signals.connect(connection['from'], connection['to'], connection['mapping']) signals.connect(connection['from'], connection['to'], connection['mapping'])

View File

@ -4,9 +4,11 @@ import itertools
import networkx as nx import networkx as nx
import os import os
import db
from solar import utils from solar import utils
from solar.interfaces.db import get_db
db = get_db()
CLIENTS_CONFIG_KEY = 'clients-data-file' CLIENTS_CONFIG_KEY = 'clients-data-file'
@ -46,10 +48,10 @@ class Connections(object):
:return: :return:
""" """
for emitter_name, dest_dict in CLIENTS.items(): for emitter_name, dest_dict in CLIENTS.items():
emitter = db.get_resource(emitter_name) emitter = db.get_obj_resource(emitter_name)
for emitter_input, destinations in dest_dict.items(): for emitter_input, destinations in dest_dict.items():
for receiver_name, receiver_input in destinations: for receiver_name, receiver_input in destinations:
receiver = db.get_resource(receiver_name) receiver = db.get_obj_resource(receiver_name)
emitter.args[emitter_input].subscribe( emitter.args[emitter_input].subscribe(
receiver.args[receiver_input]) receiver.args[receiver_input])
@ -107,7 +109,7 @@ def connect(emitter, receiver, mapping=None):
def disconnect(emitter, receiver): def disconnect(emitter, receiver):
for src, destinations in CLIENTS[emitter.name].items(): for src, destinations in CLIENTS[emitter.name].items():
disconnect_by_src(emitter, src, receiver) disconnect_by_src(emitter.name, src, receiver)
for destination in destinations: for destination in destinations:
receiver_input = destination[1] receiver_input = destination[1]
@ -125,13 +127,13 @@ def disconnect_receiver_by_input(receiver, input):
""" """
for emitter_name, inputs in CLIENTS.items(): for emitter_name, inputs in CLIENTS.items():
emitter = db.get_resource(emitter_name) emitter = db.get_resource(emitter_name)
disconnect_by_src(emitter, input, receiver) disconnect_by_src(emitter['id'], input, receiver)
def disconnect_by_src(emitter, src, receiver): def disconnect_by_src(emitter_name, src, receiver):
if src in CLIENTS[emitter.name]: if src in CLIENTS[emitter_name]:
CLIENTS[emitter.name][src] = [ CLIENTS[emitter_name][src] = [
destination for destination in CLIENTS[emitter.name][src] destination for destination in CLIENTS[emitter_name][src]
if destination[0] != receiver.name if destination[0] != receiver.name
] ]
@ -143,7 +145,7 @@ def notify(source, key, value):
print 'Notify', source.name, key, value, CLIENTS[source.name] print 'Notify', source.name, key, value, CLIENTS[source.name]
if key in CLIENTS[source.name]: if key in CLIENTS[source.name]:
for client, r_key in CLIENTS[source.name][key]: for client, r_key in CLIENTS[source.name][key]:
resource = db.get_resource(client) resource = db.get_obj_resource(client)
print 'Resource found', client print 'Resource found', client
if resource: if resource:
resource.update({r_key: value}, emitter=source) resource.update({r_key: value}, emitter=source)

View File

@ -11,39 +11,26 @@ from solar import utils
from solar import errors from solar import errors
def get_files(path, pattern):
for root, dirs, files in os.walk(path):
for file_name in files:
if fnmatch(file_name, pattern):
yield os.path.join(root, file_name)
class FileSystemDB(DirDBM): class FileSystemDB(DirDBM):
RESOURCES_PATH = utils.read_config()['file-system-db']['resources-path']
STORAGE_PATH = utils.read_config()['file-system-db']['storage-path'] STORAGE_PATH = utils.read_config()['file-system-db']['storage-path']
RESOURCE_COLLECTION_NAME = 'resource'
def __init__(self): def __init__(self):
utils.create_dir(self.STORAGE_PATH) utils.create_dir(self.STORAGE_PATH)
super(FileSystemDB, self).__init__(self.STORAGE_PATH) super(FileSystemDB, self).__init__(self.STORAGE_PATH)
self.entities = {} self.entities = {}
def create_resource(self, resource, tags): def get_resource(self, uid):
self.from_files(self.RESOURCES_PATH) return self[self._make_key(self.RESOURCE_COLLECTION_NAME, uid)]
resource_uid = '{0}_{1}'.format(resource, '_'.join(tags)) def get_obj_resource(self, uid):
data = deepcopy(self.get(resource)) from solar.core.resource import wrap_resource
data['tags'] = tags raw_resource = self[self._make_key(self.RESOURCE_COLLECTION_NAME, uid)]
self[resource_uid] = data
def get_copy(self, key): return wrap_resource(raw_resource)
return deepcopy(self[key])
def add(self, obj): def add_resource(self, uid, resource):
if 'id' in obj: self[self._make_key(self.RESOURCE_COLLECTION_NAME, uid)] = resource
self.entities[obj['id']] = obj
def store_from_file(self, file_path):
self.store(file_path)
def store(self, collection, obj): def store(self, collection, obj):
if 'id' in obj: if 'id' in obj:
@ -72,20 +59,6 @@ class FileSystemDB(DirDBM):
def _make_key(self, collection, _id): def _make_key(self, collection, _id):
return '{0}-{1}'.format(collection, _id) return '{0}-{1}'.format(collection, _id)
def add_resource(self, resource):
if 'id' in resource:
self.entities[resource['id']] = resource
def get(self, resource_id):
return self.entities[resource_id]
def from_files(self, path):
for file_path in get_files(path, '*.yml'):
with open(file_path) as f:
entity = f
self.add_resource(entity)
def _readFile(self, path): def _readFile(self, path):
return yaml.load(super(FileSystemDB, self)._readFile(path)) return yaml.load(super(FileSystemDB, self)._readFile(path))

View File

@ -4,9 +4,11 @@ import tempfile
import unittest import unittest
import yaml import yaml
from solar.core import db
from solar.core import resource as xr from solar.core import resource as xr
from solar.core import signals as xs from solar.core import signals as xs
from solar.interfaces.db import get_db
db = get_db()
class BaseResourceTest(unittest.TestCase): class BaseResourceTest(unittest.TestCase):
@ -29,8 +31,4 @@ class BaseResourceTest(unittest.TestCase):
return path return path
def create_resource(self, name, src, args): def create_resource(self, name, src, args):
dst = os.path.join(self.storage_dir, 'rs', name) return xr.create(name, src, args)
os.makedirs(dst)
return xr.create(name, src, dst, args)

View File

@ -1,118 +0,0 @@
# x
## HAProxy deployment
```
cd /vagrant
python cli.py deploy haproxy_deployment/haproxy-deployment.yaml
```
or from Python shell:
```
from x import deployment
deployment.deploy('/vagrant/haproxy_deployment/haproxy-deployment.yaml')
```
## 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', 'ssh_user':'vagrant'})
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'], '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'], '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`
To test notifications:
```
keystone_db_data.args # displays node2 IP
node2.update({'ip': '10.0.0.5'})
keystone_db_data.args # updated IP
```
If you close the Python shell you can load the resources like this:
```
from x import resource
node1 = resource.load('rs/node1')
node2 = resource.load('rs/node2')
keystone_db_data = resource.load('rs/mariadn_keystone_data')
nova_db_data = resource.load('rs/mariadb_nova_data')
```
Connections are loaded automatically.
You can also load all resources at once:
```
from x import resource
all_resources = resource.load_all('rs')
```
## CLI
You can do the above from the command-line client:
```
cd /vagrant
python cli.py resource create node1 x/resources/ro_node/ rs/ '{"ip":"10.0.0.3", "ssh_key" : "/vagrant/tmp/keys/ssh_private", "ssh_user":"vagrant"}'
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"], "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"], "ip": "", "ssh_user": "", "ssh_key": ""}'
# View resources
python cli.py resource show rs/mariadb_keystone_data
# Show all resources at location rs/
python cli.py resource show rs/ --all
# Show resources with specific tag
python cli.py resources show rs/ --tag test
# Connect resources
python cli.py connect rs/node2 rs/mariadb_keystone_data
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
# Outputs graph to 'graph.png' file, please note that arrows don't have "normal" pointers, but just the line is thicker
# please see http://networkx.lanl.gov/_modules/networkx/drawing/nx_pylab.html
python cli.py connections graph
# Disconnect
python cli.py disconnect rs/mariadb_nova_data rs/node1
# Tag a resource:
python cli.py resource tag rs/node1 test-tag
# Remove tag
python cli.py resource tag rs/node1 test-tag --delete
```