Initial change to support heat-based environments

Moved the patch from the mcp/mcp-qa repo, ref #1170 to
not lose it after cleaning up.

1.Added envmanager_heat.py to create environment in OpenStack
  and use the created heat stack as the metadata source.
  Current conventions for heat stack metadata:
  - OS::Nova::Server must use 'metadata' property to specify list
    of the node roles, example:

    cfg01_node:
      type: OS::Nova::Server
      ...
      properties:
        ...
        metadata:
          roles:
          - salt_master

  - OS::Neutron::Subnet must use 'tags' property to specify the
    address pool name (L3 network roles), example:

    control_subnet:
      type: OS::Neutron::Subnet
      properties:
        ...
        tags:
        - private_pool01
2. Change underlay.yaml to use the user data file 'as is', without
   indents and jinja blocks. This will allow to use the same
   user data file for fuel-devops envs and heat stack envs.

3. Add an example microcloud-8116.env file with some defaults.
   For other stacks, another .env files can be created, with different
   access keys, networks, images, ...

Related-Bug: PROD-27687

Change-Id: Iaa9e97447bd1b41e5930a1ffbb7312945ba139f4
diff --git a/tcp_tests/utils/gen_test_config.py b/tcp_tests/utils/gen_test_config.py
new file mode 100755
index 0000000..17360ab
--- /dev/null
+++ b/tcp_tests/utils/gen_test_config.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import os
+import sys
+import copy
+import ConfigParser
+
+import json
+
+from itertools import chain
+from itertools import ifilter
+from collections import namedtuple
+from collections import OrderedDict
+from heatclient import client as heatclient
+from keystoneauth1.identity import V2Password
+from keystoneauth1.session import Session as KeystoneSession
+
+SshHost = namedtuple("SshHost",
+                     "roles node_name host login password keys")
+
+# host_tmpl = {
+#     "roles": ["salt_master"],
+#     "node_name": "cfg01.mk22-lab-dvr.local",
+#     "host": "172.16.10.100",
+#     "address_pool": "admin-pool01",
+#     "login": "root",
+#     "password": "r00tme"}
+
+CONFIG_TMPL = OrderedDict([
+    ('hardware', {
+        'manager': 'heat',
+        'current_snapshot': None
+    }),
+    ('underlay', {
+        'ssh': None,
+        'roles': None,
+    }),
+    ('salt', {
+        'salt_master_host': None
+    })
+])
+
+
+def fill_hosts(hosts, ssh_key=None):
+    ret = []
+    for h in hosts:
+
+        ret.append(
+            SshHost(
+                roles=h['roles'],
+                node_name=h['hostname'],
+                host=h['public_ip'],
+                login='ubuntu',
+                password='ubuntu',
+                keys=[ssh_key] if ssh_key else []))
+    return ret
+
+
+def get_heat():
+    keystone_auth = V2Password(
+        auth_url=os.environ['OS_AUTH_URL'],
+        username=os.environ['OS_USERNAME'],
+        password=os.environ['OS_PASSWORD'],
+        tenant_name=os.environ['OS_TENANT_NAME'])
+    session = KeystoneSession(auth=keystone_auth, verify=False)
+    endpoint_url = session.get_endpoint(
+        service_type='orchestration',
+        endpoint_type='publicURL')
+    heat = heatclient.Client(
+        version='1',
+        endpoint=endpoint_url,
+        token=session.get_token())
+    return heat
+
+
+def fill_config(hosts, env_name, last_snapshot):
+    ini = copy.deepcopy(CONFIG_TMPL)
+
+    ini['hardware']['current_snapshot'] = last_snapshot
+    ini['underlay']['ssh'] = json.dumps([h.__dict__ for h in hosts])
+    ini['underlay']['roles'] = json.dumps(
+        list(set(chain(*[h.roles for h in hosts]))))
+    ini['salt']['salt_master_host'] = next(h.host for h in hosts
+                                           if 'salt-master' in h.roles)
+
+    return ini
+
+
+def save_ini_config(ini, filename):
+    config = ConfigParser.ConfigParser()
+
+    for s in ini:
+        config.add_section(s)
+        for k, v in ini[s].items():
+            config.set(s, k, v)
+
+    with open(filename, 'w') as f:
+        config.write(f)
+
+
+def print_help():
+    text = """
+    Usage: {command} HEAT_STACK_NAME HEAT_SNAPHOT_NAME
+    """.format(command=sys.argv[0])
+    print(text)
+    sys.exit(1)
+
+
+def main():
+    if len(sys.argv) < 3:
+        print_help()
+
+    heat = get_heat()
+    env_name = sys.argv[1]
+    snapshot = sys.argv[2]
+    ssh_key = next(iter(sys.argv[3:]), None)
+    stack = heat.stacks.get(env_name)
+    hosts = next(ifilter(
+        lambda v: v['output_key'] == 'hosts', stack.outputs))['output_value']
+    hosts = list(chain(*hosts))
+    hosts = fill_hosts(hosts, ssh_key=ssh_key)
+    ini = fill_config(hosts, env_name, snapshot)
+    save_ini_config(ini, "{name}_{snapshot}.ini".format(name=env_name,
+                                                        snapshot=snapshot))
+
+
+if __name__ == '__main__':
+    main()