Skip to content

Commit

Permalink
Add Docker image
Browse files Browse the repository at this point in the history
  • Loading branch information
pierky committed Feb 28, 2021
1 parent d9377c2 commit b838515
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.git/
.github/
arouteserver.egg-info/
dist/
tools/
tests/last_results
tests/live_tests/
tools/
utils/
var/
81 changes: 81 additions & 0 deletions .github/workflows/docker_image_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Docker image tests

on: push

jobs:
docker-image-tests:
name: Docker image tests
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Build the image
run: >
docker build \
-t pierky/arouteserver:latest \
-f docker/Dockerfile \
.
- name: Run nosetests
run: >
docker run \
-t \
--rm \
pierky/arouteserver:latest \
nosetests -vsx tests/static
- name: Run CLI tests
run: >
docker run \
-t \
--rm \
pierky/arouteserver:latest \
./tests/cli
- name: Test configuration building (BIRD 1.x)
run: >
mkdir ~/arouteserver_configs && \
docker run \
-t \
--rm \
-v $(pwd)/config.d/clients.yml:/root/clients.txt:ro \
-v ~/arouteserver_configs:/root/arouteserver_configs \
-e RS_ASN=65500 \
-e ROUTER_ID=192.0.2.123 \
-e LOCAL_PREFIXES=192.0.2.0/24,2001:db8::/32 \
-e IP_VER=4 \
-e DAEMON=bird \
-e VERSION=1.6.8 \
pierky/arouteserver:latest
- name: Test configuration building (BIRD 2)
run: >
mkdir ~/arouteserver_configs && \
docker run \
-t \
--rm \
-v $(pwd)/config.d/clients.yml:/root/clients.txt:ro \
-v ~/arouteserver_configs:/root/arouteserver_configs \
-e RS_ASN=65500 \
-e ROUTER_ID=192.0.2.123 \
-e LOCAL_PREFIXES=192.0.2.0/24,2001:db8::/32 \
-e DAEMON=bird \
-e VERSION=2.0.7 \
pierky/arouteserver:latest
- name: Test configuration building (OpenBGPD)
run: >
mkdir ~/arouteserver_configs && \
docker run \
-t \
--rm \
-v $(pwd)/config.d/clients.yml:/root/clients.txt:ro \
-v ~/arouteserver_configs:/root/arouteserver_configs \
-e RS_ASN=65500 \
-e ROUTER_ID=192.0.2.123 \
-e LOCAL_PREFIXES=192.0.2.0/24,2001:db8::/32 \
-e DAEMON=openbgpd \
-e VERSION=6.7 \
pierky/arouteserver:latest
28 changes: 28 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM python:3.9

RUN mkdir /arouteserver
WORKDIR /arouteserver

RUN mkdir /bgpq4 && \
cd /bgpq4 && \
git clone https://github.com/bgp/bgpq4.git ./ && \
./bootstrap && \
./configure && \
make && \
make install

ADD requirements.txt ./

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

COPY . ./
COPY docker/run.sh /root/run.sh
RUN pip install .

RUN arouteserver \
setup --dest-dir /etc/arouteserver

RUN rm /etc/arouteserver/clients.yml

CMD /root/run.sh
82 changes: 82 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# ARouteServer Docker image

This Docker image can be used to run ARouteServer as a container, either to experiment with it or to easily generate production level configurations that are based on best practices and suggested settings.

## Usage

### Generating configurations

To generate BIRD or OpenBGPD configurations, route-server clients need to be defined in your local system, in YAML, following the [ARouteServer format](https://github.com/pierky/arouteserver/blob/master/config.d/clients.yml).

The clients need to be stored in a local file, `~/clients.yml` for example.

```yaml
clients:
- asn: 3333
ip: "192.0.2.11"
- asn: 10745
ip:
- "192.0.2.22"
- "2001:db8:1:1::22"
```

Docker can then be instructed to run the image using some input arguments that are needed to specify the route server's ASN, its router ID, which are the local prefixes of the peering LAN, and what's the target BGP daemon and its version (BIRD vs OpenBGPD).

When BIRD 1.x is the target BGP daemon for which the configurations are built, also the `IP_VER` variable must be set, to specify for which address-family the configuration must be generated.

The local file where clients are defined must be mounted into the `/root/clients.txt` path of the container, and the local directory where configuration files need to be saved must be mounted as `/root/arouteserver_configs`.

Example:

```bash
# This is the local directory where configs will be stored:
mkdir ~/arouteserver_configs

docker run \
-it \
--rm \
-v ~/clients.yml:/root/clients.txt:ro \
-v ~/arouteserver_configs:/root/arouteserver_configs \
-e RS_ASN=65500 \
-e ROUTER_ID=192.0.2.123 \
-e LOCAL_PREFIXES=192.0.2.0/24,2001:db8::/32 \
-e IP_VER=4 \
-e DAEMON=bird \
-e VERSION=1.6.8 \
pierky/arouteserver:latest
```

After running the container, the configurations will be saved inside the local host's directory, `~/arouteserver_configs` in the example.

#### Customizing the route-server features

The options used to build the configuration files can be customized by providing a user-defined general.yml file at run-time.

This can be done by mounting the local host's general.yml file into the `/etc/arouteserver/general.yml` path of the container.

Details on all the available features and options can be found in the [doc site](https://arouteserver.readthedocs.io/en/latest/CONFIG.html) or in the [commented version of general.yml](https://github.com/pierky/arouteserver/blob/master/config.d/general.yml).

```bash
docker run \
-it \
--rm \
-v ~/custom-general.yml:/etc/arouteserver/general.yml:ro \
... # other options
```

### Interactively execution

To experiment with the tool, the Docker image can be executed interactively:

```bash
docker run \
-it \
--rm \
pierky/arouteserver:latest bash
```

This will give you access to an environment where ARouteServer and its dependencies (bgpq4) are installed and ready to be used.

## Dockerfile

The Dockerfile can also provide some useful hints on how to install and configure ARouteServer on a host that is different than a Docker image. You can [check it out on GitHub](https://github.com/pierky/arouteserver/blob/master/docker/Dockerfile).
117 changes: 117 additions & 0 deletions docker/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/bin/bash

set -e

function bold {
echo -e "\e[1m${1}\e[0m"
}

function error {
bold "ERROR: $1"
exit 1
}

function error_envvar_not_set {
# $1 missing variable
# $2 optional reason
error "environment variable not set: ${1}\n
${2}\n
Please run the container passing the '-e ${1}=value' argument."
}

DAEMON="${DAEMON}"
VERSION="${VERSION}"
RS_ASN="${RS_ASN}"
ROUTER_ID="${ROUTER_ID}"
LOCAL_PREFIXES="${LOCAL_PREFIXES}"
IP_VER="${IP_VER}"

CLIENTS_FILE_PATH="/root/clients.txt"
OUTPUT_DIR="/root/arouteserver_configs"

if [[ ! -e "${OUTPUT_DIR}" && ! -d "${OUTPUT_DIR}" ]]; then
error "The output directory ${OUTPUT_DIR} can't be found.
This is the directory where the configurations generate by ARouteServer will be saved.
Please be sure to mount the desired directory of the host to the ${OUTPUT_DIR} directory on the container.
You can run the container passing the '-v PATH_OF_DIRECTORY_ON_THE_HOST:${OUTPUT_DIR}' argument."
fi

if [[ -z "${DAEMON}" ]]; then
error_envvar_not_set "DAEMON"
fi

if [[ -z "${VERSION}" ]]; then
error_envvar_not_set "VERSION"
fi

if [[ -z "${RS_ASN}" ]]; then
error_envvar_not_set "RS_ASN"
fi

if [[ -z "${ROUTER_ID}" ]]; then
error_envvar_not_set "ROUTER_ID"
fi

if [[ -z "${LOCAL_PREFIXES}" ]]; then
error_envvar_not_set "LOCAL_PREFIXES"
fi

if [[ ! -e "${CLIENTS_FILE_PATH}" ]]; then
error "Couldn't find the file ${CLIENTS_FILE_PATH} on the container.\n
Please mount the local file where the list of clients is defined using '-v PATH_OF_CLIENTS_FILE_ON_THE_HOST:${CLIENTS_FILE_PATH}:ro' argument."
fi

IP_VER_ARG=""
OUTPUT_FILE="${DAEMON}.cfg"

if [[ "${DAEMON}" == "bird" ]]; then
set +e
egrep "^1\." <<< "${VERSION}" &>/dev/null
IP_VER_REQUIRED=$? # 0 = IP_VER is required
set -e

if [[ ${IP_VER_REQUIRED} -eq 0 ]]; then
if [[ -z "${IP_VER}" ]]; then
error_envvar_not_set "IP_VER" "When BIRD 1.x is used, IP_VER must be set."
else
IP_VER_ARG="--ip-ver ${IP_VER}"
OUTPUT_FILE="${DAEMON}${IP_VER}.cfg"
fi
fi
fi

if [[ ! -e /etc/arouteserver/general.yml ]]; then
echo ""
bold "Configuring ARouteServer for ${DAEMON} ${VERSION}..."
echo ""

arouteserver \
configure --preset-answer \
daemon=${DAEMON} \
version=${VERSION} \
asn=${RS_ASN} \
router_id=${ROUTER_ID} \
black_list=${LOCAL_PREFIXES}
else
echo ""
bold "The user-provided configuration from general.yml will be used."
echo ""
fi

echo ""
bold "Generating route server configuration for ${DAEMON} ${VERSION}..."
echo ""

OUTPUT_PATH="${OUTPUT_DIR}/${OUTPUT_FILE}"

arouteserver \
"${DAEMON}" \
--target-version "${VERSION}" \
${IP_VER_ARG} \
--clients "${CLIENTS_FILE_PATH}" \
-o "${OUTPUT_PATH}"

echo ""
bold "Route server configuration for ${DAEMON} ${VERSION} saved to ${OUTPUT_PATH} (path on the container)."
echo "You will find the configuration file in your host system, inside the directory that you mounted at run-time."
echo ""
3 changes: 3 additions & 0 deletions pierky/arouteserver/commands/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ def add_answer(self, answer_id, ask_func, *args, **kwargs):
raise ARouteServerError("Aborted!")
if answer_ok:
break
else:
if self.preset_answers:
raise ARouteServerError("Pre-set answer is invalid!")
self.answers[answer_id] = answer

def ask_list_of_ip_prefixes(self, text, raise_exc=False):
Expand Down

0 comments on commit b838515

Please sign in to comment.