Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also 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: picoCTF/docker-reaper
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.1.1
Choose a base ref
...
head repository: picoCTF/docker-reaper
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref

Commits on Aug 25, 2023

  1. Update deps

    dmartin committed Aug 25, 2023
    Copy the full SHA
    0e1db8a View commit details
  2. Run updated rustfmt

    dmartin committed Aug 25, 2023
    Copy the full SHA
    3999e68 View commit details

Commits on Aug 30, 2023

  1. Temporarily pin bollard to git commit

    to mitigate RUSTSEC-2023-0052 advisory
    dmartin committed Aug 30, 2023
    Copy the full SHA
    2d093db View commit details
  2. Update changelog for v0.1.2

    dmartin committed Aug 30, 2023
    Copy the full SHA
    4f6eec7 View commit details

Commits on Sep 1, 2023

  1. Bump clap from 4.4.1 to 4.4.2 (#31)

    Bumps [clap](https://github.com/clap-rs/clap) from 4.4.1 to 4.4.2.
    - [Release notes](https://github.com/clap-rs/clap/releases)
    - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
    - [Commits](clap-rs/clap@v4.4.1...v4.4.2)
    
    ---
    updated-dependencies:
    - dependency-name: clap
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 1, 2023
    Copy the full SHA
    5c6dd50 View commit details
  2. Bump chrono from 0.4.27 to 0.4.28 (#30)

    Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.27 to 0.4.28.
    - [Release notes](https://github.com/chronotope/chrono/releases)
    - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
    - [Commits](chronotope/chrono@v0.4.27...v0.4.28)
    
    ---
    updated-dependencies:
    - dependency-name: chrono
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Sep 1, 2023
    Copy the full SHA
    2237467 View commit details

Commits on Sep 29, 2023

  1. Update deps

    dmartin committed Sep 29, 2023
    Copy the full SHA
    9be408a View commit details

Commits on Nov 1, 2023

  1. Bump tokio from 1.32.0 to 1.33.0 (#36)

    Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.32.0 to 1.33.0.
    - [Release notes](https://github.com/tokio-rs/tokio/releases)
    - [Commits](tokio-rs/tokio@tokio-1.32.0...tokio-1.33.0)
    
    ---
    updated-dependencies:
    - dependency-name: tokio
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 1, 2023
    Copy the full SHA
    09f3f2d View commit details
  2. Bump futures from 0.3.28 to 0.3.29 (#34)

    Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.28 to 0.3.29.
    - [Release notes](https://github.com/rust-lang/futures-rs/releases)
    - [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
    - [Commits](rust-lang/futures-rs@0.3.28...0.3.29)
    
    ---
    updated-dependencies:
    - dependency-name: futures
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 1, 2023
    Copy the full SHA
    afa7712 View commit details
  3. Bump thiserror from 1.0.49 to 1.0.50 (#35)

    Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.49 to 1.0.50.
    - [Release notes](https://github.com/dtolnay/thiserror/releases)
    - [Commits](dtolnay/thiserror@1.0.49...1.0.50)
    
    ---
    updated-dependencies:
    - dependency-name: thiserror
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 1, 2023
    Copy the full SHA
    a80cf1c View commit details
  4. Bump tracing from 0.1.37 to 0.1.40 (#32)

    Bumps [tracing](https://github.com/tokio-rs/tracing) from 0.1.37 to 0.1.40.
    - [Release notes](https://github.com/tokio-rs/tracing/releases)
    - [Commits](tokio-rs/tracing@tracing-0.1.37...tracing-0.1.40)
    
    ---
    updated-dependencies:
    - dependency-name: tracing
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 1, 2023
    Copy the full SHA
    8ab11e9 View commit details
  5. Bump clap from 4.4.6 to 4.4.7 (#33)

    Bumps [clap](https://github.com/clap-rs/clap) from 4.4.6 to 4.4.7.
    - [Release notes](https://github.com/clap-rs/clap/releases)
    - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
    - [Commits](clap-rs/clap@v4.4.6...v4.4.7)
    
    ---
    updated-dependencies:
    - dependency-name: clap
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Nov 1, 2023
    Copy the full SHA
    8ef4128 View commit details

Commits on Dec 1, 2023

  1. Bump clap from 4.4.7 to 4.4.10 (#37)

    Bumps [clap](https://github.com/clap-rs/clap) from 4.4.7 to 4.4.10.
    - [Release notes](https://github.com/clap-rs/clap/releases)
    - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
    - [Commits](clap-rs/clap@v4.4.7...v4.4.10)
    
    ---
    updated-dependencies:
    - dependency-name: clap
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Dec 1, 2023
    Copy the full SHA
    50d6554 View commit details
  2. Bump tokio from 1.33.0 to 1.34.0 (#38)

    Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.33.0 to 1.34.0.
    - [Release notes](https://github.com/tokio-rs/tokio/releases)
    - [Commits](tokio-rs/tokio@tokio-1.33.0...tokio-1.34.0)
    
    ---
    updated-dependencies:
    - dependency-name: tokio
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Dec 1, 2023
    Copy the full SHA
    7a0287e View commit details
  3. Bump tracing-subscriber from 0.3.17 to 0.3.18 (#39)

    Bumps [tracing-subscriber](https://github.com/tokio-rs/tracing) from 0.3.17 to 0.3.18.
    - [Release notes](https://github.com/tokio-rs/tracing/releases)
    - [Commits](tokio-rs/tracing@tracing-subscriber-0.3.17...tracing-subscriber-0.3.18)
    
    ---
    updated-dependencies:
    - dependency-name: tracing-subscriber
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Dec 1, 2023
    Copy the full SHA
    74ef2ff View commit details

Commits on Jan 3, 2024

  1. Bump thiserror from 1.0.50 to 1.0.53 (#42)

    Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.50 to 1.0.53.
    - [Release notes](https://github.com/dtolnay/thiserror/releases)
    - [Commits](dtolnay/thiserror@1.0.50...1.0.53)
    
    ---
    updated-dependencies:
    - dependency-name: thiserror
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jan 3, 2024
    Copy the full SHA
    83a93b3 View commit details
  2. Bump clap from 4.4.10 to 4.4.12 (#40)

    Bumps [clap](https://github.com/clap-rs/clap) from 4.4.10 to 4.4.12.
    - [Release notes](https://github.com/clap-rs/clap/releases)
    - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
    - [Commits](clap-rs/clap@v4.4.10...v4.4.12)
    
    ---
    updated-dependencies:
    - dependency-name: clap
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jan 3, 2024
    Copy the full SHA
    4079c13 View commit details
  3. Bump futures from 0.3.29 to 0.3.30 (#43)

    Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.29 to 0.3.30.
    - [Release notes](https://github.com/rust-lang/futures-rs/releases)
    - [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
    - [Commits](rust-lang/futures-rs@0.3.29...0.3.30)
    
    ---
    updated-dependencies:
    - dependency-name: futures
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jan 3, 2024
    Copy the full SHA
    1066c80 View commit details
  4. Bump tokio from 1.34.0 to 1.35.1 (#41)

    Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.34.0 to 1.35.1.
    - [Release notes](https://github.com/tokio-rs/tokio/releases)
    - [Commits](tokio-rs/tokio@tokio-1.34.0...tokio-1.35.1)
    
    ---
    updated-dependencies:
    - dependency-name: tokio
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jan 3, 2024
    Copy the full SHA
    51159ea View commit details
  5. Upgrade dependencies

    dmartin committed Jan 3, 2024
    Copy the full SHA
    1854afe View commit details
  6. Copy the full SHA
    e015420 View commit details

Commits on Jan 24, 2024

  1. Update dependencies

    dmartin committed Jan 24, 2024
    Copy the full SHA
    c1d0474 View commit details
  2. Copy the full SHA
    eddc0d0 View commit details
  3. Copy the full SHA
    469d749 View commit details

Commits on Feb 1, 2024

  1. Bump chrono from 0.4.32 to 0.4.33

    Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.32 to 0.4.33.
    - [Release notes](https://github.com/chronotope/chrono/releases)
    - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
    - [Commits](chronotope/chrono@v0.4.32...v0.4.33)
    
    ---
    updated-dependencies:
    - dependency-name: chrono
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Feb 1, 2024
    Copy the full SHA
    aa63496 View commit details

Commits on Mar 4, 2024

  1. Bump anyhow from 1.0.79 to 1.0.80

    Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.79 to 1.0.80.
    - [Release notes](https://github.com/dtolnay/anyhow/releases)
    - [Commits](dtolnay/anyhow@1.0.79...1.0.80)
    
    ---
    updated-dependencies:
    - dependency-name: anyhow
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Mar 4, 2024
    Copy the full SHA
    46672b1 View commit details
  2. Bump thiserror from 1.0.56 to 1.0.57

    Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.56 to 1.0.57.
    - [Release notes](https://github.com/dtolnay/thiserror/releases)
    - [Commits](dtolnay/thiserror@1.0.56...1.0.57)
    
    ---
    updated-dependencies:
    - dependency-name: thiserror
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Mar 4, 2024
    Copy the full SHA
    07387d8 View commit details
  3. Bump clap from 4.4.18 to 4.5.1

    Bumps [clap](https://github.com/clap-rs/clap) from 4.4.18 to 4.5.1.
    - [Release notes](https://github.com/clap-rs/clap/releases)
    - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
    - [Commits](clap-rs/clap@v4.4.18...clap_complete-v4.5.1)
    
    ---
    updated-dependencies:
    - dependency-name: clap
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Mar 4, 2024
    Copy the full SHA
    80685f7 View commit details
  4. Bump tokio from 1.35.1 to 1.36.0

    Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.35.1 to 1.36.0.
    - [Release notes](https://github.com/tokio-rs/tokio/releases)
    - [Commits](tokio-rs/tokio@tokio-1.35.1...tokio-1.36.0)
    
    ---
    updated-dependencies:
    - dependency-name: tokio
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Mar 4, 2024
    Copy the full SHA
    16e34d2 View commit details
  5. Bump chrono from 0.4.33 to 0.4.34

    Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.33 to 0.4.34.
    - [Release notes](https://github.com/chronotope/chrono/releases)
    - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
    - [Commits](chronotope/chrono@v0.4.33...v0.4.34)
    
    ---
    updated-dependencies:
    - dependency-name: chrono
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Mar 4, 2024
    Copy the full SHA
    b69b923 View commit details
  6. Update deps

    dmartin committed Mar 4, 2024
    Copy the full SHA
    c472e37 View commit details
  7. Copy the full SHA
    07a431a View commit details
  8. Bump actions/checkout from 2 to 4

    Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 4.
    - [Release notes](https://github.com/actions/checkout/releases)
    - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
    - [Commits](actions/checkout@v2...v4)
    
    ---
    updated-dependencies:
    - dependency-name: actions/checkout
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Mar 4, 2024
    Copy the full SHA
    7ebebae View commit details

Commits on Apr 1, 2024

  1. Bump thiserror from 1.0.57 to 1.0.58

    Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.57 to 1.0.58.
    - [Release notes](https://github.com/dtolnay/thiserror/releases)
    - [Commits](dtolnay/thiserror@1.0.57...1.0.58)
    
    ---
    updated-dependencies:
    - dependency-name: thiserror
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Apr 1, 2024
    Copy the full SHA
    31ea9b0 View commit details
  2. Bump anyhow from 1.0.80 to 1.0.81

    Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.80 to 1.0.81.
    - [Release notes](https://github.com/dtolnay/anyhow/releases)
    - [Commits](dtolnay/anyhow@1.0.80...1.0.81)
    
    ---
    updated-dependencies:
    - dependency-name: anyhow
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Apr 1, 2024
    Copy the full SHA
    2610be6 View commit details
  3. Bump chrono from 0.4.34 to 0.4.37

    Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.34 to 0.4.37.
    - [Release notes](https://github.com/chronotope/chrono/releases)
    - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
    - [Commits](chronotope/chrono@v0.4.34...v0.4.37)
    
    ---
    updated-dependencies:
    - dependency-name: chrono
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Apr 1, 2024
    Copy the full SHA
    16a47d4 View commit details
  4. Bump clap from 4.5.1 to 4.5.4

    Bumps [clap](https://github.com/clap-rs/clap) from 4.5.1 to 4.5.4.
    - [Release notes](https://github.com/clap-rs/clap/releases)
    - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
    - [Commits](clap-rs/clap@clap_complete-v4.5.1...v4.5.4)
    
    ---
    updated-dependencies:
    - dependency-name: clap
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Apr 1, 2024
    Copy the full SHA
    4edaad7 View commit details
  5. Bump softprops/action-gh-release from 1 to 2

    Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
    - [Release notes](https://github.com/softprops/action-gh-release/releases)
    - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
    - [Commits](softprops/action-gh-release@v1...v2)
    
    ---
    updated-dependencies:
    - dependency-name: softprops/action-gh-release
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Apr 1, 2024
    Copy the full SHA
    a0d0cd3 View commit details
  6. Bump bollard from 0.15.0 to 0.16.1

    Bumps [bollard](https://github.com/fussybeaver/bollard) from 0.15.0 to 0.16.1.
    - [Release notes](https://github.com/fussybeaver/bollard/releases)
    - [Commits](fussybeaver/bollard@v0.15.0...v0.16.1)
    
    ---
    updated-dependencies:
    - dependency-name: bollard
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Apr 1, 2024
    Copy the full SHA
    2d18589 View commit details

Commits on Apr 19, 2024

  1. Bump deps

    dmartin committed Apr 19, 2024
    Copy the full SHA
    b394eca View commit details

Commits on May 1, 2024

  1. Bump thiserror from 1.0.58 to 1.0.59

    Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.58 to 1.0.59.
    - [Release notes](https://github.com/dtolnay/thiserror/releases)
    - [Commits](dtolnay/thiserror@1.0.58...1.0.59)
    
    ---
    updated-dependencies:
    - dependency-name: thiserror
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed May 1, 2024
    Copy the full SHA
    43fde11 View commit details

Commits on Jun 3, 2024

  1. Update deps

    dmartin committed Jun 3, 2024
    Copy the full SHA
    4f0d717 View commit details

Commits on Jun 4, 2024

  1. Copy the full SHA
    8311ed4 View commit details
  2. Run tests in CI

    dmartin committed Jun 4, 2024
    Copy the full SHA
    c5f1dac View commit details
  3. Copy the full SHA
    721424d View commit details
  4. Copy the full SHA
    ae530f6 View commit details

Commits on Jun 5, 2024

  1. Add network reaping tests

    dmartin committed Jun 5, 2024
    Copy the full SHA
    589782b View commit details
  2. Add volume reaping tests

    dmartin committed Jun 5, 2024
    Copy the full SHA
    a04a090 View commit details
  3. Tag as v1.0.0

    dmartin committed Jun 5, 2024
    Copy the full SHA
    53832d3 View commit details

Commits on Jul 1, 2024

  1. Bump clap from 4.5.4 to 4.5.8

    Bumps [clap](https://github.com/clap-rs/clap) from 4.5.4 to 4.5.8.
    - [Release notes](https://github.com/clap-rs/clap/releases)
    - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
    - [Commits](clap-rs/clap@clap_complete-v4.5.4...v4.5.8)
    
    ---
    updated-dependencies:
    - dependency-name: clap
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored and dmartin committed Jul 1, 2024
    Copy the full SHA
    5b13b79 View commit details
Showing with 1,639 additions and 748 deletions.
  1. +6 −0 .github/dependabot.yml
  2. +4 −1 .github/workflows/ci.yaml
  3. +10 −4 .github/workflows/release.yaml
  4. +21 −4 CHANGELOG.md
  5. +852 −691 Cargo.lock
  6. +20 −13 Cargo.toml
  7. +12 −0 RELEASING.md
  8. +51 −29 src/lib.rs
  9. +8 −6 src/main.rs
  10. +232 −0 tests/common.rs
  11. +185 −0 tests/containers.rs
  12. +119 −0 tests/networks.rs
  13. +119 −0 tests/volumes.rs
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -6,3 +6,9 @@ updates:
interval: "monthly"
labels:
- "dependencies"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
labels:
- "dependencies"
5 changes: 4 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Set up Rust caching
@@ -43,3 +43,6 @@ jobs:
- name: Run clippy
run: |
cargo clippy -- -D warnings
- name: Run tests
run: |
cargo test
14 changes: 10 additions & 4 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -15,19 +15,25 @@ jobs:
steps:
- name: Create release
id: create-release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
build:
name: Build release binaries
runs-on: ${{ matrix.runner-os }}
needs: create-release
strategy:
matrix:
include:
- runner-os: ubuntu-20.04
- runner-os: ubuntu-22.04
rustc-target: "x86_64-unknown-linux-gnu"
- runner-os: ubuntu-22.04
rustc-target: "aarch64-unknown-linux-gnu"
- runner-os: macos-latest
rustc-target: "x86_64-apple-darwin"
- runner-os: macos-latest
rustc-target: "aarch64-apple-darwin"
steps:
- name: Checkout repo
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
@@ -44,6 +50,6 @@ jobs:
env:
suffix: ${{ matrix.rustc-target }}
- name: Upload tarball
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
files: out/*.tar.gz
25 changes: 21 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
# Changelog

## 0.1.1
## v1.1.0

- Fixes volume removal.
- Dependency updates.
- Linux binaries are now built on Ubuntu 22.04 runners (rather than 24.04) for compability with a wider range of glibc versions.

## 0.1.0
## v1.0.0

- Added integration tests.
- Updated dependencies.

## v0.1.3

- Updated dependencies.

## v0.1.2

- Updated dependencies.

## v0.1.1

- Fixed volume removal.
- Updated dependencies.

## v0.1.0

Initial release. Supports removal of matching containers, networks, and volumes based on creation time and Docker filter syntax.
1,543 changes: 852 additions & 691 deletions Cargo.lock

Large diffs are not rendered by default.

33 changes: 20 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
[package]
authors = ["Dustin Martin <dustin@dmartin.io>", "picoCTF Team <opensource@picoctf.org>"]
authors = ["picoCTF Team <opensource@picoctf.org>"]
description = "Command line tool for removing expired Docker resources"
edition = "2021"
edition = "2024"
license = "MIT OR Apache-2.0"
name = "docker-reaper"
repository = "https://github.com/picoCTF/docker-reaper"
version = "0.1.0"
version = "1.1.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.72"
bollard = {version = "0.14.0", features = ["ssl"]}
chrono = {version = "0.4.26", default-features = false, features = ["std", "clock"]}
clap = {version = "4.3.19", features = ["derive"]}
futures = "0.3.28"
anyhow = "1.0.98"
bollard = { version = "0.18.1", features = ["ssl"] }
chrono = { version = "0.4.41", default-features = false, features = [
"std",
"clock",
] }
clap = { version = "4.5.37", features = ["derive"] }
futures = "0.3.31"
go-parse-duration = "0.1.1"
tabled = "0.14.0"
thiserror = "1.0.44"
tokio = {version = "1.29.1", features = ["full"]}
tracing = "0.1.37"
tracing-subscriber = "0.3.17"
tabled = "0.19.0"
thiserror = "2.0.12"
tokio = { version = "1.44.2", features = ["full"] }
tracing = "0.1.41"
tracing-subscriber = "0.3.19"

[dev-dependencies]
serial_test = { version = "3.2.0" }
tokio-stream = "0.1.17"
12 changes: 12 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Releasing

1. Ensure that [`CHANGELOG.md`](./CHANGELOG.md) is up-to-date with all relevant changes. Additionally, make sure that the version specified in [Cargo.toml](./Cargo.toml) matches the to-be-released version.

1. Create and push a new Git tag for the version with a `v` prefix, e.g.:
```shell
git tag vX.Y.Z
git push --tags
```
This will automatically run the "Publish release" GitHub Actions workflow, which will create a GitHub release, build a release tarball, and attach the tarball to the release.

1. Edit the newly created GitHub release, setting the relevant section of `CHANGELOG.md` as the description.
80 changes: 51 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#[doc(no_inline)]
pub use bollard::Docker;
use bollard::container::{ListContainersOptions, RemoveContainerOptions};
use bollard::network::ListNetworksOptions;
use bollard::service::VolumeListResponse;
use bollard::volume::ListVolumesOptions;
#[doc(no_inline)]
pub use bollard::Docker;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::time::{SystemTime, UNIX_EPOCH};
@@ -51,7 +51,7 @@ pub struct ReapVolumesConfig<'a> {
}

#[derive(Debug)]
enum RemovalStatus {
pub enum RemovalStatus {
/// Used in dry-run mode to indicate that a resource is eligible for removal.
Eligible,
/// Resource was successfully removed.
@@ -108,10 +108,9 @@ impl Filter {
}

#[derive(Debug, PartialEq, Eq)]
enum ResourceType {
pub enum ResourceType {
Container,
Network,
#[allow(dead_code)]
Volume,
}

@@ -135,12 +134,17 @@ impl fmt::Display for ResourceType {
#[tabled(rename_all = "PascalCase")]
pub struct Resource {
#[tabled(rename = "Resource Type")]
resource_type: ResourceType,
pub resource_type: ResourceType,
#[tabled(skip)]
#[allow(dead_code)]
id: String,
name: String,
status: RemovalStatus,
pub id: String,
pub name: String,
pub status: RemovalStatus,
}

impl PartialEq for Resource {
fn eq(&self, other: &Self) -> bool {
self.resource_type == other.resource_type && self.id == other.id
}
}

impl Resource {
@@ -265,7 +269,7 @@ pub async fn reap_containers(
// reason, the returned creation time is missing or negative, skip the container.
let Some(creation_secs) = container.created else {
warn!("Skipped container {}: missing creation timestamp", id);
return false
return false;
};
let creation_secs: u64 = match creation_secs.try_into() {
Ok(secs) => secs,
@@ -275,8 +279,11 @@ pub async fn reap_containers(
}
};
let Some(age) = now.checked_sub(Duration::from_secs(creation_secs)) else {
warn!("Skipped container {}: creation timestamp after system time", id);
return false
warn!(
"Skipped container {}: creation timestamp after system time",
id
);
return false;
};
let within_age_range = age > config.min_age.unwrap_or(Duration::ZERO)
&& age < config.max_age.unwrap_or(Duration::MAX);
@@ -292,7 +299,7 @@ pub async fn reap_containers(
for container in eligible_containers {
let Some(id) = container.id else {
warn!("Skipped container (unknown ID): missing ID value");
continue
continue;
};
eligible_resources.push(Resource {
resource_type: ResourceType::Container,
@@ -368,19 +375,25 @@ pub async fn reap_networks(
eligible_networks.retain(|network| {
let Some(ref name) = network.name else {
warn!("Skipped network (unknown name): missing name value");
return false
return false;
};
let Some(ref creation_timestamp) = network.created else {
warn!("Skipped network {}: missing creation timestamp", name);
return false
return false;
};
let Ok(creation_time) = chrono::DateTime::parse_from_rfc3339(creation_timestamp) else {
warn!("Skipped network {}: failed to parse creation timestamp as RFC3339", name);
return false
warn!(
"Skipped network {}: failed to parse creation timestamp as RFC3339",
name
);
return false;
};
let Ok(age) = now.signed_duration_since(creation_time).to_std() else {
warn!("Skipped network {}: creation timestamp after system time", name);
return false
warn!(
"Skipped network {}: creation timestamp after system time",
name
);
return false;
};
let within_age_range = age > config.min_age.unwrap_or(Duration::ZERO)
&& age < config.max_age.unwrap_or(Duration::MAX);
@@ -394,9 +407,9 @@ pub async fn reap_networks(
.into_iter()
.filter_map(|network| {
let Some(name) = network.name else {
warn!("Skipped network (unknown name): missing name value");
return None
};
warn!("Skipped network (unknown name): missing name value");
return None;
};
Some(Resource {
resource_type: ResourceType::Network,
id: name.clone(),
@@ -447,20 +460,29 @@ pub async fn reap_volumes(
eligible_volumes.retain(|volume| {
let Some(ref creation_timestamp) = volume.created_at else {
warn!("Skipped volume {}: missing creation timestamp", volume.name);
return false
return false;
};
let Ok(creation_time) = chrono::DateTime::parse_from_rfc3339(creation_timestamp) else {
warn!("Skipped volume {}: failed to parse creation timestamp as RFC3339", volume.name);
return false
warn!(
"Skipped volume {}: failed to parse creation timestamp as RFC3339",
volume.name
);
return false;
};
let Ok(age) = now.signed_duration_since(creation_time).to_std() else {
warn!("Skipped volume {}: creation timestamp after system time", volume.name);
return false
warn!(
"Skipped volume {}: creation timestamp after system time",
volume.name
);
return false;
};
let within_age_range = age > config.min_age.unwrap_or(Duration::ZERO)
&& age < config.max_age.unwrap_or(Duration::MAX);
if !within_age_range {
debug!("Skipped volume {}: age outside of specified range", volume.name);
debug!(
"Skipped volume {}: age outside of specified range",
volume.name
);
}
within_age_range
})
14 changes: 8 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -4,10 +4,10 @@ use tracing::{debug, error, info, warn};
use anyhow::Context;
use clap::{Args, Parser, Subcommand};
use docker_reaper::{
reap_containers, reap_networks, reap_volumes, Docker, Filter, ReapContainersConfig,
ReapNetworksConfig, ReapVolumesConfig,
Docker, Filter, ReapContainersConfig, ReapNetworksConfig, ReapVolumesConfig, reap_containers,
reap_networks, reap_volumes,
};
use tokio::time::{sleep, Duration};
use tokio::time::{Duration, sleep};

#[derive(Debug, Parser)]
#[command(
@@ -131,7 +131,9 @@ async fn main() -> Result<(), anyhow::Error> {
debug!("Environment variable DOCKER_CERT_PATH set. Connecting via TLS");
Docker::connect_with_ssl_defaults()?
} else if env::var("DOCKER_HOST").is_ok() {
debug!("Environment variable DOCKER_HOST set, but not DOCKER_CERT_PATH. Connecting via HTTP");
debug!(
"Environment variable DOCKER_HOST set, but not DOCKER_CERT_PATH. Connecting via HTTP"
);
Docker::connect_with_http_defaults()?
} else {
debug!("Environment variable DOCKER_HOST not set, connecting to local machine");
@@ -185,15 +187,15 @@ async fn main() -> Result<(), anyhow::Error> {
info!("Found {} matching resources", removed_resources.len());
if !removed_resources.is_empty() {
use tabled::{
settings::{object::Columns, Modify, Style, Width},
Table,
settings::{Style, Width, object::Columns},
};
let mut table = Table::new(removed_resources);
info!(
"\n{}",
table
.with(Style::sharp())
.with(Modify::new(Columns::last()).with(Width::wrap(80)))
.modify(Columns::last(), Width::wrap(80))
.to_string()
);
}
232 changes: 232 additions & 0 deletions tests/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
//! Common utility functions for integration tests.
#![allow(dead_code)]

use bollard::Docker;
use bollard::container::{Config, NetworkingConfig};
use bollard::image::CreateImageOptions;
use bollard::network::CreateNetworkOptions;
use bollard::secret::{ContainerCreateResponse, EndpointSettings};
use bollard::volume::CreateVolumeOptions;
use chrono::Utc;
use docker_reaper::{
Filter, ReapContainersConfig, ReapNetworksConfig, ReapVolumesConfig, reap_containers,
reap_networks, reap_volumes,
};
use std::collections::HashMap;
use std::sync::OnceLock;
use tokio_stream::StreamExt;

/// A label set on all test-created Docker resources.
pub(crate) const TEST_LABEL: &str = "docker-reaper-test";

/// Obtain a client for the local Docker daemon.
pub(crate) fn docker_client() -> &'static Docker {
static CLIENT: OnceLock<Docker> = OnceLock::new();
CLIENT.get_or_init(|| {
Docker::connect_with_local_defaults().expect("failed to connect to Docker daemon")
})
}

/// Return type for [run_container] calls.
/// A network will not be created unless the `with_network` argument was `true`.
pub(crate) struct RunContainerResult {
pub(crate) container_id: String,
pub(crate) network_id: Option<String>,
}

/// Run a container on the local Docker daemon.
/// The label [TEST_LABEL] will always be set. Additional labels may also be specified.
pub(crate) async fn run_container(
with_network: bool,
extra_labels: Option<HashMap<String, String>>,
) -> RunContainerResult {
static TEST_IMAGE: &'static str = "busybox:latest";

let client = docker_client();
let mut labels = HashMap::from([(TEST_LABEL.to_string(), "true".to_string())]);
if let Some(ref extra_labels) = extra_labels {
labels.extend(extra_labels.clone().into_iter())
}
let mut network_id = None;

// Ensure test image is present on host
if client.inspect_image(&TEST_IMAGE).await.is_err() {
let mut pull_results_stream = client.create_image(
Some(CreateImageOptions {
from_image: TEST_IMAGE,
..Default::default()
}),
None,
None,
);
while let Some(result) = pull_results_stream.next().await {
result.expect("failed to pull test image");
}
}

let ContainerCreateResponse {
id: container_id, ..
} = client
.create_container::<String, String>(
None,
Config {
tty: Some(true),
cmd: None,
image: Some(TEST_IMAGE.to_string()),
labels: Some(labels),
networking_config: {
if with_network {
network_id = Some(create_network(extra_labels.clone()).await);
Some(NetworkingConfig {
endpoints_config: HashMap::from([(
"docker-reaper-test-network".to_string(),
EndpointSettings {
network_id: network_id.clone(),
..Default::default()
},
)]),
})
} else {
None
}
},
..Default::default()
},
)
.await
.expect("failed to create container");
client
.start_container::<&str>(&container_id, None)
.await
.expect(&format!("failed to start container {container_id}"));
RunContainerResult {
container_id,
network_id,
}
}

/// Create a network on the local Docker daemon. Returns the name of the created network.
/// The label [TEST_LABEL] will always be set. Additional labels may also be specified.
pub(crate) async fn create_network(extra_labels: Option<HashMap<String, String>>) -> String {
let client = docker_client();
let mut labels = HashMap::from([(TEST_LABEL.to_string(), "true".to_string())]);
if let Some(extra_labels) = extra_labels {
labels.extend(extra_labels.into_iter())
}
let name = Utc::now().timestamp_millis().to_string(); // network names must be unique
client
.create_network(CreateNetworkOptions {
name: name.clone(),
labels,
..Default::default()
})
.await
.expect("failed to create network");
// We use names rather than actual IDs to uniquely identify networks in docker-reaper
// because they are more meaningful in the user-facing output. Docker's handling of network
// names vs. IDs is strange - they can effectively be used interchangably.
name
}

/// Create a volume on the local Docker daemon. Returns the name of the created volume.
/// The label [TEST_LABEL] will always be set. Additional labels may also be specified.
pub(crate) async fn create_volume(extra_labels: Option<HashMap<String, String>>) -> String {
let client = docker_client();
let mut labels = HashMap::from([(TEST_LABEL.to_string(), "true".to_string())]);
if let Some(extra_labels) = extra_labels {
labels.extend(extra_labels.into_iter())
}
let name = Utc::now().timestamp_millis().to_string(); // volume names must be unique
client
.create_volume(CreateVolumeOptions {
name: name.clone(),
labels,
..Default::default()
})
.await
.expect("failed to create volume");
name
}

/// Check whether a container with the given ID exists.
pub(crate) async fn container_exists(id: &str) -> bool {
let client = docker_client();
match client.inspect_container(id, None).await {
Ok(_) => return true,
Err(err) => match err {
bollard::errors::Error::DockerResponseServerError {
status_code: 404, ..
} => return false,
_ => panic!("unexpected error: {err}"),
},
}
}

/// Check whether a network with the given name exists.
pub(crate) async fn network_exists(name: &str) -> bool {
let client = docker_client();
match client.inspect_network::<&str>(name, None).await {
Ok(_) => return true,
Err(err) => match err {
bollard::errors::Error::DockerResponseServerError {
status_code: 404, ..
} => return false,
_ => panic!("unexpected error: {err}"),
},
}
}

/// Check whether a volume with the given name exists.
pub(crate) async fn volume_exists(name: &str) -> bool {
let client = docker_client();
match client.inspect_volume(name).await {
Ok(_) => return true,
Err(err) => match err {
bollard::errors::Error::DockerResponseServerError {
status_code: 404, ..
} => return false,
_ => panic!("unexpected error: {err}"),
},
}
}

/// Clean up all remaining test resources.
pub(crate) async fn cleanup() {
let client = docker_client();
reap_containers(
client,
&ReapContainersConfig {
dry_run: false,
min_age: None,
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
reap_networks: true,
},
)
.await
.expect("failed to clean up containers");

reap_networks(
client,
&ReapNetworksConfig {
dry_run: false,
min_age: None,
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to clean up networks");

reap_volumes(
client,
&ReapVolumesConfig {
dry_run: false,
min_age: None,
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to clean up volumes");
}
185 changes: 185 additions & 0 deletions tests/containers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
//! Container reaping tests.
//!
//! These are run serially because all test-related resources are cleaned up after each test.
mod common;

use std::collections::HashMap;

use common::{
RunContainerResult, TEST_LABEL, cleanup, container_exists, docker_client, network_exists,
run_container,
};
use docker_reaper::{
Filter, ReapContainersConfig, RemovalStatus, Resource, ResourceType, reap_containers,
};
use serial_test::serial;
use tokio::time::{Duration, sleep};

/// Test that only containers older than the `min_age` threshold are reaped.
#[tokio::test]
#[serial]
async fn min_age() {
let RunContainerResult {
container_id: ref old_container_id,
..
} = run_container(false, None).await;
sleep(Duration::from_secs(2)).await;
let RunContainerResult {
container_id: ref new_container_id,
..
} = run_container(false, None).await;
reap_containers(
docker_client(),
&ReapContainersConfig {
dry_run: false,
min_age: Some(Duration::from_secs(2)),
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
reap_networks: false,
},
)
.await
.expect("failed to reap containers");
assert_eq!(container_exists(old_container_id).await, false);
assert_eq!(container_exists(new_container_id).await, true);
cleanup().await;
}

/// Test that only containers younger than the `max_age` threshold are reaped.
#[tokio::test]
#[serial]
async fn max_age() {
let RunContainerResult {
container_id: ref old_container_id,
..
} = run_container(false, None).await;
sleep(Duration::from_secs(2)).await;
let RunContainerResult {
container_id: ref new_container_id,
..
} = run_container(false, None).await;
reap_containers(
docker_client(),
&ReapContainersConfig {
dry_run: false,
min_age: None,
max_age: Some(Duration::from_secs(2)),
filters: &vec![Filter::new("label", TEST_LABEL)],
reap_networks: false,
},
)
.await
.expect("failed to reap containers");
assert_eq!(container_exists(old_container_id).await, true);
assert_eq!(container_exists(new_container_id).await, false);
cleanup().await;
}

/// Test that only containers matching the specified filters are reaped.
#[tokio::test]
#[serial]
async fn filters() {
let RunContainerResult {
container_id: ref purple_container_id,
..
} = run_container(
false,
Some(HashMap::from([("color".to_string(), "purple".to_string())])),
)
.await;
let RunContainerResult {
container_id: ref orange_container_id,
..
} = run_container(
false,
Some(HashMap::from([("color".to_string(), "orange".to_string())])),
)
.await;
reap_containers(
docker_client(),
&ReapContainersConfig {
dry_run: false,
min_age: None,
max_age: None,
filters: &vec![
Filter::new("label", TEST_LABEL),
Filter::new("label", "color=orange"),
],
reap_networks: false,
},
)
.await
.expect("failed to reap containers");
assert_eq!(container_exists(purple_container_id).await, true);
assert_eq!(container_exists(orange_container_id).await, false);
cleanup().await;
}

/// Test that container-associated networks are also removed if `reap_networks` is set.
#[tokio::test]
#[serial]
async fn reap_networks() {
let RunContainerResult {
container_id,
network_id,
} = run_container(true, None).await;
reap_containers(
docker_client(),
&ReapContainersConfig {
dry_run: false,
min_age: None,
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
reap_networks: true,
},
)
.await
.expect("failed to reap containers");
assert_eq!(
network_exists(&network_id.expect("network ID not present")).await,
false
);
assert_eq!(container_exists(&container_id).await, false);
cleanup().await;
}

/// Test that resources are identified but not removed if `dry_run` is set.
#[tokio::test]
#[serial]
async fn dry_run() {
let RunContainerResult {
container_id,
network_id,
} = run_container(true, None).await;
let result = reap_containers(
docker_client(),
&ReapContainersConfig {
dry_run: true,
min_age: None,
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
reap_networks: true,
},
)
.await
.expect("failed to reap containers");
assert!(result.contains(&Resource {
resource_type: ResourceType::Container,
id: container_id.clone(),
name: String::new(),
status: RemovalStatus::Eligible,
}));
assert!(result.contains(&Resource {
resource_type: ResourceType::Network,
id: network_id.clone().expect("network ID not present"),
name: String::new(),
status: RemovalStatus::Eligible,
}));
assert_eq!(
network_exists(&network_id.expect("network ID not present")).await,
true
);
assert_eq!(container_exists(&container_id).await, true);
cleanup().await;
}
119 changes: 119 additions & 0 deletions tests/networks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//! Network reaping tests.
//!
//! These are run serially because all test-related resources are cleaned up after each test.
mod common;

use std::collections::HashMap;

use common::{TEST_LABEL, cleanup, create_network, docker_client, network_exists};
use docker_reaper::{
Filter, ReapNetworksConfig, RemovalStatus, Resource, ResourceType, reap_networks,
};
use serial_test::serial;
use tokio::time::{Duration, sleep};

/// Test that only networks older than the `min_age` threshold are reaped.
#[tokio::test]
#[serial]
async fn min_age() {
let old_network_id = create_network(None).await;
sleep(Duration::from_secs(2)).await;
let new_network_id = create_network(None).await;
reap_networks(
docker_client(),
&ReapNetworksConfig {
dry_run: false,
min_age: Some(Duration::from_secs(2)),
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to reap networks");
assert_eq!(network_exists(&old_network_id).await, false);
assert_eq!(network_exists(&new_network_id).await, true);
cleanup().await;
}

/// Test that only networks younger than the `max_age` threshold are reaped.
#[tokio::test]
#[serial]
async fn max_age() {
let old_network_id = create_network(None).await;
sleep(Duration::from_secs(2)).await;
let new_network_id = create_network(None).await;
reap_networks(
docker_client(),
&ReapNetworksConfig {
dry_run: false,
min_age: None,
max_age: Some(Duration::from_secs(2)),
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to reap networks");
assert_eq!(network_exists(&old_network_id).await, true);
assert_eq!(network_exists(&new_network_id).await, false);
cleanup().await;
}

/// Test that only networks matching the specified filters are reaped.
#[tokio::test]
#[serial]
async fn filters() {
let purple_network_id = create_network(Some(HashMap::from([(
"color".to_string(),
"purple".to_string(),
)])))
.await;
let orange_network_id = create_network(Some(HashMap::from([(
"color".to_string(),
"orange".to_string(),
)])))
.await;
reap_networks(
docker_client(),
&ReapNetworksConfig {
dry_run: false,
min_age: None,
max_age: None,
filters: &vec![
Filter::new("label", TEST_LABEL),
Filter::new("label", "color=orange"),
],
},
)
.await
.expect("failed to reap networks");
assert_eq!(network_exists(&purple_network_id).await, true);
assert_eq!(network_exists(&orange_network_id).await, false);
cleanup().await;
}

/// Test that resources are identified but not removed if `dry_run` is set.
#[tokio::test]
#[serial]
async fn dry_run() {
let network_id = create_network(None).await;
let result = reap_networks(
docker_client(),
&ReapNetworksConfig {
dry_run: true,
min_age: None,
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to reap networks");
assert!(result.contains(&Resource {
resource_type: ResourceType::Network,
id: network_id.clone(),
name: String::new(),
status: RemovalStatus::Eligible
}));
assert_eq!(network_exists(&network_id).await, true);
cleanup().await;
}
119 changes: 119 additions & 0 deletions tests/volumes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//! Volume reaping tests.
//!
//! These are run serially because all test-related resources are cleaned up after each test.
mod common;

use std::collections::HashMap;

use common::{TEST_LABEL, cleanup, create_volume, docker_client, volume_exists};
use docker_reaper::{
Filter, ReapVolumesConfig, RemovalStatus, Resource, ResourceType, reap_volumes,
};
use serial_test::serial;
use tokio::time::{Duration, sleep};

/// Test that only volumes older than the `min_age` threshold are reaped.
#[tokio::test]
#[serial]
async fn min_age() {
let old_volume_id = create_volume(None).await;
sleep(Duration::from_secs(2)).await;
let new_volume_id = create_volume(None).await;
reap_volumes(
docker_client(),
&ReapVolumesConfig {
dry_run: false,
min_age: Some(Duration::from_secs(2)),
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to reap volumes");
assert_eq!(volume_exists(&old_volume_id).await, false);
assert_eq!(volume_exists(&new_volume_id).await, true);
cleanup().await;
}

/// Test that only volumes younger than the `max_age` threshold are reaped.
#[tokio::test]
#[serial]
async fn max_age() {
let old_volume_id = create_volume(None).await;
sleep(Duration::from_secs(2)).await;
let new_volume_id = create_volume(None).await;
reap_volumes(
docker_client(),
&ReapVolumesConfig {
dry_run: false,
min_age: None,
max_age: Some(Duration::from_secs(2)),
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to reap volumes");
assert_eq!(volume_exists(&old_volume_id).await, true);
assert_eq!(volume_exists(&new_volume_id).await, false);
cleanup().await;
}

/// Test that only volumes matching the specified filters are reaped.
#[tokio::test]
#[serial]
async fn filters() {
let purple_volume_id = create_volume(Some(HashMap::from([(
"color".to_string(),
"purple".to_string(),
)])))
.await;
let orange_volume_id = create_volume(Some(HashMap::from([(
"color".to_string(),
"orange".to_string(),
)])))
.await;
reap_volumes(
docker_client(),
&ReapVolumesConfig {
dry_run: false,
min_age: None,
max_age: None,
filters: &vec![
Filter::new("label", TEST_LABEL),
Filter::new("label", "color=orange"),
],
},
)
.await
.expect("failed to reap volumes");
assert_eq!(volume_exists(&purple_volume_id).await, true);
assert_eq!(volume_exists(&orange_volume_id).await, false);
cleanup().await;
}

/// Test that resources are identified but not removed if `dry_run` is set.
#[tokio::test]
#[serial]
async fn dry_run() {
let volume_id = create_volume(None).await;
let result = reap_volumes(
docker_client(),
&ReapVolumesConfig {
dry_run: true,
min_age: None,
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to reap volumes");
assert!(result.contains(&Resource {
resource_type: ResourceType::Volume,
id: volume_id.clone(),
name: String::new(),
status: RemovalStatus::Eligible
}));
assert_eq!(volume_exists(&volume_id).await, true);
cleanup().await;
}