def wait_for_quorum(keyname, db_nodes, replication): """ Waits until enough Cassandra nodes are up for a quorum. Args: keyname: A string containing the deployment's keyname. db_nodes: An integer specifying the total number of DB nodes. replication: An integer specifying the keyspace replication factor. """ command = cassandra_interface.NODE_TOOL + " " + 'status' key_file = '{}/{}.key'.format(utils.KEY_DIRECTORY, keyname) ssh_cmd = [ 'ssh', '-i', key_file, appscale_info.get_db_master_ip(), command ] # Determine the number of nodes needed for a quorum. if db_nodes < 1 or replication < 1: raise dbconstants.AppScaleDBError( 'At least 1 database machine is needed.') if replication > db_nodes: raise dbconstants.AppScaleDBError( 'The replication factor cannot exceed the number of database machines.' ) can_fail = math.ceil(replication / 2.0 - 1) needed = int(db_nodes - can_fail) while True: output = subprocess.check_output(ssh_cmd) nodes_ready = len( [line for line in output.splitlines() if line.startswith('UN')]) logging.info('{} nodes are up. {} are needed.'.format( nodes_ready, needed)) if nodes_ready >= needed: break time.sleep(1)
def main(): """ Starts the AdminServer. """ logging.basicConfig(format=LOG_FORMAT, level=logging.INFO) parser = argparse.ArgumentParser() parser.add_argument('-p', '--port', type=int, default=constants.DEFAULT_PORT, help='The port to listen on') parser.add_argument('-v', '--verbose', action='store_true', help='Output debug-level logging') args = parser.parse_args() if args.verbose: logging.getLogger().setLevel(logging.DEBUG) options.define('secret', appscale_info.get_secret()) options.define('login_ip', appscale_info.get_login_ip()) options.define('private_ip', appscale_info.get_private_ip()) acc = appscale_info.get_appcontroller_client() ua_client = UAClient(appscale_info.get_db_master_ip(), options.secret) zk_client = KazooClient(hosts=','.join(appscale_info.get_zk_node_ips()), connection_retry=ZK_PERSISTENT_RECONNECTS) zk_client.start() version_update_lock = zk_client.Lock(constants.VERSION_UPDATE_LOCK_NODE) thread_pool = ThreadPoolExecutor(4) monit_operator = MonitOperator() all_resources = { 'acc': acc, 'ua_client': ua_client, 'zk_client': zk_client, 'version_update_lock': version_update_lock, 'thread_pool': thread_pool } if options.private_ip in appscale_info.get_taskqueue_nodes(): logging.info('Starting push worker manager') GlobalPushWorkerManager(zk_client, monit_operator) app = web.Application([ ('/v1/apps/([a-z0-9-]+)/services/([a-z0-9-]+)/versions', VersionsHandler, all_resources), ('/v1/apps/([a-z0-9-]+)/services/([a-z0-9-]+)/versions/([a-z0-9-]+)', VersionHandler, all_resources), ('/v1/apps/([a-z0-9-]+)/operations/([a-z0-9-]+)', OperationsHandler), ('/api/queue/update', UpdateQueuesHandler, { 'zk_client': zk_client }) ]) logging.info('Starting AdminServer') app.listen(args.port) io_loop = IOLoop.current() io_loop.start()
def deploy_apps(app_paths): """ Deploys all apps that reside in /opt/appscale/apps. Args: app_paths: A list of the full paths of the apps to be deployed. Returns: True on success, False otherwise. """ secret = appscale_info.get_secret() ua_client = UAClient(appscale_info.get_db_master_ip(), secret) acc = AppControllerClient(appscale_info.get_headnode_ip(), secret) # Wait for Cassandra to come up after a restore. time.sleep(15) for app_path in app_paths: # Extract app ID. app_id = app_path[app_path.rfind('/') + 1:app_path.find('.')] if not app_id: logging.error( "Malformed source code archive. Cannot complete " "application recovery for '{}'. Aborting...".format(app_path)) return False # Retrieve app admin via uaserver. app_data = ua_client.get_app_data(app_id) if 'owner' in app_data: app_admin = app_data['owner'] else: logging.error( "Missing application data. Cannot complete application " "recovery for '{}'. Aborting...".format(app_id)) return False file_suffix = re.search("\.(.*)\Z", app_path).group(1) logging.warning( "Restoring app '{}', from '{}', with owner '{}'.".format( app_id, app_path, app_admin)) acc.upload_app(app_path, file_suffix, app_admin) return True
def deploy(self): """ Uploads the sensor app for registered deployments. """ deployment_id = helper.get_deployment_id() # If deployment is not registered, then do nothing. if not deployment_id: return ua_client = UAClient(appscale_info.get_db_master_ip(), options.secret) # If the appscalesensor app is already running, then do nothing. version_node = '/appscale/projects/{}/services/{}/versions/{}'.format( constants.APPSCALE_SENSOR, DEFAULT_SERVICE, DEFAULT_VERSION) if self.zk_client.exists(version_node) is not None: return pwd = appscale_utils.encrypt_password( constants.USER_EMAIL, appscale_utils.random_password_generator()) if create_appscale_user(pwd, ua_client) and create_xmpp_user( pwd, ua_client): logging.debug( "Created new user and now tarring app to be deployed.") file_path = os.path.join(os.path.dirname(__file__), '../Apps/sensor') app_dir_location = os.path.join(constants.APP_DIR_LOCATION, constants.APPSCALE_SENSOR) archive = tarfile.open(app_dir_location, "w|gz") archive.add(file_path, arcname=constants.APPSCALE_SENSOR) archive.close() try: logging.info( "Deploying the sensor app for registered deployments.") acc = appscale_info.get_appcontroller_client() acc.upload_app(app_dir_location, constants.FILE_SUFFIX) except AppControllerException: logging.exception( "AppControllerException while trying to deploy " "appscalesensor app.") else: logging.error( "Error while creating or accessing the user to deploy " "appscalesensor app.")
def get_node_info(): """ Creates a list of JSON objects that contain node information and are needed to perform a backup/restore task on the current AppScale deployment. """ # TODO # Add logic for choosing minimal set of nodes that need to perform a task. # e.g. Only the node that owns the entire keyspace. nodes = [{ NodeInfoTags.HOST: get_br_service_url(appscale_info.get_db_master_ip()), NodeInfoTags.ROLE: 'db_master', NodeInfoTags.INDEX: None }] index = 0 for node in appscale_info.get_db_slave_ips(): host = get_br_service_url(node) # Make sure we don't send the same request on DB roles that reside on the # same node. if host not in nodes[0].values(): nodes.append({ NodeInfoTags.HOST: host, NodeInfoTags.ROLE: 'db_slave', NodeInfoTags.INDEX: index }) index += 1 index = 0 for node in appscale_info.get_zk_node_ips(): nodes.append({ NodeInfoTags.HOST: get_br_service_url(node), NodeInfoTags.ROLE: 'zk', NodeInfoTags.INDEX: index }) index += 1 return nodes
def deploy_sensor_app(): """ Uploads the sensor app for registered deployments. """ deployment_id = helper.get_deployment_id() #If deployment is not registered, then do nothing. if not deployment_id: return secret = appscale_info.get_secret() ua_client = UAClient(appscale_info.get_db_master_ip(), secret) # If the appscalesensor app is already running, then do nothing. if ua_client.is_app_enabled(hermes_constants.APPSCALE_SENSOR): return pwd = appscale_utils.encrypt_password( hermes_constants.USER_EMAIL, appscale_utils.random_password_generator()) if create_appscale_user(pwd, ua_client) and create_xmpp_user( pwd, ua_client): logging.debug("Created new user and now tarring app to be deployed.") file_path = os.path.join(os.path.dirname(__file__), '../Apps/sensor') app_dir_location = os.path.join(hermes_constants.APP_DIR_LOCATION, hermes_constants.APPSCALE_SENSOR) archive = tarfile.open(app_dir_location, "w|gz") archive.add(file_path, arcname=hermes_constants.APPSCALE_SENSOR) archive.close() try: logging.info( "Deploying the sensor app for registered deployments.") acc = appscale_info.get_appcontroller_client() acc.upload_app(app_dir_location, hermes_constants.FILE_SUFFIX, hermes_constants.USER_EMAIL) except AppControllerException: logging.exception("AppControllerException while trying to deploy " "appscalesensor app.") else: logging.error("Error while creating or accessing the user to deploy " "appscalesensor app.")
def get_node_info(): """ Creates a list of JSON objects that contain node information and are needed to perform a backup/restore task on the current AppScale deployment. """ # TODO # Add logic for choosing minimal set of nodes that need to perform a task. # e.g. Only the node that owns the entire keyspace. nodes = [{ NodeInfoTags.HOST: get_br_service_url(appscale_info.get_db_master_ip()), NodeInfoTags.ROLE: 'db_master', NodeInfoTags.INDEX: None }] index = 0 for node in appscale_info.get_db_slave_ips(): host = get_br_service_url(node) # Make sure we don't send the same request on DB roles that reside on the # same node. if host not in nodes[0].values(): nodes.append({ NodeInfoTags.HOST: host, NodeInfoTags.ROLE: 'db_slave', NodeInfoTags.INDEX: index }) index += 1 index = 0 for node in appscale_info.get_zk_node_ips(): nodes.append({ NodeInfoTags.HOST: get_br_service_url(node), NodeInfoTags.ROLE: 'zk', NodeInfoTags.INDEX: index }) index += 1 return nodes
def deploy(self): """ Uploads the sensor app for registered deployments. """ deployment_id = helper.get_deployment_id() # If deployment is not registered, then do nothing. if not deployment_id: return ua_client = UAClient(appscale_info.get_db_master_ip(), options.secret) # If the appscalesensor app is already running, then do nothing. version_node = '/appscale/projects/{}/services/{}/versions/{}'.format( constants.APPSCALE_SENSOR, DEFAULT_SERVICE, DEFAULT_VERSION) if self.zk_client.exists(version_node) is not None: return pwd = appscale_utils.encrypt_password(constants.USER_EMAIL, appscale_utils.random_password_generator()) if create_appscale_user(pwd, ua_client) and create_xmpp_user(pwd, ua_client): logging.debug("Created new user and now tarring app to be deployed.") file_path = os.path.join(os.path.dirname(__file__), '../Apps/sensor') app_dir_location = os.path.join(constants.APP_DIR_LOCATION, constants.APPSCALE_SENSOR) archive = tarfile.open(app_dir_location, "w|gz") archive.add(file_path, arcname=constants.APPSCALE_SENSOR) archive.close() try: logging.info("Deploying the sensor app for registered deployments.") acc = appscale_info.get_appcontroller_client() acc.upload_app(app_dir_location, constants.FILE_SUFFIX) except AppControllerException: logging.exception("AppControllerException while trying to deploy " "appscalesensor app.") else: logging.error("Error while creating or accessing the user to deploy " "appscalesensor app.")
""" This script dumps all users. """ from appscale.common import appscale_info from appscale.common.ua_client import UAClient if __name__ == "__main__": secret = appscale_info.get_secret() ua_client = UAClient(appscale_info.get_db_master_ip(), secret) for user in ua_client.get_all_users(): print(user)
def main(): """ Starts the AdminServer. """ logging.basicConfig(format=LOG_FORMAT, level=logging.INFO) parser = argparse.ArgumentParser( prog='appscale-admin', description='Manages AppScale-related processes') subparsers = parser.add_subparsers(dest='command') subparsers.required = True serve_parser = subparsers.add_parser( 'serve', description='Starts the server that manages AppScale processes') serve_parser.add_argument( '-p', '--port', type=int, default=constants.DEFAULT_PORT, help='The port to listen on') serve_parser.add_argument( '-v', '--verbose', action='store_true', help='Output debug-level logging') subparsers.add_parser( 'summary', description='Lists AppScale processes running on this machine') restart_parser = subparsers.add_parser( 'restart', description='Restart AppScale processes running on this machine') restart_parser.add_argument('service', nargs='+', help='The process or service ID to restart') args = parser.parse_args() if args.command == 'summary': table = sorted(list(get_combined_services().items())) print(tabulate(table, headers=['Service', 'State'])) sys.exit(0) if args.command == 'restart': socket_path = urlquote(ServiceManagerHandler.SOCKET_PATH, safe='') session = requests_unixsocket.Session() response = session.post( 'http+unix://{}/'.format(socket_path), data={'command': 'restart', 'arg': [args.service]}) response.raise_for_status() return if args.verbose: logger.setLevel(logging.DEBUG) options.define('secret', appscale_info.get_secret()) options.define('login_ip', appscale_info.get_login_ip()) options.define('private_ip', appscale_info.get_private_ip()) options.define('load_balancers', appscale_info.get_load_balancer_ips()) acc = appscale_info.get_appcontroller_client() ua_client = UAClient(appscale_info.get_db_master_ip(), options.secret) zk_client = KazooClient( hosts=','.join(appscale_info.get_zk_node_ips()), connection_retry=ZK_PERSISTENT_RECONNECTS) zk_client.start() version_update_lock = zk_client.Lock(constants.VERSION_UPDATE_LOCK_NODE) thread_pool = ThreadPoolExecutor(4) monit_operator = MonitOperator() all_resources = { 'acc': acc, 'ua_client': ua_client, 'zk_client': zk_client, 'version_update_lock': version_update_lock, 'thread_pool': thread_pool } if options.private_ip in appscale_info.get_taskqueue_nodes(): logger.info('Starting push worker manager') GlobalPushWorkerManager(zk_client, monit_operator) service_manager = ServiceManager(zk_client) service_manager.start() app = web.Application([ ('/oauth/token', OAuthHandler, {'ua_client': ua_client}), ('/v1/apps/([a-z0-9-]+)/services/([a-z0-9-]+)/versions', VersionsHandler, {'ua_client': ua_client, 'zk_client': zk_client, 'version_update_lock': version_update_lock, 'thread_pool': thread_pool}), ('/v1/projects', ProjectsHandler, all_resources), ('/v1/projects/([a-z0-9-]+)', ProjectHandler, all_resources), ('/v1/apps/([a-z0-9-]+)/services/([a-z0-9-]+)', ServiceHandler, all_resources), ('/v1/apps/([a-z0-9-]+)/services/([a-z0-9-]+)/versions/([a-z0-9-]+)', VersionHandler, all_resources), ('/v1/apps/([a-z0-9-]+)/operations/([a-z0-9-]+)', OperationsHandler, {'ua_client': ua_client}), ('/api/cron/update', UpdateCronHandler, {'acc': acc, 'zk_client': zk_client, 'ua_client': ua_client}), ('/api/datastore/index/add', UpdateIndexesHandler, {'zk_client': zk_client, 'ua_client': ua_client}), ('/api/queue/update', UpdateQueuesHandler, {'zk_client': zk_client, 'ua_client': ua_client}) ]) logger.info('Starting AdminServer') app.listen(args.port) management_app = web.Application([ ('/', ServiceManagerHandler, {'service_manager': service_manager})]) management_server = HTTPServer(management_app) management_socket = bind_unix_socket(ServiceManagerHandler.SOCKET_PATH) management_server.add_socket(management_socket) io_loop = IOLoop.current() io_loop.start()
""" This script dumps all users. """ from appscale.common import appscale_info from appscale.common.ua_client import UAClient if __name__ == "__main__": secret = appscale_info.get_secret() ua_client = UAClient(appscale_info.get_db_master_ip(), secret) for user in ua_client.get_all_users(): print(user)
def main(): """ Starts the AdminServer. """ logging.basicConfig(format=LOG_FORMAT, level=logging.INFO) parser = argparse.ArgumentParser( prog='appscale-admin', description='Manages AppScale-related processes') subparsers = parser.add_subparsers(dest='command') subparsers.required = True serve_parser = subparsers.add_parser( 'serve', description='Starts the server that manages AppScale processes') serve_parser.add_argument( '-p', '--port', type=int, default=constants.DEFAULT_PORT, help='The port to listen on') serve_parser.add_argument( '-v', '--verbose', action='store_true', help='Output debug-level logging') subparsers.add_parser( 'summary', description='Lists AppScale processes running on this machine') args = parser.parse_args() if args.command == 'summary': table = sorted(list(get_combined_services().items())) print(tabulate(table, headers=['Service', 'State'])) sys.exit(0) if args.verbose: logger.setLevel(logging.DEBUG) options.define('secret', appscale_info.get_secret()) options.define('login_ip', appscale_info.get_login_ip()) options.define('private_ip', appscale_info.get_private_ip()) options.define('load_balancers', appscale_info.get_load_balancer_ips()) acc = appscale_info.get_appcontroller_client() ua_client = UAClient(appscale_info.get_db_master_ip(), options.secret) zk_client = KazooClient( hosts=','.join(appscale_info.get_zk_node_ips()), connection_retry=ZK_PERSISTENT_RECONNECTS) zk_client.start() version_update_lock = zk_client.Lock(constants.VERSION_UPDATE_LOCK_NODE) thread_pool = ThreadPoolExecutor(4) monit_operator = MonitOperator() all_resources = { 'acc': acc, 'ua_client': ua_client, 'zk_client': zk_client, 'version_update_lock': version_update_lock, 'thread_pool': thread_pool } if options.private_ip in appscale_info.get_taskqueue_nodes(): logger.info('Starting push worker manager') GlobalPushWorkerManager(zk_client, monit_operator) service_manager = ServiceManager(zk_client) service_manager.start() app = web.Application([ ('/oauth/token', OAuthHandler, {'ua_client': ua_client}), ('/v1/apps/([a-z0-9-]+)/services/([a-z0-9-]+)/versions', VersionsHandler, all_resources), ('/v1/projects', ProjectsHandler, all_resources), ('/v1/projects/([a-z0-9-]+)', ProjectHandler, all_resources), ('/v1/apps/([a-z0-9-]+)/services/([a-z0-9-]+)', ServiceHandler, all_resources), ('/v1/apps/([a-z0-9-]+)/services/([a-z0-9-]+)/versions/([a-z0-9-]+)', VersionHandler, all_resources), ('/v1/apps/([a-z0-9-]+)/operations/([a-z0-9-]+)', OperationsHandler, {'ua_client': ua_client}), ('/api/cron/update', UpdateCronHandler, {'acc': acc, 'zk_client': zk_client, 'ua_client': ua_client}), ('/api/queue/update', UpdateQueuesHandler, {'zk_client': zk_client, 'ua_client': ua_client}) ]) logger.info('Starting AdminServer') app.listen(args.port) io_loop = IOLoop.current() io_loop.start()