def get_app_runtime_from_app_config(cls, app_dir): """Checks the configuration file packaged with the given App Engine app to determine what language runtime should be used to deploy this app. Currently there are only four runtimes: python (Python 2.5), java (Java), go (Go), and python27 (Python 2.7) Args: app_dir: The directory on the local filesystem where the App Engine application can be found. Returns: A str indicating which runtime should be used to run this application. Raises: AppEngineConfigException: If there is no runtime set for this application. """ app_config_file = cls.get_config_file_from_dir(app_dir) if cls.FILE_IS_YAML.search(app_config_file): yaml_contents = yaml.safe_load(cls.read_file(app_config_file)) if 'runtime' in yaml_contents and yaml_contents['runtime'] in \ cls.ALLOWED_RUNTIMES: return yaml_contents['runtime'] elif 'runtime' in yaml_contents and yaml_contents['runtime'] in \ cls.DEPRECATED_RUNTIMES: raise AppEngineConfigException("This runtime is deprecated and no " + \ "longer supported.") else: raise AppEngineConfigException("No runtime set in your app.yaml") else: return 'java'
def get_app_id_from_app_config(cls, app_dir): """Checks the configuration file packages with the given App Engine app to determine what the user has set as this application's name. Args: app_dir: The directory on the local filesystem where the App Engine application can be found. Returns: A str indicating the application ID for this application. Raises: AppEngineConfigException: If there is no application ID set for this application. """ app_config_file = cls.get_config_file_from_dir(app_dir) if cls.FILE_IS_YAML.search(app_config_file): yaml_contents = yaml.safe_load(cls.read_file(app_config_file)) if 'application' in yaml_contents and yaml_contents['application'] != '': return yaml_contents['application'] else: raise AppEngineConfigException("No valid application ID found in " + "your app.yaml. " + cls.REGEX_MESSAGE) else: xml_contents = cls.read_file(app_config_file) app_id_matchdata = cls.JAVA_APP_ID_REGEX.search(xml_contents) if app_id_matchdata: return app_id_matchdata.group(1) else: raise AppEngineConfigException("No application ID found in " + "your appengine-web.xml. " + cls.REGEX_MESSAGE)
def validate_app_id(cls, app_id): """Checks the given app_id to make sure that it represents an app_id that we can run within AppScale. Args: app_id: A str that represents the application ID. Raises: AppEngineConfigException: If the given application ID is a reserved app_id, or does not represent an acceptable app_id. """ if app_id in cls.DISALLOWED_APP_IDS: raise AppEngineConfigException("{0} is a reserved appid".format(app_id)) if not cls.APP_ID_REGEX.match(app_id): raise AppEngineConfigException("Invalid application ID. You can only" + \ " use alphanumeric characters and/or '-'.")
def get_config_file_from_dir(cls, app_dir): """Finds the location of the app.yaml or appengine-web.xml file in the provided App Engine app. Args: app_dir: The directory on the local filesystem where the App Engine application can be found. Returns: A str containing the path to the configuration file on the local filesystem. Raises: AppEngineConfigException: If there is no configuration file for this application. """ if os.path.exists(cls.get_app_yaml_location(app_dir)): return cls.get_app_yaml_location(app_dir) elif os.path.exists(cls.get_appengine_web_xml_location(app_dir)): return cls.get_appengine_web_xml_location(app_dir) else: raise AppEngineConfigException("Couldn't find an app.yaml or " + "appengine-web.xml file in {0}".format(app_dir))
def upload_app(cls, options): """Uploads the given App Engine application into AppScale. Args: options: A Namespace that has fields for each parameter that can be passed in via the command-line interface. Returns: A tuple containing the host and port where the application is serving traffic from. """ if cls.TAR_GZ_REGEX.search(options.file): file_location = LocalState.extract_tgz_app_to_dir( options.file, options.verbose) created_dir = True elif cls.ZIP_REGEX.search(options.file): file_location = LocalState.extract_zip_app_to_dir( options.file, options.verbose) created_dir = True elif os.path.isdir(options.file): file_location = options.file created_dir = False else: raise AppEngineConfigException('{0} is not a tar.gz file, a zip file, ' \ 'or a directory. Please try uploading either a tar.gz file, a zip ' \ 'file, or a directory.'.format(options.file)) try: app_id = AppEngineHelper.get_app_id_from_app_config(file_location) except AppEngineConfigException as config_error: AppScaleLogger.log(config_error) if 'yaml' in str(config_error): raise config_error # Java App Engine users may have specified their war directory. In that # case, just move up one level, back to the app's directory. file_location = file_location + os.sep + ".." app_id = AppEngineHelper.get_app_id_from_app_config(file_location) app_language = AppEngineHelper.get_app_runtime_from_app_config( file_location) AppEngineHelper.validate_app_id(app_id) if app_language == 'java': if AppEngineHelper.is_sdk_mismatch(file_location): AppScaleLogger.warn( 'AppScale did not find the correct SDK jar ' + 'versions in your app. The current supported ' + 'SDK version is ' + AppEngineHelper.SUPPORTED_SDK_VERSION + '.') login_host = LocalState.get_login_host(options.keyname) secret_key = LocalState.get_secret_key(options.keyname) acc = AppControllerClient(login_host, secret_key) if options.test: username = LocalState.DEFAULT_USER elif options.email: username = options.email else: username = LocalState.get_username_from_stdin(is_admin=False) if not acc.does_user_exist(username): password = LocalState.get_password_from_stdin() RemoteHelper.create_user_accounts(username, password, login_host, options.keyname, clear_datastore=False) app_exists = acc.does_app_exist(app_id) app_admin = acc.get_app_admin(app_id) if app_admin is not None and username != app_admin: raise AppScaleException("The given user doesn't own this application" + \ ", so they can't upload an app with that application ID. Please " + \ "change the application ID and try again.") if app_exists: AppScaleLogger.log( "Uploading new version of app {0}".format(app_id)) else: AppScaleLogger.log( "Uploading initial version of app {0}".format(app_id)) acc.reserve_app_id(username, app_id, app_language) # Ignore all .pyc files while tarring. if app_language == 'python27': AppScaleLogger.log("Ignoring .pyc files") remote_file_path = RemoteHelper.copy_app_to_host( file_location, options.keyname, options.verbose) acc.done_uploading(app_id, remote_file_path) acc.update([app_id]) # now that we've told the AppController to start our app, find out what port # the app is running on and wait for it to start serving AppScaleLogger.log("Please wait for your app to start serving.") if app_exists: time.sleep(20) # give the AppController time to restart the app # Makes a call to the AppController to get all the stats and looks # through them for the http port the app can be reached on. sleep_time = 2 * cls.SLEEP_TIME current_app = None for i in range(cls.MAX_RETRIES): try: result = acc.get_all_stats() json_result = json.loads(result) apps_result = json_result['apps'] current_app = apps_result[app_id] http_port = current_app['http'] break except ValueError: pass except KeyError: pass AppScaleLogger.verbose("Waiting {0} second(s) for a port to be assigned to {1}".\ format(sleep_time, app_id), options.verbose) time.sleep(sleep_time) if not current_app: raise AppScaleException( "Unable to get the serving port for the application.") RemoteHelper.sleep_until_port_is_open(login_host, http_port, options.verbose) AppScaleLogger.success( "Your app can be reached at the following URL: " + "http://{0}:{1}".format(login_host, http_port)) if created_dir: shutil.rmtree(file_location) return (login_host, http_port)
def upload_app(cls, options): """Uploads the given App Engine application into AppScale. Args: options: A Namespace that has fields for each parameter that can be passed in via the command-line interface. Returns: A tuple containing the host and port where the application is serving traffic from. """ if cls.TAR_GZ_REGEX.search(options.file): file_location = LocalState.extract_tgz_app_to_dir( options.file, options.verbose) created_dir = True elif cls.ZIP_REGEX.search(options.file): file_location = LocalState.extract_zip_app_to_dir( options.file, options.verbose) created_dir = True elif os.path.isdir(options.file): file_location = options.file created_dir = False else: raise AppEngineConfigException('{0} is not a tar.gz file, a zip file, ' \ 'or a directory. Please try uploading either a tar.gz file, a zip ' \ 'file, or a directory.'.format(options.file)) try: app_id = AppEngineHelper.get_app_id_from_app_config(file_location) except AppEngineConfigException: # Java App Engine users may have specified their war directory. In that # case, just move up one level, back to the app's directory. file_location = file_location + os.sep + ".." app_id = AppEngineHelper.get_app_id_from_app_config(file_location) app_language = AppEngineHelper.get_app_runtime_from_app_config( file_location) AppEngineHelper.validate_app_id(app_id) if app_language == 'java': if AppEngineHelper.is_sdk_mismatch(file_location): AppScaleLogger.warn( 'AppScale did not find the correct SDK jar ' + 'versions in your app. The current supported ' + 'SDK version is ' + AppEngineHelper.SUPPORTED_SDK_VERSION + '.') acc = AppControllerClient(LocalState.get_login_host(options.keyname), LocalState.get_secret_key(options.keyname)) userappserver_host = acc.get_uaserver_host(options.verbose) userappclient = UserAppClient( userappserver_host, LocalState.get_secret_key(options.keyname)) if options.test: username = LocalState.DEFAULT_USER elif options.email: username = options.email else: username = LocalState.get_username_from_stdin(is_admin=False) if not userappclient.does_user_exist(username): password = LocalState.get_password_from_stdin() RemoteHelper.create_user_accounts(username, password, userappserver_host, options.keyname, clear_datastore=False) app_exists = userappclient.does_app_exist(app_id) app_admin = userappclient.get_app_admin(app_id) if app_admin is not None and username != app_admin: raise AppScaleException("The given user doesn't own this application" + \ ", so they can't upload an app with that application ID. Please " + \ "change the application ID and try again.") if app_exists: AppScaleLogger.log( "Uploading new version of app {0}".format(app_id)) else: AppScaleLogger.log( "Uploading initial version of app {0}".format(app_id)) userappclient.reserve_app_id(username, app_id, app_language) remote_file_path = RemoteHelper.copy_app_to_host( file_location, options.keyname, options.verbose) acc.done_uploading(app_id, remote_file_path) acc.update([app_id]) # now that we've told the AppController to start our app, find out what port # the app is running on and wait for it to start serving AppScaleLogger.log("Please wait for your app to start serving.") if app_exists: time.sleep(20) # give the AppController time to restart the app serving_host, serving_port = userappclient.get_serving_info( app_id, options.keyname) RemoteHelper.sleep_until_port_is_open(serving_host, serving_port, options.verbose) AppScaleLogger.success( "Your app can be reached at the following URL: " + "http://{0}:{1}".format(serving_host, serving_port)) if created_dir: shutil.rmtree(file_location) return (serving_host, serving_port)