Compare commits
368 Commits
2.0.0-beta
...
c85e61f5d0
Author | SHA1 | Date | |
---|---|---|---|
c85e61f5d0 | |||
f1c31b0eeb | |||
677b0d7b3c | |||
f539be8f52 | |||
4336490a72 | |||
9f75f874d1 | |||
90eda75219 | |||
b13e922966 | |||
0d36a48f93 | |||
60016b8c3e | |||
07263520b6 | |||
0f3812b666 | |||
50a9d0ddde | |||
f5d3005c3b | |||
76b3b83d07 | |||
14ca5bf0ea | |||
d1768e5742 | |||
0fcf0f60e8 | |||
e9ad85a0ac | |||
b4b122fe7f | |||
6aaeda7a3c | |||
0b3f7b2b5c | |||
e9e7c5f7b5 | |||
0df53ed5ae | |||
136478aff7 | |||
5b812b30f7 | |||
f2b5c16e71 | |||
df1f29c0ff | |||
afbd6fc1ac | |||
327e0aa799 | |||
b7e948954b | |||
93c0658c19 | |||
bdf74f2deb | |||
2435bb9f8a | |||
5ee38dcf7f | |||
a754dc9275 | |||
732e080da3 | |||
22e1ebdce1 | |||
e4280f2c4e | |||
a99609d21d | |||
e55658d382 | |||
9dbe9e1114 | |||
eea198786a | |||
da9c0a7b58 | |||
d582b884bf | |||
aa3e4c64ee | |||
ce479629f6 | |||
89fd516b20 | |||
8bbb991afb | |||
4c5c9ba553 | |||
ef1511d4f7 | |||
a290219c81 | |||
c4e406f855 | |||
2beac5f4dd | |||
5f5cd0268a | |||
796cbb6d30 | |||
39ebf7eb78 | |||
a1c5161ff7 | |||
2307ad667e | |||
a26e832fed | |||
8582010d90 | |||
b7186eb8b4 | |||
0f3528818f | |||
9fadc77979 | |||
13d231a62c | |||
6cbaa06bec | |||
1552e9c877 | |||
3b2cd37ea4 | |||
4c566cbc1a | |||
69c528e5e0 | |||
42bf35593f | |||
4e739c5f08 | |||
f75623b4ff | |||
d82b5e4a98 | |||
42c738211c | |||
c54bc35c9f | |||
1f406dc558 | |||
0c0b50b0df | |||
6efee2fbae | |||
47e149e20b | |||
d163700147 | |||
fa3befaa88 | |||
e5b7c0d550 | |||
9e4663cc6e | |||
1a5c95d240 | |||
21845c5de1 | |||
4a91d458fd | |||
a52b20efab | |||
02c4c5168b | |||
7b875454cb | |||
2da5d9df08 | |||
a0eb3c0bb6 | |||
7e76543c48 | |||
09c2c86d59 | |||
e58948bb44 | |||
a00b03b2aa | |||
b47b956798 | |||
a409a1347e | |||
8999aabc21 | |||
14e8907437 | |||
740c400b9a | |||
7cd38bbd23 | |||
8c509b5bff | |||
28b22a0b30 | |||
748d0bf1ea | |||
130e6d4e24 | |||
a66fec07e1 | |||
a3d1e9342f | |||
72bc88661a | |||
e2b897eb9d | |||
9fcce059e5 | |||
36f6413917 | |||
8c729f3c57 | |||
063cc9d439 | |||
ac5317e600 | |||
bc0b65006d | |||
933f04bf5e | |||
7d46435ba2 | |||
d94bb8ac32 | |||
b143f743ef | |||
a8341a9b44 | |||
def5d097a4 | |||
ba0ae1bc60 | |||
d77029b597 | |||
b5f62d43af | |||
9220dc3278 | |||
36c72fb665 | |||
|
c90504f4f1 | ||
9ef961ae7c | |||
fe6663f9f4 | |||
1190b316bb | |||
7068dc229c | |||
|
61ce6fb25b | ||
116ef658d8 | |||
d7b354de8c | |||
|
d06c0574fb | ||
|
bcd7894e3b | ||
80aba05f66 | |||
41a4292939 | |||
131ea5d569 | |||
e36bbf41f4 | |||
c97b398914 | |||
d27ed76cf4 | |||
17b6ea51af | |||
0986f73f06 | |||
dcd282779f | |||
b93a3df98c | |||
4768330c1a | |||
23d0afd85f | |||
5c939383be | |||
72ddb8aa74 | |||
4d0e5b2e6a | |||
58d1e8e450 | |||
d0790f37a8 | |||
62b0576c2d | |||
e574a2e2a8 | |||
eb760d4299 | |||
3833037862 | |||
6dc92df4b5 | |||
d458cdbd73 | |||
628b35d471 | |||
84363be0e8 | |||
5284cdf5cc | |||
632ffc2b66 | |||
2ff705164e | |||
73ab867509 | |||
45e44dee14 | |||
689c2a4803 | |||
e023544c8a | |||
10b7a49bbf | |||
bb1354e228 | |||
957cc4bcf6 | |||
9f1f6c7e78 | |||
a80ddcc054 | |||
921eaff367 | |||
b63d8e4210 | |||
9766dac763 | |||
441be30720 | |||
e13653fba1 | |||
6b301f3171 | |||
9181c389d4 | |||
3b4dade699 | |||
4f0298c0a9 | |||
5f20585fb2 | |||
0714eac615 | |||
456e7f41f2 | |||
fc335247f8 | |||
ad16005091 | |||
a676372bbe | |||
7fadc45e9e | |||
41a0dc58a5 | |||
dc34d32c5c | |||
36984e3825 | |||
046410a5ec | |||
827b5bc830 | |||
8aee6d9983 | |||
7b890df1c5 | |||
e925f58e82 | |||
91fc0fd9f0 | |||
1a1d2b5ee8 | |||
95f3abfa74 | |||
3b51f41716 | |||
3f63375b60 | |||
8c97937b44 | |||
96f843630a | |||
48f6045cd3 | |||
49045a2ccd | |||
af8dabba85 | |||
cc1019b5a8 | |||
14877fbfa3 | |||
7b5e45131c | |||
b09316b416 | |||
315f5da970 | |||
9b392a1f64 | |||
9358076a36 | |||
427f2909d5 | |||
8ab1763902 | |||
e409be235e | |||
1ca71f264c | |||
5f464253c4 | |||
75869975f6 | |||
ac43256511 | |||
5b51ba6d98 | |||
dd63bb6343 | |||
817ebe0e53 | |||
6023ca4508 | |||
e0c829c2ce | |||
2d33367422 | |||
d72f371c59 | |||
db168c91c9 | |||
d31993953b | |||
63c6d5d0ef | |||
164a617869 | |||
865473b41b
|
|||
533e1422d0
|
|||
d2c8d08b7f
|
|||
4703aa7df5
|
|||
918f1b845b
|
|||
78dfb15cf5
|
|||
adc44a5e8b
|
|||
4367a01769
|
|||
d98268f45b
|
|||
ccfebd1a70
|
|||
e4f67dbd31
|
|||
d01a35e2d4
|
|||
0aa7023947
|
|||
451a1341bd
|
|||
da7d92bbfa | |||
15a2f25e51 | |||
f73d598bb4 | |||
98c7c6ddc1 | |||
39d63c11b1 | |||
8f4d69d6e2 | |||
531756d8ea | |||
e0c18ec2ad
|
|||
a3e7435544 | |||
c01cdf50c8
|
|||
2e3dd5032f
|
|||
8b01807568
|
|||
46c878b56e
|
|||
10b9342607 | |||
77de53c999
|
|||
6a7fedee7e
|
|||
c31299197f
|
|||
49c1fa5fb0
|
|||
d1186ee1e1
|
|||
50975ae94a
|
|||
7e8cb57979 | |||
12814f4732 | |||
dc41826691 | |||
6770f8176a | |||
cd946b2df6 | |||
734b0ed39d | |||
78d37c4405 | |||
fd3ba6d577 | |||
8ae9350d31 | |||
9621493343 | |||
f291d17aa3
|
|||
9826a54187
|
|||
d48fd2f911
|
|||
ec62a79d82
|
|||
58d19cce52
|
|||
3bb635a627 | |||
35f464a1cb | |||
85f1b2d43c | |||
77e8be4e63 | |||
57b274e345 | |||
3c743fb135 | |||
ab15614076
|
|||
c41fa22c59
|
|||
81ea0fbb6f
|
|||
821c038206
|
|||
19a37ace18
|
|||
d8bd66e66f
|
|||
c780e6c2a2
|
|||
3317459b0b | |||
564b939464 | |||
c7c18f01cd | |||
2f53638f82 | |||
5070101706 | |||
cc3c42b8fd | |||
45de7ab543
|
|||
984b50356a
|
|||
441b30a570
|
|||
2aad5d4b9d
|
|||
50169c8fbc
|
|||
fc67cb668d
|
|||
8e4b3be108
|
|||
3ae5ec99ff
|
|||
ef7fcb6133
|
|||
50c2f9d1dc
|
|||
eeb044bab0
|
|||
6ce52cc037
|
|||
9a3fc6a2b4
|
|||
4ded4d4e09
|
|||
dc47e73b4b | |||
76aa332dc2 | |||
5d4f72e984 | |||
5a358f0a6a | |||
ed9b4681ad | |||
d135f5bc0a
|
|||
f9cf3972d5
|
|||
6e33fa474a
|
|||
3a0cf1a7db
|
|||
475a025d9e
|
|||
c37bde487b | |||
|
982917c25b | ||
|
7feb7427f2 | ||
a2bf9c005b | |||
119b5d699c
|
|||
|
eca5154d75 | ||
16196aae34
|
|||
9726cc4a18
|
|||
7eb75015a0
|
|||
66dec780ae
|
|||
6cd361705d
|
|||
9c449eefab
|
|||
|
16c8e3dd20 | ||
b21c821086
|
|||
890d7b5017
|
|||
|
1266545919 | ||
874e12f35d
|
|||
b25b2fda2c
|
|||
e2a4d296f6
|
|||
7d5b4d9306
|
|||
a1d963c15b
|
|||
bb83384d62
|
|||
bc3c5dc932
|
|||
203449aa9e
|
|||
a3dbdfd8c6
|
|||
1b1397b45f
|
|||
1122c02e07
|
|||
01e045e4b7
|
|||
d28cbab0fe
|
|||
b1dc94e0e9
|
|||
f9fd6332d6 | |||
|
7203928d95 | ||
dc9b198208
|
|||
0f9a46f52d
|
|||
8cf3ff9f73
|
|||
114fab4870
|
|||
5fc8c06d8b
|
|||
51ca4e81d1
|
|||
a6f6b91ab9
|
|||
63afc3066b
|
|||
|
1e8fd44857 | ||
|
1403f9b198 | ||
|
22ef9211ec |
@@ -4,3 +4,8 @@ root = true
|
|||||||
indent_style=tab
|
indent_style=tab
|
||||||
indent_size=4
|
indent_size=4
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
47
.gitea/workflows/build-oci.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Build and push OCI image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "**"
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: repo.katenary.io
|
||||||
|
IMAGE_NAME: ${{ gitea.repository }}
|
||||||
|
VERSION: ${{ gitea.ref_name }}
|
||||||
|
STORAGE_DRIVER: vfs
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- name: Install Buildah
|
||||||
|
run: |-
|
||||||
|
env
|
||||||
|
if ! command -v buildah 2>/dev/null; then
|
||||||
|
echo "Install Buildah"
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y buildah
|
||||||
|
else
|
||||||
|
echo "Buildah already installed"
|
||||||
|
fi
|
||||||
|
- name: Login to repository
|
||||||
|
run: |
|
||||||
|
buildah login $REGISTRY -u ${{ gitea.actor }} -p ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build and tag
|
||||||
|
run: |-
|
||||||
|
buildah build --isolation=chroot --build-arg VERSION=$VERSION -t katenary -f ./oci/katenary/Containerfile .
|
||||||
|
buildah tag katenary $REGISTRY/${IMAGE_NAME,,}:$VERSION
|
||||||
|
buildah tag katenary $REGISTRY/${IMAGE_NAME,,}:latest
|
||||||
|
|
||||||
|
- name: Push image
|
||||||
|
run: |-
|
||||||
|
buildah push $REGISTRY/${IMAGE_NAME,,}:$VERSION
|
||||||
|
buildah push $REGISTRY/${IMAGE_NAME,,}:latest
|
68
.gitea/workflows/go-test.yaml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
name: Go-Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- edited
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "master"
|
||||||
|
- "main"
|
||||||
|
env:
|
||||||
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tests:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.25
|
||||||
|
- name: Install helm
|
||||||
|
run: |
|
||||||
|
command -v helm || curl -sSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||||
|
|
||||||
|
- name: Tidy
|
||||||
|
run: |
|
||||||
|
go mod tidy
|
||||||
|
- name: Launch Test
|
||||||
|
run: |
|
||||||
|
go vet ./...
|
||||||
|
go test -coverprofile=coverprofile.out -json -v ./... > gotest.json
|
||||||
|
# - uses: actions/upload-artifact@v4
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: christopherhx/gitea-upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: tests-results
|
||||||
|
path: |
|
||||||
|
coverprofile.out
|
||||||
|
gotest.json
|
||||||
|
sonar:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: tests
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
#- uses: actions/download-artifact@v4
|
||||||
|
- name: Download artifact
|
||||||
|
uses: christopherhx/gitea-download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: tests-results
|
||||||
|
- name: Sonar
|
||||||
|
run: |
|
||||||
|
export SONAR_SCANNER_VERSION=7.2.0.5079
|
||||||
|
export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-x64
|
||||||
|
curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux-x64.zip
|
||||||
|
unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
|
||||||
|
export PATH=$SONAR_SCANNER_HOME/bin:$PATH
|
||||||
|
sonar-scanner \
|
||||||
|
-Dsonar.organization=katenary \
|
||||||
|
-Dsonar.projectKey=katenary_katenary
|
11
.github/dependabot.yml
vendored
@@ -1,11 +0,0 @@
|
|||||||
# To get started with Dependabot version updates, you'll need to specify which
|
|
||||||
# package ecosystems to update and where the package manifests are located.
|
|
||||||
# Please see the documentation for all configuration options:
|
|
||||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "gomod"
|
|
||||||
directory: "/" # Location of package manifests
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
35
.gitignore
vendored
@@ -1,10 +1,33 @@
|
|||||||
dist/*
|
dist/*
|
||||||
.cache/*
|
|
||||||
chart/*
|
|
||||||
docker-compose.yaml
|
|
||||||
./katenary
|
|
||||||
*.env
|
*.env
|
||||||
docker-compose*
|
|
||||||
!examples/**/docker-compose*
|
|
||||||
.credentials
|
.credentials
|
||||||
release.id
|
release.id
|
||||||
|
cover*
|
||||||
|
.sq
|
||||||
|
.aider*
|
||||||
|
.python_history
|
||||||
|
.bash_history
|
||||||
|
|
||||||
|
.cache/
|
||||||
|
.aider/
|
||||||
|
.config/
|
||||||
|
*/venv
|
||||||
|
|
||||||
|
|
||||||
|
# will be treated later
|
||||||
|
/examples/*
|
||||||
|
|
||||||
|
# nsis
|
||||||
|
nsis/*.dll
|
||||||
|
nsis/*.exe
|
||||||
|
|
||||||
|
doc/share
|
||||||
|
__pycache__
|
||||||
|
|
||||||
|
.rpmmacros
|
||||||
|
*.gpg
|
||||||
|
|
||||||
|
# local binaries
|
||||||
|
katenary
|
||||||
|
!cmd/katenary
|
||||||
|
!oci/katenary
|
||||||
|
0
.gitmodules
vendored
Normal file
26
.golangci.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
version: "2"
|
||||||
|
run:
|
||||||
|
issues-exit-code: 1
|
||||||
|
linters:
|
||||||
|
enabled:
|
||||||
|
- unused
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
presets:
|
||||||
|
- comments
|
||||||
|
- common-false-positives
|
||||||
|
- legacy
|
||||||
|
- std-error-handling
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
- "(.+)_test.go"
|
||||||
|
formatters:
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
- "(.+)_test.go"
|
21
.markdownlint.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# markdownlint configuration file
|
||||||
|
default: true
|
||||||
|
|
||||||
|
MD013: # Line length
|
||||||
|
line_length: 120
|
||||||
|
|
||||||
|
MD010: # Hard tabs
|
||||||
|
code_blocks: false
|
||||||
|
|
||||||
|
# no inline HTML
|
||||||
|
MD033: false
|
||||||
|
|
||||||
|
# heading as first line element...
|
||||||
|
MD041: false
|
||||||
|
|
||||||
|
# list indentation
|
||||||
|
MD007:
|
||||||
|
indent: 4
|
||||||
|
|
||||||
|
# no problem using several code blocks styles
|
||||||
|
MD046: false
|
20
.readthedocs.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# .readthedocs.yaml
|
||||||
|
# Read the Docs configuration file
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
# Required
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
# Set the version of Python and other tools you might need
|
||||||
|
build:
|
||||||
|
os: ubuntu-20.04
|
||||||
|
tools:
|
||||||
|
python: "3.9"
|
||||||
|
|
||||||
|
mkdocs:
|
||||||
|
configuration: doc/mkdocs.yml
|
||||||
|
|
||||||
|
# Optionally declare the Python requirements required to build your docs
|
||||||
|
python:
|
||||||
|
install:
|
||||||
|
- requirements: doc/requirements.txt
|
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2022 Patrice Ferlet
|
Copyright (c) 2022-2025 The Katenary authors
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
183
Makefile
@@ -1,30 +1,79 @@
|
|||||||
|
# Strict mode
|
||||||
|
SHELL := bash
|
||||||
|
.SHELLFLAGS := -eu -o pipefail -c
|
||||||
|
.ONESHELL:
|
||||||
|
.DELETE_ON_ERROR:
|
||||||
|
.PHONY: all binaries build check-dist-all check-dist-archlinux check-dist-debian check-dist-fedora check-dist-rocky check-dist-ubuntu check-sign clean-all clean-dist clean-go-cache clean-package-signer cover deb dist dist-full doc freebsd gpg-sign help install install-gomarkdoc katenary manpage packager-oci-image packages pacman prepare pull rpm rpm-sign sast serve-doc show-cover tar test uninstall upx warn-docker
|
||||||
|
MAKEFLAGS += --warn-undefined-variables
|
||||||
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
|
||||||
|
# Get a version string from git
|
||||||
CUR_SHA=$(shell git log -n1 --pretty='%h')
|
CUR_SHA=$(shell git log -n1 --pretty='%h')
|
||||||
CUR_BRANCH=$(shell git branch --show-current)
|
CUR_BRANCH=$(shell git branch --show-current)
|
||||||
VERSION=$(shell git describe --exact-match --tags $(CUR_SHA) 2>/dev/null || echo $(CUR_BRANCH)-$(CUR_SHA))
|
VERSION=$(shell git describe --exact-match --tags $(CUR_SHA) 2>/dev/null || echo $(CUR_BRANCH)-$(CUR_SHA))# use by golang flags
|
||||||
CTN:=$(shell which podman 2>&1 1>/dev/null && echo "podman" || echo "docker")
|
|
||||||
PREFIX=~/.local
|
|
||||||
|
|
||||||
GO=container
|
# Go build command and environment variables for target OS and architecture
|
||||||
OUT=katenary
|
GOVERSION=1.25
|
||||||
BLD_CMD=go build -ldflags="-X 'main.Version=$(VERSION)'" -o $(OUT) ./cmd/katenary/*.go
|
GO=container# container, local
|
||||||
|
OUTPUT=katenary
|
||||||
GOOS=linux
|
GOOS=linux
|
||||||
GOARCH=amd64
|
GOARCH=amd64
|
||||||
|
CGO_ENABLED=0
|
||||||
|
PREFIX=~/.local
|
||||||
|
|
||||||
BUILD_IMAGE=docker.io/golang:1.18-alpine
|
# UPX compression
|
||||||
|
UPX_OPTS =
|
||||||
|
UPX ?= upx $(UPX_OPTS)
|
||||||
|
|
||||||
.PHONY: help clean build
|
# List of source files
|
||||||
|
SOURCES=$(shell find -name "*.go" -or -name "*.tpl" -type f | grep -v -P "^./example|^./vendor")
|
||||||
|
# List of binaries to build and sign
|
||||||
|
BINARIES=\
|
||||||
|
dist/katenary-linux-amd64\
|
||||||
|
dist/katenary-linux-arm64\
|
||||||
|
dist/katenary-darwin-amd64\
|
||||||
|
dist/katenary-freebsd-amd64\
|
||||||
|
dist/katenary-freebsd-arm64\
|
||||||
|
dist/katenary.exe\
|
||||||
|
dist/katenary-windows-setup.exe
|
||||||
|
|
||||||
|
## GPG
|
||||||
|
# List of signatures to build
|
||||||
|
ASC_BINARIES=$(patsubst %,%.asc,$(BINARIES))
|
||||||
|
# GPG signer
|
||||||
|
SIGNER=metal3d@gmail.com
|
||||||
|
|
||||||
|
# Browser command to see coverage report after tests
|
||||||
|
BROWSER=$(shell command -v epiphany || echo xdg-open)
|
||||||
|
|
||||||
|
include makefiles/build.mk
|
||||||
|
include makefiles/containers.mk
|
||||||
|
include makefiles/doc.mk
|
||||||
|
include makefiles/gpg.mk
|
||||||
|
include makefiles/packager.mk
|
||||||
|
include makefiles/test.mk
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
# if docker is used instead of podman, we warn the user
|
||||||
|
warn-docker:
|
||||||
|
@echo -e "\033[1;31mWarning: Docker is not recommended, use Podman instead.\033[0m"
|
||||||
|
sleep 5
|
||||||
|
|
||||||
.ONESHELL:
|
|
||||||
help:
|
help:
|
||||||
@cat <<EOF
|
@cat <<EOF | fold -s -w 80
|
||||||
=== HELP ===
|
=== HELP ===
|
||||||
To avoid you to install Go, the build is made by podman or docker.
|
To avoid you to install Go, the build is made by podman or docker.
|
||||||
|
|
||||||
You can use:
|
Installinf (you can use local Go by setting GO=local)):
|
||||||
|
# use podman or docker to build
|
||||||
$$ make install
|
$$ make install
|
||||||
|
# or use local Go
|
||||||
|
$$ make install GO=local
|
||||||
This will build and install katenary inside the PREFIX(/bin) value (default is $(PREFIX))
|
This will build and install katenary inside the PREFIX(/bin) value (default is $(PREFIX))
|
||||||
|
|
||||||
To change the PREFIX to somewhere where only root or sudo users can save the binary, it is recommended to build before install:
|
|
||||||
|
To change the PREFIX to somewhere where only root or sudo users can save the binary, it is recommended to build before install, one more time you can use local Go by setting GO=local:
|
||||||
$$ make build
|
$$ make build
|
||||||
$$ sudo make install PREFIX=/usr/local
|
$$ sudo make install PREFIX=/usr/local
|
||||||
|
|
||||||
@@ -44,113 +93,29 @@ help:
|
|||||||
This will build the binary for darwin amd64.
|
This will build the binary for darwin amd64.
|
||||||
|
|
||||||
Or you can build all versions:
|
Or you can build all versions:
|
||||||
$$ make build-all
|
$$ make binaries
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
build: pull katenary
|
|
||||||
|
|
||||||
build-all:
|
|
||||||
rm -f dist/*
|
|
||||||
$(MAKE) _build-all
|
|
||||||
|
|
||||||
_build-all: pull dist dist/katenary-linux-amd64 dist/katenary-linux-arm64 dist/katenary.exe dist/katenary-darwin-amd64 dist/katenary-freebsd-amd64 dist/katenary-freebsd-arm64
|
|
||||||
|
|
||||||
pull:
|
|
||||||
ifneq ($(GO),local)
|
|
||||||
@echo -e "\033[1;32mPulling $(BUILD_IMAGE) docker image\033[0m"
|
|
||||||
@$(CTN) pull $(BUILD_IMAGE)
|
|
||||||
endif
|
|
||||||
|
|
||||||
dist:
|
|
||||||
mkdir -p dist
|
|
||||||
|
|
||||||
dist/katenary-linux-amd64:
|
|
||||||
@echo
|
|
||||||
@echo -e "\033[1;32mBuilding katenary $(VERSION) for linux-amd64...\033[0m"
|
|
||||||
$(MAKE) katenary GOOS=linux GOARCH=amd64 OUT=$@
|
|
||||||
|
|
||||||
|
|
||||||
dist/katenary-linux-arm64:
|
|
||||||
@echo
|
|
||||||
@echo -e "\033[1;32mBuilding katenary $(VERSION) for linux-arm...\033[0m"
|
|
||||||
$(MAKE) katenary GOOS=linux GOARCH=arm64 OUT=$@
|
|
||||||
|
|
||||||
dist/katenary.exe:
|
|
||||||
@echo
|
|
||||||
@echo -e "\033[1;32mBuilding katenary $(VERSION) for windows...\033[0m"
|
|
||||||
$(MAKE) katenary GOOS=windows GOARCH=amd64 OUT=$@
|
|
||||||
|
|
||||||
dist/katenary-darwin-amd64:
|
|
||||||
@echo
|
|
||||||
@echo -e "\033[1;32mBuilding katenary $(VERSION) for darwin...\033[0m"
|
|
||||||
$(MAKE) katenary GOOS=darwin GOARCH=amd64 OUT=$@
|
|
||||||
|
|
||||||
dist/katenary-freebsd-amd64:
|
|
||||||
@echo
|
|
||||||
@echo -e "\033[1;32mBuilding katenary $(VERSION) for freebsd...\033[0m"
|
|
||||||
$(MAKE) katenary GOOS=freebsd GOARCH=amd64 OUT=$@
|
|
||||||
|
|
||||||
dist/katenary-freebsd-arm64:
|
|
||||||
@echo
|
|
||||||
@echo -e "\033[1;32mBuilding katenary $(VERSION) for freebsd-arm64...\033[0m"
|
|
||||||
$(MAKE) katenary GOOS=freebsd GOARCH=arm64 OUT=$@
|
|
||||||
|
|
||||||
katenary: $(wildcard */*.go Makefile go.mod go.sum)
|
|
||||||
ifeq ($(GO),local)
|
|
||||||
@echo "=> Build in host using go"
|
|
||||||
else
|
|
||||||
@echo "=> Build in container using" $(CTN)
|
|
||||||
endif
|
|
||||||
echo $(BLD_CMD)
|
|
||||||
ifeq ($(GO),local)
|
|
||||||
$(BLD_CMD)
|
|
||||||
else ifeq ($(CTN),podman)
|
|
||||||
@podman run -e CGO_ENABLED=0 -e GOOS=$(GOOS) -e GOARCH=$(GOARCH) \
|
|
||||||
--rm -v $(PWD):/go/src/katenary:z -w /go/src/katenary --userns keep-id -it $(BUILD_IMAGE) $(BLD_CMD)
|
|
||||||
else
|
|
||||||
@docker run -e CGO_ENABLED=0 -e GOOS=$(GOOS) -e GOARCH=$(GOARCH) \
|
|
||||||
--rm -v $(PWD):/go/src/katenary:z -w /go/src/katenary --user $(shell id -u):$(shell id -g) -e HOME=/tmp -it $(BUILD_IMAGE) $(BLD_CMD)
|
|
||||||
endif
|
|
||||||
echo "=> Stripping if possible"
|
|
||||||
strip $(OUT) 2>/dev/null || echo "=> No strip available"
|
|
||||||
|
|
||||||
|
|
||||||
|
## installation and uninstallation
|
||||||
|
|
||||||
install: build
|
install: build
|
||||||
cp katenary $(PREFIX)/bin/katenary
|
install -Dm755 katenary $(PREFIX)/bin/katenary
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(PREFIX)/bin/katenary
|
rm -f $(PREFIX)/bin/katenary
|
||||||
|
|
||||||
clean:
|
## Miscellaneous
|
||||||
rm -rf katenary dist/* release.id
|
|
||||||
|
|
||||||
|
clean-all: clean-dist clean-package-signer clean-go-cache
|
||||||
|
|
||||||
tests: test
|
clean-dist:
|
||||||
test:
|
rm -rf dist
|
||||||
@echo -e "\033[1;33mTesting katenary $(VERSION)...\033[0m"
|
rm -f katenary
|
||||||
go test -v ./...
|
|
||||||
|
|
||||||
|
clean-package-signer:
|
||||||
|
rm -f .secret.gpg .rpmmacros
|
||||||
|
|
||||||
|
clean-go-cache:
|
||||||
|
$(CTN) volume rm -f go-cache
|
||||||
|
|
||||||
.ONESHELL:
|
|
||||||
push-release: build-all
|
|
||||||
@rm -f release.id
|
|
||||||
# read personal access token from .git-credentials
|
|
||||||
TOKEN=$(shell cat .credentials)
|
|
||||||
# create a new release based on current tag and get the release id
|
|
||||||
@curl -sSL -X POST \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
-H "Authorization: token $$TOKEN" \
|
|
||||||
-d "{\"tag_name\": \"$(VERSION)\", \"target_commitish\": \"\", \"name\": \"$(VERSION)\", \"draft\": true, \"prerelease\": true}" \
|
|
||||||
https://api.github.com/repos/metal3d/katenary/releases | jq -r '.id' > release.id
|
|
||||||
@echo "Release id: $$(cat release.id) created"
|
|
||||||
@echo "Uploading assets..."
|
|
||||||
# push all dist binary as assets to the release
|
|
||||||
@for i in $$(find dist -type f -name "katenary*"); do
|
|
||||||
curl -sSL -H "Authorization: token $$TOKEN" \
|
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
|
||||||
-H "Content-Type: application/octet-stream" \
|
|
||||||
--data-binary @$$i \
|
|
||||||
https://uploads.github.com/repos/metal3d/katenary/releases/$$(cat release.id)/assets?name=$$(basename $$i)
|
|
||||||
done
|
|
||||||
@rm -f release.id
|
|
||||||
|
272
README.md
@@ -1,30 +1,55 @@
|
|||||||
<div style="text-align:center">
|
<div style="text-align:center; margin: auto 0 4em 0" align="center">
|
||||||
<img src="./misc/logo.png" alt="Katenary Logo" />
|
<img src="./doc/docs/statics/logo-vertical.svg" alt="Katenary Logo" style="max-width: 90%" align="center"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Katenary is a tool to help transforming `docker-compose` files to a working Helm Chart for Kubernetes.
|
<div style="text-align:center; margin: auto 0 4em 0" align="center">
|
||||||
|
|
||||||
> **Important Note:** Katenary is a tool to help building Helm Chart from a docker-compose file, but docker-compose doesn't propose as many features as what can do Kubernetes. So, we strongly recommend to use Katenary as a "bootstrap" tool and then to manually enhance the generated helm chart.
|
[](https://katenary.readthedocs.io/latest/?badge=latest)
|
||||||
|
[](https://sonarcloud.io/summary/new_code?id=katenary_katenary)
|
||||||
|
[](https://sonarcloud.io/summary/new_code?id=katenary_katenary)
|
||||||
|
[](https://sonarcloud.io/summary/new_code?id=katenary_katenary)
|
||||||
|
|
||||||
This project is partially made at [Smile](https://www.smile.eu)
|
|
||||||
|
|
||||||
<div style="text-align:center">
|
|
||||||
<a href="https://www.smile.eu"><img src="./misc/Logo_Smile.png" alt="Smile Logo" width="250" /></a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
# Install
|
<div style="text-align:center; margin: auto 0 4em 0" align="center">
|
||||||
|
<h3>🚀 Unleash Productivity with Katenary! 🚀</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
You can download the binaries from the [Release](https://github.com/metal3d/katenary/releases) section. Copy the binary and rename it to `katenary`. Place the binary inside your `PATH`. You should now be able to call the `katenary` command.
|
Tired of manual conversions? Katenary harnesses the labels from your "`compose`" file to craft complete Helm Charts
|
||||||
|
effortlessly, saving you time and energy.
|
||||||
|
|
||||||
You can of course get the binary with `go install -u github.com/metal3d/katenary/cmd/katenary/...` but the `main` branch is continuously updated. It's preferable to use releases.
|
🛠️ Simple automated CLI: Katenary handles the grunt work, generating everything needed for seamless service binding
|
||||||
|
and Helm Chart creation.
|
||||||
|
|
||||||
|
💡 Effortless Efficiency: You only need to add labels when it's necessary to precise things.
|
||||||
|
Then call `katenary convert` and let the magic happen.
|
||||||
|
|
||||||
|
## What ?
|
||||||
|
|
||||||
|
Katenary is a tool to help to transform `compose` (`docker compose`, `podman compose`, `nerdctl compose`, ...) files
|
||||||
|
to a working Helm Chart for Kubernetes.
|
||||||
|
|
||||||
|
Today, it's partially developed in collaboration with [Klee Group](https://www.kleegroup.com). Note that Katenary is
|
||||||
|
and **will stay an open source and free (as freedom) project**. We are convinced that the best way to make it better is to
|
||||||
|
share it with the community.
|
||||||
|
|
||||||
|
The main developer is [Patrice FERLET](https://github.com/metal3d).
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
You can download the binaries from the [Release](https://github.com/Katenary/katenary/releases) section. Copy the binary
|
||||||
|
and rename it to `katenary`. Place the binary inside your `PATH`. You should now be able to call the `katenary` command.
|
||||||
|
|
||||||
|
You can of course get the binary with `go install -u github.com/Katenary/katenary/cmd/katenary/...` but the `main` branch
|
||||||
|
is continuously updated. It's preferable to use releases.
|
||||||
|
|
||||||
You can use this commands on Linux:
|
You can use this commands on Linux:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sh <(curl -sSL https://raw.githubusercontent.com/metal3d/katenary/master/install.sh)
|
sh <(curl -sSL https://raw.githubusercontent.com/Katenary/katenary/master/install.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
# Else... Build yourself
|
## Or, build yourself
|
||||||
|
|
||||||
If you've got `podman` or `docker`, you can build `katenary` by using:
|
If you've got `podman` or `docker`, you can build `katenary` by using:
|
||||||
|
|
||||||
@@ -33,11 +58,13 @@ make build
|
|||||||
```
|
```
|
||||||
|
|
||||||
You can then install it with:
|
You can then install it with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make install
|
make install
|
||||||
```
|
```
|
||||||
|
|
||||||
It will use the default PREFIX (`~/.local/`) to install the binary in the `bin` subdirectory. You can force the PREFIX value at install time, but maybe you need to use "sudo":
|
It will use the default PREFIX (`~/.local/`) to install the binary in the `bin` subdirectory. You can force the PREFIX
|
||||||
|
value at install time, but maybe you need to use "sudo":
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo make install PREFIX=/usr/local
|
sudo make install PREFIX=/usr/local
|
||||||
@@ -54,12 +81,12 @@ make build GO=local GOOS=linux GOARCH=arm64
|
|||||||
|
|
||||||
Then place the `katenary` binary file inside your PATH.
|
Then place the `katenary` binary file inside your PATH.
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
# Tips
|
We strongly recommend adding the completion call to you SHELL using the common `bashrc`, or whatever the profile file
|
||||||
|
you use.
|
||||||
|
|
||||||
We strongly recommand to add the "completion" call to you SHELL using the common bashrc, or whatever the profile file you use.
|
E.g.,
|
||||||
|
|
||||||
E.g. :
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# bash in ~/.bashrc file
|
# bash in ~/.bashrc file
|
||||||
@@ -68,76 +95,69 @@ source <(katenary completion bash)
|
|||||||
source <(katenary completion bash --no-description)
|
source <(katenary completion bash --no-description)
|
||||||
|
|
||||||
# zsh in ~/.zshrc
|
# zsh in ~/.zshrc
|
||||||
source <(helm completion zsh)
|
source <(katenary completion zsh)
|
||||||
|
|
||||||
# fish in ~/.config/fish/config.fish
|
# fish in ~/.config/fish/config.fish
|
||||||
katenary completion fish | source
|
katenary completion fish | source
|
||||||
|
|
||||||
|
# experimental
|
||||||
# powershell (as we don't provide any support on Windows yet, please avoid this...)
|
# powershell (as we don't provide any support on Windows yet, please avoid this...)
|
||||||
```
|
```
|
||||||
|
|
||||||
# Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```text
|
||||||
Katenary aims to be a tool to convert docker-compose files to Helm Charts.
|
|
||||||
It will create deployments, services, volumes, secrets, and ingress resources.
|
|
||||||
But it will also create initContainers based on depend_on, healthcheck, and other features.
|
|
||||||
It's not magical, sometimes you'll need to fix the generated charts.
|
|
||||||
The general way to use it is to call one of these commands:
|
|
||||||
|
|
||||||
katenary convert
|
Katenary is a tool to convert compose files to Helm Charts.
|
||||||
katenary convert -c docker-compose.yml
|
|
||||||
katenary convert -c docker-compose.yml -o ./charts
|
|
||||||
|
|
||||||
In case of, check the help of each command using:
|
Each [command] and subcommand has got an "help" and "--help" flag to show more information.
|
||||||
katenary <command> --help
|
|
||||||
or
|
|
||||||
"katenary help <command>"
|
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
katenary [command]
|
katenary [command]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
katenary convert -c docker-compose.yml -o ./charts
|
||||||
|
|
||||||
Available Commands:
|
Available Commands:
|
||||||
completion Generate the autocompletion script for the specified shell
|
completion Generates completion scripts
|
||||||
convert Convert docker-compose to helm chart
|
convert Converts a docker-compose file to a Helm Chart
|
||||||
help Help about any command
|
hash-composefiles Print the hash of the composefiles
|
||||||
show-labels Show labels of a resource
|
help Help about any command
|
||||||
upgrade Upgrade katenary to the latest version if available
|
help-labels Print the labels help for all or a specific label
|
||||||
version Display version
|
schema Print the schema of the katenary file
|
||||||
|
version Print the version number of Katenary
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-h, --help help for katenary
|
-h, --help help for katenary
|
||||||
|
-v, --version version for katenary
|
||||||
|
|
||||||
Use "katenary [command] --help" for more information about a command.
|
Use "katenary [command] --help" for more information about a command.
|
||||||
```
|
```
|
||||||
|
|
||||||
Katenary will try to find a `docker-compose.yaml` or `docker-compose.yml` file inside the current directory. It will check *the existence of the `chart` directory to create a new Helm Chart inside a named subdirectory. Katenary will ask you if you want to delete it before recreating.
|
Katenary will try to find a `docker-compose.yaml` or `docker-compose.yml` file inside the current directory. It will
|
||||||
|
check \*the existence of the `chart` directory to create a new Helm Chart inside a named subdirectory. Katenary will ask
|
||||||
|
you if you want to delete it before recreating.
|
||||||
|
|
||||||
It creates a subdirectory inside `chart` that is named with the `appname` option (default is `MyApp`)
|
It creates a subdirectory inside `chart` that is named with the `appname` option (default is `MyApp`)
|
||||||
|
|
||||||
> To respect the ability to install the same application in the same namespace, Katenary will create "variable" names like `{{ .Release.Name }}-servicename`. So, you will need to use some labels inside your docker-compose file to help katenary to build a correct helm chart.
|
> To respect the ability to install the same application in the same namespace, Katenary will create variable names
|
||||||
|
> like `{{ .Release.Name }}-servicename`. So, you will need to use some labels inside your docker-compose file to help
|
||||||
|
> Katenary to build a correct helm chart.
|
||||||
|
|
||||||
What can be interpreted by Katenary:
|
Example of a possible `docker-compose.yaml` file:
|
||||||
|
|
||||||
- Services with "image" section (cannot work with "build" section)
|
|
||||||
- **Named Volumes** are transformed to persistent volume claims - note that local volume will break the transformation to Helm Chart because there is (for now) no way to make it working (see below for resolution)
|
|
||||||
- if `ports` and/or `expose` section, katenary will create Services and bind the port to the corresponding container port
|
|
||||||
- `depends_on` will add init containers to wait for the depending service (using the first port)
|
|
||||||
- `env_file` list will create a configMap object per environemnt file (⚠ todo: the "to-service" label doesn't work with configMap for now)
|
|
||||||
- some labels can help to bind values, for example:
|
|
||||||
- `katenary.io/ingress: 80` will expose the port 80 in a ingress
|
|
||||||
- `katenary.io/mapenv: |`: allow to map environment to something else than the given value in the compose file
|
|
||||||
|
|
||||||
Exemple of a possible `docker-compose.yaml` file:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "3"
|
|
||||||
services:
|
services:
|
||||||
webapp:
|
webapp:
|
||||||
image: php:7-apache
|
image: php:7-apache
|
||||||
environment:
|
environment:
|
||||||
# note that "database" is a service name
|
# note that "database" is a "compose" service name
|
||||||
|
# so we need to adapt it with the map-env label
|
||||||
DB_HOST: database
|
DB_HOST: database
|
||||||
|
# a pitty to repeat this values, isn't it?
|
||||||
|
# so, let's change them with "values-from" label
|
||||||
|
DB_USER: foo
|
||||||
|
DB_PASSWORD: bar
|
||||||
expose:
|
expose:
|
||||||
- 80
|
- 80
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -146,15 +166,23 @@ services:
|
|||||||
- database
|
- database
|
||||||
labels:
|
labels:
|
||||||
# expose the port 80 as an ingress
|
# expose the port 80 as an ingress
|
||||||
katenary.io/ingress: 80
|
katenary.v3/ingress: |-
|
||||||
|
hostname: myapp.example.com
|
||||||
|
port: 80
|
||||||
# make adaptations, DB_HOST environment is actually the service name
|
# make adaptations, DB_HOST environment is actually the service name
|
||||||
# to hit (note the yaml style, start with "|")
|
katenary.v3/map-env: |-
|
||||||
katenary.io/mapenv: |
|
DB_HOST: '{{ .Release.Name }}-database'
|
||||||
DB_HOST: {{ .Release.Name }}-database
|
# get the values from the "database" service
|
||||||
|
# this will use the database secrets and environment,
|
||||||
|
# see the "database" service to see the values
|
||||||
|
katenary.v3/values-from: |-
|
||||||
|
DB_USER: database.MARIADB_USER
|
||||||
|
DB_PASSWORD: database.MARIADB_PASSWORD
|
||||||
|
|
||||||
database:
|
database:
|
||||||
image: mariadb:10
|
image: mariadb:10
|
||||||
env_file:
|
env_file:
|
||||||
# this will create a configMap
|
# this values will be added in a configMap
|
||||||
- my_env.env
|
- my_env.env
|
||||||
environment:
|
environment:
|
||||||
MARIADB_USER: foo
|
MARIADB_USER: foo
|
||||||
@@ -163,38 +191,112 @@ services:
|
|||||||
labels:
|
labels:
|
||||||
# no need to declare this port in docker-compose
|
# no need to declare this port in docker-compose
|
||||||
# but katenary will need it
|
# but katenary will need it
|
||||||
katenary.io/ports: 3306
|
katenary.v3/ports: |-
|
||||||
|
- 3306
|
||||||
# these variables are secrets
|
# these variables are secrets
|
||||||
katenary.io/secret-vars: MARIADB_ROOT_PASSWORD, MARIADB_PASSWORD
|
katenary.v3/secrets: |-
|
||||||
|
- MARIADB_ROOT_PASSWORD
|
||||||
|
- MARIADB_PASSWORD
|
||||||
```
|
```
|
||||||
|
|
||||||
# Labels
|
## Labels
|
||||||
|
|
||||||
These labels could be found by `katenary show-labels`, and can be placed as "labels" inside your docker-compose file:
|
These labels could be found by `katenary help-labels`, and can be placed as labels inside your docker-compose file:
|
||||||
|
|
||||||
```
|
```text
|
||||||
katenary.io/ignore : ignore the container, it will not yied any object in the helm chart
|
To get more information about a label, use `katenary help-label <name_without_prefix>
|
||||||
katenary.io/secret-vars : secret variables to push on a secret file
|
e.g. katenary help-label dependencies
|
||||||
katenary.io/secret-envfiles : set the given file names as a secret instead of configmap
|
|
||||||
katenary.io/mapenv : map environment variable to a template string (yaml style)
|
katenary.v3/configmap-files: []string Inject files as Configmap.
|
||||||
katenary.io/ports : set the ports to expose as a service (coma separated)
|
katenary.v3/cronjob: object Create a cronjob from the service.
|
||||||
katenary.io/ingress : set the port to expose in an ingress (coma separated)
|
katenary.v3/dependencies: []object Add Helm dependencies to the service.
|
||||||
katenary.io/configmap-volumes : specifies that the volumes points on a configmap (coma separated)
|
katenary.v3/description: string Description of the service
|
||||||
katenary.io/same-pod : specifies that the pod should be deployed in the same pod than the given service name
|
katenary.v3/env-from: []string Add environment variables from another service.
|
||||||
katenary.io/empty-dirs : specifies that the given volume names should be "emptyDir" instead of persistentVolumeClaim (coma separated)
|
katenary.v3/exchange-volumes: []object Add exchange volumes (empty directory on the node) to share data
|
||||||
katenary.io/healthcheck : specifies that the container should be monitored by a healthcheck, **it overrides the docker-compose healthcheck**.
|
katenary.v3/health-check: object Health check to be added to the deployment.
|
||||||
You can use these form of label values:
|
katenary.v3/ignore: bool Ignore the service
|
||||||
- "http://[not used address][:port][/path]" to specify an http healthcheck
|
katenary.v3/ingress: object Ingress rules to be added to the service.
|
||||||
- "tcp://[not used address]:port" to specify a tcp healthcheck
|
katenary.v3/main-app: bool Mark the service as the main app.
|
||||||
- other string is condidered as a "command" healthcheck
|
katenary.v3/map-env: map[string]string Map env vars from the service to the deployment.
|
||||||
|
katenary.v3/ports: []uint32 Ports to be added to the service.
|
||||||
|
katenary.v3/same-pod: string Move the same-pod deployment to the target deployment.
|
||||||
|
katenary.v3/secrets: []string Env vars to be set as secrets.
|
||||||
|
katenary.v3/values: []string or map[string]string Environment variables to be added to the values.yaml
|
||||||
|
katenary.v3/values-from: map[string]string Add values from another service.
|
||||||
```
|
```
|
||||||
|
|
||||||
# What a name...
|
## Katenary.yaml file and schema validation
|
||||||
|
|
||||||
|
Instead of using labels inside the docker-compose file, you can use a `katenary.yaml` file to define the labels. This
|
||||||
|
file is simpler to read and maintain, but you need to keep it up-to-date with the docker-compose file.
|
||||||
|
|
||||||
|
For example, instead of using this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: nginx:latest
|
||||||
|
katenary.v3/ingress: |-
|
||||||
|
hostname: myapp.example.com
|
||||||
|
port: 80
|
||||||
|
```
|
||||||
|
|
||||||
|
You can remove the labels, and use a `katenary.yaml` file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
web:
|
||||||
|
ingress:
|
||||||
|
hostname: myapp.example.com
|
||||||
|
port: 80
|
||||||
|
```
|
||||||
|
|
||||||
|
To validate the `katenary.yaml` file, you can use the JSON schema using the "master" raw content:
|
||||||
|
|
||||||
|
`https://raw.githubusercontent.com/Katenary/katenary/refs/heads/master/katenary.json`
|
||||||
|
|
||||||
|
It's easy to configure in [LazyVim](https://www.lazyvim.org/), using `nvim-lspconfig`,
|
||||||
|
create a Lua file in your `plugins` directory, or apply the settings as the example below:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- yaml.lua
|
||||||
|
|
||||||
|
return {
|
||||||
|
{
|
||||||
|
"neovim/nvim-lspconfig",
|
||||||
|
opts = {
|
||||||
|
servers = {
|
||||||
|
yamlls = {
|
||||||
|
settings = {
|
||||||
|
yaml = {
|
||||||
|
schemas = {
|
||||||
|
["https://raw.githubusercontent.com/Katenary/katenary/master/katenary.json"] = "katenary.yaml",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use this address to validate the `katenary.yaml` file in VSCode:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"yaml.schemas": {
|
||||||
|
"https://raw.githubusercontent.com/Katenary/katenary/master/katenary.json": "katenary.yaml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> You can, of course, replace the `master` with a specific tag or branch.
|
||||||
|
|
||||||
|
## What a name…
|
||||||
|
|
||||||
Katenary is the stylized name of the project that comes from the "catenary" word.
|
Katenary is the stylized name of the project that comes from the "catenary" word.
|
||||||
|
|
||||||
A catenary is a curve formed by a wire, rope, or chain hanging freely from two points that are not in the same vertical line. For example, the anchor chain between a bot and the anchor.
|
A catenary is a curve formed by a wire, rope, or chain hanging freely from two points that are not in the same vertical
|
||||||
|
line. For example, the anchor chain between a boat and the anchor.
|
||||||
This "curved link" represents what we try to do, the project is a "streched link from docker-compose to helm chart".
|
|
||||||
|
|
||||||
|
|
||||||
|
This curved link represents what we try to do, the project is a stretched link from docker-compose to helm chart.
|
||||||
|
@@ -1,154 +1,320 @@
|
|||||||
|
// Katenary CLI, main package.
|
||||||
|
//
|
||||||
|
// This package is not intended to be imported. It contains the
|
||||||
|
// main function that build the command line with `cobra` package.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"katenary/generator/writers"
|
"log"
|
||||||
"katenary/helm"
|
"os"
|
||||||
"katenary/update"
|
"strings"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
|
"github.com/katenary/katenary/internal/generator"
|
||||||
|
"github.com/katenary/katenary/internal/generator/katenaryfile"
|
||||||
|
"github.com/katenary/katenary/internal/generator/labels"
|
||||||
|
"github.com/katenary/katenary/internal/utils"
|
||||||
|
|
||||||
|
"github.com/compose-spec/compose-go/cli"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Version = "master" // changed at compile time
|
const longHelp = `Katenary is a tool to convert compose files to Helm Charts.
|
||||||
|
|
||||||
var longHelp = `Katenary aims to be a tool to convert docker-compose files to Helm Charts.
|
Each [command] and subcommand has got an "help" and "--help" flag to show more information.
|
||||||
It will create deployments, services, volumes, secrets, and ingress resources.
|
|
||||||
But it will also create initContainers based on depend_on, healthcheck, and other features.
|
|
||||||
It's not magical, sometimes you'll need to fix the generated charts.
|
|
||||||
The general way to use it is to call one of these commands:
|
|
||||||
|
|
||||||
katenary convert
|
|
||||||
katenary convert -c docker-compose.yml
|
|
||||||
katenary convert -c docker-compose.yml -o ./charts
|
|
||||||
|
|
||||||
In case of, check the help of each command using:
|
|
||||||
katenary <command> --help
|
|
||||||
or
|
|
||||||
"katenary help <command>"
|
|
||||||
`
|
`
|
||||||
|
|
||||||
func init() {
|
func main() {
|
||||||
// apply the version to the "update" package
|
rootCmd := buildRootCmd()
|
||||||
update.Version = Version
|
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func buildRootCmd() *cobra.Command {
|
||||||
|
|
||||||
// The base command
|
|
||||||
rootCmd := &cobra.Command{
|
rootCmd := &cobra.Command{
|
||||||
Use: "katenary",
|
Use: "katenary",
|
||||||
Long: longHelp,
|
Long: longHelp,
|
||||||
Short: "Katenary is a tool to convert docker-compose files to Helm Charts",
|
Short: "Katenary is a tool to convert docker-compose files to Helm Charts",
|
||||||
}
|
}
|
||||||
|
rootCmd.Example = ` katenary convert -c docker-compose.yml -o ./charts`
|
||||||
|
|
||||||
// to display the version
|
rootCmd.Version = generator.GetVersion()
|
||||||
versionCmd := &cobra.Command{
|
rootCmd.CompletionOptions.DisableDescriptions = false
|
||||||
Use: "version",
|
rootCmd.CompletionOptions.DisableNoDescFlag = false
|
||||||
Short: "Display version",
|
|
||||||
Run: func(c *cobra.Command, args []string) { c.Println(Version) },
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert command, need some flags
|
|
||||||
convertCmd := &cobra.Command{
|
|
||||||
Use: "convert",
|
|
||||||
Short: "Convert docker-compose to helm chart",
|
|
||||||
Long: "Convert docker-compose to helm chart. The resulting helm chart will be in the current directory/" +
|
|
||||||
ChartsDir + "/" + AppName +
|
|
||||||
".\nThe appversion will be generated that way:\n" +
|
|
||||||
"- if it's in a git project, it takes git version or tag\n" +
|
|
||||||
"- if it's not defined, so the version will be get from the --app-version flag \n" +
|
|
||||||
"- if it's not defined, so the 0.0.1 version is used",
|
|
||||||
Run: func(c *cobra.Command, args []string) {
|
|
||||||
force := c.Flag("force").Changed
|
|
||||||
// TODO: is there a way to get typed values from cobra?
|
|
||||||
appversion := c.Flag("app-version").Value.String()
|
|
||||||
composeFile := c.Flag("compose-file").Value.String()
|
|
||||||
appName := c.Flag("app-name").Value.String()
|
|
||||||
chartVersion := c.Flag("chart-version").Value.String()
|
|
||||||
chartDir := c.Flag("output-dir").Value.String()
|
|
||||||
indentation, err := strconv.Atoi(c.Flag("indent-size").Value.String())
|
|
||||||
if err != nil {
|
|
||||||
writers.IndentSize = indentation
|
|
||||||
}
|
|
||||||
Convert(composeFile, appversion, appName, chartDir, chartVersion, force)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
convertCmd.Flags().BoolP(
|
|
||||||
"force", "f", false, "force overwrite of existing output files")
|
|
||||||
convertCmd.Flags().StringP(
|
|
||||||
"app-version", "a", AppVersion, "app version")
|
|
||||||
convertCmd.Flags().StringP(
|
|
||||||
"chart-version", "v", ChartVersion, "chart version")
|
|
||||||
convertCmd.Flags().StringP(
|
|
||||||
"compose-file", "c", ComposeFile, "docker compose file")
|
|
||||||
convertCmd.Flags().StringP(
|
|
||||||
"app-name", "n", AppName, "application name")
|
|
||||||
convertCmd.Flags().StringP(
|
|
||||||
"output-dir", "o", ChartsDir, "chart directory")
|
|
||||||
convertCmd.Flags().IntP(
|
|
||||||
"indent-size", "i", 2, "set the indent size of the YAML files")
|
|
||||||
|
|
||||||
// show possible labels to set in docker-compose file
|
|
||||||
showLabelsCmd := &cobra.Command{
|
|
||||||
Use: "show-labels",
|
|
||||||
Short: "Show labels of a resource",
|
|
||||||
Run: func(c *cobra.Command, args []string) {
|
|
||||||
c.Println(helm.GetLabelsDocumentation())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the binary to the latest version
|
|
||||||
updateCmd := &cobra.Command{
|
|
||||||
Use: "upgrade",
|
|
||||||
Short: "Upgrade katenary to the latest version if available",
|
|
||||||
Run: func(c *cobra.Command, args []string) {
|
|
||||||
version, assets, err := update.CheckLatestVersion()
|
|
||||||
if err != nil {
|
|
||||||
c.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Println("Updating to version: " + version)
|
|
||||||
err = update.DownloadLatestVersion(assets)
|
|
||||||
if err != nil {
|
|
||||||
c.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Println("Update completed")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
versionCmd,
|
generateCompletionCommand(rootCmd.Name()),
|
||||||
convertCmd,
|
generateVersionCommand(),
|
||||||
showLabelsCmd,
|
generateConvertCommand(),
|
||||||
updateCmd,
|
generateHashComposefilesCommand(),
|
||||||
|
generateLabelHelpCommand(),
|
||||||
|
generateSchemaCommand(),
|
||||||
)
|
)
|
||||||
|
|
||||||
// in parallel, check if the current katenary version is the latest
|
return rootCmd
|
||||||
ch := make(chan string)
|
}
|
||||||
go func() {
|
|
||||||
version, _, err := update.CheckLatestVersion()
|
const completionHelp = `To load completions:
|
||||||
if err != nil {
|
|
||||||
ch <- ""
|
Bash:
|
||||||
return
|
# Add this line in your ~/.bashrc or ~/.bash_profile file
|
||||||
}
|
$ source <(%[1]s completion bash)
|
||||||
if Version != version {
|
|
||||||
ch <- fmt.Sprintf("\x1b[33mNew version available: " +
|
# Or, you can load completions for each users session. Execute once:
|
||||||
version +
|
# Linux:
|
||||||
" - to auto upgrade katenary, you can execute: katenary upgrade\x1b[0m\n")
|
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
|
||||||
}
|
# macOS:
|
||||||
}()
|
$ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s
|
||||||
|
|
||||||
// Execute the command
|
Zsh:
|
||||||
finalize := make(chan error)
|
# If shell completion is not already enabled in your environment,
|
||||||
go func() {
|
# you will need to enable it. You can execute the following once:
|
||||||
finalize <- rootCmd.Execute()
|
|
||||||
}()
|
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
|
||||||
|
|
||||||
// Wait for both goroutines to finish
|
# To load completions for each session, execute once:
|
||||||
if err := <-finalize; err != nil {
|
$ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
|
||||||
fmt.Println(err)
|
|
||||||
}
|
# You will need to start a new shell for this setup to take effect.
|
||||||
fmt.Print(<-ch)
|
|
||||||
|
fish:
|
||||||
|
$ %[1]s completion fish | source
|
||||||
|
|
||||||
|
# To load completions for each session, execute once:
|
||||||
|
$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
|
||||||
|
|
||||||
|
PowerShell:
|
||||||
|
PS> %[1]s completion powershell | Out-String | Invoke-Expression
|
||||||
|
|
||||||
|
# To load completions for every new session, run:
|
||||||
|
PS> %[1]s completion powershell > %[1]s.ps1
|
||||||
|
# and source this file from your PowerShell profile.
|
||||||
|
`
|
||||||
|
|
||||||
|
func generateCompletionCommand(name string) *cobra.Command {
|
||||||
|
bashV1 := false
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "completion",
|
||||||
|
DisableFlagsInUseLine: true,
|
||||||
|
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
|
||||||
|
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
|
||||||
|
Short: "Generates completion scripts",
|
||||||
|
Long: fmt.Sprintf(completionHelp, name),
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return cmd.Help()
|
||||||
|
}
|
||||||
|
switch args[0] {
|
||||||
|
case "bash":
|
||||||
|
// get the bash version
|
||||||
|
if cmd.Flags().Changed("bash-v1") {
|
||||||
|
return cmd.Root().GenBashCompletion(os.Stdout)
|
||||||
|
}
|
||||||
|
return cmd.Root().GenBashCompletionV2(os.Stdout, true)
|
||||||
|
case "zsh":
|
||||||
|
return cmd.Root().GenZshCompletion(os.Stdout)
|
||||||
|
case "fish":
|
||||||
|
return cmd.Root().GenFishCompletion(os.Stdout, true)
|
||||||
|
case "powershell":
|
||||||
|
return cmd.Root().GenPowerShellCompletion(os.Stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("unknown completion type: %s", args[0])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a flag to force bash completion v1
|
||||||
|
cmd.Flags().Bool("bash-v1", bashV1, "Force bash completion v1")
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateConvertCommand() *cobra.Command {
|
||||||
|
force := false
|
||||||
|
outputDir := "./chart"
|
||||||
|
dockerComposeFile := make([]string, 0)
|
||||||
|
profiles := make([]string, 0)
|
||||||
|
helmdepUpdate := false
|
||||||
|
var appVersion *string
|
||||||
|
givenAppVersion := ""
|
||||||
|
chartVersion := "0.1.0"
|
||||||
|
icon := ""
|
||||||
|
envFiles := []string{}
|
||||||
|
|
||||||
|
convertCmd := &cobra.Command{
|
||||||
|
Use: "convert",
|
||||||
|
Short: "Converts a docker-compose file to a Helm Chart",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(strings.TrimSpace(givenAppVersion)) > 0 {
|
||||||
|
appVersion = &givenAppVersion
|
||||||
|
}
|
||||||
|
return generator.Convert(generator.ConvertOptions{
|
||||||
|
Force: force,
|
||||||
|
OutputDir: outputDir,
|
||||||
|
Profiles: profiles,
|
||||||
|
HelmUpdate: helmdepUpdate,
|
||||||
|
AppVersion: appVersion,
|
||||||
|
ChartVersion: chartVersion,
|
||||||
|
Icon: icon,
|
||||||
|
EnvFiles: envFiles,
|
||||||
|
}, dockerComposeFile...)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
convertCmd.Flags().BoolVarP(
|
||||||
|
&force,
|
||||||
|
"force",
|
||||||
|
"f",
|
||||||
|
force,
|
||||||
|
"Force the overwrite of the chart directory",
|
||||||
|
)
|
||||||
|
convertCmd.Flags().BoolVarP(
|
||||||
|
&helmdepUpdate,
|
||||||
|
"helm-update",
|
||||||
|
"u",
|
||||||
|
helmdepUpdate,
|
||||||
|
"Update helm dependencies if helm is installed",
|
||||||
|
)
|
||||||
|
convertCmd.Flags().StringSliceVarP(
|
||||||
|
&profiles,
|
||||||
|
"profile",
|
||||||
|
"p",
|
||||||
|
profiles,
|
||||||
|
"Specify the profiles to use",
|
||||||
|
)
|
||||||
|
convertCmd.Flags().StringVarP(
|
||||||
|
&outputDir,
|
||||||
|
"output-dir",
|
||||||
|
"o",
|
||||||
|
outputDir,
|
||||||
|
"Specify the output directory",
|
||||||
|
)
|
||||||
|
convertCmd.Flags().StringSliceVarP(
|
||||||
|
&dockerComposeFile,
|
||||||
|
"compose-file",
|
||||||
|
"c",
|
||||||
|
cli.DefaultFileNames,
|
||||||
|
"Specify an alternate compose files - can be specified multiple times or use coma to separate them.\n"+
|
||||||
|
"Note that overides files are also used whatever the files you specify here.\nThe overides files are:\n"+
|
||||||
|
strings.Join(cli.DefaultOverrideFileNames, ", \n")+
|
||||||
|
"\n",
|
||||||
|
)
|
||||||
|
convertCmd.Flags().StringVarP(
|
||||||
|
&givenAppVersion,
|
||||||
|
"app-version",
|
||||||
|
"a",
|
||||||
|
"",
|
||||||
|
"Specify the app version (in Chart.yaml)",
|
||||||
|
)
|
||||||
|
convertCmd.Flags().StringVarP(
|
||||||
|
&chartVersion,
|
||||||
|
"chart-version",
|
||||||
|
"v",
|
||||||
|
chartVersion,
|
||||||
|
"Specify the chart version (in Chart.yaml)",
|
||||||
|
)
|
||||||
|
convertCmd.Flags().StringVarP(
|
||||||
|
&icon,
|
||||||
|
"icon",
|
||||||
|
"i",
|
||||||
|
"",
|
||||||
|
"Specify the icon (in Chart.yaml), use a valid URL, Helm does not support local files at this time.",
|
||||||
|
)
|
||||||
|
convertCmd.Flags().StringSliceVarP(
|
||||||
|
&envFiles,
|
||||||
|
"env-file",
|
||||||
|
"e",
|
||||||
|
envFiles,
|
||||||
|
"Specify the env file to use additonnaly to the .env file. Can be specified multiple times.",
|
||||||
|
)
|
||||||
|
|
||||||
|
return convertCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateVersionCommand() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "Print the version number of Katenary",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println(generator.GetVersion())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateLabelHelpCommand() *cobra.Command {
|
||||||
|
markdown := false
|
||||||
|
all := false
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "help-labels [label]",
|
||||||
|
Short: "Print the labels help for all or a specific label",
|
||||||
|
Long: `Print the labels help for all or a specific label
|
||||||
|
If no label is specified, the help for all labels is printed.
|
||||||
|
If a label is specified, the help for this label is printed.
|
||||||
|
|
||||||
|
The name of the label must be specified without the prefix ` + labels.Prefix() + `.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
kanetary help-labels
|
||||||
|
katenary help-labels ingress
|
||||||
|
katenary help-labels map-env
|
||||||
|
`,
|
||||||
|
ValidArgs: labels.GetLabelNames(),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
fmt.Println(labels.GetLabelHelpFor(args[0], markdown))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if all {
|
||||||
|
// show the help for all labels
|
||||||
|
l := len(labels.GetLabelNames())
|
||||||
|
for i, label := range labels.GetLabelNames() {
|
||||||
|
fmt.Println(labels.GetLabelHelpFor(label, markdown))
|
||||||
|
if !markdown && i < l-1 {
|
||||||
|
fmt.Println(strings.Repeat("-", 80))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(labels.GetLabelHelp(markdown))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Flags().BoolVarP(&markdown, "markdown", "m", markdown, "Use the markdown format")
|
||||||
|
cmd.Flags().BoolVarP(&all, "all", "a", all, "Print the full help for all labels")
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateHashComposefilesCommand() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "hash-composefiles [composefile]",
|
||||||
|
Short: "Print the hash of the composefiles",
|
||||||
|
Long: `Print the hash of the composefiles
|
||||||
|
If no composefile is specified, the hash of all composefiles is printed.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
if hash, err := utils.HashComposefiles(args); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(hash)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateSchemaCommand() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "schema",
|
||||||
|
Short: "Print the schema of the katenary file",
|
||||||
|
Long: "Generate a schama for katenary.yaml file that can be used to validate the file or to use with yaml LSP to complete and check your configuration.",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println(katenaryfile.GenerateSchema())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
78
cmd/katenary/main_test.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildCommand(t *testing.T) {
|
||||||
|
rootCmd := buildRootCmd()
|
||||||
|
if rootCmd == nil {
|
||||||
|
t.Errorf("Expected rootCmd to be defined")
|
||||||
|
} else if rootCmd.Use != "katenary" {
|
||||||
|
t.Errorf("Expected rootCmd.Use to be katenary, got %s", rootCmd.Use)
|
||||||
|
}
|
||||||
|
numCommands := 6
|
||||||
|
if len(rootCmd.Commands()) != numCommands {
|
||||||
|
t.Errorf("Expected %d command, got %d", numCommands, len(rootCmd.Commands()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetVersion(t *testing.T) {
|
||||||
|
cmd := buildRootCmd()
|
||||||
|
if cmd == nil {
|
||||||
|
t.Errorf("Expected cmd to be defined")
|
||||||
|
}
|
||||||
|
version := generateVersionCommand()
|
||||||
|
old := os.Stdout
|
||||||
|
r, w, _ := os.Pipe()
|
||||||
|
os.Stdout = w
|
||||||
|
|
||||||
|
version.Run(cmd, nil)
|
||||||
|
|
||||||
|
w.Close()
|
||||||
|
os.Stdout = old
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
io.Copy(&buf, r)
|
||||||
|
output := buf.String()
|
||||||
|
if !strings.Contains(output, "(devel)") {
|
||||||
|
t.Errorf("Expected output to contain '(devel)', got %s", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSchemaCommand(t *testing.T) {
|
||||||
|
cmd := buildRootCmd()
|
||||||
|
if cmd == nil {
|
||||||
|
t.Errorf("Expected cmd to be defined")
|
||||||
|
}
|
||||||
|
schema := generateSchemaCommand()
|
||||||
|
old := os.Stdout
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create pipe: %v", err)
|
||||||
|
}
|
||||||
|
os.Stdout = w
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
schema.Run(cmd, nil)
|
||||||
|
w.Close()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
io.Copy(&buf, r)
|
||||||
|
<-done
|
||||||
|
|
||||||
|
os.Stdout = old
|
||||||
|
|
||||||
|
// try to parse json
|
||||||
|
schemaContent := make(map[string]any)
|
||||||
|
if err := json.Unmarshal(buf.Bytes(), &schemaContent); err != nil {
|
||||||
|
t.Errorf("Expected valid json")
|
||||||
|
}
|
||||||
|
}
|
@@ -1,144 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"katenary/compose"
|
|
||||||
"katenary/generator"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
composeFiles = []string{"compose.yml", "compose.yaml", "docker-compose.yaml", "docker-compose.yml"}
|
|
||||||
ComposeFile = ""
|
|
||||||
AppName = "MyApp"
|
|
||||||
ChartsDir = "chart"
|
|
||||||
AppVersion = "0.0.1"
|
|
||||||
ChartVersion = "0.1.0"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
FindComposeFile()
|
|
||||||
SetAppName()
|
|
||||||
SetAppVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
func FindComposeFile() bool {
|
|
||||||
for _, file := range composeFiles {
|
|
||||||
if _, err := os.Stat(file); err == nil {
|
|
||||||
ComposeFile = file
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAppName sets the application name from the current directory name.
|
|
||||||
func SetAppName() {
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
AppName = filepath.Base(wd)
|
|
||||||
|
|
||||||
if AppName == "" {
|
|
||||||
AppName = "MyApp"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAppVersion set the AppVersion variable to the git version/tag
|
|
||||||
func SetAppVersion() {
|
|
||||||
AppVersion, _ = detectGitVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to detect the git version/tag.
|
|
||||||
func detectGitVersion() (string, error) {
|
|
||||||
defaulVersion := "0.0.1"
|
|
||||||
// Check if .git directory exists
|
|
||||||
if s, err := os.Stat(".git"); err != nil {
|
|
||||||
// .git should be a directory
|
|
||||||
return defaulVersion, errors.New("no git repository found")
|
|
||||||
} else if !s.IsDir() {
|
|
||||||
// .git should be a directory
|
|
||||||
return defaulVersion, errors.New(".git is not a directory")
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if "git" executable is callable
|
|
||||||
if _, err := exec.LookPath("git"); err != nil {
|
|
||||||
return defaulVersion, errors.New("git executable not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the latest commit hash
|
|
||||||
if out, err := exec.Command("git", "log", "-n1", "--pretty=format:%h").Output(); err == nil {
|
|
||||||
latestCommit := strings.TrimSpace(string(out))
|
|
||||||
// then get the current branch/tag
|
|
||||||
out, err := exec.Command("git", "branch", "--show-current").Output()
|
|
||||||
if err != nil {
|
|
||||||
return defaulVersion, errors.New("git branch --show-current failed")
|
|
||||||
} else {
|
|
||||||
currentBranch := strings.TrimSpace(string(out))
|
|
||||||
// finally, check if the current tag (if exists) correspond to the current commit
|
|
||||||
// git describe --exact-match --tags <latestCommit>
|
|
||||||
out, err := exec.Command("git", "describe", "--exact-match", "--tags", latestCommit).Output()
|
|
||||||
if err == nil {
|
|
||||||
return strings.TrimSpace(string(out)), nil
|
|
||||||
} else {
|
|
||||||
return currentBranch + "-" + latestCommit, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaulVersion, errors.New("git log failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Convert(composeFile, appVersion, appName, chartDir, chartVersion string, force bool) {
|
|
||||||
if len(composeFile) == 0 {
|
|
||||||
fmt.Println("No compose file given")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err := os.Stat(composeFile)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("No compose file found")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the compose file now
|
|
||||||
p := compose.NewParser(composeFile)
|
|
||||||
p.Parse(appName)
|
|
||||||
|
|
||||||
dirname := filepath.Join(chartDir, appName)
|
|
||||||
if _, err := os.Stat(dirname); err == nil && !force {
|
|
||||||
response := ""
|
|
||||||
for response != "y" && response != "n" {
|
|
||||||
response = "n"
|
|
||||||
fmt.Printf(""+
|
|
||||||
"The %s directory already exists, it will be \x1b[31;1mremoved\x1b[0m!\n"+
|
|
||||||
"Do you really want to continue? [y/N]: ", dirname)
|
|
||||||
fmt.Scanf("%s", &response)
|
|
||||||
response = strings.ToLower(response)
|
|
||||||
}
|
|
||||||
if response == "n" {
|
|
||||||
fmt.Println("Cancelled")
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanup and create the chart directory (until "templates")
|
|
||||||
if err := os.RemoveAll(dirname); err != nil {
|
|
||||||
fmt.Printf("Error removing %s: %s\n", dirname, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the templates directory
|
|
||||||
templatesDir := filepath.Join(dirname, "templates")
|
|
||||||
if err := os.MkdirAll(templatesDir, 0755); err != nil {
|
|
||||||
fmt.Printf("Error creating %s: %s\n", templatesDir, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// start generator
|
|
||||||
generator.Generate(p, Version, appName, appVersion, chartVersion, ComposeFile, dirname)
|
|
||||||
|
|
||||||
}
|
|
@@ -1,91 +0,0 @@
|
|||||||
package compose
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/cli"
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ICON_EXCLAMATION = "❕"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Parser is a docker-compose parser.
|
|
||||||
type Parser struct {
|
|
||||||
Data *types.Project
|
|
||||||
temporary *string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
Appname = ""
|
|
||||||
CURRENT_DIR, _ = os.Getwd()
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewParser create a Parser and parse the file given in filename. If filename is empty, we try to parse the content[0] argument that should be a valid YAML content.
|
|
||||||
func NewParser(filename string, content ...string) *Parser {
|
|
||||||
|
|
||||||
p := &Parser{}
|
|
||||||
|
|
||||||
if len(content) > 0 { // mainly for the tests...
|
|
||||||
dir := filepath.Dir(filename)
|
|
||||||
err := os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
p.temporary = &dir
|
|
||||||
ioutil.WriteFile(filename, []byte(content[0]), 0644)
|
|
||||||
cli.DefaultFileNames = []string{filename}
|
|
||||||
}
|
|
||||||
// if filename is not in cli Default files, add it
|
|
||||||
if len(filename) > 0 {
|
|
||||||
found := false
|
|
||||||
for _, f := range cli.DefaultFileNames {
|
|
||||||
if f == filename {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add the file at first position
|
|
||||||
if !found {
|
|
||||||
cli.DefaultFileNames = append([]string{filename}, cli.DefaultFileNames...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse using compose-go parser, adapt a bit the Project and set Appname.
|
|
||||||
func (p *Parser) Parse(appname string) {
|
|
||||||
|
|
||||||
// Reminder:
|
|
||||||
// - set Appname
|
|
||||||
// - loas services
|
|
||||||
|
|
||||||
options, err := cli.NewProjectOptions(nil,
|
|
||||||
cli.WithDefaultConfigPath,
|
|
||||||
cli.WithNormalization(true),
|
|
||||||
cli.WithInterpolation(true),
|
|
||||||
cli.WithResolvedPaths(true),
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
proj, err := cli.ProjectFromOptions(options)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Failed to create project", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
Appname = proj.Name
|
|
||||||
p.Data = proj
|
|
||||||
CURRENT_DIR = p.Data.WorkingDir
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetCurrentDir() string {
|
|
||||||
return CURRENT_DIR
|
|
||||||
}
|
|
9
doc/docs/.markdownlint.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
MD012: false
|
||||||
|
MD013: false
|
||||||
|
MD022: false
|
||||||
|
MD033: false
|
||||||
|
MD041: false
|
||||||
|
MD046: false
|
||||||
|
# list indentation
|
||||||
|
MD007:
|
||||||
|
indent: 4
|
105
doc/docs/coding.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# How Katenary works behind the scene
|
||||||
|
|
||||||
|
This section is for developers who want to take part in Katenary. Here we describe how it works and the expected
|
||||||
|
principles.
|
||||||
|
|
||||||
|
## A few important points
|
||||||
|
|
||||||
|
Katenary is developed in Go. The version currently supported is 1.20. For reasons of readability, the `any` type is
|
||||||
|
preferred to `interface{}`.
|
||||||
|
|
||||||
|
Since version v3, Katenary uses, in addition to `go-compose`, the `k8s` library to generate objects that are guaranteed
|
||||||
|
to work before transformation. Katenary adds Helm syntax entries to add loops, transformations, and conditions.
|
||||||
|
|
||||||
|
We really try to follow best practices and code principles. But, Katenary needs a lot of workarounds and string
|
||||||
|
manipulation during the process. There are, also, some drawbacks using standard k8s packages that make a lot of type
|
||||||
|
checks when generating the objects. We need to finalize the values after object generation.
|
||||||
|
|
||||||
|
**This makes the coding a bit harder than simply converting from YAML to YAML.**
|
||||||
|
|
||||||
|
> If Katenary only generated YAML objects, the algorithms would be much simpler and would require less generation work.
|
||||||
|
|
||||||
|
## General principle
|
||||||
|
|
||||||
|
During conversion, the `generator` package is primarily responsible for creating "objects". The principle is to generate
|
||||||
|
one `Deployment` per `compose` service. If the container coming from "compose" exposes ports (explicitly), then a
|
||||||
|
service is created.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
|
||||||
|
D[Deployment]:::outputs@{shape: curv-trap}
|
||||||
|
C[Container List]@{shape: docs}
|
||||||
|
ConfigMap:::outputs@{shape: curv-trap}
|
||||||
|
Secrets:::outputs@{shape: curv-trap}
|
||||||
|
H[Helm Chart.yaml file]:::outputs@{shape: curv-trap}
|
||||||
|
Val[Values files]:::outputs@{shape: curv-trap}
|
||||||
|
PVC:::outputs@{shape: curv-trap}
|
||||||
|
S[Service]:::outputs@{shape: curv-trap}
|
||||||
|
|
||||||
|
A[Compose file]:::inputs --> B[Compose parser]
|
||||||
|
B --> G[Generator]
|
||||||
|
G --> P[Ports exposed to services] ---> S
|
||||||
|
G ------> H
|
||||||
|
G --> C --> D
|
||||||
|
G ------> Val
|
||||||
|
G ....-> M[Merge Continainers if same-pod]
|
||||||
|
M ..-> C
|
||||||
|
G --> E[Environment variables] ----> Secrets & ConfigMap
|
||||||
|
G--> V[Bind volumes] -------> PVC
|
||||||
|
V -----> CF[ Create ConfigMap\nfor static files as\nconfigmap-files] --> ConfigMap
|
||||||
|
|
||||||
|
Secrets & ConfigMap -- create envFrom --> D
|
||||||
|
V -- bind volumes --> D
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
If the declaration of a container is to be integrated into another pod (via the `same-pod` label), this `Deployment` and
|
||||||
|
its associated service are still created. They are deleted last, once the merge has been completed.
|
||||||
|
|
||||||
|
## Conversion in "`generator`" package
|
||||||
|
|
||||||
|
The `generator` package is where object struct are defined, and where you can find the `Generate()` function.
|
||||||
|
|
||||||
|
The generation fills `HelmChart` object using a loop:
|
||||||
|
|
||||||
|
```golang
|
||||||
|
for _, service := range project.Services {
|
||||||
|
dep := NewDeployment(service)
|
||||||
|
y, _ := dep.Yaml()
|
||||||
|
chart.Templates[dep.Filename()] = &ChartTemplate{
|
||||||
|
Content: y,
|
||||||
|
Servicename: service.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**A lot** of string manipulations are made by each `Yaml()` methods. This is where you find the complex and impacting
|
||||||
|
operations. The `Yaml` methods **don't return a valid YAML content**. This is a Helm Chart YAML content with template
|
||||||
|
conditions, values and calls to helper templates.
|
||||||
|
|
||||||
|
> The `Yaml()` methods, in each object, need contribution, help, fixes, enhancements... They work, but there is a lot of
|
||||||
|
> complexity. Please, create issues, pull-requests and conversation in the GitHub repository.
|
||||||
|
|
||||||
|
The final step, before sending all templates to chart, is to bind the containers inside the same pod where it's
|
||||||
|
specified.
|
||||||
|
|
||||||
|
For each source container linked to the destination:
|
||||||
|
|
||||||
|
- we get the deployment of the source
|
||||||
|
- we copy the container to the destination deployment
|
||||||
|
- we get the associated service (if any)
|
||||||
|
- we then copy the service port to the destination service
|
||||||
|
- we finally remove the source service and deployment
|
||||||
|
|
||||||
|
> The `Configmap`, secrets, variables... are kept.
|
||||||
|
|
||||||
|
It finally computes the `helper` file.
|
||||||
|
|
||||||
|
## Conversion command
|
||||||
|
|
||||||
|
The `generator` works the same as described above. But the "convert" command makes some final steps:
|
||||||
|
|
||||||
|
- generate `values.yaml` and `Chart.yaml` files from the `HelmChart` object
|
||||||
|
- add comments to the `values.yaml` files
|
||||||
|
- add comments to the `Chart.yaml` files
|
18
doc/docs/dependencies.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Why those dependencies?
|
||||||
|
|
||||||
|
Katenary uses `compose-go` and several Kubernetes official packages.
|
||||||
|
|
||||||
|
- `github.com/compose-spec/compose-go`: to parse compose files. It ensures :
|
||||||
|
- that the project respects the "compose" specification
|
||||||
|
- that Katenary uses the "compose" struct exactly the same way `podman compose` or `docker compose` does
|
||||||
|
- `github.com/spf13/cobra`: to parse command line arguments, sub-commands and flags. It also generates completion for
|
||||||
|
bash, zsh, fish and PowerShell.
|
||||||
|
- `github.com/thediveo/netdb`: to get the standard names of a service from its port number
|
||||||
|
- `gopkg.in/yaml.v3`:
|
||||||
|
- to generate `Chart.yaml` and `values.yaml` files (only)
|
||||||
|
- to parse Katenary labels in the compose file
|
||||||
|
- `k8s.io/api` and `k8s.io/apimachinery` to create Kubernetes objects
|
||||||
|
- `sigs.k8s.io/yaml`: to generate Katenary YAML files in the format of Kubernetes objects
|
||||||
|
|
||||||
|
There are also some other packages used in the project, like `gopkg.in/yaml` to parse labels. I'm sorry to not list the
|
||||||
|
entire dependencies. You can check the `go.mod` file to see all the dependencies.
|
112
doc/docs/faq.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# Frequently Asked Questions
|
||||||
|
|
||||||
|
## Why Katenary?
|
||||||
|
|
||||||
|
The main author[^1] of Katenary is a big fan of Podman, Docker and makes a huge use of Compose. He uses it a lot in his
|
||||||
|
daily work. When he started to work with Kubernetes, he wanted to have the same experience as with Docker Compose.
|
||||||
|
He wanted to have a tool that could convert his `docker-compose` files to Kubernetes manifests, but also to Helm charts.
|
||||||
|
|
||||||
|
Kompose was a good option. But the lacks of some options and configuration for the output Helm chart made him think
|
||||||
|
about creating a new tool. He wanted to have a tool that could generate a complete Helm chart, with a lot of options
|
||||||
|
and flexibility.
|
||||||
|
|
||||||
|
[^1]: I'm talking about myself :sunglasses: - Patrice FERLET, aka Metal3d, Tech Lead and DevOps Engineer at Klee Group.
|
||||||
|
|
||||||
|
## What's the difference between Katenary and Kompose?
|
||||||
|
|
||||||
|
[Kompose](https://kompose.io/) is a very nice tool, made by the Kubernetes community. It's a tool to convert
|
||||||
|
`docker-compose` files to Kubernetes manifests. It's a very good tool, and it's more mature than Katenary.
|
||||||
|
|
||||||
|
Kompose is able to generate Helm charts, but [it could be not the case in future releases](https://github.com/kubernetes/kompose/issues/1716) for several reasons[^2].
|
||||||
|
|
||||||
|
[^2]:
|
||||||
|
The author of Kompose explains that they have no bandwidth to maintain the Helm chart generation. It's a complex
|
||||||
|
task, and we can confirm. Katenary takes a lot of time to be developed and maintained. This issue mentions Katenary as
|
||||||
|
an alternative to Helm chart generation :smile:
|
||||||
|
|
||||||
|
The project is focused on Kubernetes manifests and proposes to use "Kustomize" to adapt the manifests. Helm seems to be
|
||||||
|
not the priority.
|
||||||
|
|
||||||
|
Anyway, before this decision, the Helm chart generation was not what we expected. We wanted to have a more complete
|
||||||
|
chart, with more options and more flexibility.
|
||||||
|
|
||||||
|
> That's why we decided to create Katenary.
|
||||||
|
|
||||||
|
Kompose didn't manage to generate a values file, complex volume binding, and many other things. It was also not able
|
||||||
|
to manage dependencies between services.
|
||||||
|
|
||||||
|
> Be sure that we don't want to compete with Kompose. We just want to propose a different approach to the problem.
|
||||||
|
|
||||||
|
Kompose is an excellent tool, and we use it in some projects. It's a good choice if you want to convert
|
||||||
|
your `docker-compose` files to Kubernetes manifests, but if you want to use Helm, Katenary is the tool you need.
|
||||||
|
|
||||||
|
## Why not using "one label" for all the configuration?
|
||||||
|
|
||||||
|
That was a discussion I had with my colleagues. The idea was to use a single label to store all the configuration.
|
||||||
|
But, it's not a good idea.
|
||||||
|
|
||||||
|
Sometimes, you will have a long list of things to configure, like ports, ingress, dependencies, etc. It's better to have
|
||||||
|
a clear and readable configuration. Segmented labels are easier to read and to maintain. It also avoids having too
|
||||||
|
many indentation levels in the YAML file.
|
||||||
|
|
||||||
|
It is also more flexible. You can add or remove labels without changing the others.
|
||||||
|
|
||||||
|
## Why not using a configuration file?
|
||||||
|
|
||||||
|
The idea was to keep the configuration at a same place, and using the go-compose library to read the labels. It's
|
||||||
|
easier to have a single file to manage.
|
||||||
|
|
||||||
|
By the way, Katenary auto accepts a `compose.katenary.yaml` file in the same directory. It's a way to separate the
|
||||||
|
configuration from the compose file. It uses
|
||||||
|
the [overrides' mechanism](https://docs.docker.com/compose/multiple-compose-files/merge/) like "compose" does.
|
||||||
|
|
||||||
|
## Why not developing with Rust?
|
||||||
|
|
||||||
|
Seriously...
|
||||||
|
|
||||||
|
OK, I will answer.
|
||||||
|
|
||||||
|
Rust is a good language. But, Podman, Docker, Kubernetes, Helm, and mostly all technologies around Kubernetes are
|
||||||
|
written in Go. We have a large ecosystem in Go to manipulate, read, and write Kubernetes manifests as parsing
|
||||||
|
Compose files.
|
||||||
|
|
||||||
|
> Go is better for this task.
|
||||||
|
|
||||||
|
There is no reason to use Rust for this project.
|
||||||
|
|
||||||
|
## Any chance to have a GUI?
|
||||||
|
|
||||||
|
Yes, it's a possibility. But, it's not a priority. We have a lot of things to do before. We need to stabilize the
|
||||||
|
project, to have a good documentation, to have a good test coverage, and to have a good community.
|
||||||
|
|
||||||
|
But, in a not so far future, we could have a GUI. The choice of [Fyne.io](https://fyne.io) is already made, and we
|
||||||
|
tested some concepts.
|
||||||
|
|
||||||
|
## I'm rich (or not), I want to help you. How can I do?
|
||||||
|
|
||||||
|
You can help us in many ways.
|
||||||
|
|
||||||
|
- The first things we really need, more than money, more than anything else, is to have feedback. If you use Katenary,
|
||||||
|
if you have some issues, if you have some ideas, please open an issue on the [GitHub repository](https://github.com/Katenary/katenary).
|
||||||
|
- The second thing is to help us to fix issues. If you're a Go developer, or if you want to fix the documentation,
|
||||||
|
your help is greatly appreciated.
|
||||||
|
- And then, of course, we need money, or sponsors.
|
||||||
|
|
||||||
|
### If you're a company
|
||||||
|
|
||||||
|
We will be happy to communicate your help by putting your logo on the website and in the documentation. You can sponsor
|
||||||
|
us by giving us some money, or by giving us some time of your developers, or leaving us some time to work on the project.
|
||||||
|
|
||||||
|
### If you're an individual
|
||||||
|
|
||||||
|
All donators will be listed on the website and in the documentation. You can give us some money by using
|
||||||
|
the [GitHub Sponsors]()
|
||||||
|
|
||||||
|
All main contributors[^3] will be listed on the website and in the documentation.
|
||||||
|
|
||||||
|
> If you want to be anonymous, please tell us.
|
||||||
|
|
||||||
|
[^3]:
|
||||||
|
Main contributors are the people who have made a significant contribution to the project. It could be code,
|
||||||
|
documentation, or any other help. There is no defined rules, at this time, to evaluate the contribution.
|
||||||
|
It's a subjective decision.
|
162
doc/docs/index.md
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
<div class="md-center">
|
||||||
|

|
||||||
|
</div>
|
||||||
|
|
||||||
|
# Welcome to Katenary documentation
|
||||||
|
|
||||||
|
🚀 Unleash Productivity with Katenary! 🚀
|
||||||
|
|
||||||
|
Tired of manual conversions? Katenary harnesses the labels from your "compose" file to craft complete Helm Charts
|
||||||
|
effortlessly, saving you time and energy.
|
||||||
|
|
||||||
|
🛠️ Simple automated CLI: Katenary handles the grunt work, generating everything needed for seamless service binding
|
||||||
|
and Helm Chart creation.
|
||||||
|
|
||||||
|
💡 Effortless Efficiency: You only need to add labels when it's necessary to precise things. Then call `katenary convert`
|
||||||
|
and let the magic happen.
|
||||||
|
|
||||||
|
<div style="margin: auto" class="zoomable">
|
||||||
|

|
||||||
|
</div>
|
||||||
|
|
||||||
|
# What is it?
|
||||||
|
|
||||||
|
Katenary is a tool made to help you to transform "compose" files (`compose.yaml`, `docker-compose.yml`,
|
||||||
|
`podman-compose.yml`...) to complete and production ready [Helm Chart](https://helm.sh).
|
||||||
|
|
||||||
|
You'll be able to deploy your project in [:material-kubernetes: Kubernetes](https://kubernetes.io) in a few seconds
|
||||||
|
(of course, more if you need to tweak with labels).
|
||||||
|
|
||||||
|
It uses your current file and optionally labels to configure the result.
|
||||||
|
|
||||||
|
It's an open source project, under MIT license, originally partially developed at [Smile](https://www.smile.eu).
|
||||||
|
|
||||||
|
Today, it's partially developed in collaboration with [Klee Group](https://www.kleegroup.com). Note that Katenary is
|
||||||
|
and **will stay an open source and free (as freedom) project**. We are convinced that the best way to make it better is to
|
||||||
|
share it with the community.
|
||||||
|
|
||||||
|
<div id="klee">
|
||||||
|

|
||||||
|
</div>
|
||||||
|
|
||||||
|
The main developer is [Patrice FERLET](https://github.com/metal3d).
|
||||||
|
|
||||||
|
The project source
|
||||||
|
code is hosted on the [:fontawesome-brands-github: Katenary GitHub Repository](https://github.com/Katenary/katenary).
|
||||||
|
|
||||||
|
## Install Katenary
|
||||||
|
|
||||||
|
Katenary is developed using the :fontawesome-brands-golang:{ .gopher } [Go](https://go.dev) language.
|
||||||
|
The binary is statically linked, so you can simply download it from the [release
|
||||||
|
page](https://github.com/Katenary/katenary/releases) of the project in GitHub.
|
||||||
|
|
||||||
|
You need to select the right binary for your operating system and architecture, and copy the binary in a directory
|
||||||
|
that is in your `PATH`.
|
||||||
|
|
||||||
|
If you are a Linux user, you can use the "one line installation command" which will download the binary in your
|
||||||
|
`$HOME/.local/bin` directory if it exists.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sh <(curl -sSL https://raw.githubusercontent.com/Katenary/katenary/master/install.sh)
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! Info "Upgrading is integrated to the `katenary` command"
|
||||||
|
Katenary propose a `upgrade` sub-command to update the current binary to the latest stable release.
|
||||||
|
|
||||||
|
Of course, you need to install Katenary once :smile:
|
||||||
|
|
||||||
|
!!! Note "You prefer to compile it, no need to install Go"
|
||||||
|
You can also build and install it yourself, the provided Makefile has got a `build` command that uses `podman` or
|
||||||
|
`docker` to build the binary.
|
||||||
|
|
||||||
|
So, you don't need to install Go compiler :+1:.
|
||||||
|
|
||||||
|
But, note that the "master" branch is not the "stable" version. It's preferable to switch to a tag, or to use the
|
||||||
|
releases.
|
||||||
|
|
||||||
|
To compile it, you can use the following commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/Katenary/katenary.git
|
||||||
|
cd katenary
|
||||||
|
make build
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
`make install` copies `./katenary` binary to your user binary path (`~/.local/bin`)
|
||||||
|
|
||||||
|
You can install it in other directory by changing the `PREFIX` variable. E.g.:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build
|
||||||
|
sudo make install PREFIX=/usr/local
|
||||||
|
```
|
||||||
|
|
||||||
|
Check if everything is OK using `katenary version` and / or `katenary help`
|
||||||
|
|
||||||
|
## Install completion
|
||||||
|
|
||||||
|
Katenary uses the very nice project named `cobra` to manage flags, argument and auto-completion.
|
||||||
|
|
||||||
|
You can activate it with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# replace "bash" by "zsh" if needed
|
||||||
|
source <(katenary completion bash)
|
||||||
|
```
|
||||||
|
|
||||||
|
Add this line in you `~/.profile`, `~/.bash_aliases` or `~/.bashrc` file to have completion at startup.
|
||||||
|
|
||||||
|
## What a name
|
||||||
|
|
||||||
|
A catenary is the curve that a hanging chain or cable assumes under its own weight when supported only at its ends.
|
||||||
|
I, the maintainer, decided to name "Katenary" this project because it's like a chain that links a boat to a dock.
|
||||||
|
Making the link between the "compose" world and the "Kubernetes" world is the main goal of this project.
|
||||||
|
|
||||||
|
Anyway, it's too late to change the name now :smile:
|
||||||
|
|
||||||
|
!!! Note "But I like this name!"
|
||||||
|
|
||||||
|
I spent time to find it :wink:
|
||||||
|
|
||||||
|
## Special thanks to
|
||||||
|
|
||||||
|
I really want to thank all the contributors, testers, and of course, the authors of the packages and tools that are used
|
||||||
|
in this project. There is too many to list here. Katenary can work because of all these people. Open source is a great
|
||||||
|
thing! :heart:
|
||||||
|
|
||||||
|
!!! Edit "Special thanks"
|
||||||
|
|
||||||
|
**Katenary is built with:** <br />
|
||||||
|
|
||||||
|
<a href="https://go.dev" target="_blank">:fontawesome-brands-golang:{ .go-logo }</a>
|
||||||
|
|
||||||
|
Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.
|
||||||
|
Because Docker, Podman, Kubernetes, and Helm are written in Go, Katenary is also written in Go and borrows packages
|
||||||
|
from these projects to make it as efficient as possible.
|
||||||
|
|
||||||
|
Thanks to Kubernetes to provide [Kind](https://kind.sigs.k8s.io) that is used to test Katenary locally.
|
||||||
|
|
||||||
|
**Thanks to everyone who contributes to all these projects.**
|
||||||
|
|
||||||
|
Katenary can progress because of all these people. All contributions, as comments, issues, pull requests and
|
||||||
|
feedbacks are welcome.
|
||||||
|
|
||||||
|
**Everything was also possible because of:** <br />
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://helm.sh" target="_blank"><img src="https://helm.sh/img/helm.svg" style="height: 1rem"/>
|
||||||
|
Helm</a> that is the main toppic of Katenary, Kubernetes is easier to use with it.</li>
|
||||||
|
<li><a href="https://cobra.dev/"><img src="https://cobra.dev/home/logo.png" style="height: 1rem"/> Cobra</a> that
|
||||||
|
makes command, subcommand and completion possible for Katenary with ease.</li>
|
||||||
|
<li>Podman, Docker, Kubernetes that are the main tools that Katenary is made for.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
**Documentation is built with:** <br />
|
||||||
|
|
||||||
|
<a href="https://www.mkdocs.org/" target="_blank">MkDocs</a> using <a
|
||||||
|
href="https://squidfunk.github.io/mkdocs-material/" target="_blank">Material for MkDocs</a> theme template.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Katenary is an open source project under the MIT license. You can use it, modify it, and distribute it as you want.
|
489
doc/docs/labels.md
Normal file
@@ -0,0 +1,489 @@
|
|||||||
|
# Labels documentation
|
||||||
|
|
||||||
|
Katenary proposes labels to set in `compose.yaml` files (or override files) to configure the Helm Chart generation.
|
||||||
|
Because it is sometimes needed to have structured values, it is necessary to use the YAML syntax.
|
||||||
|
While compose labels are string, we can use _here-doc_ syntax using `|` to use YAML multiline as value.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
label-name: |-
|
||||||
|
# this is actually a multiline string here
|
||||||
|
key1: value1
|
||||||
|
key2: value2
|
||||||
|
```
|
||||||
|
|
||||||
|
Katenary will try to _Unmarshal_ these labels.
|
||||||
|
|
||||||
|
## Label list and types
|
||||||
|
|
||||||
|
<!-- START_LABEL_DOC : do not remove this tag !-->
|
||||||
|
| Label name | Description | Type |
|
||||||
|
| ------------------------------ | ---------------------------------------------------------------- | -------------------------------- |
|
||||||
|
| `katenary.v3/configmap-files` | Inject files as Configmap. | `[]string` |
|
||||||
|
| `katenary.v3/cronjob` | Create a cronjob from the service. | `object` |
|
||||||
|
| `katenary.v3/dependencies` | Add Helm dependencies to the service. | `[]object` |
|
||||||
|
| `katenary.v3/description` | Description of the service | `string` |
|
||||||
|
| `katenary.v3/env-from` | Add environment variables from another service. | `[]string` |
|
||||||
|
| `katenary.v3/exchange-volumes` | Add exchange volumes (empty directory on the node) to share data | `[]object` |
|
||||||
|
| `katenary.v3/health-check` | Health check to be added to the deployment. | `object` |
|
||||||
|
| `katenary.v3/ignore` | Ignore the service | `bool` |
|
||||||
|
| `katenary.v3/ingress` | Ingress rules to be added to the service. | `object` |
|
||||||
|
| `katenary.v3/main-app` | Mark the service as the main app. | `bool` |
|
||||||
|
| `katenary.v3/map-env` | Map env vars from the service to the deployment. | `map[string]string` |
|
||||||
|
| `katenary.v3/ports` | Ports to be added to the service. | `[]uint32` |
|
||||||
|
| `katenary.v3/same-pod` | Move the same-pod deployment to the target deployment. | `string` |
|
||||||
|
| `katenary.v3/secrets` | Env vars to be set as secrets. | `[]string` |
|
||||||
|
| `katenary.v3/values` | Environment variables to be added to the values.yaml | `[]string or map[string]string` |
|
||||||
|
| `katenary.v3/values-from` | Add values from another service. | `map[string]string` |
|
||||||
|
|
||||||
|
<!-- STOP_LABEL_DOC : do not remove this tag !-->
|
||||||
|
|
||||||
|
## Detailed description
|
||||||
|
|
||||||
|
<!-- START_DETAILED_DOC : do not remove this tag !-->
|
||||||
|
### katenary.v3/configmap-files
|
||||||
|
|
||||||
|
Inject files as Configmap.
|
||||||
|
|
||||||
|
**Type**: `[]string`
|
||||||
|
|
||||||
|
It makes a file or directory to be converted to one or more ConfigMaps
|
||||||
|
and mounted in the pod. The file or directory is relative to the
|
||||||
|
service directory.
|
||||||
|
|
||||||
|
If it is a directory, all files inside it are added to the ConfigMap.
|
||||||
|
|
||||||
|
If the directory as subdirectories, so one configmap per subpath are created.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
It is not intended to be used to store an entire project in configmaps.
|
||||||
|
It is intended to be used to store configuration files that are not managed
|
||||||
|
by the application, like nginx configuration files. Keep in mind that your
|
||||||
|
project sources should be stored in an application image or in a storage.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
volumes
|
||||||
|
- ./conf.d:/etc/nginx/conf.d
|
||||||
|
labels:
|
||||||
|
katenary.v3/configmap-files: |-
|
||||||
|
- ./conf.d
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/cronjob
|
||||||
|
|
||||||
|
Create a cronjob from the service.
|
||||||
|
|
||||||
|
**Type**: `object`
|
||||||
|
|
||||||
|
This adds a cronjob to the chart.
|
||||||
|
|
||||||
|
The label value is a YAML object with the following attributes:
|
||||||
|
- command: the command to be executed
|
||||||
|
- schedule: the cron schedule (cron format or @every where "every" is a
|
||||||
|
duration like 1h30m, daily, hourly...)
|
||||||
|
- rbac: false (optionnal), if true, it will create a role, a rolebinding and
|
||||||
|
a serviceaccount to make your cronjob able to connect the Kubernetes API
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
katenary.v3/cronjob: |-
|
||||||
|
command: echo "hello world"
|
||||||
|
schedule: "* */1 * * *" # or @hourly for example
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/dependencies
|
||||||
|
|
||||||
|
Add Helm dependencies to the service.
|
||||||
|
|
||||||
|
**Type**: `[]object`
|
||||||
|
|
||||||
|
Set the service to be, actually, a Helm dependency. This means that the
|
||||||
|
service will not be exported as template. The dependencies are added to
|
||||||
|
the Chart.yaml file and the values are added to the values.yaml file.
|
||||||
|
|
||||||
|
It's a list of objects with the following attributes:
|
||||||
|
|
||||||
|
- name: the name of the dependency
|
||||||
|
- repository: the repository of the dependency
|
||||||
|
- alias: the name of the dependency in values.yaml (optional)
|
||||||
|
- values: the values to be set in values.yaml (optional)
|
||||||
|
|
||||||
|
!!! Info
|
||||||
|
Katenary doesn't update the helm depenedencies by default.
|
||||||
|
|
||||||
|
Use `--helm-update` (or `-u`) flag to update the dependencies.
|
||||||
|
|
||||||
|
example: <code>katenary convert -u</code>
|
||||||
|
|
||||||
|
By setting an alias, it is possible to change the name of the dependency
|
||||||
|
in values.yaml.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
katenary.v3/dependencies: |-
|
||||||
|
- name: mariadb
|
||||||
|
repository: oci://registry-1.docker.io/bitnamicharts
|
||||||
|
|
||||||
|
## optional, it changes the name of the section in values.yaml
|
||||||
|
# alias: mydatabase
|
||||||
|
|
||||||
|
## optional, it adds the values to values.yaml
|
||||||
|
values:
|
||||||
|
auth:
|
||||||
|
database: mydatabasename
|
||||||
|
username: myuser
|
||||||
|
password: the secret password
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/description
|
||||||
|
|
||||||
|
Description of the service
|
||||||
|
|
||||||
|
**Type**: `string`
|
||||||
|
|
||||||
|
This replaces the default comment in values.yaml file to the given description.
|
||||||
|
It is useful to document the service and configuration.
|
||||||
|
|
||||||
|
The value can be set with a documentation in multiline format.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
katenary.v3/description: |-
|
||||||
|
This is a description of the service.
|
||||||
|
It can be multiline.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/env-from
|
||||||
|
|
||||||
|
Add environment variables from another service.
|
||||||
|
|
||||||
|
**Type**: `[]string`
|
||||||
|
|
||||||
|
It adds environment variables from another service to the current service.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
service1:
|
||||||
|
image: nginx:1.19
|
||||||
|
environment:
|
||||||
|
FOO: bar
|
||||||
|
|
||||||
|
service2:
|
||||||
|
image: php:7.4-fpm
|
||||||
|
labels:
|
||||||
|
# get the congigMap from service1 where FOO is
|
||||||
|
# defined inside this service too
|
||||||
|
katenary.v3/env-from: |-
|
||||||
|
- myservice1
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/exchange-volumes
|
||||||
|
|
||||||
|
Add exchange volumes (empty directory on the node) to share data
|
||||||
|
|
||||||
|
**Type**: `[]object`
|
||||||
|
|
||||||
|
This label allows sharing data between containres. The volume is created in
|
||||||
|
the node and mounted in the pod. It is useful to share data between containers
|
||||||
|
in a "same pod" logic. For example to let PHP-FPM and Nginx share the same direcotory.
|
||||||
|
|
||||||
|
This will create:
|
||||||
|
|
||||||
|
- an `emptyDir` volume in the deployment
|
||||||
|
- a `voumeMount` in the pod for **each container**
|
||||||
|
- a `initContainer` for each definition
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
- name: the name of the volume (manadatory)
|
||||||
|
- mountPath: the path where the volume is mounted in the pod (optional, default is `/opt`)
|
||||||
|
- init: a command to run to initialize the volume with data (optional)
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is highly experimental. This is mainly useful when using the "same-pod" label.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
nginx:
|
||||||
|
# ...
|
||||||
|
labels;
|
||||||
|
katenary.v3/exchange-volumes: |-
|
||||||
|
- name: php-fpm
|
||||||
|
mountPath: /var/www/html
|
||||||
|
php:
|
||||||
|
# ...
|
||||||
|
labels:
|
||||||
|
katenary.v3/exchange-volumes: |-
|
||||||
|
- name: php-fpm
|
||||||
|
mountPath: /opt
|
||||||
|
init: cp -ra /var/www/html/* /opt
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/health-check
|
||||||
|
|
||||||
|
Health check to be added to the deployment.
|
||||||
|
|
||||||
|
**Type**: `object`
|
||||||
|
|
||||||
|
Health check to be added to the deployment.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
katenary.v3/health-check: |-
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/ignore
|
||||||
|
|
||||||
|
Ignore the service
|
||||||
|
|
||||||
|
**Type**: `bool`
|
||||||
|
|
||||||
|
Ingoring a service to not be exported in helm chart.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
katenary.v3/ignore: "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/ingress
|
||||||
|
|
||||||
|
Ingress rules to be added to the service.
|
||||||
|
|
||||||
|
**Type**: `object`
|
||||||
|
|
||||||
|
Declare an ingress rule for the service. The port should be exposed or
|
||||||
|
declared with `katenary.v3/ports`.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
katenary.v3/ingress: |-
|
||||||
|
port: 80
|
||||||
|
hostname: mywebsite.com (optional)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/main-app
|
||||||
|
|
||||||
|
Mark the service as the main app.
|
||||||
|
|
||||||
|
**Type**: `bool`
|
||||||
|
|
||||||
|
This makes the service to be the main application. Its image tag is
|
||||||
|
considered to be the Chart appVersion and to be the defaultvalue in Pod
|
||||||
|
container image attribute.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This label cannot be repeated in others services. If this label is
|
||||||
|
set in more than one service as true, Katenary will return an error.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ghost:
|
||||||
|
image: ghost:1.25.5
|
||||||
|
labels:
|
||||||
|
# The chart is now named ghost, and the appVersion is 1.25.5.
|
||||||
|
# In Deployment, the image attribute is set to ghost:1.25.5 if
|
||||||
|
# you don't change the "tag" attribute in values.yaml
|
||||||
|
katenary.v3/main-app: true
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/map-env
|
||||||
|
|
||||||
|
Map env vars from the service to the deployment.
|
||||||
|
|
||||||
|
**Type**: `map[string]string`
|
||||||
|
|
||||||
|
Because you may need to change the variable for Kubernetes, this label
|
||||||
|
forces the value to another. It is also particullary helpful to use a template
|
||||||
|
value instead. For example, you could bind the value to a service name
|
||||||
|
with Helm attributes:
|
||||||
|
`{{ tpl .Release.Name . }}`.
|
||||||
|
|
||||||
|
If you use `__APP__` in the value, it will be replaced by the Chart name.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
env:
|
||||||
|
DB_HOST: database
|
||||||
|
RUNNING: docker
|
||||||
|
OTHER: value
|
||||||
|
labels:
|
||||||
|
katenary.v3/map-env: |-
|
||||||
|
RUNNING: kubernetes
|
||||||
|
DB_HOST: '{{ include "__APP__.fullname" . }}-database'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/ports
|
||||||
|
|
||||||
|
Ports to be added to the service.
|
||||||
|
|
||||||
|
**Type**: `[]uint32`
|
||||||
|
|
||||||
|
Only useful for services without exposed port. It is mandatory if the
|
||||||
|
service is a dependency of another service.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
katenary.v3/ports: |-
|
||||||
|
- 8080
|
||||||
|
- 8081
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/same-pod
|
||||||
|
|
||||||
|
Move the same-pod deployment to the target deployment.
|
||||||
|
|
||||||
|
**Type**: `string`
|
||||||
|
|
||||||
|
This will make the service to be included in another service pod. Some services
|
||||||
|
must work together in the same pod, like a sidecar or a proxy or nginx + php-fpm.
|
||||||
|
|
||||||
|
Note that volume and VolumeMount are copied from the source to the target
|
||||||
|
deployment.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
web:
|
||||||
|
image: nginx:1.19
|
||||||
|
|
||||||
|
php:
|
||||||
|
image: php:7.4-fpm
|
||||||
|
labels:
|
||||||
|
katenary.v3/same-pod: web
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/secrets
|
||||||
|
|
||||||
|
Env vars to be set as secrets.
|
||||||
|
|
||||||
|
**Type**: `[]string`
|
||||||
|
|
||||||
|
This label allows setting the environment variables as secrets. The variable
|
||||||
|
is removed from the environment and added to a secret object.
|
||||||
|
|
||||||
|
The variable can be set to the `katenary.v3/values` too,
|
||||||
|
so the secret value can be configured in values.yaml
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
env:
|
||||||
|
PASSWORD: a very secret password
|
||||||
|
NOT_A_SECRET: a public value
|
||||||
|
labels:
|
||||||
|
katenary.v3/secrets: |-
|
||||||
|
- PASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/values
|
||||||
|
|
||||||
|
Environment variables to be added to the values.yaml
|
||||||
|
|
||||||
|
**Type**: `[]string or map[string]string`
|
||||||
|
|
||||||
|
By default, all environment variables in the "env" and environment
|
||||||
|
files are added to configmaps with the static values set. This label
|
||||||
|
allows adding environment variables to the values.yaml file.
|
||||||
|
|
||||||
|
Note that the value inside the configmap is `{{ tpl vaname . }}`, so
|
||||||
|
you can set the value to a template that will be rendered with the
|
||||||
|
values.yaml file.
|
||||||
|
|
||||||
|
The value can be set with a documentation. This may help to understand
|
||||||
|
the purpose of the variable.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
env:
|
||||||
|
FOO: bar
|
||||||
|
DB_NAME: mydb
|
||||||
|
TO_CONFIGURE: something that can be changed in values.yaml
|
||||||
|
A_COMPLEX_VALUE: example
|
||||||
|
labels:
|
||||||
|
katenary.v3/values: |-
|
||||||
|
# simple values, set as is in values.yaml
|
||||||
|
- TO_CONFIGURE
|
||||||
|
# complex values, set as a template in values.yaml with a documentation
|
||||||
|
- A_COMPLEX_VALUE: |-
|
||||||
|
This is the documentation for the variable to
|
||||||
|
configure in values.yaml.
|
||||||
|
It can be, of course, a multiline text.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### katenary.v3/values-from
|
||||||
|
|
||||||
|
Add values from another service.
|
||||||
|
|
||||||
|
**Type**: `map[string]string`
|
||||||
|
|
||||||
|
This label allows adding values from another service to the current service.
|
||||||
|
It avoid duplicating values, environment or secrets that should be the same.
|
||||||
|
|
||||||
|
The key is the value to be added, and the value is the "key" to fetch in the
|
||||||
|
form `service_name.environment_name`.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
database:
|
||||||
|
image: mariadb:10.5
|
||||||
|
environment:
|
||||||
|
MARIADB_USER: myuser
|
||||||
|
MARIADB_PASSWORD: mypassword
|
||||||
|
labels:
|
||||||
|
# we can declare secrets
|
||||||
|
katenary.v3/secrets: |-
|
||||||
|
- MARIADB_PASSWORD
|
||||||
|
php:
|
||||||
|
image: php:7.4-fpm
|
||||||
|
environment:
|
||||||
|
# it's duplicated in docker / podman
|
||||||
|
DB_USER: myuser
|
||||||
|
DB_PASSWORD: mypassword
|
||||||
|
labels:
|
||||||
|
# removes the duplicated, use the configMap and secrets from "database"
|
||||||
|
katenary.v3/values-from: |-
|
||||||
|
DB_USER: database.MARIADB_USER
|
||||||
|
DB_PASSWORD: database.MARIADB_PASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
<!-- STOP_DETAILED_DOC : do not remove this tag !-->
|
12
doc/docs/packages/cmd/katenary.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||||
|
|
||||||
|
# katenary
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/katenary/katenary/cmd/katenary"
|
||||||
|
```
|
||||||
|
|
||||||
|
Katenary CLI, main package.
|
||||||
|
|
||||||
|
This package is not intended to be imported. It contains the main function that build the command line with \`cobra\` package.
|
||||||
|
|
923
doc/docs/packages/internal/generator.md
Normal file
@@ -0,0 +1,923 @@
|
|||||||
|
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||||
|
|
||||||
|
# generator
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/katenary/katenary/internal/generator"
|
||||||
|
```
|
||||||
|
|
||||||
|
Package generator generates kubernetes objects from a "compose" file and transforms them into a helm chart.
|
||||||
|
|
||||||
|
The generator package is the core of katenary. It is responsible for generating kubernetes objects from a compose file and transforming them into a helm chart. Conversion manipulates Yaml representation of kubernetes object to add conditions, labels, annotations, etc. to the objects. It also create the values to be set to the values.yaml file.
|
||||||
|
|
||||||
|
The generate.Convert\(\) create an HelmChart object and call "Generate\(\)" method to convert from a compose file to a helm chart. It saves the helm chart in the given directory.
|
||||||
|
|
||||||
|
If you want to change or override the write behavior, you can use the HelmChart.Generate\(\) function and implement your own write function. This function returns the helm chart object containing all kubernetes objects and helm chart ingormation. It does not write the helm chart to the disk.
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
<a name="Annotations"></a>
|
||||||
|
|
||||||
|
```go
|
||||||
|
var (
|
||||||
|
|
||||||
|
// Standard annotationss
|
||||||
|
Annotations = map[string]string{
|
||||||
|
labels.LabelName("version"): Version,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="Version"></a>Version is the version of katenary. It is set at compile time.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var Version = "master" // changed at compile time
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="Convert"></a>
|
||||||
|
## func [Convert](<https://github.com/katenary/katenary/blob/master/internal/generator/converter.go#L100>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Convert(config ConvertOptions, dockerComposeFile ...string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
Convert a compose \(docker, podman...\) project to a helm chart. It calls Generate\(\) to generate the chart and then write it to the disk.
|
||||||
|
|
||||||
|
<a name="GetLabels"></a>
|
||||||
|
## func [GetLabels](<https://github.com/katenary/katenary/blob/master/internal/generator/labels.go#L12>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetLabels(serviceName, appName string) map[string]string
|
||||||
|
```
|
||||||
|
|
||||||
|
GetLabels returns the labels for a service. It uses the appName to replace the \_\_replace\_\_ in the labels. This is used to generate the labels in the templates.
|
||||||
|
|
||||||
|
<a name="GetMatchLabels"></a>
|
||||||
|
## func [GetMatchLabels](<https://github.com/katenary/katenary/blob/master/internal/generator/labels.go#L25>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetMatchLabels(serviceName, appName string) map[string]string
|
||||||
|
```
|
||||||
|
|
||||||
|
GetMatchLabels returns the matchLabels for a service. It uses the appName to replace the \_\_replace\_\_ in the labels. This is used to generate the matchLabels in the templates.
|
||||||
|
|
||||||
|
<a name="GetVersion"></a>
|
||||||
|
## func [GetVersion](<https://github.com/katenary/katenary/blob/master/internal/generator/version.go#L14>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetVersion() string
|
||||||
|
```
|
||||||
|
|
||||||
|
GetVersion return the version of katneary. It's important to understand that the version is set at compile time for the github release. But, it the user get katneary using \`go install\`, the version should be different.
|
||||||
|
|
||||||
|
<a name="Helper"></a>
|
||||||
|
## func [Helper](<https://github.com/katenary/katenary/blob/master/internal/generator/helper.go#L15>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Helper(name string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
Helper returns the \_helpers.tpl file for a chart.
|
||||||
|
|
||||||
|
<a name="NewCronJob"></a>
|
||||||
|
## func [NewCronJob](<https://github.com/katenary/katenary/blob/master/internal/generator/cronJob.go#L28>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewCronJob(service types.ServiceConfig, chart *HelmChart, appName string) (*CronJob, *RBAC)
|
||||||
|
```
|
||||||
|
|
||||||
|
NewCronJob creates a new CronJob from a compose service. The appName is the name of the application taken from the project name.
|
||||||
|
|
||||||
|
<a name="ToK8SYaml"></a>
|
||||||
|
## func [ToK8SYaml](<https://github.com/katenary/katenary/blob/master/internal/generator/utils.go#L91>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ToK8SYaml(obj any) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="UnWrapTPL"></a>
|
||||||
|
## func [UnWrapTPL](<https://github.com/katenary/katenary/blob/master/internal/generator/utils.go#L87>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func UnWrapTPL(in []byte) []byte
|
||||||
|
```
|
||||||
|
|
||||||
|
UnWrapTPL removes the line wrapping from a template.
|
||||||
|
|
||||||
|
<a name="ChartTemplate"></a>
|
||||||
|
## type [ChartTemplate](<https://github.com/katenary/katenary/blob/master/internal/generator/chart.go#L22-L25>)
|
||||||
|
|
||||||
|
ChartTemplate is a template of a chart. It contains the content of the template and the name of the service. This is used internally to generate the templates.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ChartTemplate struct {
|
||||||
|
Servicename string
|
||||||
|
Content []byte
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="ConfigMap"></a>
|
||||||
|
## type [ConfigMap](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L37-L42>)
|
||||||
|
|
||||||
|
ConfigMap is a kubernetes ConfigMap. Implements the DataMap interface.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ConfigMap struct {
|
||||||
|
*corev1.ConfigMap
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="NewConfigMap"></a>
|
||||||
|
### func [NewConfigMap](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L46>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewConfigMap(service types.ServiceConfig, appName string, forFile bool) *ConfigMap
|
||||||
|
```
|
||||||
|
|
||||||
|
NewConfigMap creates a new ConfigMap from a compose service. The appName is the name of the application taken from the project name. The ConfigMap is filled by environment variables and labels "map\-env".
|
||||||
|
|
||||||
|
<a name="NewConfigMapFromDirectory"></a>
|
||||||
|
### func [NewConfigMapFromDirectory](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L119>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewConfigMapFromDirectory(service types.ServiceConfig, appName, path string) *ConfigMap
|
||||||
|
```
|
||||||
|
|
||||||
|
NewConfigMapFromDirectory creates a new ConfigMap from a compose service. This path is the path to the file or directory. If the path is a directory, all files in the directory are added to the ConfigMap. Each subdirectory are ignored. Note that the Generate\(\) function will create the subdirectories ConfigMaps.
|
||||||
|
|
||||||
|
<a name="ConfigMap.AddBinaryData"></a>
|
||||||
|
### func \(\*ConfigMap\) [AddBinaryData](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L157>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *ConfigMap) AddBinaryData(key string, value []byte)
|
||||||
|
```
|
||||||
|
|
||||||
|
AddBinaryData adds binary data to the configmap. Append or overwrite the value if the key already exists.
|
||||||
|
|
||||||
|
<a name="ConfigMap.AddData"></a>
|
||||||
|
### func \(\*ConfigMap\) [AddData](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L152>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *ConfigMap) AddData(key, value string)
|
||||||
|
```
|
||||||
|
|
||||||
|
AddData adds a key value pair to the configmap. Append or overwrite the value if the key already exists.
|
||||||
|
|
||||||
|
<a name="ConfigMap.AppendDir"></a>
|
||||||
|
### func \(\*ConfigMap\) [AppendDir](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L166>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *ConfigMap) AppendDir(path string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
AppendDir adds files from given path to the configmap. It is not recursive, to add all files in a directory, you need to call this function for each subdirectory.
|
||||||
|
|
||||||
|
<a name="ConfigMap.AppendFile"></a>
|
||||||
|
### func \(\*ConfigMap\) [AppendFile](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L213>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *ConfigMap) AppendFile(path string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="ConfigMap.Filename"></a>
|
||||||
|
### func \(\*ConfigMap\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L237>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *ConfigMap) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
Filename returns the filename of the configmap. If the configmap is used for files, the filename contains the path.
|
||||||
|
|
||||||
|
<a name="ConfigMap.SetData"></a>
|
||||||
|
### func \(\*ConfigMap\) [SetData](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L247>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *ConfigMap) SetData(data map[string]string)
|
||||||
|
```
|
||||||
|
|
||||||
|
SetData sets the data of the configmap. It replaces the entire data.
|
||||||
|
|
||||||
|
<a name="ConfigMap.Yaml"></a>
|
||||||
|
### func \(\*ConfigMap\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L252>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *ConfigMap) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Yaml returns the yaml representation of the configmap
|
||||||
|
|
||||||
|
<a name="ConfigMapMount"></a>
|
||||||
|
## type [ConfigMapMount](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L28-L31>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ConfigMapMount struct {
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="ConvertOptions"></a>
|
||||||
|
## type [ConvertOptions](<https://github.com/katenary/katenary/blob/master/internal/generator/chart.go#L28-L37>)
|
||||||
|
|
||||||
|
ConvertOptions are the options to convert a compose project to a helm chart.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ConvertOptions struct {
|
||||||
|
AppVersion *string
|
||||||
|
OutputDir string
|
||||||
|
ChartVersion string
|
||||||
|
Icon string
|
||||||
|
Profiles []string
|
||||||
|
EnvFiles []string
|
||||||
|
Force bool
|
||||||
|
HelmUpdate bool
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="CronJob"></a>
|
||||||
|
## type [CronJob](<https://github.com/katenary/katenary/blob/master/internal/generator/cronJob.go#L22-L25>)
|
||||||
|
|
||||||
|
CronJob is a kubernetes CronJob.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type CronJob struct {
|
||||||
|
*batchv1.CronJob
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="CronJob.Filename"></a>
|
||||||
|
### func \(\*CronJob\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/cronJob.go#L114>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *CronJob) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
Filename returns the filename of the cronjob.
|
||||||
|
|
||||||
|
Implements the Yaml interface.
|
||||||
|
|
||||||
|
<a name="CronJob.Yaml"></a>
|
||||||
|
### func \(\*CronJob\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/cronJob.go#L121>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (c *CronJob) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Yaml returns the yaml representation of the cronjob.
|
||||||
|
|
||||||
|
Implements the Yaml interface.
|
||||||
|
|
||||||
|
<a name="CronJobValue"></a>
|
||||||
|
## type [CronJobValue](<https://github.com/katenary/katenary/blob/master/internal/generator/values.go#L118-L123>)
|
||||||
|
|
||||||
|
CronJobValue is a cronjob configuration that will be saved in values.yaml.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type CronJobValue struct {
|
||||||
|
Repository *RepositoryValue `yaml:"repository,omitempty"`
|
||||||
|
Environment map[string]any `yaml:"environment,omitempty"`
|
||||||
|
ImagePullPolicy string `yaml:"imagePullPolicy,omitempty"`
|
||||||
|
Schedule string `yaml:"schedule"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="DataMap"></a>
|
||||||
|
## type [DataMap](<https://github.com/katenary/katenary/blob/master/internal/generator/types.go#L4-L7>)
|
||||||
|
|
||||||
|
DataMap is a kubernetes ConfigMap or Secret. It can be used to add data to the ConfigMap or Secret.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type DataMap interface {
|
||||||
|
SetData(map[string]string)
|
||||||
|
AddData(string, string)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="Deployment"></a>
|
||||||
|
## type [Deployment](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L34-L44>)
|
||||||
|
|
||||||
|
Deployment is a kubernetes Deployment.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Deployment struct {
|
||||||
|
*appsv1.Deployment `yaml:",inline"`
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="NewDeployment"></a>
|
||||||
|
### func [NewDeployment](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L48>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewDeployment(service types.ServiceConfig, chart *HelmChart) *Deployment
|
||||||
|
```
|
||||||
|
|
||||||
|
NewDeployment creates a new Deployment from a compose service. The appName is the name of the application taken from the project name. It also creates the Values map that will be used to create the values.yaml file.
|
||||||
|
|
||||||
|
<a name="Deployment.AddContainer"></a>
|
||||||
|
### func \(\*Deployment\) [AddContainer](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L115>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) AddContainer(service types.ServiceConfig)
|
||||||
|
```
|
||||||
|
|
||||||
|
AddContainer adds a container to the deployment.
|
||||||
|
|
||||||
|
<a name="Deployment.AddHealthCheck"></a>
|
||||||
|
### func \(\*Deployment\) [AddHealthCheck](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L161>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) AddHealthCheck(service types.ServiceConfig, container *corev1.Container)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Deployment.AddIngress"></a>
|
||||||
|
### func \(\*Deployment\) [AddIngress](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L190>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) AddIngress(service types.ServiceConfig, appName string) *Ingress
|
||||||
|
```
|
||||||
|
|
||||||
|
AddIngress adds an ingress to the deployment. It creates the ingress object.
|
||||||
|
|
||||||
|
<a name="Deployment.AddLegacyVolume"></a>
|
||||||
|
### func \(\*Deployment\) [AddLegacyVolume](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L220>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) AddLegacyVolume(name, kind string)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Deployment.AddVolumes"></a>
|
||||||
|
### func \(\*Deployment\) [AddVolumes](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L196>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) AddVolumes(service types.ServiceConfig, appName string)
|
||||||
|
```
|
||||||
|
|
||||||
|
AddVolumes adds a volume to the deployment. It does not create the PVC, it only adds the volumes to the deployment. If the volume is a bind volume it will warn the user that it is not supported yet.
|
||||||
|
|
||||||
|
<a name="Deployment.BindFrom"></a>
|
||||||
|
### func \(\*Deployment\) [BindFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L241>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) BindFrom(service types.ServiceConfig, binded *Deployment)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Deployment.BindMapFilesToContainer"></a>
|
||||||
|
### func \(\*Deployment\) [BindMapFilesToContainer](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L375>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) BindMapFilesToContainer(service types.ServiceConfig, secrets []string, appName string) (*corev1.Container, int)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Deployment.DependsOn"></a>
|
||||||
|
### func \(\*Deployment\) [DependsOn](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L269>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) DependsOn(to *Deployment, servicename string) error
|
||||||
|
```
|
||||||
|
|
||||||
|
DependsOn adds a initContainer to the deployment that will wait for the service to be up.
|
||||||
|
|
||||||
|
<a name="Deployment.Filename"></a>
|
||||||
|
### func \(\*Deployment\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L300>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
Filename returns the filename of the deployment.
|
||||||
|
|
||||||
|
<a name="Deployment.MountExchangeVolumes"></a>
|
||||||
|
### func \(\*Deployment\) [MountExchangeVolumes](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L426>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) MountExchangeVolumes()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Deployment.SetEnvFrom"></a>
|
||||||
|
### func \(\*Deployment\) [SetEnvFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L305>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) SetEnvFrom(service types.ServiceConfig, appName string, samePod ...bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
SetEnvFrom sets the environment variables to a configmap. The configmap is created.
|
||||||
|
|
||||||
|
<a name="Deployment.Yaml"></a>
|
||||||
|
### func \(\*Deployment\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/deployment.go#L450>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (d *Deployment) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Yaml returns the yaml representation of the deployment.
|
||||||
|
|
||||||
|
<a name="FileMapUsage"></a>
|
||||||
|
## type [FileMapUsage](<https://github.com/katenary/katenary/blob/master/internal/generator/configMap.go#L21>)
|
||||||
|
|
||||||
|
FileMapUsage is the usage of the filemap.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type FileMapUsage uint8
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="FileMapUsageConfigMap"></a>FileMapUsage constants.
|
||||||
|
|
||||||
|
```go
|
||||||
|
const (
|
||||||
|
FileMapUsageConfigMap FileMapUsage = iota // pure configmap for key:values.
|
||||||
|
FileMapUsageFiles // files in a configmap.
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="HelmChart"></a>
|
||||||
|
## type [HelmChart](<https://github.com/katenary/katenary/blob/master/internal/generator/chart.go#L41-L54>)
|
||||||
|
|
||||||
|
HelmChart is a Helm Chart representation. It contains all the templates, values, versions, helpers...
|
||||||
|
|
||||||
|
```go
|
||||||
|
type HelmChart struct {
|
||||||
|
Templates map[string]*ChartTemplate `yaml:"-"`
|
||||||
|
Values map[string]any `yaml:"-"`
|
||||||
|
VolumeMounts map[string]any `yaml:"-"`
|
||||||
|
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Icon string `yaml:"icon,omitempty"`
|
||||||
|
APIVersion string `yaml:"apiVersion"`
|
||||||
|
Version string `yaml:"version"`
|
||||||
|
AppVersion string `yaml:"appVersion"`
|
||||||
|
Description string `yaml:"description"`
|
||||||
|
Helper string `yaml:"-"`
|
||||||
|
Dependencies []labelstructs.Dependency `yaml:"dependencies,omitempty"`
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="Generate"></a>
|
||||||
|
### func [Generate](<https://github.com/katenary/katenary/blob/master/internal/generator/generator.go#L32>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Generate(project *types.Project) (*HelmChart, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Generate a chart from a compose project. This does not write files to disk, it only creates the HelmChart object.
|
||||||
|
|
||||||
|
The Generate function will create the HelmChart object this way:
|
||||||
|
|
||||||
|
- Detect the service port name or leave the port number if not found.
|
||||||
|
- Create a deployment for each service that are not ingnore.
|
||||||
|
- Create a service and ingresses for each service that has ports and/or declared ingresses.
|
||||||
|
- Create a PVC or Configmap volumes for each volume.
|
||||||
|
- Create init containers for each service which has dependencies to other services.
|
||||||
|
- Create a chart dependencies.
|
||||||
|
- Create a configmap and secrets from the environment variables.
|
||||||
|
- Merge the same\-pod services.
|
||||||
|
|
||||||
|
<a name="NewChart"></a>
|
||||||
|
### func [NewChart](<https://github.com/katenary/katenary/blob/master/internal/generator/chart.go#L57>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewChart(name string) *HelmChart
|
||||||
|
```
|
||||||
|
|
||||||
|
NewChart creates a new empty chart with the given name.
|
||||||
|
|
||||||
|
<a name="HelmChart.SaveTemplates"></a>
|
||||||
|
### func \(\*HelmChart\) [SaveTemplates](<https://github.com/katenary/katenary/blob/master/internal/generator/chart.go#L72>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (chart *HelmChart) SaveTemplates(templateDir string)
|
||||||
|
```
|
||||||
|
|
||||||
|
SaveTemplates the templates of the chart to the given directory.
|
||||||
|
|
||||||
|
<a name="Ingress"></a>
|
||||||
|
## type [Ingress](<https://github.com/katenary/katenary/blob/master/internal/generator/ingress.go#L18-L22>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Ingress struct {
|
||||||
|
*networkv1.Ingress
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="NewIngress"></a>
|
||||||
|
### func [NewIngress](<https://github.com/katenary/katenary/blob/master/internal/generator/ingress.go#L25>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewIngress(service types.ServiceConfig, Chart *HelmChart) *Ingress
|
||||||
|
```
|
||||||
|
|
||||||
|
NewIngress creates a new Ingress from a compose service.
|
||||||
|
|
||||||
|
<a name="Ingress.Filename"></a>
|
||||||
|
### func \(\*Ingress\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/ingress.go#L129>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (ingress *Ingress) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Ingress.Yaml"></a>
|
||||||
|
### func \(\*Ingress\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/ingress.go#L133>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (ingress *Ingress) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="IngressValue"></a>
|
||||||
|
## type [IngressValue](<https://github.com/katenary/katenary/blob/master/internal/generator/values.go#L29-L36>)
|
||||||
|
|
||||||
|
IngressValue is a ingress configuration that will be saved in values.yaml.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type IngressValue struct {
|
||||||
|
Annotations map[string]string `yaml:"annotations"`
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
Class string `yaml:"class"`
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
TLS TLS `yaml:"tls"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="PersistenceValue"></a>
|
||||||
|
## type [PersistenceValue](<https://github.com/katenary/katenary/blob/master/internal/generator/values.go#L16-L21>)
|
||||||
|
|
||||||
|
PersistenceValue is a persistence configuration that will be saved in values.yaml.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type PersistenceValue struct {
|
||||||
|
StorageClass string `yaml:"storageClass"`
|
||||||
|
Size string `yaml:"size"`
|
||||||
|
AccessMode []string `yaml:"accessMode"`
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="RBAC"></a>
|
||||||
|
## type [RBAC](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L20-L24>)
|
||||||
|
|
||||||
|
RBAC is a kubernetes RBAC containing a role, a rolebinding and an associated serviceaccount.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type RBAC struct {
|
||||||
|
RoleBinding *RoleBinding
|
||||||
|
Role *Role
|
||||||
|
ServiceAccount *ServiceAccount
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="NewRBAC"></a>
|
||||||
|
### func [NewRBAC](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L27>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewRBAC(service types.ServiceConfig, appName string) *RBAC
|
||||||
|
```
|
||||||
|
|
||||||
|
NewRBAC creates a new RBAC from a compose service. The appName is the name of the application taken from the project name.
|
||||||
|
|
||||||
|
<a name="RepositoryValue"></a>
|
||||||
|
## type [RepositoryValue](<https://github.com/katenary/katenary/blob/master/internal/generator/values.go#L10-L13>)
|
||||||
|
|
||||||
|
RepositoryValue is a docker repository image and tag that will be saved in values.yaml.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type RepositoryValue struct {
|
||||||
|
Image string `yaml:"image"`
|
||||||
|
Tag string `yaml:"tag"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="Role"></a>
|
||||||
|
## type [Role](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L114-L117>)
|
||||||
|
|
||||||
|
Role is a kubernetes Role.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Role struct {
|
||||||
|
*rbacv1.Role
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="Role.Filename"></a>
|
||||||
|
### func \(\*Role\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L119>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *Role) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Role.Yaml"></a>
|
||||||
|
### func \(\*Role\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L123>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *Role) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="RoleBinding"></a>
|
||||||
|
## type [RoleBinding](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L100-L103>)
|
||||||
|
|
||||||
|
RoleBinding is a kubernetes RoleBinding.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type RoleBinding struct {
|
||||||
|
*rbacv1.RoleBinding
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="RoleBinding.Filename"></a>
|
||||||
|
### func \(\*RoleBinding\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L105>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *RoleBinding) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="RoleBinding.Yaml"></a>
|
||||||
|
### func \(\*RoleBinding\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L109>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *RoleBinding) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Secret"></a>
|
||||||
|
## type [Secret](<https://github.com/katenary/katenary/blob/master/internal/generator/secret.go#L22-L25>)
|
||||||
|
|
||||||
|
Secret is a kubernetes Secret.
|
||||||
|
|
||||||
|
Implements the DataMap interface.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Secret struct {
|
||||||
|
*corev1.Secret
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="NewSecret"></a>
|
||||||
|
### func [NewSecret](<https://github.com/katenary/katenary/blob/master/internal/generator/secret.go#L28>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewSecret(service types.ServiceConfig, appName string) *Secret
|
||||||
|
```
|
||||||
|
|
||||||
|
NewSecret creates a new Secret from a compose service
|
||||||
|
|
||||||
|
<a name="Secret.AddData"></a>
|
||||||
|
### func \(\*Secret\) [AddData](<https://github.com/katenary/katenary/blob/master/internal/generator/secret.go#L70>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Secret) AddData(key, value string)
|
||||||
|
```
|
||||||
|
|
||||||
|
AddData adds a key value pair to the secret.
|
||||||
|
|
||||||
|
<a name="Secret.Filename"></a>
|
||||||
|
### func \(\*Secret\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/secret.go#L86>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Secret) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
Filename returns the filename of the secret.
|
||||||
|
|
||||||
|
<a name="Secret.SetData"></a>
|
||||||
|
### func \(\*Secret\) [SetData](<https://github.com/katenary/katenary/blob/master/internal/generator/secret.go#L91>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Secret) SetData(data map[string]string)
|
||||||
|
```
|
||||||
|
|
||||||
|
SetData sets the data of the secret.
|
||||||
|
|
||||||
|
<a name="Secret.Yaml"></a>
|
||||||
|
### func \(\*Secret\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/secret.go#L98>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Secret) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Yaml returns the yaml representation of the secret.
|
||||||
|
|
||||||
|
<a name="Service"></a>
|
||||||
|
## type [Service](<https://github.com/katenary/katenary/blob/master/internal/generator/service.go#L18-L21>)
|
||||||
|
|
||||||
|
Service is a kubernetes Service.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Service struct {
|
||||||
|
*v1.Service `yaml:",inline"`
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="NewService"></a>
|
||||||
|
### func [NewService](<https://github.com/katenary/katenary/blob/master/internal/generator/service.go#L24>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewService(service types.ServiceConfig, appName string) *Service
|
||||||
|
```
|
||||||
|
|
||||||
|
NewService creates a new Service from a compose service.
|
||||||
|
|
||||||
|
<a name="Service.AddPort"></a>
|
||||||
|
### func \(\*Service\) [AddPort](<https://github.com/katenary/katenary/blob/master/internal/generator/service.go#L53>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Service) AddPort(port types.ServicePortConfig, serviceName ...string)
|
||||||
|
```
|
||||||
|
|
||||||
|
AddPort adds a port to the service.
|
||||||
|
|
||||||
|
<a name="Service.Filename"></a>
|
||||||
|
### func \(\*Service\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/service.go#L74>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Service) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
Filename returns the filename of the service.
|
||||||
|
|
||||||
|
<a name="Service.Yaml"></a>
|
||||||
|
### func \(\*Service\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/service.go#L79>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *Service) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Yaml returns the yaml representation of the service.
|
||||||
|
|
||||||
|
<a name="ServiceAccount"></a>
|
||||||
|
## type [ServiceAccount](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L132-L135>)
|
||||||
|
|
||||||
|
ServiceAccount is a kubernetes ServiceAccount.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ServiceAccount struct {
|
||||||
|
*corev1.ServiceAccount
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="ServiceAccount.Filename"></a>
|
||||||
|
### func \(\*ServiceAccount\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L137>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *ServiceAccount) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="ServiceAccount.Yaml"></a>
|
||||||
|
### func \(\*ServiceAccount\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/rbac.go#L141>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *ServiceAccount) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="TLS"></a>
|
||||||
|
## type [TLS](<https://github.com/katenary/katenary/blob/master/internal/generator/values.go#L23-L26>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type TLS struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
SecretName string `yaml:"secretName"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="Value"></a>
|
||||||
|
## type [Value](<https://github.com/katenary/katenary/blob/master/internal/generator/values.go#L39-L50>)
|
||||||
|
|
||||||
|
Value will be saved in values.yaml. It contains configuration for all deployment and services.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Value struct {
|
||||||
|
Repository *RepositoryValue `yaml:"repository,omitempty"`
|
||||||
|
Persistence map[string]*PersistenceValue `yaml:"persistence,omitempty"`
|
||||||
|
Ingress *IngressValue `yaml:"ingress,omitempty"`
|
||||||
|
Environment map[string]any `yaml:"environment,omitempty"`
|
||||||
|
Replicas *uint32 `yaml:"replicas,omitempty"`
|
||||||
|
CronJob *CronJobValue `yaml:"cronjob,omitempty"`
|
||||||
|
NodeSelector map[string]string `yaml:"nodeSelector"`
|
||||||
|
Resources map[string]any `yaml:"resources"`
|
||||||
|
ImagePullPolicy string `yaml:"imagePullPolicy,omitempty"`
|
||||||
|
ServiceAccount string `yaml:"serviceAccount"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="NewValue"></a>
|
||||||
|
### func [NewValue](<https://github.com/katenary/katenary/blob/master/internal/generator/values.go#L57>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewValue(service types.ServiceConfig, main ...bool) *Value
|
||||||
|
```
|
||||||
|
|
||||||
|
NewValue creates a new Value from a compose service. The value contains the necessary information to deploy the service \(image, tag, replicas, etc.\).
|
||||||
|
|
||||||
|
If \`main\` is true, the tag will be empty because it will be set in the helm chart appVersion.
|
||||||
|
|
||||||
|
<a name="Value.AddIngress"></a>
|
||||||
|
### func \(\*Value\) [AddIngress](<https://github.com/katenary/katenary/blob/master/internal/generator/values.go#L90>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (v *Value) AddIngress(host, path string)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Value.AddPersistence"></a>
|
||||||
|
### func \(\*Value\) [AddPersistence](<https://github.com/katenary/katenary/blob/master/internal/generator/values.go#L104>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (v *Value) AddPersistence(volumeName string)
|
||||||
|
```
|
||||||
|
|
||||||
|
AddPersistence adds persistence configuration to the Value.
|
||||||
|
|
||||||
|
<a name="VolumeClaim"></a>
|
||||||
|
## type [VolumeClaim](<https://github.com/katenary/katenary/blob/master/internal/generator/volume.go#L18-L23>)
|
||||||
|
|
||||||
|
VolumeClaim is a kubernetes VolumeClaim. This is a PersistentVolumeClaim.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type VolumeClaim struct {
|
||||||
|
*v1.PersistentVolumeClaim
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="NewVolumeClaim"></a>
|
||||||
|
### func [NewVolumeClaim](<https://github.com/katenary/katenary/blob/master/internal/generator/volume.go#L26>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewVolumeClaim(service types.ServiceConfig, volumeName, appName string) *VolumeClaim
|
||||||
|
```
|
||||||
|
|
||||||
|
NewVolumeClaim creates a new VolumeClaim from a compose service.
|
||||||
|
|
||||||
|
<a name="VolumeClaim.Filename"></a>
|
||||||
|
### func \(\*VolumeClaim\) [Filename](<https://github.com/katenary/katenary/blob/master/internal/generator/volume.go#L62>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (v *VolumeClaim) Filename() string
|
||||||
|
```
|
||||||
|
|
||||||
|
Filename returns the suggested filename for a VolumeClaim.
|
||||||
|
|
||||||
|
<a name="VolumeClaim.Yaml"></a>
|
||||||
|
### func \(\*VolumeClaim\) [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/volume.go#L67>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (v *VolumeClaim) Yaml() ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Yaml marshals a VolumeClaim into yaml.
|
||||||
|
|
||||||
|
<a name="Yaml"></a>
|
||||||
|
## type [Yaml](<https://github.com/katenary/katenary/blob/master/internal/generator/types.go#L10-L13>)
|
||||||
|
|
||||||
|
Yaml is a kubernetes object that can be converted to yaml.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Yaml interface {
|
||||||
|
Yaml() ([]byte, error)
|
||||||
|
Filename() string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
|
28
doc/docs/packages/internal/generator/extrafiles.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||||
|
|
||||||
|
# extrafiles
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/katenary/katenary/internal/generator/extrafiles"
|
||||||
|
```
|
||||||
|
|
||||||
|
Package extrafiles provides function to generate the Chart files that are not objects. Like README.md and notes.txt...
|
||||||
|
|
||||||
|
## func [NotesFile](<https://github.com/katenary/katenary/blob/master/internal/generator/extrafiles/notes.go#L13>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NotesFile(services []string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
NotesFile returns the content of the note.txt file.
|
||||||
|
|
||||||
|
<a name="ReadMeFile"></a>
|
||||||
|
## func [ReadMeFile](<https://github.com/katenary/katenary/blob/master/internal/generator/extrafiles/readme.go#L46>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ReadMeFile(charname, description string, values map[string]any) string
|
||||||
|
```
|
||||||
|
|
||||||
|
ReadMeFile returns the content of the README.md file.
|
||||||
|
|
||||||
|
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
|
67
doc/docs/packages/internal/generator/katenaryfile.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||||
|
|
||||||
|
# katenaryfile
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/katenary/katenary/internal/generator/katenaryfile"
|
||||||
|
```
|
||||||
|
|
||||||
|
Package katenaryfile is a package for reading and writing katenary files.
|
||||||
|
|
||||||
|
A katenary file, named "katenary.yml" or "katenary.yaml", is a file where you can define the configuration of the conversion avoiding the use of labels in the compose file.
|
||||||
|
|
||||||
|
Formely, the file describe the same structure as in labels, and so that can be validated and completed by LSP. It also ease the use of katenary.
|
||||||
|
|
||||||
|
## func [GenerateSchema](<https://github.com/katenary/katenary/blob/master/internal/generator/katenaryfile/main.go#L137>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GenerateSchema() string
|
||||||
|
```
|
||||||
|
|
||||||
|
GenerateSchema generates the schema for the katenary.yaml file.
|
||||||
|
|
||||||
|
<a name="OverrideWithConfig"></a>
|
||||||
|
## func [OverrideWithConfig](<https://github.com/katenary/katenary/blob/master/internal/generator/katenaryfile/main.go#L49>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func OverrideWithConfig(project *types.Project)
|
||||||
|
```
|
||||||
|
|
||||||
|
OverrideWithConfig overrides the project with the katenary.yaml file. It will set the labels of the services with the values from the katenary.yaml file. It work in memory, so it will not modify the original project.
|
||||||
|
|
||||||
|
<a name="Service"></a>
|
||||||
|
## type [Service](<https://github.com/katenary/katenary/blob/master/internal/generator/katenaryfile/main.go#L27-L44>)
|
||||||
|
|
||||||
|
Service is a struct that contains the service configuration for katenary
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Service struct {
|
||||||
|
MainApp *bool `yaml:"main-app,omitempty" json:"main-app,omitempty" jsonschema:"title=Is this service the main application"`
|
||||||
|
Values []StringOrMap `yaml:"values,omitempty" json:"values,omitempty" jsonschema:"description=Environment variables to be set in values.yaml with or without a description"`
|
||||||
|
Secrets *labelstructs.Secrets `yaml:"secrets,omitempty" json:"secrets,omitempty" jsonschema:"title=Secrets,description=Environment variables to be set as secrets"`
|
||||||
|
Ports *labelstructs.Ports `yaml:"ports,omitempty" json:"ports,omitempty" jsonschema:"title=Ports,description=Ports to be exposed in services"`
|
||||||
|
Ingress *labelstructs.Ingress `yaml:"ingress,omitempty" json:"ingress,omitempty" jsonschema:"title=Ingress,description=Ingress configuration"`
|
||||||
|
HealthCheck *labelstructs.HealthCheck `yaml:"health-check,omitempty" json:"health-check,omitempty" jsonschema:"title=Health Check,description=Health check configuration that respects the kubernetes api"`
|
||||||
|
SamePod *string `yaml:"same-pod,omitempty" json:"same-pod,omitempty" jsonschema:"title=Same Pod,description=Service that should be in the same pod"`
|
||||||
|
Description *string `yaml:"description,omitempty" json:"description,omitempty" jsonschema:"title=Description,description=Description of the service that will be injected in the values.yaml file"`
|
||||||
|
Ignore *bool `yaml:"ignore,omitempty" json:"ignore,omitempty" jsonschema:"title=Ignore,description=Ignore the service in the conversion"`
|
||||||
|
Dependencies []labelstructs.Dependency `yaml:"dependencies,omitempty" json:"dependencies,omitempty" jsonschema:"title=Dependencies,description=Services that should be injected in the Chart.yaml file"`
|
||||||
|
ConfigMapFiles *labelstructs.ConfigMapFiles `yaml:"configmap-files,omitempty" json:"configmap-files,omitempty" jsonschema:"title=ConfigMap Files,description=Files that should be injected as ConfigMap"`
|
||||||
|
MapEnv *labelstructs.MapEnv `yaml:"map-env,omitempty" json:"map-env,omitempty" jsonschema:"title=Map Env,description=Map environment variables to another value"`
|
||||||
|
CronJob *labelstructs.CronJob `yaml:"cron-job,omitempty" json:"cron-job,omitempty" jsonschema:"title=Cron Job,description=Cron Job configuration"`
|
||||||
|
EnvFrom *labelstructs.EnvFrom `yaml:"env-from,omitempty" json:"env-from,omitempty" jsonschema:"title=Env From,description=Inject environment variables from another service"`
|
||||||
|
ExchangeVolumes []*labelstructs.ExchangeVolume `yaml:"exchange-volumes,omitempty" json:"exchange-volumes,omitempty" jsonschema:"title=Exchange Volumes,description=Exchange volumes between services"`
|
||||||
|
ValuesFrom *labelstructs.ValueFrom `yaml:"values-from,omitempty" json:"values-from,omitempty" jsonschema:"title=Values From,description=Inject values from another service (secret or configmap environment variables)"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="StringOrMap"></a>
|
||||||
|
## type [StringOrMap](<https://github.com/katenary/katenary/blob/master/internal/generator/katenaryfile/main.go#L24>)
|
||||||
|
|
||||||
|
StringOrMap is a struct that can be either a string or a map of strings. It's a helper struct to unmarshal the katenary.yaml file and produce the schema
|
||||||
|
|
||||||
|
```go
|
||||||
|
type StringOrMap any
|
||||||
|
```
|
||||||
|
|
||||||
|
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
|
110
doc/docs/packages/internal/generator/labels.md
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||||
|
|
||||||
|
# labels
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/katenary/katenary/internal/generator/labels"
|
||||||
|
```
|
||||||
|
|
||||||
|
Package labels provides functionality to parse and manipulate labels.
|
||||||
|
|
||||||
|
## Constants
|
||||||
|
|
||||||
|
<a name="KatenaryLabelPrefix"></a>
|
||||||
|
|
||||||
|
```go
|
||||||
|
const KatenaryLabelPrefix = "katenary.v3"
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="GetLabelHelp"></a>
|
||||||
|
## func [GetLabelHelp](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/katenaryLabels.go#L88>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetLabelHelp(asMarkdown bool) string
|
||||||
|
```
|
||||||
|
|
||||||
|
GetLabelHelp return the help for the labels.
|
||||||
|
|
||||||
|
<a name="GetLabelHelpFor"></a>
|
||||||
|
## func [GetLabelHelpFor](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/katenaryLabels.go#L97>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetLabelHelpFor(labelname string, asMarkdown bool) string
|
||||||
|
```
|
||||||
|
|
||||||
|
GetLabelHelpFor returns the help for a specific label.
|
||||||
|
|
||||||
|
<a name="GetLabelNames"></a>
|
||||||
|
## func [GetLabelNames](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/katenaryLabels.go#L72>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetLabelNames() []string
|
||||||
|
```
|
||||||
|
|
||||||
|
GetLabelNames returns a sorted list of all katenary label names.
|
||||||
|
|
||||||
|
<a name="Prefix"></a>
|
||||||
|
## func [Prefix](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/katenaryLabels.go#L235>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Prefix() string
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Help"></a>
|
||||||
|
## type [Help](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/katenaryLabels.go#L64-L69>)
|
||||||
|
|
||||||
|
Help is the documentation of a label.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Help struct {
|
||||||
|
Short string `yaml:"short"`
|
||||||
|
Long string `yaml:"long"`
|
||||||
|
Example string `yaml:"example"`
|
||||||
|
Type string `yaml:"type"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="Label"></a>
|
||||||
|
## type [Label](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/katenaryLabels.go#L57>)
|
||||||
|
|
||||||
|
Label is a katenary label to find in compose files.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Label = string
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="LabelMainApp"></a>Known labels.
|
||||||
|
|
||||||
|
```go
|
||||||
|
const (
|
||||||
|
LabelMainApp Label = KatenaryLabelPrefix + "/main-app"
|
||||||
|
LabelValues Label = KatenaryLabelPrefix + "/values"
|
||||||
|
LabelSecrets Label = KatenaryLabelPrefix + "/secrets"
|
||||||
|
LabelPorts Label = KatenaryLabelPrefix + "/ports"
|
||||||
|
LabelIngress Label = KatenaryLabelPrefix + "/ingress"
|
||||||
|
LabelMapEnv Label = KatenaryLabelPrefix + "/map-env"
|
||||||
|
LabelHealthCheck Label = KatenaryLabelPrefix + "/health-check"
|
||||||
|
LabelSamePod Label = KatenaryLabelPrefix + "/same-pod"
|
||||||
|
LabelDescription Label = KatenaryLabelPrefix + "/description"
|
||||||
|
LabelIgnore Label = KatenaryLabelPrefix + "/ignore"
|
||||||
|
LabelDependencies Label = KatenaryLabelPrefix + "/dependencies"
|
||||||
|
LabelConfigMapFiles Label = KatenaryLabelPrefix + "/configmap-files"
|
||||||
|
LabelCronJob Label = KatenaryLabelPrefix + "/cronjob"
|
||||||
|
LabelEnvFrom Label = KatenaryLabelPrefix + "/env-from"
|
||||||
|
LabelExchangeVolume Label = KatenaryLabelPrefix + "/exchange-volumes"
|
||||||
|
LabelValuesFrom Label = KatenaryLabelPrefix + "/values-from"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="LabelName"></a>
|
||||||
|
### func [LabelName](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/katenaryLabels.go#L59>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func LabelName(name string) Label
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
|
246
doc/docs/packages/internal/generator/labels/labelstructs.md
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||||
|
|
||||||
|
# labelstructs
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/katenary/katenary/internal/generator/labels/labelstructs"
|
||||||
|
```
|
||||||
|
|
||||||
|
Package labelstructs is a package that contains the structs used to represent the labels in the yaml files.
|
||||||
|
|
||||||
|
## type [ConfigMapFiles](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/configMap.go#L5>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ConfigMapFiles []string
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="ConfigMapFileFrom"></a>
|
||||||
|
### func [ConfigMapFileFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/configMap.go#L7>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ConfigMapFileFrom(data string) (ConfigMapFiles, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="CronJob"></a>
|
||||||
|
## type [CronJob](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/cronJob.go#L5-L10>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type CronJob struct {
|
||||||
|
Image string `yaml:"image,omitempty" json:"image,omitempty"`
|
||||||
|
Command string `yaml:"command" json:"command,omitempty"`
|
||||||
|
Schedule string `yaml:"schedule" json:"schedule,omitempty"`
|
||||||
|
Rbac bool `yaml:"rbac" json:"rbac,omitempty"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="CronJobFrom"></a>
|
||||||
|
### func [CronJobFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/cronJob.go#L12>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CronJobFrom(data string) (*CronJob, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Dependency"></a>
|
||||||
|
## type [Dependency](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/dependencies.go#L6-L12>)
|
||||||
|
|
||||||
|
Dependency is a dependency of a chart to other charts.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Dependency struct {
|
||||||
|
Values map[string]any `yaml:"-" json:"values,omitempty"`
|
||||||
|
Name string `yaml:"name" json:"name"`
|
||||||
|
Version string `yaml:"version" json:"version"`
|
||||||
|
Repository string `yaml:"repository" json:"repository"`
|
||||||
|
Alias string `yaml:"alias,omitempty" json:"alias,omitempty"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="DependenciesFrom"></a>
|
||||||
|
### func [DependenciesFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/dependencies.go#L15>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func DependenciesFrom(data string) ([]Dependency, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
DependenciesFrom returns a slice of dependencies from the given string.
|
||||||
|
|
||||||
|
<a name="EnvFrom"></a>
|
||||||
|
## type [EnvFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/envFrom.go#L5>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type EnvFrom []string
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="EnvFromFrom"></a>
|
||||||
|
### func [EnvFromFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/envFrom.go#L8>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func EnvFromFrom(data string) (EnvFrom, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
EnvFromFrom returns a EnvFrom from the given string.
|
||||||
|
|
||||||
|
<a name="ExchangeVolume"></a>
|
||||||
|
## type [ExchangeVolume](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/exchangeVolume.go#L5-L10>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ExchangeVolume struct {
|
||||||
|
Name string `yaml:"name" json:"name"`
|
||||||
|
MountPath string `yaml:"mountPath" json:"mountPath"`
|
||||||
|
Type string `yaml:"type,omitempty" json:"type,omitempty"`
|
||||||
|
Init string `yaml:"init,omitempty" json:"init,omitempty"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="NewExchangeVolumes"></a>
|
||||||
|
### func [NewExchangeVolumes](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/exchangeVolume.go#L12>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func NewExchangeVolumes(data string) ([]*ExchangeVolume, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="HealthCheck"></a>
|
||||||
|
## type [HealthCheck](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/probes.go#L11-L14>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type HealthCheck struct {
|
||||||
|
LivenessProbe *corev1.Probe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty"`
|
||||||
|
ReadinessProbe *corev1.Probe `yaml:"readinessProbe,omitempty" json:"readinessProbe,omitempty"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="ProbeFrom"></a>
|
||||||
|
### func [ProbeFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/probes.go#L16>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ProbeFrom(data string) (*HealthCheck, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="Ingress"></a>
|
||||||
|
## type [Ingress](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/ingress.go#L14-L22>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Ingress struct {
|
||||||
|
Port *int32 `yaml:"port,omitempty" json:"port,omitempty"`
|
||||||
|
Annotations map[string]string `yaml:"annotations,omitempty" jsonschema:"nullable" json:"annotations,omitempty"`
|
||||||
|
Hostname string `yaml:"hostname,omitempty" json:"hostname,omitempty"`
|
||||||
|
Path *string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||||
|
Class *string `yaml:"class,omitempty" json:"class,omitempty" jsonschema:"default:-"`
|
||||||
|
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
|
||||||
|
TLS *TLS `yaml:"tls,omitempty" json:"tls,omitempty"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="IngressFrom"></a>
|
||||||
|
### func [IngressFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/ingress.go#L25>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IngressFrom(data string) (*Ingress, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
IngressFrom creates a new Ingress from a compose service.
|
||||||
|
|
||||||
|
<a name="MapEnv"></a>
|
||||||
|
## type [MapEnv](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/mapenv.go#L5>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MapEnv map[string]string
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="MapEnvFrom"></a>
|
||||||
|
### func [MapEnvFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/mapenv.go#L8>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func MapEnvFrom(data string) (MapEnv, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
MapEnvFrom returns a MapEnv from the given string.
|
||||||
|
|
||||||
|
<a name="Ports"></a>
|
||||||
|
## type [Ports](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/ports.go#L5>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Ports []uint32
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="PortsFrom"></a>
|
||||||
|
### func [PortsFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/ports.go#L8>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func PortsFrom(data string) (Ports, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
PortsFrom returns a Ports from the given string.
|
||||||
|
|
||||||
|
<a name="Secrets"></a>
|
||||||
|
## type [Secrets](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/secrets.go#L5>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Secrets []string
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="SecretsFrom"></a>
|
||||||
|
### func [SecretsFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/secrets.go#L7>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func SecretsFrom(data string) (Secrets, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="TLS"></a>
|
||||||
|
## type [TLS](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/ingress.go#L10-L12>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type TLS struct {
|
||||||
|
Enabled bool `yaml:"enabled" json:"enabled,omitempty"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="ValueFrom"></a>
|
||||||
|
## type [ValueFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/valueFrom.go#L5>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
type ValueFrom map[string]string
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="GetValueFrom"></a>
|
||||||
|
### func [GetValueFrom](<https://github.com/katenary/katenary/blob/master/internal/generator/labels/labelstructs/valueFrom.go#L7>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetValueFrom(data string) (*ValueFrom, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
|
19
doc/docs/packages/internal/parser.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||||
|
|
||||||
|
# parser
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/katenary/katenary/internal/parser"
|
||||||
|
```
|
||||||
|
|
||||||
|
Package parser is a wrapper around compose\-go to parse compose files.
|
||||||
|
|
||||||
|
## func [Parse](<https://github.com/katenary/katenary/blob/master/internal/parser/main.go#L29>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Parse(profiles []string, envFiles []string, dockerComposeFile ...string) (*types.Project, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
Parse compose files and return a project. The project is parsed with dotenv, osenv and profiles.
|
||||||
|
|
||||||
|
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
|
221
doc/docs/packages/internal/utils.md
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
|
||||||
|
|
||||||
|
# utils
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/katenary/katenary/internal/utils"
|
||||||
|
```
|
||||||
|
|
||||||
|
Package utils provides some utility functions used in katenary. It defines some constants and functions used in the whole project.
|
||||||
|
|
||||||
|
## Constants
|
||||||
|
|
||||||
|
<a name="DirectoryPermission"></a>DirectoryPermission is the default values for permissions apply to created directories.
|
||||||
|
|
||||||
|
```go
|
||||||
|
const DirectoryPermission = 0o755
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="AsResourceName"></a>
|
||||||
|
## func [AsResourceName](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L196>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func AsResourceName(name string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
AsResourceName returns a resource name with underscores to respect the kubernetes naming convention. It's the opposite of FixedResourceName.
|
||||||
|
|
||||||
|
<a name="Confirm"></a>
|
||||||
|
## func [Confirm](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L164>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Confirm(question string, icon ...Icon) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Confirm asks a question and returns true if the answer is y.
|
||||||
|
|
||||||
|
<a name="CountStartingSpaces"></a>
|
||||||
|
## func [CountStartingSpaces](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L41>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func CountStartingSpaces(line string) int
|
||||||
|
```
|
||||||
|
|
||||||
|
CountStartingSpaces counts the number of spaces at the beginning of a string.
|
||||||
|
|
||||||
|
<a name="EncodeBasicYaml"></a>
|
||||||
|
## func [EncodeBasicYaml](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L178>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func EncodeBasicYaml(data any) ([]byte, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
EncodeBasicYaml encodes a basic yaml from an interface.
|
||||||
|
|
||||||
|
<a name="FixedResourceName"></a>
|
||||||
|
## func [FixedResourceName](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L190>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func FixedResourceName(name string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
FixedResourceName returns a resource name without underscores to respect the kubernetes naming convention.
|
||||||
|
|
||||||
|
<a name="GetContainerByName"></a>
|
||||||
|
## func [GetContainerByName](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L87>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetContainerByName(name string, containers []corev1.Container) (*corev1.Container, int)
|
||||||
|
```
|
||||||
|
|
||||||
|
GetContainerByName returns a container by name and its index in the array. It returns nil, \-1 if not found.
|
||||||
|
|
||||||
|
<a name="GetKind"></a>
|
||||||
|
## func [GetKind](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L54>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetKind(path string) (kind string)
|
||||||
|
```
|
||||||
|
|
||||||
|
GetKind returns the kind of the resource from the file path.
|
||||||
|
|
||||||
|
<a name="GetServiceNameByPort"></a>
|
||||||
|
## func [GetServiceNameByPort](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L77>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetServiceNameByPort(port int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
GetServiceNameByPort returns the service name for a port. It the service name is not found, it returns an empty string.
|
||||||
|
|
||||||
|
<a name="GetValuesFromLabel"></a>
|
||||||
|
## func [GetValuesFromLabel](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L129>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func GetValuesFromLabel(service types.ServiceConfig, LabelValues string) map[string]*EnvConfig
|
||||||
|
```
|
||||||
|
|
||||||
|
GetValuesFromLabel returns a map of values from a label.
|
||||||
|
|
||||||
|
<a name="HashComposefiles"></a>
|
||||||
|
## func [HashComposefiles](<https://github.com/katenary/katenary/blob/master/internal/utils/hash.go#L12>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func HashComposefiles(files []string) (string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
HashComposefiles returns a hash of the compose files.
|
||||||
|
|
||||||
|
<a name="Int32Ptr"></a>
|
||||||
|
## func [Int32Ptr](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L35>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Int32Ptr(i int32) *int32
|
||||||
|
```
|
||||||
|
|
||||||
|
Int32Ptr returns a pointer to an int32.
|
||||||
|
|
||||||
|
<a name="PathToName"></a>
|
||||||
|
## func [PathToName](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L106>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func PathToName(path string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
PathToName converts a path to a kubernetes complient name.
|
||||||
|
|
||||||
|
<a name="StrPtr"></a>
|
||||||
|
## func [StrPtr](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L38>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func StrPtr(s string) *string
|
||||||
|
```
|
||||||
|
|
||||||
|
StrPtr returns a pointer to a string.
|
||||||
|
|
||||||
|
<a name="TplName"></a>
|
||||||
|
## func [TplName](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L22>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TplName(serviceName, appname string, suffix ...string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
TplName returns the name of the kubernetes resource as a template string. It is used in the templates and defined in \_helper.tpl file.
|
||||||
|
|
||||||
|
<a name="TplValue"></a>
|
||||||
|
## func [TplValue](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L97>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func TplValue(serviceName, variable string, pipes ...string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
TplValue returns a string that can be used in a template to access a value from the values file.
|
||||||
|
|
||||||
|
<a name="Warn"></a>
|
||||||
|
## func [Warn](<https://github.com/katenary/katenary/blob/master/internal/utils/icons.go#L25>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Warn(msg ...any)
|
||||||
|
```
|
||||||
|
|
||||||
|
Warn prints a warning message
|
||||||
|
|
||||||
|
<a name="WordWrap"></a>
|
||||||
|
## func [WordWrap](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L159>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func WordWrap(text string, lineWidth int) string
|
||||||
|
```
|
||||||
|
|
||||||
|
WordWrap wraps a string to a given line width. Warning: it may break the string. You need to check the result.
|
||||||
|
|
||||||
|
<a name="Wrap"></a>
|
||||||
|
## func [Wrap](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L71>)
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Wrap(src, above, below string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
Wrap wraps a string with a string above and below. It will respect the indentation of the src string.
|
||||||
|
|
||||||
|
<a name="EnvConfig"></a>
|
||||||
|
## type [EnvConfig](<https://github.com/katenary/katenary/blob/master/internal/utils/utils.go#L123-L126>)
|
||||||
|
|
||||||
|
EnvConfig is a struct to hold the description of an environment variable.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type EnvConfig struct {
|
||||||
|
Service types.ServiceConfig
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="Icon"></a>
|
||||||
|
## type [Icon](<https://github.com/katenary/katenary/blob/master/internal/utils/icons.go#L6>)
|
||||||
|
|
||||||
|
Icon is a unicode icon
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Icon string
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="IconSuccess"></a>Icons used in katenary.
|
||||||
|
|
||||||
|
```go
|
||||||
|
const (
|
||||||
|
IconSuccess Icon = "✅"
|
||||||
|
IconFailure Icon = "❌"
|
||||||
|
IconWarning Icon = "❕"
|
||||||
|
IconNote Icon = "📝"
|
||||||
|
IconWorld Icon = "🌐"
|
||||||
|
IconPlug Icon = "🔌"
|
||||||
|
IconPackage Icon = "📦"
|
||||||
|
IconCabinet Icon = "🗄️"
|
||||||
|
IconInfo Icon = "🔵"
|
||||||
|
IconSecret Icon = "🔒"
|
||||||
|
IconConfig Icon = "🔧"
|
||||||
|
IconDependency Icon = "🔗"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)
|
48
doc/docs/statics/addons.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Install the highlight.js in the documentation. Then
|
||||||
|
// highlight all the source code.
|
||||||
|
function hljsInstall() {
|
||||||
|
const version = "11.9.0";
|
||||||
|
const theme = "github-dark";
|
||||||
|
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = `//cdnjs.cloudflare.com/ajax/libs/highlight.js/${version}/highlight.min.js`;
|
||||||
|
script.onload = () => {
|
||||||
|
const style = document.createElement("link");
|
||||||
|
style.rel = "stylesheet";
|
||||||
|
style.href = `//cdnjs.cloudflare.com/ajax/libs/highlight.js/${version}/styles/${theme}.min.css`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
hljs.highlightAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All images in an .zoomable div is zoomable, that
|
||||||
|
// meanse that we can click to zoom and unzoom.
|
||||||
|
// This needs specific CSS (see main.css).
|
||||||
|
function makeImagesZoomable() {
|
||||||
|
const zone = document.querySelectorAll(".zoomable");
|
||||||
|
|
||||||
|
zone.forEach((z, i) => {
|
||||||
|
const im = z.querySelectorAll("img,svg");
|
||||||
|
if (im.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const input = document.createElement("input");
|
||||||
|
input.setAttribute("type", "checkbox");
|
||||||
|
input.setAttribute("id", `image-zoom-${i}`);
|
||||||
|
z.appendChild(input);
|
||||||
|
|
||||||
|
const label = document.createElement("label");
|
||||||
|
label.setAttribute("for", `image-zoom-${i}`);
|
||||||
|
z.appendChild(label);
|
||||||
|
|
||||||
|
label.appendChild(im[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
hljsInstall();
|
||||||
|
makeImagesZoomable();
|
||||||
|
});
|
121
doc/docs/statics/icon.svg
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
id="svg211948"
|
||||||
|
viewBox="0 0 95.440796 85.01416"
|
||||||
|
height="85.01416"
|
||||||
|
width="95.440796"
|
||||||
|
version="1.1"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<metadata
|
||||||
|
id="metadata211954">
|
||||||
|
<rdf:rdf>
|
||||||
|
<cc:work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:work>
|
||||||
|
</rdf:rdf>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs211952" />
|
||||||
|
<linearGradient
|
||||||
|
spreadMethod="pad"
|
||||||
|
y2="0.30000001"
|
||||||
|
x2="-0.1"
|
||||||
|
y1="1.2"
|
||||||
|
x1="0.30000001"
|
||||||
|
id="3d_gradient2-logo-24885591-b378-4c55-b87b-b7d42ed10694">
|
||||||
|
<stop
|
||||||
|
id="stop211929"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#ffffff"
|
||||||
|
offset="0%" />
|
||||||
|
<stop
|
||||||
|
id="stop211931"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#000000"
|
||||||
|
offset="100%" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="rotate(-30)"
|
||||||
|
spreadMethod="pad"
|
||||||
|
y2="0.30000001"
|
||||||
|
x2="-0.1"
|
||||||
|
y1="1.2"
|
||||||
|
x1="0.30000001"
|
||||||
|
id="3d_gradient3-logo-24885591-b378-4c55-b87b-b7d42ed10694">
|
||||||
|
<stop
|
||||||
|
id="stop211934"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#ffffff"
|
||||||
|
offset="0%" />
|
||||||
|
<stop
|
||||||
|
id="stop211936"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#cccccc"
|
||||||
|
offset="50%" />
|
||||||
|
<stop
|
||||||
|
id="stop211938"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#000000"
|
||||||
|
offset="100%" />
|
||||||
|
</linearGradient>
|
||||||
|
<g
|
||||||
|
id="logo-group"
|
||||||
|
transform="translate(-394.01147,-211.65063)">
|
||||||
|
<path
|
||||||
|
d="m 773.83594,234.02344 c -0.4545,0.0375 -0.92821,0.1629 -1.40821,0.3789 -1.91999,0.864 -2.68851,2.68743 -1.72851,4.60743 l 21.4082,44.35351 0.0957,0.0957 -9.5996,21.02344 c -0.96,2.112 -0.28778,3.74342 1.82421,4.60742 0.576,0.288 1.15252,0.38477 1.72852,0.38477 1.248,0 2.2072,-0.76703 2.7832,-2.20703 l 31.10352,-68.35352 c 0.96,-2.112 0.28778,-3.64772 -1.82422,-4.51172 -2.112,-0.864 -3.64742,-0.28748 -4.60742,1.72852 l -17.85547,39.35937 -18.7207,-39.45507 c -0.648,-1.44 -1.83572,-2.12422 -3.19922,-2.01172 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path9" />
|
||||||
|
<path
|
||||||
|
d="m 692.07617,233.63477 c -15.26398,0 -26.68945,11.51921 -26.68945,26.7832 0,15.26398 11.13594,26.68945 25.91992,26.68945 8.44799,0 15.64875,-3.84038 19.96875,-9.98437 v 5.85547 c 0,2.11199 1.53614,3.64843 3.74414,3.64843 2.112,0 3.74414,-1.53644 3.74414,-3.64843 v -22.56055 c -0.096,-15.26399 -11.51951,-26.7832 -26.6875,-26.7832 z m 0,6.7207 c 11.03999,0 19.39063,8.63851 19.39063,20.0625 0,11.42399 -8.35064,19.96875 -19.39063,19.96875 -11.03999,0 -19.48828,-8.54476 -19.48828,-19.96875 0,-11.42399 8.44829,-20.0625 19.48828,-20.0625 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path8" />
|
||||||
|
<path
|
||||||
|
d="m 566.60352,233.63477 c -14.78399,0 -25.15235,11.13521 -25.15235,26.7832 0,15.64798 11.03981,26.68945 26.5918,26.68945 5.95199,0 13.24866,-2.59224 17.47265,-6.24023 1.536,-1.344 1.4406,-3.36079 -0.1914,-4.80078 -1.344,-1.056 -3.26508,-0.9606 -4.70508,0.1914 -2.784,2.4 -7.96818,4.22461 -12.57617,4.22461 -10.65599,0 -18.52799,-7.20007 -19.58399,-17.66406 h 38.78516 c 2.016,0 3.45508,-1.34338 3.45508,-3.35938 0,-15.07198 -9.59972,-25.82421 -24.0957,-25.82421 z m 0,6.62304 c 9.69599,0 16.22359,6.72003 17.18359,16.41602 h -35.13477 c 1.344,-9.69599 8.15919,-16.41602 17.95118,-16.41602 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path7" />
|
||||||
|
<path
|
||||||
|
d="m 756.875,233.53906 c -6.71999,0 -12.67202,3.16757 -16.41602,8.35156 v -4.1289 c 0,-2.304 -1.34248,-3.64649 -3.64648,-3.64649 -2.304,0 -3.64844,1.34249 -3.64844,3.64649 v 45.2168 c 0,2.30399 1.34444,3.64843 3.64844,3.64843 2.304,0 3.64648,-1.34444 3.64648,-3.64843 v -28.70313 c 0,-8.92799 7.87302,-14.68851 18.625,-13.72852 3.168,0.192 5.75965,0.76867 6.43164,-2.11132 0.768,-3.168 -2.68863,-4.89649 -8.64062,-4.89649 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path6" />
|
||||||
|
<path
|
||||||
|
d="m 628.04297,233.53906 c -7.10399,0 -13.34271,2.87999 -17.4707,7.58399 v -3.26368 c 0,-2.20799 -1.44044,-3.74414 -3.64844,-3.74414 -2.208,0 -3.74414,1.53615 -3.74414,3.74414 v 45.11915 c 0,2.20799 1.53614,3.64843 3.74414,3.64843 2.208,0 3.64844,-1.44044 3.64844,-3.64843 V 254.5625 c 0,-7.96799 7.19913,-14.01563 16.70312,-14.01563 9.79199,0 17.18359,5.66467 17.18359,17.47266 v 24.95899 c 0,2.11199 1.63215,3.64843 3.74414,3.64843 2.016,0 3.64844,-1.53644 3.64844,-3.64843 v -24.95899 c 0,-15.83998 -10.2726,-24.48047 -23.80859,-24.48047 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path5" />
|
||||||
|
<path
|
||||||
|
d="m 512.17187,217.41016 c -2.11199,0 -3.64843,1.53614 -3.64843,3.74414 v 14.88086 h -6.24024 c -2.01599,0 -3.35937,1.34367 -3.35937,3.26367 0,1.824 1.34338,3.16797 3.35937,3.16797 h 6.24024 v 25.63281 c 0,10.65599 7.39207,18.43134 17.66406,18.52734 h 2.01562 c 2.304,0 4.03321,-1.53644 4.03321,-3.64843 0,-2.208 -1.44104,-3.74415 -3.45703,-3.74415 h -2.5918 c -5.95199,0 -10.27148,-4.60677 -10.27148,-11.13476 V 242.4668 h 10.84765 c 2.016,0 3.35938,-1.34397 3.35938,-3.16797 0,-1.92 -1.34338,-3.26367 -3.35938,-3.26367 H 515.91602 V 221.1543 c 0,-2.208 -1.53615,-3.74414 -3.74415,-3.74414 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path4" />
|
||||||
|
<image
|
||||||
|
xlink:href=""
|
||||||
|
id="container"
|
||||||
|
x="272"
|
||||||
|
y="144"
|
||||||
|
width="480"
|
||||||
|
height="480"
|
||||||
|
style="display:none" />
|
||||||
|
<image
|
||||||
|
xlink:href=""
|
||||||
|
id="icon_container"
|
||||||
|
style="display:none"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="0"
|
||||||
|
height="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#388ec7;fill-opacity:1;stroke:none;stroke-width:1.41128"
|
||||||
|
d="m 488.71354,251.36014 -33.31908,17.65778 -13.63054,6.42952 -13.63053,-6.42952 -33.31907,-17.65778 c 0,5.32502 -2.24747,16.12101 0.77828,20.72433 1.84892,2.81293 6.84753,4.46784 9.82323,6.09432 8.26868,4.51957 16.72019,8.751 24.98932,13.27082 3.1083,1.69895 7.62988,5.16897 11.35877,5.21476 3.70778,0.0455 8.2451,-3.55102 11.35878,-5.19752 8.33909,-4.40967 16.72005,-8.76818 24.98932,-13.28806 3.05286,-1.66866 8.68533,-3.49778 10.14461,-6.69253 2.3911,-5.23485 0.45691,-14.46175 0.45691,-20.12612 m -46.19236,16.00215 c 3.59731,-0.51544 7.48607,-3.47354 10.60152,-5.12097 7.58911,-4.0131 15.20174,-8.00941 22.71755,-12.13797 3.53683,-1.94283 9.05374,-3.7013 11.65911,-6.69847 3.28982,-3.78453 1.93068,-13.45759 -2.58668,-15.74886 -4.7363,-2.40229 -8.80251,1.12086 -12.85868,3.25251 l -21.20306,11.2665 c -2.56736,1.35182 -6.01463,4.01777 -9.08702,4.01777 -3.29073,0 -7.12524,-2.97742 -9.84427,-4.47101 -6.50984,-3.57597 -13.17851,-6.90091 -19.68854,-10.47698 -2.85668,-1.56921 -7.10587,-4.85415 -10.60153,-4.52437 -7.2756,0.6864 -9.69308,11.97712 -5.60111,16.68444 2.43875,2.80547 7.56529,4.49972 10.90188,6.26408 7.83167,4.14137 15.6667,8.28474 23.4748,12.46456 3.21433,1.72068 8.18431,5.79216 12.11603,5.22877 m 30.29007,-45.33762 v -1.39693 l -18.17404,-8.90973 -12.11603,4.65427 -12.87329,-4.72164 -18.93129,8.9771 v 1.39693 l 21.20305,11.17542 9.84427,4.34169 9.84428,-4.33415 z"
|
||||||
|
id="path1" />
|
||||||
|
<path
|
||||||
|
d="m 334.95508,211.65039 c -2.016,0 -3.74414,1.63214 -3.74414,3.74414 v 67.48828 c 0,2.112 1.72814,3.74414 3.74414,3.74414 2.112,0 3.74414,-1.63214 3.74414,-3.74414 v -24.57617 l 8.54492,-8.64062 26.11133,35.32812 c 0.768,1.152 1.82397,1.63281 3.16797,1.63281 2.68799,0 4.5115,-3.36112 2.6875,-5.95312 l -26.5918,-36.28711 26.30469,-26.30469 c 2.304,-2.592 1.24701,-6.43164 -2.20899,-6.43164 -1.152,0 -2.01461,0.38375 -2.97461,1.34375 l -35.04101,35.04102 v -32.64063 c 0,-2.112 -1.63214,-3.74414 -3.74414,-3.74414 z"
|
||||||
|
style="fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path3" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.7 KiB |
1
doc/docs/statics/klee.svg
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
doc/docs/statics/logo-bright.png
Normal file
After Width: | Height: | Size: 15 KiB |
118
doc/docs/statics/logo-bright.svg
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
id="svg211948"
|
||||||
|
viewBox="0 0 544.44238 97.824005"
|
||||||
|
height="97.824005"
|
||||||
|
width="544.44238"
|
||||||
|
version="1.1"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<metadata
|
||||||
|
id="metadata211954">
|
||||||
|
<rdf:rdf>
|
||||||
|
<cc:work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:work>
|
||||||
|
</rdf:rdf>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs211952" />
|
||||||
|
<linearGradient
|
||||||
|
spreadMethod="pad"
|
||||||
|
y2="0.30000001"
|
||||||
|
x2="-0.1"
|
||||||
|
y1="1.2"
|
||||||
|
x1="0.30000001"
|
||||||
|
id="3d_gradient2-logo-24885591-b378-4c55-b87b-b7d42ed10694">
|
||||||
|
<stop
|
||||||
|
id="stop211929"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#ffffff"
|
||||||
|
offset="0%" />
|
||||||
|
<stop
|
||||||
|
id="stop211931"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#000000"
|
||||||
|
offset="100%" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="rotate(-30)"
|
||||||
|
spreadMethod="pad"
|
||||||
|
y2="0.30000001"
|
||||||
|
x2="-0.1"
|
||||||
|
y1="1.2"
|
||||||
|
x1="0.30000001"
|
||||||
|
id="3d_gradient3-logo-24885591-b378-4c55-b87b-b7d42ed10694">
|
||||||
|
<stop
|
||||||
|
id="stop211934"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#ffffff"
|
||||||
|
offset="0%" />
|
||||||
|
<stop
|
||||||
|
id="stop211936"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#cccccc"
|
||||||
|
offset="50%" />
|
||||||
|
<stop
|
||||||
|
id="stop211938"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#000000"
|
||||||
|
offset="100%" />
|
||||||
|
</linearGradient>
|
||||||
|
<g
|
||||||
|
id="logo-group"
|
||||||
|
transform="translate(-185.54797,-175.3735)">
|
||||||
|
<image
|
||||||
|
xlink:href=""
|
||||||
|
id="container"
|
||||||
|
x="272"
|
||||||
|
y="144"
|
||||||
|
width="480"
|
||||||
|
height="480"
|
||||||
|
style="display:none" />
|
||||||
|
<image
|
||||||
|
xlink:href=""
|
||||||
|
id="icon_container"
|
||||||
|
style="display:none"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="0"
|
||||||
|
height="0" />
|
||||||
|
<g
|
||||||
|
id="g18"
|
||||||
|
transform="translate(-91.179677,-177.97015)">
|
||||||
|
<path
|
||||||
|
style="fill:#388ec7;fill-opacity:1;stroke:none;stroke-width:1.41128"
|
||||||
|
d="m 650.16134,532.23713 -33.31908,17.65778 -13.63054,6.42952 -13.63053,-6.42952 -33.31907,-17.65778 c 0,5.32502 -2.24747,16.12101 0.77828,20.72433 1.84892,2.81293 6.84753,4.46784 9.82323,6.09432 8.26868,4.51957 16.72019,8.751 24.98932,13.27082 3.1083,1.69895 7.62988,5.16897 11.35877,5.21476 3.70778,0.0455 8.2451,-3.55102 11.35878,-5.19752 8.33909,-4.40967 16.72005,-8.76818 24.98932,-13.28806 3.05286,-1.66866 8.68533,-3.49778 10.14461,-6.69253 2.3911,-5.23485 0.45691,-14.46175 0.45691,-20.12612 m -46.19236,16.00215 c 3.59731,-0.51544 7.48607,-3.47354 10.60152,-5.12097 7.58911,-4.0131 15.20174,-8.00941 22.71755,-12.13797 3.53683,-1.94283 9.05374,-3.7013 11.65911,-6.69847 3.28982,-3.78453 1.93068,-13.45759 -2.58668,-15.74886 -4.7363,-2.40229 -8.80251,1.12086 -12.85868,3.25251 l -21.20306,11.2665 c -2.56736,1.35182 -6.01463,4.01777 -9.08702,4.01777 -3.29073,0 -7.12524,-2.97742 -9.84427,-4.47101 -6.50984,-3.57597 -13.17851,-6.90091 -19.68854,-10.47698 -2.85668,-1.56921 -7.10587,-4.85415 -10.60153,-4.52437 -7.2756,0.6864 -9.69308,11.97712 -5.60111,16.68444 2.43875,2.80547 7.56529,4.49972 10.90188,6.26408 7.83167,4.14137 15.6667,8.28474 23.4748,12.46456 3.21433,1.72068 8.18431,5.79216 12.11603,5.22877 m 30.29007,-45.33762 v -1.39693 l -18.17404,-8.90973 -12.11603,4.65427 -12.87329,-4.72164 -18.93129,8.9771 v 1.39693 l 21.20305,11.17542 9.84427,4.34169 9.84428,-4.33415 z"
|
||||||
|
id="path17" />
|
||||||
|
<path
|
||||||
|
d="m 388.93329,654.58136 c 2.112,0 3.744,-1.632 3.744,-3.744 v -24.576 l 8.544,-8.64 26.112,35.328 c 0.768,1.152 1.824,1.632 3.168,1.632 2.688,0 4.512,-3.36 2.688,-5.952 l -26.592,-36.288 26.304,-26.304 c 2.304,-2.592 1.248,-6.432 -2.208,-6.432 -1.152,0 -2.016,0.384 -2.976,1.344 l -35.04,35.04 v -32.64 c 0,-2.112 -1.632,-3.744 -3.744,-3.744 -2.016,0 -3.744,1.632 -3.744,3.744 v 67.488 c 0,2.112 1.728,3.744 3.744,3.744 z m 75.55212,0.48 c 8.448,0 15.648,-3.84 19.968,-9.984 v 5.856 c 0,2.112 1.536,3.648 3.744,3.648 2.112,0 3.744,-1.536 3.744,-3.648 v -22.56 c -0.096,-15.264 -11.52,-26.784 -26.688,-26.784 -15.264,0 -26.688,11.52 -26.688,26.784 0,15.264 11.136,26.688 25.92,26.688 z m 0.768,-6.72 c -11.04,0 -19.488,-8.544 -19.488,-19.968 0,-11.424 8.448,-20.064 19.488,-20.064 11.04,0 19.392,8.64 19.392,20.064 0,11.424 -8.352,19.968 -19.392,19.968 z m 61.63201,6.24 h 2.016 c 2.304,0 4.032,-1.536 4.032,-3.648 0,-2.208 -1.44,-3.744 -3.456,-3.744 h -2.592 c -5.952,0 -10.272,-4.608 -10.272,-11.136 v -25.632 h 10.848 c 2.016,0 3.36,-1.344 3.36,-3.168 0,-1.92 -1.344,-3.264 -3.36,-3.264 h -10.848 v -14.88 c 0,-2.208 -1.536,-3.744 -3.744,-3.744 -2.112,0 -3.648,1.536 -3.648,3.744 v 14.88 h -6.24 c -2.016,0 -3.36,1.344 -3.36,3.264 0,1.824 1.344,3.168 3.36,3.168 h 6.24 v 25.632 c 0,10.656 7.392,18.432 17.664,18.528 z m 41.85604,0.48 c 5.952,0 13.248,-2.592 17.472,-6.24 1.536,-1.344 1.44,-3.36 -0.192,-4.8 -1.344,-1.056 -3.264,-0.96 -4.704,0.192 -2.784,2.4 -7.968,4.224 -12.576,4.224 -10.656,0 -18.528,-7.2 -19.584,-17.664 h 38.784 c 2.016,0 3.456,-1.344 3.456,-3.36 0,-15.072 -9.6,-25.824 -24.096,-25.824 -14.784,0 -25.152,11.136 -25.152,26.784 0,15.648 11.04,26.688 26.592,26.688 z m -1.44,-46.848 c 9.696,0 16.224,6.72 17.184,16.416 h -35.136 c 1.344,-9.696 8.16,-16.416 17.952,-16.416 z m 40.32003,46.368 c 2.208,0 3.648,-1.44 3.648,-3.648 v -28.416 c 0,-7.968 7.2,-14.016 16.704,-14.016 9.792,0 17.184,5.664 17.184,17.472 v 24.96 c 0,2.112 1.632,3.648 3.744,3.648 2.016,0 3.648,-1.536 3.648,-3.648 v -24.96 c 0,-15.84 -10.272,-24.48 -23.808,-24.48 -7.104,0 -13.344,2.88 -17.472,7.584 v -3.264 c 0,-2.208 -1.44,-3.744 -3.648,-3.744 -2.208,0 -3.744,1.536 -3.744,3.744 v 45.12 c 0,2.208 1.536,3.648 3.744,3.648 z m 84.384,0.48 c 8.448,0 15.648,-3.84 19.968,-9.984 v 5.856 c 0,2.112 1.536,3.648 3.744,3.648 2.112,0 3.744,-1.536 3.744,-3.648 v -22.56 c -0.096,-15.264 -11.52,-26.784 -26.688,-26.784 -15.264,0 -26.688,11.52 -26.688,26.784 0,15.264 11.136,26.688 25.92,26.688 z m 0.768,-6.72 c -11.04,0 -19.488,-8.544 -19.488,-19.968 0,-11.424 8.448,-20.064 19.488,-20.064 11.04,0 19.392,8.64 19.392,20.064 0,11.424 -8.352,19.968 -19.392,19.968 z m 44.73601,6.24 c 2.304,0 3.648,-1.344 3.648,-3.648 v -28.704 c 0,-8.928 7.872,-14.688 18.624,-13.728 3.168,0.192 5.76,0.768 6.432,-2.112 0.768,-3.168 -2.688,-4.896 -8.64,-4.896 -6.72,0 -12.672,3.168 -16.416,8.352 v -4.128 c 0,-2.304 -1.344,-3.648 -3.648,-3.648 -2.304,0 -3.648,1.344 -3.648,3.648 v 45.216 c 0,2.304 1.344,3.648 3.648,3.648 z m 49.34401,22.848 c 1.248,0 2.208,-0.768 2.784,-2.208 l 31.104,-68.352 c 0.96,-2.112 0.288,-3.648 -1.824,-4.512 -2.112,-0.864 -3.648,-0.288 -4.608,1.728 l -17.856,39.36 -18.72,-39.456 c -0.864,-1.92 -2.688,-2.496 -4.608,-1.632 -1.92,0.864 -2.688,2.688 -1.728,4.608 l 21.408,44.352 0.096,0.096 -9.6,21.024 c -0.96,2.112 -0.288,3.744 1.824,4.608 0.576,0.288 1.152,0.384 1.728,0.384 z"
|
||||||
|
id="text18"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
aria-label="Katenary" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
style="fill:#388ec7;fill-opacity:1;stroke:none;stroke-width:1.41128"
|
||||||
|
d="m 558.98167,600.50526 -33.31908,17.65778 -13.63054,6.42952 -13.63053,-6.42952 -33.31907,-17.65778 c 0,5.32502 -2.24747,16.12101 0.77828,20.72433 1.84892,2.81293 6.84753,4.46784 9.82323,6.09432 8.26868,4.51957 16.72019,8.751 24.98932,13.27082 3.1083,1.69895 7.62988,5.16897 11.35877,5.21476 3.70778,0.0455 8.2451,-3.55102 11.35878,-5.19752 8.33909,-4.40967 16.72005,-8.76818 24.98932,-13.28806 3.05286,-1.66866 8.68533,-3.49778 10.14461,-6.69253 2.3911,-5.23485 0.45691,-14.46175 0.45691,-20.12612 m -46.19236,16.00215 c 3.59731,-0.51544 7.48607,-3.47354 10.60152,-5.12097 7.58911,-4.0131 15.20174,-8.00941 22.71755,-12.13797 3.53683,-1.94283 9.05374,-3.7013 11.65911,-6.69847 3.28982,-3.78453 1.93068,-13.45759 -2.58668,-15.74886 -4.7363,-2.40229 -8.80251,1.12086 -12.85868,3.25251 l -21.20306,11.2665 c -2.56736,1.35182 -6.01463,4.01777 -9.08702,4.01777 -3.29073,0 -7.12524,-2.97742 -9.84427,-4.47101 -6.50984,-3.57597 -13.17851,-6.90091 -19.68854,-10.47698 -2.85668,-1.56921 -7.10587,-4.85415 -10.60153,-4.52437 -7.2756,0.6864 -9.69308,11.97712 -5.60111,16.68444 2.43875,2.80547 7.56529,4.49972 10.90188,6.26408 7.83167,4.14137 15.6667,8.28474 23.4748,12.46456 3.21433,1.72068 8.18431,5.79216 12.11603,5.22877 m 30.29007,-45.33762 v -1.39693 l -18.17404,-8.90973 -12.11603,4.65427 -12.87329,-4.72164 -18.93129,8.9771 v 1.39693 l 21.20305,11.17542 9.84427,4.34169 9.84428,-4.33415 z"
|
||||||
|
id="path18" />
|
||||||
|
<g
|
||||||
|
id="g19">
|
||||||
|
<path
|
||||||
|
style="fill:#388ec7;fill-opacity:1;stroke:none;stroke-width:1.41128"
|
||||||
|
d="m 280.25003,221.48792 -33.31908,17.65778 -13.63054,6.42952 -13.63053,-6.42952 -33.31907,-17.65778 c 0,5.32502 -2.24747,16.12101 0.77828,20.72433 1.84892,2.81293 6.84753,4.46784 9.82323,6.09432 8.26868,4.51957 16.72019,8.751 24.98932,13.27082 3.1083,1.69895 7.62988,5.16897 11.35877,5.21476 3.70778,0.0455 8.2451,-3.55102 11.35878,-5.19752 8.33909,-4.40967 16.72005,-8.76818 24.98932,-13.28806 3.05286,-1.66866 8.68533,-3.49778 10.14461,-6.69253 2.3911,-5.23485 0.45691,-14.46175 0.45691,-20.12612 m -46.19236,16.00215 c 3.59731,-0.51544 7.48607,-3.47354 10.60152,-5.12097 7.58911,-4.0131 15.20174,-8.00941 22.71755,-12.13797 3.53683,-1.94283 9.05374,-3.7013 11.65911,-6.69847 3.28982,-3.78453 1.93068,-13.45759 -2.58668,-15.74886 -4.7363,-2.40229 -8.80251,1.12086 -12.85868,3.25251 l -21.20306,11.2665 c -2.56736,1.35182 -6.01463,4.01777 -9.08702,4.01777 -3.29073,0 -7.12524,-2.97742 -9.84427,-4.47101 -6.50984,-3.57597 -13.17851,-6.90091 -19.68854,-10.47698 -2.85668,-1.56921 -7.10587,-4.85415 -10.60153,-4.52437 -7.2756,0.6864 -9.69308,11.97712 -5.60111,16.68444 2.43875,2.80547 7.56529,4.49972 10.90188,6.26408 7.83167,4.14137 15.6667,8.28474 23.4748,12.46456 3.21433,1.72068 8.18431,5.79216 12.11603,5.22877 m 30.29007,-45.33762 v -1.39693 l -18.17404,-8.90973 -12.11603,4.65427 -12.87329,-4.72164 -18.93129,8.9771 v 1.39693 l 21.20305,11.17542 9.84427,4.34169 9.84428,-4.33415 z"
|
||||||
|
id="path19" />
|
||||||
|
<path
|
||||||
|
d="m 297.75361,250.3495 c 2.112,0 3.744,-1.632 3.744,-3.744 v -24.576 l 8.544,-8.64 26.112,35.328 c 0.768,1.152 1.824,1.632 3.168,1.632 2.688,0 4.512,-3.36 2.688,-5.952 l -26.592,-36.288 26.304,-26.304 c 2.304,-2.592 1.248,-6.432 -2.208,-6.432 -1.152,0 -2.016,0.384 -2.976,1.344 l -35.04,35.04 v -32.64 c 0,-2.112 -1.632,-3.744 -3.744,-3.744 -2.016,0 -3.744,1.632 -3.744,3.744 v 67.488 c 0,2.112 1.728,3.744 3.744,3.744 z m 75.55211,0.48 c 8.448,0 15.648,-3.84 19.968,-9.984 v 5.856 c 0,2.112 1.536,3.648 3.744,3.648 2.112,0 3.744,-1.536 3.744,-3.648 v -22.56 c -0.096,-15.264 -11.52,-26.784 -26.688,-26.784 -15.264,0 -26.688,11.52 -26.688,26.784 0,15.264 11.136,26.688 25.92,26.688 z m 0.768,-6.72 c -11.04,0 -19.488,-8.544 -19.488,-19.968 0,-11.424 8.448,-20.064 19.488,-20.064 11.04,0 19.392,8.64 19.392,20.064 0,11.424 -8.352,19.968 -19.392,19.968 z m 61.63201,6.24 h 2.016 c 2.304,0 4.032,-1.536 4.032,-3.648 0,-2.208 -1.44,-3.744 -3.456,-3.744 h -2.592 c -5.952,0 -10.272,-4.608 -10.272,-11.136 v -25.632 h 10.848 c 2.016,0 3.36,-1.344 3.36,-3.168 0,-1.92 -1.344,-3.264 -3.36,-3.264 h -10.848 v -14.88 c 0,-2.208 -1.536,-3.744 -3.744,-3.744 -2.112,0 -3.648,1.536 -3.648,3.744 v 14.88 h -6.24 c -2.016,0 -3.36,1.344 -3.36,3.264 0,1.824 1.344,3.168 3.36,3.168 h 6.24 v 25.632 c 0,10.656 7.392,18.432 17.664,18.528 z m 41.85604,0.48 c 5.952,0 13.248,-2.592 17.472,-6.24 1.536,-1.344 1.44,-3.36 -0.192,-4.8 -1.344,-1.056 -3.264,-0.96 -4.704,0.192 -2.784,2.4 -7.968,4.224 -12.576,4.224 -10.656,0 -18.528,-7.2 -19.584,-17.664 h 38.784 c 2.016,0 3.456,-1.344 3.456,-3.36 0,-15.072 -9.6,-25.824 -24.096,-25.824 -14.784,0 -25.152,11.136 -25.152,26.784 0,15.648 11.04,26.688 26.592,26.688 z m -1.44,-46.848 c 9.696,0 16.224,6.72 17.184,16.416 h -35.136 c 1.344,-9.696 8.16,-16.416 17.952,-16.416 z m 40.32003,46.368 c 2.208,0 3.648,-1.44 3.648,-3.648 v -28.416 c 0,-7.968 7.2,-14.016 16.704,-14.016 9.792,0 17.184,5.664 17.184,17.472 v 24.96 c 0,2.112 1.632,3.648 3.744,3.648 2.016,0 3.648,-1.536 3.648,-3.648 v -24.96 c 0,-15.84 -10.272,-24.48 -23.808,-24.48 -7.104,0 -13.344,2.88 -17.472,7.584 v -3.264 c 0,-2.208 -1.44,-3.744 -3.648,-3.744 -2.208,0 -3.744,1.536 -3.744,3.744 v 45.12 c 0,2.208 1.536,3.648 3.744,3.648 z m 84.384,0.48 c 8.448,0 15.648,-3.84 19.968,-9.984 v 5.856 c 0,2.112 1.536,3.648 3.744,3.648 2.112,0 3.744,-1.536 3.744,-3.648 v -22.56 c -0.096,-15.264 -11.52,-26.784 -26.688,-26.784 -15.264,0 -26.688,11.52 -26.688,26.784 0,15.264 11.136,26.688 25.92,26.688 z m 0.768,-6.72 c -11.04,0 -19.488,-8.544 -19.488,-19.968 0,-11.424 8.448,-20.064 19.488,-20.064 11.04,0 19.392,8.64 19.392,20.064 0,11.424 -8.352,19.968 -19.392,19.968 z m 44.73601,6.24 c 2.304,0 3.648,-1.344 3.648,-3.648 v -28.704 c 0,-8.928 7.872,-14.688 18.624,-13.728 3.168,0.192 5.76,0.768 6.432,-2.112 0.768,-3.168 -2.688,-4.896 -8.64,-4.896 -6.72,0 -12.672,3.168 -16.416,8.352 v -4.128 c 0,-2.304 -1.344,-3.648 -3.648,-3.648 -2.304,0 -3.648,1.344 -3.648,3.648 v 45.216 c 0,2.304 1.344,3.648 3.648,3.648 z m 49.34402,22.848 c 1.248,0 2.208,-0.768 2.784,-2.208 l 31.104,-68.352 c 0.96,-2.112 0.288,-3.648 -1.824,-4.512 -2.112,-0.864 -3.648,-0.288 -4.608,1.728 l -17.856,39.36 -18.72,-39.456 c -0.864,-1.92 -2.688,-2.496 -4.608,-1.632 -1.92,0.864 -2.688,2.688 -1.728,4.608 l 21.408,44.352 0.096,0.096 -9.6,21.024 c -0.96,2.112 -0.288,3.744 1.824,4.608 0.576,0.288 1.152,0.384 1.728,0.384 z"
|
||||||
|
id="text19"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
aria-label="Katenary" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 14 KiB |
121
doc/docs/statics/logo-dark.svg
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
id="svg211948"
|
||||||
|
viewBox="0 0 489.26056 97.824219"
|
||||||
|
height="97.824219"
|
||||||
|
width="489.26056"
|
||||||
|
version="1.1"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<metadata
|
||||||
|
id="metadata211954">
|
||||||
|
<rdf:rdf>
|
||||||
|
<cc:work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:work>
|
||||||
|
</rdf:rdf>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs211952" />
|
||||||
|
<linearGradient
|
||||||
|
spreadMethod="pad"
|
||||||
|
y2="0.30000001"
|
||||||
|
x2="-0.1"
|
||||||
|
y1="1.2"
|
||||||
|
x1="0.30000001"
|
||||||
|
id="3d_gradient2-logo-24885591-b378-4c55-b87b-b7d42ed10694">
|
||||||
|
<stop
|
||||||
|
id="stop211929"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#ffffff"
|
||||||
|
offset="0%" />
|
||||||
|
<stop
|
||||||
|
id="stop211931"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#000000"
|
||||||
|
offset="100%" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="rotate(-30)"
|
||||||
|
spreadMethod="pad"
|
||||||
|
y2="0.30000001"
|
||||||
|
x2="-0.1"
|
||||||
|
y1="1.2"
|
||||||
|
x1="0.30000001"
|
||||||
|
id="3d_gradient3-logo-24885591-b378-4c55-b87b-b7d42ed10694">
|
||||||
|
<stop
|
||||||
|
id="stop211934"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#ffffff"
|
||||||
|
offset="0%" />
|
||||||
|
<stop
|
||||||
|
id="stop211936"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#cccccc"
|
||||||
|
offset="50%" />
|
||||||
|
<stop
|
||||||
|
id="stop211938"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#000000"
|
||||||
|
offset="100%" />
|
||||||
|
</linearGradient>
|
||||||
|
<g
|
||||||
|
id="logo-group"
|
||||||
|
transform="translate(-331.21094,-211.65039)">
|
||||||
|
<path
|
||||||
|
d="m 773.83594,234.02344 c -0.4545,0.0375 -0.92821,0.1629 -1.40821,0.3789 -1.91999,0.864 -2.68851,2.68743 -1.72851,4.60743 l 21.4082,44.35351 0.0957,0.0957 -9.5996,21.02344 c -0.96,2.112 -0.28778,3.74342 1.82421,4.60742 0.576,0.288 1.15252,0.38477 1.72852,0.38477 1.248,0 2.2072,-0.76703 2.7832,-2.20703 l 31.10352,-68.35352 c 0.96,-2.112 0.28778,-3.64772 -1.82422,-4.51172 -2.112,-0.864 -3.64742,-0.28748 -4.60742,1.72852 l -17.85547,39.35937 -18.7207,-39.45507 c -0.648,-1.44 -1.83572,-2.12422 -3.19922,-2.01172 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path9" />
|
||||||
|
<path
|
||||||
|
d="m 692.07617,233.63477 c -15.26398,0 -26.68945,11.51921 -26.68945,26.7832 0,15.26398 11.13594,26.68945 25.91992,26.68945 8.44799,0 15.64875,-3.84038 19.96875,-9.98437 v 5.85547 c 0,2.11199 1.53614,3.64843 3.74414,3.64843 2.112,0 3.74414,-1.53644 3.74414,-3.64843 v -22.56055 c -0.096,-15.26399 -11.51951,-26.7832 -26.6875,-26.7832 z m 0,6.7207 c 11.03999,0 19.39063,8.63851 19.39063,20.0625 0,11.42399 -8.35064,19.96875 -19.39063,19.96875 -11.03999,0 -19.48828,-8.54476 -19.48828,-19.96875 0,-11.42399 8.44829,-20.0625 19.48828,-20.0625 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path8" />
|
||||||
|
<path
|
||||||
|
d="m 566.60352,233.63477 c -14.78399,0 -25.15235,11.13521 -25.15235,26.7832 0,15.64798 11.03981,26.68945 26.5918,26.68945 5.95199,0 13.24866,-2.59224 17.47265,-6.24023 1.536,-1.344 1.4406,-3.36079 -0.1914,-4.80078 -1.344,-1.056 -3.26508,-0.9606 -4.70508,0.1914 -2.784,2.4 -7.96818,4.22461 -12.57617,4.22461 -10.65599,0 -18.52799,-7.20007 -19.58399,-17.66406 h 38.78516 c 2.016,0 3.45508,-1.34338 3.45508,-3.35938 0,-15.07198 -9.59972,-25.82421 -24.0957,-25.82421 z m 0,6.62304 c 9.69599,0 16.22359,6.72003 17.18359,16.41602 h -35.13477 c 1.344,-9.69599 8.15919,-16.41602 17.95118,-16.41602 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path7" />
|
||||||
|
<path
|
||||||
|
d="m 756.875,233.53906 c -6.71999,0 -12.67202,3.16757 -16.41602,8.35156 v -4.1289 c 0,-2.304 -1.34248,-3.64649 -3.64648,-3.64649 -2.304,0 -3.64844,1.34249 -3.64844,3.64649 v 45.2168 c 0,2.30399 1.34444,3.64843 3.64844,3.64843 2.304,0 3.64648,-1.34444 3.64648,-3.64843 v -28.70313 c 0,-8.92799 7.87302,-14.68851 18.625,-13.72852 3.168,0.192 5.75965,0.76867 6.43164,-2.11132 0.768,-3.168 -2.68863,-4.89649 -8.64062,-4.89649 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path6" />
|
||||||
|
<path
|
||||||
|
d="m 628.04297,233.53906 c -7.10399,0 -13.34271,2.87999 -17.4707,7.58399 v -3.26368 c 0,-2.20799 -1.44044,-3.74414 -3.64844,-3.74414 -2.208,0 -3.74414,1.53615 -3.74414,3.74414 v 45.11915 c 0,2.20799 1.53614,3.64843 3.74414,3.64843 2.208,0 3.64844,-1.44044 3.64844,-3.64843 V 254.5625 c 0,-7.96799 7.19913,-14.01563 16.70312,-14.01563 9.79199,0 17.18359,5.66467 17.18359,17.47266 v 24.95899 c 0,2.11199 1.63215,3.64843 3.74414,3.64843 2.016,0 3.64844,-1.53644 3.64844,-3.64843 v -24.95899 c 0,-15.83998 -10.2726,-24.48047 -23.80859,-24.48047 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path5" />
|
||||||
|
<path
|
||||||
|
d="m 512.17187,217.41016 c -2.11199,0 -3.64843,1.53614 -3.64843,3.74414 v 14.88086 h -6.24024 c -2.01599,0 -3.35937,1.34367 -3.35937,3.26367 0,1.824 1.34338,3.16797 3.35937,3.16797 h 6.24024 v 25.63281 c 0,10.65599 7.39207,18.43134 17.66406,18.52734 h 2.01562 c 2.304,0 4.03321,-1.53644 4.03321,-3.64843 0,-2.208 -1.44104,-3.74415 -3.45703,-3.74415 h -2.5918 c -5.95199,0 -10.27148,-4.60677 -10.27148,-11.13476 V 242.4668 h 10.84765 c 2.016,0 3.35938,-1.34397 3.35938,-3.16797 0,-1.92 -1.34338,-3.26367 -3.35938,-3.26367 H 515.91602 V 221.1543 c 0,-2.208 -1.53615,-3.74414 -3.74415,-3.74414 z"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path4" />
|
||||||
|
<image
|
||||||
|
xlink:href=""
|
||||||
|
id="container"
|
||||||
|
x="272"
|
||||||
|
y="144"
|
||||||
|
width="480"
|
||||||
|
height="480"
|
||||||
|
style="display:none" />
|
||||||
|
<image
|
||||||
|
xlink:href=""
|
||||||
|
id="icon_container"
|
||||||
|
style="display:none"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="0"
|
||||||
|
height="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#388ec7;fill-opacity:1;stroke:none;stroke-width:1.41128"
|
||||||
|
d="m 488.71354,251.36014 -33.31908,17.65778 -13.63054,6.42952 -13.63053,-6.42952 -33.31907,-17.65778 c 0,5.32502 -2.24747,16.12101 0.77828,20.72433 1.84892,2.81293 6.84753,4.46784 9.82323,6.09432 8.26868,4.51957 16.72019,8.751 24.98932,13.27082 3.1083,1.69895 7.62988,5.16897 11.35877,5.21476 3.70778,0.0455 8.2451,-3.55102 11.35878,-5.19752 8.33909,-4.40967 16.72005,-8.76818 24.98932,-13.28806 3.05286,-1.66866 8.68533,-3.49778 10.14461,-6.69253 2.3911,-5.23485 0.45691,-14.46175 0.45691,-20.12612 m -46.19236,16.00215 c 3.59731,-0.51544 7.48607,-3.47354 10.60152,-5.12097 7.58911,-4.0131 15.20174,-8.00941 22.71755,-12.13797 3.53683,-1.94283 9.05374,-3.7013 11.65911,-6.69847 3.28982,-3.78453 1.93068,-13.45759 -2.58668,-15.74886 -4.7363,-2.40229 -8.80251,1.12086 -12.85868,3.25251 l -21.20306,11.2665 c -2.56736,1.35182 -6.01463,4.01777 -9.08702,4.01777 -3.29073,0 -7.12524,-2.97742 -9.84427,-4.47101 -6.50984,-3.57597 -13.17851,-6.90091 -19.68854,-10.47698 -2.85668,-1.56921 -7.10587,-4.85415 -10.60153,-4.52437 -7.2756,0.6864 -9.69308,11.97712 -5.60111,16.68444 2.43875,2.80547 7.56529,4.49972 10.90188,6.26408 7.83167,4.14137 15.6667,8.28474 23.4748,12.46456 3.21433,1.72068 8.18431,5.79216 12.11603,5.22877 m 30.29007,-45.33762 v -1.39693 l -18.17404,-8.90973 -12.11603,4.65427 -12.87329,-4.72164 -18.93129,8.9771 v 1.39693 l 21.20305,11.17542 9.84427,4.34169 9.84428,-4.33415 z"
|
||||||
|
id="path1" />
|
||||||
|
<path
|
||||||
|
d="m 334.95508,211.65039 c -2.016,0 -3.74414,1.63214 -3.74414,3.74414 v 67.48828 c 0,2.112 1.72814,3.74414 3.74414,3.74414 2.112,0 3.74414,-1.63214 3.74414,-3.74414 v -24.57617 l 8.54492,-8.64062 26.11133,35.32812 c 0.768,1.152 1.82397,1.63281 3.16797,1.63281 2.68799,0 4.5115,-3.36112 2.6875,-5.95312 l -26.5918,-36.28711 26.30469,-26.30469 c 2.304,-2.592 1.24701,-6.43164 -2.20899,-6.43164 -1.152,0 -2.01461,0.38375 -2.97461,1.34375 l -35.04101,35.04102 v -32.64063 c 0,-2.112 -1.63214,-3.74414 -3.74414,-3.74414 z"
|
||||||
|
style="fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
id="path3" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.7 KiB |
BIN
doc/docs/statics/logo-vertical.png
Normal file
After Width: | Height: | Size: 14 KiB |
118
doc/docs/statics/logo-vertical.svg
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
id="svg211948"
|
||||||
|
viewBox="0 0 435.98074 184.9017"
|
||||||
|
height="184.9017"
|
||||||
|
width="435.98074"
|
||||||
|
version="1.1"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<metadata
|
||||||
|
id="metadata211954">
|
||||||
|
<rdf:rdf>
|
||||||
|
<cc:work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:work>
|
||||||
|
</rdf:rdf>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs211952" />
|
||||||
|
<linearGradient
|
||||||
|
spreadMethod="pad"
|
||||||
|
y2="0.30000001"
|
||||||
|
x2="-0.1"
|
||||||
|
y1="1.2"
|
||||||
|
x1="0.30000001"
|
||||||
|
id="3d_gradient2-logo-24885591-b378-4c55-b87b-b7d42ed10694">
|
||||||
|
<stop
|
||||||
|
id="stop211929"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#ffffff"
|
||||||
|
offset="0%" />
|
||||||
|
<stop
|
||||||
|
id="stop211931"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#000000"
|
||||||
|
offset="100%" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="rotate(-30)"
|
||||||
|
spreadMethod="pad"
|
||||||
|
y2="0.30000001"
|
||||||
|
x2="-0.1"
|
||||||
|
y1="1.2"
|
||||||
|
x1="0.30000001"
|
||||||
|
id="3d_gradient3-logo-24885591-b378-4c55-b87b-b7d42ed10694">
|
||||||
|
<stop
|
||||||
|
id="stop211934"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#ffffff"
|
||||||
|
offset="0%" />
|
||||||
|
<stop
|
||||||
|
id="stop211936"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#cccccc"
|
||||||
|
offset="50%" />
|
||||||
|
<stop
|
||||||
|
id="stop211938"
|
||||||
|
stop-opacity="1"
|
||||||
|
stop-color="#000000"
|
||||||
|
offset="100%" />
|
||||||
|
</linearGradient>
|
||||||
|
<g
|
||||||
|
id="logo-group"
|
||||||
|
transform="translate(-294.00961,-314.5575)">
|
||||||
|
<image
|
||||||
|
xlink:href=""
|
||||||
|
id="container"
|
||||||
|
x="272"
|
||||||
|
y="144"
|
||||||
|
width="480"
|
||||||
|
height="480"
|
||||||
|
style="display:none" />
|
||||||
|
<image
|
||||||
|
xlink:href=""
|
||||||
|
id="icon_container"
|
||||||
|
style="display:none"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="0"
|
||||||
|
height="0" />
|
||||||
|
<g
|
||||||
|
id="g18"
|
||||||
|
transform="translate(-91.179677,-177.97015)">
|
||||||
|
<path
|
||||||
|
style="fill:#388ec7;fill-opacity:1;stroke:none;stroke-width:1.41128"
|
||||||
|
d="m 650.16134,532.23713 -33.31908,17.65778 -13.63054,6.42952 -13.63053,-6.42952 -33.31907,-17.65778 c 0,5.32502 -2.24747,16.12101 0.77828,20.72433 1.84892,2.81293 6.84753,4.46784 9.82323,6.09432 8.26868,4.51957 16.72019,8.751 24.98932,13.27082 3.1083,1.69895 7.62988,5.16897 11.35877,5.21476 3.70778,0.0455 8.2451,-3.55102 11.35878,-5.19752 8.33909,-4.40967 16.72005,-8.76818 24.98932,-13.28806 3.05286,-1.66866 8.68533,-3.49778 10.14461,-6.69253 2.3911,-5.23485 0.45691,-14.46175 0.45691,-20.12612 m -46.19236,16.00215 c 3.59731,-0.51544 7.48607,-3.47354 10.60152,-5.12097 7.58911,-4.0131 15.20174,-8.00941 22.71755,-12.13797 3.53683,-1.94283 9.05374,-3.7013 11.65911,-6.69847 3.28982,-3.78453 1.93068,-13.45759 -2.58668,-15.74886 -4.7363,-2.40229 -8.80251,1.12086 -12.85868,3.25251 l -21.20306,11.2665 c -2.56736,1.35182 -6.01463,4.01777 -9.08702,4.01777 -3.29073,0 -7.12524,-2.97742 -9.84427,-4.47101 -6.50984,-3.57597 -13.17851,-6.90091 -19.68854,-10.47698 -2.85668,-1.56921 -7.10587,-4.85415 -10.60153,-4.52437 -7.2756,0.6864 -9.69308,11.97712 -5.60111,16.68444 2.43875,2.80547 7.56529,4.49972 10.90188,6.26408 7.83167,4.14137 15.6667,8.28474 23.4748,12.46456 3.21433,1.72068 8.18431,5.79216 12.11603,5.22877 m 30.29007,-45.33762 v -1.39693 l -18.17404,-8.90973 -12.11603,4.65427 -12.87329,-4.72164 -18.93129,8.9771 v 1.39693 l 21.20305,11.17542 9.84427,4.34169 9.84428,-4.33415 z"
|
||||||
|
id="path17" />
|
||||||
|
<path
|
||||||
|
d="m 388.93329,654.58136 c 2.112,0 3.744,-1.632 3.744,-3.744 v -24.576 l 8.544,-8.64 26.112,35.328 c 0.768,1.152 1.824,1.632 3.168,1.632 2.688,0 4.512,-3.36 2.688,-5.952 l -26.592,-36.288 26.304,-26.304 c 2.304,-2.592 1.248,-6.432 -2.208,-6.432 -1.152,0 -2.016,0.384 -2.976,1.344 l -35.04,35.04 v -32.64 c 0,-2.112 -1.632,-3.744 -3.744,-3.744 -2.016,0 -3.744,1.632 -3.744,3.744 v 67.488 c 0,2.112 1.728,3.744 3.744,3.744 z m 75.55212,0.48 c 8.448,0 15.648,-3.84 19.968,-9.984 v 5.856 c 0,2.112 1.536,3.648 3.744,3.648 2.112,0 3.744,-1.536 3.744,-3.648 v -22.56 c -0.096,-15.264 -11.52,-26.784 -26.688,-26.784 -15.264,0 -26.688,11.52 -26.688,26.784 0,15.264 11.136,26.688 25.92,26.688 z m 0.768,-6.72 c -11.04,0 -19.488,-8.544 -19.488,-19.968 0,-11.424 8.448,-20.064 19.488,-20.064 11.04,0 19.392,8.64 19.392,20.064 0,11.424 -8.352,19.968 -19.392,19.968 z m 61.63201,6.24 h 2.016 c 2.304,0 4.032,-1.536 4.032,-3.648 0,-2.208 -1.44,-3.744 -3.456,-3.744 h -2.592 c -5.952,0 -10.272,-4.608 -10.272,-11.136 v -25.632 h 10.848 c 2.016,0 3.36,-1.344 3.36,-3.168 0,-1.92 -1.344,-3.264 -3.36,-3.264 h -10.848 v -14.88 c 0,-2.208 -1.536,-3.744 -3.744,-3.744 -2.112,0 -3.648,1.536 -3.648,3.744 v 14.88 h -6.24 c -2.016,0 -3.36,1.344 -3.36,3.264 0,1.824 1.344,3.168 3.36,3.168 h 6.24 v 25.632 c 0,10.656 7.392,18.432 17.664,18.528 z m 41.85604,0.48 c 5.952,0 13.248,-2.592 17.472,-6.24 1.536,-1.344 1.44,-3.36 -0.192,-4.8 -1.344,-1.056 -3.264,-0.96 -4.704,0.192 -2.784,2.4 -7.968,4.224 -12.576,4.224 -10.656,0 -18.528,-7.2 -19.584,-17.664 h 38.784 c 2.016,0 3.456,-1.344 3.456,-3.36 0,-15.072 -9.6,-25.824 -24.096,-25.824 -14.784,0 -25.152,11.136 -25.152,26.784 0,15.648 11.04,26.688 26.592,26.688 z m -1.44,-46.848 c 9.696,0 16.224,6.72 17.184,16.416 h -35.136 c 1.344,-9.696 8.16,-16.416 17.952,-16.416 z m 40.32003,46.368 c 2.208,0 3.648,-1.44 3.648,-3.648 v -28.416 c 0,-7.968 7.2,-14.016 16.704,-14.016 9.792,0 17.184,5.664 17.184,17.472 v 24.96 c 0,2.112 1.632,3.648 3.744,3.648 2.016,0 3.648,-1.536 3.648,-3.648 v -24.96 c 0,-15.84 -10.272,-24.48 -23.808,-24.48 -7.104,0 -13.344,2.88 -17.472,7.584 v -3.264 c 0,-2.208 -1.44,-3.744 -3.648,-3.744 -2.208,0 -3.744,1.536 -3.744,3.744 v 45.12 c 0,2.208 1.536,3.648 3.744,3.648 z m 84.384,0.48 c 8.448,0 15.648,-3.84 19.968,-9.984 v 5.856 c 0,2.112 1.536,3.648 3.744,3.648 2.112,0 3.744,-1.536 3.744,-3.648 v -22.56 c -0.096,-15.264 -11.52,-26.784 -26.688,-26.784 -15.264,0 -26.688,11.52 -26.688,26.784 0,15.264 11.136,26.688 25.92,26.688 z m 0.768,-6.72 c -11.04,0 -19.488,-8.544 -19.488,-19.968 0,-11.424 8.448,-20.064 19.488,-20.064 11.04,0 19.392,8.64 19.392,20.064 0,11.424 -8.352,19.968 -19.392,19.968 z m 44.73601,6.24 c 2.304,0 3.648,-1.344 3.648,-3.648 v -28.704 c 0,-8.928 7.872,-14.688 18.624,-13.728 3.168,0.192 5.76,0.768 6.432,-2.112 0.768,-3.168 -2.688,-4.896 -8.64,-4.896 -6.72,0 -12.672,3.168 -16.416,8.352 v -4.128 c 0,-2.304 -1.344,-3.648 -3.648,-3.648 -2.304,0 -3.648,1.344 -3.648,3.648 v 45.216 c 0,2.304 1.344,3.648 3.648,3.648 z m 49.34401,22.848 c 1.248,0 2.208,-0.768 2.784,-2.208 l 31.104,-68.352 c 0.96,-2.112 0.288,-3.648 -1.824,-4.512 -2.112,-0.864 -3.648,-0.288 -4.608,1.728 l -17.856,39.36 -18.72,-39.456 c -0.864,-1.92 -2.688,-2.496 -4.608,-1.632 -1.92,0.864 -2.688,2.688 -1.728,4.608 l 21.408,44.352 0.096,0.096 -9.6,21.024 c -0.96,2.112 -0.288,3.744 1.824,4.608 0.576,0.288 1.152,0.384 1.728,0.384 z"
|
||||||
|
id="text18"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
aria-label="Katenary" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
style="fill:#388ec7;fill-opacity:1;stroke:none;stroke-width:1.41128"
|
||||||
|
d="m 558.98167,600.50526 -33.31908,17.65778 -13.63054,6.42952 -13.63053,-6.42952 -33.31907,-17.65778 c 0,5.32502 -2.24747,16.12101 0.77828,20.72433 1.84892,2.81293 6.84753,4.46784 9.82323,6.09432 8.26868,4.51957 16.72019,8.751 24.98932,13.27082 3.1083,1.69895 7.62988,5.16897 11.35877,5.21476 3.70778,0.0455 8.2451,-3.55102 11.35878,-5.19752 8.33909,-4.40967 16.72005,-8.76818 24.98932,-13.28806 3.05286,-1.66866 8.68533,-3.49778 10.14461,-6.69253 2.3911,-5.23485 0.45691,-14.46175 0.45691,-20.12612 m -46.19236,16.00215 c 3.59731,-0.51544 7.48607,-3.47354 10.60152,-5.12097 7.58911,-4.0131 15.20174,-8.00941 22.71755,-12.13797 3.53683,-1.94283 9.05374,-3.7013 11.65911,-6.69847 3.28982,-3.78453 1.93068,-13.45759 -2.58668,-15.74886 -4.7363,-2.40229 -8.80251,1.12086 -12.85868,3.25251 l -21.20306,11.2665 c -2.56736,1.35182 -6.01463,4.01777 -9.08702,4.01777 -3.29073,0 -7.12524,-2.97742 -9.84427,-4.47101 -6.50984,-3.57597 -13.17851,-6.90091 -19.68854,-10.47698 -2.85668,-1.56921 -7.10587,-4.85415 -10.60153,-4.52437 -7.2756,0.6864 -9.69308,11.97712 -5.60111,16.68444 2.43875,2.80547 7.56529,4.49972 10.90188,6.26408 7.83167,4.14137 15.6667,8.28474 23.4748,12.46456 3.21433,1.72068 8.18431,5.79216 12.11603,5.22877 m 30.29007,-45.33762 v -1.39693 l -18.17404,-8.90973 -12.11603,4.65427 -12.87329,-4.72164 -18.93129,8.9771 v 1.39693 l 21.20305,11.17542 9.84427,4.34169 9.84428,-4.33415 z"
|
||||||
|
id="path18" />
|
||||||
|
<g
|
||||||
|
id="g19">
|
||||||
|
<path
|
||||||
|
style="fill:#388ec7;fill-opacity:1;stroke:none;stroke-width:1.41128"
|
||||||
|
d="m 280.25003,221.48792 -33.31908,17.65778 -13.63054,6.42952 -13.63053,-6.42952 -33.31907,-17.65778 c 0,5.32502 -2.24747,16.12101 0.77828,20.72433 1.84892,2.81293 6.84753,4.46784 9.82323,6.09432 8.26868,4.51957 16.72019,8.751 24.98932,13.27082 3.1083,1.69895 7.62988,5.16897 11.35877,5.21476 3.70778,0.0455 8.2451,-3.55102 11.35878,-5.19752 8.33909,-4.40967 16.72005,-8.76818 24.98932,-13.28806 3.05286,-1.66866 8.68533,-3.49778 10.14461,-6.69253 2.3911,-5.23485 0.45691,-14.46175 0.45691,-20.12612 m -46.19236,16.00215 c 3.59731,-0.51544 7.48607,-3.47354 10.60152,-5.12097 7.58911,-4.0131 15.20174,-8.00941 22.71755,-12.13797 3.53683,-1.94283 9.05374,-3.7013 11.65911,-6.69847 3.28982,-3.78453 1.93068,-13.45759 -2.58668,-15.74886 -4.7363,-2.40229 -8.80251,1.12086 -12.85868,3.25251 l -21.20306,11.2665 c -2.56736,1.35182 -6.01463,4.01777 -9.08702,4.01777 -3.29073,0 -7.12524,-2.97742 -9.84427,-4.47101 -6.50984,-3.57597 -13.17851,-6.90091 -19.68854,-10.47698 -2.85668,-1.56921 -7.10587,-4.85415 -10.60153,-4.52437 -7.2756,0.6864 -9.69308,11.97712 -5.60111,16.68444 2.43875,2.80547 7.56529,4.49972 10.90188,6.26408 7.83167,4.14137 15.6667,8.28474 23.4748,12.46456 3.21433,1.72068 8.18431,5.79216 12.11603,5.22877 m 30.29007,-45.33762 v -1.39693 l -18.17404,-8.90973 -12.11603,4.65427 -12.87329,-4.72164 -18.93129,8.9771 v 1.39693 l 21.20305,11.17542 9.84427,4.34169 9.84428,-4.33415 z"
|
||||||
|
id="path19" />
|
||||||
|
<path
|
||||||
|
d="m 297.75361,250.3495 c 2.112,0 3.744,-1.632 3.744,-3.744 v -24.576 l 8.544,-8.64 26.112,35.328 c 0.768,1.152 1.824,1.632 3.168,1.632 2.688,0 4.512,-3.36 2.688,-5.952 l -26.592,-36.288 26.304,-26.304 c 2.304,-2.592 1.248,-6.432 -2.208,-6.432 -1.152,0 -2.016,0.384 -2.976,1.344 l -35.04,35.04 v -32.64 c 0,-2.112 -1.632,-3.744 -3.744,-3.744 -2.016,0 -3.744,1.632 -3.744,3.744 v 67.488 c 0,2.112 1.728,3.744 3.744,3.744 z m 75.55211,0.48 c 8.448,0 15.648,-3.84 19.968,-9.984 v 5.856 c 0,2.112 1.536,3.648 3.744,3.648 2.112,0 3.744,-1.536 3.744,-3.648 v -22.56 c -0.096,-15.264 -11.52,-26.784 -26.688,-26.784 -15.264,0 -26.688,11.52 -26.688,26.784 0,15.264 11.136,26.688 25.92,26.688 z m 0.768,-6.72 c -11.04,0 -19.488,-8.544 -19.488,-19.968 0,-11.424 8.448,-20.064 19.488,-20.064 11.04,0 19.392,8.64 19.392,20.064 0,11.424 -8.352,19.968 -19.392,19.968 z m 61.63201,6.24 h 2.016 c 2.304,0 4.032,-1.536 4.032,-3.648 0,-2.208 -1.44,-3.744 -3.456,-3.744 h -2.592 c -5.952,0 -10.272,-4.608 -10.272,-11.136 v -25.632 h 10.848 c 2.016,0 3.36,-1.344 3.36,-3.168 0,-1.92 -1.344,-3.264 -3.36,-3.264 h -10.848 v -14.88 c 0,-2.208 -1.536,-3.744 -3.744,-3.744 -2.112,0 -3.648,1.536 -3.648,3.744 v 14.88 h -6.24 c -2.016,0 -3.36,1.344 -3.36,3.264 0,1.824 1.344,3.168 3.36,3.168 h 6.24 v 25.632 c 0,10.656 7.392,18.432 17.664,18.528 z m 41.85604,0.48 c 5.952,0 13.248,-2.592 17.472,-6.24 1.536,-1.344 1.44,-3.36 -0.192,-4.8 -1.344,-1.056 -3.264,-0.96 -4.704,0.192 -2.784,2.4 -7.968,4.224 -12.576,4.224 -10.656,0 -18.528,-7.2 -19.584,-17.664 h 38.784 c 2.016,0 3.456,-1.344 3.456,-3.36 0,-15.072 -9.6,-25.824 -24.096,-25.824 -14.784,0 -25.152,11.136 -25.152,26.784 0,15.648 11.04,26.688 26.592,26.688 z m -1.44,-46.848 c 9.696,0 16.224,6.72 17.184,16.416 h -35.136 c 1.344,-9.696 8.16,-16.416 17.952,-16.416 z m 40.32003,46.368 c 2.208,0 3.648,-1.44 3.648,-3.648 v -28.416 c 0,-7.968 7.2,-14.016 16.704,-14.016 9.792,0 17.184,5.664 17.184,17.472 v 24.96 c 0,2.112 1.632,3.648 3.744,3.648 2.016,0 3.648,-1.536 3.648,-3.648 v -24.96 c 0,-15.84 -10.272,-24.48 -23.808,-24.48 -7.104,0 -13.344,2.88 -17.472,7.584 v -3.264 c 0,-2.208 -1.44,-3.744 -3.648,-3.744 -2.208,0 -3.744,1.536 -3.744,3.744 v 45.12 c 0,2.208 1.536,3.648 3.744,3.648 z m 84.384,0.48 c 8.448,0 15.648,-3.84 19.968,-9.984 v 5.856 c 0,2.112 1.536,3.648 3.744,3.648 2.112,0 3.744,-1.536 3.744,-3.648 v -22.56 c -0.096,-15.264 -11.52,-26.784 -26.688,-26.784 -15.264,0 -26.688,11.52 -26.688,26.784 0,15.264 11.136,26.688 25.92,26.688 z m 0.768,-6.72 c -11.04,0 -19.488,-8.544 -19.488,-19.968 0,-11.424 8.448,-20.064 19.488,-20.064 11.04,0 19.392,8.64 19.392,20.064 0,11.424 -8.352,19.968 -19.392,19.968 z m 44.73601,6.24 c 2.304,0 3.648,-1.344 3.648,-3.648 v -28.704 c 0,-8.928 7.872,-14.688 18.624,-13.728 3.168,0.192 5.76,0.768 6.432,-2.112 0.768,-3.168 -2.688,-4.896 -8.64,-4.896 -6.72,0 -12.672,3.168 -16.416,8.352 v -4.128 c 0,-2.304 -1.344,-3.648 -3.648,-3.648 -2.304,0 -3.648,1.344 -3.648,3.648 v 45.216 c 0,2.304 1.344,3.648 3.648,3.648 z m 49.34402,22.848 c 1.248,0 2.208,-0.768 2.784,-2.208 l 31.104,-68.352 c 0.96,-2.112 0.288,-3.648 -1.824,-4.512 -2.112,-0.864 -3.648,-0.288 -4.608,1.728 l -17.856,39.36 -18.72,-39.456 c -0.864,-1.92 -2.688,-2.496 -4.608,-1.632 -1.92,0.864 -2.688,2.688 -1.728,4.608 l 21.408,44.352 0.096,0.096 -9.6,21.024 c -0.96,2.112 -0.288,3.744 1.824,4.608 0.576,0.288 1.152,0.384 1.728,0.384 z"
|
||||||
|
id="text19"
|
||||||
|
style="font-size:96px;line-height:0;font-family:Comfortaa;-inkscape-font-specification:Comfortaa;fill:#ff7f2a;stroke-width:51.0236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0"
|
||||||
|
aria-label="Katenary" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 14 KiB |
145
doc/docs/statics/logo.svg
Normal file
After Width: | Height: | Size: 21 KiB |
117
doc/docs/statics/main.css
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
:root {
|
||||||
|
--code-bg-color: var(--lt-color-gray-800);
|
||||||
|
--code-fg-color: var(--lt-color-gray-300);
|
||||||
|
--md-primary-fg-color: var(--lt-color-gray-900);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-md-color-scheme="default"] {
|
||||||
|
--md-primary-fg-color: var(--md-code-fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.smile-logo {
|
||||||
|
display: flex;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.smile-logo img {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.md-clipboard::after {
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
color: var(--lt-color-gray-500);
|
||||||
|
}
|
||||||
|
button.md-clipboard:hover::after {
|
||||||
|
color: var(--md-primary-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
article a,
|
||||||
|
article a:visited {
|
||||||
|
color: var(--md-code-hl-number-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-center {
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-center img {
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-nav__item .md-nav__link--active {
|
||||||
|
color: var(--md-code-hl-string-color) !important;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.go-logo {
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HLJS */
|
||||||
|
pre code.hljs {
|
||||||
|
background-color: var(--code-bg-color);
|
||||||
|
color: var(--code-fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
table tbody code {
|
||||||
|
text-align: left;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 1em !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
color: var(--md-code-hl-special-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3[id*="katenaryio"] {
|
||||||
|
color: var(--md-code-hl-special-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
background-image: url("logo-vertical.svg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-size: contain;
|
||||||
|
height: 8em;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto 2rem auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Zoomable images*/
|
||||||
|
.zoomable svg {
|
||||||
|
background-color: var(--md-default-bg-color);
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-md-color-scheme="slate"] .zoomable svg {
|
||||||
|
background-color: var(--md-default-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-md-color-scheme="slate"] .zoomable svg .colorize {
|
||||||
|
fill: var(--md-typeset-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoomable input[type="checkbox"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (min-width: 1399px) {
|
||||||
|
.zoomable label > * {
|
||||||
|
cursor: zoom-in;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
.zoomable input[type="checkbox"]:checked ~ label > * {
|
||||||
|
transform: scale(2);
|
||||||
|
cursor: zoom-out;
|
||||||
|
box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#klee {
|
||||||
|
filter: drop-shadow(0 0 16px var(--md-default-fg-color));
|
||||||
|
text-align: center;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
#klee svg {
|
||||||
|
zoom: 2;
|
||||||
|
}
|
BIN
doc/docs/statics/workflow.png
Normal file
After Width: | Height: | Size: 124 KiB |
538
doc/docs/statics/workflow.svg
Normal file
After Width: | Height: | Size: 310 KiB |
262
doc/docs/usage.md
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
# Basic Usage
|
||||||
|
|
||||||
|
Basically, you can use `katenary` to transpose a docker-compose file (or any compose file compatible with
|
||||||
|
`podman-compose` and `docker-compose`) to a configurable Helm Chart. This resulting helm chart can be installed with
|
||||||
|
`helm` command to your Kubernetes cluster.
|
||||||
|
|
||||||
|
For very basic compose files, without any specific configuration, Katenary will create a working helm chart using the
|
||||||
|
simple command line:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
katenary convert
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create a `chart` directory with the helm chart inside.
|
||||||
|
|
||||||
|
But, in general, you will need to add a few configurations to help Katenary to transpose the compose file to a working
|
||||||
|
helm chart.
|
||||||
|
|
||||||
|
There are two ways to configure Katenary:
|
||||||
|
|
||||||
|
- Using the compose files, adding labels to the services
|
||||||
|
- Using a specific file named `katenary.yaml`
|
||||||
|
|
||||||
|
The Katenary file `katenary.yaml` has benefits over the labels in the compose file:
|
||||||
|
|
||||||
|
- you can validate the configuration with a schema, and use completion in your editor
|
||||||
|
- you separate the configuration and leave the compose file "intact"
|
||||||
|
- the syntax is a bit simpler, instead of using `katenary.v3/xxx: |-` you can use `xxx: ...`
|
||||||
|
|
||||||
|
But: **this implies that you have to maintain two files if the compose file changes.**
|
||||||
|
|
||||||
|
For example. With "labels", you should do:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# in compose file
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: php:7-apache
|
||||||
|
ports:
|
||||||
|
- 8080:80
|
||||||
|
environment:
|
||||||
|
DB_HOST: database
|
||||||
|
labels:
|
||||||
|
katenary.v3/ingress: |-
|
||||||
|
hostname: myapp.example.com
|
||||||
|
port: 8080
|
||||||
|
katenary.v3/map-env: |-
|
||||||
|
DB_HOST: "{{ .Release.Name }}-database"
|
||||||
|
```
|
||||||
|
|
||||||
|
Using a Katenary file, you can do:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# in compose file, no need to add labels
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: php:7-apache
|
||||||
|
ports:
|
||||||
|
- 8080:80
|
||||||
|
environment:
|
||||||
|
DB_HOST: database
|
||||||
|
|
||||||
|
# in katenary.yaml
|
||||||
|
webapp:
|
||||||
|
ingress:
|
||||||
|
hostname: myapp.example.com
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
map-env:
|
||||||
|
DB_HOST: "{{ .Release.Name }}-database"
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! Warning "YAML in multiline label"
|
||||||
|
|
||||||
|
Compose only accept text label. So, to put a complete YAML content in the target label,
|
||||||
|
you need to use a pipe char (`|` or `|-`) and to **indent** your content.
|
||||||
|
|
||||||
|
For example :
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
# your labels
|
||||||
|
foo: bar
|
||||||
|
# katenary labels with multiline
|
||||||
|
katenary.v3/ingress: |-
|
||||||
|
hostname: my.website.tld
|
||||||
|
port: 80
|
||||||
|
katenary.v3/ports: |-
|
||||||
|
- 1234
|
||||||
|
```
|
||||||
|
|
||||||
|
Katenary transforms compose services this way:
|
||||||
|
|
||||||
|
- Takes the service and create a "Deployment" file
|
||||||
|
- if a port is declared, Katenary creates a service (`ClusterIP`)
|
||||||
|
- if a port is exposed, Katenary creates a service (`NodePort`)
|
||||||
|
- environment variables will be stored inside a `ConfigMap`
|
||||||
|
- image, tags, and ingresses configuration are also stored in `values.yaml` file
|
||||||
|
- if named volumes are declared, Katenary create `PersistentVolumeClaims` - not enabled in values file
|
||||||
|
- `depends_on` needs that the pointed service declared a port. If not, you can use labels to inform Katenary
|
||||||
|
|
||||||
|
For any other specific configuration, like binding local files as `ConfigMap`, bind variables, add values with
|
||||||
|
documentation, etc. You'll need to use labels.
|
||||||
|
|
||||||
|
Katenary can also configure containers grouping in pods, declare dependencies, ignore some services, force variables as
|
||||||
|
secrets, mount files as `configMap`, and many others things. To adapt the helm chart generation, you will need to use
|
||||||
|
some specific labels.
|
||||||
|
|
||||||
|
For more complete label usage, see [the labels page](labels.md).
|
||||||
|
|
||||||
|
!!! Info "Overriding file"
|
||||||
|
|
||||||
|
It could be sometimes more convinient to separate the
|
||||||
|
configuration related to Katenary inside a secondary file.
|
||||||
|
|
||||||
|
Instead of adding labels inside the `compose.yaml` file,
|
||||||
|
you can create a file named `compose.katenary.yaml` and
|
||||||
|
declare your labels inside. Katenary will detect it by
|
||||||
|
default.
|
||||||
|
|
||||||
|
**No need to precise the file in the command line.**
|
||||||
|
|
||||||
|
## Make conversion
|
||||||
|
|
||||||
|
After having installed `katenary`, the standard usage is to call:
|
||||||
|
|
||||||
|
katenary convert
|
||||||
|
|
||||||
|
It will search standard compose files in the current directory and try to create a helm chart in "chart" directory.
|
||||||
|
|
||||||
|
!!! Info
|
||||||
|
Katenary uses the compose-go library which respects the Docker and Docker-Compose specification. Keep in mind that
|
||||||
|
it will find files exactly the same way as `docker-compose` and `podman-compose` do it.
|
||||||
|
|
||||||
|
Of course, you can provide others files than the default with (cumulative) `-c` options:
|
||||||
|
|
||||||
|
katenary convert -c file1.yaml -c file2.yaml
|
||||||
|
|
||||||
|
## Some common labels to use
|
||||||
|
|
||||||
|
Katenary proposes a lot of labels to configure the helm chart generation, but some are very important.
|
||||||
|
|
||||||
|
!!! Info
|
||||||
|
For more complete label usage, see [the labels page](labels.md).
|
||||||
|
|
||||||
|
### Work with Depends On?
|
||||||
|
|
||||||
|
Kubernetes does not provide service or pod starting detection from others pods. But Katenary will create `initContainer`
|
||||||
|
to make you able to wait for a service to respond. But you'll probably need to adapt a bit the compose file.
|
||||||
|
|
||||||
|
See this compose file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: php:8-apache
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: mariadb
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: foobar
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, `webapp` needs to know the `database` port because the `depends_on` points on it and Kubernetes has not
|
||||||
|
(yet) solution to check the database startup. Katenary wants to create a `initContainer` to hit on the related service.
|
||||||
|
So, instead of exposing the port in the compose definition, let's declare this to Katenary with labels:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: php:8-apache
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: mariadb
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: foobar
|
||||||
|
labels:
|
||||||
|
katenary.v3/ports: |-
|
||||||
|
- 3306
|
||||||
|
```
|
||||||
|
|
||||||
|
### Declare ingresses
|
||||||
|
|
||||||
|
It's very common to have an Ingress resource on web application to deploy on Kubernetes. It allows exposing the
|
||||||
|
service to the outside of the cluster (you need to install an ingress controller).
|
||||||
|
|
||||||
|
Katenary can create this resource for you. You just need to declare the hostname and the port to bind.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: ...
|
||||||
|
ports: 8080:5050
|
||||||
|
labels:
|
||||||
|
katenary.v3/ingress: |-
|
||||||
|
# the target port is 5050 wich is the "service" port
|
||||||
|
port: 5050
|
||||||
|
hostname: myapp.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the port to bind is the one used by the container, not the used locally. This is because Katenary create a
|
||||||
|
service to bind the container itself.
|
||||||
|
|
||||||
|
### Map environment to helm values
|
||||||
|
|
||||||
|
A lot of framework needs to receive service host or IP in an environment variable to configure the connection. For
|
||||||
|
example, to connect a PHP application to a database.
|
||||||
|
|
||||||
|
With a compose file, there is no problem as Docker/Podman allows resolving the name by container name:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: php:7-apache
|
||||||
|
environment:
|
||||||
|
DB_HOST: database
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: mariadb
|
||||||
|
```
|
||||||
|
|
||||||
|
Katenary prefixes the services with `{{ .Release.Name }}` (to make it possible to install the application several times
|
||||||
|
in a namespace), so you need to "remap" the environment variable to the right one.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: php:7-apache
|
||||||
|
environment:
|
||||||
|
DB_HOST: database
|
||||||
|
labels:
|
||||||
|
katenary.v3/mapenv: |-
|
||||||
|
DB_HOST: "{{ .Release.Name }}-database"
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: mariadb
|
||||||
|
```
|
||||||
|
|
||||||
|
This label can be used to map others environment for any others reason. E.g. to change an informational environment
|
||||||
|
variable.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
#...
|
||||||
|
environment:
|
||||||
|
RUNNING: docker
|
||||||
|
labels:
|
||||||
|
katenary.v3/mapenv: |-
|
||||||
|
RUNNING: kubernetes
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above example, `RUNNING` will be set to `kubernetes` when you'll deploy the application with helm, and it's
|
||||||
|
`docker` for "Podman" and "Docker" executions.
|
48
doc/fix.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
""" Fix the markdown files to replace code blocs by lists when the code blocs are lists."""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
# get markdown bloc code
|
||||||
|
re_code = re.compile(r"```(.*?)```", re.DOTALL)
|
||||||
|
|
||||||
|
|
||||||
|
def fix(text: str) -> Tuple[str, bool]:
|
||||||
|
"""Fix the markdown text to replace code blocs by lists when the code blocs are lists."""
|
||||||
|
# in the text, get the code blocs
|
||||||
|
code_blocs = re_code.findall(text)
|
||||||
|
# for each code bloc, if lines begin by a "-", this is a list. So,
|
||||||
|
# make it a mkdocs list and remove the block code
|
||||||
|
fixed = False
|
||||||
|
for code in code_blocs:
|
||||||
|
lines = code.split("\n")
|
||||||
|
lines = [line.strip() for line in lines if line.strip()]
|
||||||
|
if all(line.startswith("-") for line in lines):
|
||||||
|
fixed = True
|
||||||
|
# make a mkdocs list
|
||||||
|
lines = [f"- {line[1:]}" for line in lines]
|
||||||
|
# replace the code bloc by the list
|
||||||
|
text = text.replace(f"```{code}```", "\n".join(lines))
|
||||||
|
return text, fixed
|
||||||
|
|
||||||
|
|
||||||
|
def main(filename: str):
|
||||||
|
"""Fix and rewrite the markdown file."""
|
||||||
|
with open(filename, "r", encoding="utf-8") as f:
|
||||||
|
text = f.read()
|
||||||
|
content, fixed = fix(text)
|
||||||
|
|
||||||
|
if not fixed:
|
||||||
|
return
|
||||||
|
|
||||||
|
with open(sys.argv[1], "w", encoding="utf-8") as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("Usage: python fix.py <file>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
main(sys.argv[1])
|
74
doc/mkdocs.yml
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
site_name: Katenary documentation
|
||||||
|
docs_dir: ./docs
|
||||||
|
plugins:
|
||||||
|
- search
|
||||||
|
- inline-svg
|
||||||
|
- manpage:
|
||||||
|
enabled: !ENV [MANPAGE, false]
|
||||||
|
preprocess: preprocess.py
|
||||||
|
pages:
|
||||||
|
- title: Katenary
|
||||||
|
header: Katenary helm chart generator
|
||||||
|
output: share/man/man1/katenary.1
|
||||||
|
inputs:
|
||||||
|
- usage.md
|
||||||
|
- labels.md
|
||||||
|
theme:
|
||||||
|
name: material
|
||||||
|
custom_dir: overrides
|
||||||
|
logo: statics/logo-bright.svg
|
||||||
|
favicon: statics/icon.svg
|
||||||
|
palette:
|
||||||
|
- scheme: slate
|
||||||
|
toggle:
|
||||||
|
icon: material/brightness-4
|
||||||
|
name: Switch to light mode
|
||||||
|
|
||||||
|
- scheme: default
|
||||||
|
toggle:
|
||||||
|
icon: material/brightness-7
|
||||||
|
name: Switch to dark mode
|
||||||
|
markdown_extensions:
|
||||||
|
- admonition
|
||||||
|
- footnotes
|
||||||
|
- attr_list
|
||||||
|
- pymdownx.emoji:
|
||||||
|
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
||||||
|
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
||||||
|
- pymdownx.highlight:
|
||||||
|
anchor_linenums: true
|
||||||
|
use_pygments: false
|
||||||
|
- pymdownx.superfences:
|
||||||
|
custom_fences:
|
||||||
|
- name: mermaid
|
||||||
|
class: mermaid
|
||||||
|
format: !!python/name:pymdownx.superfences.fence_code_format
|
||||||
|
extra_css:
|
||||||
|
- statics/main.css
|
||||||
|
extra_javascript:
|
||||||
|
- statics/addons.js
|
||||||
|
copyright: Copyright © 2021 - 2024 - Katenary authors
|
||||||
|
extra:
|
||||||
|
generator: false
|
||||||
|
social:
|
||||||
|
- icon: fontawesome/brands/github
|
||||||
|
link: https://github.com/katenary/katenary
|
||||||
|
nav:
|
||||||
|
- "Home": index.md
|
||||||
|
- usage.md
|
||||||
|
- labels.md
|
||||||
|
- Behind the scene:
|
||||||
|
- coding.md
|
||||||
|
- dependencies.md
|
||||||
|
- FAQ: faq.md
|
||||||
|
- Go Packages:
|
||||||
|
- packages/cmd/katenary.md
|
||||||
|
- packages/internal/parser.md
|
||||||
|
- packages/internal/utils.md
|
||||||
|
- Generator:
|
||||||
|
- Index: packages/internal/generator.md
|
||||||
|
- ExtraFiles: packages/internal/generator/extrafiles.md
|
||||||
|
- labels:
|
||||||
|
- packages/internal/generator/labels.md
|
||||||
|
- Labelstructs: packages/internal/generator/labels/labelstructs.md
|
||||||
|
- KatenaryFile: packages/internal/generator/katenaryfile.md
|
56
doc/overrides/partials/footer.html
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
{#- This file was automatically generated - do not edit -#}
|
||||||
|
<footer class="md-footer">
|
||||||
|
{% if page.previous_page or page.next_page %} {% if page.meta and
|
||||||
|
page.meta.hide %} {% set hidden = "hidden" if "footer" in page.meta.hide %} {%
|
||||||
|
endif %}
|
||||||
|
<nav
|
||||||
|
class="md-footer__inner md-grid"
|
||||||
|
aria-label="{{ lang.t('footer.title') }}"
|
||||||
|
{{
|
||||||
|
hidden
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{% if page.previous_page %} {% set direction = lang.t("footer.previous") %}
|
||||||
|
<a
|
||||||
|
href="{{ page.previous_page.url | url }}"
|
||||||
|
class="md-footer__link md-footer__link--prev"
|
||||||
|
aria-label="{{ direction }}: {{ page.previous_page.title | e }}"
|
||||||
|
rel="prev"
|
||||||
|
>
|
||||||
|
<div class="md-footer__button md-icon">
|
||||||
|
{% include ".icons/material/arrow-left.svg" %}
|
||||||
|
</div>
|
||||||
|
<div class="md-footer__title">
|
||||||
|
<div class="md-ellipsis">
|
||||||
|
<span class="md-footer__direction"> {{ direction }} </span>
|
||||||
|
{{ page.previous_page.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% endif %} {% if page.next_page %} {% set direction = lang.t("footer.next")
|
||||||
|
%}
|
||||||
|
<a
|
||||||
|
href="{{ page.next_page.url | url }}"
|
||||||
|
class="md-footer__link md-footer__link--next"
|
||||||
|
aria-label="{{ direction }}: {{ page.next_page.title | e }}"
|
||||||
|
rel="next"
|
||||||
|
>
|
||||||
|
<div class="md-footer__title">
|
||||||
|
<div class="md-ellipsis">
|
||||||
|
<span class="md-footer__direction"> {{ direction }} </span>
|
||||||
|
{{ page.next_page.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="md-footer__button md-icon">
|
||||||
|
{% include ".icons/material/arrow-right.svg" %}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
<div class="md-footer-meta md-typeset">
|
||||||
|
<div class="md-footer-meta__inner md-grid">
|
||||||
|
{% include "partials/copyright.html" %} {% if config.extra.social %} {%
|
||||||
|
include "partials/social.html" %} {% endif %}
|
||||||
|
</div>
|
||||||
|
</footer>
|
22
doc/preprocess.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"""Called by mkdocs to preprocess files and build manpages"""
|
||||||
|
|
||||||
|
from bs4 import BeautifulSoup, Tag
|
||||||
|
|
||||||
|
|
||||||
|
def to_remove(tag: Tag) -> bool:
|
||||||
|
"""Removes images, SVGs, links containing images or SVGs, and permalinks from the BeautifulSoup object."""
|
||||||
|
if tag.name in {"img", "svg"}:
|
||||||
|
return True
|
||||||
|
# remove links containing images or SVGs
|
||||||
|
if tag.name == "a" and tag.img and to_remove(tag.img):
|
||||||
|
return True
|
||||||
|
# remove permalinks
|
||||||
|
if tag.name == "a" and "headerlink" in tag.get("class", ()):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def preprocess(soup: BeautifulSoup, output: str) -> None:
|
||||||
|
"""Preprocess the BeautifulSoup object to remove unwanted elements."""
|
||||||
|
for element in soup.find_all(to_remove):
|
||||||
|
element.decompose()
|
9
doc/requirements.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
mkdocs==1.*
|
||||||
|
Jinja2==3.*
|
||||||
|
MarkupSafe==3.*
|
||||||
|
pymdown-extensions==10.*
|
||||||
|
mkdocs-material==9.*
|
||||||
|
mkdocs-material-extensions==1.*
|
||||||
|
mkdocs-plugin-inline-svg-mod
|
||||||
|
beautifulsoup4==4.*
|
||||||
|
mkdocs-manpage[preprocess]
|
@@ -1,10 +0,0 @@
|
|||||||
# Basic example
|
|
||||||
|
|
||||||
This is a basic example of what can do Katenary with standard docker-compose file.
|
|
||||||
|
|
||||||
In this example:
|
|
||||||
|
|
||||||
- `depends_on` yield a `initContainer` in the webapp ddeployment to wait for database
|
|
||||||
- so we need to declare the listened port inside `database` container as we don't use it with docker-compose- also, we needed to declare that `DB_HOST` is actually a service name using `mapenv` label
|
|
||||||
|
|
||||||
Take a look on [chart/basic](chart/basic) directory to see what `katenary convert` command has generated.
|
|
@@ -1,8 +0,0 @@
|
|||||||
# Create on 2022-02-17T10:27:30+01:00
|
|
||||||
# Katenary command line: katenary convert
|
|
||||||
apiVersion: v2
|
|
||||||
appVersion: 0.0.1
|
|
||||||
description: A helm chart for basic
|
|
||||||
name: basic
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
@@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
Congratulations,
|
|
||||||
|
|
||||||
Your application is now deployed. This may take a while to be up and responding.
|
|
||||||
|
|
||||||
{{ if .Values.webapp.ingress.enabled -}}
|
|
||||||
- webapp is accessible on : http://{{ .Values.webapp.ingress.host }}
|
|
||||||
{{- end }}
|
|
@@ -1,39 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-database'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: database
|
|
||||||
katenary.io/project: basic
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: b9f12bb7d1e97901c1d7680394209525763f6640
|
|
||||||
katenary.io/version: master-3619cc4
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
katenary.io/component: database
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
katenary.io/component: database
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: database
|
|
||||||
image: '{{ .Values.database.image }}'
|
|
||||||
ports:
|
|
||||||
- name: database
|
|
||||||
containerPort: 3306
|
|
||||||
env:
|
|
||||||
- name: MARIADB_PASSWORD
|
|
||||||
value: foo
|
|
||||||
- name: MARIADB_DATABASE
|
|
||||||
value: myapp
|
|
||||||
- name: MARIADB_ROOT_PASSWORD
|
|
||||||
value: foobar
|
|
||||||
- name: MARIADB_USER
|
|
||||||
value: foo
|
|
||||||
|
|
@@ -1,19 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-database'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: database
|
|
||||||
katenary.io/project: basic
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: b9f12bb7d1e97901c1d7680394209525763f6640
|
|
||||||
katenary.io/version: master-3619cc4
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
katenary.io/component: database
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 3306
|
|
||||||
targetPort: 3306
|
|
@@ -1,48 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-webapp'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: webapp
|
|
||||||
katenary.io/project: basic
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: b9f12bb7d1e97901c1d7680394209525763f6640
|
|
||||||
katenary.io/version: master-3619cc4
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
katenary.io/component: webapp
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
katenary.io/component: webapp
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
spec:
|
|
||||||
initContainers:
|
|
||||||
- name: check-database
|
|
||||||
image: busybox
|
|
||||||
command:
|
|
||||||
- sh
|
|
||||||
- -c
|
|
||||||
- |-
|
|
||||||
OK=0
|
|
||||||
echo "Checking database port"
|
|
||||||
while [ $OK != 1 ]; do
|
|
||||||
echo -n "."
|
|
||||||
nc -z {{ .Release.Name }}-database 3306 2>&1 >/dev/null && OK=1 || sleep 1
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
echo "Done"
|
|
||||||
containers:
|
|
||||||
- name: webapp
|
|
||||||
image: '{{ .Values.webapp.image }}'
|
|
||||||
ports:
|
|
||||||
- name: webapp
|
|
||||||
containerPort: 80
|
|
||||||
env:
|
|
||||||
- name: DB_HOST
|
|
||||||
value: '{{ .Release.Name }}-database'
|
|
||||||
|
|
@@ -1,34 +0,0 @@
|
|||||||
{{- if .Values.webapp.ingress.enabled -}}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-webapp'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: webapp
|
|
||||||
katenary.io/project: basic
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: b9f12bb7d1e97901c1d7680394209525763f6640
|
|
||||||
katenary.io/version: master-3619cc4
|
|
||||||
spec:
|
|
||||||
{{- if and .Values.webapp.ingress.class (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
|
||||||
ingressClassName: '{{ .Values.webapp.ingress.class }}'
|
|
||||||
{{- end }}
|
|
||||||
rules:
|
|
||||||
- host: '{{ .Values.webapp.ingress.host }}'
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: /
|
|
||||||
pathType: Prefix
|
|
||||||
backend:
|
|
||||||
{{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }}
|
|
||||||
service:
|
|
||||||
name: '{{ .Release.Name }}-webapp'
|
|
||||||
port:
|
|
||||||
number: 80
|
|
||||||
{{- else }}
|
|
||||||
serviceName: '{{ .Release.Name }}-webapp'
|
|
||||||
servicePort: 80
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- end -}}
|
|
@@ -1,19 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-webapp'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: webapp
|
|
||||||
katenary.io/project: basic
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: b9f12bb7d1e97901c1d7680394209525763f6640
|
|
||||||
katenary.io/version: master-3619cc4
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
katenary.io/component: webapp
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 80
|
|
||||||
targetPort: 80
|
|
@@ -1,8 +0,0 @@
|
|||||||
database:
|
|
||||||
image: mariadb:10
|
|
||||||
webapp:
|
|
||||||
image: php:7-apache
|
|
||||||
ingress:
|
|
||||||
class: nginx
|
|
||||||
enabled: false
|
|
||||||
host: webapp.basic.tld
|
|
@@ -1,31 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
# this example is absolutely not working, it's an example to see how it is converted
|
|
||||||
# by Katenary
|
|
||||||
services:
|
|
||||||
webapp:
|
|
||||||
image: php:7-apache
|
|
||||||
environment:
|
|
||||||
DB_HOST: database
|
|
||||||
ports:
|
|
||||||
- "8080:80"
|
|
||||||
labels:
|
|
||||||
# expose an ingress
|
|
||||||
katenary.io/ingress: 80
|
|
||||||
# DB_HOST is actually a service name
|
|
||||||
katenary.io/mapenv: |
|
|
||||||
DB_HOST: {{ .Release.Name }}-database
|
|
||||||
depends_on:
|
|
||||||
- database
|
|
||||||
|
|
||||||
database:
|
|
||||||
image: mariadb:10
|
|
||||||
environment:
|
|
||||||
MARIADB_ROOT_PASSWORD: foobar
|
|
||||||
MARIADB_USER: foo
|
|
||||||
MARIADB_PASSWORD: foo
|
|
||||||
MARIADB_DATABASE: myapp
|
|
||||||
labels:
|
|
||||||
# because we don't provide "ports" or "expose", alert katenary
|
|
||||||
# to use the mysql port for service declaration
|
|
||||||
katenary.io/ports: 3306
|
|
@@ -1,9 +0,0 @@
|
|||||||
# Example with Ghost
|
|
||||||
|
|
||||||
[Ghost](https://ghost.org/) is a simple but powerfull blog engine. It is very nice to test some behaviors with Docker or Podman.
|
|
||||||
|
|
||||||
The given `docker-compose.yaml` file here declares a stand-alone blog service. To help using it, we use [Patwae](https://pathwae.net) reverse-proxy to listend http://ghost.example.localhost
|
|
||||||
|
|
||||||
The problem to solve is that the `url` environment variable correspond to the Ingress host when we will convert it to Helm Chart. So, we use the `mapenv` label to declare that `url` is actually `{{ .Values.blog.ingress.host }}` value.
|
|
||||||
|
|
||||||
Note that we also `ignore` pathwae because we don't need it in our Helm Chart.
|
|
@@ -1,8 +0,0 @@
|
|||||||
# Create on 2022-05-05T14:16:27+02:00
|
|
||||||
# Katenary command line: /tmp/go-build669507924/b001/exe/main convert
|
|
||||||
apiVersion: v2
|
|
||||||
appVersion: 0.0.1
|
|
||||||
description: A helm chart for ghost
|
|
||||||
name: ghost
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
@@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
Congratulations,
|
|
||||||
|
|
||||||
Your application is now deployed. This may take a while to be up and responding.
|
|
||||||
|
|
||||||
{{ if .Values.blog.ingress.enabled -}}
|
|
||||||
- blog is accessible on : http://{{ .Values.blog.ingress.host }}
|
|
||||||
{{- end }}
|
|
@@ -1,33 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-blog'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: blog
|
|
||||||
katenary.io/project: ghost
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: 0c2bbf548ff569c3dc5d77dc158e98bbe86fb5d4
|
|
||||||
katenary.io/version: master
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
katenary.io/component: blog
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
katenary.io/component: blog
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: blog
|
|
||||||
image: '{{ .Values.blog.image }}'
|
|
||||||
ports:
|
|
||||||
- name: blog
|
|
||||||
containerPort: 2368
|
|
||||||
env:
|
|
||||||
- name: url
|
|
||||||
value: http://{{ .Values.blog.ingress.host }}
|
|
||||||
|
|
@@ -1,42 +0,0 @@
|
|||||||
{{- if .Values.blog.ingress.enabled -}}
|
|
||||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1beta1
|
|
||||||
{{- else -}}
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
{{- end }}
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-blog'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: blog
|
|
||||||
katenary.io/project: ghost
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: 0c2bbf548ff569c3dc5d77dc158e98bbe86fb5d4
|
|
||||||
katenary.io/version: master
|
|
||||||
spec:
|
|
||||||
{{- if and .Values.blog.ingress.class (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
|
||||||
ingressClassName: '{{ .Values.blog.ingress.class }}'
|
|
||||||
{{- end }}
|
|
||||||
rules:
|
|
||||||
- host: '{{ .Values.blog.ingress.host }}'
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: /
|
|
||||||
{{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }}
|
|
||||||
pathType: Prefix
|
|
||||||
{{- end }}
|
|
||||||
backend:
|
|
||||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
|
|
||||||
service:
|
|
||||||
name: '{{ .Release.Name }}-blog'
|
|
||||||
port:
|
|
||||||
number: 2368
|
|
||||||
{{- else }}
|
|
||||||
serviceName: '{{ .Release.Name }}-blog'
|
|
||||||
servicePort: 2368
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- end -}}
|
|
@@ -1,19 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-blog'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: blog
|
|
||||||
katenary.io/project: ghost
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: 0c2bbf548ff569c3dc5d77dc158e98bbe86fb5d4
|
|
||||||
katenary.io/version: master
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
katenary.io/component: blog
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 2368
|
|
||||||
targetPort: 2368
|
|
@@ -1,6 +0,0 @@
|
|||||||
blog:
|
|
||||||
image: ghost
|
|
||||||
ingress:
|
|
||||||
class: nginx
|
|
||||||
enabled: false
|
|
||||||
host: blog.ghost.tld
|
|
@@ -1,30 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
blog:
|
|
||||||
image: ghost
|
|
||||||
environment:
|
|
||||||
# this is OK for local test, but not with Helm
|
|
||||||
# because the URL depends on Ingress
|
|
||||||
url: http://ghost.example.localhost
|
|
||||||
labels:
|
|
||||||
katenary.io/ports: 2368
|
|
||||||
katenary.io/ingress: 2368
|
|
||||||
# ... so we declare that "url" is actually
|
|
||||||
# the ingress host
|
|
||||||
katenary.io/mapenv: |
|
|
||||||
url: http://{{ .Values.blog.ingress.host }}
|
|
||||||
|
|
||||||
proxy:
|
|
||||||
# A simple proxy for localhost
|
|
||||||
image: quay.io/pathwae/proxy
|
|
||||||
environment:
|
|
||||||
CONFIG: |
|
|
||||||
ghost.example.localhost:
|
|
||||||
to: http://blog:2368
|
|
||||||
ports:
|
|
||||||
- 80:80
|
|
||||||
labels:
|
|
||||||
# we don't want this in Helm because we will use
|
|
||||||
# an ingress
|
|
||||||
katenary.io/ignore: true
|
|
@@ -1,13 +0,0 @@
|
|||||||
# Make it possible to bind several containers in one pod
|
|
||||||
|
|
||||||
In this example, we need to make nginx and php-fpm to run inside the same "pod". The reason is that we configured FPM to listen an unix socket instead of the 9000 port.
|
|
||||||
|
|
||||||
Because NGinx will need to connect to the unix socket wich is a file, both containers should share the same node and work together.
|
|
||||||
|
|
||||||
So, in the docker-compose file, we need to declare:
|
|
||||||
- `katenary.io/empty-dirs: socket` where `socket` is the "volume name", this will avoid the creation of a PVC
|
|
||||||
- `katenary.io/same-pod: http` in `php` container to declare that this will be added in the `containers` section of the `http` deployment
|
|
||||||
|
|
||||||
You can note that we also use `configmap-volumes` to declare our configuration as `configMap`.
|
|
||||||
|
|
||||||
Take a look on [chart/same-pod](chart/same-pod) directory to see the result of the `katenary convert` command.
|
|
@@ -1,8 +0,0 @@
|
|||||||
# Create on 2022-02-17T11:36:02+01:00
|
|
||||||
# Katenary command line: katenary convert --force
|
|
||||||
apiVersion: v2
|
|
||||||
appVersion: 0.0.1
|
|
||||||
description: A helm chart for same-pod
|
|
||||||
name: same-pod
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
@@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
Congratulations,
|
|
||||||
|
|
||||||
Your application is now deployed. This may take a while to be up and responding.
|
|
||||||
|
|
||||||
{{ if .Values.http.ingress.enabled -}}
|
|
||||||
- http is accessible on : http://{{ .Values.http.ingress.host }}
|
|
||||||
{{- end }}
|
|
@@ -1,23 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-config-nginx-http'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: ""
|
|
||||||
katenary.io/project: same-pod
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: 74e67695bfdbb829f15531321e158808018280e0
|
|
||||||
katenary.io/version: master-bf44d44
|
|
||||||
data:
|
|
||||||
default.conf: |
|
|
||||||
upstream _php {
|
|
||||||
server unix:/sock/fpm.sock;
|
|
||||||
}
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
location ~ ^/index\.php(/|$) {
|
|
||||||
fastcgi_pass _php;
|
|
||||||
include fastcgi_params;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,30 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-config-php-php'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: ""
|
|
||||||
katenary.io/project: same-pod
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: 74e67695bfdbb829f15531321e158808018280e0
|
|
||||||
katenary.io/version: master-bf44d44
|
|
||||||
data:
|
|
||||||
www.conf: |
|
|
||||||
[www]
|
|
||||||
user = www-data
|
|
||||||
group = www-data
|
|
||||||
|
|
||||||
listen = /sock/fpm.sock
|
|
||||||
|
|
||||||
pm = dynamic
|
|
||||||
pm.max_children = 5
|
|
||||||
pm.start_servers = 2
|
|
||||||
pm.min_spare_servers = 1
|
|
||||||
pm.max_spare_servers = 3
|
|
||||||
|
|
||||||
access.log = /proc/self/fd/2
|
|
||||||
log_limit = 8192
|
|
||||||
clear_env = no
|
|
||||||
catch_workers_output = yes
|
|
||||||
decorate_workers_output = no
|
|
@@ -1,52 +0,0 @@
|
|||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-http'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: http
|
|
||||||
katenary.io/project: same-pod
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: 74e67695bfdbb829f15531321e158808018280e0
|
|
||||||
katenary.io/version: master-bf44d44
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
katenary.io/component: http
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
katenary.io/component: http
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: http
|
|
||||||
image: '{{ .Values.http.image }}'
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: 80
|
|
||||||
volumeMounts:
|
|
||||||
- mountPath: /sock
|
|
||||||
name: sock
|
|
||||||
- mountPath: /etc/nginx/conf.d
|
|
||||||
name: config-nginx
|
|
||||||
- name: php
|
|
||||||
image: '{{ .Values.php.image }}'
|
|
||||||
volumeMounts:
|
|
||||||
- mountPath: /sock
|
|
||||||
name: sock
|
|
||||||
- mountPath: /usr/local/etc/php-fpm.d/www.conf
|
|
||||||
name: config-php
|
|
||||||
subPath: www.conf
|
|
||||||
volumes:
|
|
||||||
- emptyDir: {}
|
|
||||||
name: sock
|
|
||||||
- configMap:
|
|
||||||
name: '{{ .Release.Name }}-config-nginx-http'
|
|
||||||
name: config-nginx
|
|
||||||
- configMap:
|
|
||||||
name: '{{ .Release.Name }}-config-php-php'
|
|
||||||
name: config-php
|
|
||||||
|
|
@@ -1,34 +0,0 @@
|
|||||||
{{- if .Values.http.ingress.enabled -}}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-http'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: http
|
|
||||||
katenary.io/project: same-pod
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: 74e67695bfdbb829f15531321e158808018280e0
|
|
||||||
katenary.io/version: master-bf44d44
|
|
||||||
spec:
|
|
||||||
{{- if and .Values.http.ingress.class (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
|
||||||
ingressClassName: '{{ .Values.http.ingress.class }}'
|
|
||||||
{{- end }}
|
|
||||||
rules:
|
|
||||||
- host: '{{ .Values.http.ingress.host }}'
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: /
|
|
||||||
pathType: Prefix
|
|
||||||
backend:
|
|
||||||
{{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }}
|
|
||||||
service:
|
|
||||||
name: '{{ .Release.Name }}-http'
|
|
||||||
port:
|
|
||||||
number: 80
|
|
||||||
{{- else }}
|
|
||||||
serviceName: '{{ .Release.Name }}-http'
|
|
||||||
servicePort: 80
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- end -}}
|
|
@@ -1,19 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: '{{ .Release.Name }}-http'
|
|
||||||
labels:
|
|
||||||
katenary.io/component: http
|
|
||||||
katenary.io/project: same-pod
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
annotations:
|
|
||||||
katenary.io/docker-compose-sha1: 74e67695bfdbb829f15531321e158808018280e0
|
|
||||||
katenary.io/version: master-bf44d44
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
katenary.io/component: http
|
|
||||||
katenary.io/release: '{{ .Release.Name }}'
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 80
|
|
||||||
targetPort: 80
|
|
@@ -1,8 +0,0 @@
|
|||||||
http:
|
|
||||||
image: nginx:alpine
|
|
||||||
ingress:
|
|
||||||
class: nginx
|
|
||||||
enabled: false
|
|
||||||
host: http.same-pod.tld
|
|
||||||
php:
|
|
||||||
image: php:fpm
|
|
@@ -1,10 +0,0 @@
|
|||||||
upstream _php {
|
|
||||||
server unix:/sock/fpm.sock;
|
|
||||||
}
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
location ~ ^/index\.php(/|$) {
|
|
||||||
fastcgi_pass _php;
|
|
||||||
include fastcgi_params;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
[www]
|
|
||||||
user = www-data
|
|
||||||
group = www-data
|
|
||||||
|
|
||||||
listen = /sock/fpm.sock
|
|
||||||
|
|
||||||
pm = dynamic
|
|
||||||
pm.max_children = 5
|
|
||||||
pm.start_servers = 2
|
|
||||||
pm.min_spare_servers = 1
|
|
||||||
pm.max_spare_servers = 3
|
|
||||||
|
|
||||||
access.log = /proc/self/fd/2
|
|
||||||
log_limit = 8192
|
|
||||||
clear_env = no
|
|
||||||
catch_workers_output = yes
|
|
||||||
decorate_workers_output = no
|
|
@@ -1,38 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
|
|
||||||
http:
|
|
||||||
image: nginx:alpine
|
|
||||||
ports:
|
|
||||||
- "8080:80"
|
|
||||||
volumes:
|
|
||||||
- "sock:/sock"
|
|
||||||
- "./config/nginx:/etc/nginx/conf.d:z"
|
|
||||||
|
|
||||||
labels:
|
|
||||||
# the "sock" volume will need to be shared to the same pod, so let's
|
|
||||||
# declare that this is not a PVC
|
|
||||||
katenary.io/empty-dirs: sock
|
|
||||||
|
|
||||||
# use ./config/nginx as a configMap
|
|
||||||
katenary.io/configmap-volumes: ./config/nginx
|
|
||||||
|
|
||||||
# declare an ingress
|
|
||||||
katenary.io/ingress: 80
|
|
||||||
|
|
||||||
php:
|
|
||||||
image: php:fpm
|
|
||||||
volumes:
|
|
||||||
- "sock:/sock"
|
|
||||||
- "./config/php/www.conf:/usr/local/etc/php-fpm.d/www.conf:z"
|
|
||||||
labels:
|
|
||||||
# fpm will need to use a unix socket shared
|
|
||||||
# with nginx (http service above), so we want here
|
|
||||||
# make a single pod containing nginx and php
|
|
||||||
katenary.io/same-pod: http
|
|
||||||
# use the ./config/php files as a configMap
|
|
||||||
katenary.io/configmap-volumes: ./config/php/www.conf
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
sock:
|
|
@@ -1,892 +0,0 @@
|
|||||||
package generator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"katenary/compose"
|
|
||||||
"katenary/helm"
|
|
||||||
"katenary/logger"
|
|
||||||
"log"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EnvVal = helm.EnvValue
|
|
||||||
|
|
||||||
const (
|
|
||||||
ICON_PACKAGE = "📦"
|
|
||||||
ICON_SERVICE = "🔌"
|
|
||||||
ICON_SECRET = "🔏"
|
|
||||||
ICON_CONF = "📝"
|
|
||||||
ICON_STORE = "⚡"
|
|
||||||
ICON_INGRESS = "🌐"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Values is kept in memory to create a values.yaml file.
|
|
||||||
var (
|
|
||||||
Values = make(map[string]map[string]interface{})
|
|
||||||
VolumeValues = make(map[string]map[string]map[string]EnvVal)
|
|
||||||
EmptyDirs = []string{}
|
|
||||||
servicesMap = make(map[string]int)
|
|
||||||
locker = &sync.Mutex{}
|
|
||||||
|
|
||||||
dependScript = `
|
|
||||||
OK=0
|
|
||||||
echo "Checking __service__ port"
|
|
||||||
while [ $OK != 1 ]; do
|
|
||||||
echo -n "."
|
|
||||||
nc -z ` + helm.ReleaseNameTpl + `-__service__ __port__ 2>&1 >/dev/null && OK=1 || sleep 1
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
echo "Done"
|
|
||||||
`
|
|
||||||
|
|
||||||
madeDeployments = make(map[string]helm.Deployment, 0)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create a Deployment for a given compose.Service. It returns a list chan
|
|
||||||
// of HelmFileGenerator which will be used to generate the files (deployment, secrets, configMap...).
|
|
||||||
func CreateReplicaObject(name string, s types.ServiceConfig, linked map[string]types.ServiceConfig) HelmFileGenerator {
|
|
||||||
ret := make(chan HelmFile, runtime.NumCPU())
|
|
||||||
// there is a bug woth typs.ServiceConfig if we use the pointer. So we need to dereference it.
|
|
||||||
go buildDeployment(name, &s, linked, ret)
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function will try to yied deployment and services based on a service from the compose file structure.
|
|
||||||
func buildDeployment(name string, s *types.ServiceConfig, linked map[string]types.ServiceConfig, fileGeneratorChan HelmFileGenerator) {
|
|
||||||
|
|
||||||
logger.Magenta(ICON_PACKAGE+" Generating deployment for ", name)
|
|
||||||
deployment := helm.NewDeployment(name)
|
|
||||||
|
|
||||||
newContainerForDeployment(name, name, deployment, s, fileGeneratorChan)
|
|
||||||
|
|
||||||
// Add selectors
|
|
||||||
selectors := buildSelector(name, s)
|
|
||||||
deployment.Spec.Selector = map[string]interface{}{
|
|
||||||
"matchLabels": selectors,
|
|
||||||
}
|
|
||||||
deployment.Spec.Template.Metadata.Labels = selectors
|
|
||||||
|
|
||||||
// Now, the linked services (same pod)
|
|
||||||
for lname, link := range linked {
|
|
||||||
newContainerForDeployment(name, lname, deployment, &link, fileGeneratorChan)
|
|
||||||
// append ports and expose ports to the deployment,
|
|
||||||
// to be able to generate them in the Service file
|
|
||||||
if len(link.Ports) > 0 || len(link.Expose) > 0 {
|
|
||||||
s.Ports = append(s.Ports, link.Ports...)
|
|
||||||
s.Expose = append(s.Expose, link.Expose...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove duplicates in volumes
|
|
||||||
volumes := make([]map[string]interface{}, 0)
|
|
||||||
done := make(map[string]bool)
|
|
||||||
for _, vol := range deployment.Spec.Template.Spec.Volumes {
|
|
||||||
name := vol["name"].(string)
|
|
||||||
if _, ok := done[name]; ok {
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
done[name] = true
|
|
||||||
volumes = append(volumes, vol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deployment.Spec.Template.Spec.Volumes = volumes
|
|
||||||
|
|
||||||
// Then, create Services and possible Ingresses for ingress labels, "ports" and "expose" section
|
|
||||||
if len(s.Ports) > 0 || len(s.Expose) > 0 {
|
|
||||||
for _, s := range generateServicesAndIngresses(name, s) {
|
|
||||||
if s != nil {
|
|
||||||
fileGeneratorChan <- s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the volumes in Values
|
|
||||||
if len(VolumeValues[name]) > 0 {
|
|
||||||
AddValues(name, map[string]EnvVal{"persistence": VolumeValues[name]})
|
|
||||||
}
|
|
||||||
|
|
||||||
// the deployment is ready, give it
|
|
||||||
fileGeneratorChan <- deployment
|
|
||||||
|
|
||||||
// and then, we can say that it's the end
|
|
||||||
fileGeneratorChan <- nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepareContainer assigns image, command, env, and labels to a container.
|
|
||||||
func prepareContainer(container *helm.Container, service *types.ServiceConfig, servicename string) {
|
|
||||||
// if there is no image name, this should fail!
|
|
||||||
if service.Image == "" {
|
|
||||||
log.Fatal(ICON_PACKAGE+" No image name for service ", servicename)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the image tag
|
|
||||||
imageParts := strings.Split(service.Image, ":")
|
|
||||||
tag := ""
|
|
||||||
if len(imageParts) == 2 {
|
|
||||||
container.Image = imageParts[0]
|
|
||||||
tag = imageParts[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
vtag := ".Values." + servicename + ".repository.tag"
|
|
||||||
container.Image = `{{ .Values.` + servicename + `.repository.image }}` +
|
|
||||||
`{{ if ne ` + vtag + ` "" }}:{{ ` + vtag + ` }}{{ end }}`
|
|
||||||
container.Command = service.Command
|
|
||||||
AddValues(servicename, map[string]EnvVal{
|
|
||||||
"repository": map[string]EnvVal{
|
|
||||||
"image": imageParts[0],
|
|
||||||
"tag": tag,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
prepareProbes(servicename, service, container)
|
|
||||||
generateContainerPorts(service, servicename, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a service (k8s).
|
|
||||||
func generateServicesAndIngresses(name string, s *types.ServiceConfig) []HelmFile {
|
|
||||||
|
|
||||||
ret := make([]HelmFile, 0) // can handle helm.Service or helm.Ingress
|
|
||||||
logger.Magenta(ICON_SERVICE+" Generating service for ", name)
|
|
||||||
ks := helm.NewService(name)
|
|
||||||
|
|
||||||
for _, p := range s.Ports {
|
|
||||||
target := int(p.Target)
|
|
||||||
ks.Spec.Ports = append(ks.Spec.Ports, helm.NewServicePort(target, target))
|
|
||||||
}
|
|
||||||
ks.Spec.Selector = buildSelector(name, s)
|
|
||||||
|
|
||||||
ret = append(ret, ks)
|
|
||||||
if v, ok := s.Labels[helm.LABEL_INGRESS]; ok {
|
|
||||||
port, err := strconv.Atoi(v)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("The given port \"%v\" as ingress port in \"%s\" service is not an integer\n", v, name)
|
|
||||||
}
|
|
||||||
logger.Cyanf(ICON_INGRESS+" Create an ingress for port %d on %s service\n", port, name)
|
|
||||||
ing := createIngress(name, port, s)
|
|
||||||
ret = append(ret, ing)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.Expose) > 0 {
|
|
||||||
logger.Magenta(ICON_SERVICE+" Generating service for ", name+"-external")
|
|
||||||
ks := helm.NewService(name + "-external")
|
|
||||||
ks.Spec.Type = "NodePort"
|
|
||||||
for _, expose := range s.Expose {
|
|
||||||
|
|
||||||
p, _ := strconv.Atoi(expose)
|
|
||||||
ks.Spec.Ports = append(ks.Spec.Ports, helm.NewServicePort(p, p))
|
|
||||||
}
|
|
||||||
ks.Spec.Selector = buildSelector(name, s)
|
|
||||||
ret = append(ret, ks)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an ingress.
|
|
||||||
func createIngress(name string, port int, s *types.ServiceConfig) *helm.Ingress {
|
|
||||||
ingress := helm.NewIngress(name)
|
|
||||||
|
|
||||||
annotations := map[string]string{}
|
|
||||||
ingressVal := map[string]interface{}{
|
|
||||||
"class": "nginx",
|
|
||||||
"host": name + "." + helm.Appname + ".tld",
|
|
||||||
"enabled": false,
|
|
||||||
"annotations": annotations,
|
|
||||||
}
|
|
||||||
|
|
||||||
// add Annotations in values
|
|
||||||
AddValues(name, map[string]EnvVal{"ingress": ingressVal})
|
|
||||||
|
|
||||||
ingress.Spec.Rules = []helm.IngressRule{
|
|
||||||
{
|
|
||||||
Host: fmt.Sprintf("{{ .Values.%s.ingress.host }}", name),
|
|
||||||
Http: helm.IngressHttp{
|
|
||||||
Paths: []helm.IngressPath{{
|
|
||||||
Path: "/",
|
|
||||||
PathType: "Prefix",
|
|
||||||
Backend: &helm.IngressBackend{
|
|
||||||
Service: helm.IngressService{
|
|
||||||
Name: helm.ReleaseNameTpl + "-" + name,
|
|
||||||
Port: map[string]interface{}{
|
|
||||||
"number": port,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ingress.SetIngressClass(name)
|
|
||||||
|
|
||||||
return ingress
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the selector for the service.
|
|
||||||
func buildSelector(name string, s *types.ServiceConfig) map[string]string {
|
|
||||||
return map[string]string{
|
|
||||||
"katenary.io/component": name,
|
|
||||||
"katenary.io/release": helm.ReleaseNameTpl,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildConfigMapFromPath generates a ConfigMap from a path.
|
|
||||||
func buildConfigMapFromPath(name, path string) *helm.ConfigMap {
|
|
||||||
stat, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
files := make(map[string]string, 0)
|
|
||||||
if stat.IsDir() {
|
|
||||||
found, _ := filepath.Glob(path + "/*")
|
|
||||||
for _, f := range found {
|
|
||||||
if s, err := os.Stat(f); err != nil || s.IsDir() {
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "An error occured reading volume path %s\n", err.Error())
|
|
||||||
} else {
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Yellowf("Warning, %s is a directory, at this time we only "+
|
|
||||||
"can create configmap for first level file list\n", f)
|
|
||||||
logger.ActivateColors = false
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_, filename := filepath.Split(f)
|
|
||||||
c, _ := ioutil.ReadFile(f)
|
|
||||||
files[filename] = string(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cm := helm.NewConfigMap(name, GetRelPath(path))
|
|
||||||
cm.Data = files
|
|
||||||
return cm
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateContainerPorts add the container ports of a service.
|
|
||||||
func generateContainerPorts(s *types.ServiceConfig, name string, container *helm.Container) {
|
|
||||||
|
|
||||||
exists := make(map[int]string)
|
|
||||||
for _, port := range s.Ports {
|
|
||||||
portName := name
|
|
||||||
for _, n := range exists {
|
|
||||||
if name == n {
|
|
||||||
portName = fmt.Sprintf("%s-%d", name, port.Target)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
container.Ports = append(container.Ports, &helm.ContainerPort{
|
|
||||||
Name: portName,
|
|
||||||
ContainerPort: int(port.Target),
|
|
||||||
})
|
|
||||||
exists[int(port.Target)] = name
|
|
||||||
}
|
|
||||||
|
|
||||||
// manage the "expose" section to be a NodePort in Kubernetes
|
|
||||||
for _, expose := range s.Expose {
|
|
||||||
|
|
||||||
port, _ := strconv.Atoi(expose)
|
|
||||||
|
|
||||||
if _, exist := exists[port]; exist {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
container.Ports = append(container.Ports, &helm.ContainerPort{
|
|
||||||
Name: name,
|
|
||||||
ContainerPort: port,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepareVolumes add the volumes of a service.
|
|
||||||
func prepareVolumes(deployment, name string, s *types.ServiceConfig, container *helm.Container, fileGeneratorChan HelmFileGenerator) []map[string]interface{} {
|
|
||||||
|
|
||||||
volumes := make([]map[string]interface{}, 0)
|
|
||||||
mountPoints := make([]interface{}, 0)
|
|
||||||
configMapsVolumes := make([]string, 0)
|
|
||||||
if v, ok := s.Labels[helm.LABEL_VOL_CM]; ok {
|
|
||||||
configMapsVolumes = strings.Split(v, ",")
|
|
||||||
for i, cm := range configMapsVolumes {
|
|
||||||
configMapsVolumes[i] = strings.TrimSpace(cm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, vol := range s.Volumes {
|
|
||||||
|
|
||||||
volname := vol.Source
|
|
||||||
volepath := vol.Target
|
|
||||||
|
|
||||||
if volname == "" {
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Yellowf("Warning, volume source to %s is empty for %s -- skipping\n", volepath, name)
|
|
||||||
logger.ActivateColors = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
isConfigMap := false
|
|
||||||
for _, cmVol := range configMapsVolumes {
|
|
||||||
if GetRelPath(volname) == cmVol {
|
|
||||||
isConfigMap = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// local volume cannt be mounted
|
|
||||||
if !isConfigMap && (strings.HasPrefix(volname, ".") || strings.HasPrefix(volname, "/")) {
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Redf("You cannot, at this time, have local volume in %s deployment\n", name)
|
|
||||||
logger.ActivateColors = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if isConfigMap {
|
|
||||||
// check if the volname path points on a file, if so, we need to add subvolume to the interface
|
|
||||||
stat, err := os.Stat(volname)
|
|
||||||
if err != nil {
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Redf("An error occured reading volume path %s\n", err.Error())
|
|
||||||
logger.ActivateColors = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
pointToFile := ""
|
|
||||||
if !stat.IsDir() {
|
|
||||||
pointToFile = filepath.Base(volname)
|
|
||||||
volname = filepath.Dir(volname)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the volume is a path and it's explicitally asked to be a configmap in labels
|
|
||||||
cm := buildConfigMapFromPath(name, volname)
|
|
||||||
cm.K8sBase.Metadata.Name = helm.ReleaseNameTpl + "-" + name + "-" + PathToName(volname)
|
|
||||||
|
|
||||||
// build a configmapRef for this volume
|
|
||||||
volumes = append(volumes, map[string]interface{}{
|
|
||||||
"name": volname,
|
|
||||||
"configMap": map[string]string{
|
|
||||||
"name": cm.K8sBase.Metadata.Name,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if len(pointToFile) > 0 {
|
|
||||||
mountPoints = append(mountPoints, map[string]interface{}{
|
|
||||||
"name": volname,
|
|
||||||
"mountPath": volepath,
|
|
||||||
"subPath": pointToFile,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
mountPoints = append(mountPoints, map[string]interface{}{
|
|
||||||
"name": volname,
|
|
||||||
"mountPath": volepath,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if cm != nil {
|
|
||||||
fileGeneratorChan <- cm
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// rmove minus sign from volume name
|
|
||||||
volname = strings.ReplaceAll(volname, "-", "")
|
|
||||||
|
|
||||||
isEmptyDir := false
|
|
||||||
for _, v := range EmptyDirs {
|
|
||||||
v = strings.ReplaceAll(v, "-", "")
|
|
||||||
if v == volname {
|
|
||||||
volumes = append(volumes, map[string]interface{}{
|
|
||||||
"name": volname,
|
|
||||||
"emptyDir": map[string]string{},
|
|
||||||
})
|
|
||||||
mountPoints = append(mountPoints, map[string]interface{}{
|
|
||||||
"name": volname,
|
|
||||||
"mountPath": volepath,
|
|
||||||
})
|
|
||||||
container.VolumeMounts = append(container.VolumeMounts, mountPoints...)
|
|
||||||
isEmptyDir = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isEmptyDir {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
volumes = append(volumes, map[string]interface{}{
|
|
||||||
"name": volname,
|
|
||||||
"persistentVolumeClaim": map[string]string{
|
|
||||||
"claimName": helm.ReleaseNameTpl + "-" + volname,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
mountPoints = append(mountPoints, map[string]interface{}{
|
|
||||||
"name": volname,
|
|
||||||
"mountPath": volepath,
|
|
||||||
})
|
|
||||||
|
|
||||||
logger.Yellow(ICON_STORE+" Generate volume values", volname, "for container named", name, "in deployment", deployment)
|
|
||||||
AddVolumeValues(deployment, volname, map[string]EnvVal{
|
|
||||||
"enabled": false,
|
|
||||||
"capacity": "1Gi",
|
|
||||||
})
|
|
||||||
|
|
||||||
if pvc := helm.NewPVC(deployment, volname); pvc != nil {
|
|
||||||
fileGeneratorChan <- pvc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add the volume in the container and return the volume definition to add in Deployment
|
|
||||||
container.VolumeMounts = append(container.VolumeMounts, mountPoints...)
|
|
||||||
return volumes
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepareInitContainers add the init containers of a service.
|
|
||||||
func prepareInitContainers(name string, s *types.ServiceConfig, container *helm.Container) []*helm.Container {
|
|
||||||
|
|
||||||
// We need to detect others services, but we probably not have parsed them yet, so
|
|
||||||
// we will wait for them for a while.
|
|
||||||
initContainers := make([]*helm.Container, 0)
|
|
||||||
for dp := range s.DependsOn {
|
|
||||||
c := helm.NewContainer("check-"+dp, "busybox", nil, s.Labels)
|
|
||||||
command := strings.ReplaceAll(strings.TrimSpace(dependScript), "__service__", dp)
|
|
||||||
|
|
||||||
foundPort := -1
|
|
||||||
locker.Lock()
|
|
||||||
if defaultPort, ok := servicesMap[dp]; !ok {
|
|
||||||
logger.Redf("Error while getting port for service %s\n", dp)
|
|
||||||
os.Exit(1)
|
|
||||||
} else {
|
|
||||||
foundPort = defaultPort
|
|
||||||
}
|
|
||||||
locker.Unlock()
|
|
||||||
if foundPort == -1 {
|
|
||||||
log.Fatalf(
|
|
||||||
"ERROR, the %s service is waiting for %s port number, "+
|
|
||||||
"but it is never discovered. You must declare at least one port in "+
|
|
||||||
"the \"ports\" section of the service in the docker-compose file",
|
|
||||||
name,
|
|
||||||
dp,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
command = strings.ReplaceAll(command, "__port__", strconv.Itoa(foundPort))
|
|
||||||
|
|
||||||
c.Command = []string{
|
|
||||||
"sh",
|
|
||||||
"-c",
|
|
||||||
command,
|
|
||||||
}
|
|
||||||
initContainers = append(initContainers, c)
|
|
||||||
}
|
|
||||||
return initContainers
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepareProbes generate http/tcp/command probes for a service.
|
|
||||||
func prepareProbes(name string, s *types.ServiceConfig, container *helm.Container) {
|
|
||||||
// first, check if there a label for the probe
|
|
||||||
if check, ok := s.Labels[helm.LABEL_HEALTHCHECK]; ok {
|
|
||||||
check = strings.TrimSpace(check)
|
|
||||||
p := helm.NewProbeFromService(s)
|
|
||||||
// get the port of the "url" check
|
|
||||||
if checkurl, err := url.Parse(check); err == nil {
|
|
||||||
if err == nil {
|
|
||||||
container.LivenessProbe = buildProtoProbe(p, checkurl)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// it's a command
|
|
||||||
container.LivenessProbe = p
|
|
||||||
container.LivenessProbe.Exec = &helm.Exec{
|
|
||||||
Command: []string{
|
|
||||||
"sh",
|
|
||||||
"-c",
|
|
||||||
check,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return // label overrides everything
|
|
||||||
}
|
|
||||||
|
|
||||||
// if not, we will use the default one
|
|
||||||
if s.HealthCheck != nil {
|
|
||||||
container.LivenessProbe = buildCommandProbe(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildProtoProbe builds a probe from a url that can be http or tcp.
|
|
||||||
func buildProtoProbe(probe *helm.Probe, u *url.URL) *helm.Probe {
|
|
||||||
port, err := strconv.Atoi(u.Port())
|
|
||||||
if err != nil {
|
|
||||||
port = 80
|
|
||||||
}
|
|
||||||
|
|
||||||
path := "/"
|
|
||||||
if u.Path != "" {
|
|
||||||
path = u.Path
|
|
||||||
}
|
|
||||||
|
|
||||||
switch u.Scheme {
|
|
||||||
case "http", "https":
|
|
||||||
probe.HttpGet = &helm.HttpGet{
|
|
||||||
Path: path,
|
|
||||||
Port: port,
|
|
||||||
}
|
|
||||||
case "tcp":
|
|
||||||
probe.TCP = &helm.TCP{
|
|
||||||
Port: port,
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
logger.Redf("Error while parsing healthcheck url %s\n", u.String())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
return probe
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildCommandProbe(s *types.ServiceConfig) *helm.Probe {
|
|
||||||
|
|
||||||
// Get the first element of the command from ServiceConfig
|
|
||||||
first := s.HealthCheck.Test[0]
|
|
||||||
|
|
||||||
p := helm.NewProbeFromService(s)
|
|
||||||
switch first {
|
|
||||||
case "CMD", "CMD-SHELL":
|
|
||||||
// CMD or CMD-SHELL
|
|
||||||
p.Exec = &helm.Exec{
|
|
||||||
Command: s.HealthCheck.Test[1:],
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
default:
|
|
||||||
// badly made but it should work...
|
|
||||||
p.Exec = &helm.Exec{
|
|
||||||
Command: []string(s.HealthCheck.Test),
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepareEnvFromFiles generate configMap or secrets from environment files.
|
|
||||||
func prepareEnvFromFiles(name string, s *types.ServiceConfig, container *helm.Container, fileGeneratorChan HelmFileGenerator) {
|
|
||||||
|
|
||||||
// prepare secrets
|
|
||||||
secretsFiles := make([]string, 0)
|
|
||||||
if v, ok := s.Labels[helm.LABEL_ENV_SECRET]; ok {
|
|
||||||
secretsFiles = strings.Split(v, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
// manage environment files (env_file in compose)
|
|
||||||
for _, envfile := range s.EnvFile {
|
|
||||||
f := PathToName(envfile)
|
|
||||||
f = strings.ReplaceAll(f, ".env", "")
|
|
||||||
isSecret := false
|
|
||||||
for _, s := range secretsFiles {
|
|
||||||
s = strings.TrimSpace(s)
|
|
||||||
if s == envfile {
|
|
||||||
isSecret = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var store helm.InlineConfig
|
|
||||||
if !isSecret {
|
|
||||||
logger.Bluef(ICON_CONF+" Generating configMap from %s\n", envfile)
|
|
||||||
store = helm.NewConfigMap(name, envfile)
|
|
||||||
} else {
|
|
||||||
logger.Bluef(ICON_SECRET+" Generating secret from %s\n", envfile)
|
|
||||||
store = helm.NewSecret(name, envfile)
|
|
||||||
}
|
|
||||||
|
|
||||||
envfile = filepath.Join(compose.GetCurrentDir(), envfile)
|
|
||||||
if err := store.AddEnvFile(envfile); err != nil {
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Red(err.Error())
|
|
||||||
logger.ActivateColors = false
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
section := "configMapRef"
|
|
||||||
if isSecret {
|
|
||||||
section = "secretRef"
|
|
||||||
}
|
|
||||||
|
|
||||||
container.EnvFrom = append(container.EnvFrom, map[string]map[string]string{
|
|
||||||
section: {
|
|
||||||
"name": store.Metadata().Name,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// read the envfile and remove them from the container environment or secret
|
|
||||||
envs := readEnvFile(envfile)
|
|
||||||
for varname := range envs {
|
|
||||||
if !isSecret {
|
|
||||||
// remove varname from container
|
|
||||||
for i, s := range container.Env {
|
|
||||||
if s.Name == varname {
|
|
||||||
container.Env = append(container.Env[:i], container.Env[i+1:]...)
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if store != nil {
|
|
||||||
fileGeneratorChan <- store.(HelmFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddValues adds values to the values.yaml map.
|
|
||||||
func AddValues(servicename string, values map[string]EnvVal) {
|
|
||||||
locker.Lock()
|
|
||||||
defer locker.Unlock()
|
|
||||||
|
|
||||||
if _, ok := Values[servicename]; !ok {
|
|
||||||
Values[servicename] = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range values {
|
|
||||||
Values[servicename][k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddVolumeValues add a volume to the values.yaml map for the given deployment name.
|
|
||||||
func AddVolumeValues(deployment string, volname string, values map[string]EnvVal) {
|
|
||||||
locker.Lock()
|
|
||||||
defer locker.Unlock()
|
|
||||||
|
|
||||||
if _, ok := VolumeValues[deployment]; !ok {
|
|
||||||
VolumeValues[deployment] = make(map[string]map[string]EnvVal)
|
|
||||||
}
|
|
||||||
VolumeValues[deployment][volname] = values
|
|
||||||
}
|
|
||||||
|
|
||||||
func readEnvFile(envfilename string) map[string]EnvVal {
|
|
||||||
env := make(map[string]EnvVal)
|
|
||||||
content, err := ioutil.ReadFile(envfilename)
|
|
||||||
if err != nil {
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Red(err.Error())
|
|
||||||
logger.ActivateColors = false
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
// each value is on a separate line with KEY=value
|
|
||||||
lines := strings.Split(string(content), "\n")
|
|
||||||
for _, line := range lines {
|
|
||||||
if strings.Contains(line, "=") {
|
|
||||||
kv := strings.SplitN(line, "=", 2)
|
|
||||||
env[kv[0]] = kv[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return env
|
|
||||||
}
|
|
||||||
|
|
||||||
// applyEnvMapLabel will get all LABEL_MAP_ENV to rebuild the env map with tpl.
|
|
||||||
func applyEnvMapLabel(s *types.ServiceConfig, c *helm.Container) {
|
|
||||||
|
|
||||||
locker.Lock()
|
|
||||||
defer locker.Unlock()
|
|
||||||
mapenv, ok := s.Labels[helm.LABEL_MAP_ENV]
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// the mapenv is a YAML string
|
|
||||||
var envmap map[string]EnvVal
|
|
||||||
err := yaml.Unmarshal([]byte(mapenv), &envmap)
|
|
||||||
if err != nil {
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Red(err.Error())
|
|
||||||
logger.ActivateColors = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// add in envmap
|
|
||||||
for k, v := range envmap {
|
|
||||||
vstring := fmt.Sprintf("%v", v)
|
|
||||||
s.Environment[k] = &vstring
|
|
||||||
touched := false
|
|
||||||
if c.Env != nil {
|
|
||||||
c.Env = make([]*helm.Value, 0)
|
|
||||||
}
|
|
||||||
for _, env := range c.Env {
|
|
||||||
if env.Name == k {
|
|
||||||
env.Value = v
|
|
||||||
touched = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !touched {
|
|
||||||
c.Env = append(c.Env, &helm.Value{Name: k, Value: v})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// setEnvToValues will set the environment variables to the values.yaml map.
|
|
||||||
func setEnvToValues(name string, s *types.ServiceConfig, c *helm.Container) {
|
|
||||||
// crete the "environment" key
|
|
||||||
|
|
||||||
env := make(map[string]EnvVal)
|
|
||||||
for k, v := range s.Environment {
|
|
||||||
env[k] = v
|
|
||||||
}
|
|
||||||
if len(env) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
AddValues(name, map[string]EnvVal{"environment": env})
|
|
||||||
for k := range env {
|
|
||||||
v := "{{ tpl .Values." + name + ".environment." + k + " . }}"
|
|
||||||
s.Environment[k] = &v
|
|
||||||
touched := false
|
|
||||||
for _, c := range c.Env {
|
|
||||||
if c.Name == k {
|
|
||||||
c.Value = v
|
|
||||||
touched = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !touched {
|
|
||||||
c.Env = append(c.Env, &helm.Value{Name: k, Value: v})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setSecretVar(name string, s *types.ServiceConfig, c *helm.Container) *helm.Secret {
|
|
||||||
locker.Lock()
|
|
||||||
defer locker.Unlock()
|
|
||||||
// get the list of secret vars
|
|
||||||
secretvars, ok := s.Labels[helm.LABEL_SECRETVARS]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
store := helm.NewSecret(name, "")
|
|
||||||
for _, secretvar := range strings.Split(secretvars, ",") {
|
|
||||||
secretvar = strings.TrimSpace(secretvar)
|
|
||||||
// get the value from env
|
|
||||||
_, ok := s.Environment[secretvar]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// add the secret
|
|
||||||
store.AddEnv(secretvar, ".Values."+name+".environment."+secretvar)
|
|
||||||
for i, env := range c.Env {
|
|
||||||
if env.Name == secretvar {
|
|
||||||
c.Env = append(c.Env[:i], c.Env[i+1:]...)
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// remove env from ServiceConfig
|
|
||||||
delete(s.Environment, secretvar)
|
|
||||||
}
|
|
||||||
return store
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a container in deployment with all needed objects (volumes, secrets, env, ...).
|
|
||||||
// The deployName shoud be the name of the deployment, we cannot get it from Metadata as this is a variable name.
|
|
||||||
func newContainerForDeployment(deployName, containerName string, deployment *helm.Deployment, s *types.ServiceConfig, fileGeneratorChan HelmFileGenerator) *helm.Container {
|
|
||||||
container := helm.NewContainer(containerName, s.Image, s.Environment, s.Labels)
|
|
||||||
|
|
||||||
applyEnvMapLabel(s, container)
|
|
||||||
if secretFile := setSecretVar(containerName, s, container); secretFile != nil {
|
|
||||||
fileGeneratorChan <- secretFile
|
|
||||||
container.EnvFrom = append(container.EnvFrom, map[string]map[string]string{
|
|
||||||
"secretRef": {
|
|
||||||
"name": secretFile.Metadata().Name,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
setEnvToValues(containerName, s, container)
|
|
||||||
prepareContainer(container, s, containerName)
|
|
||||||
prepareEnvFromFiles(deployName, s, container, fileGeneratorChan)
|
|
||||||
|
|
||||||
// add the container in deployment
|
|
||||||
if deployment.Spec.Template.Spec.Containers == nil {
|
|
||||||
deployment.Spec.Template.Spec.Containers = make([]*helm.Container, 0)
|
|
||||||
}
|
|
||||||
deployment.Spec.Template.Spec.Containers = append(
|
|
||||||
deployment.Spec.Template.Spec.Containers,
|
|
||||||
container,
|
|
||||||
)
|
|
||||||
|
|
||||||
// add the volumes
|
|
||||||
if deployment.Spec.Template.Spec.Volumes == nil {
|
|
||||||
deployment.Spec.Template.Spec.Volumes = make([]map[string]interface{}, 0)
|
|
||||||
}
|
|
||||||
// manage LABEL_VOLUMEFROM
|
|
||||||
addVolumeFrom(deployment, container, s)
|
|
||||||
// and then we can add other volumes
|
|
||||||
deployment.Spec.Template.Spec.Volumes = append(
|
|
||||||
deployment.Spec.Template.Spec.Volumes,
|
|
||||||
prepareVolumes(deployName, containerName, s, container, fileGeneratorChan)...,
|
|
||||||
)
|
|
||||||
|
|
||||||
// add init containers
|
|
||||||
if deployment.Spec.Template.Spec.InitContainers == nil {
|
|
||||||
deployment.Spec.Template.Spec.InitContainers = make([]*helm.Container, 0)
|
|
||||||
}
|
|
||||||
deployment.Spec.Template.Spec.InitContainers = append(
|
|
||||||
deployment.Spec.Template.Spec.InitContainers,
|
|
||||||
prepareInitContainers(containerName, s, container)...,
|
|
||||||
)
|
|
||||||
|
|
||||||
return container
|
|
||||||
}
|
|
||||||
|
|
||||||
// addVolumeFrom takes the LABEL_VOLUMEFROM to get volumes from another container. This can only work with
|
|
||||||
// container that has got LABEL_SAMEPOD as we need to get the volumes from another container in the same deployment.
|
|
||||||
func addVolumeFrom(deployment *helm.Deployment, container *helm.Container, s *types.ServiceConfig) {
|
|
||||||
labelfrom, ok := s.Labels[helm.LABEL_VOLUMEFROM]
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode Yaml from the label
|
|
||||||
var volumesFrom map[string]map[string]string
|
|
||||||
err := yaml.Unmarshal([]byte(labelfrom), &volumesFrom)
|
|
||||||
if err != nil {
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Red(err.Error())
|
|
||||||
logger.ActivateColors = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each declared volume "from", we will find it from the deployment volumes and add it to the container.
|
|
||||||
// Then, to avoid duplicates, we will remove it from the ServiceConfig object.
|
|
||||||
for name, volumes := range volumesFrom {
|
|
||||||
for volumeName := range volumes {
|
|
||||||
initianame := volumeName
|
|
||||||
volumeName = PathToName(volumeName)
|
|
||||||
// get the volume from the deployment container "name"
|
|
||||||
var ctn *helm.Container
|
|
||||||
for _, c := range deployment.Spec.Template.Spec.Containers {
|
|
||||||
if c.Name == name {
|
|
||||||
ctn = c
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ctn == nil {
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Redf("VolumeFrom: container %s not found", name)
|
|
||||||
logger.ActivateColors = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// get the volume from the container
|
|
||||||
for _, v := range ctn.VolumeMounts {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
if v["name"] == volumeName {
|
|
||||||
if container.VolumeMounts == nil {
|
|
||||||
container.VolumeMounts = make([]interface{}, 0)
|
|
||||||
}
|
|
||||||
// make a copy of the volume mount and then add it to the VolumeMounts
|
|
||||||
var mountpoint = make(map[string]interface{})
|
|
||||||
for k, v := range v {
|
|
||||||
mountpoint[k] = v
|
|
||||||
}
|
|
||||||
container.VolumeMounts = append(container.VolumeMounts, mountpoint)
|
|
||||||
|
|
||||||
// remove the volume from the ServiceConfig
|
|
||||||
for i, vol := range s.Volumes {
|
|
||||||
if vol.Source == initianame {
|
|
||||||
s.Volumes = append(s.Volumes[:i], s.Volumes[i+1:]...)
|
|
||||||
i--
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,397 +0,0 @@
|
|||||||
package generator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"katenary/compose"
|
|
||||||
"katenary/helm"
|
|
||||||
"katenary/logger"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
const DOCKER_COMPOSE_YML = `version: '3'
|
|
||||||
services:
|
|
||||||
# first service, very simple
|
|
||||||
http:
|
|
||||||
image: nginx
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
|
|
||||||
# second service, with environment variables
|
|
||||||
http2:
|
|
||||||
image: nginx
|
|
||||||
environment:
|
|
||||||
SOME_ENV_VAR: some_value
|
|
||||||
ANOTHER_ENV_VAR: another_value
|
|
||||||
|
|
||||||
# third service with ingress label
|
|
||||||
web:
|
|
||||||
image: nginx
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
labels:
|
|
||||||
katenary.io/ingress: 80
|
|
||||||
|
|
||||||
web2:
|
|
||||||
image: nginx
|
|
||||||
command: ["/bin/sh", "-c", "while true; do echo hello; sleep 1; done"]
|
|
||||||
|
|
||||||
# fourth service is a php service depending on database
|
|
||||||
php:
|
|
||||||
image: php:7.2-apache
|
|
||||||
depends_on:
|
|
||||||
- database
|
|
||||||
environment:
|
|
||||||
SOME_ENV_VAR: some_value
|
|
||||||
ANOTHER_ENV_VAR: another_value
|
|
||||||
DB_HOST: database
|
|
||||||
labels:
|
|
||||||
katenary.io/mapenv: |
|
|
||||||
DB_HOST: {{ .Release.Name }}-database
|
|
||||||
|
|
||||||
database:
|
|
||||||
image: mysql:5.7
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: root
|
|
||||||
MYSQL_DATABASE: database
|
|
||||||
MYSQL_USER: user
|
|
||||||
MYSQL_PASSWORD: password
|
|
||||||
volumes:
|
|
||||||
- data:/var/lib/mysql
|
|
||||||
labels:
|
|
||||||
katenary.io/ports: 3306
|
|
||||||
|
|
||||||
|
|
||||||
# try to deploy 2 services but one is in the same pod than the other
|
|
||||||
http3:
|
|
||||||
image: nginx
|
|
||||||
|
|
||||||
http4:
|
|
||||||
image: nginx
|
|
||||||
labels:
|
|
||||||
katenary.io/same-pod: http3
|
|
||||||
|
|
||||||
# unmapped volumes
|
|
||||||
novol:
|
|
||||||
image: nginx
|
|
||||||
volumes:
|
|
||||||
- /tmp/data
|
|
||||||
labels:
|
|
||||||
katenary.io/ports: 80
|
|
||||||
|
|
||||||
# use = sign for environment variables
|
|
||||||
eqenv:
|
|
||||||
image: nginx
|
|
||||||
environment:
|
|
||||||
- SOME_ENV_VAR=some_value
|
|
||||||
- ANOTHER_ENV_VAR=another_value
|
|
||||||
|
|
||||||
# use environment file
|
|
||||||
useenvfile:
|
|
||||||
image: nginx
|
|
||||||
env_file:
|
|
||||||
- config/env
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
data:
|
|
||||||
`
|
|
||||||
|
|
||||||
var defaultCliFiles = cli.DefaultFileNames
|
|
||||||
var TMP_DIR = ""
|
|
||||||
var TMPWORK_DIR = ""
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
logger.NOLOG = len(os.Getenv("NOLOG")) < 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func setUp(t *testing.T) (string, *compose.Parser) {
|
|
||||||
|
|
||||||
// cleanup "made" files
|
|
||||||
helm.ResetMadePVC()
|
|
||||||
|
|
||||||
cli.DefaultFileNames = defaultCliFiles
|
|
||||||
|
|
||||||
// create a temporary directory
|
|
||||||
tmp, err := os.MkdirTemp(os.TempDir(), "katenary-test-")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpwork, err := os.MkdirTemp(os.TempDir(), "katenary-test-work-")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
composefile := filepath.Join(tmpwork, "docker-compose.yaml")
|
|
||||||
p := compose.NewParser(composefile, DOCKER_COMPOSE_YML)
|
|
||||||
|
|
||||||
// create envfile for "useenvfile" service
|
|
||||||
err = os.Mkdir(filepath.Join(tmpwork, "config"), 0777)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
envfile := filepath.Join(tmpwork, "config", "env")
|
|
||||||
fp, err := os.Create(envfile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("MKFILE", err)
|
|
||||||
}
|
|
||||||
fp.WriteString("FILEENV1=some_value\n")
|
|
||||||
fp.WriteString("FILEENV2=another_value\n")
|
|
||||||
fp.Close()
|
|
||||||
|
|
||||||
TMP_DIR = tmp
|
|
||||||
TMPWORK_DIR = tmpwork
|
|
||||||
|
|
||||||
p.Parse("testapp")
|
|
||||||
|
|
||||||
Generate(p, "test-0", "testapp", "1.2.3", "4.5.6", DOCKER_COMPOSE_YML, tmp)
|
|
||||||
|
|
||||||
return tmp, p
|
|
||||||
}
|
|
||||||
|
|
||||||
func tearDown() {
|
|
||||||
if len(TMP_DIR) > 0 {
|
|
||||||
os.RemoveAll(TMP_DIR)
|
|
||||||
}
|
|
||||||
if len(TMPWORK_DIR) > 0 {
|
|
||||||
os.RemoveAll(TMPWORK_DIR)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the web2 service has got a command.
|
|
||||||
func TestCommand(t *testing.T) {
|
|
||||||
tmp, p := setUp(t)
|
|
||||||
defer tearDown()
|
|
||||||
|
|
||||||
for _, service := range p.Data.Services {
|
|
||||||
name := service.Name
|
|
||||||
if name == "web2" {
|
|
||||||
// Ensure that the command is correctly set
|
|
||||||
// The command should be a string array
|
|
||||||
path := filepath.Join(tmp, "templates", name+".deployment.yaml")
|
|
||||||
path = filepath.Join(tmp, "templates", name+".deployment.yaml")
|
|
||||||
fp, _ := os.Open(path)
|
|
||||||
defer fp.Close()
|
|
||||||
lines, _ := ioutil.ReadAll(fp)
|
|
||||||
next := false
|
|
||||||
commands := make([]string, 0)
|
|
||||||
for _, line := range strings.Split(string(lines), "\n") {
|
|
||||||
if strings.Contains(line, "command") {
|
|
||||||
next = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if next {
|
|
||||||
commands = append(commands, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ok := 0
|
|
||||||
for _, command := range commands {
|
|
||||||
if strings.Contains(command, "- /bin/sh") {
|
|
||||||
ok++
|
|
||||||
}
|
|
||||||
if strings.Contains(command, "- -c") {
|
|
||||||
ok++
|
|
||||||
}
|
|
||||||
if strings.Contains(command, "while true; do") {
|
|
||||||
ok++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ok != 3 {
|
|
||||||
t.Error("Command is not correctly set")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if environment is correctly set.
|
|
||||||
func TestEnvs(t *testing.T) {
|
|
||||||
tmp, p := setUp(t)
|
|
||||||
defer tearDown()
|
|
||||||
|
|
||||||
for _, service := range p.Data.Services {
|
|
||||||
name := service.Name
|
|
||||||
|
|
||||||
if name == "php" {
|
|
||||||
// the "DB_HOST" environment variable inside the template must be set to '{{ .Release.Name }}-database'
|
|
||||||
path := filepath.Join(tmp, "templates", name+".deployment.yaml")
|
|
||||||
// read the file and find the DB_HOST variable
|
|
||||||
matched := false
|
|
||||||
fp, _ := os.Open(path)
|
|
||||||
defer fp.Close()
|
|
||||||
lines, _ := ioutil.ReadAll(fp)
|
|
||||||
next := false
|
|
||||||
for _, line := range strings.Split(string(lines), "\n") {
|
|
||||||
if !next && strings.Contains(line, "name: DB_HOST") {
|
|
||||||
next = true
|
|
||||||
continue
|
|
||||||
} else if next && strings.Contains(line, "value:") {
|
|
||||||
matched = true
|
|
||||||
if !strings.Contains(line, "{{ tpl .Values.php.environment.DB_HOST . }}") {
|
|
||||||
t.Error("DB_HOST variable should be set to {{ tpl .Values.php.environment.DB_HOST . }}", line, string(lines))
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !matched {
|
|
||||||
t.Error("DB_HOST variable not found in ", path)
|
|
||||||
t.Log(string(lines))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the same pod is not deployed twice.
|
|
||||||
func TestSamePod(t *testing.T) {
|
|
||||||
tmp, p := setUp(t)
|
|
||||||
defer tearDown()
|
|
||||||
|
|
||||||
for _, service := range p.Data.Services {
|
|
||||||
name := service.Name
|
|
||||||
path := filepath.Join(tmp, "templates", name+".deployment.yaml")
|
|
||||||
|
|
||||||
if _, found := service.Labels[helm.LABEL_SAMEPOD]; found {
|
|
||||||
// fail if the service has a deployment
|
|
||||||
if _, err := os.Stat(path); err == nil {
|
|
||||||
t.Error("Service ", name, " should not have a deployment")
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// others should have a deployment file
|
|
||||||
t.Log("Checking ", name, " deployment file")
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the ports are correctly set.
|
|
||||||
func TestPorts(t *testing.T) {
|
|
||||||
tmp, p := setUp(t)
|
|
||||||
defer tearDown()
|
|
||||||
|
|
||||||
for _, service := range p.Data.Services {
|
|
||||||
name := service.Name
|
|
||||||
path := ""
|
|
||||||
|
|
||||||
// if the service has a port found in helm.LABEL_PORT or ports, so the service file should exist
|
|
||||||
hasPort := false
|
|
||||||
if _, found := service.Labels[helm.LABEL_PORT]; found {
|
|
||||||
hasPort = true
|
|
||||||
}
|
|
||||||
if service.Ports != nil {
|
|
||||||
hasPort = true
|
|
||||||
}
|
|
||||||
if hasPort {
|
|
||||||
path = filepath.Join(tmp, "templates", name+".service.yaml")
|
|
||||||
t.Log("Checking ", name, " service file")
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the volumes are correctly set.
|
|
||||||
func TestPVC(t *testing.T) {
|
|
||||||
tmp, p := setUp(t)
|
|
||||||
defer tearDown()
|
|
||||||
|
|
||||||
for _, service := range p.Data.Services {
|
|
||||||
name := service.Name
|
|
||||||
path := filepath.Join(tmp, "templates", name+"-data.pvc.yaml")
|
|
||||||
|
|
||||||
// the "database" service should have a pvc file in templates (name-data.pvc.yaml)
|
|
||||||
if name == "database" {
|
|
||||||
path = filepath.Join(tmp, "templates", name+"-data.pvc.yaml")
|
|
||||||
t.Log("Checking ", name, " pvc file")
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
list, _ := filepath.Glob(tmp + "/templates/*")
|
|
||||||
t.Log(list)
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if web service has got a ingress.
|
|
||||||
func TestIngress(t *testing.T) {
|
|
||||||
tmp, p := setUp(t)
|
|
||||||
defer tearDown()
|
|
||||||
|
|
||||||
for _, service := range p.Data.Services {
|
|
||||||
name := service.Name
|
|
||||||
path := filepath.Join(tmp, "templates", name+".ingress.yaml")
|
|
||||||
|
|
||||||
// the "web" service should have a ingress file in templates (name.ingress.yaml)
|
|
||||||
if name == "web" {
|
|
||||||
path = filepath.Join(tmp, "templates", name+".ingress.yaml")
|
|
||||||
t.Log("Checking ", name, " ingress file")
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check unmapped volumes
|
|
||||||
func TestUnmappedVolumes(t *testing.T) {
|
|
||||||
tmp, p := setUp(t)
|
|
||||||
defer tearDown()
|
|
||||||
|
|
||||||
for _, service := range p.Data.Services {
|
|
||||||
name := service.Name
|
|
||||||
if name == "novol" {
|
|
||||||
path := filepath.Join(tmp, "templates", name+".deployment.yaml")
|
|
||||||
fp, _ := os.Open(path)
|
|
||||||
defer fp.Close()
|
|
||||||
lines, _ := ioutil.ReadAll(fp)
|
|
||||||
for _, line := range strings.Split(string(lines), "\n") {
|
|
||||||
if strings.Contains(line, "novol-data") {
|
|
||||||
t.Error("novol service should not have a volume")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if service using equal sign for environment works
|
|
||||||
func TestEqualSignOnEnv(t *testing.T) {
|
|
||||||
tmp, p := setUp(t)
|
|
||||||
defer tearDown()
|
|
||||||
|
|
||||||
// if the name is eqenv, the service should habe environment
|
|
||||||
for _, service := range p.Data.Services {
|
|
||||||
name := service.Name
|
|
||||||
if name == "eqenv" {
|
|
||||||
path := filepath.Join(tmp, "templates", name+".deployment.yaml")
|
|
||||||
fp, _ := os.Open(path)
|
|
||||||
defer fp.Close()
|
|
||||||
lines, _ := ioutil.ReadAll(fp)
|
|
||||||
match := 0
|
|
||||||
for _, line := range strings.Split(string(lines), "\n") {
|
|
||||||
// we must find the line with the environment variable name
|
|
||||||
if strings.Contains(line, "SOME_ENV_VAR") {
|
|
||||||
// we must find the line with the environment variable value
|
|
||||||
match++
|
|
||||||
}
|
|
||||||
if strings.Contains(line, "ANOTHER_ENV_VAR") {
|
|
||||||
// we must find the line with the environment variable value
|
|
||||||
match++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if match != 4 { // because the value points on .Values...
|
|
||||||
t.Error("eqenv service should have 2 environment variables")
|
|
||||||
t.Log(string(lines))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,22 +0,0 @@
|
|||||||
package generator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"katenary/compose"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// replaceChars replaces some chars in a string.
|
|
||||||
const replaceChars = `[^a-zA-Z0-9._]`
|
|
||||||
|
|
||||||
// GetRelPath return the relative path from the root of the project.
|
|
||||||
func GetRelPath(path string) string {
|
|
||||||
return strings.Replace(path, compose.GetCurrentDir(), ".", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PathToName transform a path to a yaml name.
|
|
||||||
func PathToName(path string) string {
|
|
||||||
path = strings.TrimPrefix(GetRelPath(path), "./")
|
|
||||||
path = regexp.MustCompile(replaceChars).ReplaceAllString(path, "-")
|
|
||||||
return path
|
|
||||||
}
|
|
@@ -1,231 +0,0 @@
|
|||||||
package generator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"katenary/compose"
|
|
||||||
"katenary/generator/writers"
|
|
||||||
"katenary/helm"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HelmFile represents a helm file from helm package that has got some necessary methods
|
|
||||||
// to generate a helm file.
|
|
||||||
type HelmFile interface {
|
|
||||||
GetType() string
|
|
||||||
GetPathRessource() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// HelmFileGenerator is a chanel of HelmFile.
|
|
||||||
type HelmFileGenerator chan HelmFile
|
|
||||||
|
|
||||||
var PrefixRE = regexp.MustCompile(`\{\{.*\}\}-?`)
|
|
||||||
|
|
||||||
func portExists(port int, ports []types.ServicePortConfig) bool {
|
|
||||||
for _, p := range ports {
|
|
||||||
if p.Target == uint32(port) {
|
|
||||||
log.Println("portExists:", port, p.Target)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate get a parsed compose file, and generate the helm files.
|
|
||||||
func Generate(p *compose.Parser, katernayVersion, appName, appVersion, chartVersion, composeFile, dirName string) {
|
|
||||||
|
|
||||||
// make the appname global (yes... ugly but easy)
|
|
||||||
helm.Appname = appName
|
|
||||||
helm.Version = katernayVersion
|
|
||||||
templatesDir := filepath.Join(dirName, "templates")
|
|
||||||
|
|
||||||
// try to create the directory
|
|
||||||
err := os.MkdirAll(templatesDir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
generators := make(map[string]HelmFileGenerator)
|
|
||||||
|
|
||||||
// remove skipped services from the parsed data
|
|
||||||
for i, service := range p.Data.Services {
|
|
||||||
if v, ok := service.Labels[helm.LABEL_IGNORE]; !ok || v != "true" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
p.Data.Services = append(p.Data.Services[:i], p.Data.Services[i+1:]...)
|
|
||||||
i--
|
|
||||||
|
|
||||||
// find this service in others as "depends_on" and remove it
|
|
||||||
for _, service2 := range p.Data.Services {
|
|
||||||
delete(service2.DependsOn, service.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, service := range p.Data.Services {
|
|
||||||
n := service.Name
|
|
||||||
|
|
||||||
// if the service port is declared in labels, add it to the service.
|
|
||||||
if ports, ok := service.Labels[helm.LABEL_PORT]; ok {
|
|
||||||
if service.Ports == nil {
|
|
||||||
service.Ports = make([]types.ServicePortConfig, 0)
|
|
||||||
}
|
|
||||||
for _, port := range strings.Split(ports, ",") {
|
|
||||||
target, err := strconv.Atoi(port)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
if portExists(target, service.Ports) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
service.Ports = append(service.Ports, types.ServicePortConfig{
|
|
||||||
Target: uint32(target),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// find port and store it in servicesMap
|
|
||||||
for _, port := range service.Ports {
|
|
||||||
target := int(port.Target)
|
|
||||||
if target != 0 {
|
|
||||||
servicesMap[n] = target
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// manage emptyDir volumes
|
|
||||||
if empty, ok := service.Labels[helm.LABEL_EMPTYDIRS]; ok {
|
|
||||||
//split empty list by coma
|
|
||||||
emptyDirs := strings.Split(empty, ",")
|
|
||||||
for i, emptyDir := range emptyDirs {
|
|
||||||
emptyDirs[i] = strings.TrimSpace(emptyDir)
|
|
||||||
}
|
|
||||||
//append them in EmptyDirs
|
|
||||||
EmptyDirs = append(EmptyDirs, emptyDirs...)
|
|
||||||
}
|
|
||||||
p.Data.Services[i] = service
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// for all services in linked map, and not in samePods map, generate the service
|
|
||||||
for _, s := range p.Data.Services {
|
|
||||||
name := s.Name
|
|
||||||
|
|
||||||
// do not make a deployment for services declared to be in the same pod than another
|
|
||||||
if _, ok := s.Labels[helm.LABEL_SAMEPOD]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// find services that is in the same pod
|
|
||||||
linked := make(map[string]types.ServiceConfig, 0)
|
|
||||||
for _, service := range p.Data.Services {
|
|
||||||
n := service.Name
|
|
||||||
if linkname, ok := service.Labels[helm.LABEL_SAMEPOD]; ok && linkname == name {
|
|
||||||
linked[n] = service
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
generators[name] = CreateReplicaObject(name, s, linked)
|
|
||||||
}
|
|
||||||
|
|
||||||
// to generate notes, we need to keep an Ingresses list
|
|
||||||
ingresses := make(map[string]*helm.Ingress)
|
|
||||||
|
|
||||||
for n, generator := range generators { // generators is a map : name -> generator
|
|
||||||
for helmFile := range generator { // generator is a chan
|
|
||||||
if helmFile == nil { // generator finished
|
|
||||||
break
|
|
||||||
}
|
|
||||||
kind := helmFile.(helm.Kinded).Get()
|
|
||||||
kind = strings.ToLower(kind)
|
|
||||||
|
|
||||||
// Add a SHA inside the generated file, it's only
|
|
||||||
// to make it easy to check it the compose file corresponds to the
|
|
||||||
// generated helm chart
|
|
||||||
helmFile.(helm.Signable).BuildSHA(composeFile)
|
|
||||||
|
|
||||||
// Some types need special fixes in yaml generation
|
|
||||||
switch c := helmFile.(type) {
|
|
||||||
case *helm.Storage:
|
|
||||||
// For storage, we need to add a "condition" to activate it
|
|
||||||
writers.BuildStorage(c, n, templatesDir)
|
|
||||||
|
|
||||||
case *helm.Deployment:
|
|
||||||
// for the deployment, we need to fix persitence volumes
|
|
||||||
// to be activated only when the storage is "enabled",
|
|
||||||
// either we use an "emptyDir"
|
|
||||||
writers.BuildDeployment(c, n, templatesDir)
|
|
||||||
|
|
||||||
case *helm.Service:
|
|
||||||
// Change the type for service if it's an "exposed" port
|
|
||||||
writers.BuildService(c, n, templatesDir)
|
|
||||||
|
|
||||||
case *helm.Ingress:
|
|
||||||
// we need to make ingresses "activable" from values
|
|
||||||
ingresses[n] = c // keep it to generate notes
|
|
||||||
writers.BuildIngress(c, n, templatesDir)
|
|
||||||
|
|
||||||
case *helm.ConfigMap, *helm.Secret:
|
|
||||||
// there could be several files, so let's force the filename
|
|
||||||
name := c.(helm.Named).Name() + "-" + c.GetType()
|
|
||||||
suffix := c.GetPathRessource()
|
|
||||||
suffix = PathToName(suffix)
|
|
||||||
name += suffix
|
|
||||||
name = PrefixRE.ReplaceAllString(name, "")
|
|
||||||
writers.BuildConfigMap(c, kind, n, name, templatesDir)
|
|
||||||
|
|
||||||
default:
|
|
||||||
fname := filepath.Join(templatesDir, n+"."+kind+".yaml")
|
|
||||||
fp, err := os.Create(fname)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer fp.Close()
|
|
||||||
enc := yaml.NewEncoder(fp)
|
|
||||||
enc.SetIndent(writers.IndentSize)
|
|
||||||
enc.Encode(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Create the values.yaml file
|
|
||||||
valueFile, err := os.Create(filepath.Join(dirName, "values.yaml"))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer valueFile.Close()
|
|
||||||
enc := yaml.NewEncoder(valueFile)
|
|
||||||
enc.SetIndent(writers.IndentSize)
|
|
||||||
enc.Encode(Values)
|
|
||||||
|
|
||||||
// Create tht Chart.yaml file
|
|
||||||
chartFile, err := os.Create(filepath.Join(dirName, "Chart.yaml"))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer chartFile.Close()
|
|
||||||
chartFile.WriteString(`# Create on ` + time.Now().Format(time.RFC3339) + "\n")
|
|
||||||
chartFile.WriteString(`# Katenary command line: ` + strings.Join(os.Args, " ") + "\n")
|
|
||||||
enc = yaml.NewEncoder(chartFile)
|
|
||||||
enc.SetIndent(writers.IndentSize)
|
|
||||||
enc.Encode(map[string]interface{}{
|
|
||||||
"apiVersion": "v2",
|
|
||||||
"name": appName,
|
|
||||||
"description": "A helm chart for " + appName,
|
|
||||||
"type": "application",
|
|
||||||
"version": chartVersion,
|
|
||||||
"appVersion": appVersion,
|
|
||||||
})
|
|
||||||
|
|
||||||
// And finally, create a NOTE.txt file
|
|
||||||
noteFile, err := os.Create(filepath.Join(templatesDir, "NOTES.txt"))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer noteFile.Close()
|
|
||||||
noteFile.WriteString(helm.GenerateNotesFile(ingresses))
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
package writers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BuildConfigMap writes the configMap.
|
|
||||||
func BuildConfigMap(c interface{}, kind, servicename, name, templatesDir string) {
|
|
||||||
fname := filepath.Join(templatesDir, name+"."+kind+".yaml")
|
|
||||||
fp, _ := os.Create(fname)
|
|
||||||
enc := yaml.NewEncoder(fp)
|
|
||||||
enc.SetIndent(IndentSize)
|
|
||||||
enc.Encode(c)
|
|
||||||
fp.Close()
|
|
||||||
}
|
|
@@ -1,44 +0,0 @@
|
|||||||
package writers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"katenary/helm"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BuildDeployment builds a deployment.
|
|
||||||
func BuildDeployment(deployment *helm.Deployment, name, templatesDir string) {
|
|
||||||
kind := "deployment"
|
|
||||||
fname := filepath.Join(templatesDir, name+"."+kind+".yaml")
|
|
||||||
fp, _ := os.Create(fname)
|
|
||||||
buffer := bytes.NewBuffer(nil)
|
|
||||||
enc := yaml.NewEncoder(buffer)
|
|
||||||
enc.SetIndent(IndentSize)
|
|
||||||
enc.Encode(deployment)
|
|
||||||
_content := string(buffer.Bytes())
|
|
||||||
content := strings.Split(string(_content), "\n")
|
|
||||||
dataname := ""
|
|
||||||
component := deployment.Spec.Selector["matchLabels"].(map[string]string)[helm.K+"/component"]
|
|
||||||
n := 0 // will be count of lines only on "persistentVolumeClaim" line, to indent "else" and "end" at the right place
|
|
||||||
for _, line := range content {
|
|
||||||
if strings.Contains(line, "name:") {
|
|
||||||
dataname = strings.Split(line, ":")[1]
|
|
||||||
dataname = strings.TrimSpace(dataname)
|
|
||||||
} else if strings.Contains(line, "persistentVolumeClaim") {
|
|
||||||
n = CountSpaces(line)
|
|
||||||
line = strings.Repeat(" ", n) + "{{- if .Values." + component + ".persistence." + dataname + ".enabled }}\n" + line
|
|
||||||
} else if strings.Contains(line, "claimName") {
|
|
||||||
spaces := strings.Repeat(" ", n)
|
|
||||||
line += "\n" + spaces + "{{ else }}"
|
|
||||||
line += "\n" + spaces + "emptyDir: {}"
|
|
||||||
line += "\n" + spaces + "{{- end }}"
|
|
||||||
}
|
|
||||||
fp.WriteString(line + "\n")
|
|
||||||
}
|
|
||||||
fp.Close()
|
|
||||||
|
|
||||||
}
|
|
@@ -1,101 +0,0 @@
|
|||||||
package writers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"katenary/helm"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
classAndVersionCondition = `{{- if and .Values.__name__.ingress.class (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}` + "\n"
|
|
||||||
versionCondition118 = `{{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }}` + "\n"
|
|
||||||
versionCondition119 = `{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}` + "\n"
|
|
||||||
apiVersion = `{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
apiVersion: networking.k8s.io/v1beta1
|
|
||||||
{{- else -}}
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
{{- end }}`
|
|
||||||
)
|
|
||||||
|
|
||||||
// BuildIngress generates the ingress yaml file with conditions.
|
|
||||||
func BuildIngress(ingress *helm.Ingress, name, templatesDir string) {
|
|
||||||
// Set the backend for 1.18
|
|
||||||
for _, b := range ingress.Spec.Rules {
|
|
||||||
for _, p := range b.Http.Paths {
|
|
||||||
p.Backend.ServiceName = p.Backend.Service.Name
|
|
||||||
if n, ok := p.Backend.Service.Port["number"]; ok {
|
|
||||||
p.Backend.ServicePort = n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kind := "ingress"
|
|
||||||
buffer := bytes.NewBuffer(nil)
|
|
||||||
fname := filepath.Join(templatesDir, name+"."+kind+".yaml")
|
|
||||||
enc := yaml.NewEncoder(buffer)
|
|
||||||
enc.SetIndent(IndentSize)
|
|
||||||
buffer.WriteString("{{- if .Values." + name + ".ingress.enabled -}}\n")
|
|
||||||
enc.Encode(ingress)
|
|
||||||
buffer.WriteString("{{- end -}}")
|
|
||||||
|
|
||||||
fp, err := os.Create(fname)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer fp.Close()
|
|
||||||
|
|
||||||
content := string(buffer.Bytes())
|
|
||||||
lines := strings.Split(content, "\n")
|
|
||||||
|
|
||||||
backendHit := false
|
|
||||||
for _, l := range lines {
|
|
||||||
// apiVersion is a pain...
|
|
||||||
if strings.Contains(l, "apiVersion:") {
|
|
||||||
l = apiVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
// add annotations linked to the Values
|
|
||||||
if strings.Contains(l, "annotations:") {
|
|
||||||
n := CountSpaces(l) + IndentSize
|
|
||||||
l += "\n" + strings.Repeat(" ", n) + "{{- range $k, $v := .Values.__name__.ingress.annotations }}\n"
|
|
||||||
l += strings.Repeat(" ", n) + "{{ $k }}: {{ $v }}\n"
|
|
||||||
l += strings.Repeat(" ", n) + "{{- end }}"
|
|
||||||
l = strings.ReplaceAll(l, "__name__", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pathTyype is ony for 1.19+
|
|
||||||
if strings.Contains(l, "pathType:") {
|
|
||||||
n := CountSpaces(l)
|
|
||||||
l = strings.Repeat(" ", n) + versionCondition118 +
|
|
||||||
l + "\n" +
|
|
||||||
strings.Repeat(" ", n) + "{{- end }}"
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(l, "ingressClassName") {
|
|
||||||
// should be set only if the version of Kubernetes is 1.18-0 or higher
|
|
||||||
cond := strings.ReplaceAll(classAndVersionCondition, "__name__", name)
|
|
||||||
l = ` ` + cond + l + "\n" + ` {{- end }}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// manage the backend format following the Kubernetes 1.19-0 version or higher
|
|
||||||
if strings.Contains(l, "service:") {
|
|
||||||
n := CountSpaces(l)
|
|
||||||
l = strings.Repeat(" ", n) + versionCondition119 + l
|
|
||||||
}
|
|
||||||
if strings.Contains(l, "serviceName:") || strings.Contains(l, "servicePort:") {
|
|
||||||
n := CountSpaces(l)
|
|
||||||
if !backendHit {
|
|
||||||
l = strings.Repeat(" ", n) + "{{- else }}\n" + l
|
|
||||||
} else {
|
|
||||||
l = l + "\n" + strings.Repeat(" ", n) + "{{- end }}\n"
|
|
||||||
}
|
|
||||||
backendHit = true
|
|
||||||
}
|
|
||||||
fp.WriteString(l + "\n")
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,24 +0,0 @@
|
|||||||
package writers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"katenary/helm"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BuildService writes the service (external or not).
|
|
||||||
func BuildService(service *helm.Service, name, templatesDir string) {
|
|
||||||
kind := "service"
|
|
||||||
suffix := ""
|
|
||||||
if service.Spec.Type == "NodePort" {
|
|
||||||
suffix = "-external"
|
|
||||||
}
|
|
||||||
fname := filepath.Join(templatesDir, name+suffix+"."+kind+".yaml")
|
|
||||||
fp, _ := os.Create(fname)
|
|
||||||
enc := yaml.NewEncoder(fp)
|
|
||||||
enc.SetIndent(IndentSize)
|
|
||||||
enc.Encode(service)
|
|
||||||
fp.Close()
|
|
||||||
}
|
|
@@ -1,32 +0,0 @@
|
|||||||
package writers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"katenary/helm"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BuildStorage writes the persistentVolumeClaim.
|
|
||||||
func BuildStorage(storage *helm.Storage, name, templatesDir string) {
|
|
||||||
kind := "pvc"
|
|
||||||
name = storage.Metadata.Labels[helm.K+"/component"]
|
|
||||||
pvcname := storage.Metadata.Labels[helm.K+"/pvc-name"]
|
|
||||||
fname := filepath.Join(templatesDir, name+"-"+pvcname+"."+kind+".yaml")
|
|
||||||
fp, err := os.Create(fname)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer fp.Close()
|
|
||||||
volname := storage.K8sBase.Metadata.Labels[helm.K+"/pvc-name"]
|
|
||||||
|
|
||||||
fp.WriteString("{{ if .Values." + name + ".persistence." + volname + ".enabled }}\n")
|
|
||||||
enc := yaml.NewEncoder(fp)
|
|
||||||
enc.SetIndent(IndentSize)
|
|
||||||
if err := enc.Encode(storage); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
fp.WriteString("{{- end -}}")
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
package writers
|
|
||||||
|
|
||||||
// IndentSize set the indentation size for yaml output. Could ba changed by command line argument.
|
|
||||||
var IndentSize = 2
|
|
||||||
|
|
||||||
// CountSpaces returns the number of spaces from the begining of the line.
|
|
||||||
func CountSpaces(line string) int {
|
|
||||||
var spaces int
|
|
||||||
for _, char := range line {
|
|
||||||
if char == ' ' {
|
|
||||||
spaces++
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return spaces
|
|
||||||
}
|
|
65
go.mod
@@ -1,16 +1,57 @@
|
|||||||
module katenary
|
module github.com/katenary/katenary
|
||||||
|
|
||||||
go 1.16
|
go 1.25
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/compose-spec/compose-go v1.2.4
|
github.com/compose-spec/compose-go v1.20.2
|
||||||
github.com/distribution/distribution/v3 v3.0.0-20220505155552-985711c1f414 // indirect
|
github.com/invopop/jsonschema v0.13.0
|
||||||
github.com/kr/pretty v0.2.0 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/spf13/cobra v1.9.1
|
||||||
github.com/spf13/cobra v1.4.0
|
github.com/thediveo/netdb v1.1.2
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
golang.org/x/mod v0.5.1
|
k8s.io/api v0.33.4
|
||||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
|
k8s.io/apimachinery v0.33.4
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
sigs.k8s.io/yaml v1.6.0
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||||
|
github.com/buger/jsonparser v1.1.1 // indirect
|
||||||
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
|
github.com/docker/go-connections v0.6.0 // indirect
|
||||||
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/imdario/mergo v0.3.16 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
github.com/mailru/easyjson v0.9.0 // indirect
|
||||||
|
github.com/mattn/go-shellwords v1.0.12 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.7 // indirect
|
||||||
|
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||||
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
|
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 // indirect
|
||||||
|
golang.org/x/net v0.43.0 // indirect
|
||||||
|
golang.org/x/sync v0.16.0 // indirect
|
||||||
|
golang.org/x/sys v0.35.0 // indirect
|
||||||
|
golang.org/x/text v0.28.0 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||||
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
|
||||||
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||||
)
|
)
|
||||||
|
374
go.sum
@@ -1,192 +1,92 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||||
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
github.com/Azure/azure-sdk-for-go v56.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
github.com/compose-spec/compose-go v1.20.2 h1:u/yfZHn4EaHGdidrZycWpxXgFffjYULlTbRfJ51ykjQ=
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
github.com/compose-spec/compose-go v1.20.2/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
|
||||||
github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
|
||||||
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
|
|
||||||
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
|
||||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
|
||||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
|
||||||
github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
|
||||||
github.com/aws/aws-sdk-go v1.43.16/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
|
||||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
|
||||||
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
|
||||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
|
||||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
|
||||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/compose-spec/compose-go v1.2.4 h1:nzTFqM8+2J7Veao5Pq5U451thinv3U1wChIvcjX59/A=
|
|
||||||
github.com/compose-spec/compose-go v1.2.4/go.mod h1:pAy7Mikpeft4pxkFU565/DRHEbDfR84G6AQuiL+Hdg8=
|
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||||
github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e/go.mod h1:xpWTC2KnJMiDLkoawhsPQcXjvwATEBcbq0xevG2YR9M=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/distribution/distribution/v3 v3.0.0-20220504180456-7a6b9e3042bd h1:KRoLSsR7wZ4H2dueR/O6BGBIXDxfOxUVmaMiu1QiQPw=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/distribution/distribution/v3 v3.0.0-20220504180456-7a6b9e3042bd/go.mod h1:qLi7jGj1b5TUaYTB3ekkHiocxHJi8+3CFhXM54MGKBs=
|
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||||
github.com/distribution/distribution/v3 v3.0.0-20220505155552-985711c1f414 h1:KfVB1Z5fm10trO24Rn5Zzocd8sTm5k/gS24ijxQ1aJU=
|
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
github.com/distribution/distribution/v3 v3.0.0-20220505155552-985711c1f414/go.mod h1:2oyLKljQFnsI1tzJxjUg4GI+HEpDfzFP3LrGM04rKg0=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
|
||||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
|
||||||
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
|
||||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||||
|
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
|
||||||
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
|
||||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
|
||||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
|
||||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
|
||||||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
|
||||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/thediveo/netdb v1.1.2 h1:XdLx/YJPutxrSkPYtmCAIY5sgAvxtkS1Tz+Z0UX2I+U=
|
||||||
|
github.com/thediveo/netdb v1.1.2/go.mod h1:KJczM//7VIIiovQO1qDooHvM8+0pt6RdRt3rVDZxEGM=
|
||||||
|
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||||
|
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||||
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
@@ -194,111 +94,75 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
|
|||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
|
||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
|
||||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||||
|
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
k8s.io/api v0.33.4 h1:oTzrFVNPXBjMu0IlpA2eDDIU49jsuEorGHB4cvKupkk=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
k8s.io/api v0.33.4/go.mod h1:VHQZ4cuxQ9sCUMESJV5+Fe8bGnqAARZ08tSTdHWfeAc=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
k8s.io/apimachinery v0.33.4 h1:SOf/JW33TP0eppJMkIgQ+L6atlDiP/090oaX0y9pd9s=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
k8s.io/apimachinery v0.33.4/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk=
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
|
||||||
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||||
|
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
|
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||||
|
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||||
|
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||||
|
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||||
|
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||||
|
@@ -1,126 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InlineConfig is made to represent a configMap or a secret
|
|
||||||
type InlineConfig interface {
|
|
||||||
AddEnvFile(filename string) error
|
|
||||||
AddEnv(key, val string) error
|
|
||||||
Metadata() *Metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigMap is made to represent a configMap with data.
|
|
||||||
type ConfigMap struct {
|
|
||||||
*K8sBase `yaml:",inline"`
|
|
||||||
Data map[string]string `yaml:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConfigMap returns a new initialzed ConfigMap.
|
|
||||||
func NewConfigMap(name, path string) *ConfigMap {
|
|
||||||
base := NewBase()
|
|
||||||
base.ApiVersion = "v1"
|
|
||||||
base.Kind = "ConfigMap"
|
|
||||||
base.Metadata.Name = ReleaseNameTpl + "-" + name
|
|
||||||
base.Metadata.Labels[K+"/component"] = name
|
|
||||||
if path != "" {
|
|
||||||
base.Metadata.Labels[K+"/path"] = path
|
|
||||||
}
|
|
||||||
return &ConfigMap{
|
|
||||||
K8sBase: base,
|
|
||||||
Data: make(map[string]string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metadata returns the metadata of the configMap.
|
|
||||||
func (c *ConfigMap) Metadata() *Metadata {
|
|
||||||
return c.K8sBase.Metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddEnvFile adds an environment file to the configMap.
|
|
||||||
func (c *ConfigMap) AddEnvFile(file string) error {
|
|
||||||
content, err := ioutil.ReadFile(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
lines := strings.Split(string(content), "\n")
|
|
||||||
for _, l := range lines {
|
|
||||||
l = strings.TrimSpace(l)
|
|
||||||
if len(l) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parts := strings.SplitN(l, "=", 2)
|
|
||||||
if len(parts) < 2 {
|
|
||||||
return errors.New("The environment file " + file + " is not valid")
|
|
||||||
}
|
|
||||||
c.Data[parts[0]] = parts[1]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConfigMap) AddEnv(key, val string) error {
|
|
||||||
c.Data[key] = val
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Secret is made to represent a secret with data.
|
|
||||||
type Secret struct {
|
|
||||||
*K8sBase `yaml:",inline"`
|
|
||||||
Data map[string]string `yaml:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSecret returns a new initialzed Secret.
|
|
||||||
func NewSecret(name, path string) *Secret {
|
|
||||||
base := NewBase()
|
|
||||||
base.ApiVersion = "v1"
|
|
||||||
base.Kind = "Secret"
|
|
||||||
base.Metadata.Name = ReleaseNameTpl + "-" + name
|
|
||||||
base.Metadata.Labels[K+"/component"] = name
|
|
||||||
if path != "" {
|
|
||||||
base.Metadata.Labels[K+"/path"] = path
|
|
||||||
}
|
|
||||||
return &Secret{
|
|
||||||
K8sBase: base,
|
|
||||||
Data: make(map[string]string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddEnvFile adds an environment file to the secret.
|
|
||||||
func (s *Secret) AddEnvFile(file string) error {
|
|
||||||
content, err := ioutil.ReadFile(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
lines := strings.Split(string(content), "\n")
|
|
||||||
for _, l := range lines {
|
|
||||||
l = strings.TrimSpace(l)
|
|
||||||
if len(l) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parts := strings.SplitN(l, "=", 2)
|
|
||||||
if len(parts) < 2 {
|
|
||||||
return errors.New("The environment file " + file + " is not valid")
|
|
||||||
}
|
|
||||||
s.Data[parts[0]] = fmt.Sprintf(`{{ "%s" | b64enc }}`, parts[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metadata returns the metadata of the secret.
|
|
||||||
func (s *Secret) Metadata() *Metadata {
|
|
||||||
return s.K8sBase.Metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddEnv adds an environment variable to the secret.
|
|
||||||
func (s *Secret) AddEnv(key, val string) error {
|
|
||||||
s.Data[key] = fmt.Sprintf(`{{ %s | b64enc }}`, val)
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -1,65 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"katenary/logger"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EnvValue interface{}
|
|
||||||
|
|
||||||
// ContainerPort represent a port mapping.
|
|
||||||
type ContainerPort struct {
|
|
||||||
Name string
|
|
||||||
ContainerPort int `yaml:"containerPort"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value represent a environment variable with name and value.
|
|
||||||
type Value struct {
|
|
||||||
Name string `yaml:"name"`
|
|
||||||
Value EnvValue `yaml:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Container represent a container with name, image, and environment variables. It is used in Deployment.
|
|
||||||
type Container struct {
|
|
||||||
Name string `yaml:"name,omitempty"`
|
|
||||||
Image string `yaml:"image"`
|
|
||||||
Ports []*ContainerPort `yaml:"ports,omitempty"`
|
|
||||||
Env []*Value `yaml:"env,omitempty"`
|
|
||||||
EnvFrom []map[string]map[string]string `yaml:"envFrom,omitempty"`
|
|
||||||
Command []string `yaml:"command,omitempty"`
|
|
||||||
VolumeMounts []interface{} `yaml:"volumeMounts,omitempty"`
|
|
||||||
LivenessProbe *Probe `yaml:"livenessProbe,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContainer creates a new container with name, image, labels and environment variables.
|
|
||||||
func NewContainer(name, image string, environment types.MappingWithEquals, labels map[string]string) *Container {
|
|
||||||
container := &Container{
|
|
||||||
Image: image,
|
|
||||||
Name: name,
|
|
||||||
EnvFrom: make([]map[string]map[string]string, 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
// find bound environment variable to a service
|
|
||||||
toServices := make([]string, 0)
|
|
||||||
if bound, ok := labels[LABEL_ENV_SERVICE]; ok {
|
|
||||||
toServices = strings.Split(bound, ",")
|
|
||||||
}
|
|
||||||
if len(toServices) > 0 {
|
|
||||||
// warn, it's deprecated now
|
|
||||||
logger.ActivateColors = true
|
|
||||||
logger.Yellowf(
|
|
||||||
"[deprecated] in \"%s\" service: label %s is deprecated and **ignored**, please use %s instead\n"+
|
|
||||||
"e.g.\n"+
|
|
||||||
" labels:\n"+
|
|
||||||
" FOO: {{ .Release.Name }}-fooservice\n",
|
|
||||||
name,
|
|
||||||
LABEL_ENV_SERVICE,
|
|
||||||
LABEL_MAP_ENV,
|
|
||||||
)
|
|
||||||
logger.ActivateColors = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return container
|
|
||||||
}
|
|
@@ -1,39 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
// Deployment is a k8s deployment.
|
|
||||||
type Deployment struct {
|
|
||||||
*K8sBase `yaml:",inline"`
|
|
||||||
Spec *DepSpec `yaml:"spec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDeployment(name string) *Deployment {
|
|
||||||
d := &Deployment{K8sBase: NewBase(), Spec: NewDepSpec()}
|
|
||||||
d.K8sBase.Metadata.Name = ReleaseNameTpl + "-" + name
|
|
||||||
d.K8sBase.ApiVersion = "apps/v1"
|
|
||||||
d.K8sBase.Kind = "Deployment"
|
|
||||||
d.K8sBase.Metadata.Labels[K+"/component"] = name
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
type DepSpec struct {
|
|
||||||
Replicas int `yaml:"replicas"`
|
|
||||||
Selector map[string]interface{} `yaml:"selector"`
|
|
||||||
Template PodTemplate `yaml:"template"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDepSpec() *DepSpec {
|
|
||||||
return &DepSpec{
|
|
||||||
Replicas: 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PodSpec struct {
|
|
||||||
InitContainers []*Container `yaml:"initContainers,omitempty"`
|
|
||||||
Containers []*Container `yaml:"containers"`
|
|
||||||
Volumes []map[string]interface{} `yaml:"volumes,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type PodTemplate struct {
|
|
||||||
Metadata Metadata `yaml:"metadata"`
|
|
||||||
Spec PodSpec `yaml:"spec"`
|
|
||||||
}
|
|
@@ -1,54 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
// Ingress is the kubernetes ingress object.
|
|
||||||
type Ingress struct {
|
|
||||||
*K8sBase `yaml:",inline"`
|
|
||||||
Spec IngressSpec
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewIngress(name string) *Ingress {
|
|
||||||
i := &Ingress{}
|
|
||||||
i.K8sBase = NewBase()
|
|
||||||
i.K8sBase.Metadata.Name = ReleaseNameTpl + "-" + name
|
|
||||||
i.K8sBase.Kind = "Ingress"
|
|
||||||
i.ApiVersion = "networking.k8s.io/v1"
|
|
||||||
i.K8sBase.Metadata.Labels[K+"/component"] = name
|
|
||||||
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Ingress) SetIngressClass(name string) {
|
|
||||||
class := "{{ .Values." + name + ".ingress.class }}"
|
|
||||||
i.Spec.IngressClassName = class
|
|
||||||
}
|
|
||||||
|
|
||||||
type IngressSpec struct {
|
|
||||||
IngressClassName string `yaml:"ingressClassName,omitempty"`
|
|
||||||
Rules []IngressRule
|
|
||||||
}
|
|
||||||
|
|
||||||
type IngressRule struct {
|
|
||||||
Host string
|
|
||||||
Http IngressHttp
|
|
||||||
}
|
|
||||||
|
|
||||||
type IngressHttp struct {
|
|
||||||
Paths []IngressPath
|
|
||||||
}
|
|
||||||
|
|
||||||
type IngressPath struct {
|
|
||||||
Path string
|
|
||||||
PathType string `yaml:"pathType"`
|
|
||||||
Backend *IngressBackend
|
|
||||||
}
|
|
||||||
|
|
||||||
type IngressBackend struct {
|
|
||||||
Service IngressService
|
|
||||||
ServiceName string `yaml:"serviceName"` // for kubernetes version < 1.18
|
|
||||||
ServicePort interface{} `yaml:"servicePort"` // for kubernetes version < 1.18
|
|
||||||
}
|
|
||||||
|
|
||||||
type IngressService struct {
|
|
||||||
Name string `yaml:"name"`
|
|
||||||
Port map[string]interface{} `yaml:"port"`
|
|
||||||
}
|
|
@@ -1,73 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha1"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Metadata is the metadata for a kubernetes object.
|
|
||||||
type Metadata struct {
|
|
||||||
Name string `yaml:"name,omitempty"`
|
|
||||||
Labels map[string]string `yaml:"labels"`
|
|
||||||
Annotations map[string]string `yaml:"annotations,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMetadata() *Metadata {
|
|
||||||
return &Metadata{
|
|
||||||
Name: "",
|
|
||||||
Labels: make(map[string]string),
|
|
||||||
Annotations: make(map[string]string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// K8sBase is the base for all kubernetes objects.
|
|
||||||
type K8sBase struct {
|
|
||||||
ApiVersion string `yaml:"apiVersion"`
|
|
||||||
Kind string `yaml:"kind"`
|
|
||||||
Metadata *Metadata `yaml:"metadata"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBase is a factory for creating a new base object with metadata, labels and annotations set to the default.
|
|
||||||
func NewBase() *K8sBase {
|
|
||||||
b := &K8sBase{
|
|
||||||
Metadata: NewMetadata(),
|
|
||||||
}
|
|
||||||
// add some information of the build
|
|
||||||
b.Metadata.Labels[K+"/project"] = "{{ .Chart.Name }}"
|
|
||||||
b.Metadata.Labels[K+"/release"] = ReleaseNameTpl
|
|
||||||
b.Metadata.Annotations[K+"/version"] = Version
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *K8sBase) BuildSHA(filename string) {
|
|
||||||
c, _ := ioutil.ReadFile(filename)
|
|
||||||
//sum := sha256.Sum256(c)
|
|
||||||
sum := sha1.Sum(c)
|
|
||||||
k.Metadata.Annotations[K+"/docker-compose-sha1"] = fmt.Sprintf("%x", string(sum[:]))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the Kind.
|
|
||||||
func (k *K8sBase) Get() string {
|
|
||||||
return k.Kind
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the name of the object from Metadata.
|
|
||||||
func (k *K8sBase) Name() string {
|
|
||||||
return k.Metadata.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *K8sBase) GetType() string {
|
|
||||||
if n, ok := k.Metadata.Labels[K+"/type"]; ok {
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
return strings.ToLower(k.Kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *K8sBase) GetPathRessource() string {
|
|
||||||
if p, ok := k.Metadata.Labels[K+"/path"]; ok {
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
@@ -1,61 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"html/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
const ReleaseNameTpl = "{{ .Release.Name }}"
|
|
||||||
const (
|
|
||||||
LABEL_MAP_ENV = K + "/mapenv"
|
|
||||||
LABEL_ENV_SECRET = K + "/secret-envfiles"
|
|
||||||
LABEL_PORT = K + "/ports"
|
|
||||||
LABEL_INGRESS = K + "/ingress"
|
|
||||||
LABEL_VOL_CM = K + "/configmap-volumes"
|
|
||||||
LABEL_HEALTHCHECK = K + "/healthcheck"
|
|
||||||
LABEL_SAMEPOD = K + "/same-pod"
|
|
||||||
LABEL_VOLUMEFROM = K + "/volume-from"
|
|
||||||
LABEL_EMPTYDIRS = K + "/empty-dirs"
|
|
||||||
LABEL_IGNORE = K + "/ignore"
|
|
||||||
LABEL_SECRETVARS = K + "/secret-vars"
|
|
||||||
|
|
||||||
//deprecated: use LABEL_MAP_ENV instead
|
|
||||||
LABEL_ENV_SERVICE = K + "/env-to-service"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetLabelsDocumentation returns the documentation for the labels.
|
|
||||||
func GetLabelsDocumentation() string {
|
|
||||||
t, _ := template.New("labels").Parse(`
|
|
||||||
# Labels
|
|
||||||
{{.LABEL_IGNORE | printf "%-33s"}}: ignore the container, it will not yied any object in the helm chart
|
|
||||||
{{.LABEL_SECRETVARS | printf "%-33s"}}: secret variables to push on a secret file
|
|
||||||
{{.LABEL_ENV_SECRET | printf "%-33s"}}: set the given file names as a secret instead of configmap
|
|
||||||
{{.LABEL_MAP_ENV | printf "%-33s"}}: map environment variable to a template string (yaml style)
|
|
||||||
{{.LABEL_PORT | printf "%-33s"}}: set the ports to expose as a service (coma separated)
|
|
||||||
{{.LABEL_INGRESS | printf "%-33s"}}: set the port to expose in an ingress (coma separated)
|
|
||||||
{{.LABEL_VOL_CM | printf "%-33s"}}: specifies that the volumes points on a configmap (coma separated)
|
|
||||||
{{.LABEL_SAMEPOD | printf "%-33s"}}: specifies that the pod should be deployed in the same pod than the given service name
|
|
||||||
{{.LABEL_VOLUMEFROM | printf "%-33s"}}: specifies that the volumes to be mounted from the given service (yaml style)
|
|
||||||
{{.LABEL_EMPTYDIRS | printf "%-33s"}}: specifies that the given volume names should be "emptyDir" instead of persistentVolumeClaim (coma separated)
|
|
||||||
{{.LABEL_HEALTHCHECK | printf "%-33s"}}: specifies that the container should be monitored by a healthcheck, **it overrides the docker-compose healthcheck**.
|
|
||||||
{{ printf "%-34s" ""}} You can use these form of label values:
|
|
||||||
{{ printf "%-35s" ""}}- "http://[not used address][:port][/path]" to specify an http healthcheck
|
|
||||||
{{ printf "%-35s" ""}}- "tcp://[not used address]:port" to specify a tcp healthcheck
|
|
||||||
{{ printf "%-35s" ""}}- other string is condidered as a "command" healthcheck
|
|
||||||
`)
|
|
||||||
buff := bytes.NewBuffer(nil)
|
|
||||||
t.Execute(buff, map[string]string{
|
|
||||||
"LABEL_ENV_SECRET": LABEL_ENV_SECRET,
|
|
||||||
"LABEL_PORT": LABEL_PORT,
|
|
||||||
"LABEL_INGRESS": LABEL_INGRESS,
|
|
||||||
"LABEL_VOL_CM": LABEL_VOL_CM,
|
|
||||||
"LABEL_HEALTHCHECK": LABEL_HEALTHCHECK,
|
|
||||||
"LABEL_SAMEPOD": LABEL_SAMEPOD,
|
|
||||||
"LABEL_VOLUMEFROM": LABEL_VOLUMEFROM,
|
|
||||||
"LABEL_EMPTYDIRS": LABEL_EMPTYDIRS,
|
|
||||||
"LABEL_IGNORE": LABEL_IGNORE,
|
|
||||||
"LABEL_MAP_ENV": LABEL_MAP_ENV,
|
|
||||||
"LABEL_SECRETVARS": LABEL_SECRETVARS,
|
|
||||||
})
|
|
||||||
return buff.String()
|
|
||||||
}
|
|
@@ -1,25 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
var NOTES = `
|
|
||||||
Congratulations,
|
|
||||||
|
|
||||||
Your application is now deployed. This may take a while to be up and responding.
|
|
||||||
|
|
||||||
__list__
|
|
||||||
`
|
|
||||||
|
|
||||||
// GenerateNotesFile generates the notes file for the helm chart.
|
|
||||||
func GenerateNotesFile(ingressess map[string]*Ingress) string {
|
|
||||||
|
|
||||||
list := make([]string, 0)
|
|
||||||
|
|
||||||
for name, ing := range ingressess {
|
|
||||||
for _, r := range ing.Spec.Rules {
|
|
||||||
list = append(list, "{{ if .Values."+name+".ingress.enabled -}}\n- "+name+" is accessible on : http://"+r.Host+"\n{{- end }}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.ReplaceAll(NOTES, "__list__", strings.Join(list, "\n"))
|
|
||||||
}
|
|
104
helm/probe.go
@@ -1,104 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Probe is a struct that can be used to create a Liveness or Readiness probe.
|
|
||||||
type Probe struct {
|
|
||||||
HttpGet *HttpGet `yaml:"httpGet,omitempty"`
|
|
||||||
Exec *Exec `yaml:"exec,omitempty"`
|
|
||||||
TCP *TCP `yaml:"tcp,omitempty"`
|
|
||||||
Period float64 `yaml:"periodSeconds"`
|
|
||||||
InitialDelay float64 `yaml:"initialDelaySeconds"`
|
|
||||||
Success uint64 `yaml:"successThreshold"`
|
|
||||||
Failure uint64 `yaml:"failureThreshold"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new Probe object that can be apply to HttpProbe or TCPProbe.
|
|
||||||
func NewProbe(period, initialDelaySeconds float64, success, failure uint64) *Probe {
|
|
||||||
probe := &Probe{
|
|
||||||
Period: period,
|
|
||||||
Success: success,
|
|
||||||
Failure: failure,
|
|
||||||
InitialDelay: initialDelaySeconds,
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix default values from
|
|
||||||
// https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
|
|
||||||
if period == 0 {
|
|
||||||
probe.Period = 10
|
|
||||||
}
|
|
||||||
if success == 0 {
|
|
||||||
probe.Success = 1
|
|
||||||
}
|
|
||||||
if failure == 0 {
|
|
||||||
probe.Failure = 3
|
|
||||||
}
|
|
||||||
return probe
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewProbeWithDuration creates a new Probe object with the given duration from types.
|
|
||||||
func NewProbeWithDuration(period, initialDelaySeconds *types.Duration, success, failure *uint64) *Probe {
|
|
||||||
|
|
||||||
if period == nil {
|
|
||||||
d := types.Duration(0 * time.Second)
|
|
||||||
period = &d
|
|
||||||
}
|
|
||||||
|
|
||||||
if initialDelaySeconds == nil {
|
|
||||||
d := types.Duration(0 * time.Second)
|
|
||||||
initialDelaySeconds = &d
|
|
||||||
}
|
|
||||||
|
|
||||||
if success == nil {
|
|
||||||
s := uint64(0)
|
|
||||||
success = &s
|
|
||||||
}
|
|
||||||
|
|
||||||
if failure == nil {
|
|
||||||
f := uint64(0)
|
|
||||||
failure = &f
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := time.ParseDuration(period.String())
|
|
||||||
if err != nil {
|
|
||||||
p = time.Second * 10
|
|
||||||
}
|
|
||||||
|
|
||||||
i, err := time.ParseDuration(initialDelaySeconds.String())
|
|
||||||
if err != nil {
|
|
||||||
i = time.Second * 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewProbe(p.Seconds(), i.Seconds(), *success, *failure)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewProbeFromService creates a new Probe object from a ServiceConfig.
|
|
||||||
func NewProbeFromService(s *types.ServiceConfig) *Probe {
|
|
||||||
if s == nil || s.HealthCheck == nil {
|
|
||||||
return NewProbe(0, 0, 0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewProbeWithDuration(s.HealthCheck.Interval, s.HealthCheck.StartPeriod, nil, s.HealthCheck.Retries)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// HttpGet is a Probe configuration to check http health.
|
|
||||||
type HttpGet struct {
|
|
||||||
Path string `yaml:"path"`
|
|
||||||
Port int `yaml:"port"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execis a Probe configuration to check exec health.
|
|
||||||
type Exec struct {
|
|
||||||
Command []string `yaml:"command"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TCP is a Probe configuration to check tcp health.
|
|
||||||
type TCP struct {
|
|
||||||
Port int `yaml:"port"`
|
|
||||||
}
|
|
@@ -1,51 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
// Service is a Kubernetes service.
|
|
||||||
type Service struct {
|
|
||||||
*K8sBase `yaml:",inline"`
|
|
||||||
Spec *ServiceSpec `yaml:"spec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewService creates a new initialized service.
|
|
||||||
func NewService(name string) *Service {
|
|
||||||
s := &Service{
|
|
||||||
K8sBase: NewBase(),
|
|
||||||
Spec: NewServiceSpec(),
|
|
||||||
}
|
|
||||||
s.K8sBase.Metadata.Name = ReleaseNameTpl + "-" + name
|
|
||||||
s.K8sBase.Kind = "Service"
|
|
||||||
s.K8sBase.ApiVersion = "v1"
|
|
||||||
s.K8sBase.Metadata.Labels[K+"/component"] = name
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServicePort is a port on a service.
|
|
||||||
type ServicePort struct {
|
|
||||||
Protocol string `yaml:"protocol"`
|
|
||||||
Port int `yaml:"port"`
|
|
||||||
TargetPort int `yaml:"targetPort"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewServicePort creates a new initialized service port.
|
|
||||||
func NewServicePort(port, target int) *ServicePort {
|
|
||||||
return &ServicePort{
|
|
||||||
Protocol: "TCP",
|
|
||||||
Port: port,
|
|
||||||
TargetPort: port,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceSpec is the spec for a service.
|
|
||||||
type ServiceSpec struct {
|
|
||||||
Selector map[string]string
|
|
||||||
Ports []*ServicePort
|
|
||||||
Type string `yaml:"type,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewServiceSpec creates a new initialized service spec.
|
|
||||||
func NewServiceSpec() *ServiceSpec {
|
|
||||||
return &ServiceSpec{
|
|
||||||
Selector: make(map[string]string),
|
|
||||||
Ports: make([]*ServicePort, 0),
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,54 +0,0 @@
|
|||||||
package helm
|
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
var (
|
|
||||||
made = make(map[string]bool)
|
|
||||||
locker = sync.Mutex{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// ResetMadePVC resets the cache of made PVCs.
|
|
||||||
// Useful in tests only.
|
|
||||||
func ResetMadePVC() {
|
|
||||||
locker.Lock()
|
|
||||||
defer locker.Unlock()
|
|
||||||
made = make(map[string]bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Storage is a struct for a PersistentVolumeClaim.
|
|
||||||
type Storage struct {
|
|
||||||
*K8sBase `yaml:",inline"`
|
|
||||||
Spec *PVCSpec
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPVC creates a new PersistentVolumeClaim object.
|
|
||||||
func NewPVC(name, storageName string) *Storage {
|
|
||||||
locker.Lock()
|
|
||||||
defer locker.Unlock()
|
|
||||||
if _, ok := made[name+storageName]; ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
made[name+storageName] = true
|
|
||||||
pvc := &Storage{}
|
|
||||||
pvc.K8sBase = NewBase()
|
|
||||||
pvc.K8sBase.Kind = "PersistentVolumeClaim"
|
|
||||||
pvc.K8sBase.Metadata.Labels[K+"/pvc-name"] = storageName
|
|
||||||
pvc.K8sBase.ApiVersion = "v1"
|
|
||||||
pvc.K8sBase.Metadata.Name = ReleaseNameTpl + "-" + storageName
|
|
||||||
pvc.K8sBase.Metadata.Labels[K+"/component"] = name
|
|
||||||
pvc.Spec = &PVCSpec{
|
|
||||||
Resouces: map[string]interface{}{
|
|
||||||
"requests": map[string]string{
|
|
||||||
"storage": "{{ .Values." + name + ".persistence." + storageName + ".capacity }}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
AccessModes: []string{"ReadWriteOnce"},
|
|
||||||
}
|
|
||||||
return pvc
|
|
||||||
}
|
|
||||||
|
|
||||||
// PVCSpec is a struct for a PersistentVolumeClaim spec.
|
|
||||||
type PVCSpec struct {
|
|
||||||
Resouces map[string]interface{} `yaml:"resources"`
|
|
||||||
AccessModes []string `yaml:"accessModes"`
|
|
||||||
}
|
|