How-To Archives

Assert Your Environment


In the category of "scratching my itch".

I was doing some data pipelining and dockerising my creation. And - as always - when testing and devving I forgot to set the right environment variables. And when container image gets passed around, the information about the required env settings will certainly get lost.

Here is something of a solution to that:

How to ensure you have the environment variables and values you need?

Here is a common sight:

$ PLAEC='Stockholm'
$ if [[ "$PLACE" == '' ]]; then echo "Normal OK"; fi

... And the program fails with no errors!

Not quite what we want!

Another example, from a docker container image I created lately:

perl -Ilib bin/ --verbose         \
    | perl -Ilib bin/ --verbose  \
    | az storage blob upload --data @-            \
        --content-type 'text/csv'                 \
        --content-encoding 'UTF-8'                \
        --content-language 'en_US'                \
        --name "$blob_name"                       \
        --container "$CONTAINER_NAME"             \
        --account-name "$AZURE_STORAGE_ACCOUNT"   \
        --sas-token "$AZURE_STORAGE_SAS_TOKEN"

If the environment variables are wrongly set, or entirely unset, it won't become known until after the run has started. And it could take hours before it reaches that point.

What we need is a way to find out if the environment variables are what we assume them to be. This needs to be done in an easy way and right at the beginning of the run.

Environment Description to the Rescue

Package Env::Assert and the executable envassert that comes with it do just this.

envassert is a CLI command to assert that your environment variables match your environment description.

environment description is a way to describe which environment variables are required by your program.

environment description is written in a file. Default file name is .envdesc.

If you are in the habbit of using .env files anyway, .envdesc complements it. Commit your .envdesc file into your repository and it will act as a template for user to create his/her .env file which should not be committed into Git anyway.

.envdesc actually looks a lot like a .env file, except instead of defining variables and their content, it defines regular expressions which control the variables' content. These regexps are Perl's extended regular expressions (m/<regexp>/msx).



In normal circumstances, envassert only verifies the variables that you specifically describe. If you want more control over your environment, there is the meta command envassert (opts: exact=1) which will make envassert also assert that the environment doesn't contain any unknown variables.

## envassert (opts: exact=1)

You can create an airtight environment description to verify environment variables in both test and production. Just run envassert as the first command during container execution.

This is what I do:

envassert --env-description /home/me/.envdesc \
    || ( echo 'Break execution ...' 1>&2 && exit 1 )


If I need to add envassert to a container image during build, there is a FatPacked executable ready for those cases when using CPAN is overkill.

I do this in Dockerfile!

RUN curl -LSs -o /usr/local/bin/envassert \
RUN chmod +x /usr/local/bin/envassert

There is no extra dependencies outside Perl's standard distribution, so envassert is as lean as it can be.


If you are using Docker, you may have noticed that it creates random names for containers when you haven't provided any specific name. These names are a combination of an adjective and a proper name of an individual. The individuals are famous men and women picked from the history of scientific exploration and engineering.

This package allows you to use the same system in your own programs. You would get combinations like interesting_mendeleev, epic_engelbart, lucid_dhawan, recursing_cori, ecstatic_liskov and busy_ardinghelli.

The combination boring_wozniak is not allowed because Steve Wozniak is not boring. This same limitation exists in the original code.


# As an object (if you create many, this is more efficient).
require Docker::Names::Random;

my $dnr = Docker::Names::Random->new();
my $random_name1 = $dnr->docker_name();

# As an imported function.
use Docker::Names::Random qw( docker_name );
# OR
use Docker::Names::Random qw( :all );

my $random_name2 = docker_name();

Git Repo in Shared Hosting #4 - Git Full Service Via SSH

In this fourth article we will now use SSH connection and SSH public keys to give access and also limit access to our repositories.

Git Repo in Shared Hosting #3 - Git::Hooks for a Secure and Clean Repo

About Mikko Koivunalho

user-pic I blog about Perl.