run.py 6.12 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
# -*- coding: utf-8 -*-
# vim: set et sts=2:
# pylint: disable-msg=W0311,C0301,C0103,C0111,R0904,R0903

import ConfigParser
import datetime
import flask
import logging
import logging.handlers
import os
11
import urlparse
12 13 14
from slapos.htpasswd import HtpasswdFile
from slapos.runner.process import setHandler
import sys
15
from slapos.runner.utils import runInstanceWithLock, startProxy
16
from slapos.runner.views import *
17 18
from slapos.runner.gittools import cloneRepo, switchBranch
from git import GitCommandError
19
import time
20
import traceback
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135

TRUE_VALUES = (1, '1', True, 'true', 'True')

class Config:
  def __init__(self):
    self.configuration_file_path = None
    self.console = None
    self.log_file = None
    self.logger = None
    self.verbose = None

  def setConfig(self):
    """
    Set options given by parameters.
    """
    self.configuration_file_path = os.path.abspath(os.getenv('RUNNER_CONFIG'))

    # Load configuration file
    configuration_parser = ConfigParser.SafeConfigParser()
    configuration_parser.read(self.configuration_file_path)

    for section in ("slaprunner", "slapos", "slapproxy", "slapformat",
                    "sshkeys_authority", "gitclient"):
      configuration_dict = dict(configuration_parser.items(section))
      for key in configuration_dict:
        if not getattr(self, key, None):
          setattr(self, key, configuration_dict[key])

    # set up logging
    self.logger = logging.getLogger("slaprunner")
    self.logger.setLevel(logging.INFO)
    if self.console:
      self.logger.addHandler(logging.StreamHandler())

    self.log_file = self.log_dir + '/slaprunner.log'
    if not os.path.isdir(os.path.dirname(self.log_file)):
    # fallback to console only if directory for logs does not exists and
    # continue to run
      raise ValueError('Please create directory %r to store %r log file' % (
      os.path.dirname(self.log_file), self.log_file))
    else:
      file_handler = logging.FileHandler(self.log_file)
      file_handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
      self.logger.addHandler(file_handler)
      self.logger.info('Configured logging to file %r' % self.log_file)

    self.logger.info("Started.")
    self.logger.info(os.environ['PATH'])
    if self.verbose:
      self.logger.setLevel(logging.DEBUG)
      self.logger.debug("Verbose mode enabled.")


def checkHtpasswd(config):
  """XXX:set for backward compatiblity
  create a htpassword if etc/.users exist"""
  user = os.path.join(config['etc_dir'], '.users')
  htpasswdfile = os.path.join(config['etc_dir'], '.htpasswd')
  if os.path.exists(user) and not os.path.exists(htpasswdfile):
    data = open(user).read().strip().split(';')
    htpasswd = HtpasswdFile(htpasswdfile, create=True)
    htpasswd.update(data[0], data[1])
    htpasswd.save()
  else:
    return

def checkJSONConfig(config):
  """create a default json file with some parameters inside
  if the file has never been created"""
  json_file = os.path.join(config['etc_dir'], 'config.json')
  if not os.path.exists(json_file):
    params = {
      'run_instance' : True,
      'run_software' : True,
      'max_run_instance' : 3,
      'max_run_software' : 2
    }
    open(json_file, "w").write(json.dumps(params))


def run():
  "Run default configuration."
  # Parse arguments
  config = Config()
  config.setConfig()

  if os.getuid() == 0:
    # avoid mistakes (mainly in development mode)
    raise Exception('Do not run SlapRunner as root.')

  serve(config)

def serve(config):
  from werkzeug.contrib.fixers import ProxyFix
  workdir = os.path.join(config.runner_workdir, 'project')
  software_link = os.path.join(config.runner_workdir, 'softwareLink')
  app.config.update(**config.__dict__)
  app.config.update(
    software_log=config.software_root.rstrip('/') + '.log',
    instance_log=config.instance_root.rstrip('/') + '.log',
    workspace=workdir,
    software_link=software_link,
    instance_profile='instance.cfg',
    software_profile='software.cfg',
    SECRET_KEY=os.urandom(24),
    PERMANENT_SESSION_LIFETIME=datetime.timedelta(days=31),
  )
  checkHtpasswd(app.config)
  checkJSONConfig(app.config)
  if not os.path.exists(workdir):
    os.mkdir(workdir)
  if not os.path.exists(software_link):
    os.mkdir(software_link)
  setHandler()
  app.logger.addHandler(config.logger)
136 137 138 139 140 141 142 143 144 145 146 147 148 149
  repo_url = app.config['default_repository']
  branch_name = app.config.get('default_repository_branch', '')
  repo_name = os.path.basename(repo_url.replace('.git', ''))
  try:
    repository_path = os.path.join(workdir, repo_name)
    app.config.update(default_repository_path=repository_path)
    if len(os.listdir(workdir)) == 0 or not os.path.exists(repository_path):
      app.logger.info('cloning repository %s...' % repo_url)
      result = cloneRepo(repo_url, repository_path)
      if branch_name:
        switchBranch(repository_path, branch_name)
  except GitCommandError, e:
    app.logger.warning('Error while cloning default repository: %s' % str(e))
    traceback.print_exc()
150 151 152
  # Start slapproxy here when runner is starting
  app.logger.info('Stating slapproxy...')
  startProxy(app.config)
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
  app.logger.info('Running slapgrid...')
  if app.config['auto_deploy_instance'] in TRUE_VALUES:
    import thread
    # XXX-Nicolas: Hack to be sure that supervisord has started
    # before any communication with it, so that gunicorn doesn't exit
    thread.start_new_thread(waitForRun, (app.config,))
  config.logger.info('Done.')
  app.wsgi_app = ProxyFix(app.wsgi_app)


def waitForRun(config):
    time.sleep(3)
    runInstanceWithLock(config)


def getUpdatedParameter(self, var):
  configuration_parser = ConfigParser.SafeConfigParser()
  configuration_file_path = os.path.abspath(os.getenv('RUNNER_CONFIG'))
  configuration_parser.read(configuration_file_path)

  for section in configuration_parser.sections():
    if configuration_parser.has_option(section, var):
      return configuration_parser.get(section, var)
  # if the requested var is dependant of flask
  if var in self.keys():
    temp_dict = dict()
    temp_dict.update(self)
    return temp_dict[var]
  else:
    raise KeyError

184 185 186
if __name__ == 'slapos.runner.run':
  flask.config.Config.__getitem__ = getUpdatedParameter
  run()