from xml_marshaller import xml_marshaller
import os
import signal
import slapos.slap
import socket
import subprocess
import sys
import time

process_group_pid_list = []
process_pid_file_list = []
process_command_list = []
def sigterm_handler(signal, frame):
  for pgpid in process_group_pid_list:
    try:
      os.killpg(pgpid, signal.SIGTERM)
    except:
      pass
  for pid_file in process_pid_file_list:
    try:
      os.kill(int(open(pid_file).read().strip()), signal.SIGTERM)
    except:
      pass
  for p in process_command_list:
    try:
      subprocess.call(p)
    except:
      pass
  sys.exit(1)

signal.signal(signal.SIGTERM, sigterm_handler)

def run(args):
  config = args[0]
  for k,v in config['environment'].iteritems():
    os.environ[k] = v
  proxy = None
  slapgrid = None
  supervisord_pid_file = os.path.join(config['instance_root'], 'var', 'run',
        'supervisord.pid')
  if os.path.exists(config['proxy_database']):
    os.unlink(config['proxy_database'])
  try:
    proxy = subprocess.Popen([config['slapproxy_binary'],
      config['slapos_config']], close_fds=True, preexec_fn=os.setsid)
    process_group_pid_list.append(proxy.pid)
    slap = slapos.slap.slap()
    slap.initializeConnection(config['master_url'])
    while True:
      try:
        slap.registerSupply().supply(config['profile_url'],
          computer_guid=config['computer_id'])
      except socket.error:
        time.sleep(1)
        pass
      else:
        break
    while True:
      slapgrid = subprocess.Popen([config['slapgrid_software_binary'], '-vc',
        config['slapos_config']], close_fds=True, preexec_fn=os.setsid)
      process_group_pid_list.append(slapgrid.pid)
      slapgrid.wait()
      if slapgrid.returncode == 0:
        print 'Software installed properly'
        break
      print 'Problem with software installation, trying again'
      time.sleep(600)
    computer = slap.registerComputer(config['computer_id'])
    partition_reference = config['partition_reference']
    partition_path = os.path.join(config['instance_root'], partition_reference)
    if not os.path.exists(partition_path):
      os.mkdir(partition_path)
      os.chmod(partition_path, 0750)
    computer.updateConfiguration(xml_marshaller.dumps({
 'address': config['ipv4_address'],
 'instance_root': config['instance_root'],
 'netmask': '255.255.255.255',
 'partition_list': [{'address_list': [{'addr': config['ipv4_address'],
                                       'netmask': '255.255.255.255'},
                                      {'addr': config['ipv6_address'],
                                       'netmask': 'ffff:ffff:ffff::'},
                      ],
                     'path': partition_path,
                     'reference': partition_reference,
                     'tap': {'name': partition_reference},
                     }
                    ],
 'reference': config['computer_id'],
 'software_root': config['software_root']}))
    slap.registerOpenOrder().request(config['profile_url'],
        partition_reference='testing partition',
        partition_parameter_kw=config['instance_dict'])
    slapgrid = subprocess.Popen([config['slapgrid_partition_binary'], '-vc',
      config['slapos_config']], close_fds=True, preexec_fn=os.setsid)
    slapgrid.wait()
    if slapgrid.returncode != 0:
      raise ValueError('Slapgrid instance failed')
    runUnitTest = os.path.join(partition_path, 'bin', 'runUnitTest')
    if not os.path.exists(runUnitTest):
      raise ValueError('No %r provided' % runUnitTest)
  except:
    try:
      if os.path.exists(supervisord_pid_file):
        os.kill(int(open(supervisord_pid_file).read().strip()), signal.SIGTERM)
    except:
      pass
    raise
  finally:
    # Nice way to kill *everything* generated by run process -- process
    # groups working only in POSIX compilant systems
    # Exceptions are swallowed during cleanup phase
    if proxy is not None:
      os.killpg(proxy.pid, signal.SIGTERM)
    if os.path.exists(config['proxy_database']):
      os.unlink(config['proxy_database'])
    if slapgrid is not None and slapgrid.returncode is None:
      os.killpg(slapgrid.pid, signal.SIGTERM)
  try:
    bot_env = os.environ.copy()
    bot_env['PATH'] = ':'.join([config['bin_directory']] +
        bot_env['PATH'].split(':'))
    for l in config['bot_environment'].split():
      k, v = l.split('=')
      bot_env[k] = v
    if subprocess.call([config['buildbot_binary'], 'create-slave', '-f',
      config['working_directory'], config['buildbot_host'],
      config['slave_name'], config['slave_password']]) != 0:
      raise ValueError('Buildbot call failed')
    process_command_list.append([config['buildbot_binary'], 'stop',
      config['working_directory']])
    if os.path.exists(os.path.join(config['working_directory'],
      'buildbot.tac.new')):
      tac = os.path.join(config['working_directory'], 'buildbot.tac')
      if os.path.exists(tac):
        os.unlink(tac)
      os.rename(os.path.join(config['working_directory'],
      'buildbot.tac.new'), tac)
    if subprocess.call([config['buildbot_binary'], 'start',
      config['working_directory']], env=bot_env) != 0:
      raise ValueError('Issue during starting buildbot')
    while True:
      time.sleep(3600)
  finally:
    try:
      subprocess.call([config['buildbot_binary'], 'stop',
      config['working_directory']])
    except:
      pass
    try:
      if os.path.exists(supervisord_pid_file):
        os.kill(int(open(supervisord_pid_file).read().strip()), signal.SIGTERM)
    except:
      pass