def start_worker(self, json_request): """ Starts taskqueue workers if they are not already running. A worker can be started on both a master and slave node. Args: json_request: A JSON string with the application id. Returns: A JSON string with the error status and error reason. """ request = self.__parse_json_and_validate_tags(json_request, self.SETUP_WORKERS_TAGS) logging.info("Start worker request: {0}".format(request)) if 'error' in request: return json.dumps(request) app_id = self.__cleanse(request['app_id']) hostname = appscale_info.get_private_ip() config = TaskQueueConfig(TaskQueueConfig.RABBITMQ, app_id) # Load the queue info. try: self.__queue_info_cache[app_id] = config.load_queues_from_file(app_id) config.create_celery_file(TaskQueueConfig.QUEUE_INFO_FILE) config.create_celery_worker_scripts(TaskQueueConfig.QUEUE_INFO_FILE) except ValueError, value_error: return json.dumps({"error": True, "reason": str(value_error)})
def create_java_start_cmd(app_name, port, load_balancer_host): """ Creates the start command to run the java application server. Args: app_name: The name of the application to run port: The local port the application server will bind to load_balancer_host: The host of the load balancer Returns: A string of the start command. """ db_location = DATASTORE_PATH # The Java AppServer needs the NGINX_PORT flag set so that it will read the # local FS and see what port it's running on. The value doesn't matter. cmd = ["cd " + constants.JAVA_APPSERVER + " &&", "./genKeystore.sh &&", "./appengine-java-sdk-repacked/bin/dev_appserver.sh", "--port=" + str(port), #this jvm flag allows javax.email to connect to the smtp server "--jvm_flag=-Dsocket.permit_connect=true", "--disable_update_check", "--address=" + appscale_info.get_private_ip(), "--datastore_path=" + db_location, "--login_server=" + load_balancer_host, "--appscale_version=1", "--APP_NAME=" + app_name, "--NGINX_ADDRESS=" + load_balancer_host, "--NGINX_PORT=anything", os.path.dirname(locate_dir("/var/apps/" + app_name +"/app/", \ "WEB-INF")) ] return ' '.join(cmd)
def add_routing(app, port): """ Tells the AppController to begin routing traffic to an AppServer. Args: app: A string that contains the application ID. port: A string that contains the port that the AppServer listens on. """ logging.info("Waiting for application {} on port {} to be active.". format(str(app), str(port))) if not wait_on_app(port): # In case the AppServer fails we let the AppController to detect it # and remove it if it still show in monit. logging.warning("AppServer did not come up in time, for {}:{}.". format(str(app), str(port))) return acc = appscale_info.get_appcontroller_client() appserver_ip = appscale_info.get_private_ip() while True: result = acc.add_routing_for_appserver(app, appserver_ip, port) if result == AppControllerClient.NOT_READY: logging.info('AppController not yet ready to add routing.') time.sleep(ROUTING_RETRY_INTERVAL) else: break logging.info('Successfully established routing for {} on port {}'. format(app, port))
def create_java_start_cmd(app_name, port, load_balancer_host, load_balancer_port, db_locations): """ Creates the start command to run the java application server. Args: app_name: The name of the application to run port: The local port the application server will bind to load_balancer_host: The host of the load balancer load_balancer_port: The port of the load balancer xmpp_ip: The IP of the XMPP service Returns: A string of the start command. """ db_location = choose_db_location(db_locations) cmd = ["cd " + constants.JAVA_APPSERVER + " &&", "./genKeystore.sh &&", "./appengine-java-sdk-repacked/bin/dev_appserver.sh", "--port=" + str(port), "--cookie_secret=" + appscale_info.get_secret(), "--address=" + appscale_info.get_private_ip(), "--datastore_path=" + db_location, "--login_server=" + load_balancer_host, "--appscale_version=1", "--NGINX_ADDRESS=" + load_balancer_host, "--NGINX_PORT=" + str(load_balancer_port), "/var/apps/" + app_name +"/app/war/", ] return ' '.join(cmd)
def wait_on_app(port): """ Waits for the application hosted on this machine, on the given port, to respond to HTTP requests. Args: port: Port where app is hosted on the local machine Returns: True on success, False otherwise """ retries = math.ceil(START_APP_TIMEOUT / BACKOFF_TIME) private_ip = appscale_info.get_private_ip() url = "http://" + private_ip + ":" + str(port) + FETCH_PATH while retries > 0: try: opener = urllib2.build_opener(NoRedirection) response = opener.open(url) if response.code != HTTP_OK: logging.warning('{} returned {}. Headers: {}'.format( url, response.code, response.headers.headers)) return True except IOError: retries -= 1 time.sleep(BACKOFF_TIME) logging.error('Application did not come up on {} after {} seconds'.format( url, START_APP_TIMEOUT)) return False
def wait_on_app(port): """ Waits for the application hosted on this machine, on the given port, to respond to HTTP requests. Args: port: Port where app is hosted on the local machine Returns: True on success, False otherwise """ backoff = INITIAL_BACKOFF_TIME retries = MAX_FETCH_ATTEMPTS private_ip = appscale_info.get_private_ip() url = "http://" + private_ip + ":" + str(port) + FETCH_PATH while retries > 0: try: urllib.urlopen(url) return True except IOError: retries -= 1 logging.warning("Application was not up at %s, retrying in %d seconds"%\ (url, backoff)) time.sleep(backoff) backoff *= 2 logging.error("Application did not come up on %s after %d attemps"%\ (url, MAX_FETCH_ATTEMPTS)) return False
def add_routing(app, port): """ Tells the AppController to begin routing traffic to an AppServer. Args: app: A string that contains the application ID. port: A string that contains the port that the AppServer listens on. """ logging.info("Waiting for application {} on port {} to be active.".format( str(app), str(port))) if not wait_on_app(port): # In case the AppServer fails we let the AppController to detect it # and remove it if it still show in monit. logging.warning("AppServer did not come up in time, for {}:{}.".format( str(app), str(port))) return acc = appscale_info.get_appcontroller_client() appserver_ip = appscale_info.get_private_ip() while True: result = acc.add_routing_for_appserver(app, appserver_ip, port) if result == AppControllerClient.NOT_READY: logging.info('AppController not yet ready to add routing.') time.sleep(ROUTING_RETRY_INTERVAL) else: break logging.info('Successfully established routing for {} on port {}'.format( app, port))
def wait_on_app(port): """ Waits for the application hosted on this machine, on the given port, to respond to HTTP requests. Args: port: Port where app is hosted on the local machine Returns: True on success, False otherwise """ retries = math.ceil(START_APP_TIMEOUT / BACKOFF_TIME) private_ip = appscale_info.get_private_ip() url = "http://" + private_ip + ":" + str(port) + FETCH_PATH while retries > 0: try: opener = urllib2.build_opener(NoRedirection) response = opener.open(url) if response.code != HTTP_OK: logging.warning('{} returned {}. Headers: {}'. format(url, response.code, response.headers.headers)) return True except IOError: retries -= 1 time.sleep(BACKOFF_TIME) logging.error('Application did not come up on {} after {} seconds'. format(url, START_APP_TIMEOUT)) return False
def create_python27_start_cmd(app_name, login_ip, port, load_balancer_host, xmpp_ip): """ Creates the start command to run the python application server. Args: app_name: The name of the application to run login_ip: The public IP port: The local port the application server will bind to load_balancer_host: The host of the load balancer xmpp_ip: The IP of the XMPP service Returns: A string of the start command. """ db_location = DATASTORE_PATH cmd = [ "/usr/bin/python2", constants.APPSCALE_HOME + "/AppServer/dev_appserver.py", "--port " + str(port), "--admin_port " + str(port + 10000), "--login_server " + login_ip, "--skip_sdk_update_check", "--nginx_host " + str(load_balancer_host), "--require_indexes", "--enable_sendmail", "--xmpp_path " + xmpp_ip, "--php_executable_path=" + str(PHP_CGI_LOCATION), "--uaserver_path " + db_location + ":" + str(constants.UA_SERVER_PORT), "--datastore_path " + db_location + ":" + str(constants.DB_SERVER_PORT), "/var/apps/" + app_name + "/app", "--host " + appscale_info.get_private_ip(), ] if app_name in TRUSTED_APPS: cmd.extend([TRUSTED_FLAG]) return " ".join(cmd)
def start_worker(self, json_request): """ Starts taskqueue workers if they are not already running. A worker can be started on both a master and slave node. Args: json_request: A JSON string with the application id. Returns: A JSON string with the error status and error reason. """ request = self.__parse_json_and_validate_tags(json_request, self.SETUP_WORKERS_TAGS) logging.info("Start worker request: {0}".format(request)) if 'error' in request: return json.dumps(request) app_id = self.__cleanse(request['app_id']) hostname = appscale_info.get_private_ip() config = TaskQueueConfig(TaskQueueConfig.RABBITMQ, app_id) # Load the queue info. try: self.__queue_info_cache[app_id] = config.load_queues_from_file( app_id) config.create_celery_file(TaskQueueConfig.QUEUE_INFO_FILE) config.create_celery_worker_scripts( TaskQueueConfig.QUEUE_INFO_FILE) except ValueError, value_error: return json.dumps({"error": True, "reason": str(value_error)})
def remove_routing(app, port): """ Tells the AppController to stop routing traffic to an AppServer. Args: app: A string that contains the application ID. port: A string that contains the port that the AppServer listens on. """ acc = appscale_info.get_appcontroller_client() appserver_ip = appscale_info.get_private_ip() acc.remove_appserver_from_haproxy(app, appserver_ip, port)
def create_python_start_cmd(app_name, login_ip, port, load_balancer_host, load_balancer_port, xmpp_ip, db_locations, py_version): """ Creates the start command to run the python application server. Args: app_name: The name of the application to run login_ip: The public IP port: The local port the application server will bind to load_balancer_host: The host of the load balancer load_balancer_port: The port of the load balancer xmpp_ip: The IP of the XMPP service py_version: The version of python to use Returns: A string of the start command. """ db_location = choose_db_location(db_locations) python = choose_python_executable(py_version) cmd = [python, constants.APPSCALE_HOME + "/AppServer/old_dev_appserver.py", "-p " + str(port), "--cookie_secret " + appscale_info.get_secret(), "--login_server " + login_ip, "--admin_console_server ''", "--enable_console", "--nginx_port " + str(load_balancer_port), "--nginx_host " + str(load_balancer_host), "--require_indexes", "--enable_sendmail", "--xmpp_path " + xmpp_ip, "--uaserver_path " + db_location + ":"\ + str(constants.UA_SERVER_PORT), "--datastore_path " + db_location + ":"\ + str(constants.DB_SERVER_PORT), "--history_path /var/apps/" + app_name\ + "/data/app.datastore.history", "/var/apps/" + app_name + "/app", "-a " + appscale_info.get_private_ip()] if app_name in TRUSTED_APPS: cmd.extend([TRUSTED_FLAG]) return ' '.join(cmd)
def create_python_start_cmd(app_name, login_ip, port, load_balancer_host, load_balancer_port, xmpp_ip, db_locations, py_version): """ Creates the start command to run the python application server. Args: app_name: The name of the application to run login_ip: The public IP port: The local port the application server will bind to load_balancer_host: The host of the load balancer load_balancer_port: The port of the load balancer xmpp_ip: The IP of the XMPP service py_version: The version of python to use Returns: A string of the start command. """ db_location = choose_db_location(db_locations) python = choose_python_executable(py_version) cmd = [python, constants.APPSCALE_HOME + "/AppServer/old_dev_appserver.py", "-p " + str(port), "--cookie_secret " + appscale_info.get_secret(), "--login_server " + login_ip, "--admin_console_server ''", "--enable_console", "--nginx_host " + str(load_balancer_host), "--require_indexes", "--enable_sendmail", "--xmpp_path " + xmpp_ip, "--uaserver_path " + db_location + ":"\ + str(constants.UA_SERVER_PORT), "--datastore_path " + db_location + ":"\ + str(constants.DB_SERVER_PORT), "--history_path /var/apps/" + app_name\ + "/data/app.datastore.history", "/var/apps/" + app_name + "/app", "-a " + appscale_info.get_private_ip()] if app_name in TRUSTED_APPS: cmd.extend([TRUSTED_FLAG]) return ' '.join(cmd)
def add_routing(app, port): """ Tells the AppController to begin routing traffic to an AppServer. Args: app: A string that contains the application ID. port: A string that contains the port that the AppServer listens on. """ acc = appscale_info.get_appcontroller_client() appserver_ip = appscale_info.get_private_ip() while True: result = acc.add_routing_for_appserver(app, appserver_ip, port) if result == NOT_READY: logging.info("AppController not yet ready to add routing.") time.sleep(ROUTING_RETRY_INTERVAL) else: break logging.info("Successfully established routing for {} on port {}".format(app, port))
def create_java_stop_cmd(port): """ This creates the stop command for an application which is uniquely identified by a port number. Additional portions of the start command are included to prevent the termination of other processes. Args: port: The port which the application server is running Returns: A string of the stop command. """ cmd = ["appengine-java-sdk-repacked/bin/dev_appserver.sh", "--port=" + str(port), "--address=" + appscale_info.get_private_ip(), "--cookie_secret=" + appscale_info.get_secret()] cmd = ' '.join(cmd) stop_cmd = "ps aux | grep '" + cmd + \ "' | grep -v grep | awk '{print $2'}' xargs -d '\n' kill -9" return stop_cmd
def add_routing(app, port): """ Tells the AppController to begin routing traffic to an AppServer. Args: app: A string that contains the application ID. port: A string that contains the port that the AppServer listens on. """ acc = appscale_info.get_appcontroller_client() appserver_ip = appscale_info.get_private_ip() while True: result = acc.add_routing_for_appserver(app, appserver_ip, port) if result == AppControllerClient.NOT_READY: logging.info('AppController not yet ready to add routing.') time.sleep(ROUTING_RETRY_INTERVAL) else: break logging.info('Successfully established routing for {} on port {}'.format( app, port))
def create_python27_start_cmd(app_name, login_ip, port, load_balancer_host, xmpp_ip): """ Creates the start command to run the python application server. Args: app_name: The name of the application to run login_ip: The public IP port: The local port the application server will bind to load_balancer_host: The host of the load balancer xmpp_ip: The IP of the XMPP service Returns: A string of the start command. """ db_location = DATASTORE_PATH cmd = [ "/usr/bin/python2", constants.APPSCALE_HOME + "/AppServer/dev_appserver.py", "--port " + str(port), "--admin_port " + str(port + 10000), "--login_server " + login_ip, "--skip_sdk_update_check", "--nginx_host " + str(load_balancer_host), "--require_indexes", "--enable_sendmail", "--xmpp_path " + xmpp_ip, "--php_executable_path=" + str(PHP_CGI_LOCATION), "--uaserver_path " + db_location + ":"\ + str(constants.UA_SERVER_PORT), "--datastore_path " + db_location + ":"\ + str(constants.DB_SERVER_PORT), "/var/apps/" + app_name + "/app", "--host " + appscale_info.get_private_ip(), "--automatic_restart", "no"] if app_name in TRUSTED_APPS: cmd.extend([TRUSTED_FLAG]) return ' '.join(cmd)
def create_java_start_cmd(app_name, port, load_balancer_host, max_heap): """ Creates the start command to run the java application server. Args: app_name: The name of the application to run port: The local port the application server will bind to load_balancer_host: The host of the load balancer max_heap: An integer specifying the max heap size in MB. Returns: A string of the start command. """ db_proxy = appscale_info.get_db_proxy() tq_proxy = appscale_info.get_tq_proxy() # The Java AppServer needs the NGINX_PORT flag set so that it will read the # local FS and see what port it's running on. The value doesn't matter. cmd = [ "cd " + constants.JAVA_APPSERVER + " &&", "./appengine-java-sdk-repacked/bin/dev_appserver.sh", "--port=" + str(port), #this jvm flag allows javax.email to connect to the smtp server "--jvm_flag=-Dsocket.permit_connect=true", '--jvm_flag=-Xmx{}m'.format(max_heap), '--jvm_flag=-Djava.security.egd=file:/dev/./urandom', "--disable_update_check", "--address=" + appscale_info.get_private_ip(), "--datastore_path=" + db_proxy, "--login_server=" + load_balancer_host, "--appscale_version=1", "--APP_NAME=" + app_name, "--NGINX_ADDRESS=" + load_balancer_host, "--NGINX_PORT=anything", "--TQ_PROXY=" + tq_proxy, os.path.dirname( locate_dir("/var/apps/" + app_name + "/app/", "WEB-INF")) ] return ' '.join(cmd)
return True def usage(): """ Prints usage of this program """ print "args: --help or -h for this menu" ################################ # MAIN ################################ if __name__ == "__main__": for args_index in range(1, len(sys.argv)): if sys.argv[args_index] in ("-h", "--help"): usage() sys.exit() INTERNAL_IP = appscale_info.get_private_ip() SERVER = SOAPpy.SOAPServer((INTERNAL_IP, constants.APP_MANAGER_PORT)) SERVER.registerFunction(start_app) SERVER.registerFunction(stop_app) SERVER.registerFunction(stop_app_instance) SERVER.registerFunction(restart_app_instances_for_app) file_io.set_logging_format() while 1: try: SERVER.serve_forever() except SSL.SSLError: pass
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 load_balancer_ip: Public ip of load balancer xmpp_ip: IP of XMPP service 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 == 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'] env_vars['GOPATH'] = '/var/lib/appscale/AppServer/gopath/' env_vars['GOROOT'] = '/var/lib/appscale/AppServer/goroot/' watch = "app___" + config['app_name'] 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['load_balancer_ip'], config['app_port'], config['load_balancer_ip'], config['xmpp_ip']) stop_cmd = create_python27_stop_cmd(config['app_port']) env_vars.update(create_python_app_env( config['load_balancer_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 start_cmd = create_java_start_cmd( config['app_name'], config['app_port'], config['load_balancer_ip']) 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( str(watch), str(start_cmd), str(stop_cmd), [config['app_port']], env_vars, config['max_memory'], syslog_server, appscale_info.get_private_ip()) if not monit_interface.start(watch): logging.error("Unable to start application server with monit") return BAD_PID if not wait_on_app(int(config['app_port'])): logging.error("Application server did not come up in time, " "removing monit watch") monit_interface.stop(watch) return BAD_PID 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
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 load_balancer_ip: Public ip of load balancer xmpp_ip: IP of XMPP service 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'] env_vars['GOPATH'] = '/root/appscale/AppServer/gopath/' env_vars['GOROOT'] = '/root/appscale/AppServer/goroot/' watch = "app___" + config['app_name'] 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['load_balancer_ip'], config['app_port'], config['load_balancer_ip'], config['xmpp_ip']) stop_cmd = create_python27_stop_cmd(config['app_port']) env_vars.update( create_python_app_env(config['load_balancer_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 start_cmd = create_java_start_cmd(config['app_name'], config['app_port'], config['load_balancer_ip']) 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(str(watch), str(start_cmd), str(stop_cmd), [config['app_port']], env_vars, config['max_memory'], syslog_server, appscale_info.get_private_ip()) if not monit_interface.start(watch): logging.error("Unable to start application server with monit") return BAD_PID if not wait_on_app(int(config['app_port'])): logging.error("Application server did not come up in time, " "removing monit watch") monit_interface.stop(watch) return BAD_PID 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
def usage(): """ Prints usage of this program """ print "args: --help or -h for this menu" ################################ # MAIN ################################ if __name__ == "__main__": for args_index in range(1, len(sys.argv)): if sys.argv[args_index] in ("-h", "--help"): usage() sys.exit() INTERNAL_IP = appscale_info.get_private_ip() SERVER = SOAPpy.SOAPServer((INTERNAL_IP, constants.APP_MANAGER_PORT)) SERVER.registerFunction(start_app) SERVER.registerFunction(stop_app) SERVER.registerFunction(stop_app_instance) SERVER.registerFunction(restart_app_instances_for_app) file_io.set_logging_format() while 1: try: SERVER.serve_forever() except SSL.SSLError: pass
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 load_balancer_ip: Public ip of load balancer xmpp_ip: IP of XMPP service 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'] env_vars['GOPATH'] = '/root/appscale/AppServer/gopath/' env_vars['GOROOT'] = '/root/appscale/AppServer/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['load_balancer_ip'], config['app_port'], config['load_balancer_ip'], config['xmpp_ip']) stop_cmd = create_python27_stop_cmd(config['app_port']) env_vars.update( create_python_app_env(config['load_balancer_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['load_balancer_ip'], max_heap) 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(str(watch), str(start_cmd), str(stop_cmd), [config['app_port']], env_vars, config['max_memory'], syslog_server, appscale_info.get_private_ip(), match_cmd=match_cmd) # 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
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 load_balancer_ip: Public ip of load balancer xmpp_ip: IP of XMPP service 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'] env_vars['GOPATH'] = '/root/appscale/AppServer/gopath/' env_vars['GOROOT'] = '/root/appscale/AppServer/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['load_balancer_ip'], config['app_port'], config['load_balancer_ip'], config['xmpp_ip']) stop_cmd = create_python27_stop_cmd(config['app_port']) env_vars.update(create_python_app_env( config['load_balancer_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['load_balancer_ip'], max_heap ) 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( str(watch), str(start_cmd), str(stop_cmd), [config['app_port']], env_vars, config['max_memory'], syslog_server, appscale_info.get_private_ip(), match_cmd=match_cmd) # 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