diff --git a/config.yaml b/config.yaml index 6eae7d95..d52c879b 100644 --- a/config.yaml +++ b/config.yaml @@ -1,4 +1,4 @@ -clients-data-file: /vagrant/clients.json +clients-data-file: /vagrant/tmp/connections.yaml tmp: /vagrant/tmp @@ -7,9 +7,8 @@ examples-dir: /vagrant/examples extensions-dir: /vagrant/solar/solar/extensions file-system-db: - resources-path: ./schema/resources storage-path: /vagrant/tmp/storage template-dir: /vagrant/templates -resources-files-mask: /vagrant/x/resources/*/*.yaml -resource-instances-path: /vagrant/tmp/resource-instances +resources-files-mask: /vagrant/resources/*/*.yaml +node_resource_template: /vagrant/resources/ro_node/ diff --git a/example.py b/example.py index 25a29e19..67ffcad7 100644 --- a/example.py +++ b/example.py @@ -6,6 +6,10 @@ import time from solar.core import resource from solar.core import signals +from solar.interfaces.db import get_db + +db = get_db() +db.clear() signals.Connections.clear() @@ -13,23 +17,23 @@ if os.path.exists('rs'): shutil.rmtree('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'}) -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'}) +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/', {'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': ''}) -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_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':''}) +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/', {'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/', {'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_service1 = resource.create('keystone_service1', 'resources/keystone_service/', 'rs/', {'port':'5001', 'admin_port':'35357', 'image': '', 'ip':'', 'ssh_key':'', 'ssh_user':'', 'config_dir':''}) +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/', {'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_service2 = resource.create('keystone_service2', 'resources/keystone_service/', 'rs/', {'port':'5002', 'admin_port':'35357', 'image': '', 'ip':'', 'ssh_key':'', 'ssh_user':'', 'config_dir':''}) +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/', {'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_config = resource.create('haproxy_config', 'resources/haproxy', 'rs/', {'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_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', {'ip':'', 'ssh_key':'', 'ssh_user':'', 'configs_names':[], 'configs_ports':[], 'listen_ports':[], 'configs':[], 'config_dir': ''}) +haproxy_service = resource.create('haproxy_service', 'resources/docker_container/', {'image' : 'tutum/haproxy', 'ports': [], 'host_binds': [], 'volume_binds':[], 'ip':'', 'ssh_key':'', 'ssh_user':''}) #### diff --git a/examples/nodes_list.yaml b/examples/nodes_list.yaml index d25ecc4e..364ccea2 100644 --- a/examples/nodes_list.yaml +++ b/examples/nodes_list.yaml @@ -1,9 +1,9 @@ - id: node_1 ip: 10.0.0.2 ssh_user: vagrant - ssh_private_key_path: /vagrant/tmp/keys/ssh_private + ssh_key: /vagrant/tmp/keys/ssh_private - id: node_2 ip: 10.0.0.3 ssh_user: vagrant - ssh_private_key_path: /vagrant/tmp/keys/ssh_private + ssh_key: /vagrant/tmp/keys/ssh_private diff --git a/jenkins-config.yaml b/jenkins-config.yaml index c3df4ee4..e8c2adaf 100644 --- a/jenkins-config.yaml +++ b/jenkins-config.yaml @@ -1 +1 @@ -clients-data-file: /tmp/clients.json +clients-data-file: /tmp/connections.yaml diff --git a/requirements.txt b/requirements.txt index a963a8f2..a13f9914 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ networkx==1.9.1 PyYAML==3.11 jsonschema==2.4.0 requests==2.7.0 +mock diff --git a/run_tests.sh b/run_tests.sh index 6f3572f5..4f2760a1 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -4,6 +4,7 @@ set -e VENV=x-venv +WORKSPACE=${WORKSPACE:-"/vagrant"} CONFIG_FILE=$WORKSPACE/jenkins-config.yaml # Setup a proper path, I call my virtualenv dir "$VENV" and diff --git a/solar/solar/cli.py b/solar/solar/cli.py index 5b2adaf2..cff6c62c 100644 --- a/solar/solar/cli.py +++ b/solar/solar/cli.py @@ -107,12 +107,7 @@ class Cmd(object): lambda r: Expression(args.resources, r.get('tags', [])).evaluate(), self._get_resources_list()) - resource_instances_path = utils.read_config()['resource-instances-path'] - utils.create_dir(resource_instances_path) - assign_resources_to_nodes( - resources, - nodes, - resource_instances_path) + assign_resources_to_nodes(resources, nodes) def _get_resources_list(self): result = [] @@ -128,3 +123,7 @@ class Cmd(object): def main(): api = Cmd() api.parse(sys.argv[1:]) + + +if __name__ == '__main__': + main() diff --git a/solar/solar/core/db.py b/solar/solar/core/db.py deleted file mode 100644 index 4ffcc490..00000000 --- a/solar/solar/core/db.py +++ /dev/null @@ -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 = {} diff --git a/solar/solar/core/handlers/base.py b/solar/solar/core/handlers/base.py index 0572080f..f801a1ec 100644 --- a/solar/solar/core/handlers/base.py +++ b/solar/solar/core/handlers/base.py @@ -1,4 +1,4 @@ -# -*- coding: UTF-8 -*- +# -*- coding: utf-8 -*- import os import shutil import tempfile @@ -25,7 +25,7 @@ class BaseHandler(object): def _compile_action_file(self, resource, 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] dest_file = tempfile.mkstemp(text=True, prefix=action, dir=dir_path)[1] args = self._make_args(resource) @@ -43,7 +43,7 @@ class BaseHandler(object): def _make_args(self, resource): args = {'name': resource.name} - args['resource_dir'] = resource.base_dir + args['resource_dir'] = resource.metadata['actions_path'] args.update(resource.args) return args diff --git a/solar/solar/core/resource.py b/solar/solar/core/resource.py index 0369dffa..59941f07 100644 --- a/solar/solar/core/resource.py +++ b/solar/solar/core/resource.py @@ -8,23 +8,27 @@ from copy import deepcopy import yaml +import solar + from solar.core import actions -from solar.core import db from solar.core import observer from solar.core import signals from solar import utils from solar.core import validation from solar.core.connections import ResourcesConnectionGraph +from solar.interfaces.db import get_db + +db = get_db() 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.base_dir = base_dir self.metadata = metadata self.actions = metadata['actions'].keys() if metadata['actions'] else None self.args = {} + for arg_name, arg_value in args.items(): if not self.metadata['input'].get(arg_name): continue @@ -42,11 +46,10 @@ class Resource(object): def __repr__(self): return ("Resource(name='{0}', metadata={1}, args={2}, " - "base_dir='{3}', tags={4})").format(self.name, - json.dumps(self.metadata), - json.dumps(self.args_show()), - self.base_dir, - self.tags) + "tags={3})").format(self.name, + json.dumps(self.metadata), + json.dumps(self.args_show()), + self.tags) def args_show(self): def formatter(v): @@ -111,20 +114,13 @@ class Resource(object): for k, v in self.args_dict().items(): metadata['input'][k]['value'] = v - meta_file = os.path.join(self.base_dir, 'meta.yaml') - with open(meta_file, 'w') as f: - f.write(yaml.dump(metadata, default_flow_style=False)) + db.add_resource(self.name, metadata) -def create(name, base_path, dest_path, args, connections={}): +def create(name, base_path, args, tags=[], connections={}): if not os.path.exists(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') 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['version'] = '1.0.0' meta['actions'] = {} + meta['actions_path'] = actions_path if os.path.exists(actions_path): for f in os.listdir(actions_path): 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) - - # save - shutil.copytree(base_path, dest_path) resource.save() - db.resource_add(name, resource) return resource -def load(dest_path): - meta_file = os.path.join(dest_path, 'meta.yaml') - meta = utils.load_file(meta_file) - name = meta['id'] - args = meta['input'] - tags = meta.get('tags', []) +def wrap_resource(raw_resource): + name = raw_resource['id'] + args = raw_resource['input'] + tags = raw_resource.get('tags', []) - resource = Resource(name, meta, args, dest_path, tags=tags) - - db.resource_add(name, resource) - - return resource + return Resource(name, raw_resource, args, tags=tags) -def load_all(dest_path): +def load_all(): ret = {} - for name in os.listdir(dest_path): - resource_path = os.path.join(dest_path, name) - resource = load(resource_path) + for raw_resource in db.get_list('resource'): + resource = wrap_resource(raw_resource) ret[resource.name] = resource signals.Connections.reconnect_all() @@ -175,26 +161,28 @@ def load_all(dest_path): return ret -def assign_resources_to_nodes(resources, nodes, dst_dir): +def assign_resources_to_nodes(resources, nodes): for node in nodes: for resource in resources: - merged = deepcopy(resource) - # Node specific setting should override resource's - merged.update(deepcopy(node)) - merged['tags'] = list(set(node.get('tags', [])) | - set(resource.get('tags', []))) + res = deepcopy(resource) + res['tags'] = list(set(node.get('tags', [])) | + set(resource.get('tags', []))) + resource_uuid = solar.utils.generate_uuid() + # We should not generate here any uuid's, because + # a single node should be represented with a single + # resource + node_uuid = node['id'] - create( - format('{0}-{1}'.format(node['id'], resource['id'])), - resource['dir_path'], - dst_dir, - merged) + node_resource_template = solar.utils.read_config()['node_resource_template'] + created_resource = create(resource_uuid, resource['dir_path'], res['input'], tags=res['tags']) + created_node = create(node_uuid, node_resource_template, node, tags=node.get('tags', [])) + + signals.connect(created_node, created_resource) def connect_resources(profile): connections = profile.get('connections', []) - resources = load_all('/vagrant/tmp/resource-instances/') - graph = ResourcesConnectionGraph(connections, resources.values()) + graph = ResourcesConnectionGraph(connections, load_all().values()) for connection in graph.iter_connections(): signals.connect(connection['from'], connection['to'], connection['mapping']) diff --git a/solar/solar/core/signals.py b/solar/solar/core/signals.py index fc1a5c9d..79bff180 100644 --- a/solar/solar/core/signals.py +++ b/solar/solar/core/signals.py @@ -4,9 +4,11 @@ import itertools import networkx as nx import os -import db - from solar import utils +from solar.interfaces.db import get_db + +db = get_db() + CLIENTS_CONFIG_KEY = 'clients-data-file' @@ -46,10 +48,10 @@ class Connections(object): :return: """ 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 receiver_name, receiver_input in destinations: - receiver = db.get_resource(receiver_name) + receiver = db.get_obj_resource(receiver_name) emitter.args[emitter_input].subscribe( receiver.args[receiver_input]) @@ -107,7 +109,7 @@ def connect(emitter, receiver, mapping=None): def disconnect(emitter, receiver): 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: receiver_input = destination[1] @@ -125,13 +127,13 @@ def disconnect_receiver_by_input(receiver, input): """ for emitter_name, inputs in CLIENTS.items(): 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): - if src in CLIENTS[emitter.name]: - CLIENTS[emitter.name][src] = [ - destination for destination in CLIENTS[emitter.name][src] +def disconnect_by_src(emitter_name, src, receiver): + if src in CLIENTS[emitter_name]: + CLIENTS[emitter_name][src] = [ + destination for destination in CLIENTS[emitter_name][src] if destination[0] != receiver.name ] @@ -143,7 +145,7 @@ def notify(source, key, value): 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) + resource = db.get_obj_resource(client) print 'Resource found', client if resource: resource.update({r_key: value}, emitter=source) diff --git a/solar/solar/interfaces/db/file_system_db.py b/solar/solar/interfaces/db/file_system_db.py index da3ea043..950c0e46 100644 --- a/solar/solar/interfaces/db/file_system_db.py +++ b/solar/solar/interfaces/db/file_system_db.py @@ -11,39 +11,26 @@ from solar import utils 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): - RESOURCES_PATH = utils.read_config()['file-system-db']['resources-path'] STORAGE_PATH = utils.read_config()['file-system-db']['storage-path'] + RESOURCE_COLLECTION_NAME = 'resource' def __init__(self): utils.create_dir(self.STORAGE_PATH) super(FileSystemDB, self).__init__(self.STORAGE_PATH) self.entities = {} - def create_resource(self, resource, tags): - self.from_files(self.RESOURCES_PATH) + def get_resource(self, uid): + return self[self._make_key(self.RESOURCE_COLLECTION_NAME, uid)] - resource_uid = '{0}_{1}'.format(resource, '_'.join(tags)) - data = deepcopy(self.get(resource)) - data['tags'] = tags - self[resource_uid] = data + def get_obj_resource(self, uid): + from solar.core.resource import wrap_resource + raw_resource = self[self._make_key(self.RESOURCE_COLLECTION_NAME, uid)] - def get_copy(self, key): - return deepcopy(self[key]) + return wrap_resource(raw_resource) - def add(self, obj): - if 'id' in obj: - self.entities[obj['id']] = obj - - def store_from_file(self, file_path): - self.store(file_path) + def add_resource(self, uid, resource): + self[self._make_key(self.RESOURCE_COLLECTION_NAME, uid)] = resource def store(self, collection, obj): if 'id' in obj: @@ -72,20 +59,6 @@ class FileSystemDB(DirDBM): def _make_key(self, 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): return yaml.load(super(FileSystemDB, self)._readFile(path)) diff --git a/solar/solar/test/base.py b/solar/solar/test/base.py index 7dfcd82c..5bb526ef 100644 --- a/solar/solar/test/base.py +++ b/solar/solar/test/base.py @@ -4,9 +4,11 @@ import tempfile import unittest import yaml -from solar.core import db from solar.core import resource as xr from solar.core import signals as xs +from solar.interfaces.db import get_db + +db = get_db() class BaseResourceTest(unittest.TestCase): @@ -29,8 +31,4 @@ class BaseResourceTest(unittest.TestCase): return path def create_resource(self, name, src, args): - dst = os.path.join(self.storage_dir, 'rs', name) - os.makedirs(dst) - - return xr.create(name, src, dst, args) - + return xr.create(name, src, args) diff --git a/x-README.md b/x-README.md deleted file mode 100644 index 5f756ec7..00000000 --- a/x-README.md +++ /dev/null @@ -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 -```