Пример #1
0
    def validate_infrastructure_flags(self):
        """Validates flags corresponding to cloud infrastructures.

    Raises:
      BadConfigurationException: If the value given to us for
        infrastructure-related flags were invalid.
    """
        if not self.args.infrastructure:
            # Make sure we didn't get a machine flag, since that's infrastructure-only
            if self.args.machine:
                raise BadConfigurationException("Cannot specify a machine image " + \
                  "when infrastructure is not specified.")

            # Also make sure they gave us a valid availability zone.
            if self.args.zone:
                raise BadConfigurationException(
                    "Cannot specify an availability zone " +
                    "when infrastructure is not specified.")

            # Fail if the user is trying to use AWS Spot Instances on a virtualized
            # cluster.
            if self.args.use_spot_instances or self.args.max_spot_price:
                raise BadConfigurationException("Can't run spot instances when " + \
                  "when infrastructure is not specified.")

            # Fail if the user is trying to use persistent disks on a virtualized
            # cluster.
            if self.args.disks:
                raise BadConfigurationException("Can't specify persistent disks " + \
                  "when infrastructure is not specified.")

            # Fail if the user is trying to use an Elastic IP / Static IP on a
            # virtualized cluster.
            if self.args.static_ip:
                raise BadConfigurationException("Can't specify a static IP " + \
                  "when infrastructure is not specified.")

            return

        # Make sure the user gave us an ami/emi if running in a cloud.
        if not self.args.machine:
            raise BadConfigurationException(
                "Need a machine image (ami) " +
                "when running in a cloud infrastructure.")

        # Also make sure they gave us an availability zone if they want to use
        # persistent disks.
        if self.args.disks and not self.args.zone:
            raise BadConfigurationException(
                "Need an availability zone specified " +
                "when persistent disks are specified.")

        # In Google Compute Engine, we have to specify the availability zone.
        if self.args.infrastructure == 'gce' and not self.args.zone:
            self.args.zone = GCEAgent.DEFAULT_ZONE

        # If the user wants to use spot instances in a cloud, make sure that it's
        # EC2 (since Euca doesn't have spot instances).
        if self.args.infrastructure != 'ec2' and (self.args.use_spot_instances or \
          self.args.max_spot_price):
            raise BadConfigurationException("Can't run spot instances unless " + \
              "Amazon EC2 is the infrastructure used.")

        # If the user does want to set a max spot price, make sure they told us that
        # they want to use spot instances in the first place.
        if self.args.max_spot_price and not self.args.use_spot_instances:
            raise BadConfigurationException("Can't have a max spot instance price" + \
              " if --use_spot_instances is not set.")

        # If the user does want to use persistent disks, make sure they specified
        # them in the right format, a dictionary mapping node IDs to disk names.
        if self.args.disks:
            self.args.disks = yaml.safe_load(base64.b64decode(self.args.disks))

            if not isinstance(self.args.disks, dict):
                raise BadConfigurationException("--disks must be a dict, but was a " \
                  "{0}".format(type(self.args.disks)))

        if not self.args.instance_type:
            raise BadConfigurationException("Cannot start a cloud instance without " \
                                            "the instance type.")

        if self.args.instance_type in self.DISALLOWED_INSTANCE_TYPES and \
            not (self.args.force or self.args.test):
            LocalState.confirm_or_abort("The {0} instance type does not have " \
              "enough RAM to run Cassandra in a production setting. Please " \
              "consider using a larger instance type.".format(
              self.args.instance_type))

        if self.args.infrastructure == 'azure':
            if not self.args.azure_subscription_id:
                raise BadConfigurationException("Cannot start an Azure instance without " \
                                                "the Subscription ID.")
            if not self.args.azure_app_id:
                raise BadConfigurationException("Cannot authenticate an Azure instance " \
                                                "without the App ID.")
            if not self.args.azure_app_secret_key:
                raise BadConfigurationException("Cannot authenticate an Azure instance " \
                                                "without the App Secret Key.")
            if not self.args.azure_tenant_id:
                raise BadConfigurationException("Cannot authenticate an Azure instance " \
                                                "without the Tenant ID.")
Пример #2
0
    def down(self, clean=False, terminate=False):
        """ 'down' provides a nicer experience for users than the
    appscale-terminate-instances command, by using the configuration options
    present in the AppScalefile found in the current working directory.

    Args:
      clean: A boolean to indicate if the deployment data and metadata
        needs to be clean. This will clear the datastore.
      terminate: A boolean to indicate if instances needs to be terminated
        (valid only if we spawn instances at start).

    Raises:
      AppScalefileException: If there is no AppScalefile in the current working
      directory.
    """
        contents = self.read_appscalefile()

        # Construct a terminate-instances command from the file's contents
        command = []
        contents_as_yaml = yaml.safe_load(contents)

        if 'verbose' in contents_as_yaml and contents_as_yaml[
                'verbose'] == True:
            is_verbose = contents_as_yaml['verbose']
            command.append("--verbose")
        else:
            is_verbose = False

        if 'keyname' in contents_as_yaml:
            keyname = contents_as_yaml['keyname']
            command.append("--keyname")
            command.append(contents_as_yaml['keyname'])
        else:
            keyname = 'appscale'

        if "EC2_ACCESS_KEY" in contents_as_yaml:
            os.environ["EC2_ACCESS_KEY"] = contents_as_yaml["EC2_ACCESS_KEY"]

        if "EC2_SECRET_KEY" in contents_as_yaml:
            os.environ["EC2_SECRET_KEY"] = contents_as_yaml["EC2_SECRET_KEY"]

        if "EC2_URL" in contents_as_yaml:
            os.environ["EC2_URL"] = contents_as_yaml["EC2_URL"]

        if clean:
            if 'test' not in contents_as_yaml or contents_as_yaml[
                    'test'] != True:
                LocalState.confirm_or_abort(
                    "Clean will delete every data in the deployment.")
            all_ips = LocalState.get_all_public_ips(keyname)
            for ip in all_ips:
                RemoteHelper.ssh(ip, keyname, self.TERMINATE, is_verbose)
            AppScaleLogger.success(
                "Successfully cleaned your AppScale deployment.")

        if terminate:
            infrastructure = LocalState.get_infrastructure(keyname)
            if infrastructure != "xen" and not LocalState.are_disks_used(
                    keyname) and 'test' not in contents_as_yaml:
                LocalState.confirm_or_abort(
                    "Terminate will delete instances and the data on them.")
            command.append("--terminate")

        if 'test' in contents_as_yaml and contents_as_yaml['test'] == True:
            command.append("--test")

        # Finally, exec the command. Don't worry about validating it -
        # appscale-terminate-instances will do that for us.
        options = ParseArgs(command, "appscale-terminate-instances").args
        AppScaleTools.terminate_instances(options)

        LocalState.cleanup_appscale_files(keyname, terminate)
        AppScaleLogger.success(
            "Successfully shut down your AppScale deployment.")
Пример #3
0
  def validate_node_layout(self):
    """Checks to see if this NodeLayout represents an acceptable (new) advanced
    deployment strategy, and if so, constructs self.nodes from it.

    Returns:
      True if the deployment strategy is valid.
    Raises:
      BadConfigurationException with reason if the deployment strategy is not
        valid.
    """
    if self.input_yaml and not isinstance(self.input_yaml, list):
      return self.invalid("Node layout format was not recognized.")
    if not self.input_yaml and self.infrastructure not in \
        InfrastructureAgentFactory.VALID_AGENTS:
      # When running in a cloud, simple formats don't require an input_yaml
      return self.invalid("Node layout format was not recognized.")

    if not self.input_yaml:
      if self.infrastructure in InfrastructureAgentFactory.VALID_AGENTS:
        if not self.min_machines:
          self.invalid(self.NO_YAML_REQUIRES_MIN)

        if not self.max_machines:
          self.invalid(self.NO_YAML_REQUIRES_MAX)

        # No layout was created, so create a generic one and then allow it
        # to be validated.
        self.input_yaml = self.generate_cloud_layout()
      else:
        self.invalid(self.INPUT_YAML_REQUIRED)

    # Keep track of whether the deployment is valid while going through.
    node_hash = {}
    role_count = {
      'compute': 0,
      'shadow': 0,
      'memcache': 0,
      'taskqueue': 0,
      'zookeeper': 0,
      'login': 0,
      'db_master': 0,
      'taskqueue_master': 0
    }
    node_count = 0
    all_disks = []
    login_found = False
    # Loop through the list of "node sets", which are grouped by role.
    for node_set in self.input_yaml:
      # If the key nodes is mapped to an integer it should be a cloud
      # deployment so we will use node-ids.
      using_cloud_ids = isinstance(node_set.get('nodes'), int)

      # In cloud_ids deployments, set the fake public ips to node-#.
      if using_cloud_ids:
        ips_list = ["node-{}".format(node_count + i) \
                    for i in xrange(node_set.get('nodes'))]
        # Update node_count.
        node_count += len(ips_list)
      # Otherwise get the ips and validate them.
      else:
        ip_or_ips = node_set.get('nodes')
        ips_list = ip_or_ips if isinstance(ip_or_ips, list) else [ip_or_ips]
        # Validate that the ips_list are either node-id or ip addresses.
        if any([self.is_cloud_ip(ip) for ip in ips_list]):
          self.invalid("Role(s) {}: using node-id format is not supported"
                       " with the ips_layout format being used. Please "
                       "specify an integer or an ip address."\
                       .format(node_set.get('roles')))

        if len(ips_list) - len(set(ips_list)) > 0:
          self.invalid(self.DUPLICATE_IPS)

      # Get the roles.
      role_or_roles = node_set.get('roles')
      if len(ips_list) == 0:
        self.invalid("Node amount cannot be zero for role(s) {}."\
                     .format(role_or_roles))
      roles = role_or_roles if isinstance(role_or_roles, list) else \
        [role_or_roles]

      # Immediately fail if we have more than one node for master.
      if 'master' in roles and (self.master or len(ips_list) > 1):
        self.invalid("Only one master is allowed.")

      # Create or retrieve the nodes from the node_hash.
      nodes = [node_hash[ip] if ip in node_hash else \
               Node(ip, using_cloud_ids) for ip in ips_list]

      # Validate volume usage, there should be an equal number of volumes to
      # number of nodes.
      if node_set.get('disks', None):
        disk_or_disks = node_set.get('disks')
        disks = disk_or_disks if isinstance(disk_or_disks, list) else \
          [disk_or_disks]
        all_disks.extend(disks)
        self.validate_disks(len(nodes), disks)

        for node, disk in zip(nodes, disks):
          node.disk = disk

      instance_type = node_set.get('instance_type', self.default_instance_type)

      if self.infrastructure:
        if not instance_type:
          self.invalid("Must set a default instance type or specify instance "
                       "type per role.")

      # Check if this is an allowed instance type.
      if instance_type in ParseArgs.DISALLOWED_INSTANCE_TYPES and \
          not (self.force or self.test):
        reason = "the suggested 4GB of RAM"
        if 'database' in roles:
          reason += " to run Cassandra"
        LocalState.confirm_or_abort("The {0} instance type does not have {1}."
                                    "Please consider using a larger instance "
                                    "type.".format(instance_type, reason))
      # Assign master.
      if 'master' in roles:
        self.master = nodes[0]

      # Add the defined roles to the nodes.
      for node in nodes:
        for role in roles:
          node.add_role(role)
          if role == 'login':
            node.public_ip = self.login_host or node.public_ip
        node.instance_type = instance_type
        if not node.is_valid():
          self.invalid(",".join(node.errors()))

      # All nodes that have the same roles will be expanded the same way,
      # so get the updated list of roles from the first node.
      roles = nodes[0].roles

      # Check for login after roles have been expanded.
      if 'login' in roles and login_found:
        self.invalid("Only one login is allowed.")
      elif 'login' in roles:
        login_found = True

      # Update dictionary containing role counts.
      role_count.update({role: role_count.get(role, 0) + len(nodes)
                         for role in roles})
      # Update the node_hash with the modified nodes.
      node_hash.update({node.public_ip: node for node in nodes})

    # Make sure disks are unique.
    if all_disks:
      self.validate_disks(len(all_disks), all_disks)

    self.validate_database_replication(node_hash.values())
    # Distribute unassigned roles and validate that certain roles are filled
    # and return a list of nodes or raise BadConfigurationException.
    nodes = self.distribute_unassigned_roles(node_hash.values(), role_count)

    if self.infrastructure in InfrastructureAgentFactory.VALID_AGENTS:
      if not self.min_machines:
        self.min_machines = len(nodes)
      if not self.max_machines:
        self.max_machines = len(nodes)

    self.nodes = nodes

    return True
Пример #4
0
    def validate_node_layout(self):
        """Checks to see if this NodeLayout represents an acceptable (new) advanced
    deployment strategy, and if so, constructs self.nodes from it.

    Returns:
      True if the deployment strategy is valid.
    Raises:
      BadConfigurationException with reason if the deployment strategy is not
        valid.
    """
        if self.input_yaml and not isinstance(self.input_yaml, list):
            return self.invalid("Node layout format was not recognized.")
        if not self.input_yaml and self.infrastructure not in \
            InfrastructureAgentFactory.VALID_AGENTS:
            # When running in a cloud, simple formats don't require an input_yaml
            return self.invalid("Node layout format was not recognized.")

        if not self.input_yaml:
            if self.infrastructure in InfrastructureAgentFactory.VALID_AGENTS:
                if not self.min_machines:
                    self.invalid(self.NO_YAML_REQUIRES_MIN)

                if not self.max_machines:
                    self.invalid(self.NO_YAML_REQUIRES_MAX)

                # No layout was created, so create a generic one and then allow it
                # to be validated.
                self.input_yaml = self.generate_cloud_layout()
            else:
                self.invalid(self.INPUT_YAML_REQUIRED)

        # Keep track of whether the deployment is valid while going through.
        node_hash = {}
        role_count = {
            'compute': 0,
            'shadow': 0,
            'memcache': 0,
            'taskqueue': 0,
            'zookeeper': 0,
            'login': 0,
            'db_master': 0,
            'taskqueue_master': 0
        }
        node_count = 0
        all_disks = []
        login_found = False
        # Loop through the list of "node sets", which are grouped by role.
        for node_set in self.input_yaml:
            # If the key nodes is mapped to an integer it should be a cloud
            # deployment so we will use node-ids.
            using_cloud_ids = isinstance(node_set.get('nodes'), int)

            # In cloud_ids deployments, set the fake public ips to node-#.
            if using_cloud_ids:
                ips_list = ["node-{}".format(node_count + i) \
                            for i in xrange(node_set.get('nodes'))]
                # Update node_count.
                node_count += len(ips_list)
            # Otherwise get the ips and validate them.
            else:
                ip_or_ips = node_set.get('nodes')
                ips_list = ip_or_ips if isinstance(ip_or_ips,
                                                   list) else [ip_or_ips]
                # Validate that the ips_list are either node-id or ip addresses.
                if any([self.is_cloud_ip(ip) for ip in ips_list]):
                    self.invalid("Role(s) {}: using node-id format is not supported"
                                 " with the ips_layout format being used. Please "
                                 "specify an integer or an ip address."\
                                 .format(node_set.get('roles')))

                if len(ips_list) - len(set(ips_list)) > 0:
                    self.invalid(self.DUPLICATE_IPS)

            # Get the roles.
            role_or_roles = node_set.get('roles')
            if len(ips_list) == 0:
                self.invalid("Node amount cannot be zero for role(s) {}."\
                             .format(role_or_roles))
            roles = role_or_roles if isinstance(role_or_roles, list) else \
              [role_or_roles]

            # Immediately fail if we have more than one node for master.
            if 'master' in roles and (self.master or len(ips_list) > 1):
                self.invalid("Only one master is allowed.")

            # Create or retrieve the nodes from the node_hash.
            nodes = [node_hash[ip] if ip in node_hash else \
                     Node(ip, using_cloud_ids) for ip in ips_list]

            # Validate volume usage, there should be an equal number of volumes to
            # number of nodes.
            if node_set.get('disks', None):
                disk_or_disks = node_set.get('disks')
                disks = disk_or_disks if isinstance(disk_or_disks, list) else \
                  [disk_or_disks]
                all_disks.extend(disks)
                self.validate_disks(len(nodes), disks)

                for node, disk in zip(nodes, disks):
                    node.disk = disk

            instance_type = node_set.get('instance_type',
                                         self.default_instance_type)

            if self.infrastructure:
                if not instance_type:
                    self.invalid(
                        "Must set a default instance type or specify instance "
                        "type per role.")

            # Check if this is an allowed instance type.
            if instance_type in ParseArgs.DISALLOWED_INSTANCE_TYPES and \
                not (self.force or self.test):
                reason = "the suggested 4GB of RAM"
                if 'database' in roles:
                    reason += " to run Cassandra"
                LocalState.confirm_or_abort(
                    "The {0} instance type does not have {1}."
                    "Please consider using a larger instance "
                    "type.".format(instance_type, reason))
            # Assign master.
            if 'master' in roles:
                self.master = nodes[0]

            # Add the defined roles to the nodes.
            for node in nodes:
                for role in roles:
                    node.add_role(role)
                    if role == 'login':
                        node.public_ip = self.login_host or node.public_ip
                node.instance_type = instance_type
                if not node.is_valid():
                    self.invalid(",".join(node.errors()))

            # All nodes that have the same roles will be expanded the same way,
            # so get the updated list of roles from the first node.
            roles = nodes[0].roles

            # Check for login after roles have been expanded.
            if 'login' in roles and login_found:
                self.invalid("Only one login is allowed.")
            elif 'login' in roles:
                login_found = True

            # Update dictionary containing role counts.
            role_count.update(
                {role: role_count.get(role, 0) + len(nodes)
                 for role in roles})
            # Update the node_hash with the modified nodes.
            node_hash.update({node.public_ip: node for node in nodes})

        # Make sure disks are unique.
        if all_disks:
            self.validate_disks(len(all_disks), all_disks)

        self.validate_database_replication(node_hash.values())
        # Distribute unassigned roles and validate that certain roles are filled
        # and return a list of nodes or raise BadConfigurationException.
        nodes = self.distribute_unassigned_roles(node_hash.values(),
                                                 role_count)

        if self.infrastructure in InfrastructureAgentFactory.VALID_AGENTS:
            if not self.min_machines:
                self.min_machines = len(nodes)
            if not self.max_machines:
                self.max_machines = len(nodes)

        self.nodes = nodes

        return True
Пример #5
0
    def validate_infrastructure_flags(self):
        """Validates flags corresponding to cloud infrastructures.

    Raises:
      BadConfigurationException: If the value given to us for
        infrastructure-related flags were invalid.
    """
        if not self.args.infrastructure:
            # Make sure we didn't get a machine flag, since that's infrastructure-only
            if self.args.machine:
                raise BadConfigurationException(
                    "Cannot specify a machine image " + "when infrastructure is not specified."
                )

            # Also make sure they gave us a valid availability zone.
            if self.args.zone:
                raise BadConfigurationException(
                    "Cannot specify an availability zone " + "when infrastructure is not specified."
                )

            # Fail if the user is trying to use AWS Spot Instances on a virtualized
            # cluster.
            if self.args.use_spot_instances or self.args.max_spot_price:
                raise BadConfigurationException(
                    "Can't run spot instances when " + "when infrastructure is not specified."
                )

            # Fail if the user is trying to use persistent disks on a virtualized
            # cluster.
            if self.args.disks:
                raise BadConfigurationException(
                    "Can't specify persistent disks " + "when infrastructure is not specified."
                )

            # Fail if the user is trying to use an Elastic IP / Static IP on a
            # virtualized cluster.
            if self.args.static_ip:
                raise BadConfigurationException("Can't specify a static IP " + "when infrastructure is not specified.")

            return

        # Make sure the user gave us an ami/emi if running in a cloud.
        if not self.args.machine:
            raise BadConfigurationException("Need a machine image (ami) " + "when running in a cloud infrastructure.")

        # Also make sure they gave us an availability zone if they want to use
        # persistent disks.
        if self.args.disks and not self.args.zone:
            raise BadConfigurationException(
                "Need an availability zone specified " + "when persistent disks are specified."
            )

        # In Google Compute Engine, we have to specify the availability zone.
        if self.args.infrastructure == "gce" and not self.args.zone:
            self.args.zone = GCEAgent.DEFAULT_ZONE

        # If the user wants to use spot instances in a cloud, make sure that it's
        # EC2 (since Euca doesn't have spot instances).
        if self.args.infrastructure != "ec2" and (self.args.use_spot_instances or self.args.max_spot_price):
            raise BadConfigurationException(
                "Can't run spot instances unless " + "Amazon EC2 is the infrastructure used."
            )

        # If the user does want to set a max spot price, make sure they told us that
        # they want to use spot instances in the first place.
        if self.args.max_spot_price and not self.args.use_spot_instances:
            raise BadConfigurationException(
                "Can't have a max spot instance price" + " if --use_spot_instances is not set."
            )

        # If the user does want to use persistent disks, make sure they specified
        # them in the right format, a dictionary mapping node IDs to disk names.
        if self.args.disks:
            self.args.disks = yaml.safe_load(base64.b64decode(self.args.disks))

            if not isinstance(self.args.disks, dict):
                raise BadConfigurationException(
                    "--disks must be a dict, but was a " "{0}".format(type(self.args.disks))
                )

        if self.args.instance_type in EC2Agent.DISALLOWED_INSTANCE_TYPES and not (self.args.force or self.args.test):
            LocalState.confirm_or_abort(
                "The {0} instance type does not have "
                "enough RAM to run Cassandra in a production setting. Please "
                "consider using a larger instance type.".format(self.args.instance_type)
            )

        if self.args.gce_instance_type in GCEAgent.DISALLOWED_INSTANCE_TYPES and not (
            self.args.force or self.args.test
        ):
            LocalState.confirm_or_abort(
                "The {0} instance type does not have "
                "enough RAM to run Cassandra in a production setting. Please "
                "consider using a larger instance type.".format(self.args.gce_instance_type)
            )
Пример #6
0
  def validate_infrastructure_flags(self):
    """Validates flags corresponding to cloud infrastructures.

    Raises:
      BadConfigurationException: If the value given to us for
        infrastructure-related flags were invalid.
    """
    if not self.args.infrastructure:
      # Make sure we didn't get a machine flag, since that's infrastructure-only
      if self.args.machine:
        raise BadConfigurationException("Cannot specify a machine image " + \
          "when infrastructure is not specified.")

      # Also make sure they gave us a valid availability zone.
      if self.args.zone:
        raise BadConfigurationException("Cannot specify an availability zone " +
          "when infrastructure is not specified.")

      # Fail if the user is trying to use AWS Spot Instances on a virtualized
      # cluster.
      if self.args.use_spot_instances or self.args.max_spot_price:
        raise BadConfigurationException("Can't run spot instances when " + \
          "when infrastructure is not specified.")

      # Fail if the user is trying to use persistent disks on a virtualized
      # cluster.
      if self.args.disks:
        raise BadConfigurationException("Can't specify persistent disks " + \
          "when infrastructure is not specified.")

      # Fail if the user is trying to use an Elastic IP / Static IP on a
      # virtualized cluster.
      if self.args.static_ip:
        raise BadConfigurationException("Can't specify a static IP " + \
          "when infrastructure is not specified.")

      return

    # Make sure the user gave us an ami/emi if running in a cloud.
    if not self.args.machine:
      raise BadConfigurationException("Need a machine image (ami) " +
        "when running in a cloud infrastructure.")

    # Also make sure they gave us an availability zone if they want to use
    # persistent disks.
    if self.args.disks and not self.args.zone:
      raise BadConfigurationException("Need an availability zone specified " +
        "when persistent disks are specified.")

    # In Google Compute Engine, we have to specify the availability zone.
    if self.args.infrastructure == 'gce' and not self.args.zone:
      self.args.zone = GCEAgent.DEFAULT_ZONE

    # If the user wants to use spot instances in a cloud, make sure that it's
    # EC2 (since Euca doesn't have spot instances).
    if self.args.infrastructure != 'ec2' and (self.args.use_spot_instances or \
      self.args.max_spot_price):
      raise BadConfigurationException("Can't run spot instances unless " + \
        "Amazon EC2 is the infrastructure used.")

    # If the user does want to set a max spot price, make sure they told us that
    # they want to use spot instances in the first place.
    if self.args.max_spot_price and not self.args.use_spot_instances:
      raise BadConfigurationException("Can't have a max spot instance price" + \
        " if --use_spot_instances is not set.")

    # If the user does want to use persistent disks, make sure they specified
    # them in the right format, a dictionary mapping node IDs to disk names.
    if self.args.disks:
      self.args.disks = yaml.safe_load(base64.b64decode(self.args.disks))

      if not isinstance(self.args.disks, dict):
        raise BadConfigurationException("--disks must be a dict, but was a " \
          "{0}".format(type(self.args.disks)))

    if self.args.instance_type in self.DISALLOWED_INSTANCE_TYPES and \
        not (self.args.force or self.args.test):
      LocalState.confirm_or_abort("The {0} instance type does not have "
        "the suggested 4GB of RAM. Please consider using a larger instance "
        "type.".format(self.args.instance_type))

    if self.args.infrastructure == 'azure':
      if not self.args.azure_subscription_id:
        raise BadConfigurationException("Cannot start an Azure instance without " \
                                        "the Subscription ID.")
      if not self.args.azure_app_id:
        raise BadConfigurationException("Cannot authenticate an Azure instance " \
                                        "without the App ID.")
      if not self.args.azure_app_secret_key:
        raise BadConfigurationException("Cannot authenticate an Azure instance " \
                                        "without the App Secret Key.")
      if not self.args.azure_tenant_id:
        raise BadConfigurationException("Cannot authenticate an Azure instance " \
                                        "without the Tenant ID.")
    elif self.args.infrastructure in ['euca', 'ec2']:
      if not (self.args.EC2_ACCESS_KEY and self.args.EC2_SECRET_KEY):
        raise BadConfigurationException("Both EC2_ACCESS_KEY and "
                                        "EC2_SECRET_KEY must be specified.")
Пример #7
0
  def down(self, clean=False, terminate=False):
    """ 'down' provides a nicer experience for users than the
    appscale-terminate-instances command, by using the configuration options
    present in the AppScalefile found in the current working directory.

    Args:
      clean: A boolean to indicate if the deployment data and metadata
        needs to be clean. This will clear the datastore.
      terminate: A boolean to indicate if instances needs to be terminated
        (valid only if we spawn instances at start).

    Raises:
      AppScalefileException: If there is no AppScalefile in the current working
      directory.
    """
    contents = self.read_appscalefile()

    # Construct a terminate-instances command from the file's contents
    command = []
    contents_as_yaml = yaml.safe_load(contents)

    if 'verbose' in contents_as_yaml and contents_as_yaml['verbose'] == True:
      is_verbose = contents_as_yaml['verbose']
      command.append("--verbose")
    else:
      is_verbose = False

    if 'keyname' in contents_as_yaml:
      keyname = contents_as_yaml['keyname']
      command.append("--keyname")
      command.append(contents_as_yaml['keyname'])
    else:
      keyname = 'appscale'

    if "EC2_ACCESS_KEY" in contents_as_yaml:
      os.environ["EC2_ACCESS_KEY"] = contents_as_yaml["EC2_ACCESS_KEY"]

    if "EC2_SECRET_KEY" in contents_as_yaml:
      os.environ["EC2_SECRET_KEY"] = contents_as_yaml["EC2_SECRET_KEY"]

    if "EC2_URL" in contents_as_yaml:
      os.environ["EC2_URL"] = contents_as_yaml["EC2_URL"]

    if clean:
      if 'test' not in contents_as_yaml or contents_as_yaml['test'] != True:
        LocalState.confirm_or_abort("Clean will delete every data in the deployment.")
      all_ips = LocalState.get_all_public_ips(keyname)
      for ip in all_ips:
        RemoteHelper.ssh(ip, keyname, self.TERMINATE, is_verbose)
      AppScaleLogger.success("Successfully cleaned your AppScale deployment.")

    if terminate:
      infrastructure = LocalState.get_infrastructure(keyname)
      if infrastructure != "xen" and not LocalState.are_disks_used(
        keyname) and 'test' not in contents_as_yaml:
        LocalState.confirm_or_abort("Terminate will delete instances and the data on them.")
      command.append("--terminate")

    if 'test' in contents_as_yaml and contents_as_yaml['test'] == True:
      command.append("--test")

    # Finally, exec the command. Don't worry about validating it -
    # appscale-terminate-instances will do that for us.
    options = ParseArgs(command, "appscale-terminate-instances").args
    AppScaleTools.terminate_instances(options)

    LocalState.cleanup_appscale_files(keyname, terminate)
    AppScaleLogger.success("Successfully shut down your AppScale deployment.")