Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Saving the (Production) Environment

DZone's Guide to

Saving the (Production) Environment

Using Bazel to create different environments, and then ensure that targets only build with the correct environment.

· DevOps Zone ·
Free Resource

Learn more about how CareerBuilder was able to resolve customer issues 5x faster by using Scalyr, the fastest log management tool on the market. 

You can create different environments (e.g., testing, prod, mobile, rainforest) with Bazel, then use them to make sure that targets only build with the right environment. This is a cool feature that’s undocumented (because it’s still in development, shhhhh, don’t tell anyone I told you about it).

Let’s say you have a prod SSH key that you don’t want used in development or test builds. You could restrict it to only be used in prod builds by defining the following:

environment(name = "dev")
environment(name = "prod")
environment(name = "testing")

environment_group(
    name = "buildenv",
    defaults = ["dev"],
    environments = [
        "dev",
        "prod",
        "testing",
    ],
)

filegroup(
    name = "ssh-key",
    restricted_to = [":prod"],
    srcs = ["key"],
)

Now whenever we use :ssh-key, it has to be in a prod-environment rule.

For example, this works:

cc_binary(
    name = "prod-job",
    srcs = ["job.cc"],
    restricted_to = [":prod"],
    data = ["ssh-key"],
)

This doesn’t:

cc_test(
    name = "job-test",
    srcs = ["job_test.cc"],
    data = [":ssh-key"],
)

Building the second one gives:

$ bazel build :job-test
ERROR: /Users/kchodorow/test/a/BUILD:34:1: in cc_test rule //:job-test: dependency //:ssh-key doesn't support expected environment: //:dev.
ERROR: Analysis of target '//:job-test' failed; build aborted.
INFO: Elapsed time: 0.167s

Hopefully, if someone tried to add restricted_to = [":prod"] to a test, it’d “look wrong” and be easier to catch.

Note that you must set your defaults sanely.   When I first tried this, I made the environment_group‘s defaults = ["prod"] and then was confused that I wasn’t getting any errors. Everything is built for the default environments unless specified otherwise!

This lets us say:

“If a depends on b and b is restricted to a certain environment, then a must be restricted to the environment.”

However, there is another direction to look at this from: if a is restricted to an environment, b must be compatible with that environment. To express this, you can use "compatible_with":

filegroup(
    name = "dev-key",
    srcs = ["key.dev"],
    compatible_with = [
        ":dev",
        ":testing"
    ],
)

Now anything that’s restricted to “:dev” or “:testing” environments can depend on “:dev-key”. For example, these work:

cc_binary(
    name = "dev-job",
    srcs = ["job.cc"],
    data = [":dev-key"],
)

cc_test(
    name = "job-test",
    srcs = ["job_test.cc"],
    restricted_to = [":testing"],
    data = [":dev-key"],
)

This does not:

cc_binary(
    name = "prod-job",
    srcs = ["job.cc"],
    restricted_to = [":prod"],
    data = [":dev-key"],
)

The full matrix (assuming env is an environment) is:

b b

restricted to

env b

compatible with

env a

✓ ✗ ✓

a

restricted to

env

✗ ✓ ✓

a

compatible with

env

✗ ✗ ✓

Remember that environments are targets themselves, so avoid proliferating environments that aren’t global to the global scope (don’t make them publicly visible and keep them as private as possible).

Find out more about how Scalyr built a proprietary database that does not use text indexing for their log management tool.

Topics:
bazel ,python ,dev ops

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}