Ejemplo n.º 1
0
 def test_create_config_file(self):
     flexmock(file_io).should_receive('write')
     monit_app_configuration.create_config_file('mywatch', 'start_cmd',
                                                'pidfile', 4000, {
                                                    'ENV1': 'VALUE1',
                                                    'ENV2': 'VALUE2'
                                                })
Ejemplo n.º 2
0
    def update_worker(self, queue_config):
        """ Updates a worker's configuration and restarts it.

    Args:
      queue_config: A JSON string specifying queue configuration.
    """
        self._write_worker_configuration(queue_config)
        status = yield self._wait_for_stable_state()

        # Start the worker if it doesn't exist. Restart it if it does.
        if status == MonitStates.MISSING:
            command = self.celery_command()
            env_vars = {
                'APP_ID': self.project_id,
                'HOST': options.load_balancers[0],
                'C_FORCE_ROOT': True
            }
            pidfile = os.path.join(PID_DIR,
                                   'celery-{}.pid'.format(self.project_id))
            create_config_file(self.monit_watch,
                               command,
                               pidfile,
                               env_vars=env_vars,
                               max_memory=CELERY_SAFE_MEMORY)
            logger.info('Starting push worker for {}'.format(self.project_id))
            yield self.monit_operator.reload()
        else:
            logger.info('Restarting push worker for {}'.format(
                self.project_id))
            yield self.monit_operator.send_command(self.monit_watch, 'restart')

        start_future = self.monit_operator.ensure_running(self.monit_watch)
        yield gen.with_timeout(timedelta(seconds=60), start_future,
                               IOLoop.current())
Ejemplo n.º 3
0
    def update_worker(self, queue_config):
        """ Updates a worker's configuration and restarts it.

    Args:
      queue_config: A JSON string specifying queue configuration.
    """
        self._write_worker_configuration(queue_config)
        status = yield self._wait_for_stable_state()

        pid_location = os.path.join(VAR_DIR,
                                    'celery-{}.pid'.format(self.project_id))
        try:
            with open(pid_location) as pidfile:
                old_pid = int(pidfile.read().strip())
        except IOError:
            old_pid = None

        # Start the worker if it doesn't exist. Restart it if it does.
        if status == MonitStates.MISSING:
            command = self.celery_command()
            env_vars = {
                'APP_ID': self.project_id,
                'HOST': options.load_balancers[0],
                'C_FORCE_ROOT': True
            }
            create_config_file(self.monit_watch,
                               command,
                               pid_location,
                               env_vars=env_vars,
                               max_memory=CELERY_SAFE_MEMORY)
            logger.info('Starting push worker for {}'.format(self.project_id))
            yield self.monit_operator.reload()
        else:
            logger.info('Restarting push worker for {}'.format(
                self.project_id))
            yield self.monit_operator.send_command(self.monit_watch, 'restart')

        start_future = self.monit_operator.ensure_running(self.monit_watch)
        yield gen.with_timeout(timedelta(seconds=60), start_future,
                               IOLoop.current())

        try:
            yield self.ensure_pid_changed(old_pid, pid_location)
        except AssertionError:
            # Occasionally, Monit will get interrupted during a restart. Retry the
            # restart if the Celery worker PID is the same.
            logger.warning(
                '{} worker PID did not change. Restarting it.'.format(
                    self.project_id))
            yield self.update_worker(queue_config)
Ejemplo n.º 4
0
 def test_create_config_file(self):
     flexmock(file_io)\
       .should_receive('write')\
       .and_return()
     temp_file = monit_app_configuration.create_config_file(
         "mywatch", "start_cmd", "stop_cmd", [1, 2, 3], {
             'ENV1': "VALUE1",
             'ENV2': "VALUE2"
         })
     self.assertIsNone(temp_file)
Ejemplo n.º 5
0
  def update_worker(self, queue_config):
    """ Updates a worker's configuration and restarts it.

    Args:
      queue_config: A JSON string specifying queue configuration.
    """
    self._write_worker_configuration(queue_config)
    status = yield self._wait_for_stable_state()

    pid_location = os.path.join(PID_DIR, 'celery-{}.pid'.format(self.project_id))
    try:
      with open(pid_location) as pidfile:
        old_pid = int(pidfile.read().strip())
    except IOError:
      old_pid = None

    # Start the worker if it doesn't exist. Restart it if it does.
    if status == MonitStates.MISSING:
      command = self.celery_command()
      env_vars = {'APP_ID': self.project_id, 'HOST': options.load_balancers[0],
                  'C_FORCE_ROOT': True}
      create_config_file(self.monit_watch, command, pid_location,
                         env_vars=env_vars, max_memory=CELERY_SAFE_MEMORY)
      logger.info('Starting push worker for {}'.format(self.project_id))
      yield self.monit_operator.reload()
    else:
      logger.info('Restarting push worker for {}'.format(self.project_id))
      yield self.monit_operator.send_command(self.monit_watch, 'restart')

    start_future = self.monit_operator.ensure_running(self.monit_watch)
    yield gen.with_timeout(timedelta(seconds=60), start_future,
                           IOLoop.current())

    try:
      yield self.ensure_pid_changed(old_pid, pid_location)
    except AssertionError:
      # Occasionally, Monit will get interrupted during a restart. Retry the
      # restart if the Celery worker PID is the same.
      logger.warning(
        '{} worker PID did not change. Restarting it.'.format(self.project_id))
      yield self.update_worker(queue_config)
Ejemplo n.º 6
0
def ensure_api_server(project_id):
    """ Make sure there is a running API server for a project.

  Args:
    project_id: A string specifying the project ID.
  Returns:
    An integer specifying the API server port.
  """
    global api_servers
    if project_id in api_servers:
        return api_servers[project_id]

    server_port = MAX_API_SERVER_PORT
    for port in api_servers.values():
        if port <= server_port:
            server_port = port - 1

    zk_locations = appscale_info.get_zk_node_ips()
    start_cmd = ' '.join([
        API_SERVER_LOCATION, '--port',
        str(server_port), '--project-id', project_id, '--zookeeper-locations',
        ' '.join(zk_locations)
    ])

    watch = ''.join([API_SERVER_PREFIX, project_id])
    full_watch = '-'.join([watch, str(server_port)])
    pidfile = os.path.join(PID_DIR, '{}.pid'.format(full_watch))
    monit_app_configuration.create_config_file(
        watch,
        start_cmd,
        pidfile,
        server_port,
        max_memory=DEFAULT_MAX_APPSERVER_MEMORY,
        check_port=True)

    assert monit_interface.start(
        full_watch,
        is_group=False), ('Monit was unable to start {}'.format(watch))

    api_servers[project_id] = server_port
    return server_port
Ejemplo n.º 7
0
def ensure_api_server(project_id):
    """ Make sure there is a running API server for a project.

  Args:
    project_id: A string specifying the project ID.
  Returns:
    An integer specifying the API server port.
  """
    global api_servers
    if project_id in api_servers:
        raise gen.Return(api_servers[project_id])

    server_port = MAX_API_SERVER_PORT
    for port in api_servers.values():
        if port <= server_port:
            server_port = port - 1

    zk_locations = appscale_info.get_zk_node_ips()
    start_cmd = ' '.join([
        API_SERVER_LOCATION, '--port',
        str(server_port), '--project-id', project_id, '--zookeeper-locations',
        ' '.join(zk_locations)
    ])

    watch = ''.join([API_SERVER_PREFIX, project_id])
    full_watch = '-'.join([watch, str(server_port)])
    pidfile = os.path.join(VAR_DIR, '{}.pid'.format(full_watch))
    monit_app_configuration.create_config_file(
        watch,
        start_cmd,
        pidfile,
        server_port,
        max_memory=DEFAULT_MAX_APPSERVER_MEMORY,
        check_port=True)

    monit_operator = MonitOperator()
    yield monit_operator.reload(thread_pool)
    yield monit_operator.send_command_retry_process(full_watch, 'start')

    api_servers[project_id] = server_port
    raise gen.Return(server_port)
Ejemplo n.º 8
0
def ensure_api_server(project_id):
  """ Make sure there is a running API server for a project.

  Args:
    project_id: A string specifying the project ID.
  Returns:
    An integer specifying the API server port.
  """
  global api_servers
  if project_id in api_servers:
    return api_servers[project_id]

  server_port = MAX_API_SERVER_PORT
  for port in api_servers.values():
    if port <= server_port:
      server_port = port - 1

  zk_locations = appscale_info.get_zk_node_ips()
  start_cmd = ' '.join([API_SERVER_LOCATION,
                        '--port', str(server_port),
                        '--project-id', project_id,
                        '--zookeeper-locations', ' '.join(zk_locations)])

  watch = ''.join([API_SERVER_PREFIX, project_id])
  full_watch = '-'.join([watch, str(server_port)])
  pidfile = os.path.join(PID_DIR, '{}.pid'.format(full_watch))
  monit_app_configuration.create_config_file(
    watch,
    start_cmd,
    pidfile,
    server_port,
    max_memory=DEFAULT_MAX_APPSERVER_MEMORY,
    check_port=True)

  assert monit_interface.start(full_watch, is_group=False), (
    'Monit was unable to start {}'.format(watch))

  api_servers[project_id] = server_port
  return server_port
Ejemplo n.º 9
0
  def _ensure_api_server(self, project_id):
    """ Make sure there is a running API server for a project.

    Args:
      project_id: A string specifying the project ID.
    Returns:
      An integer specifying the API server port.
    """
    if project_id in self._api_servers:
      raise gen.Return(self._api_servers[project_id])

    server_port = MAX_API_SERVER_PORT
    for port in self._api_servers.values():
      if port <= server_port:
        server_port = port - 1

    zk_locations = appscale_info.get_zk_node_ips()
    start_cmd = ' '.join([API_SERVER_LOCATION,
                          '--port', str(server_port),
                          '--project-id', project_id,
                          '--zookeeper-locations', ' '.join(zk_locations)])

    watch = ''.join([API_SERVER_PREFIX, project_id])
    full_watch = '-'.join([watch, str(server_port)])
    pidfile = os.path.join(VAR_DIR, '{}.pid'.format(full_watch))
    monit_app_configuration.create_config_file(
      watch,
      start_cmd,
      pidfile,
      server_port,
      max_memory=DEFAULT_MAX_APPSERVER_MEMORY,
      check_port=True)

    yield self._monit_operator.reload(self._thread_pool)
    yield self._monit_operator.send_command_retry_process(full_watch, 'start')

    self._api_servers[project_id] = server_port
    raise gen.Return(server_port)
Ejemplo n.º 10
0
def start_service(service_name):
  """ Creates a monit configuration file and prompts Monit to start service.
  Args:
    service_name: The name of the service to start.
  """
  logging.info("Starting " + service_name)
  watch_name = ""
  if service_name == datastore_upgrade.CASSANDRA_WATCH_NAME:
    cassandra_cmd = CASSANDRA_EXECUTABLE + " -p " + PID_FILE
    start_cmd = 'su -c "{0}" cassandra'.format(cassandra_cmd)
    stop_cmd = "/usr/bin/python2 " + APPSCALE_HOME + "/scripts/stop_service.py java cassandra"
    watch_name = datastore_upgrade.CASSANDRA_WATCH_NAME
    ports = [CASSANDRA_PORT]
    match_cmd = cassandra_interface.CASSANDRA_INSTALL_DIR

  if service_name == datastore_upgrade.ZK_WATCH_NAME:
    zk_server="zookeeper-server"
    command = 'service --status-all|grep zookeeper$'
    if subprocess.call(command, shell=True) == 0:
      zk_server = "zookeeper"

    start_cmd = "/usr/sbin/service " + zk_server + " start"
    stop_cmd = "/usr/sbin/service " + zk_server + " stop"
    watch_name = datastore_upgrade.ZK_WATCH_NAME
    match_cmd = "org.apache.zookeeper.server.quorum.QuorumPeerMain"
    ports = [zk.DEFAULT_PORT]

  monit_app_configuration.create_config_file(watch_name, start_cmd, stop_cmd,
    ports, upgrade_flag=True, match_cmd=match_cmd)

  if not monit_interface.start(watch_name):
    logging.error("Monit was unable to start " + service_name)
    return 1
  else:
    logging.info('Monit configured for {}'.format(service_name))
    return 0
 def test_create_config_file(self):
   flexmock(file_io).should_receive('write')
   monit_app_configuration.create_config_file(
     'mywatch', 'start_cmd', 'pidfile', 4000,
     {'ENV1': 'VALUE1', 'ENV2': 'VALUE2'})
Ejemplo n.º 12
0
  def _start_instance(self, version, port):
    """ Starts a Google App Engine application on this machine. It
        will start it up and then proceed to fetch the main page.

    Args:
      version: A Version object.
      port: An integer specifying a port to use.
    """
    version_details = version.version_details
    runtime = version_details['runtime']
    env_vars = version_details.get('envVariables', {})
    runtime_params = self._deployment_config.get_config('runtime_parameters')
    max_memory = runtime_params.get('default_max_appserver_memory',
                                    DEFAULT_MAX_APPSERVER_MEMORY)
    if 'instanceClass' in version_details:
      max_memory = INSTANCE_CLASSES.get(version_details['instanceClass'],
                                        max_memory)

    source_archive = version_details['deployment']['zip']['sourceUrl']

    api_server_port = yield self._ensure_api_server(version.project_id)
    yield self._source_manager.ensure_source(
      version.revision_key, source_archive, runtime)

    logger.info('Starting {}:{}'.format(version, port))

    pidfile = PIDFILE_TEMPLATE.format(revision=version.revision_key, port=port)

    if runtime == GO:
      env_vars['GOPATH'] = os.path.join(UNPACK_ROOT, version.revision_key,
                                        'gopath')
      env_vars['GOROOT'] = os.path.join(GO_SDK, 'goroot')

    watch = ''.join([MONIT_INSTANCE_PREFIX, version.revision_key])
    if runtime in (PYTHON27, GO, PHP):
      start_cmd = create_python27_start_cmd(
        version.project_id,
        self._login_server,
        port,
        pidfile,
        version.revision_key,
        api_server_port)
      env_vars.update(create_python_app_env(self._login_server,
                                            version.project_id))
    elif runtime == JAVA:
      # Account for MaxPermSize (~170MB), the parent process (~50MB), and thread
      # stacks (~20MB).
      max_heap = max_memory - 250
      if max_heap <= 0:
        raise BadConfigurationException(
          'Memory for Java applications must be greater than 250MB')

      start_cmd = create_java_start_cmd(
        version.project_id,
        port,
        self._login_server,
        max_heap,
        pidfile,
        version.revision_key,
        api_server_port
      )

      env_vars.update(create_java_app_env(self._deployment_config))
    else:
      raise BadConfigurationException(
        'Unknown runtime {} for {}'.format(runtime, version.project_id))

    logger.info("Start command: " + str(start_cmd))
    logger.info("Environment variables: " + str(env_vars))

    base_version = version.revision_key.rsplit(VERSION_PATH_SEPARATOR, 1)[0]
    log_tag = "app_{}".format(hashlib.sha1(base_version).hexdigest()[:28])

    monit_app_configuration.create_config_file(
      watch,
      start_cmd,
      pidfile,
      port,
      env_vars,
      max_memory,
      self._syslog_server,
      check_port=True,
      kill_exceeded_memory=True,
      log_tag=log_tag,
    )

    full_watch = '{}-{}'.format(watch, port)

    yield self._monit_operator.reload(self._thread_pool)

    # The reload command does not block, and we don't have a good way to check
    # if Monit is ready with its new configuration yet. If the daemon begins
    # reloading while it is handling the 'start', it can end up in a state
    # where it never starts the process. As a temporary workaround, this
    # small period allows it to finish reloading. This can be removed if
    # instances are started inside a cgroup.
    yield gen.sleep(1)
    yield self._monit_operator.send_command_retry_process(full_watch, 'start')

    # Make sure the version registration node exists.
    self._zk_client.ensure_path(
      '/'.join([VERSION_REGISTRATION_NODE, version.version_key]))

    instance = Instance(version.revision_key, port)
    yield self._add_routing(instance)

    if version.project_id == DASHBOARD_PROJECT_ID:
      log_size = DASHBOARD_LOG_SIZE
    else:
      log_size = APP_LOG_SIZE

    if not setup_logrotate(version.project_id, log_size):
      logger.error("Error while setting up log rotation for application: {}".
                    format(version.project_id))
Ejemplo n.º 13
0
    def _start_instance(self, version, port):
        """ Starts a Google App Engine application on this machine. It
        will start it up and then proceed to fetch the main page.

    Args:
      version: A Version object.
      port: An integer specifying a port to use.
    """
        version_details = version.version_details
        runtime = version_details['runtime']
        env_vars = version_details.get('envVariables', {})
        runtime_params = self._deployment_config.get_config(
            'runtime_parameters')
        max_memory = runtime_params.get('default_max_appserver_memory',
                                        DEFAULT_MAX_APPSERVER_MEMORY)
        if 'instanceClass' in version_details:
            max_memory = INSTANCE_CLASSES.get(version_details['instanceClass'],
                                              max_memory)

        source_archive = version_details['deployment']['zip']['sourceUrl']

        api_server_port = yield self._ensure_api_server(version.project_id)
        yield self._source_manager.ensure_source(version.revision_key,
                                                 source_archive, runtime)

        logger.info('Starting {}:{}'.format(version, port))

        pidfile = PIDFILE_TEMPLATE.format(revision=version.revision_key,
                                          port=port)

        if runtime == GO:
            env_vars['GOPATH'] = os.path.join(UNPACK_ROOT,
                                              version.revision_key, 'gopath')
            env_vars['GOROOT'] = os.path.join(GO_SDK, 'goroot')

        watch = ''.join([MONIT_INSTANCE_PREFIX, version.revision_key])
        if runtime in (PYTHON27, GO, PHP):
            start_cmd = create_python27_start_cmd(version.project_id,
                                                  self._login_server, port,
                                                  pidfile,
                                                  version.revision_key,
                                                  api_server_port)
            env_vars.update(
                create_python_app_env(self._login_server, version.project_id))
        elif runtime == JAVA:
            # Account for MaxPermSize (~170MB), the parent process (~50MB), and thread
            # stacks (~20MB).
            max_heap = max_memory - 250
            if max_heap <= 0:
                raise BadConfigurationException(
                    'Memory for Java applications must be greater than 250MB')

            start_cmd = create_java_start_cmd(version.project_id, port,
                                              self._login_server, max_heap,
                                              pidfile, version.revision_key,
                                              api_server_port)

            env_vars.update(create_java_app_env(self._deployment_config))
        else:
            raise BadConfigurationException('Unknown runtime {} for {}'.format(
                runtime, version.project_id))

        logger.info("Start command: " + str(start_cmd))
        logger.info("Environment variables: " + str(env_vars))

        monit_app_configuration.create_config_file(watch,
                                                   start_cmd,
                                                   pidfile,
                                                   port,
                                                   env_vars,
                                                   max_memory,
                                                   self._syslog_server,
                                                   check_port=True,
                                                   kill_exceeded_memory=True)

        full_watch = '{}-{}'.format(watch, port)

        yield self._monit_operator.reload(self._thread_pool)

        # The reload command does not block, and we don't have a good way to check
        # if Monit is ready with its new configuration yet. If the daemon begins
        # reloading while it is handling the 'start', it can end up in a state
        # where it never starts the process. As a temporary workaround, this
        # small period allows it to finish reloading. This can be removed if
        # instances are started inside a cgroup.
        yield gen.sleep(0.5)
        yield self._monit_operator.send_command_retry_process(
            full_watch, 'start')

        # Make sure the version registration node exists.
        self._zk_client.ensure_path('/'.join(
            [VERSION_REGISTRATION_NODE, version.version_key]))

        instance = Instance(version.revision_key, port)
        yield self._add_routing(instance)

        if version.project_id == DASHBOARD_PROJECT_ID:
            log_size = DASHBOARD_LOG_SIZE
        else:
            log_size = APP_LOG_SIZE

        if not setup_logrotate(version.project_id, log_size):
            logger.error(
                "Error while setting up log rotation for application: {}".
                format(version.project_id))
Ejemplo n.º 14
0
  def _ensure_api_server(self, project_id, runtime):
    """ Make sure there is a running API server for a project.

    Args:
      project_id: A string specifying the project ID.
      runtime: The runtime for the project
    Returns:
      An integer specifying the API server port.
    """
    ensure_app_server_api = runtime==JAVA8
    if project_id in self._api_servers:
      api_server_ports = self._api_servers[project_id]
      if not ensure_app_server_api:
        raise gen.Return(api_server_ports[0])
      elif len(api_server_ports) > 1:
          raise gen.Return(api_server_ports[1])

    server_port = MAX_API_SERVER_PORT
    for ports in self._api_servers.values():
      for port in ports:
        if port <= server_port:
          server_port = port - 1

    full_watch = None
    if not project_id in self._api_servers:
      watch = ''.join([API_SERVER_PREFIX, project_id])
      full_watch = '-'.join([watch, str(server_port)])
      pidfile = os.path.join(VAR_DIR, '{}.pid'.format(full_watch))
      zk_locations = appscale_info.get_zk_node_ips()
      start_cmd = ' '.join([API_SERVER_LOCATION,
                          '--port', str(server_port),
                          '--project-id', project_id,
                          '--zookeeper-locations', ' '.join(zk_locations)])
      monit_app_configuration.create_config_file(
        watch,
        start_cmd,
        pidfile,
        server_port,
        max_memory=DEFAULT_MAX_APPSERVER_MEMORY,
        check_port=True,
        check_host='127.0.0.1')
      api_server_port = server_port
    else:
      api_server_port = self._api_servers[project_id][0]

    full_watch_app = None
    if ensure_app_server_api:
      # Start an Python 27 runtime API server
      if api_server_port==server_port:
        server_port -= 1
      watch = ''.join([API_SERVER_PREFIX, '1_', project_id])
      full_watch_app = '-'.join([watch, str(server_port)])
      pidfile = os.path.join(VAR_DIR, '{}.pid'.format(full_watch_app))
      start_cmd = create_python_api_start_cmd(project_id,
                                              self._login_server,
                                              server_port,
                                              pidfile,
                                              api_server_port)
      monit_app_configuration.create_config_file(
        watch,
        start_cmd,
        pidfile,
        server_port,
        max_memory=DEFAULT_MAX_APPSERVER_MEMORY,
        check_port=True,
        check_host='127.0.0.1',
        group='api-server')
      self._api_servers[project_id] = [api_server_port, server_port]
    else:
      self._api_servers[project_id] = [server_port]

    yield self._monit_operator.reload(self._thread_pool)
    if full_watch:
      yield self._monit_operator.send_command_retry_process(full_watch, 'start')
    if full_watch_app:
      yield self._monit_operator.send_command_retry_process(full_watch_app, 'start')

    raise gen.Return(server_port)
Ejemplo n.º 15
0
def start_app(config):
    """ Starts a Google App Engine application on this machine. It
      will start it up and then proceed to fetch the main page.

  Args:
    config: a dictionary that contains
       app_name: Name of the application to start
       app_port: Port to start on
       language: What language the app is written in
       login_ip: Public ip of deployment
       env_vars: A dict of environment variables that should be passed to the
        app.
       max_memory: An int that names the maximum amount of memory that this
        App Engine app is allowed to consume before being restarted.
       syslog_server: The IP of the syslog server to send the application
         logs to. Usually it's the login private IP.
  Returns:
    PID of process on success, -1 otherwise
  """
    config = convert_config_from_json(config)
    if config is None:
        logging.error("Invalid configuration for application")
        return BAD_PID

    if not misc.is_app_name_valid(config['app_name']):
        logging.error("Invalid app name for application: " +
                      config['app_name'])
        return BAD_PID
    logging.info("Starting %s application %s" %
                 (config['language'], config['app_name']))

    env_vars = config['env_vars']
    pidfile = PIDFILE_TEMPLATE.format(project=config['app_name'],
                                      port=config['app_port'])

    if config['language'] == constants.GO:
        env_vars['GOPATH'] = os.path.join('/var', 'apps', config['app_name'],
                                          'gopath')
        env_vars['GOROOT'] = os.path.join(GO_SDK, 'goroot')

    watch = "app___" + config['app_name']
    match_cmd = ""

    if config['language'] == constants.PYTHON27 or \
        config['language'] == constants.GO or \
        config['language'] == constants.PHP:
        start_cmd = create_python27_start_cmd(config['app_name'],
                                              config['login_ip'],
                                              config['app_port'], pidfile)
        stop_cmd = create_python27_stop_cmd(config['app_port'])
        env_vars.update(
            create_python_app_env(config['login_ip'], config['app_name']))
    elif config['language'] == constants.JAVA:
        remove_conflicting_jars(config['app_name'])
        copy_successful = copy_modified_jars(config['app_name'])
        if not copy_successful:
            return BAD_PID

        # Account for MaxPermSize (~170MB), the parent process (~50MB), and thread
        # stacks (~20MB).
        max_heap = config['max_memory'] - 250
        if max_heap <= 0:
            return BAD_PID
        start_cmd = create_java_start_cmd(config['app_name'],
                                          config['app_port'],
                                          config['login_ip'], max_heap,
                                          pidfile)
        match_cmd = "java -ea -cp.*--port={}.*{}".format(
            str(config['app_port']),
            os.path.dirname(
                locate_dir("/var/apps/" + config['app_name'] + "/app/",
                           "WEB-INF")))

        stop_cmd = create_java_stop_cmd(config['app_port'])
        env_vars.update(create_java_app_env(config['app_name']))
    else:
        logging.error("Unknown application language %s for appname %s" \
          % (config['language'], config['app_name']))
        return BAD_PID

    logging.info("Start command: " + str(start_cmd))
    logging.info("Stop command: " + str(stop_cmd))
    logging.info("Environment variables: " + str(env_vars))

    # Set the syslog_server is specified.
    syslog_server = ""
    if 'syslog_server' in config:
        syslog_server = config['syslog_server']
    monit_app_configuration.create_config_file(watch,
                                               start_cmd,
                                               pidfile,
                                               config['app_port'],
                                               env_vars,
                                               config['max_memory'],
                                               syslog_server,
                                               check_port=True)

    # We want to tell monit to start the single process instead of the
    # group, since monit can get slow if there are quite a few processes in
    # the same group.
    full_watch = "{}-{}".format(str(watch), str(config['app_port']))
    if not monit_interface.start(full_watch, is_group=False):
        logging.warning("Monit was unable to start {}:{}".format(
            str(config['app_name']), config['app_port']))
        return BAD_PID

    # Since we are going to wait, possibly for a long time for the
    # application to be ready, we do it in a thread.
    threading.Thread(target=add_routing,
                     args=(config['app_name'], config['app_port'])).start()

    if 'log_size' in config.keys():
        log_size = config['log_size']
    else:
        if config['app_name'] == APPSCALE_DASHBOARD_ID:
            log_size = DASHBOARD_LOG_SIZE
        else:
            log_size = APP_LOG_SIZE

    if not setup_logrotate(config['app_name'], watch, log_size):
        logging.error(
            "Error while setting up log rotation for application: {}".format(
                config['app_name']))

    return 0
Ejemplo n.º 16
0
def start_app(version_key, config):
    """ Starts a Google App Engine application on this machine. It
      will start it up and then proceed to fetch the main page.

  Args:
    version_key: A string specifying a version key.
    config: a dictionary that contains
      app_port: An integer specifying the port to use.
      login_server: The server address the AppServer will use for login urls.
  """
    if 'app_port' not in config:
        raise BadConfigurationException('app_port is required')
    if 'login_server' not in config or not config['login_server']:
        raise BadConfigurationException('login_server is required')

    login_server = config['login_server']

    project_id, service_id, version_id = version_key.split(
        VERSION_PATH_SEPARATOR)

    if not misc.is_app_name_valid(project_id):
        raise BadConfigurationException(
            'Invalid project ID: {}'.format(project_id))

    try:
        service_manager = projects_manager[project_id][service_id]
        version_details = service_manager[version_id].version_details
    except KeyError:
        raise BadConfigurationException('Version not found')

    runtime = version_details['runtime']
    env_vars = version_details.get('envVariables', {})
    runtime_params = deployment_config.get_config('runtime_parameters')
    max_memory = runtime_params.get('default_max_appserver_memory',
                                    DEFAULT_MAX_APPSERVER_MEMORY)
    if 'instanceClass' in version_details:
        max_memory = INSTANCE_CLASSES.get(version_details['instanceClass'],
                                          max_memory)

    revision_key = VERSION_PATH_SEPARATOR.join(
        [project_id, service_id, version_id,
         str(version_details['revision'])])
    source_archive = version_details['deployment']['zip']['sourceUrl']

    api_server_port = yield ensure_api_server(project_id)
    yield source_manager.ensure_source(revision_key, source_archive, runtime)

    logging.info('Starting {} application {}'.format(runtime, project_id))

    pidfile = PIDFILE_TEMPLATE.format(revision=revision_key,
                                      port=config['app_port'])

    if runtime == constants.GO:
        env_vars['GOPATH'] = os.path.join(UNPACK_ROOT, revision_key, 'gopath')
        env_vars['GOROOT'] = os.path.join(GO_SDK, 'goroot')

    watch = ''.join([MONIT_INSTANCE_PREFIX, revision_key])
    if runtime in (constants.PYTHON27, constants.GO, constants.PHP):
        start_cmd = create_python27_start_cmd(project_id, login_server,
                                              config['app_port'], pidfile,
                                              revision_key, api_server_port)
        env_vars.update(create_python_app_env(login_server, project_id))
    elif runtime == constants.JAVA:
        # Account for MaxPermSize (~170MB), the parent process (~50MB), and thread
        # stacks (~20MB).
        max_heap = max_memory - 250
        if max_heap <= 0:
            raise BadConfigurationException(
                'Memory for Java applications must be greater than 250MB')

        start_cmd = create_java_start_cmd(project_id, config['app_port'],
                                          login_server, max_heap, pidfile,
                                          revision_key, api_server_port)

        env_vars.update(create_java_app_env(project_id))
    else:
        raise BadConfigurationException('Unknown runtime {} for {}'.format(
            runtime, project_id))

    logging.info("Start command: " + str(start_cmd))
    logging.info("Environment variables: " + str(env_vars))

    monit_app_configuration.create_config_file(watch,
                                               start_cmd,
                                               pidfile,
                                               config['app_port'],
                                               env_vars,
                                               max_memory,
                                               options.syslog_server,
                                               check_port=True,
                                               kill_exceeded_memory=True)

    full_watch = '{}-{}'.format(watch, config['app_port'])

    monit_operator = MonitOperator()
    yield monit_operator.reload(thread_pool)
    yield monit_operator.send_command_retry_process(full_watch, 'start')

    # Make sure the version node exists.
    zk_client.ensure_path('/'.join([VERSION_REGISTRATION_NODE, version_key]))

    # Since we are going to wait, possibly for a long time for the
    # application to be ready, we do it later.
    IOLoop.current().spawn_callback(add_routing,
                                    Instance(revision_key, config['app_port']))

    if project_id == DASHBOARD_PROJECT_ID:
        log_size = DASHBOARD_LOG_SIZE
    else:
        log_size = APP_LOG_SIZE

    if not setup_logrotate(project_id, log_size):
        logging.error(
            "Error while setting up log rotation for application: {}".format(
                project_id))
Ejemplo n.º 17
0
def start_app(version_key, config):
  """ Starts a Google App Engine application on this machine. It
      will start it up and then proceed to fetch the main page.

  Args:
    version_key: A string specifying a version key.
    config: a dictionary that contains
      app_port: An integer specifying the port to use.
      login_server: The server address the AppServer will use for login urls.
  """
  if 'app_port' not in config:
    raise BadConfigurationException('app_port is required')
  if 'login_server' not in config or not config['login_server']:
    raise BadConfigurationException('login_server is required')

  login_server = config['login_server']

  project_id, service_id, version_id = version_key.split(
    VERSION_PATH_SEPARATOR)

  if not misc.is_app_name_valid(project_id):
    raise BadConfigurationException(
      'Invalid project ID: {}'.format(project_id))

  try:
    service_manager = projects_manager[project_id][service_id]
    version_details = service_manager[version_id].version_details
  except KeyError:
    raise BadConfigurationException('Version not found')

  runtime = version_details['runtime']
  env_vars = version_details.get('envVariables', {})
  runtime_params = deployment_config.get_config('runtime_parameters')
  max_memory = runtime_params.get('default_max_appserver_memory',
                                  DEFAULT_MAX_APPSERVER_MEMORY)
  if 'instanceClass' in version_details:
    max_memory = INSTANCE_CLASSES.get(version_details['instanceClass'],
                                      max_memory)

  version_key = VERSION_PATH_SEPARATOR.join(
    [project_id, service_id, version_id])
  revision_key = VERSION_PATH_SEPARATOR.join(
    [project_id, service_id, version_id, str(version_details['revision'])])
  source_archive = version_details['deployment']['zip']['sourceUrl']

  api_server_port = ensure_api_server(project_id)
  yield source_manager.ensure_source(revision_key, source_archive, runtime)

  logging.info('Starting {} application {}'.format(runtime, project_id))

  pidfile = PIDFILE_TEMPLATE.format(revision=revision_key,
                                    port=config['app_port'])

  if runtime == constants.GO:
    env_vars['GOPATH'] = os.path.join(UNPACK_ROOT, revision_key, 'gopath')
    env_vars['GOROOT'] = os.path.join(GO_SDK, 'goroot')

  watch = ''.join([MONIT_INSTANCE_PREFIX, revision_key])
  if runtime in (constants.PYTHON27, constants.GO, constants.PHP):
    start_cmd = create_python27_start_cmd(
      project_id,
      login_server,
      config['app_port'],
      pidfile,
      revision_key,
      api_server_port)
    env_vars.update(create_python_app_env(
      login_server,
      project_id))
  elif runtime == constants.JAVA:
    # Account for MaxPermSize (~170MB), the parent process (~50MB), and thread
    # stacks (~20MB).
    max_heap = max_memory - 250
    if max_heap <= 0:
      raise BadConfigurationException(
        'Memory for Java applications must be greater than 250MB')

    start_cmd = create_java_start_cmd(
      project_id,
      config['app_port'],
      login_server,
      max_heap,
      pidfile,
      revision_key
    )

    env_vars.update(create_java_app_env(project_id))
  else:
    raise BadConfigurationException(
      'Unknown runtime {} for {}'.format(runtime, project_id))

  logging.info("Start command: " + str(start_cmd))
  logging.info("Environment variables: " + str(env_vars))

  monit_app_configuration.create_config_file(
    watch,
    start_cmd,
    pidfile,
    config['app_port'],
    env_vars,
    max_memory,
    options.syslog_server,
    check_port=True,
    kill_exceeded_memory=True)

  # We want to tell monit to start the single process instead of the
  # group, since monit can get slow if there are quite a few processes in
  # the same group.
  full_watch = '{}-{}'.format(watch, config['app_port'])
  assert monit_interface.start(full_watch, is_group=False), (
    'Monit was unable to start {}:{}'.format(project_id, config['app_port']))

  # Since we are going to wait, possibly for a long time for the
  # application to be ready, we do it in a thread.
  threading.Thread(target=add_routing,
    args=(version_key, config['app_port'])).start()

  if project_id == DASHBOARD_PROJECT_ID:
    log_size = DASHBOARD_LOG_SIZE
  else:
    log_size = APP_LOG_SIZE

  if not setup_logrotate(project_id, log_size):
    logging.error("Error while setting up log rotation for application: {}".
      format(project_id))
Ejemplo n.º 18
0
def start_app(version_key, config):
    """ Starts a Google App Engine application on this machine. It
      will start it up and then proceed to fetch the main page.

  Args:
    version_key: A string specifying a version key.
    config: a dictionary that contains
      app_port: An integer specifying the port to use.
  """
    if 'app_port' not in config:
        raise BadConfigurationException('app_port is required')

    project_id, service_id, version_id = version_key.split(
        VERSION_PATH_SEPARATOR)

    if not misc.is_app_name_valid(project_id):
        raise BadConfigurationException(
            'Invalid project ID: {}'.format(project_id))

    try:
        service_manager = projects_manager[project_id][service_id]
        version_details = service_manager[version_id].version_details
    except KeyError:
        raise BadConfigurationException('Version not found')

    runtime = version_details['runtime']
    env_vars = version_details.get('envVariables', {})
    runtime_params = deployment_config.get_config('runtime_parameters')
    max_memory = runtime_params.get('default_max_appserver_memory',
                                    DEFAULT_MAX_APPSERVER_MEMORY)
    if 'instanceClass' in version_details:
        max_memory = INSTANCE_CLASSES.get(version_details['instanceClass'],
                                          max_memory)

    version_key = VERSION_PATH_SEPARATOR.join(
        [project_id, service_id, version_id])
    revision_key = VERSION_PATH_SEPARATOR.join(
        [project_id, service_id, version_id,
         str(version_details['revision'])])
    source_archive = version_details['deployment']['zip']['sourceUrl']

    yield source_manager.ensure_source(revision_key, source_archive, runtime)

    logging.info('Starting {} application {}'.format(runtime, project_id))

    pidfile = PIDFILE_TEMPLATE.format(revision=revision_key,
                                      port=config['app_port'])

    if runtime == constants.GO:
        env_vars['GOPATH'] = os.path.join(UNPACK_ROOT, revision_key, 'gopath')
        env_vars['GOROOT'] = os.path.join(GO_SDK, 'goroot')

    watch = ''.join([MONIT_INSTANCE_PREFIX, revision_key])

    if runtime in (constants.PYTHON27, constants.GO, constants.PHP):
        start_cmd = create_python27_start_cmd(project_id, options.login_ip,
                                              config['app_port'], pidfile,
                                              revision_key)
        env_vars.update(create_python_app_env(options.login_ip, project_id))
    elif runtime == constants.JAVA:
        # Account for MaxPermSize (~170MB), the parent process (~50MB), and thread
        # stacks (~20MB).
        max_heap = max_memory - 250
        if max_heap <= 0:
            raise BadConfigurationException(
                'Memory for Java applications must be greater than 250MB')

        start_cmd = create_java_start_cmd(project_id, config['app_port'],
                                          options.login_ip, max_heap, pidfile,
                                          revision_key)

        env_vars.update(create_java_app_env(project_id))
    else:
        raise BadConfigurationException('Unknown runtime {} for {}'.format(
            runtime, project_id))

    logging.info("Start command: " + str(start_cmd))
    logging.info("Environment variables: " + str(env_vars))

    monit_app_configuration.create_config_file(watch,
                                               start_cmd,
                                               pidfile,
                                               config['app_port'],
                                               env_vars,
                                               max_memory,
                                               options.syslog_server,
                                               check_port=True)

    # We want to tell monit to start the single process instead of the
    # group, since monit can get slow if there are quite a few processes in
    # the same group.
    full_watch = '{}-{}'.format(watch, config['app_port'])
    assert monit_interface.start(
        full_watch, is_group=False), ('Monit was unable to start {}:{}'.format(
            project_id, config['app_port']))

    # Since we are going to wait, possibly for a long time for the
    # application to be ready, we do it in a thread.
    threading.Thread(target=add_routing,
                     args=(version_key, config['app_port'])).start()

    if project_id == DASHBOARD_PROJECT_ID:
        log_size = DASHBOARD_LOG_SIZE
    else:
        log_size = APP_LOG_SIZE

    if not setup_logrotate(project_id, log_size):
        logging.error(
            "Error while setting up log rotation for application: {}".format(
                project_id))