Пример #1
0
    def run_with_timeout(self, timeout_time, default, num_retries, function,
                         *args):
        """Runs the given function, aborting it if it runs too long.

    Args:
      timeout_time: The number of seconds that we should allow function to
        execute for.
      default: The value that should be returned if the timeout is exceeded.
      num_retries: The number of times we should retry the SOAP call if we see
        an unexpected exception.
      function: The function that should be executed.
      *args: The arguments that will be passed to function.
    Returns:
      Whatever function(*args) returns if it runs within the timeout window, and
        default otherwise.
    Raises:
      AppControllerException: If the AppController we're trying to connect to is
        not running at the given IP address, or if it rejects the SOAP request.
    """
        def timeout_handler(_, __):
            """Raises a TimeoutException if the function we want to execute takes
      too long to run.

      Raises:
        TimeoutException: If a SIGALRM is raised.
      """
            raise TimeoutException()

        signal.signal(signal.SIGALRM, timeout_handler)
        signal.alarm(timeout_time)  # trigger alarm in timeout_time seconds
        try:
            retval = function(*args)
        except TimeoutException:
            return default
        except socket.error as exception:
            signal.alarm(0)  # turn off the alarm before we retry
            if num_retries > 0:
                time.sleep(1)
                return self.run_with_timeout(timeout_time, default,
                                             num_retries - 1, function, *args)
            else:
                raise AppControllerException(
                    "Got exception from socket: {}".format(exception))

        except ssl.SSLError:
            # these are intermittent, so don't decrement our retry count for this
            signal.alarm(0)  # turn off the alarm before we retry
            return self.run_with_timeout(timeout_time, default, num_retries,
                                         function, *args)
        finally:
            signal.alarm(0)  # turn off the alarm

        if retval == self.BAD_SECRET_MESSAGE:
            raise AppControllerException("Could not authenticate successfully" + \
              " to the AppController. You may need to change the keyname in use.")

        return retval
Пример #2
0
  def call(self, function, *args):
    """Runs the given function, retrying it if a transient error is seen.

    Args:
      function: The function that should be executed.
      *args: The arguments that will be passed to function.
    Returns:
      The return value of function(*args).
    Raises:
      AppControllerException: If the AppController we're trying to connect to is
        not running at the given IP address, or if it rejects the SOAP request.
    """
    try:
      result = function(*args)

      if result == self.BAD_SECRET_MESSAGE:
        raise AppControllerException("Could not authenticate successfully" + \
          " to the AppController. You may need to change the keyname in use.")
      else:
        return result
    except (ssl.SSLError, socket.error):
      sys.stderr.write("Saw SSL exception when communicating with the " \
        "AppController, retrying momentarily.")
      return self.call(function, *args)

    return retval
  def does_user_exist(self, username, silent=False):
    """ Queries the AppController to see if the given user exists.

    Args:
      username: The email address registered as username for the user's application.
    """
    while True:
      try:
        user_exists = self.run_with_timeout(
          self.DEFAULT_TIMEOUT, 'Request to check if user exists timed out.',
          self.DEFAULT_NUM_RETRIES, self.server.does_user_exist, username,
          self.secret)
        if user_exists == 'true':
          return True
        elif user_exists == 'false':
          return False
        else:
          raise Exception(user_exists)
      except BadSecretException as exception:
        raise AppControllerException(
          "Exception when checking if a user exists: {0}".format(exception))
      except Exception as acc_error:
        if not silent:
          AppScaleLogger.log("Exception when checking if a user exists: {0}".
                             format(acc_error))
          AppScaleLogger.log("Backing off and trying again.")
        time.sleep(10)
Пример #4
0
  def set_property(cls, options):
    """Instructs AppScale to replace the value it uses for a particular
    AppController instance variable (property) with a new value.

    Args:
      options: A Namespace that has fields for each parameter that can be passed
        in via the command-line interface.
    """
    shadow_host = LocalState.get_host_with_role(options.keyname, 'shadow')
    acc = AppControllerClient(shadow_host, LocalState.get_secret_key(
      options.keyname))
    result = acc.set_property(options.property_name, options.property_value)
    if result == 'OK':
      AppScaleLogger.success("Successfully updated the given property.")
    else:
      raise AppControllerException("Unable to update the given property " +
        "because: {0}".format(result))
  def receive_server_message(self):
    """Queries the AppController for a message that the server wants to send
    to the tools.

    Returns:
      The message from the AppController in JSON with format :
      {'ip':ip, 'status': status, 'output':output}
    """
    server_message = self.run_with_timeout(self.DEFAULT_TIMEOUT * 5,
                                           "Error: Client Timed Out",
                                           self.DEFAULT_NUM_RETRIES,
                                           self.server.receive_server_message,
                                           self.DEFAULT_TIMEOUT * 4,
                                           self.secret)
    if server_message.startswith("Error"):
      raise AppControllerException(server_message)
    else:
      return server_message
  def run_terminate(self, clean):
    """Tells the AppController to terminate AppScale on the deployment.

    Args:
      clean: A boolean indicating whether the clean parameter should be
        passed to terminate.rb.
    Returns:
      The request id assigned from executing the SOAP call on the remote
        AppController.
    """
    request_id = self.run_with_timeout(self.DEFAULT_TIMEOUT, "Error",
                                       self.DEFAULT_NUM_RETRIES,
                                       self.server.run_terminate, clean,
                                       self.secret)
    if request_id == "Error":
      raise AppControllerException("Unable to send request to terminate "
                                   "deployment to AppController.")
    else:
      return request_id
  def set_parameters(self, locations, params):
    """Passes the given parameters to an AppController, allowing it to start
    configuring API services in this AppScale deployment.

    Args:
      locations: A list that contains the first node's IP address.
      params: A list that contains API service-level configuration info,
        as well as a mapping of IPs to the API services they should host
        (excluding the first node).
    Raises:
      AppControllerException: If the remote AppController indicates that there
        was a problem with the parameters passed to it.
    """

    result = self.run_with_timeout(
      self.DEFAULT_TIMEOUT, "Error", self.DEFAULT_NUM_RETRIES,
      self.server.set_parameters, json.dumps(locations), json.dumps(params),
      self.secret)
    if result.startswith('Error'):
      raise AppControllerException(result)
    def get_uaserver_host(self, is_verbose):
        """Queries the AppController to see which machine is hosting the
    UserAppServer, and at what IP it can be reached.

    Args:
      is_verbose: A bool that indicates if we should print out the first
        AppController's status when we query it.
    Returns:
      The IP address where a UserAppServer can be located (although it is not
      guaranteed to be running).
    """
        last_known_state = None
        while True:
            try:
                status = self.get_status()
                AppScaleLogger.verbose(
                    'Received status from head node: ' + status, is_verbose)

                if status == self.BAD_SECRET_MESSAGE:
                    raise AppControllerException("Could not authenticate successfully" + \
                      " to the AppController. You may need to change the keyname in use.")

                match = re.search(r'Database is at (.*)', status)
                if match and match.group(1) != 'not-up-yet':
                    return match.group(1)
                else:
                    match = re.search(r'Current State: (.*)', status)
                    if match:
                        if last_known_state != match.group(1):
                            last_known_state = match.group(1)
                            AppScaleLogger.log(last_known_state)
                    else:
                        AppScaleLogger.log(
                            'Waiting for AppScale nodes to complete '
                            'the initialization process')
            except (AppControllerException, socket.error) as exception:
                raise exception
            except Exception as exception:
                AppScaleLogger.warn('Saw {0}, waiting a few moments to try again' \
                  .format(str(exception)))
            time.sleep(self.WAIT_TIME)
Пример #9
0
  def set_parameters(self, locations, credentials, app=None):
    """Passes the given parameters to an AppController, allowing it to start
    configuring API services in this AppScale deployment.

    Args:
      locations: A list that contains the first node's IP address.
      credentials: A list that contains API service-level configuration info,
        as well as a mapping of IPs to the API services they should host
        (excluding the first node).
      app: A list of the App Engine apps that should be started.
    Raises:
      AppControllerException: If the remote AppController indicates that there
        was a problem with the parameters passed to it.
    """
    if app is None:
      app = 'none'

    result = self.call(self.server.set_parameters, locations, credentials,
      [app], self.secret)
    if result.startswith('Error'):
      raise AppControllerException(result)
Пример #10
0
    def run_with_timeout(self, timeout_time, default, num_retries,
                         http_error_is_success, function, *args):
        """Runs the given function, aborting it if it runs too long.

    Args:
      timeout_time: The number of seconds that we should allow function to
        execute for.
      default: The value that should be returned if the timeout is exceeded.
      num_retries: The number of times we should retry the SOAP call if we see
        an unexpected exception.
      http_error_is_success: A bool that indicates if receiving a HTTPError is
        the expected result.
      function: The function that should be executed.
      *args: The arguments that will be passed to function.
    Returns:
      Whatever function(*args) returns if it runs within the timeout window, and
        default otherwise.
    Raises:
      AppControllerException: If the AppController we're trying to connect to is
        not running at the given IP address, or if it rejects the SOAP request.
    """
        def timeout_handler(_, __):
            """Raises a TimeoutException if the function we want to execute takes
      too long to run.

      Raises:
        TimeoutException: If a SIGALRM is raised.
      """
            raise TimeoutException()

        signal.signal(signal.SIGALRM, timeout_handler)
        signal.alarm(timeout_time)  # trigger alarm in timeout_time seconds
        try:
            retval = function(*args)
        except TimeoutException:
            return default
        except socket.error as exception:
            signal.alarm(0)  # turn off the alarm before we retry
            if num_retries > 0:
                sys.stderr.write("Saw socket exception {0} when communicating with the " \
                  "AppController, retrying momentarily. Message is {1}".format(exception, exception.msg))
                return self.run_with_timeout(timeout_time, default,
                                             num_retries - 1,
                                             http_error_is_success, function,
                                             *args)
            else:
                raise exception
        except SOAPpy.Errors.HTTPError as exception:
            if http_error_is_success:
                return "true"
            else:
                signal.alarm(0)  # turn off the alarm before we retry
                sys.stderr.write("Saw HTTPError {0} when communicating with the " \
                  "AppController, retrying momentarily. Message is {1}".format(exception, exception.msg))
                return self.run_with_timeout(timeout_time, default,
                                             num_retries,
                                             http_error_is_success, function,
                                             *args)
        except Exception as exception:
            # This 'except' should be catching ssl.SSLError, but that error isn't
            # available when running in the App Engine sandbox.
            # TODO(cgb): App Engine 1.7.7 adds ssl support, so we should be able to
            # fix this when we update our SDK to that version.
            # Don't decrement our retry count for intermittent errors.
            sys.stderr.write("Saw exception {0} when communicating with the " \
              "AppController, retrying momentarily.".format(str(exception)))
            signal.alarm(0)  # turn off the alarm before we retry
            return self.run_with_timeout(timeout_time, default, num_retries,
                                         http_error_is_success, function,
                                         *args)
        finally:
            signal.alarm(0)  # turn off the alarm

        if retval == self.BAD_SECRET_MESSAGE:
            raise AppControllerException("Could not authenticate successfully" + \
              " to the AppController. You may need to change the keyname in use.")

        return retval
Пример #11
0
  def run_instances(cls, options):
    """Starts a new AppScale deployment with the parameters given.

    Args:
      options: A Namespace that has fields for each parameter that can be
        passed in via the command-line interface.
    Raises:
      AppControllerException: If the AppController on the head node crashes.
        When this occurs, the message in the exception contains the reason why
        the AppController crashed.
      BadConfigurationException: If the user passes in options that are not
        sufficient to start an AppScale deployment (e.g., running on EC2 but
        not specifying the AMI to use), or if the user provides us
        contradictory options (e.g., running on EC2 but not specifying EC2
        credentials).
    """
    LocalState.make_appscale_directory()
    LocalState.ensure_appscale_isnt_running(options.keyname, options.force)
    if options.infrastructure:
      if not options.disks and not options.test and not options.force:
        LocalState.ensure_user_wants_to_run_without_disks()

    reduced_version = '.'.join(x for x in APPSCALE_VERSION.split('.')[:2])
    AppScaleLogger.log("Starting AppScale " + reduced_version)

    my_id = str(uuid.uuid4())
    AppScaleLogger.remote_log_tools_state(options, my_id, "started",
      APPSCALE_VERSION)

    node_layout = NodeLayout(options)
    if not node_layout.is_valid():
      raise BadConfigurationException("There were errors with your " + \
                                      "placement strategy:\n{0}".format(str(node_layout.errors())))

    head_node = node_layout.head_node()
    # Start VMs in cloud via cloud agent.
    if options.infrastructure:
      instance_ids, public_ips, private_ips = RemoteHelper.start_all_nodes(
        options, len(node_layout.nodes))
      AppScaleLogger.log("\nPlease wait for AppScale to prepare your machines "
                         "for use. This can take few minutes.")

      # Set newly obtained node layout info for this deployment.
      for i, _ in enumerate(instance_ids):
        node_layout.nodes[i].public_ip = public_ips[i]
        node_layout.nodes[i].private_ip = private_ips[i]
        node_layout.nodes[i].instance_id = instance_ids[i]

      # Enables root logins and SSH access on the head node.
      RemoteHelper.enable_root_ssh(options, head_node.public_ip)
    AppScaleLogger.verbose("Node Layout: {}".format(node_layout.to_list()),
                           options.verbose)

    # Ensure all nodes are compatible.
    RemoteHelper.ensure_machine_is_compatible(
      head_node.public_ip, options.keyname, options.verbose)

    # Use rsync to move custom code into the deployment.
    if options.scp:
      AppScaleLogger.log("Copying over local copy of AppScale from {0}".
        format(options.scp))
      RemoteHelper.rsync_files(head_node.public_ip, options.keyname, options.scp,
        options.verbose)

    # Start services on head node.
    RemoteHelper.start_head_node(options, my_id, node_layout)

    # Write deployment metadata to disk (facilitates SSH operations, etc.)
    db_master = node_layout.db_master().private_ip
    head_node = node_layout.head_node().public_ip
    LocalState.update_local_metadata(options, db_master, head_node)

    # Copy the locations.json to the head node
    RemoteHelper.copy_local_metadata(node_layout.head_node().public_ip,
                                     options.keyname, options.verbose)

    # Wait for services on head node to start.
    secret_key = LocalState.get_secret_key(options.keyname)
    acc = AppControllerClient(head_node, secret_key)
    try:
      while not acc.is_initialized():
        AppScaleLogger.log('Waiting for head node to initialize...')
        # This can take some time in particular the first time around, since
        # we will have to initialize the database.
        time.sleep(cls.SLEEP_TIME*3)
    except socket.error as socket_error:
      AppScaleLogger.warn('Unable to initialize AppController: {}'.
                          format(socket_error.message))
      message = RemoteHelper.collect_appcontroller_crashlog(
        head_node, options.keyname, options.verbose)
      raise AppControllerException(message)

    # Set up admin account.
    try:
      # We don't need to have any exception information here: we do expect
      # some anyway while the UserAppServer is coming up.
      acc.does_user_exist("non-existent-user", True)
    except Exception:
      AppScaleLogger.log('UserAppServer not ready yet. Retrying ...')
      time.sleep(cls.SLEEP_TIME)

    if options.admin_user and options.admin_pass:
      AppScaleLogger.log("Using the provided admin username/password")
      username, password = options.admin_user, options.admin_pass
    elif options.test:
      AppScaleLogger.log("Using default admin username/password")
      username, password = LocalState.DEFAULT_USER, LocalState.DEFAULT_PASSWORD
    else:
      username, password = LocalState.get_credentials()

    RemoteHelper.create_user_accounts(username, password, head_node,
                                      options.keyname)
    acc.set_admin_role(username, 'true', cls.ADMIN_CAPABILITIES)

    # Wait for machines to finish loading and AppScale Dashboard to be deployed.
    RemoteHelper.wait_for_machines_to_finish_loading(head_node, options.keyname)
    RemoteHelper.sleep_until_port_is_open(LocalState.get_login_host(
      options.keyname), RemoteHelper.APP_DASHBOARD_PORT, options.verbose)

    AppScaleLogger.success("AppScale successfully started!")
    AppScaleLogger.success("View status information about your AppScale " + \
                           "deployment at http://{0}:{1}".format(LocalState.get_login_host(
                           options.keyname), RemoteHelper.APP_DASHBOARD_PORT))
    AppScaleLogger.remote_log_tools_state(options, my_id,
      "finished", APPSCALE_VERSION)
Пример #12
0
    def run_instances(cls, options):
        """Starts a new AppScale deployment with the parameters given.

    Args:
      options: A Namespace that has fields for each parameter that can be
        passed in via the command-line interface.
    Raises:
      AppControllerException: If the AppController on the head node crashes.
        When this occurs, the message in the exception contains the reason why
        the AppController crashed.
      BadConfigurationException: If the user passes in options that are not
        sufficient to start an AppScale deployment (e.g., running on EC2 but
        not specifying the AMI to use), or if the user provides us
        contradictory options (e.g., running on EC2 but not specifying EC2
        credentials).
    """
        LocalState.make_appscale_directory()
        LocalState.ensure_appscale_isnt_running(options.keyname, options.force)

        if options.infrastructure:
            if not options.disks and not options.test and not options.force:
                LocalState.ensure_user_wants_to_run_without_disks()
            AppScaleLogger.log("Starting AppScale " + APPSCALE_VERSION +
                               " over the " + options.infrastructure +
                               " cloud.")
        else:
            AppScaleLogger.log("Starting AppScale " + APPSCALE_VERSION +
                               " over a virtualized cluster.")
        my_id = str(uuid.uuid4())
        AppScaleLogger.remote_log_tools_state(options, my_id, "started",
                                              APPSCALE_VERSION)

        node_layout = NodeLayout(options)
        if not node_layout.is_valid():
            raise BadConfigurationException("There were errors with your " + \
              "placement strategy:\n{0}".format(str(node_layout.errors())))

        if not node_layout.is_supported():
            AppScaleLogger.warn("Warning: This deployment strategy is not " + \
              "officially supported.")

        public_ip, instance_id = RemoteHelper.start_head_node(
            options, my_id, node_layout)
        AppScaleLogger.log(
            "\nPlease wait for AppScale to prepare your machines " +
            "for use.")

        # Write our metadata as soon as possible to let users SSH into those
        # machines via 'appscale ssh'
        LocalState.update_local_metadata(options, node_layout, public_ip,
                                         instance_id)
        RemoteHelper.copy_local_metadata(public_ip, options.keyname,
                                         options.verbose)

        acc = AppControllerClient(public_ip,
                                  LocalState.get_secret_key(options.keyname))
        try:
            uaserver_host = acc.get_uaserver_host(options.verbose)
        except Exception:
            message = RemoteHelper.collect_appcontroller_crashlog(
                public_ip, options.keyname, options.verbose)
            raise AppControllerException(message)

        RemoteHelper.sleep_until_port_is_open(uaserver_host,
                                              UserAppClient.PORT,
                                              options.verbose)

        # Update our metadata again so that users can SSH into other boxes that
        # may have been started.
        LocalState.update_local_metadata(options, node_layout, public_ip,
                                         instance_id)
        RemoteHelper.copy_local_metadata(public_ip, options.keyname,
                                         options.verbose)

        AppScaleLogger.log("UserAppServer is at {0}".format(uaserver_host))

        uaserver_client = UserAppClient(
            uaserver_host, LocalState.get_secret_key(options.keyname))

        if options.admin_user and options.admin_pass:
            AppScaleLogger.log("Using the provided admin username/password")
            username, password = options.admin_user, options.admin_pass
        elif options.test:
            AppScaleLogger.log("Using default admin username/password")
            username, password = LocalState.DEFAULT_USER, LocalState.DEFAULT_PASSWORD
        else:
            username, password = LocalState.get_credentials()

        RemoteHelper.create_user_accounts(username, password, uaserver_host,
                                          options.keyname,
                                          options.clear_datastore)
        uaserver_client.set_admin_role(username)

        RemoteHelper.wait_for_machines_to_finish_loading(
            public_ip, options.keyname)
        # Finally, update our metadata once we know that all of the machines are
        # up and have started all their API services.
        LocalState.update_local_metadata(options, node_layout, public_ip,
                                         instance_id)
        RemoteHelper.copy_local_metadata(public_ip, options.keyname,
                                         options.verbose)

        RemoteHelper.sleep_until_port_is_open(
            LocalState.get_login_host(options.keyname),
            RemoteHelper.APP_DASHBOARD_PORT, options.verbose)
        AppScaleLogger.success("AppScale successfully started!")
        AppScaleLogger.success("View status information about your AppScale " + \
          "deployment at http://{0}:{1}/status".format(LocalState.get_login_host(
          options.keyname), RemoteHelper.APP_DASHBOARD_PORT))
        AppScaleLogger.remote_log_tools_state(options, my_id, "finished",
                                              APPSCALE_VERSION)
Пример #13
0
    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}. 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.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:
            message = RemoteHelper.collect_appcontroller_crashlog(
                public_ip, options.keyname, options.verbose)
            raise AppControllerException(message)

        return public_ip, instance_id
Пример #14
0
    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)