Add 'create_inventory_context' command

The command 'create_inventory_context' can be used to dump all the
nodes from reclass inventory, they names from recalss.storage,
and any additional keys from nodes if needed, for example:

$ reclass-create-inventory-context \
    -d mcp11-ovs-dpdk.local \
    parameters.linux.network.interface \
    parameters.linux.storage
diff --git a/reclass_tools/cli.py b/reclass_tools/cli.py
index 48e3d9f..1bd80b7 100644
--- a/reclass_tools/cli.py
+++ b/reclass_tools/cli.py
@@ -105,6 +105,7 @@
                         help=('Show only the nodes which names are ended with the specified domain, for example:'
                               ' reclass-inventory-list -d example.local'))
 
+
     params = parser.parse_args(args)
 
     inventory = reclass_models.inventory_list(domain=params.domain)
@@ -127,5 +128,27 @@
     params = parser.parse_args(args)
 
     vcp_node_names = reclass_models.vcp_list(domain=params.domain)
-    print('\n'.join(sorted(vcp_node_names)))
+    print('\n'.join(sorted(('{0}.{1}'.format(name, domain) for name, domain in vcp_node_names))))
+
+
+def create_inventory_context(args=None):
+    try:
+        from reclass_tools import create_inventory
+    except ImportError:
+        print("Please run this tool on the salt-master node with installed 'reclass'")
+        return
+
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
+                                     description="Dumps nodes and specified node parameters from reclass, for example: create_inventory_context -d example.local parameters.linux.network.interface parameters.linux.storage")
+    parser.add_argument('--domain', '-d', dest='domain',
+                        help=('Show only the nodes which names are ended with the specified domain, for example:'
+                              ' reclass-inventory-list -d example.local'))
+    parser.add_argument('keys', help=(
+        'Reclass key names to dump with nodes'), nargs='*')
+
+    params = parser.parse_args(args)
+
+    current_underlay_context = create_inventory.create_inventory_context(domain=params.domain, keys=params.keys)
+
+    print(yaml.dump(current_underlay_context, default_flow_style=False))
 
diff --git a/reclass_tools/create_inventory.py b/reclass_tools/create_inventory.py
new file mode 100644
index 0000000..26ad89e
--- /dev/null
+++ b/reclass_tools/create_inventory.py
@@ -0,0 +1,153 @@
+import yaml
+import json
+
+from cookiecutter import __version__
+#from cookiecutter.log import configure_logger
+#from cookiecutter.main import cookiecutter
+
+from cookiecutter import generate
+from cookiecutter.exceptions import UndefinedVariableInTemplate
+
+from reclass_tools import helpers
+from reclass_tools import reclass_models
+from reclass_tools import walk_models
+
+
+def create_inventory_context(domain=None, keys=None):
+    """Dumps the current inventory per domain
+
+    Example of context:
+
+    <global_settings>: # only if required
+      ...
+    current_clusters:
+      <cluster_names>:
+        # here are cluster settings if required
+        nodes:
+          <node_names>:
+            name: ctl01
+            reclass_storage_name: openstack_control_node01
+            roles:
+            - vcp        # 'vcp' or None
+            parameters:  # specified keys to dump, for example
+                         # parameters.linux.network.interface below:
+              linux:
+                network:
+                  interfaces:
+                    ..
+    """
+    inventory = reclass_models.inventory_list(domain=domain)
+    vcp_list = reclass_models.vcp_list(domain=domain, inventory=inventory)
+    reclass_storage = reclass_models.reclass_storage(domain=domain, inventory=inventory)
+
+    current_underlay_context = {
+        'current_clusters': {
+        }
+    }
+
+    for domain, storage_nodes in reclass_storage.items():
+
+        current_cluster_nodes = {}
+        for storage_node_name, storage_node in storage_nodes.items():
+            inventory_node_name = "{0}.{1}".format(storage_node['name'], storage_node['domain'])
+            current_cluster_nodes[inventory_node_name] = {
+                'name': storage_node['name'],
+                'reclass_storage_name': storage_node_name,
+                'roles': list(),
+                'parameters': dict(),
+            }
+
+            if (storage_node['name'], storage_node['domain']) in vcp_list:
+                # Add role 'vcp' to mark the VM nodes.
+                current_cluster_nodes[inventory_node_name]['roles'].append('vcp')
+
+            if keys:
+                # Dump specified parameters for the node
+                # Will fail with KeyError if 'inventory_node_name' doesn't
+                # exists in reclass inventory
+                # (wasn't generated with reclass.storage yet, for example)
+                node = inventory[inventory_node_name]
+                for key in keys:
+                    key_path = key.split('.')
+                    reclass_key = helpers.get_nested_key(node, path=key_path)
+                    if reclass_key:
+                        helpers.create_nested_key(current_cluster_nodes[inventory_node_name], path=key_path, value=reclass_key)
+
+        current_underlay_context['current_clusters'][domain] = {
+            'nodes': current_cluster_nodes
+        }
+
+    return current_underlay_context
+
+
+    #1. Generate jinga interfaces / hw details based on node information provided to jinja
+
+    #2. Generate appropriate includes to reclass.storate model in config node
+    #configure_logger(
+    #    stream_level='DEBUG' if verbose else 'INFO',
+    #    debug_file=debug_file,
+    #)
+
+#current_clusters:
+#  <cluster_names>:
+#    nodes:
+#      <node_names>:
+#        name: ctl01
+#        reclass_storage_name: openstack_control_node01
+#        # if classes - then classes
+#        roles:
+#        - vcp  # to select wich interface type to use
+#        #- openstack_controller  # Don't forget to map the roles to corresponded classes if needed
+#        parameters: # there is just a DUMP of the existing model,
+#                    # which could be re-used complete or particulary for rendering new model
+#          linux:
+#            network:
+#              interfaces:
+#                ..
+
+
+def render_environment_class():
+    """Coockiecutter echancement to use several source JSON files
+
+    :param template_dir: directory with templates to render
+    :param output_dir: directory that should be created from templates
+    :param context_files: list of strings, paths to YAML or JSON files
+                          that provide the context variables for rendering.
+                          Merge of the files usind update() into a single
+                          dict is in the same order as files in the list.
+    """
+
+#ipdb> repo_dir
+#u'/root/cookiecutter-templates/cluster_product/openstack'
+#ipdb> context
+#{u'cookiecutter': {u'openstack_telemetry_node02_hostname': u'mdb02', ... }}
+#ipdb> overwrite_if_exists
+#False
+#ipdb> output_dir
+#'/root/my_new_deployment/'
+
+    repo_dir = '/root/cookiecutter-templates/cluster_product/openstack'
+    overwrite_if_exists = True
+    output_dir = '/root/my_new_deployment/'
+    context = {'cookiecutter': {'openstack_telemetry_node02_hostname': 'mdb02' }}
+
+    try:
+        generate.generate_files(
+            repo_dir=repo_dir,
+            context=context,
+            overwrite_if_exists=overwrite_if_exists,
+            output_dir=output_dir
+        )
+
+
+    except UndefinedVariableInTemplate as undefined_err:
+        print('>>> {}'.format(undefined_err.message))
+        print('>>> Error message: {}'.format(undefined_err.error.message))
+
+        context_str = yaml.dump(
+            undefined_err.context,
+            indent=4,
+            default_flow_style=False
+        )
+        print('='*15 + ' Context: '+ '='*15 + '\n{}'.format(context_str) + '='*40)
+        return
diff --git a/reclass_tools/helpers.py b/reclass_tools/helpers.py
index fcfc564..75e3185 100644
--- a/reclass_tools/helpers.py
+++ b/reclass_tools/helpers.py
@@ -11,6 +11,18 @@
     return data
 
 
+def create_nested_key(data, path=None, value=None):
+    if type(data) is not dict:
+        raise("Use 'dict' object for 'data'")
+    if type(path) is not list:
+        raise("Use 'list' object with key names for 'path'")
+    for key in path[:-1]:
+        if key not in data:
+            data[key] = {}
+        data = data[key]
+    data[path[-1]] = value
+
+
 def remove_nested_key(data, path=None):
     if type(path) is not list:
         raise("Use 'list' object with key names for 'path'")
diff --git a/reclass_tools/reclass_models.py b/reclass_tools/reclass_models.py
index 9f90fa7..7ebb1f3 100644
--- a/reclass_tools/reclass_models.py
+++ b/reclass_tools/reclass_models.py
@@ -43,14 +43,21 @@
     return inventory
 
 
-def vcp_list(domain=None):
+def get_nodeinfo(minion_id):
+    core = get_core()
+    return core.nodeinfo(minion_id)
+
+
+def vcp_list(domain=None, inventory=None):
     """List VCP node names
 
     Scan all nodes for the object salt.control.cluster.internal.node.XXX.name
+    Return set of tuples ((nodename1, domain), (nodename2, domain), ...)
     """
 
-    inventory = inventory_list(domain=domain)
+    inventory = inventory or inventory_list(domain=domain)
     vcp_path = 'parameters.salt.control.cluster.internal.node'.split('.')
+    domain_path = 'parameters._param.cluster_domain'.split('.')
 
     vcp_node_names = set()
 
@@ -58,7 +65,24 @@
         vcp_nodes = helpers.get_nested_key(node, path=vcp_path)
         if vcp_nodes is not None:
             for vcp_node_name, vcp_node in vcp_nodes.items():
-                vcp_node_names.add(vcp_node['name'])
+                vcp_node_names.add((vcp_node['name'], helpers.get_nested_key(node, path=domain_path)))
     return vcp_node_names
 
+def reclass_storage(domain=None, inventory=None):
+    """List VCP node names
 
+    Scan all nodes for the object salt.control.cluster.internal.node.XXX.name
+    """
+
+    inventory = inventory or inventory_list(domain=domain)
+    storage_path = 'parameters.reclass.storage.node'.split('.')
+
+    result = dict()
+    for node_name, node in inventory.items():
+        storage_nodes = helpers.get_nested_key(node, path=storage_path)
+        if storage_nodes is not None:
+            for storage_node_name, storage_node in storage_nodes.items():
+                if storage_node['domain'] not in result:
+                    result[storage_node['domain']] = dict()
+                result[storage_node['domain']][storage_node_name] = storage_node
+    return result