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)
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))