def rsync_files(cls, host, keyname, local_appscale_dir, is_verbose): """Copies over an AppScale source directory from this machine to the specified host. Args: host: A str representing a host that should be accessible from this machine. keyname: A str representing the name of the SSH keypair that can log into the specified machine. local_appscale_dir: A str representing the path on the local filesystem where the AppScale source to copy over can be found. is_verbose: A bool that indicates if we should print the rsync commands we exec to stdout. Raises: BadConfigurationException: If local_appscale_dir does not exist locally, or if any of the standard AppScale module folders do not exist. """ ssh_key = LocalState.get_key_path_from_name(keyname) appscale_dirs = ["lib", "AppController", "AppManager", "AppServer", "AppLoadBalancer", "AppMonitoring", "Neptune", "InfrastructureManager"] for dir_name in appscale_dirs: local_path = os.path.expanduser(local_appscale_dir) + os.sep + dir_name if not os.path.exists(local_path): raise BadConfigurationException("The location you specified to copy " + "from, {0}, doesn't contain a {1} folder.".format(local_appscale_dir, local_path)) LocalState.shell("rsync -e 'ssh -i {0} {1}' -arv {2}/* root@{3}:/root/appscale/{4}" \ .format(ssh_key, cls.SSH_OPTIONS, local_path, host, dir_name), is_verbose) # Rsync AppDB separately, as it has a lot of paths we may need to exclude # (e.g., built database binaries). local_app_db = os.path.expanduser(local_appscale_dir) + os.sep + "AppDB/*" LocalState.shell("rsync -e 'ssh -i {0} {1}' -arv --exclude='logs/*' --exclude='hadoop-*' --exclude='hbase/hbase-*' --exclude='voldemort/voldemort/*' --exclude='cassandra/cassandra/*' {2} root@{3}:/root/appscale/AppDB".format(ssh_key, cls.SSH_OPTIONS, local_app_db, host), is_verbose)
def scp_remote_to_local(cls, host, keyname, source, dest, is_verbose, user='******'): """Securely copies a file from a remote machine to this machine. Args: host: A str representing the machine that we should log into. keyname: A str representing the name of the SSH keypair to log in with. source: A str representing the path on the remote machine where the file should be copied from. dest: A str representing the path on the local machine where the file should be copied to. is_verbose: A bool that indicates if we should print the scp command to stdout. user: A str representing the user to log in as. Returns: A str representing the standard output of the secure copy and a str representing the standard error of the secure copy. """ ssh_key = LocalState.get_key_path_from_name(keyname) return LocalState.shell( "scp -r -i {0} {1} {2}@{3}:{4} {5}".format(ssh_key, cls.SSH_OPTIONS, user, host, source, dest), is_verbose)
def rsync_files(cls, host, keyname, local_appscale_dir, is_verbose): """Copies over an AppScale source directory from this machine to the specified host. Args: host: A str representing a host that should be accessible from this machine. keyname: A str representing the name of the SSH keypair that can log into the specified machine. local_appscale_dir: A str representing the path on the local filesystem where the AppScale source to copy over can be found. is_verbose: A bool that indicates if we should print the rsync commands we exec to stdout. Raises: BadConfigurationException: If local_appscale_dir does not exist locally, or if any of the standard AppScale module folders do not exist. """ ssh_key = LocalState.get_key_path_from_name(keyname) local_path = os.path.expanduser(local_appscale_dir) if not os.path.exists(local_path): raise BadConfigurationException("The location you specified to copy " \ "from, {0}, doesn't exist.".format(local_path)) LocalState.shell("rsync -e 'ssh -i {0} {1}' -arv " "--exclude='AppDB/logs/*' " \ "--exclude='AppDB/cassandra/cassandra/*' " \ "{2}/* root@{3}:/root/appscale/".format(ssh_key, cls.SSH_OPTIONS, local_path, host), is_verbose)
def copy_deployment_credentials(cls, host, options): """Copies credentials needed to start the AppController and have it create other instances (in cloud deployments). Args: host: A str representing the machine (reachable from this computer) to copy our deployment credentials to. options: A Namespace that indicates which SSH keypair to use, and whether or not we are running in a cloud infrastructure. """ cls.scp(host, options.keyname, LocalState.get_secret_key_location(options.keyname), '/etc/appscale/secret.key', options.verbose) cls.scp(host, options.keyname, LocalState.get_key_path_from_name(options.keyname), '/etc/appscale/ssh.key', options.verbose) LocalState.generate_ssl_cert(options.keyname, options.verbose) cls.scp(host, options.keyname, LocalState.get_certificate_location(options.keyname), '/etc/appscale/certs/mycert.pem', options.verbose) cls.scp(host, options.keyname, LocalState.get_private_key_location(options.keyname), '/etc/appscale/certs/mykey.pem', options.verbose) hash_id = subprocess.Popen([ "openssl", "x509", "-hash", "-noout", "-in", LocalState.get_certificate_location(options.keyname) ], stdout=subprocess.PIPE).communicate()[0] cls.ssh(host, options.keyname, 'ln -fs /etc/appscale/certs/mycert.pem /etc/ssl/certs/{0}.0'.\ format(hash_id.rstrip()), options.verbose) AppScaleLogger.log("Copying over deployment credentials") cert = LocalState.get_certificate_location(options.keyname) private_key = LocalState.get_private_key_location(options.keyname) cls.ssh(host, options.keyname, 'mkdir -p /etc/appscale/keys/cloud1', options.verbose) cls.scp(host, options.keyname, cert, "/etc/appscale/keys/cloud1/mycert.pem", options.verbose) cls.scp(host, options.keyname, private_key, "/etc/appscale/keys/cloud1/mykey.pem", options.verbose) # In Google Compute Engine, we also need to copy over our client_secrets # file and the OAuth2 file that the user has approved for use with their # credentials, otherwise the AppScale VMs won't be able to interact with # GCE. if options.infrastructure and options.infrastructure == 'gce': if os.path.exists(LocalState.get_client_secrets_location( \ options.keyname)): cls.scp( host, options.keyname, LocalState.get_client_secrets_location(options.keyname), '/etc/appscale/client_secrets.json', options.verbose) cls.scp(host, options.keyname, LocalState.get_oauth2_storage_location(options.keyname), '/etc/appscale/oauth2.dat', options.verbose)
def ssh(cls, host, keyname, command, is_verbose, user='******', num_retries=LocalState.DEFAULT_NUM_RETRIES): """Logs into the named host and executes the given command. Args: host: A str representing the machine that we should log into. keyname: A str representing the name of the SSH keypair to log in with. command: A str representing what to execute on the remote host. is_verbose: A bool indicating if we should print the ssh command to stdout. user: A str representing the user to log in as. Returns: A str representing the standard output of the remote command and a str representing the standard error of the remote command. """ ssh_key = LocalState.get_key_path_from_name(keyname) return LocalState.shell( "ssh -F /dev/null -i {0} {1} {2}@{3} bash".format( ssh_key, cls.SSH_OPTIONS, user, host), is_verbose, num_retries, stdin=command)
def rsync_files(cls, host, keyname, local_appscale_dir, is_verbose): """Copies over an AppScale source directory from this machine to the specified host. Args: host: A str representing a host that should be accessible from this machine. keyname: A str representing the name of the SSH keypair that can log into the specified machine. local_appscale_dir: A str representing the path on the local filesystem where the AppScale source to copy over can be found. is_verbose: A bool that indicates if we should print the rsync commands we exec to stdout. Raises: BadConfigurationException: If local_appscale_dir does not exist locally, or if any of the standard AppScale module folders do not exist. """ ssh_key = LocalState.get_key_path_from_name(keyname) local_path = os.path.expanduser(local_appscale_dir) if not os.path.exists(local_path): raise BadConfigurationException("The location you specified to copy " \ "from, {0}, doesn't exist.".format(local_path)) LocalState.shell("rsync -e 'ssh -i {0} {1}' -arv " "--exclude='AppDB/logs/*' " \ "--exclude='AppDB/cassandra/cassandra/*' " \ "{2}/* root@{3}:/root/appscale/".format(ssh_key, cls.SSH_OPTIONS, local_path, host), is_verbose)
def copy_deployment_credentials(cls, host, options): """Copies credentials needed to start the AppController and have it create other instances (in cloud deployments). Args: host: A str representing the machine (reachable from this computer) to copy our deployment credentials to. options: A Namespace that indicates which SSH keypair to use, and whether or not we are running in a cloud infrastructure. """ cls.scp(host, options.keyname, LocalState.get_secret_key_location( options.keyname), '/etc/appscale/secret.key', options.verbose) cls.scp(host, options.keyname, LocalState.get_key_path_from_name( options.keyname), '/etc/appscale/ssh.key', options.verbose) LocalState.generate_ssl_cert(options.keyname, options.verbose) cls.scp(host, options.keyname, LocalState.get_certificate_location( options.keyname), '/etc/appscale/certs/mycert.pem', options.verbose) cls.scp(host, options.keyname, LocalState.get_private_key_location( options.keyname), '/etc/appscale/certs/mykey.pem', options.verbose) AppScaleLogger.log("Copying over deployment credentials") cert = LocalState.get_certificate_location(options.keyname) private_key = LocalState.get_private_key_location(options.keyname) cls.ssh(host, options.keyname, 'mkdir -p /etc/appscale/keys/cloud1', options.verbose) cls.scp(host, options.keyname, cert, "/etc/appscale/keys/cloud1/mycert.pem", options.verbose) cls.scp(host, options.keyname, private_key, "/etc/appscale/keys/cloud1/mykey.pem", options.verbose)
def copy_deployment_credentials(cls, host, options): """Copies credentials needed to start the AppController and have it create other instances (in cloud deployments). Args: host: A str representing the machine (reachable from this computer) to copy our deployment credentials to. options: A Namespace that indicates which SSH keypair to use, and whether or not we are running in a cloud infrastructure. """ local_secret_key = LocalState.get_secret_key_location(options.keyname) cls.scp(host, options.keyname, local_secret_key, '{}/secret.key'.format(cls.CONFIG_DIR), options.verbose) local_ssh_key = LocalState.get_key_path_from_name(options.keyname) cls.scp(host, options.keyname, local_ssh_key, '{}/ssh.key'.format(cls.CONFIG_DIR), options.verbose) LocalState.generate_ssl_cert(options.keyname, options.verbose) local_cert = LocalState.get_certificate_location(options.keyname) cls.scp(host, options.keyname, local_cert, '{}/certs/mycert.pem'.format(cls.CONFIG_DIR), options.verbose) local_private_key = LocalState.get_private_key_location( options.keyname) cls.scp(host, options.keyname, local_private_key, '{}/certs/mykey.pem'.format(cls.CONFIG_DIR), options.verbose) hash_id = subprocess.Popen([ "openssl", "x509", "-hash", "-noout", "-in", LocalState.get_certificate_location(options.keyname) ], stdout=subprocess.PIPE).communicate()[0] symlink_cert = 'ln -fs {}/certs/mycert.pem /etc/ssl/certs/{}.0'.\ format(cls.CONFIG_DIR, hash_id.rstrip()) cls.ssh(host, options.keyname, symlink_cert, options.verbose) # In Google Compute Engine, we also need to copy over our client_secrets # file and the OAuth2 file that the user has approved for use with their # credentials, otherwise the AppScale VMs won't be able to interact with # GCE. if options.infrastructure and options.infrastructure == 'gce': secrets_location = LocalState.get_client_secrets_location( options.keyname) if not os.path.exists(secrets_location): raise AppScaleException( '{} does not exist.'.format(secrets_location)) secrets_type = GCEAgent.get_secrets_type(secrets_location) cls.scp(host, options.keyname, secrets_location, '{}/client_secrets.json'.format(cls.CONFIG_DIR), options.verbose) if secrets_type == CredentialTypes.OAUTH: local_oauth = LocalState.get_oauth2_storage_location( options.keyname) cls.scp(host, options.keyname, local_oauth, '{}/oauth2.dat'.format(cls.CONFIG_DIR), options.verbose)
def get_command_output_from_remote(cls, host, command, keyname, user='******', shell=False): """ Get the file from the location in the remote and passes the contents. Args: host: A str representing the machine that we should log into. command: A str representing the command to run on the remote machine. user: A str representing the user to log in as. """ user_login = user + '@' + host key_path = LocalState.get_key_path_from_name(keyname) return subprocess.Popen(['ssh', '-i', key_path, user_login, command], shell, stdout=subprocess.PIPE)
def test_get_key_path_from_local_appscale(self): keyname = "keyname" # Test key path returned is ~/.appscale when .key file is present in # that location. local_appscale_key_file_path = LocalState.LOCAL_APPSCALE_PATH + keyname + \ ".key" os.path.should_receive('isfile').with_args(local_appscale_key_file_path). \ and_return(True) actual_key_path = LocalState.get_key_path_from_name(keyname) self.assertEquals(local_appscale_key_file_path, actual_key_path) # Test key path returned is /etc/appscale/keys/cloud1/when .key file is # present in that location. etc_appscale_key_file_path = LocalState.ETC_APPSCALE_KEY_PATH + keyname + \ ".key" os.path.should_receive('isfile').with_args(local_appscale_key_file_path). \ and_return(False) os.path.should_receive('isfile').with_args(etc_appscale_key_file_path). \ and_return(True) actual_key_path = LocalState.get_key_path_from_name(keyname) self.assertEquals(etc_appscale_key_file_path, actual_key_path)
def test_get_key_path_from_local_appscale(self): keyname = "keyname" # Test key path returned is ~/.appscale when .key file is present in # that location. local_appscale_key_file_path = LocalState.LOCAL_APPSCALE_PATH + keyname + \ ".key" os.path.should_receive('isfile').with_args(local_appscale_key_file_path). \ and_return(True) actual_key_path = LocalState.get_key_path_from_name(keyname) self.assertEquals(local_appscale_key_file_path, actual_key_path) # Test key path returned is /etc/appscale/keys/cloud1/when .key file is # present in that location. etc_appscale_key_file_path = LocalState.ETC_APPSCALE_KEY_PATH + keyname + \ ".key" os.path.should_receive('isfile').with_args(local_appscale_key_file_path). \ and_return(False) os.path.should_receive('isfile').with_args(etc_appscale_key_file_path). \ and_return(True) actual_key_path = LocalState.get_key_path_from_name(keyname) self.assertEquals(etc_appscale_key_file_path, actual_key_path)
def copy_deployment_credentials(cls, host, options): """Copies credentials needed to start the AppController and have it create other instances (in cloud deployments). Args: host: A str representing the machine (reachable from this computer) to copy our deployment credentials to. options: A Namespace that indicates which SSH keypair to use, and whether or not we are running in a cloud infrastructure. """ cls.scp(host, options.keyname, LocalState.get_secret_key_location( options.keyname), '/etc/appscale/secret.key', options.verbose) cls.scp(host, options.keyname, LocalState.get_key_path_from_name( options.keyname), '/etc/appscale/ssh.key', options.verbose) LocalState.generate_ssl_cert(options.keyname, options.verbose) cls.scp(host, options.keyname, LocalState.get_certificate_location( options.keyname), '/etc/appscale/certs/mycert.pem', options.verbose) cls.scp(host, options.keyname, LocalState.get_private_key_location( options.keyname), '/etc/appscale/certs/mykey.pem', options.verbose) hash_id = subprocess.Popen(["openssl", "x509", "-hash", "-noout", "-in", LocalState.get_certificate_location(options.keyname)], stdout=subprocess.PIPE).communicate()[0] cls.ssh(host, options.keyname, 'ln -fs /etc/appscale/certs/mycert.pem /etc/ssl/certs/{0}.0'.\ format(hash_id.rstrip()), options.verbose) AppScaleLogger.log("Copying over deployment credentials") cert = LocalState.get_certificate_location(options.keyname) private_key = LocalState.get_private_key_location(options.keyname) cls.ssh(host, options.keyname, 'mkdir -p /etc/appscale/keys/cloud1', options.verbose) cls.scp(host, options.keyname, cert, "/etc/appscale/keys/cloud1/mycert.pem", options.verbose) cls.scp(host, options.keyname, private_key, "/etc/appscale/keys/cloud1/mykey.pem", options.verbose) # In Google Compute Engine, we also need to copy over our client_secrets # file and the OAuth2 file that the user has approved for use with their # credentials, otherwise the AppScale VMs won't be able to interact with # GCE. if options.infrastructure and options.infrastructure == 'gce': if os.path.exists(LocalState.get_client_secrets_location( \ options.keyname)): cls.scp(host, options.keyname, LocalState.get_client_secrets_location( options.keyname), '/etc/appscale/client_secrets.json', options.verbose) cls.scp(host, options.keyname, LocalState.get_oauth2_storage_location( options.keyname), '/etc/appscale/oauth2.dat', options.verbose)
def copy_deployment_credentials(cls, host, options): """Copies credentials needed to start the AppController and have it create other instances (in cloud deployments). Args: host: A str representing the machine (reachable from this computer) to copy our deployment credentials to. options: A Namespace that indicates which SSH keypair to use, and whether or not we are running in a cloud infrastructure. """ local_secret_key = LocalState.get_secret_key_location(options.keyname) cls.scp(host, options.keyname, local_secret_key, '{}/secret.key'.format(cls.CONFIG_DIR), options.verbose) local_ssh_key = LocalState.get_key_path_from_name(options.keyname) cls.scp(host, options.keyname, local_ssh_key, '{}/ssh.key'.format(cls.CONFIG_DIR), options.verbose) LocalState.generate_ssl_cert(options.keyname, options.verbose) local_cert = LocalState.get_certificate_location(options.keyname) cls.scp(host, options.keyname, local_cert, '{}/certs/mycert.pem'.format(cls.CONFIG_DIR), options.verbose) local_private_key = LocalState.get_private_key_location(options.keyname) cls.scp(host, options.keyname, local_private_key, '{}/certs/mykey.pem'.format(cls.CONFIG_DIR), options.verbose) hash_id = subprocess.Popen(["openssl", "x509", "-hash", "-noout", "-in", LocalState.get_certificate_location(options.keyname)], stdout=subprocess.PIPE).communicate()[0] symlink_cert = 'ln -fs {}/certs/mycert.pem /etc/ssl/certs/{}.0'.\ format(cls.CONFIG_DIR, hash_id.rstrip()) cls.ssh(host, options.keyname, symlink_cert, options.verbose) # In Google Compute Engine, we also need to copy over our client_secrets # file and the OAuth2 file that the user has approved for use with their # credentials, otherwise the AppScale VMs won't be able to interact with # GCE. if options.infrastructure and options.infrastructure == 'gce': secrets_location = LocalState.get_client_secrets_location(options.keyname) if not os.path.exists(secrets_location): raise AppScaleException('{} does not exist.'.format(secrets_location)) secrets_type = GCEAgent.get_secrets_type(secrets_location) cls.scp(host, options.keyname, secrets_location, '{}/client_secrets.json'.format(cls.CONFIG_DIR), options.verbose) if secrets_type == CredentialTypes.OAUTH: local_oauth = LocalState.get_oauth2_storage_location(options.keyname) cls.scp(host, options.keyname, local_oauth, '{}/oauth2.dat'.format(cls.CONFIG_DIR), options.verbose)
def rsync_files(cls, host, keyname, local_appscale_dir, is_verbose): """Copies over an AppScale source directory from this machine to the specified host. Args: host: A str representing a host that should be accessible from this machine. keyname: A str representing the name of the SSH keypair that can log into the specified machine. local_appscale_dir: A str representing the path on the local filesystem where the AppScale source to copy over can be found. is_verbose: A bool that indicates if we should print the rsync commands we exec to stdout. Raises: BadConfigurationException: If local_appscale_dir does not exist locally, or if any of the standard AppScale module folders do not exist. """ ssh_key = LocalState.get_key_path_from_name(keyname) appscale_dirs = [ "lib", "AppController", "AppManager", "AppServer", "AppServer_Java", "AppDashboard", "InfrastructureManager", "AppTaskQueue", "XMPPReceiver" ] for dir_name in appscale_dirs: local_path = os.path.expanduser( local_appscale_dir) + os.sep + dir_name if not os.path.exists(local_path): raise BadConfigurationException("The location you specified to copy " \ "from, {0}, doesn't contain a {1} folder.".format(local_appscale_dir, local_path)) LocalState.shell("rsync -e 'ssh -i {0} {1}' -arv {2}/* "\ "root@{3}:/root/appscale/{4}".format(ssh_key, cls.SSH_OPTIONS, local_path, host, dir_name), is_verbose) # Rsync AppDB separately, as it has a lot of paths we may need to exclude # (e.g., built database binaries). local_app_db = os.path.expanduser( local_appscale_dir) + os.sep + "AppDB/*" LocalState.shell("rsync -e 'ssh -i {0} {1}' -arv --exclude='logs/*' " \ "--exclude='hadoop-*' --exclude='hbase/hbase-*' " \ "--exclude='cassandra/cassandra/*' {2} root@{3}:/root/appscale/AppDB" \ .format(ssh_key, cls.SSH_OPTIONS, local_app_db, host), is_verbose) # And rsync the firewall configuration file separately, as it's not a # directory (which the above all are). local_firewall = os.path.expanduser(local_appscale_dir) + os.sep + \ "firewall.conf" LocalState.shell("rsync -e 'ssh -i {0} {1}' -arv {2} root@{3}:" \ "/root/appscale/firewall.conf".format(ssh_key, cls.SSH_OPTIONS, local_firewall, host), is_verbose)
def copy_ssh_keys_to_node(cls, host, keyname, is_verbose): """Sets the given SSH keypair as the default key for the named host, enabling it to log into other machines in the AppScale deployment without being prompted for a password or explicitly requiring the key to be provided. Args: host: A str representing the machine that we should log into. keyname: A str representing the name of the SSH keypair to log in with. is_verbose: A bool that indicates if we should print the SCP commands needed to copy the SSH keys over to stdout. """ ssh_key = LocalState.get_key_path_from_name(keyname) cls.scp(host, keyname, ssh_key, "/root/.ssh/id_dsa", is_verbose) cls.scp(host, keyname, ssh_key, "/root/.ssh/id_rsa", is_verbose) cls.scp(host, keyname, ssh_key, "/root/.appscale/{0}.key".format(keyname), is_verbose)
def copy_ssh_keys_to_node(cls, host, keyname, is_verbose): """Sets the given SSH keypair as the default key for the named host, enabling it to log into other machines in the AppScale deployment without being prompted for a password or explicitly requiring the key to be provided. Args: host: A str representing the machine that we should log into. keyname: A str representing the name of the SSH keypair to log in with. is_verbose: A bool that indicates if we should print the SCP commands needed to copy the SSH keys over to stdout. """ ssh_key = LocalState.get_key_path_from_name(keyname) cls.scp(host, keyname, ssh_key, '/root/.ssh/id_dsa', is_verbose) cls.scp(host, keyname, ssh_key, '/root/.ssh/id_rsa', is_verbose) cls.scp(host, keyname, ssh_key, '/root/.appscale/{0}.key'.format(keyname), is_verbose)
def ssh(cls, host, keyname, command, is_verbose, user='******'): """Logs into the named host and executes the given command. Args: host: A str representing the machine that we should log into. keyname: A str representing the name of the SSH keypair to log in with. command: A str representing what to execute on the remote host. is_verbose: A bool indicating if we should print the ssh command to stdout. user: A str representing the user to log in as. Returns: A str representing the standard output of the remote command and a str representing the standard error of the remote command. """ ssh_key = LocalState.get_key_path_from_name(keyname) return LocalState.shell("ssh -i {0} {1} {2}@{3} '{4}'".format(ssh_key, cls.SSH_OPTIONS, user, host, command), is_verbose)
def get_command_output_from_remote(cls, host, command, keyname, user='******', shell=False): """ Get the file from the location in the remote and passes the contents. Args: host: A str representing the machine that we should log into. command: A str representing the command to run on the remote machine. user: A str representing the user to log in as. """ user_login = user + '@' + host key_path = LocalState.get_key_path_from_name(keyname) return subprocess.Popen(['ssh', '-i', key_path, user_login, command], shell, stdout=subprocess.PIPE)
def scp(cls, host, keyname, source, dest, is_verbose, user='******'): """Securely copies a file from this machine to the named machine. Args: host: A str representing the machine that we should log into. keyname: A str representing the name of the SSH keypair to log in with. source: A str representing the path on the local machine where the file should be copied from. dest: A str representing the path on the remote machine where the file should be copied to. is_verbose: A bool that indicates if we should print the scp command to stdout. user: A str representing the user to log in as. Returns: A str representing the standard output of the secure copy and a str representing the standard error of the secure copy. """ ssh_key = LocalState.get_key_path_from_name(keyname) return LocalState.shell("scp -i {0} {1} {2} {3}@{4}:{5}".format(ssh_key, cls.SSH_OPTIONS, source, user, host, dest), is_verbose)
def start_head_node(cls, options, my_id, node_layout): """Starts the first node in an AppScale deployment and instructs it to start API services on its own node, as well as the other nodes in the deployment. This includes spawning the first node in the deployment, copying over all deployment-specific files to it, and starting its AppController service. Args: options: A Namespace that includes parameters passed in by the user that define non-placement-strategy-related deployment options (e.g., keypair names, security group names). my_id: A str that is used to uniquely identify this AppScale deployment with the remote start application. node_layout: A NodeLayout that describes the placement strategy that should be used for this AppScale deployment. Returns: The public IP and instance ID (a dummy value in non-cloud deployments) corresponding to the node that was started. Raises: AppControllerException: If the AppController on the head node crashes. The message in this exception indicates why the crash occurred. """ secret_key = LocalState.generate_secret_key(options.keyname) AppScaleLogger.verbose("Secret key is {0}".format(secret_key), options.verbose) if options.infrastructure: instance_id, public_ip, private_ip = cls.spawn_node_in_cloud(options) else: instance_id = cls.DUMMY_INSTANCE_ID public_ip = node_layout.head_node().public_ip private_ip = node_layout.head_node().private_ip AppScaleLogger.log("Log in to your head node: ssh -i {0} root@{1}".format( LocalState.get_key_path_from_name(options.keyname), public_ip)) try: cls.ensure_machine_is_compatible(public_ip, options.keyname, options.table, options.verbose) except AppScaleException as ase: # On failure shutdown the cloud instances, cleanup the keys, but only # if --test is not set. if options.infrastructure: if not options.test: try: cls.terminate_cloud_instance(instance_id, options) except Exception as tcie: AppScaleLogger.log("Error terminating instances: {0}" .format(str(tcie))) raise AppScaleException("{0} Please ensure that the "\ "image {1} has AppScale {2} installed on it." .format(str(ase), options.machine, APPSCALE_VERSION)) else: raise AppScaleException("{0} Please login to that machine and ensure "\ "that AppScale {1} is installed on it." .format(str(ase), APPSCALE_VERSION)) if options.scp: AppScaleLogger.log("Copying over local copy of AppScale from {0}".format( options.scp)) cls.rsync_files(public_ip, options.keyname, options.scp, options.verbose) # On Euca, we've seen issues where attaching the EBS volume right after # the instance starts doesn't work. This sleep lets the instance fully # start up and get volumes attached to it correctly. if options.infrastructure and options.infrastructure == 'euca' and \ options.disks: time.sleep(30) if options.infrastructure: agent = InfrastructureAgentFactory.create_agent(options.infrastructure) params = agent.get_params_from_args(options) additional_params = {} if agent.PARAM_CREDENTIALS in params: additional_params = params[agent.PARAM_CREDENTIALS] if options.use_spot_instances: additional_params[agent.PARAM_SPOT_PRICE] = \ str(params[agent.PARAM_SPOT_PRICE]) if agent.PARAM_REGION in params: additional_params[agent.PARAM_REGION] = params[agent.PARAM_REGION] else: additional_params = {} deployment_params = LocalState.generate_deployment_params(options, node_layout, public_ip, additional_params) AppScaleLogger.verbose(str(LocalState.obscure_dict(deployment_params)), options.verbose) AppScaleLogger.log("Head node successfully initialized at {0}.".format(public_ip)) AppScaleLogger.remote_log_tools_state(options, my_id, "started head node", APPSCALE_VERSION) time.sleep(10) # gives machines in cloud extra time to boot up cls.copy_deployment_credentials(public_ip, options) cls.run_user_commands(public_ip, options.user_commands, options.keyname, options.verbose) cls.start_remote_appcontroller(public_ip, options.keyname, options.verbose) acc = AppControllerClient(public_ip, secret_key) locations = [{ 'public_ip' : public_ip, 'private_ip' : private_ip, 'jobs' : node_layout.head_node().roles, 'instance_id' : instance_id, 'disk' : node_layout.head_node().disk }] try: acc.set_parameters(locations, LocalState.map_to_array(deployment_params)) except Exception as exception: AppScaleLogger.warn('Saw Exception while setting AC parameters: {0}' \ .format(str(exception))) message = RemoteHelper.collect_appcontroller_crashlog(public_ip, options.keyname, options.verbose) raise AppControllerException(message) return public_ip, instance_id
def start_head_node(cls, options, my_id, node_layout): """Starts the first node in an AppScale deployment and instructs it to start API services on its own node, as well as the other nodes in the deployment. This includes spawning the first node in the deployment, copying over all deployment-specific files to it, and starting its AppController service. Args: options: A Namespace that includes parameters passed in by the user that define non-placement-strategy-related deployment options (e.g., keypair names, security group names). my_id: A str that is used to uniquely identify this AppScale deployment with the remote start application. node_layout: A NodeLayout that describes the placement strategy that should be used for this AppScale deployment. Returns: The public IP and instance ID (a dummy value in non-cloud deployments) corresponding to the node that was started. Raises: AppControllerException: If the AppController on the head node crashes. The message in this exception indicates why the crash occurred. """ secret_key = LocalState.generate_secret_key(options.keyname) AppScaleLogger.verbose("Secret key is {0}".format(secret_key), options.verbose) head_node = node_layout.head_node().public_ip AppScaleLogger.log( "Log in to your head node: ssh -i {0} root@{1}".format( LocalState.get_key_path_from_name(options.keyname), head_node)) additional_params = {} if options.infrastructure: agent = InfrastructureAgentFactory.create_agent( options.infrastructure) params = agent.get_params_from_args(options) additional_params = {} if agent.PARAM_CREDENTIALS in params: additional_params = params[agent.PARAM_CREDENTIALS] if options.use_spot_instances: additional_params[agent.PARAM_SPOT_PRICE] = \ str(params[agent.PARAM_SPOT_PRICE]) if agent.PARAM_REGION in params: additional_params[agent.PARAM_REGION] = params[ agent.PARAM_REGION] time.sleep(10) # gives machines in cloud extra time to boot up cls.copy_deployment_credentials(head_node, options) cls.run_user_commands(head_node, options.user_commands, options.keyname, options.verbose) cls.start_remote_appcontroller(head_node, options.keyname, options.verbose) AppScaleLogger.log( "Head node successfully initialized at {0}.".format(head_node)) AppScaleLogger.remote_log_tools_state(options, my_id, "started head node", APPSCALE_VERSION) # Construct serverside compatible parameters. deployment_params = LocalState.generate_deployment_params( options, node_layout, additional_params) AppScaleLogger.verbose(str(LocalState.obscure_dict(deployment_params)), options.verbose) acc = AppControllerClient(head_node, secret_key) try: acc.set_parameters(node_layout.to_list(), deployment_params) except Exception as exception: AppScaleLogger.warn( 'Saw Exception while setting AC parameters: {0}'.format( str(exception))) message = RemoteHelper.collect_appcontroller_crashlog( head_node, options.keyname, options.verbose) raise AppControllerException(message)
def start_head_node(cls, options, node_layout): """Starts the first node in an AppScale deployment and instructs it to start API services on its own node, as well as the other nodes in the deployment. This includes spawning the first node in the deployment, copying over all deployment-specific files to it, and starting its AppController service. Args: options: A Namespace that includes parameters passed in by the user that define non-placement-strategy-related deployment options (e.g., keypair names, security group names). node_layout: A NodeLayout that describes the placement strategy that should be used for this AppScale deployment. Returns: The public IP and instance ID (a dummy value in non-cloud deployments) corresponding to the node that was started. """ secret_key = LocalState.generate_secret_key(options.keyname) AppScaleLogger.verbose("Secret key is {0}".format(secret_key), options.verbose) if options.infrastructure: instance_id, public_ip, private_ip = cls.spawn_node_in_cloud(options) else: instance_id = cls.DUMMY_INSTANCE_ID public_ip = node_layout.head_node().id private_ip = node_layout.head_node().id AppScaleLogger.log("Log in to your head node: ssh -i {0} root@{1}".format( LocalState.get_key_path_from_name(options.keyname), public_ip)) cls.ensure_machine_is_compatible(public_ip, options.keyname, options.table, options.verbose) if options.scp: AppScaleLogger.log("Copying over local copy of AppScale from {0}".format( options.scp)) cls.rsync_files(public_ip, options.keyname, options.scp, options.verbose) if options.infrastructure: agent = InfrastructureAgentFactory.create_agent(options.infrastructure) params = agent.get_params_from_args(options) additional_params = params[agent.PARAM_CREDENTIALS] else: additional_params = {} deployment_params = LocalState.generate_deployment_params(options, node_layout, public_ip, additional_params) AppScaleLogger.verbose(str(LocalState.obscure_dict(deployment_params)), options.verbose) AppScaleLogger.log("Head node successfully initialized at {0}. It is now starting up {1}.".format(public_ip, options.table)) AppScaleLogger.remote_log_tools_state(options, "started head node") time.sleep(10) # gives machines in cloud extra time to boot up cls.copy_deployment_credentials(public_ip, options) cls.start_remote_appcontroller(public_ip, options.keyname, options.verbose) acc = AppControllerClient(public_ip, secret_key) locations = ["{0}:{1}:{2}:{3}:cloud1".format(public_ip, private_ip, ":".join(node_layout.head_node().roles), instance_id)] acc.set_parameters(locations, LocalState.map_to_array(deployment_params)) return public_ip, instance_id
def start_head_node(cls, options, my_id, node_layout): """Starts the first node in an AppScale deployment and instructs it to start API services on its own node, as well as the other nodes in the deployment. This includes spawning the first node in the deployment, copying over all deployment-specific files to it, and starting its AppController service. Args: options: A Namespace that includes parameters passed in by the user that define non-placement-strategy-related deployment options (e.g., keypair names, security group names). my_id: A str that is used to uniquely identify this AppScale deployment with the remote start application. node_layout: A NodeLayout that describes the placement strategy that should be used for this AppScale deployment. Returns: The public IP and instance ID (a dummy value in non-cloud deployments) corresponding to the node that was started. Raises: AppControllerException: If the AppController on the head node crashes. The message in this exception indicates why the crash occurred. """ secret_key = LocalState.generate_secret_key(options.keyname) AppScaleLogger.verbose("Secret key is {0}".format(secret_key), options.verbose) if options.infrastructure: instance_id, public_ip, private_ip = cls.spawn_node_in_cloud( options) else: instance_id = cls.DUMMY_INSTANCE_ID public_ip = node_layout.head_node().public_ip private_ip = node_layout.head_node().private_ip AppScaleLogger.log( "Log in to your head node: ssh -i {0} root@{1}".format( LocalState.get_key_path_from_name(options.keyname), public_ip)) try: cls.ensure_machine_is_compatible(public_ip, options.keyname, options.table, options.verbose) except AppScaleException as ase: # On failure shutdown the cloud instances, cleanup the keys, but only # if --test is not set. if options.infrastructure: if not options.test: try: cls.terminate_cloud_instance(instance_id, options) except Exception as tcie: AppScaleLogger.log( "Error terminating instances: {0}".format( str(tcie))) raise AppScaleException("{0} Please ensure that the "\ "image {1} has AppScale {2} installed on it." .format(str(ase), options.machine, APPSCALE_VERSION)) else: raise AppScaleException("{0} Please login to that machine and ensure "\ "that AppScale {1} is installed on it." .format(str(ase), APPSCALE_VERSION)) if options.scp: AppScaleLogger.log( "Copying over local copy of AppScale from {0}".format( options.scp)) cls.rsync_files(public_ip, options.keyname, options.scp, options.verbose) # On Euca, we've seen issues where attaching the EBS volume right after # the instance starts doesn't work. This sleep lets the instance fully # start up and get volumes attached to it correctly. if options.infrastructure and options.infrastructure == 'euca' and \ options.disks: time.sleep(30) if options.infrastructure: agent = InfrastructureAgentFactory.create_agent( options.infrastructure) params = agent.get_params_from_args(options) additional_params = {} if agent.PARAM_CREDENTIALS in params: additional_params = params[agent.PARAM_CREDENTIALS] if options.use_spot_instances: additional_params[agent.PARAM_SPOT_PRICE] = \ str(params[agent.PARAM_SPOT_PRICE]) if agent.PARAM_REGION in params: additional_params[agent.PARAM_REGION] = params[ agent.PARAM_REGION] else: additional_params = {} deployment_params = LocalState.generate_deployment_params( options, node_layout, public_ip, additional_params) AppScaleLogger.verbose(str(LocalState.obscure_dict(deployment_params)), options.verbose) AppScaleLogger.log( "Head node successfully initialized at {0}.".format(public_ip)) AppScaleLogger.remote_log_tools_state(options, my_id, "started head node", APPSCALE_VERSION) time.sleep(10) # gives machines in cloud extra time to boot up cls.copy_deployment_credentials(public_ip, options) cls.run_user_commands(public_ip, options.user_commands, options.keyname, options.verbose) cls.start_remote_appcontroller(public_ip, options.keyname, options.verbose) acc = AppControllerClient(public_ip, secret_key) locations = [{ 'public_ip': public_ip, 'private_ip': private_ip, 'jobs': node_layout.head_node().roles, 'instance_id': instance_id, 'disk': node_layout.head_node().disk }] try: acc.set_parameters(locations, LocalState.map_to_array(deployment_params)) except Exception as exception: AppScaleLogger.warn('Saw Exception while setting AC parameters: {0}' \ .format(str(exception))) message = RemoteHelper.collect_appcontroller_crashlog( public_ip, options.keyname, options.verbose) raise AppControllerException(message) return public_ip, instance_id
def ssh(self, command): key_path = LocalState.get_key_path_from_name(self.key_name) ssh_command = "ssh -i {0} {1}@{2} ".format(key_path, "root", self.service_host) p = subprocess.Popen(ssh_command + command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) return p.stdout.read()
def start_head_node(cls, options, my_id, node_layout): """Starts the first node in an AppScale deployment and instructs it to start API services on its own node, as well as the other nodes in the deployment. This includes spawning the first node in the deployment, copying over all deployment-specific files to it, and starting its AppController service. Args: options: A Namespace that includes parameters passed in by the user that define non-placement-strategy-related deployment options (e.g., keypair names, security group names). my_id: A str that is used to uniquely identify this AppScale deployment with the remote start application. node_layout: A NodeLayout that describes the placement strategy that should be used for this AppScale deployment. Returns: The public IP and instance ID (a dummy value in non-cloud deployments) corresponding to the node that was started. """ secret_key = LocalState.generate_secret_key(options.keyname) AppScaleLogger.verbose("Secret key is {0}".format(secret_key), options.verbose) if options.infrastructure: instance_id, public_ip, private_ip = cls.spawn_node_in_cloud(options) else: instance_id = cls.DUMMY_INSTANCE_ID public_ip = node_layout.head_node().public_ip private_ip = node_layout.head_node().private_ip AppScaleLogger.log("Log in to your head node: ssh -i {0} root@{1}".format( LocalState.get_key_path_from_name(options.keyname), public_ip)) try: cls.ensure_machine_is_compatible(public_ip, options.keyname, options.table, options.verbose) except AppScaleException as ase: # On failure shutdown the cloud instances, cleanup the keys, but only # if --test is not set. if options.infrastructure: if not options.test: try: cls.terminate_cloud_instance(instance_id, options) except Exception as tcie: AppScaleLogger.log("Error terminating instances: {0}" .format(str(tcie))) raise AppScaleException("{0} Please ensure that the "\ "image {1} has AppScale {2} installed on it." .format(str(ase),options.machine,APPSCALE_VERSION)) else: raise AppScaleException("{0} Please login to that machine and ensure "\ "that AppScale {1} is installed on it." .format(str(ase),APPSCALE_VERSION)) if options.scp: AppScaleLogger.log("Copying over local copy of AppScale from {0}".format( options.scp)) cls.rsync_files(public_ip, options.keyname, options.scp, options.verbose) if options.infrastructure: agent = InfrastructureAgentFactory.create_agent(options.infrastructure) params = agent.get_params_from_args(options) additional_params = params[agent.PARAM_CREDENTIALS] if options.use_spot_instances: additional_params[agent.PARAM_SPOT_PRICE] = str(params[agent.PARAM_SPOT_PRICE]) else: additional_params = {} deployment_params = LocalState.generate_deployment_params(options, node_layout, public_ip, additional_params) AppScaleLogger.verbose(str(LocalState.obscure_dict(deployment_params)), options.verbose) AppScaleLogger.log("Head node successfully initialized at {0}. It is now "\ "starting up {1}.".format(public_ip, options.table)) AppScaleLogger.remote_log_tools_state(options, my_id, "started head node", APPSCALE_VERSION) time.sleep(10) # gives machines in cloud extra time to boot up cls.copy_deployment_credentials(public_ip, options) cls.start_remote_appcontroller(public_ip, options.keyname, options.verbose) acc = AppControllerClient(public_ip, secret_key) locations = ["{0}:{1}:{2}:{3}:cloud1".format(public_ip, private_ip, ":".join(node_layout.head_node().roles), instance_id)] acc.set_parameters(locations, LocalState.map_to_array(deployment_params)) return public_ip, instance_id
def start_head_node(cls, options, my_id, node_layout): """Starts the first node in an AppScale deployment and instructs it to start API services on its own node, as well as the other nodes in the deployment. This includes spawning the first node in the deployment, copying over all deployment-specific files to it, and starting its AppController service. Args: options: A Namespace that includes parameters passed in by the user that define non-placement-strategy-related deployment options (e.g., keypair names, security group names). my_id: A str that is used to uniquely identify this AppScale deployment with the remote start application. node_layout: A NodeLayout that describes the placement strategy that should be used for this AppScale deployment. Returns: The public IP and instance ID (a dummy value in non-cloud deployments) corresponding to the node that was started. Raises: AppControllerException: If the AppController on the head node crashes. The message in this exception indicates why the crash occurred. """ secret_key = LocalState.generate_secret_key(options.keyname) AppScaleLogger.verbose("Secret key is {0}". format(secret_key), options.verbose) head_node = node_layout.head_node().public_ip AppScaleLogger.log("Log in to your head node: ssh -i {0} root@{1}".format( LocalState.get_key_path_from_name(options.keyname), head_node)) additional_params = {} if options.infrastructure: agent = InfrastructureAgentFactory.create_agent(options.infrastructure) params = agent.get_params_from_args(options) additional_params = {} if agent.PARAM_CREDENTIALS in params: additional_params = params[agent.PARAM_CREDENTIALS] if options.use_spot_instances: additional_params[agent.PARAM_SPOT_PRICE] = \ str(params[agent.PARAM_SPOT_PRICE]) if agent.PARAM_REGION in params: additional_params[agent.PARAM_REGION] = params[agent.PARAM_REGION] time.sleep(10) # gives machines in cloud extra time to boot up cls.copy_deployment_credentials(head_node, options) cls.run_user_commands(head_node, options.user_commands, options.keyname, options.verbose) cls.start_remote_appcontroller(head_node, options.keyname, options.verbose) AppScaleLogger.log("Head node successfully initialized at {0}.". format(head_node)) AppScaleLogger.remote_log_tools_state( options, my_id, "started head node", APPSCALE_VERSION) # Construct serverside compatible parameters. deployment_params = LocalState.generate_deployment_params( options, node_layout, additional_params) AppScaleLogger.verbose(str(LocalState.obscure_dict(deployment_params)), options.verbose) acc = AppControllerClient(head_node, secret_key) try: acc.set_parameters(node_layout.to_list(), deployment_params) except Exception as exception: AppScaleLogger.warn(u'Saw Exception while setting AC parameters: {0}'. format(str(exception))) message = RemoteHelper.collect_appcontroller_crashlog( head_node, options.keyname, options.verbose) raise AppControllerException(message)