Baseplate

Latest version: v2.6.0

Safety actively analyzes 629723 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 20 of 24

0.21.0

Not secure
New Features

Experimental Experiments System

Baseplate now has an A/B testing experiment system. This is currently very experimental, but will be progressing in the next few weeks to something production ready. The goal is to allow rapid bucketing of users into experiment variants even deep within the call graph of services. This initial version is focused on compatibility with r2's experiment logic but with a cleaner API.

Live Data

This is a new low-level feature that will power other features down the line (like the experiments system). It consists of a sidecar daemon that watches ZooKeeper and updates files on disk, and associated tools for interacting with ZooKeeper from CI etc. This is intended to bring live config type powers to Baseplate services. `FileWatcher` instances can be used in applications to watch the data the sidecar daemon copies locally.

Changes

* The [`FileWatcher`](http://baseplate.readthedocs.io/en/v0.20/baseplate/file_watcher.html) will now continue to use its in-memory data if the underlying file fails to parse.

Upgrading

No changes should be needed when upgrading from v0.20.

0.20

2. Restart the secret fetcher daemon and verify the secrets file is updated.
3. Restart all application processes.

Gauge increment/decrement usage

This feature is completely removed, so you'll need to delete any references to
it in your code. This is quite unlikely to affect any Reddit services right now
as our previous statsd implementation, Tallier, didn't support gauges at all.

0.19

sidecar daemon. For more advanced usages, like allowing Vault to manage
encryption of data for you without you ever knowing the key, you need to talk
directly to Vault in-request. This integration brings Baseplate's
instrumentation and metrics to the [HVAC] client library for Vault.

[HVAC]: http://baseplate.readthedocs.io/en/v0.20/baseplate/context/hvac.html

Counters for success/error rate on spans

Baseplate now sends additional information to Graphite about the success and
failure of operations in your application. This can be helpful to understand
the volume of requests flowing in and out, and what percentage of them failed.

FileWatcher

Both the `SecretsStore` and `ServiceInventory` work by watching files on local
disk for changes and updating the application's in-memory state on change. This
functionality has been factored out into the [`FileWatcher`][filewatcher] which
allows you to apply this pattern directly in your application for
configuration, local data models, etc.

[filewatcher]: http://baseplate.readthedocs.io/en/v0.20/baseplate/file_watcher.html

DictOf

This is a new option type for the configuration parser which allows you to
ingest groups of keys that you don't know the full names of at coding time. This is rather abstract, so check out some examples:

ini
[app:main]
population.cn = 1383890000
population.in = 1317610000
population.us = 325165000
population.id = 263447000
population.br = 207645000


python
>>> cfg = config.parse_config(raw_config, {
... "population": config.DictOf(config.Integer),
... })

>>> len(cfg.population)
5

>>> cfg.population["br"]
207645000


See [the docs][dictof] for more examples and details.

[dictof]: http://baseplate.readthedocs.io/en/v0.20/baseplate/config.html#baseplate.config.DictOf

Changes

* Greatly improve test coverage, particularly of instrumentation integrations.
Many of the bug fixes listed below came from this work.
* Clean up formatting and do a general readability pass on the documentation.
* Atomically swap out contents of secrets file. This removes a potential race
condition where the secret fetcher daemon is caught in the middle of writing
out updated secrets.
* Add Vault URL to secrets file. This allows the HVAC integration to get the
full information on how to connect to and authenticate with Vault from one
place.
* Overhaul development environment puppet manifests for more comprehensive
setup.
* **BREAKING** Remove gauge increment/decrement support. We don't want to
encourage use of this feature as it's unreliable when the statsd service is
restarted since the "current" value is only stored in memory.

Bug fixes

* Raise an informative error instead of crashing when fetching secrets and the
secrets file is not available.
* Fix SQLAlchemy instrumentation's reporting of errors. Previously, failed
queries did not have their associated spans properly finished and so were not
instrumented.
* Fix Cassandra instrumentation's reporting of errors. Previously, failed queries
would have an error tag set but would not be finished in an error state, so
observers got an incomplete view of the error information.
* Set error tags on spans consistently in Zipkin reporting. This ensures that all
failed spans get an error=true tag set in Zipkin.
* Fix a crash detecting the hostname on systems that do not have a valid address-
to-host mapping configured.
* Catch, log, and discard exceptions when posting trace data in Zipkin integration.

Upgrading

Secrets file format changes

The secrets fetcher daemon writes out a new `vault` field to the secrets file
containing both the original `token` and new `url` fields. A `vault_token`
field is also written for compatibility with applications running on Baseplate
v0.19. The secrets store code expects this new `vault` field to exist. To upgrade
safely:

0.19.0

Not secure
New Features

Secure secret storage in Vault

Baseplate now includes support for fetching secrets in a secure, auditable, manner from Hashicorp Vault. A sidecar daemon manages the infrastructure-level authentication with Vault and fetches secrets to a file on disk. Helpers in Baseplate then allow your application to fetch these secrets efficiently from the sidecar daemon with some helpful conventions for versioning/key rotation. This is now the right way to get secret tokens into your application going forward. [See the docs for more info](http://baseplate.readthedocs.io/en/v0.19.0/baseplate/secrets.html).

Error reporting via Sentry

A new span observer integrates Baseplate applications with Raven, the Sentry client. This makes it easy to automatically report exceptions in the application to Sentry. Extra context like the trace ID, git revision of the running application, and context from the incoming request are automatically included in the exception event sent to Sentry. The raven client is also attached to the context object as `context.sentry` for sending custom events as desired.

Changes

* Rework [message signer API](http://baseplate.readthedocs.io/en/v0.19.0/baseplate/crypto.html#message-signing) to take advantage of versioned secrets from Vault. The old class-based API is still supported but is now marked deprecated.
* Rename `make_metrics_client` to `metrics_client_from_config` and `make_tracing_client` to `tracing_client_from_config` to be more consistent with other `_from_config` functions used throughout Baseplate. The old names are still supported but are now marked as deprecated.

Bug fixes

* Fix exception capture in server spans for the Thrift integration.
* Suppress noisy urllib3 logs from zipkin integration.
* Fix context property attachment in local spans, this caused observers like the metrics observer to be called multiple times on the same server span when local spans were used.
* Fix Python 3 import incompatibilities in `baseplate-healthcheck3`.

Upgrading

Adding Vault integration

In your application's entry point, instantiate a `SecretsStore` with [`secrets_store_from_config`](http://baseplate.readthedocs.io/en/v0.19.0/baseplate/secrets.html#baseplate.secrets.secrets_store_from_config) and attach it to the context object with `add_to_context`.

diff
def make_processor(app_config):
+ secrets = secrets_store_from_config(app_config)
+ baseplate.add_to_context("secrets", secrets)


Make sure that any time you use a secret you fetch it from the secret store rather than storing fetched secrets in the application. This ensures that as secrets expire and rotate your application stays up to date.

python
secret = context.secrets.get_versioned("secret/my-service/signing-key")
return make_signature(secret, "This is a signed message!", max_age)


Adding Sentry Integration

Sentry integration is just a matter of configuring and registering the new observer at application startup. For example (from [the activity service](https://github.com/reddit/reddit-service-activity)):

diff
-9,6 +9,7
from baseplate import (
Baseplate,
config,
+ error_reporter_from_config,
metrics_client_from_config,
tracing_client_from_config,
)
-122,6 +123,7 def make_processor(app_config): pragma: nocover

metrics_client = metrics_client_from_config(app_config)
tracing_client = tracing_client_from_config(app_config)
+ error_reporter = error_reporter_from_config(app_config, __name__)
redis_pool = redis.BlockingConnectionPool.from_url(
cfg.redis.url,
max_connections=cfg.redis.max_connections,
-132,6 +134,7 def make_processor(app_config): pragma: nocover
baseplate.configure_logging()
baseplate.configure_metrics(metrics_client)
baseplate.configure_tracing(tracing_client)
+ baseplate.configure_error_reporting(error_reporter)
baseplate.add_to_context("redis", RedisContextFactory(redis_pool))

counter = ActivityCounter(cfg.activity.window.total_seconds())


To configure the Sentry client in your application's config file, get a DSN from Sentry (for Reddit crew, contact IO) then see the docs for [`error_reporter_from_config`](http://baseplate.readthedocs.io/en/v0.19.0/baseplate/index.html#baseplate.error_reporter_from_config) for all the available options.

Make sure to add `python-raven` or `python3-raven` to your development environment.

Updating renamed functions

Update the import and call for `make_metrics_client` and `make_tracing_client` in your application's entry point with the new names `metrics_client_from_config` and `tracing_client_from_config`.

Updating usage of the MessageSigner

The previous `MessageSigner` API was a class that took a static secret and then provided signature generation and validation methods. The new API is bare functions that take the secret as a parameter. This allows you to refetch the secret from the `SecretsStore` immediately before use.

Before:

python
signer = MessageSigner(b"hunter2")
signature = signer.make_signature("message", max_age)
signer.validate_signature("message", signature)


After:

python
secret = context.secrets.get_versioned("secret/my-service/my-secret")
signature = signer.make_signature("message", max_age)

...

secret = context.secrets.get_versioned("secret/my-service/my-secret")
validate_signature(secret, "message", signature)


If you have not set up Vault yet, you can also use [`VersionedSecret.from_simple_secret`](http://baseplate.readthedocs.io/en/v0.19.0/baseplate/secrets.html#baseplate.secrets.VersionedSecret.from_simple_secret) to make a fake versioned secret from a static value for use with the new API.

0.18.0

Not secure
Changes

New Features

Memcached serialization helpers

The pymemcached integration now comes with helpers for serializing and deserializing python objects for storage in memcached. For green-field applications, use the non-pickle variants. Applications interacting with data from r2's caches can use the pickle variants.

CQLMapper integration

Baseplate now has [instrumented clients](https://baseplate.readthedocs.io/en/v0.19.0/baseplate/context/index.html#baseplate.context.cassandra.CQLMapperContextFactory) for use with the Cassandra object mapper [CQLMapper](https://github.com/reddit/cqlmapper) which is a stripped down fork of [cqlengine](https://github.com/datastax/python-driver/tree/master/cassandra/cqlengine) better suited for use in environments like Baseplate that avoid application-global context.

API Modifications

* The [`Baseplate.configure_tracing`](https://baseplate.readthedocs.io/en/v0.19.0/baseplate/core.html#baseplate.core.Baseplate.configure_tracing) convenience method has been reworked so that Baseplate can standardize configuration parsing for your application.
* **BREAKING**: The baseplate commands which parse INI files no longer allow interpolation of variables in the config file syntax.

Upgrading

Updating tracing setup

Replace manual configuration parsing with a call to [`Baseplate.make_tracing_client`](http://baseplate.readthedocs.io/en/v0.19.0/baseplate/index.html#baseplate.tracing_client_from_config). Here's a theoretical example of upgrading the [activity service](https://github.com/reddit/reddit-service-activity):

diff
-10,6 +10,7 from baseplate import (
Baseplate,
config,
make_metrics_client,
+ make_tracing_client,
)
from baseplate.context.redis import RedisContextFactory
from baseplate.integration.thrift import BaseplateProcessorEventHandler
-113,10 +114,6 def make_processor(app_config): pragma: nocover
"window": config.Timespan,
"fuzz_threshold": config.Integer,
},
- "tracing": {
- "endpoint": config.Optional(config.Endpoint),
- "service_name": config.String,
- },
"redis": {
"url": config.String,
"max_connections": config.Optional(config.Integer, default=100),
-124,6 +121,7 def make_processor(app_config): pragma: nocover
})

metrics_client = make_metrics_client(app_config)
+ tracing_client = make_tracing_client(app_config)
redis_pool = redis.BlockingConnectionPool.from_url(
cfg.redis.url,
max_connections=cfg.redis.max_connections,
-133,10 +131,7 def make_processor(app_config): pragma: nocover
baseplate = Baseplate()
baseplate.configure_logging()
baseplate.configure_metrics(metrics_client)
- baseplate.configure_tracing(
- cfg.tracing.service_name,
- cfg.tracing.endpoint,
- )
+ baseplate.configure_tracing(tracing_client)
baseplate.add_to_context("redis", RedisContextFactory(redis_pool))

counter = ActivityCounter(cfg.activity.window.total_seconds())

0.17.1

Not secure
* Add configuration for trace debug logging
* Move child span event listening to base SpanObserver

Page 20 of 24

© 2024 Safety CLI Cybersecurity Inc. All Rights Reserved.