Ejemplo n.º 1
0
def start_cassandra(db_ips, db_master, keyname):
  """ Creates a monit configuration file and prompts Monit to start Cassandra.
  Args:
    db_ips: A list of database node IPs to start Cassandra on.
    db_master: The IP address of the DB master.
    keyname: A string containing the deployment's keyname.
  Raises:
    AppScaleDBError if unable to start Cassandra.
  """
  logging.info("Starting Cassandra...")
  for ip in db_ips:
    init_config = '{script} --local-ip {ip} --master-ip {db_master}'.format(
      script=SETUP_CASSANDRA_SCRIPT, ip=ip, db_master=db_master)
    try:
      utils.ssh(ip, keyname, init_config)
    except subprocess.CalledProcessError:
      message = 'Unable to configure Cassandra on {}'.format(ip)
      logging.exception(message)
      raise dbconstants.AppScaleDBError(message)

    try:
      start_service_cmd = START_SERVICE_SCRIPT + CASSANDRA_WATCH_NAME
      utils.ssh(ip, keyname, start_service_cmd)
    except subprocess.CalledProcessError:
      message = 'Unable to start Cassandra on {}'.format(ip)
      logging.exception(message)
      raise dbconstants.AppScaleDBError(message)

  logging.info('Waiting for Cassandra to be ready')
  status_cmd = '{} status'.format(cassandra_interface.NODE_TOOL)
  while (utils.ssh(db_master, keyname, status_cmd,
                   method=subprocess.call) != 0):
    time.sleep(5)

  logging.info("Successfully started Cassandra.")
Ejemplo n.º 2
0
def wait_for_quorum(keyname, db_nodes, replication):
  """ Waits until enough Cassandra nodes are up for a quorum.

  Args:
    keyname: A string containing the deployment's keyname.
    db_nodes: An integer specifying the total number of DB nodes.
    replication: An integer specifying the keyspace replication factor.
  """
  command = cassandra_interface.NODE_TOOL + " " + 'status'
  key_file = '{}/{}.key'.format(utils.KEY_DIRECTORY, keyname)
  ssh_cmd = ['ssh', '-i', key_file, appscale_info.get_db_master_ip(), command]

  # Determine the number of nodes needed for a quorum.
  if db_nodes < 1 or replication < 1:
    raise dbconstants.AppScaleDBError('At least 1 database machine is needed.')
  if replication > db_nodes:
    raise dbconstants.AppScaleDBError(
      'The replication factor cannot exceed the number of database machines.')
  can_fail = math.ceil(replication/2.0 - 1)
  needed = int(db_nodes - can_fail)

  while True:
    output = subprocess.check_output(ssh_cmd)
    nodes_ready = len(
      [line for line in output.splitlines() if line.startswith('UN')])
    logging.info('{} nodes are up. {} are needed.'.format(nodes_ready, needed))
    if nodes_ready >= needed:
      break
    time.sleep(1)
Ejemplo n.º 3
0
def estimate_total_entities(session, db_master, keyname):
  """ Estimate the total number of entities.

  Args:
    session: A cassandra-driver session.
    db_master: A string containing the IP address of the primary DB node.
    keyname: A string containing the deployment keyname.
  Returns:
    A string containing an entity count.
  Raises:
    AppScaleDBError if unable to get a count.
  """
  query = SimpleStatement(
    'SELECT COUNT(*) FROM "{}"'.format(dbconstants.APP_ENTITY_TABLE),
    consistency_level=ConsistencyLevel.ONE
  )
  try:
    rows = session.execute(query)[0].count
    return str(rows / len(dbconstants.APP_ENTITY_SCHEMA))
  except dbconstants.TRANSIENT_CASSANDRA_ERRORS:
    stats_cmd = '{nodetool} cfstats {keyspace}.{table}'.format(
      nodetool=cassandra_interface.NODE_TOOL,
      keyspace=cassandra_interface.KEYSPACE,
      table=dbconstants.APP_ENTITY_TABLE)
    stats = utils.ssh(db_master, keyname, stats_cmd,
                      method=subprocess.check_output)
    for line in stats.splitlines():
      if 'Number of keys (estimate)' in line:
        return '{} (estimate)'.format(line.split()[-1])
  raise dbconstants.AppScaleDBError('Unable to estimate total entities.')