Skip to content

Commit

Permalink
Merge pull request #4 from irfansofyana/lazydocker
Browse files Browse the repository at this point in the history
add lazydocker
  • Loading branch information
irfansofyana authored Jan 7, 2025
2 parents 48dc20d + 4221d16 commit 7160662
Show file tree
Hide file tree
Showing 10 changed files with 344 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
matrix:
features:
- kcat-apt
- lazydocker-binary-release
baseImage:
- debian:latest
- ubuntu:latest
Expand All @@ -34,6 +35,7 @@ jobs:
matrix:
features:
- kcat-apt
- lazydocker-binary-release
steps:
- uses: actions/checkout@v4

Expand Down
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ This repository contains my personal collection of [Dev Container Features](http

## Available Features

### `lazydocker-binary-release`

A simple terminal UI for both docker and docker-compose, installed via Linux binary release. This feature provides an intuitive interface to manage Docker containers, services, and logs.

```jsonc
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/irfanputra/devcontainer-features/lazydocker-binary-release:1": {
"version": "latest"
}
}
}
```

#### Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| version | string | "latest" | The version of lazydocker to install (e.g. '0.24.1'). Defaults to the latest version. |

### `kcat-apt`

A Kafka command line utility using kcat (formerly kafkacat). This feature is specifically designed for Debian/Ubuntu-based containers.
Expand Down
Empty file.
14 changes: 14 additions & 0 deletions src/lazydocker-binary-release/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "lazydocker",
"id": "lazydocker-binary-release",
"version": "1.0.0",
"description": "A simple terminal UI for both docker and docker-compose. Installed by linux binary release",
"documentationURL": "https://github.com/irfansofyana/devcontainer-features/src/lazy-docker-binary-release",
"options": {
"version": {
"type": "string",
"default": "latest",
"description": "The version of lazydocker to install (e.g. 0.24.1). Defaults to the latest version."
}
}
}
43 changes: 43 additions & 0 deletions src/lazydocker-binary-release/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash -i

set -e
source ./library_scripts.sh

# nanolayer is a cli utility which keeps container layers as small as possible
# source code: https://github.com/devcontainers-contrib/nanolayer
# `ensure_nanolayer` is a bash function that will find any existing nanolayer installations,
# and if missing - will download a temporary copy that automatically get deleted at the end
# of the script
ensure_nanolayer nanolayer_location "v0.4.29"

$nanolayer_location \
install \
devcontainer-feature \
"ghcr.io/devcontainers-contrib/features/apt-get-packages:1.0.4" \
--option packages='curl,ca-certificates'

# Get the version from the options, defaulting to "latest"
VERSION=${VERSION:-"latest"}

if [[ "$VERSION" == "latest" ]]; then
LAZYDOCKER_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazydocker/releases/latest" | grep -Po '"tag_name": "v\K[^"]*')
else
# Validate if the specified version exists
if curl -s "https://api.github.com/repos/jesseduffield/lazydocker/releases/tags/v$VERSION" | grep -q '"message": "Not Found"'; then
echo "Version $VERSION does not exist."
exit 1
fi
LAZYDOCKER_VERSION=$VERSION
fi

if [[ $(uname -m) == "x86_64" ]]; then
curl -Lo lazydocker.tar.gz "https://github.com/jesseduffield/lazydocker/releases/download/v${LAZYDOCKER_VERSION}/lazydocker_${LAZYDOCKER_VERSION}_Linux_x86_64.tar.gz"
elif [[ $(uname -m) == "aarch64" ]]; then
curl -Lo lazydocker.tar.gz "https://github.com/jesseduffield/lazydocker/releases/download/v${LAZYDOCKER_VERSION}/lazydocker_${LAZYDOCKER_VERSION}_Linux_arm64.tar.gz"
else
echo "Unsupported architecture"
exit 1
fi

tar xf lazydocker.tar.gz lazydocker
install lazydocker /usr/local/bin
193 changes: 193 additions & 0 deletions src/lazydocker-binary-release/library_scripts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
#!/bin/bash -i

## This is part of devcontainers-contrib script library
# source: https://github.com/devcontainers-contrib/features
updaterc() {
if cat /etc/os-release | grep "ID_LIKE=.*alpine.*\|ID=.*alpine.*" ; then
echo "Updating /etc/profile"
echo -e "$1" >>/etc/profile
fi
if [[ "$(cat /etc/bash.bashrc)" != *"$1"* ]]; then
echo "Updating /etc/bash.bashrc"
echo -e "$1" >>/etc/bash.bashrc
fi
if [ -f "/etc/zsh/zshrc" ] && [[ "$(cat /etc/zsh/zshrc)" != *"$1"* ]]; then
echo "Updating /etc/zsh/zshrc"
echo -e "$1" >>/etc/zsh/zshrc
fi
}


clean_download() {
# The purpose of this function is to download a file with minimal impact on container layer size
# this means if no valid downloader is found (curl or wget) then we install a downloader (currently wget) in a
# temporary manner, and making sure to
# 1. uninstall the downloader at the return of the function
# 2. revert back any changes to the package installer database/cache (for example apt-get lists)
# The above steps will minimize the leftovers being created while installing the downloader
# Supported distros:
# debian/ubuntu/alpine

url=$1
output_location=$2
tempdir=$(mktemp -d)
downloader_installed=""

function _apt_get_install() {
tempdir=$1

# copy current state of apt list - in order to revert back later (minimize contianer layer size)
cp -p -R /var/lib/apt/lists $tempdir
apt-get update -y
apt-get -y install --no-install-recommends wget ca-certificates
}

function _apt_get_cleanup() {
tempdir=$1

echo "removing wget"
apt-get -y purge wget --auto-remove

echo "revert back apt lists"
rm -rf /var/lib/apt/lists/*
rm -r /var/lib/apt/lists && mv $tempdir/lists /var/lib/apt/lists
}

function _apk_install() {
tempdir=$1
# copy current state of apk cache - in order to revert back later (minimize contianer layer size)
cp -p -R /var/cache/apk $tempdir

apk add --no-cache wget
}

function _apk_cleanup() {
tempdir=$1

echo "removing wget"
apk del wget
}
# try to use either wget or curl if one of them already installer
if type curl >/dev/null 2>&1; then
downloader=curl
elif type wget >/dev/null 2>&1; then
downloader=wget
else
downloader=""
fi

# in case none of them is installed, install wget temporarly
if [ -z $downloader ] ; then
if [ -x "/usr/bin/apt-get" ] ; then
_apt_get_install $tempdir
elif [ -x "/sbin/apk" ] ; then
_apk_install $tempdir
else
echo "distro not supported"
exit 1
fi
downloader="wget"
downloader_installed="true"
fi

if [ $downloader = "wget" ] ; then
wget -q $url -O $output_location
else
curl -sfL $url -o $output_location
fi

# NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because
# alpine lack bash, and RETURN is not a valid signal under sh shell
if ! [ -z $downloader_installed ] ; then
if [ -x "/usr/bin/apt-get" ] ; then
_apt_get_cleanup $tempdir
elif [ -x "/sbin/apk" ] ; then
_apk_cleanup $tempdir
else
echo "distro not supported"
exit 1
fi
fi

}


ensure_nanolayer() {
# Ensure existance of the nanolayer cli program
local variable_name=$1

local required_version=$2
# normalize version
if ! [[ $required_version == v* ]]; then
required_version=v$required_version
fi

local nanolayer_location=""

# If possible - try to use an already installed nanolayer
if [[ -z "${NANOLAYER_FORCE_CLI_INSTALLATION}" ]]; then
if [[ -z "${NANOLAYER_CLI_LOCATION}" ]]; then
if type nanolayer >/dev/null 2>&1; then
echo "Found a pre-existing nanolayer in PATH"
nanolayer_location=nanolayer
fi
elif [ -f "${NANOLAYER_CLI_LOCATION}" ] && [ -x "${NANOLAYER_CLI_LOCATION}" ] ; then
nanolayer_location=${NANOLAYER_CLI_LOCATION}
echo "Found a pre-existing nanolayer which were given in env variable: $nanolayer_location"
fi

# make sure its of the required version
if ! [[ -z "${nanolayer_location}" ]]; then
local current_version
current_version=$($nanolayer_location --version)
if ! [[ $current_version == v* ]]; then
current_version=v$current_version
fi

if ! [ $current_version == $required_version ]; then
echo "skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version)"
nanolayer_location=""
fi
fi

fi

# If not previuse installation found, download it temporarly and delete at the end of the script
if [[ -z "${nanolayer_location}" ]]; then

if [ "$(uname -sm)" == "Linux x86_64" ] || [ "$(uname -sm)" == "Linux aarch64" ]; then
tmp_dir=$(mktemp -d -t nanolayer-XXXXXXXXXX)

clean_up () {
ARG=$?
rm -rf $tmp_dir
exit $ARG
}
trap clean_up EXIT


if [ -x "/sbin/apk" ] ; then
clib_type=musl
else
clib_type=gnu
fi

tar_filename=nanolayer-"$(uname -m)"-unknown-linux-$clib_type.tgz

# clean download will minimize leftover in case a downloaderlike wget or curl need to be installed
clean_download https://github.com/devcontainers-contrib/cli/releases/download/$required_version/$tar_filename $tmp_dir/$tar_filename

tar xfzv $tmp_dir/$tar_filename -C "$tmp_dir"
chmod a+x $tmp_dir/nanolayer
nanolayer_location=$tmp_dir/nanolayer


else
echo "No binaries compiled for non-x86-linux architectures yet: $(uname -m)"
exit 1
fi
fi

# Expose outside the resolved location
declare -g ${variable_name}=$nanolayer_location
}
21 changes: 21 additions & 0 deletions test/lazydocker-binary-release/latest.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

# This test file will be executed against an auto-generated devcontainer.json that
# includes the 'lazydocker-binary-release' Feature with no options.
#
# For more information, see: https://github.com/devcontainers/cli/blob/main/docs/features/test.md
#
# Thus, the value of all options will fall back to the default value in the
# Feature's 'devcontainer-feature.json'.

set -e

# Optional: Import test library bundled with the devcontainer CLI
source dev-container-features-test-lib

# Feature-specific tests
# The 'check' command comes from the dev-container-features-test-lib.
check "lazydocker" lazydocker --version

# Report result
reportResults
16 changes: 16 additions & 0 deletions test/lazydocker-binary-release/scenarios.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"latest": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"lazydocker-binary-release": {}
}
},
"specific_version": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"lazydocker-binary-release": {
"version": "0.23.0"
}
}
}
}
13 changes: 13 additions & 0 deletions test/lazydocker-binary-release/specific_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

set -e

# Import test library
source dev-container-features-test-lib

# Feature-specific tests
check "validate lazydocker installation" which lazydocker
check "validate lazydocker version" lazydocker --version | grep "0.23.0"

# Report result
reportResults
21 changes: 21 additions & 0 deletions test/lazydocker-binary-release/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

# This test file will be executed against an auto-generated devcontainer.json that
# includes the 'lazydocker' Feature with no options.
#
# For more information, see: https://github.com/devcontainers/cli/blob/main/docs/features/test.md
#
# Thus, the value of all options will fall back to the default value in the
# Feature's 'devcontainer-feature.json'.

set -e

# Optional: Import test library bundled with the devcontainer CLI
source dev-container-features-test-lib

# Feature-specific tests
check "validate lazydocker installation" which lazydocker
check "validate version" lazydocker --version

# Report result
reportResults

0 comments on commit 7160662

Please sign in to comment.