예제 #1
0
int main(int argc, char**argv)
{
  // Set up our exception signal handler for asserts and segfaults.
  signal(SIGABRT, signal_handler);
  signal(SIGSEGV, signal_handler);

  sem_init(&term_sem, 0, 0);
  signal(SIGTERM, terminate_handler);

  struct options options;
  options.local_host = "127.0.0.1";
  options.http_address = "0.0.0.0";
  options.http_port = 11888;
  options.http_threads = 1;
  options.http_worker_threads = 50;
  options.homestead_http_name = "homestead-http-name.unknown";
  options.digest_timeout = 300;
  options.home_domain = "home.domain";
  options.sas_server = "0.0.0.0";
  options.sas_system_name = "";
  options.access_log_enabled = false;
  options.log_to_file = false;
  options.log_level = 0;
  options.memcached_write_format = MemcachedWriteFormat::JSON;
  options.target_latency_us = 100000;
  options.max_tokens = 1000;
  options.init_token_rate = 100.0;
  options.min_token_rate = 10.0;
  options.exception_max_ttl = 600;
  options.http_blacklist_duration = HttpResolver::DEFAULT_BLACKLIST_DURATION;
  options.pidfile = "";
  options.daemon = false;

  if (init_logging_options(argc, argv, options) != 0)
  {
    return 1;
  }

  Log::setLoggingLevel(options.log_level);

  if ((options.log_to_file) && (options.log_directory != ""))
  {
    // Work out the program name from argv[0], stripping anything before the final slash.
    char* prog_name = argv[0];
    char* slash_ptr = rindex(argv[0], '/');

    if (slash_ptr != NULL)
    {
      prog_name = slash_ptr + 1;
    }

    Log::setLogger(new Logger(options.log_directory, prog_name));
  }

  TRC_STATUS("Log level set to %d", options.log_level);

  std::stringstream options_ss;

  for (int ii = 0; ii < argc; ii++)
  {
    options_ss << argv[ii];
    options_ss << " ";
  }

  std::string options_str = "Command-line options were: " + options_ss.str();

  TRC_INFO(options_str.c_str());

  if (init_options(argc, argv, options) != 0)
  {
    return 1;
  }

  if (options.daemon)
  {
    // Options parsed and validated, time to demonize before writing out our
    // pidfile or spwaning threads.
    int errnum = Utils::daemonize();
    if (errnum != 0)
    {
      TRC_ERROR("Failed to convert to daemon, %d (%s)", errnum, strerror(errnum));
      exit(0);
    }
  }

  if (options.pidfile != "")
  {
    int rc = Utils::lock_and_write_pidfile(options.pidfile);
    if (rc == -1)
    {
      // Failure to acquire pidfile lock
      TRC_ERROR("Could not write pidfile - exiting");
      return 2;
    }
  }

  start_signal_handlers();

  AccessLogger* access_logger = NULL;

  if (options.access_log_enabled)
  {
    TRC_STATUS("Access logging enabled to %s", options.access_log_directory.c_str());
    access_logger = new AccessLogger(options.access_log_directory);
  }

  HealthChecker* hc = new HealthChecker();
  hc->start_thread();

  // Create an exception handler. The exception handler doesn't need
  // to quiesce the process before killing it.
  exception_handler = new ExceptionHandler(options.exception_max_ttl,
                                           false,
                                           hc);

  SAS::init(options.sas_system_name,
            "memento",
            SASEvent::CURRENT_RESOURCE_BUNDLE,
            options.sas_server,
            sas_write,
            create_connection_in_management_namespace);

  // Ensure our random numbers are unpredictable.
  unsigned int seed;
  seed = time(NULL) ^ getpid();
  srand(seed);

  // Create alarm and communication monitor objects for the conditions
  // reported by memento.
  CommunicationMonitor* mc_comm_monitor = new CommunicationMonitor(new Alarm("memento", AlarmDef::MEMENTO_MEMCACHED_COMM_ERROR, AlarmDef::CRITICAL),
                                                                   "Memento",
                                                                   "Memcached");
  Alarm* mc_vbucket_alarm = new Alarm("memento", AlarmDef::MEMENTO_MEMCACHED_VBUCKET_ERROR, AlarmDef::MAJOR);
  CommunicationMonitor* hs_comm_monitor = new CommunicationMonitor(new Alarm("memento", AlarmDef::MEMENTO_HOMESTEAD_COMM_ERROR, AlarmDef::CRITICAL),
                                                                   "Memento",
                                                                   "Homestead");
  CommunicationMonitor* cass_comm_monitor = new CommunicationMonitor(new Alarm("memento", AlarmDef::MEMENTO_CASSANDRA_COMM_ERROR, AlarmDef::CRITICAL),
                                                                     "Memento",
                                                                     "Cassandra");

  TRC_DEBUG("Starting alarm request agent");
  AlarmReqAgent::get_instance().start();

  MemcachedStore* m_store = new MemcachedStore(true,
                                               "./cluster_settings",
                                               mc_comm_monitor,
                                               mc_vbucket_alarm);

  AuthStore::SerializerDeserializer* serializer;
  std::vector<AuthStore::SerializerDeserializer*> deserializers;

  if (options.memcached_write_format == MemcachedWriteFormat::JSON)
  {
    serializer = new AuthStore::JsonSerializerDeserializer();
  }
  else
  {
    serializer = new AuthStore::BinarySerializerDeserializer();
  }

  deserializers.push_back(new AuthStore::JsonSerializerDeserializer());
  deserializers.push_back(new AuthStore::BinarySerializerDeserializer());

  AuthStore* auth_store = new AuthStore(m_store,
                                        serializer,
                                        deserializers,
                                        options.digest_timeout);

  LoadMonitor* load_monitor = new LoadMonitor(options.target_latency_us,
                                              options.max_tokens,
                                              options.init_token_rate,
                                              options.min_token_rate);

  LastValueCache* stats_aggregator = new MementoLVC();

  // Create a DNS resolver and an HTTP specific resolver.
  int af = AF_INET;
  struct in6_addr dummy_addr;
  if (inet_pton(AF_INET6, options.local_host.c_str(), &dummy_addr) == 1)
  {
    TRC_DEBUG("Local host is an IPv6 address");
    af = AF_INET6;
  }

  DnsCachedResolver* dns_resolver = new DnsCachedResolver("127.0.0.1");
  HttpResolver* http_resolver = new HttpResolver(dns_resolver,
                                                 af,
                                                 options.http_blacklist_duration);
  HomesteadConnection* homestead_conn = new HomesteadConnection(options.homestead_http_name,
                                                                http_resolver,
                                                                load_monitor,
                                                                hs_comm_monitor);

  // Create and start the call list store.
  CallListStore::Store* call_list_store = new CallListStore::Store();
  call_list_store->configure_connection("localhost", 9160, cass_comm_monitor);

  // Test Cassandra connectivity.
  CassandraStore::ResultCode store_rc = call_list_store->connection_test();

  if (store_rc == CassandraStore::OK)
  {
    // Store can connect to Cassandra, so start it.
    store_rc = call_list_store->start();
  }

  if (store_rc != CassandraStore::OK)
  {
    TRC_ERROR("Unable to create call list store (RC = %d)", store_rc);
    exit(3);
  }

  HttpStack* http_stack = HttpStack::get_instance();
  HttpStackUtils::SimpleStatsManager stats_manager(stats_aggregator);

  CallListTask::Config call_list_config(auth_store, homestead_conn, call_list_store, options.home_domain, stats_aggregator, hc, options.api_key);

  MementoSasLogger sas_logger;
  HttpStackUtils::PingHandler ping_handler;
  HttpStackUtils::SpawningHandler<CallListTask, CallListTask::Config> call_list_handler(&call_list_config, &sas_logger);
  HttpStackUtils::HandlerThreadPool pool(options.http_worker_threads, exception_handler);

  try
  {
    http_stack->initialize();
    http_stack->configure(options.http_address,
                          options.http_port,
                          options.http_threads,
                          exception_handler,
                          access_logger,
                          load_monitor,
                          &stats_manager);
    http_stack->register_handler("^/ping$", &ping_handler);
    http_stack->register_handler("^/org.projectclearwater.call-list/users/[^/]*/call-list.xml$",
                                    pool.wrap(&call_list_handler));
    http_stack->start();
  }
  catch (HttpStack::Exception& e)
  {
    TRC_ERROR("Failed to initialize HttpStack stack - function %s, rc %d", e._func, e._rc);
    exit(2);
  }

  TRC_STATUS("Start-up complete - wait for termination signal");
  sem_wait(&term_sem);
  TRC_STATUS("Termination signal received - terminating");

  try
  {
    http_stack->stop();
    http_stack->wait_stopped();
  }
  catch (HttpStack::Exception& e)
  {
    TRC_ERROR("Failed to stop HttpStack stack - function %s, rc %d", e._func, e._rc);
  }

  call_list_store->stop();
  call_list_store->wait_stopped();

  hc->stop_thread();

  delete homestead_conn; homestead_conn = NULL;
  delete call_list_store; call_list_store = NULL;
  delete http_resolver; http_resolver = NULL;
  delete dns_resolver; dns_resolver = NULL;
  delete load_monitor; load_monitor = NULL;
  delete auth_store; auth_store = NULL;
  delete call_list_store; call_list_store = NULL;
  delete m_store; m_store = NULL;
  delete exception_handler; exception_handler = NULL;
  delete hc; hc = NULL;


  // Stop the alarm request agent
  AlarmReqAgent::get_instance().stop();

  delete mc_comm_monitor; mc_comm_monitor = NULL;
  delete mc_vbucket_alarm; mc_vbucket_alarm = NULL;
  delete hs_comm_monitor; hs_comm_monitor = NULL;
  delete cass_comm_monitor; cass_comm_monitor = NULL;

  SAS::term();

  signal(SIGTERM, SIG_DFL);
  sem_destroy(&term_sem);
}
예제 #2
0
파일: main.cpp 프로젝트: Metaswitch/memento
int main(int argc, char**argv)
{
  // Set up our exception signal handler for asserts and segfaults.
  signal(SIGABRT, signal_handler);
  signal(SIGSEGV, signal_handler);

  sem_init(&term_sem, 0, 0);
  signal(SIGTERM, terminate_handler);

  AstaireResolver* astaire_resolver = NULL;

  struct options options;
  options.local_host = "127.0.0.1";
  options.http_address = "0.0.0.0";
  options.http_port = 11888;
  options.http_threads = 1;
  options.http_worker_threads = 50;
  options.homestead_http_name = "homestead-http-name.unknown";
  options.digest_timeout = 300;
  options.home_domain = "home.domain";
  options.sas_system_name = "";
  options.access_log_enabled = false;
  options.log_to_file = false;
  options.log_level = 0;
  options.astaire = "";
  options.cassandra = "";
  options.memcached_write_format = MemcachedWriteFormat::JSON;
  options.target_latency_us = 100000;
  options.max_tokens = 1000;
  options.init_token_rate = 100.0;
  options.min_token_rate = 10.0;
  options.min_token_rate = 0.0;
  options.exception_max_ttl = 600;
  options.astaire_blacklist_duration = AstaireResolver::DEFAULT_BLACKLIST_DURATION;
  options.http_blacklist_duration = HttpResolver::DEFAULT_BLACKLIST_DURATION;
  options.pidfile = "";
  options.daemon = false;

  if (init_logging_options(argc, argv, options) != 0)
  {
    return 1;
  }

  Utils::daemon_log_setup(argc,
                          argv,
                          options.daemon,
                          options.log_directory,
                          options.log_level,
                          options.log_to_file);

  std::stringstream options_ss;

  for (int ii = 0; ii < argc; ii++)
  {
    options_ss << argv[ii];
    options_ss << " ";
  }

  std::string options_str = "Command-line options were: " + options_ss.str();

  TRC_INFO(options_str.c_str());

  if (init_options(argc, argv, options) != 0)
  {
    return 1;
  }

  if (options.pidfile != "")
  {
    int rc = Utils::lock_and_write_pidfile(options.pidfile);
    if (rc == -1)
    {
      // Failure to acquire pidfile lock
      TRC_ERROR("Could not write pidfile - exiting");
      return 2;
    }
  }

  start_signal_handlers();

  AccessLogger* access_logger = NULL;

  if (options.access_log_enabled)
  {
    TRC_STATUS("Access logging enabled to %s", options.access_log_directory.c_str());
    access_logger = new AccessLogger(options.access_log_directory);
  }

  HealthChecker* hc = new HealthChecker();
  hc->start_thread();

  // Create an exception handler. The exception handler doesn't need
  // to quiesce the process before killing it.
  exception_handler = new ExceptionHandler(options.exception_max_ttl,
                                           false,
                                           hc);

  // Initialise the SasService, to read the SAS config to pass into SAS::Init
  SasService* sas_service = new SasService(options.sas_system_name, "memento", false);

  // Ensure our random numbers are unpredictable.
  unsigned int seed;
  seed = time(NULL) ^ getpid();
  srand(seed);

  // Create a DNS resolver.
  int af = AF_INET;
  struct in6_addr dummy_addr;
  if (inet_pton(AF_INET6, options.local_host.c_str(), &dummy_addr) == 1)
  {
    TRC_DEBUG("Local host is an IPv6 address");
    af = AF_INET6;
  }

  DnsCachedResolver* dns_resolver = new DnsCachedResolver("127.0.0.1");

  // Create alarm and communication monitor objects for the conditions
  // reported by memento.
  AlarmManager* alarm_manager = new AlarmManager();
  CommunicationMonitor* astaire_comm_monitor = new CommunicationMonitor(new Alarm(alarm_manager,
                                                                                  "memento",
                                                                                  AlarmDef::MEMENTO_ASTAIRE_COMM_ERROR,
                                                                                  AlarmDef::CRITICAL),
                                                                        "Memento",
                                                                        "Astaire");
  CommunicationMonitor* hs_comm_monitor = new CommunicationMonitor(new Alarm(alarm_manager,
                                                                             "memento",
                                                                             AlarmDef::MEMENTO_HOMESTEAD_COMM_ERROR,
                                                                             AlarmDef::CRITICAL),
                                                                   "Memento",
                                                                   "Homestead");
  CommunicationMonitor* cass_comm_monitor = new CommunicationMonitor(new Alarm(alarm_manager,
                                                                               "memento",
                                                                               AlarmDef::MEMENTO_CASSANDRA_COMM_ERROR,
                                                                               AlarmDef::CRITICAL),
                                                                     "Memento",
                                                                     "Cassandra");

  astaire_resolver = new AstaireResolver(dns_resolver,
                                         af,
                                         options.astaire_blacklist_duration);

  // Default the astaire hostname to the loopback IP
  if (options.astaire == "")
  {
    if (af == AF_INET6)
    {
      options.astaire = "[::1]";
    }
    else
    {
      options.astaire = "127.0.0.1";
    }
  }

  memcached_store = (Store*)new TopologyNeutralMemcachedStore(options.astaire,
                                                              astaire_resolver,
                                                              false,
                                                              astaire_comm_monitor);

  AuthStore::SerializerDeserializer* serializer;
  std::vector<AuthStore::SerializerDeserializer*> deserializers;

  if (options.memcached_write_format == MemcachedWriteFormat::JSON)
  {
    serializer = new AuthStore::JsonSerializerDeserializer();
  }
  else
  {
    serializer = new AuthStore::BinarySerializerDeserializer();
  }

  deserializers.push_back(new AuthStore::JsonSerializerDeserializer());
  deserializers.push_back(new AuthStore::BinarySerializerDeserializer());

  AuthStore* auth_store = new AuthStore(memcached_store,
                                        serializer,
                                        deserializers,
                                        options.digest_timeout);

  LoadMonitor* load_monitor = new LoadMonitor(options.target_latency_us,
                                              options.max_tokens,
                                              options.init_token_rate,
                                              options.min_token_rate,
                                              options.max_token_rate);

  LastValueCache* stats_aggregator = new MementoLVC();

  // Create a HTTP specific resolver.
  HttpResolver* http_resolver = new HttpResolver(dns_resolver,
                                                 af,
                                                 options.http_blacklist_duration);

  HttpClient* http_client = new HttpClient(false,
                                           http_resolver,
                                           nullptr,
                                           load_monitor,
                                           SASEvent::HttpLogLevel::PROTOCOL,
                                           hs_comm_monitor);

  HttpConnection* http_connection = new HttpConnection(options.homestead_http_name,
                                                       http_client);

  HomesteadConnection* homestead_conn = new HomesteadConnection(http_connection);

  // Default to a 30s blacklist/graylist duration and port 9160
  CassandraResolver* cass_resolver = new CassandraResolver(dns_resolver,
                                                           af,
                                                           30,
                                                           30,
                                                           9160);
  // Default the cassandra hostname to the loopback IP
  if (options.cassandra == "")
  {
    if (af == AF_INET6)
    {
      options.cassandra = "[::1]";
    }
    else
    {
      options.cassandra = "127.0.0.1";
    }
  }

  // Create and start the call list store.
  CallListStore::Store* call_list_store = new CallListStore::Store();
  call_list_store->configure_connection(options.cassandra, 9160, cass_comm_monitor, cass_resolver);

  // Test Cassandra connectivity.
  CassandraStore::ResultCode store_rc = call_list_store->connection_test();

  if (store_rc == CassandraStore::OK)
  {
    // Store can connect to Cassandra, so start it.
    store_rc = call_list_store->start();
  }

  if (store_rc != CassandraStore::OK)
  {
    TRC_ERROR("Unable to create call list store (RC = %d)", store_rc);
    exit(3);
  }

  HttpStackUtils::SimpleStatsManager stats_manager(stats_aggregator);
  HttpStack* http_stack = new HttpStack(options.http_threads,
                                        exception_handler,
                                        access_logger,
                                        load_monitor,
                                        &stats_manager);

  CallListTask::Config call_list_config(auth_store, homestead_conn, call_list_store, options.home_domain, stats_aggregator, hc, options.api_key);

  MementoSasLogger sas_logger;
  HttpStackUtils::PingHandler ping_handler;
  HttpStackUtils::SpawningHandler<CallListTask, CallListTask::Config> call_list_handler(&call_list_config, &sas_logger);
  HttpStackUtils::HandlerThreadPool pool(options.http_worker_threads, exception_handler);

  try
  {
    http_stack->initialize();
    http_stack->bind_tcp_socket(options.http_address,
                                options.http_port);
    http_stack->register_handler("^/ping$", &ping_handler);
    http_stack->register_handler("^/org.projectclearwater.call-list/users/[^/]*/call-list.xml$",
                                    pool.wrap(&call_list_handler));
    http_stack->start();
  }
  catch (HttpStack::Exception& e)
  {
    TRC_ERROR("Failed to initialize HttpStack stack - function %s, rc %d", e._func, e._rc);
    exit(2);
  }

  TRC_STATUS("Start-up complete - wait for termination signal");
  sem_wait(&term_sem);
  TRC_STATUS("Termination signal received - terminating");

  try
  {
    http_stack->stop();
    http_stack->wait_stopped();
  }
  catch (HttpStack::Exception& e)
  {
    TRC_ERROR("Failed to stop HttpStack stack - function %s, rc %d", e._func, e._rc);
  }

  call_list_store->stop();
  call_list_store->wait_stopped();

  hc->stop_thread();

  delete homestead_conn; homestead_conn = NULL;
  delete http_connection; http_connection = NULL;
  delete http_client; http_client = NULL;
  delete call_list_store; call_list_store = NULL;
  delete http_resolver; http_resolver = NULL;
  delete cass_resolver; cass_resolver = NULL;
  delete dns_resolver; dns_resolver = NULL;
  delete load_monitor; load_monitor = NULL;
  delete auth_store; auth_store = NULL;
  delete call_list_store; call_list_store = NULL;
  delete astaire_resolver; astaire_resolver = NULL;
  delete memcached_store; memcached_store = NULL;
  delete exception_handler; exception_handler = NULL;
  delete hc; hc = NULL;
  delete http_stack; http_stack = NULL;

  delete astaire_comm_monitor; astaire_comm_monitor = NULL;
  delete hs_comm_monitor; hs_comm_monitor = NULL;
  delete cass_comm_monitor; cass_comm_monitor = NULL;
  delete alarm_manager; alarm_manager = NULL;

  delete sas_service; sas_service = NULL;

  signal(SIGTERM, SIG_DFL);
  sem_destroy(&term_sem);
}