Beispiel #1
0
    def test_mirror_updater(self):
        """
    Tests MirrorUpdater update flag status and command contents when creating,
    adding, removing, and eliminating endpoints.
    """
        static_source_config = json.dumps(
            {
                "source_class": "tellapart.aurproxy.source.StaticProxySource",
                "host": "127.0.0.1",
                "name": "base",
                "port": 80,
            }
        )

        template_path = "../templates/gor/mirror.sh.template"

        # Load up a mirror updater
        mirror_updater = load_mirror_updater(
            source=static_source_config,
            ports="8080,8081",
            max_qps=100,
            max_update_frequency=15,
            command_template_path=template_path,
            pid_path="/tmp/gor-mirror.pid",
        )

        # Patch in the dummy update function
        funcType = type(MirrorUpdater.update)
        mirror_updater.update = funcType(dummy_update, mirror_updater, MirrorUpdater)

        # Correct the template path for test time
        template_path = os.path.join(os.path.dirname(__file__), "../../templates/gor/mirror.sh.template")
        mirror_updater._template_path = template_path

        # Check that update signals flow correctly through to command
        # Initial setup
        self.assertTrue(mirror_updater._should_update())
        mirror_updater.set_up()
        self.assertTrue("127.0.0.1:80" in mirror_updater._generate_command())
        self.assertFalse(mirror_updater._should_update())

        # Add a new endpoint
        mirror_updater._source.add(SourceEndpoint("127.0.0.1", 81))
        self.assertTrue(mirror_updater._should_update())
        mirror_updater.update()
        self.assertTrue("127.0.0.1:81" in mirror_updater._generate_command())
        self.assertFalse(mirror_updater._should_update())

        # Remove the new endpoint
        mirror_updater._source.remove(SourceEndpoint("127.0.0.1", 81))
        self.assertTrue(mirror_updater._should_update())
        mirror_updater.update()
        self.assertTrue("127.0.0.1:81" not in mirror_updater._generate_command())

        # Remove the only remaining endpoint
        mirror_updater._source.remove(SourceEndpoint("127.0.0.1", 80))
        self.assertTrue(mirror_updater._should_update())
        mirror_updater.update()
        self.assertTrue("127.0.0.1:80" not in mirror_updater._generate_command())
        self.assertTrue(_FALLBACK_MSG in mirror_updater._generate_command())
Beispiel #2
0
def run_replay(management_port,
               replay_port,
               replay_source,
               replay_max_qps,
               replay_max_update_frequency=_DEFAULT_REPLAY_MAX_UPDATE_FREQUENCY,
               replay_pid_path=_MIRROR_PID_PATH,
               metric_publisher_class=_DEFAULT_METRIC_PUBLISHER_CLASS,
               metric_publisher_arg=_DEFAULT_METRIC_PUBLISHER_KWARGS,
               sentry_dsn=None,
               setup=False):
  """Run the Aurproxy traffic replay server manager.

  Args:
    management_port - int - port for the manager application to listen on for
      Aurora lifecycle queries and events (/health, /quitquit, etc.).
    replay_port - int - port on which the replay server to listen on for a
      mirrored traffic stream.
    replay_source - JSON string - Source configuration to which gor replay
      server will send traffic.
    replay_max_qps - maximum QPS to replay to listeners.
    replay_max_update_frequency - Max QPS to replay to source endpoints.
    metric_publisher_class - str - Python class path for metrics publisher
      class.
    metric_publisher_arg - list(str) - List of equal-sign-delimited string
      kwarg pairs.
      Example:
        ["source=cluster.role.environment.job"]
    sentry_dsn - str - Sentry DSN for error logging.
    setup - bool - When run in setup mode, aurproxy will render a configuration
      for the replay server once and then exit. Run aurproxy once in setup mode
      to set up the replay server, then start aurproxy and the replay server
      together.
  """
  try:
    source_dict = json.loads(replay_source)
  except (TypeError, ValueError):
    raise commandr.CommandrUsageError('Invalid JSON configuration specified via --replay_source')

  source = load_klass_plugin(source_dict, klass_field_name='source_class')
  mirror_updater = load_mirror_updater(source,
                                       replay_port,
                                       replay_max_qps,
                                       replay_max_update_frequency,
                                       _REPLAY_COMMAND_TEMPLATE_PATH,
                                       replay_pid_path)
  if setup:
    mirror_updater.update(kill_running=False)
  else:
    if metric_publisher_class:
      _setup_metrics(metric_publisher_class, metric_publisher_arg)
    mirror_updater.start()
    _start_web(management_port, sentry_dsn, mirror_updater.blueprints)
Beispiel #3
0
def run_replay(
        management_port,
        replay_port,
        replay_source,
        replay_max_qps,
        replay_max_update_frequency=_DEFAULT_REPLAY_MAX_UPDATE_FREQUENCY,
        replay_pid_path=_MIRROR_PID_PATH,
        metric_publisher_class=_DEFAULT_METRIC_PUBLISHER_CLASS,
        metric_publisher_arg=_DEFAULT_METRIC_PUBLISHER_KWARGS,
        sentry_dsn=None,
        setup=False):
    """Run the Aurproxy traffic replay server manager.

  Args:
    management_port - int - port for the manager application to listen on for
      Aurora lifecycle queries and events (/health, /quitquit, etc.).
    replay_port - int - port on which the replay server to listen on for a
      mirrored traffic stream.
    replay_source - JSON string - Source configuration to which gor replay
      server will send traffic.
    replay_max_qps - maximum QPS to replay to listeners.
    replay_max_update_frequency - Max QPS to replay to source endpoints.
    metric_publisher_class - str - Python class path for metrics publisher
      class.
    metric_publisher_arg - list(str) - List of equal-sign-delimited string
      kwarg pairs.
      Example:
        ["source=cluster.role.environment.job"]
    sentry_dsn - str - Sentry DSN for error logging.
    setup - bool - When run in setup mode, aurproxy will render a configuration
      for the replay server once and then exit. Run aurproxy once in setup mode
      to set up the replay server, then start aurproxy and the replay server
      together.
  """
    try:
        source_dict = json.loads(replay_source)
    except (TypeError, ValueError):
        raise commandr.CommandrUsageError(
            'Invalid JSON configuration specified via --replay_source')

    source = load_klass_plugin(source_dict, klass_field_name='source_class')
    mirror_updater = load_mirror_updater(source, replay_port, replay_max_qps,
                                         replay_max_update_frequency,
                                         _REPLAY_COMMAND_TEMPLATE_PATH,
                                         replay_pid_path)
    if setup:
        mirror_updater.update(kill_running=False)
    else:
        if metric_publisher_class:
            _setup_metrics(metric_publisher_class, metric_publisher_arg)
        mirror_updater.start()
        _start_web(management_port, sentry_dsn, mirror_updater.blueprints)
Beispiel #4
0
def run(management_port,
        config,
        backend=_DEFAULT_BACKEND,
        update_period=_DEFAULT_UPDATE_PERIOD,
        max_update_frequency=_DEFAULT_MAX_UPDATE_FREQUENCY,
        weight_adjustment_delay_seconds=_DEFAULT_WEIGHT_ADJUSTMENT_DELAY_SEC,
        registration_class=_DEFAULT_REGISTRATION_CLASS,
        registration_arg=_DEFAULT_REGISTRATION_KWARGS,
        metric_publisher_class=_DEFAULT_METRIC_PUBLISHER_CLASS,
        metric_publisher_arg=_DEFAULT_METRIC_PUBLISHER_KWARGS,
        mirror_source=_DEFAULT_MIRROR_SOURCE,
        mirror_ports=_DEFAULT_MIRROR_PORTS,
        mirror_max_qps=_DEFAULT_MIRROR_MAX_QPS,
        mirror_max_update_frequency=_DEFAULT_MIRROR_MAX_UPDATE_FREQUENCY,
        mirror_pid_path=_MIRROR_PID_PATH,
        sentry_dsn=None,
        setup=False):
  """Run the Aurproxy load balancer manager.

  Args:
    management_port - int - port for the manager application to listen on for
      Aurora lifecycle queries and events (/health, /quitquit, etc.).
    config - JSON String - Load balancer configuration. See README.md for
      detailed documentation.
    backend - Load balancer manager backend to use. EG: "nginx".
    update_period - int - frequency with which the need to update is checked.
    max_update_frequency - int - minimum number of seconds between updates.
    weight_adjustment_delay_seconds - int - number of seconds to wait before
      starting configured share adjusters. May not want them running
      immediately after aurproxy deploys.
    registration_class - str - Python class path for registration class.
    registration_arg - list(str) - List of equal-sign-delimited string kwarg
      pairs.
      Example:
        ["domain=myapp.mydomain.com", "type=A"]
    metric_publisher_class - str - Python class path for metrics publisher
      class.
    metric_publisher_arg - list(str) - List of equal-sign-delimited string
      kwarg pairs.
      Example:
        ["source=cluster.role.environment.job"]
    mirror_source - JSON String - Source configuration for gor repeater to
      which http traffic should be mirrored.
    mirror_ports - Comma separated integer string - Local ports to mirror.
      Example: "8080,8081"
    mirror_max_qps - Max QPS to mirror to gor repeater.
    mirror_max_update_frequency - integer - number of seconds between updates
      of mirror configuration.
    sentry_dsn - str - Sentry DSN for error logging.
    setup - bool - When run in setup mode, aurproxy will render a configuration
     for the managed load balancer once and then exit. Run aurproxy once in
     setup mode to set up the load balancer, then start aurproxy and the load
     balancer together.
  """
  # Set up sentry error logging
  if sentry_dsn:
    setup_sentry(sentry_dsn)

  # Load config
  try:
    proxy_config = json.loads(config)
  except (TypeError, ValueError):
    raise commandr.CommandrUsageError('Invalid JSON configuration specified via --config')

  # Set up updater
  try:
    proxy_updater = ProxyUpdater(backend, proxy_config, update_period,
                               max_update_frequency)
  except AurProxyConfigException as exc:
    raise commandr.CommandrUsageError(
      'Invalid configuration: {}'.format(str(exc)),
    )

  # Set up mirroring
  mirror_updater = None
  if mirror_source:
    mirror_updater = load_mirror_updater(mirror_source,
                                         mirror_ports,
                                         mirror_max_qps,
                                         mirror_max_update_frequency,
                                         _MIRROR_COMMAND_TEMPLATE_PATH,
                                         mirror_pid_path)

  if setup:
    proxy_updater.set_up()
    if mirror_updater:
      mirror_updater.set_up()
  else:
    # Set up metrics
    set_root_prefix('aurproxy')
    if metric_publisher_class:
      _setup_metrics(metric_publisher_class, metric_publisher_arg)

    # Set up registration
    if registration_class:
      try:
        registerer = load_cli_plugin(registration_class, registration_arg)
        registerer.add()
        register_shutdown_handler(registerer.remove)
      except Exception:
        logger.exception('Registration failure.')
        raise

    # Start the updaters and extract blueprints
    proxy_updater.start(weight_adjustment_delay_seconds)
    blueprints = proxy_updater.blueprints
    if mirror_updater:
      mirror_updater.start()
      blueprints += mirror_updater.blueprints

    _start_web(management_port, sentry_dsn, blueprints)
Beispiel #5
0
def run(management_port,
        config,
        backend=_DEFAULT_BACKEND,
        update_period=_DEFAULT_UPDATE_PERIOD,
        max_update_frequency=_DEFAULT_MAX_UPDATE_FREQUENCY,
        weight_adjustment_delay_seconds=_DEFAULT_WEIGHT_ADJUSTMENT_DELAY_SEC,
        registration_class=_DEFAULT_REGISTRATION_CLASS,
        registration_arg=_DEFAULT_REGISTRATION_KWARGS,
        metric_publisher_class=_DEFAULT_METRIC_PUBLISHER_CLASS,
        metric_publisher_arg=_DEFAULT_METRIC_PUBLISHER_KWARGS,
        mirror_source=_DEFAULT_MIRROR_SOURCE,
        mirror_ports=_DEFAULT_MIRROR_PORTS,
        mirror_max_qps=_DEFAULT_MIRROR_MAX_QPS,
        mirror_max_update_frequency=_DEFAULT_MIRROR_MAX_UPDATE_FREQUENCY,
        mirror_pid_path=_MIRROR_PID_PATH,
        sentry_dsn=None,
        setup=False):
    """Run the Aurproxy load balancer manager.

  Args:
    management_port - int - port for the manager application to listen on for
      Aurora lifecycle queries and events (/health, /quitquit, etc.).
    config - JSON String or file:// location of a JSON document - Load balancer
      configuration. See README.md for detailed documentation.
    backend - Load balancer manager backend to use. EG: "nginx".
    update_period - int - frequency with which the need to update is checked.
    max_update_frequency - int - minimum number of seconds between updates.
    weight_adjustment_delay_seconds - int - number of seconds to wait before
      starting configured share adjusters. May not want them running
      immediately after aurproxy deploys.
    registration_class - str - Python class path for registration class.
    registration_arg - list(str) - List of equal-sign-delimited string kwarg
      pairs.
      Example:
        ["domain=myapp.mydomain.com", "type=A"]
    metric_publisher_class - str - Python class path for metrics publisher
      class.
    metric_publisher_arg - list(str) - List of equal-sign-delimited string
      kwarg pairs.
      Example:
        ["source=cluster.role.environment.job"]
    mirror_source - JSON String - Source configuration for gor repeater to
      which http traffic should be mirrored.
    mirror_ports - Comma separated integer string - Local ports to mirror.
      Example: "8080,8081"
    mirror_max_qps - Max QPS to mirror to gor repeater.
    mirror_max_update_frequency - integer - number of seconds between updates
      of mirror configuration.
    sentry_dsn - str - Sentry DSN for error logging.
    setup - bool - When run in setup mode, aurproxy will render a configuration
     for the managed load balancer once and then exit. Run aurproxy once in
     setup mode to set up the load balancer, then start aurproxy and the load
     balancer together.
  """
    # Set up sentry error logging
    if sentry_dsn:
        setup_sentry(sentry_dsn)

    # Load config
    try:
        if config.startswith('file://'):
            with open(config.split('file://', 1)[1]) as config_fh:
                proxy_config = json.load(config_fh)
        else:
            proxy_config = json.loads(config)
    except (TypeError, ValueError):
        raise commandr.CommandrUsageError(
            'Invalid JSON configuration specified via --config')
    except IOError as err:
        raise commandr.CommandrUsageError('Failed to read --config file: %s' %
                                          err)

    # Set up updater
    try:
        proxy_updater = ProxyUpdater(backend, proxy_config, update_period,
                                     max_update_frequency)
    except AurProxyConfigException as exc:
        raise commandr.CommandrUsageError(
            'Invalid configuration: {}'.format(str(exc)), )

    # Set up mirroring
    mirror_updater = None
    if mirror_source:
        mirror_updater = load_mirror_updater(mirror_source, mirror_ports,
                                             mirror_max_qps,
                                             mirror_max_update_frequency,
                                             _MIRROR_COMMAND_TEMPLATE_PATH,
                                             mirror_pid_path)

    if setup:
        proxy_updater.set_up()
        if mirror_updater:
            mirror_updater.set_up()
    else:
        # Set up metrics
        set_root_prefix('aurproxy')
        if metric_publisher_class:
            _setup_metrics(metric_publisher_class, metric_publisher_arg)

        # Set up registration
        if registration_class:
            try:
                registerer = load_cli_plugin(registration_class,
                                             registration_arg)
                registerer.add()
                register_shutdown_handler(registerer.remove)
            except Exception:
                logger.exception('Registration failure.')
                raise

        # Start the updaters and extract blueprints
        proxy_updater.start(weight_adjustment_delay_seconds)
        blueprints = proxy_updater.blueprints
        if mirror_updater:
            mirror_updater.start()
            blueprints += mirror_updater.blueprints

        _start_web(management_port, sentry_dsn, blueprints)
Beispiel #6
0
    def test_mirror_updater(self):
        '''
    Tests MirrorUpdater update flag status and command contents when creating,
    adding, removing, and eliminating endpoints.
    '''
        static_source_config = json.dumps({
            "source_class": "tellapart.aurproxy.source.StaticProxySource",
            "host": "127.0.0.1",
            "name": "base",
            "port": 80
        })

        template_path = '../templates/gor/mirror.sh.template'

        # Load up a mirror updater
        mirror_updater = load_mirror_updater(
            source=static_source_config,
            ports='8080,8081',
            max_qps=100,
            max_update_frequency=15,
            command_template_path=template_path,
            pid_path='/tmp/gor-mirror.pid')

        # Patch in the dummy update function
        funcType = type(MirrorUpdater.update)
        mirror_updater.update = funcType(dummy_update, mirror_updater,
                                         MirrorUpdater)

        # Correct the template path for test time
        template_path = os.path.join(os.path.dirname(__file__),
                                     '../../templates/gor/mirror.sh.template')
        mirror_updater._template_path = template_path

        # Check that update signals flow correctly through to command
        # Initial setup
        self.assertTrue(mirror_updater._should_update())
        mirror_updater.set_up()
        self.assertTrue('127.0.0.1:80' in mirror_updater._generate_command())
        self.assertFalse(mirror_updater._should_update())

        # Add a new endpoint
        mirror_updater._source.add(SourceEndpoint('127.0.0.1', 81))
        self.assertTrue(mirror_updater._should_update())
        mirror_updater.update()
        self.assertTrue('127.0.0.1:81' in mirror_updater._generate_command())
        self.assertFalse(mirror_updater._should_update())

        # Remove the new endpoint
        mirror_updater._source.remove(SourceEndpoint('127.0.0.1', 81))
        self.assertTrue(mirror_updater._should_update())
        mirror_updater.update()
        self.assertTrue(
            '127.0.0.1:81' not in mirror_updater._generate_command())

        # Remove the only remaining endpoint
        mirror_updater._source.remove(SourceEndpoint('127.0.0.1', 80))
        self.assertTrue(mirror_updater._should_update())
        mirror_updater.update()
        self.assertTrue(
            '127.0.0.1:80' not in mirror_updater._generate_command())
        self.assertTrue(_FALLBACK_MSG in mirror_updater._generate_command())