Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: containers/netavark
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: d548facf5af96a9d08ca3f5a46fb3cc7f69a50c2
Choose a base ref
..
head repository: containers/netavark
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1c0a7d837d39aca77546831fa0ddfc1a2d8c9734
Choose a head ref
Showing with 256 additions and 8 deletions.
  1. +13 −8 .cirrus.yml
  2. +4 −0 README.md
  3. +81 −0 contrib/cirrus/cache_groom.sh
  4. +6 −0 contrib/cirrus/lib.sh
  5. +152 −0 plugin-API.md
21 changes: 13 additions & 8 deletions .cirrus.yml
Original file line number Diff line number Diff line change
@@ -50,16 +50,15 @@ build_task:
# all PRs & branches will share caches with other PRs and branches
# for a given $DEST_BRANCH and vX value. Adjust vX if cache schema
# changes.
fingerprint_key: "cargo_v2_${DEST_BRANCH}_amd64"
fingerprint_script: echo -e "cargo_v3_${DEST_BRANCH}_amd64\n---\n$(<Cargo.lock)\n---\n$(<Cargo.toml)"
# Required to be set explicitly since fingerprint_key is also set
reupload_on_changes: true
targets_cache: &targets_cache
# Similar to cargo_cache, but holds the actual compiled artifacts. This must
# be scoped similar to bin_cache to avoid binary pollution across cache
# contexts. For example, two PRs that happen to coincidentally change
# and use cache. Adjust vX if cache schema changes.
# Similar to cargo_cache, but holds the actual compiled dependent artifacts.
# This should be scoped to a hash of the dependency-metadata lock file.
# Cirrus-CI will automatically use separate caches for PRs and branches.
folder: "$CARGO_TARGET_DIR"
fingerprint_key: "targets_v2_${CIRRUS_TAG}${DEST_BRANCH}${CIRRUS_PR}_amd64" # Cache only within same tag, branch, or PR (branch will be 'pull/#')
fingerprint_script: echo -e "targets_v3_${CIRRUS_TAG}${DEST_BRANCH}${CIRRUS_PR}_amd64\n---\n$(<Cargo.lock)\n---\n$(<Cargo.toml)"
reupload_on_changes: true
bin_cache: &bin_cache
# This simply prevents rebuilding bin/netavark for every subsequent task.
@@ -70,6 +69,7 @@ build_task:
reupload_on_changes: true
setup_script: &setup "$SCRIPT_BASE/setup.sh"
main_script: &main "$SCRIPT_BASE/runner.sh $CIRRUS_TASK_NAME"
cache_grooming_script: &groom bash "$SCRIPT_BASE/cache_groom.sh"
upload_caches: [ "cargo", "targets", "bin" ]


@@ -82,11 +82,15 @@ build_aarch64_task:
architecture: arm64 # CAUTION: This has to be "arm64", not "aarch64"
cargo_cache: &cargo_cache_aarch64
folder: "$CARGO_HOME"
fingerprint_key: "cargo_v2_${DEST_BRANCH}_aarch64"
# N/B: Should exactly match (except for arch) line from build_task (above).
# (No, there isn't an easy way to not duplicate most of this :()
fingerprint_script: echo -e "cargo_v3_${DEST_BRANCH}_aarch64\n---\n$(<Cargo.lock)\n---\n$(<Cargo.toml)"
reupload_on_changes: true
targets_cache: &targets_cache_aarch64
folder: "$CARGO_TARGET_DIR"
fingerprint_key: "targets_v2_${CIRRUS_TAG}${DEST_BRANCH}${CIRRUS_PR}_aarch64" # Cache only within same tag, branch, or PR (branch will be 'pull/#')
# N/B: Should exactly match (except for arch) line from build_task (above).
# (No, there isn't an easy way to not duplicate most of this :()
fingerprint_script: echo -e "targets_v3_${CIRRUS_TAG}${DEST_BRANCH}${CIRRUS_PR}_aarch64\n---\n$(<Cargo.lock)\n---\n$(<Cargo.toml)"
reupload_on_changes: true
bin_cache: &bin_cache_aarch64
# This simply prevents rebuilding bin/netavark for every subsequent task.
@@ -95,6 +99,7 @@ build_aarch64_task:
reupload_on_changes: true
setup_script: *setup
main_script: *main
cache_grooming_script: *groom
upload_caches: [ "cargo", "targets", "bin" ]
# Downstream CI needs the aarch64 binaries from this CI system.
# However, we don't want to confuse architectures.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -39,3 +39,7 @@ For general questions and discussion, please use Podman's
For discussions around issues/bugs and features, you can use the GitHub
[issues](https://github.com/containers/netavark/issues)
and [PRs](https://github.com/containers/netavark/pulls) tracking system.

## Plugins

Netavark also supports executing external plugins, see [./plugin-API.md](./plugin-API.md).
81 changes: 81 additions & 0 deletions contrib/cirrus/cache_groom.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/bin/bash
#
# This script is intended to be run from Cirrus-CI to prepare the
# rust targets cache for re-use during subsequent runs. This mainly
# involves removing files and directories which change frequently
# but are cheap/quick to regenerate - i.e. prevent "cache-flapping".
# Any other use of this script is not supported and may cause harm.
#
# WARNING: This script is re-used from $DEST_BRANCH by other
# repositories. Namely aardvark-dns and possibly others. Check
# before removing / changing / updating.

set -eo pipefail

source $(dirname ${BASH_SOURCE[0]})/lib.sh

if [[ "$CIRRUS_CI" != true ]]; then
die "Script is not intended for use outside of Cirrus-CI"
fi

req_env_vars CARGO_HOME CARGO_TARGET_DIR CIRRUS_BUILD_ID

# Giant-meat-cleaver HACK: It's possible (with a long-running cache key) for
# the targets and/or cargo cache to grow without-bound (gigabytes). Ref:
# https://github.com/rust-lang/cargo/issues/5026
# There isn't a good way to deal with this or account for outdated content
# in some intelligent way w/o trolling through config and code files. So,
# Any time the Cirrus-CI build ID is evenly divisible by some number (chosen
# arbitrarily) clobber the whole thing and make the next run entirely
# re-populate cache. This is ugly, but maybe the best option available :(
if [[ "$CIRRUS_BRANCH" == "$DEST_BRANCH" ]] && ((CIRRUS_BUILD_ID%15==0)); then
msg "It's a cache-clobber build, yay! This build has been randomly selected for"
msg "a forced cache-wipe! Congradulations! This means the next build will be"
msg "slow, and nobody will know who to to blame!. Lucky you! Hurray!"
msg "(This is necessary to prevent branch-level cache from infinitely growing)"
cd $CARGO_TARGET_DIR
# Could use `cargo clean` for this, but it's easier to just clobber everything.
rm -rf ./* ./.??*
# In case somebody goes poking around, leave a calling-card hopefully leading
# them back to this script. I don't know of a better way to handle this :S
touch CACHE_WAS_CLOBBERED

cd $CARGO_HOME
rm -rf ./* ./.??*
touch CACHE_WAS_CLOBBERED
exit 0
fi

# The following applies to both PRs and branch-level cache. It attempts to remove
# things which are non-essential and/or may change frequently. It stops short of
# trolling through config & code files to determine what is relevant or not.
# Ref: https://doc.rust-lang.org/nightly/cargo/guide/build-cache.html
# https://github.com/Swatinem/rust-cache/tree/master/src
cd $CARGO_TARGET_DIR
for targetname in $(find ./ -type d -maxdepth 1 -mindepth 1); do
msg "Grooming $CARGO_TARGET_DIR/$targetname..."
cd $CARGO_TARGET_DIR/$targetname
# Any top-level hidden files or directories
showrun rm -rf ./.??*
# Example targets
showrun rm -rf ./target/debug/examples
# Documentation
showrun rm -rf ./target/doc
# Internal to rust build process
showrun rm -rf ./target/debug/deps ./target/debug/incremental ./target/debug/build
done

# The following only applies to dependent packages (crates). It follows recommendations
# Ref: https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci
# and probably shouldn't be extended beyond what's documented. This cache plays a major
# role in built-time reduction, but must also be prevented from causing "cache-flapping".
cd $CARGO_HOME
for dirname in $(find ./ -type d -maxdepth 2 -mindepth 1); do
case "$dirname" in
./bin) ;& # same steps as next item
./registry/index) ;&
./registry/cache) ;&
./git/db) continue ;; # Keep
*) rm -rf $dirname ;; # Remove
esac
done
6 changes: 6 additions & 0 deletions contrib/cirrus/lib.sh
Original file line number Diff line number Diff line change
@@ -32,6 +32,12 @@ else # set default values - see make_cienv() below
# VM Images are built with this setup
CARGO_HOME="${CARGO_HOME:-/var/cache/cargo}"
source $CARGO_HOME/env

# Make caching more effective - disable incremental compilation,
# so that the Rust compiler doesn't waste time creating the
# additional artifacts required for incremental builds.
# Ref: https://github.com/marketplace/actions/rust-cache#cache-details
CARGO_INCREMENTAL=0
fi

# END Global export of all variables
152 changes: 152 additions & 0 deletions plugin-API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Description of the netavark plugin API

A netavark plugin is a external binary which must implement a specific set of subcommands that will be called by podman and netavark.
- `create`: creates a network config
- `setup`: setup the network configuration
- `teardown`: tear down the network configuration
- `info`: show info about this plugin

## Create subcommand

The create subcommand creates a new network config for podman.
The subcommand will receive the JSON network config via STDIN. Podman will populate
the network name and ID before calling the plugin. The name and ID cannot be changed
by the plugin. The driver name must also not be changed. All other config
fields can be changed in the plugin.

Other fields such as subnet and options will also be populated by podman when
these options are set on the podman network create command, i.e. `--subnet`
and `--option`. The plugin should validate the given values and error out for
invalid values.

On success the plugin should print the generated config as JSON to STDOUT.

Example JSON input and output format:
```
{
"name": "podman",
"id": "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9",
"driver": "host-device",
"network_interface": "eth0",
"subnets": [
{
"subnet": "10.88.0.0/16",
"gateway": "10.88.0.1"
}
],
"ipv6_enabled": false,
"internal": false,
"dns_enabled": false,
"ipam_options": {
"driver": "host-local"
},
"options": {
"custom": "opt"
}
}
```

## Setup subcommand

The setup subcommand sets-up the network configuration. This command is called when
a container is started or network connect is used, assuming the container uses
a network which was created by the plugin, see the create command above.

On STDIN it receives a JSON config which contains the network config and container options.
ON STDOUT the plugin must return a JSON status block. This contains information about the
created interface, the assigned ip and mac address. This information will be visible in the
podman inspect output.

Also this command accepts one argument which is the path to the container network namespace.

Example JSON input:
```
TBD
```

Example JSON output:
```
TBD
```


## Teardown subcommand

The teardown command is basically the reverse of the setup command. It should
revert what the plugin did in setup.
It accepts the same input as setup but it should not return anything on success.

## Info subcommand

Used to output information about this plugin. It must contain the version of your plugin and the API version.
Extra fields can be added. The API version must be set to `1.0.0` at the moment, it is not used the moment
but could be used in the future to allow for backwards compatibility in case the plugin types change.

```
{
"version": "0.1.0",
"api_version": "1.0.0"
}
```

## Error handling

If the plugin encounters an error it should return a special json message with the following format:
```
{"error": "message"}
```
where message should be replace with your actual error message. This message will be returned by
netavark and will be visible to podman users.


## Rust types

Rust types can be found in [./src/network/types.rs](./src/network/types.rs), see the documentation
[here](https://docs.rs/netavark/latest/netavark/network/types).
Fields that are wrapped by an `Option<T>` can be omitted from the json, otherwise they must be set
to allow proper deserialization.

## Rust plugin interface

There is a simple ready to use interface for writing your plugin in rust, see [./src/plugin.rs](./src/plugin.rs)
```rust
use netavark::{
network::types,
plugin::{Info, Plugin, PluginExec, API_VERSION},
};

fn main() {
// change the version to the version of your plugin
let info = Info::new("0.1.0-dev".to_owned(), API_VERSION.to_owned(), None);

PluginExec::new(Exec {}, info).exec();
}

struct Exec {}

impl Plugin for Exec {
fn create(
&self,
_network: types::Network,
) -> Result<types::Network, Box<dyn std::error::Error>> {
// your logic here
}

fn setup(
&self,
_netns: String,
_opts: types::NetworkPluginExec,
) -> Result<types::StatusBlock, Box<dyn std::error::Error>> {
// your logic here
}

fn teardown(
&self,
_netns: String,
_opts: types::NetworkPluginExec,
) -> Result<(), Box<dyn std::error::Error>> {
// your logic here
}
}
```
Also see the examples in [./examples](./examples/).