Skip to content

Commit

Permalink
Merge pull request #1 from Tatskaari/init
Browse files Browse the repository at this point in the history
Initial release
  • Loading branch information
Tatskaari authored Jul 11, 2023
2 parents f6154fa + b637f04 commit 64f0697
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 0 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Kubernetes rules
on:
- push
- pull_request
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Run tests
run: ./pleasew test --log_file plz-out/log/test.log
- name: Archive logs
if: always()
uses: actions/upload-artifact@v2
with:
name: logs
path: |
plz-out/log
release:
needs:
- test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: thought-machine/release-action@master
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

# Entries below this point are managed by Please (DO NOT EDIT)
plz-out
.plzconfig.local
8 changes: 8 additions & 0 deletions .plzconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[please]
version = >=17.0.0

[PluginDefinition]
Name = k8s

[Plugin "shell"]
Target = //plugins:shell
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Version 0.1.0
-------------
* Initial release
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1.0
5 changes: 5 additions & 0 deletions build_defs/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
filegroup(
name = "k8s",
srcs = ["k8s.build_defs"],
visibility = ["PUBLIC"],
)
108 changes: 108 additions & 0 deletions build_defs/k8s.build_defs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
subinclude("///shell//build_defs:shell")

"""Rules for building Kubernetes objects."""


def k8s_config(name:str, srcs:list, containers:list=[], params:dict=None, visibility:list=None,
labels:list=[]):
"""Defines some Kubernetes config and performs templating of containers.

For each k8s_config rule, one genrule per container and two genrules per src are generated:
- The genrule for each container will build the container and store the full name + label
to the output file.
- The first genrule for each source will parse the YAML configs, and extract volume mounts
that are prefixed with /etc/hault/, storing them as JSON output to be consumed by an
external script.
- The second genrule for each source will template the generic config and store the templated
version.

The final rule is simply a filegroup of the templated configs.

Args:
name: Name of the rule.
srcs: YAML config files containing the Kubernetes config.
containers: Container dependencies to template into the config file. The config
contains Please build labels to refer to containers which are replaced with
actual locations when the config is built.
These rules will need to be docker_image rules (or something similar).
params: Map defining overrides for shell-substitution variables in srcs; if set, srcs is
passed through envsubst using the defined map.
visibility: Visibility of the rule
labels: Labels for this rule
"""
returned_targets = {}
containers = [c for c in containers if c]

# Make sure to canonicalise each container (they could be in the form of ':local_container').
containers = [canonicalise(container) for container in containers]

# This will template image tags into k8s resource files that reference docker images by build target.
fqns = [f'{c}_fqn' for c in containers]
# Tag with appropriate labels
labels += ['k8s'] + ['container:' + c for c in containers]

# Template each config YAML and collect them in the filegroup.
rules = []

# Now that we have a collection of files, each containing a container name + label, we can
# create a multi-expression sed command to replace a build target with the actual containers.
exports = [f'export {k}={v}' for k,v in params.items()] if params else []
replacement_command = 'cat'
envsubst_vars = ",".join(['${%s}' % k for k in params.keys()] if params else [])
check_rule = None
if containers:
# Pseudo build rule to check that the specified containers exist in the k8s files.
# Has to be a separate rule because containers might only occur in one of the files.
check_rule = build_rule(
name=name,
tag='check',
cmd='for IMG in %s; do grep "$IMG" $SRCS || (echo "Image $IMG not in k8s files"; exit 1); done' % ' '.join(containers),
srcs=srcs,
)

# macos sed only supports posix regex expressions so escape sequences like \b don't work
boundary_expr = "\\b" if CONFIG.HOSTOS != 'darwin' else ""
subcommands = ' '.join([
f'-e "s|{container}{boundary_expr}|$(cat $(location {fqn}))|g"'
for container, fqn in sorted(zip(containers, fqns))
])
replacement_command = f'sed {subcommands}'

for src in srcs:
cleaned_src = src.replace('/', '_').replace(':', '_')
src_tag = cleaned_src.replace('.', '_')
src_genrule_name = f'_{name}#{src_tag}'
if cleaned_src.endswith('_yaml'):
cleaned_src = cleaned_src[:-5] + '.yaml'
rules.append(f':{src_genrule_name}')
genrule(
name = src_genrule_name,
srcs = [src],
outs = ['templated_' + cleaned_src],
cmd = exports + [f"cat $SRCS | {replacement_command} | envsubst '{envsubst_vars}' > $OUT"],
deps = fqns + [check_rule if check_rule else None],
)

files = filegroup(
name = name,
srcs = rules,
visibility = visibility,
labels = labels,
)

# Generate a rule to push the configs.
sh_cmd(
name = name + '_push',
cmd = ' && '.join([f'kubectl apply -f $(out_location {x})' for x in rules]),
deps = rules,
labels = ["k8s-push"],
)

# Generate a rule to cleanup the configs.
sh_cmd(
name = name + '_cleanup',
cmd = ' && '.join([f'kubectl delete --ignore-not-found -f $(out_location {x})' for x in rules]),
deps = rules,
labels = ["k8s-cleanup"],
)
return files
176 changes: 176 additions & 0 deletions pleasew
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
#!/bin/sh

set -e
set -u

ESC="$(printf '\033')"

if [ "${NOCOLOR+x}" != 'x' ] || [ "${NO_COLOR+x}" != 'x' ]; then
RED="${ESC}[31m"
GREEN="${ESC}[32m"
YELLOW="${ESC}[33m"
RESET="${ESC}[0m"
else
RED=''
GREEN=''
YELLOW=''
RESET=''
fi


DEFAULT_URL_BASE='https://get.please.build'

OS="$(uname)"

if [ "${OS}" = 'Darwin' ]; then
# switch between mac amd64/arm64
ARCH="$(uname -m)"
else
# default to amd64 on other operating systems
# because we only build intel binaries
ARCH='amd64'
fi

case "${ARCH}" in
aarch64_be|aarch64|armv8b|armv8l) ARCH='arm64' ;;
x86_64) ARCH='amd64' ;;
esac

has_command () {
command -v "${1}" > /dev/null 2>&1
}

get_profile () {
while [ "${#}" -gt 0 ]
do
case "${1}" in
--profile=*) echo "${1#*=}"; return;;
--profile) echo "${2}"; return;;
*) shift;;
esac
done
}

# Check `PLZ_CONFIG_PROFILE` or fall back to arguments for a profile.
PROFILE="${PLZ_CONFIG_PROFILE:-$(get_profile "${@}")}"

# Config files on order of precedence high to low.
CONFIGS="$(cat <<- EOS
.plzconfig.local
${PROFILE:+.plzconfig.${PROFILE}}
.plzconfig_${OS}_${ARCH}
.plzconfig
${HOME}/.config/please/plzconfig
/etc/please/plzconfig
EOS
)"

read_config() {
# Disable globbing to ensure word-splitting is safe.
set -f

old_ifs="${IFS}"
search_term="${1}"

IFS='
'

# This is intended, we *do* want word-splitting here.
# shellcheck disable=2086
set -- ${CONFIGS}

grep -i "${search_term}" "${@}" 2> /dev/null | head -n 1

IFS="${old_ifs}"
set +f
}

# We might already have it downloaded...
LOCATION="$(read_config '^\s*location' | cut -d '=' -f 2 | tr -d ' ')"

if [ "${LOCATION:+x}" != 'x' ]; then
if [ "${HOME:+x}" != 'x' ]; then
# shellcheck disable=2016
printf >&2 '%b$HOME not set, not sure where to look for Please.%b\n' "${RED}" "${RESET}"
exit 1
fi

LOCATION="${HOME}/.please"
else
# It can contain a literal ~, need to explicitly handle that.
LOCATION="$(echo "${LOCATION}" | sed "s|~|${HOME}|")"
fi

# If this exists at any version, let it handle any update.
TARGET="${LOCATION}/please"

if [ -f "${TARGET}" ]; then
# shellcheck disable=2086
exec "${TARGET}" ${PLZ_ARGS:-} "${@}"
fi

URL_BASE="$(read_config '^\s*downloadlocation' | cut -d '=' -f 2 | tr -d ' ')"

if [ "${URL_BASE:+x}" != 'x' ]; then
URL_BASE="${DEFAULT_URL_BASE}"
fi

URL_BASE="${URL_BASE%/}"

VERSION="$(read_config '^\s*version[^a-z]')"
VERSION="${VERSION#*=}" # Strip until after first =
VERSION="$(echo "${VERSION}" | tr -d ' ')" # Remove all spaces
VERSION="${VERSION#>=}" # Strip any initial >=

if has_command curl; then
TRANSFER_TOOL='curl'
TRANSFER_SILENT_OPTS='-fsSL'
TRANSFER_PROGRESS_OPTS='-fSL'
elif has_command wget; then
TRANSFER_TOOL='wget'
TRANSFER_SILENT_OPTS='-qO-'
TRANSFER_PROGRESS_OPTS='-O-'
else
printf >&2 '%bUnable to find a command for network operations%b\n' "${RED}" "${RESET}"
printf >&2 'Please install either curl or wget\n'
exit 1
fi

if [ "${VERSION:+x}" != 'x' ]; then
printf >&2 "%bCan't determine version, will use latest.%b\n" "${YELLOW}" "${RESET}"
VERSION=$(${TRANSFER_TOOL} ${TRANSFER_SILENT_OPTS} "${URL_BASE}"/latest_version)
fi

# Find the os / arch to download. You can do this quite nicely with go env
# but we use this script on machines that don't necessarily have Go itself.
if [ "${OS}" = 'Linux' ]; then
GOOS='linux'
elif [ "${OS}" = 'Darwin' ]; then
GOOS='darwin'
elif [ "${OS}" = 'FreeBSD' ]; then
GOOS='freebsd'
else
printf >&2 '%bUnknown operating system %s%b\n' "${RED}" "${OS}" "${RESET}"
exit 1
fi

PLEASE_URL="${URL_BASE}/${GOOS}_${ARCH}/${VERSION}/please_${VERSION}.tar.xz"
DIR="${LOCATION}/${VERSION}"

# Potentially we could reuse this but it's easier not to really.
if [ ! -d "${DIR}" ]; then
rm -Rf "${DIR}"
fi

printf >&2 '%bDownloading Please %s to %s...%b\n' "${GREEN}" "${VERSION}" "${DIR}" "${RESET}"
mkdir -p "${DIR}"
${TRANSFER_TOOL} ${TRANSFER_PROGRESS_OPTS} "${PLEASE_URL}" | tar -xJpf- --strip-components=1 -C "${DIR}"

# Link it all back up a dir
for x in "${DIR}"/*; do
ln -sf "${x}" "${LOCATION}"
done

printf >&2 '%bShould be good to go now, running plz...%b\n' "${GREEN}" "${RESET}"
# shellcheck disable=2086
exec "${TARGET}" ${PLZ_ARGS:-} "${@}"
6 changes: 6 additions & 0 deletions plugins/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
plugin_repo(
name = "shell",
revision = "v0.2.0",
plugin = "shell-rules",
owner = "please-build",
)

0 comments on commit 64f0697

Please sign in to comment.