text: """Author: Tomasz Lichon
  Copyright (C) 2015 ACK CYFRONET AGH
  This software is released under the MIT license cited in 'LICENSE.txt'
  
  Brings up a set of oneprovider cm nodes. They can create separate clusters.
  """
  
  from __future__ import print_function
  
  import copy
  import json
  import os
  
  from . import common, docker, dns
  
  
  def cm_hostname(node_name, op_instance, uid):
      """Formats hostname for a docker hosting cluster_manager.
      NOTE: Hostnames are also used as docker names!
      """
      return common.format_hostname([node_name, op_instance], uid)
  
  
  def cm_erl_node_name(node_name, op_instance, uid):
      """Formats erlang node name for a vm on cluster_manager docker.
      """
      hostname = cm_hostname(node_name, op_instance, uid)
      return common.format_erl_node_name('cm', hostname)
  
  
  def _tweak_config(config, cm_node, op_instance, uid):
      cfg = copy.deepcopy(config)
      cfg['nodes'] = {'node': cfg['nodes'][cm_node]}
  
      sys_config = cfg['nodes']['node']['sys.config']['cluster_manager']
      sys_config['cm_nodes'] = [cm_erl_node_name(n, op_instance, uid)
                                 for n in sys_config['cm_nodes']]
  
      if 'vm.args' not in cfg['nodes']['node']:
          cfg['nodes']['node']['vm.args'] = {}
      vm_args = cfg['nodes']['node']['vm.args']
      vm_args['name'] = cm_erl_node_name(cm_node, op_instance, uid)
  
      return cfg
  
  
  def _node_up(image, bindir, config, dns_servers, logdir):
      node_name = config['nodes']['node']['vm.args']['name']
  
      (name, sep, hostname) = node_name.partition('@')
  
      command = \
          '''mkdir -p /root/bin/node/log/
  bindfs --create-for-user={uid} --create-for-group={gid} /root/bin/node/log /root/bin/node/log
  cat <<"EOF" > /tmp/gen_dev_args.json
  {gen_dev_args}
  EOF
  set -e
  escript bamboos/gen_dev/gen_dev.escript /tmp/gen_dev_args.json
  /root/bin/node/bin/cluster_manager console
  sleep 5'''  # Add sleep so logs can be chowned
      command = command.format(
          gen_dev_args=json.dumps({'cluster_manager': config}),
          uid=os.geteuid(),
          gid=os.getegid())
  
      bindir = os.path.abspath(bindir)
      volumes = ['/root/bin', (bindir, bindir, 'ro')]
  
      if logdir:
          logdir = os.path.join(os.path.abspath(logdir), hostname)
          os.makedirs(logdir)
          volumes.extend([(logdir, '/root/bin/node/log', 'rw')])
  
      container = docker.run(
          image=image,
          name=hostname,
          hostname=hostname,
          detach=True,
          interactive=True,
          tty=True,
          workdir=bindir,
          volumes=volumes,
          dns_list=dns_servers,
          privileged=True,
          command=command)
  
      return {
          'docker_ids': [container],
          'cluster_manager_nodes': [node_name]
      }
  
  
  def _ready(container):
      return True  # todo implement
  
  
  def up(image, bindir, dns_server, uid, config_path, logdir=None, domains_name='provider_domains'):
      config = common.parse_json_config_file(config_path)
      input_dir = config['dirs_config']['cluster_manager']['input_dir']
      dns_servers, output = dns.maybe_start(dns_server, uid)
  
      # CMs of every provider are started together
      for op_instance in config[domains_name]:
          gen_dev_cfg = {
              'config': {
                  'input_dir': input_dir,
                  'target_dir': '/root/bin'
              },
              'nodes': config[domains_name][op_instance]['cluster_manager']
          }
  
          tweaked_configs = [
              _tweak_config(gen_dev_cfg, cm_node, op_instance, uid)
              for cm_node in gen_dev_cfg['nodes']]
  
          cms = []
          for cfg in tweaked_configs:
              node_out = _node_up(image, bindir, cfg, dns_servers, logdir)
              cms.extend(node_out['docker_ids'])
              common.merge(output, node_out)
  
          common.wait_until(_ready, cms, 0)
  
      return output
  