Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update readme & add check help #2

Merged
merged 8 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ jobs:
BATSLIB_TEMP_PRESERVE_ON_FAILURE: "0"

steps:
- uses: actions/checkout@v3

- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7

- name: Install Ruby dependencies
run: bundle install

- name: Install dependencies
run: |
mkdir -p "$HOME/.local"
npm install --prefix "$HOME/.local" bats bats-support bats-assert
gem install bashcov:'< 2' simplecov-cobertura:'< 2'
curl -fsSL https://github.com/mozilla/sops/releases/download/v${{ env.SOPS_VERSION }}/sops-v${SOPS_VERSION}.linux -o /usr/local/bin/sops
chmod +x /usr/local/bin/sops
curl -fsSL https://github.com/helmfile/vals/releases/download/v${{ env.VALS_VERSION }}/vals_${VALS_VERSION}_linux_amd64.tar.gz | tar xzf - -C /usr/local/bin/ vals
Expand All @@ -44,8 +48,6 @@ jobs:
echo "BATS_LIB_PATH=$HOME/.local/node_modules" >> "$GITHUB_ENV"
echo "SOPS_AGE_KEY_FILE=$PWD/tests/age/key.txt" >> "$GITHUB_ENV"

- uses: actions/checkout@v3

- name: run test
run: bashcov -- bats -r --timing --tap --report-formatter junit tests

Expand Down
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source 'https://rubygems.org'

gem 'bashcov'
gem 'simplecov'
gem 'simplecov-cobertura'
27 changes: 27 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
GEM
remote: https://rubygems.org/
specs:
bashcov (1.8.1)
simplecov (~> 0.15)
docile (1.4.0)
rexml (3.2.6)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-cobertura (2.1.0)
rexml
simplecov (~> 0.19)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4)

PLATFORMS
ruby

DEPENDENCIES
bashcov
simplecov
simplecov-cobertura

BUNDLED WITH
2.1.2
42 changes: 31 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
[![CI](https://github.com/joelee2012/skustomize/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/joelee2012/skustomize/actions/workflows/ci.yaml)
[![codecov](https://codecov.io/gh/joelee2012/skustomize/branch/main/graph/badge.svg?token=HEKUTJ7AH2)](https://codecov.io/gh/joelee2012/skustomize)
# skustomize

## About

skustomize is a wrapper for [kustomize](https://github.com/kubernetes-sigs/kustomize) that generate secrets with [secretGenerator](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/secretgenerator/) from different providers on the fly.

* Use [vals](https://github.com/helmfile/vals) to load values and secrets from providers
* Use skustomize in ArgoCD


## Installation

### prerequisite
### Prerequisites

* [kustomize](https://github.com/kubernetes-sigs/kustomize)
* [yq](https://github.com/mikefarah/yq) a lightweight and portable command-line YAML processor.
* [kustomize](https://github.com/kubernetes-sigs/kustomize) is a tool to customize Kubernetes objects
* [vals](https://github.com/helmfile/vals) is a tool for managing configuration values and secrets form various sources.
* [yq](https://github.com/mikefarah/yq) is a lightweight and portable command-line YAML processor.

It supports various backends:

Expand All @@ -30,14 +27,24 @@ skustomize is a wrapper for [kustomize](https://github.com/kubernetes-sigs/kusto
* [Plain File](https://github.com/helmfile/vals#file)


### install skustomize
git clone https://github.com/joelee2012/skustomize/skustomize
### Install skustomize

```sh
curl -Lvo /usr/local/bin/skustomize https://raw.githubusercontent.com/joelee2012/skustomize/main/skustomize
chmod +x /usr/local/bin/skustomize
# optinal
echo 'alias kustomize=skustomize' >> ~/.bashrc
source ~/.bashrc
```


## Usage

create [kustomization.yaml](./tests/kustomization.yaml)
Check [tests](./tests) as example

- Create [kustomization.yaml](./tests/kustomization.yaml)

```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
Expand All @@ -47,5 +54,18 @@ create [kustomization.yaml](./tests/kustomization.yaml)
- privateKey=ref+sops://secrets.yaml#/privateKey
literals:
- publicKey=ref+sops://secrets.yaml#/publicKey
configMapGenerator:
- name: my-java-server-env-vars
literals:
- JAVA_HOME=/opt/java/jdk
- JAVA_TOOL_OPTIONS=-agentlib:hprof
```

- Create sops encrypted [secrets.yaml](./tests/secrets.yaml) files with content of [ssh](./tests/ssh/)

- Run `skustomize build tests`

create encrypted [secrets.yaml](./tests/secrets.yaml) files with sops
```sh
export SOPS_AGE_KEY_FILE=$PWD/tests/age/key.txt
skustomize build tests
```
31 changes: 17 additions & 14 deletions skustomize
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ set -o pipefail
WORKDIR=.
SUB_COMMAND=""
BOOL_FLAG=true
SHOW_HELP=false
declare -a GLOBAL_FLAGS=() SUB_FLAGS=() KUST_FILES=() KUST_DIRS=()

CMDS="(build|cfg|completion|create|edit|fn|help|localize|version|docs-fn|docs-fn-spec|docs-io-annotations|docs-merge|docs-merge3|tutorials-command-basics|tutorials-function-basics)"

parse_flags() {
for flag in "$@"; do
if [ "$flag" == "-h" ] || [ "$flag" == "--help" ]; then
SHOW_HELP=true
fi
if [[ $flag =~ ^$CMDS$ ]]; then
SUB_COMMAND="$flag"
elif [ -z "$SUB_COMMAND" ] || [ "$flag" == "--stack-trace" ]; then
Expand Down Expand Up @@ -50,24 +54,23 @@ backup_kust_file() {
trap 'revert_kust_file' EXIT
}

# the regexp for uri experission of vals
# https://github.com/helmfile/vals/blob/main/pkg/expansion/expand_match.go#L15
VALS_REF_REGEX='((secret)?ref)\+([^\+:]*:\/\/[^\+\n "]+)\+?'

check_vals_ref_uri_by_type() {
check_vals_ref_uri() {
local count=0
while read -r line; do
if [[ "$line" =~ ^=?$VALS_REF_REGEX ]]; then
echo "[ERROR]: invalid $1 source: [$line], expected key=value"
((count += 1))
fi
done < <(TYPE="$1" yq '.secretGenerator[][strenv(TYPE)][]' "${KUST_FILES[0]}")
for type in files literals; do
while read -r line; do
if [[ "$line" =~ ^=?$VALS_REF_REGEX ]]; then
echo -e "\033[1;31m[ERROR]: invalid $type source: [$line], expected key=value \033[0m"
((count += 1))
fi
done < <(TYPE="$type" yq '.secretGenerator[][strenv(TYPE)][]' "${KUST_FILES[0]}")
done
[ $count -eq 0 ]
}

check_vals_ref_uri() {
check_vals_ref_uri_by_type "files"
check_vals_ref_uri_by_type "literals"
}

update_kust_file() {
#shellcheck disable=SC2016
WORKDIR="$WORKDIR/" REF_REGEX="$VALS_REF_REGEX" yq -ie 'with(.secretGenerator[];
Expand All @@ -89,7 +92,7 @@ exec_kust_vals() {
get_kust_files() {
for fn in kustomization.yaml kustomization.yml Kustomization; do
if [ -e "$WORKDIR/$fn" ]; then
KUST_FILES=("$WORKDIR/$fn" "${KUST_FILES[@]}")
KUST_FILES+=("$WORKDIR/$fn")
fi
done
}
Expand All @@ -108,7 +111,7 @@ build_wrapper() {
# shellcheck disable=SC2091
if ! $(return 0 2>/dev/null); then
parse_flags "$@"
if [ "${#KUST_DIRS[@]}" -lt 2 ] && [ "$SUB_COMMAND" == build ]; then
if [ "${#KUST_DIRS[@]}" -lt 2 ] && [ "$SUB_COMMAND" == build ] && [ "$SHOW_HELP" == false ]; then
build_wrapper "$@"
fi
${KUSTOMIZE_BIN} "$@"
Expand Down
9 changes: 7 additions & 2 deletions tests/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ secretGenerator:
- name: test-secret
files:
- key=age/key.txt
literals:
- privateKey=ref+sops://secrets.yaml#/privateKey
- keyInBucket=ref+s3://mybucket/myjsonobj#/foo/bar
literals:
- publicKey=ref+sops://secrets.yaml#/publicKey
configMapGenerator:
- name: my-java-server-env-vars
literals:
- JAVA_HOME=/opt/java/jdk
- JAVA_TOOL_OPTIONS=-agentlib:hprof
39 changes: 28 additions & 11 deletions tests/skustomize.bats
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,31 @@ setup() {
assert_equal "$WORKDIR" "."
}

@test 'it should parse flags for sub command' {
parse_flags build --as-current-user --enable-exec --stack-trace
assert_equal "${GLOBAL_FLAGS[*]}" "--stack-trace"
@test 'it should parse sub flags only' {
parse_flags build --as-current-user --enable-exec
assert_equal "${GLOBAL_FLAGS[*]}" ""
assert_equal "$SUB_COMMAND" "build"
assert_equal "${SUB_FLAGS[*]}" "--as-current-user --enable-exec"
assert_equal "$WORKDIR" "."
}

@test 'it should parse global and sub flags for sub command' {
@test 'it should parse global and sub flags both' {
parse_flags --stack-trace build --as-current-user --enable-exec -e xx=yy abc/def
assert_equal "${GLOBAL_FLAGS[*]}" "--stack-trace"
assert_equal "$SUB_COMMAND" "build"
assert_equal "${SUB_FLAGS[*]}" "--as-current-user --enable-exec -e xx=yy abc/def"
assert_equal "$WORKDIR" "abc/def"
}

@test 'it should parse global and sub flags for sub command1' {
parse_flags --stack-trace build --as-current-user abc/def --enable-exec -e xx=yy
@test 'it should parse global and sub flags both with any order' {
parse_flags build --as-current-user abc/def --enable-exec -e xx=yy --stack-trace
assert_equal "${GLOBAL_FLAGS[*]}" "--stack-trace"
assert_equal "$SUB_COMMAND" "build"
assert_equal "${SUB_FLAGS[*]}" "--as-current-user abc/def --enable-exec -e xx=yy"
assert_equal "$WORKDIR" "abc/def"
}

@test "it should generate secrets from validated vals uri" {
@test "it should generate secrets from valid uri" {
cat >$TEMPDIR/kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Expand All @@ -72,7 +72,7 @@ EOF
assert_success
}

@test "it should exit with error if file/literal has no defined name" {
@test "it should fail if file/literal has no defined name" {
cat >$TEMPDIR/kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Expand All @@ -86,7 +86,7 @@ EOF
assert_output --partial "[ERROR]: invalid files source: [ref+sops://secrets.yaml], expected key=value"
}

@test "it should exit with error if given unsupported scheme" {
@test "it should fail if uri is invalid" {
cat >$TEMPDIR/kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Expand All @@ -100,7 +100,7 @@ EOF
assert_output --partial "no provider registered for scheme"
}

@test "it should exit with error if no fragement set" {
@test "it should fail if uri has no fragement" {
cat >$TEMPDIR/kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Expand All @@ -114,8 +114,25 @@ EOF
assert_output --partial "Error unmarshalling input json: invalid character"
}

@test "it should exit with error if two folders given" {
@test "it should fail if gives two folders" {
run "$SKUST_BIN" build folder1 folder2
assert_failure
assert_output "Error: specify one path to kustomization.yaml"
}

@test "it should fail if gives two kustomization files" {
touch $TEMPDIR/kustomization.yaml $TEMPDIR/kustomization.yml
run "$SKUST_BIN" build $TEMPDIR
assert_failure
assert_output --partial "Error: Found multiple kustomization files under"
}

@test "it should show global help if gives global -h" {
run "$SKUST_BIN" -h build
assert_output --partial "Manages declarative configuration of Kubernetes."
}

@test "it should show build help if gives -h to build" {
run "$SKUST_BIN" build -h
assert_output --partial "Build a set of KRM resources using a 'kustomization.yaml' file"
}