Compare commits

...

213 Commits

Author SHA1 Message Date
Michael Jerger bba6bbe830 bump version to: 10.2.1-SNAPSHOT 2 days ago
Michael Jerger 8388d72517 release: 10.2.0 2 days ago
Michael Jerger f2b583c060 adjust version 2 days ago
Michael Jerger 5a3aca38cf use new fkt 2 days ago
Michael Jerger 4764d1db67 use the new pcv defaults 2 days ago
Michael Jerger 8aef785bdc reenable lint & native build 2 days ago
Michael Jerger 5eb83f78a0 update deps 2 days ago
Michael Jerger d997e470a0 remove integration tests 2 days ago
bom dc86531454 Fix default storage class
Our default was not actually valid
2 weeks ago
Michael Jerger ca0d4ac7b2 add the upgrade experience 1 month ago
bom e4666a592e bump version to: 10.1.1-SNAPSHOT 1 month ago
bom fa48d9762a release: 10.1.0 1 month ago
bom 6a278ece0d Upgrade nextcloud 1 month ago
Michael Jerger dda45d92d6 update instructions 1 month ago
bom c69c9da659 bump version to: 10.0.1-SNAPSHOT 1 month ago
bom de53b9b7a5 release: 10.0.0 1 month ago
bom cc845af696 Bump clojure version 1 month ago
bom f5aa2295f0 bump version to: 9.0.1-SNAPSHOT 1 month ago
bom 1d344abc27 release: 9.0.0 1 month ago
bom 7cd4e4101d No longer package native if we dont use it 1 month ago
bom 5d2a65079e Add Doc to rename the cloud DB 1 month ago
bom b36808de7c Change db-name to cloud 1 month ago
bom 3e588c082c Mark rotation-credential as optional 1 month ago
bom 4a74a1bec0 bump version to: 8.0.9-SNAPSHOT 1 month ago
bom 1ff8a0dc13 release: 8.0.8 1 month ago
bom fd27c15ec7 lein ancient upgrade 1 month ago
bom 192e053afc Update upgrading docs 1 month ago
Mirco cab9b573c1 add namespace to metadata in credential-rotation.yaml 2 months ago
Mirco 226046d278 test credential for rotation-credential 2 months ago
Mirco f108b67e62 lint fix use current versions 2 months ago
Mirco 96343b9af5 Merge branch 'master' of ssh://repo.prod.meissa.de:2222/meissa/c4k-nextcloud 2 months ago
Mirco f072ff027d add rotation-credential-volume to backup-restore-deployment 2 months ago
bom e396880365 bump version to: 8.0.8-SNAPSHOT 2 months ago
bom 83080b30a8 release: 8.0.7 2 months ago
bom 4a78a35424 Pass namespace to ingress-and-cert 2 months ago
bom 8727f16c75 Add namespace to backup/restore commands 2 months ago
bom ac3f2a455d Move namespace before postgres 2 months ago
bom c05ecfa427 Pass namespace to postgres 2 months ago
bom fff2c939d9 bump version to: 8.0.7-SNAPSHOT 2 months ago
bom e8cec9de8a release: 8.0.6 2 months ago
bom 1fb309f213 [skip-ci] Remove project parameters 2 months ago
bom 70d41ca532 Bump c4k-common cljs version 2 months ago
bom a96cba8cb1 Add test task that runs every test 2 months ago
bom 3bdf2ea553 Require namespace namespace 2 months ago
bom fcf6d7783e Add namespace 2 months ago
bom ab4c6e0d76 bump version to: 8.0.6-SNAPSHOT 3 months ago
bom ef8bfa11fc release: 8.0.5 3 months ago
bom 7d9ca203bb bump version to: 8.0.5-SNAPSHOT 3 months ago
bom f8bcbe63ba release: 8.0.4 3 months ago
bom 7219533c86 bump version to: 8.0.4-SNAPSHOT 3 months ago
bom 9b13b96ff6 release: 8.0.3 3 months ago
bom 351b2295e3 Add auth to postgres generate 3 months ago
bom 3a9694d9a1 bump version to: 8.0.3-SNAPSHOT 3 months ago
bom 3b458b980b release: 8.0.2 3 months ago
bom 5f38fb7526 Adapt core to changes in c4k-common 3 months ago
bom fa81908791 bump version to: 8.0.2-SNAPSHOT 3 months ago
bom 17ffd5a10e release: 8.0.1 3 months ago
bom f765b17dad Bump dependencies 3 months ago
bom 2119a8b037 Update image version in test 3 months ago
bom c2574c481f Actually create the uberjar 3 months ago
bom b08831c477 Bump image version in deployment 3 months ago
bom 212a56b1ef bump version to: 8.0.1-SNAPSHOT 3 months ago
bom ee2751509b release: 8.0.0 3 months ago
bom 59391d96d4 Bump nextcloud version
add note for docker version
3 months ago
bom 3b8ae92b83 Correct shebang
'set -o pipefail' is bash specific
3 months ago
bom 408376a5ca Use inline-resources macro 3 months ago
bom e6785784a7 Remove obsolete valid config 3 months ago
bom 69f5e31c56 Add native build 3 months ago
bom 2f5dd28c23 bump version to: 7.0.7-SNAPSHOT 4 months ago
bom de69d87c87 release: 7.0.6 4 months ago
bom 76cb0b5182 Bump missing image version 4 months ago
bom 76cbffe348 bump version to: 7.0.6-SNAPSHOT 4 months ago
bom 4a2afd65b5 release: 7.0.5 4 months ago
bom 84f6974175 Bump versions 4 months ago
Mirco b8d241a2c8 [skip-ci] infrastructure/../test folder removed 5 months ago
Mirco 439385933e bump version to: 7.0.5-SNAPSHOT 5 months ago
Mirco 2e90bae8c9 release: 7.0.4 5 months ago
Mirco 2771fed341 Improvements docker image building 5 months ago
Mirco fad3a4d07c bump version to: 7.0.4-SNAPSHOT 6 months ago
Mirco b51363bead release: 7.0.3 6 months ago
Mirco 47fa110f02 Lift dependencies 6 months ago
Mirco dc3e14517b Adapt new versions to gitlab-ci.yml 6 months ago
Mirco 741f0ce716 Merge branch 'master' of ssh://repo.prod.meissa.de:2222/meissa/c4k-nextcloud 6 months ago
Mirco 7ccf587c00 Improvements docker image building 6 months ago
Michael Jerger 96b8b6a448 fail on install error 7 months ago
Mirco c931e36a0a bump version to: 7.0.3-SNAPSHOT 8 months ago
Mirco 252f14b987 release: 7.0.2 8 months ago
Mirco 99407b70f3 Update Dockerfiles nextcloud & backup 8 months ago
Mirco 680f364b24 bump version to: 7.0.2-SNAPSHOT 8 months ago
Mirco 43ebd230e4 release: 7.0.1 8 months ago
Mirco 6837a99cdf change build.py 8 months ago
Mirco f211a8b75c change shadow-cljs.edn 8 months ago
Mirco e57c43bd1e Change infrastructure/build.py 8 months ago
Mirco 3bc19ea5f1 Change nextcloud_test.cljc 8 months ago
Mirco dd9cc84472 Downgrade to former version 25 8 months ago
Mirco e6c334f5ed Changes project.clj 8 months ago
Mirco f064fb98ed [Skip-CI] Updated build.py, nextcloud version 27 8 months ago
erik c7297fc953 [Skip-CI] Add Development and mirrors section 10 months ago
Michael Jerger 00c317a55b added mirrors 1 year ago
Clemens b862f8943a fixed restore.sh 1 year ago
Clemens 848857b6a9 removed deprecated step from restore doc 1 year ago
Clemens Geibel 75629ae366 Merge branch 'refactor-uptodate' into 'master'
Refactoring

See merge request domaindrivenarchitecture/c4k-nextcloud!6
1 year ago
Michael Jerger 2c0f340903 enable restore parameter 1 year ago
Michael Jerger 1757fcebb9 introduce list-snapshot 1 year ago
Clemens bc2f444b75 Added restic-snapshots 1 year ago
Michael Jerger eb2cbad90f update cloud migration doc 1 year ago
bom 8afc7ee9e1 Version bump 1 year ago
bom c3c2740e5a Version 7.0.0 1 year ago
bom 53e4f0781f Prepare release v7.0.0 1 year ago
bom 11323e2832 Fix tests 1 year ago
bom 861f1f1c21 Update pinned version 1 year ago
bom 0e14a59f6d Add docs for upgrading a live deployment 1 year ago
bom 6215434199 Update nextcloud version to newest release 1 year ago
bom 2198b2c76c Pin nextcloud image version 1 year ago
bom 4cad3daa3f Update name of service in ingress
Otherwise the ingress doesn't know the service it's pointing to
1 year ago
jerger 27c2044913 update lein inst 1 year ago
Clemens a286cffb03 upgraded non-c4k deps 1 year ago
bom f43e46ac3b Fix ci and valid config/auths 1 year ago
bom 483fb69918 Point to right valid config/auth file in ci 1 year ago
bom efac24b6df Fix import name 1 year ago
bom be684408a0 Add monitoring config/auth to browser 1 year ago
bom 3ffd98786b Fix k8s-objects 1 year ago
bom 234c920c63 Remove unused variable 1 year ago
bom d6ab7c555a Use common monitoring 1 year ago
bom e74280bf78 Fix spec for should-generate-secret 1 year ago
bom 84e70af742 Use groups for webview 1 year ago
bom fe4c381791 Use common ingress 1 year ago
bom 16dd0c5828 Spec and instrument generate functions 1 year ago
bom 19682eec36 Add and test valid/invalid config/auth files 1 year ago
bom 91d88d2a68 Use nextcloud instead of jitsi 1 year ago
bom 88a077e776 Use standardized uberjar 1 year ago
bom 107b8c3872 Use common load-as-edn
To avoid common code duplication
1 year ago
bom 74505dbab7 Bump c4k-common to newest version 1 year ago
Clemens 018d8d8b61 Updated Docker tests 1 year ago
erik 1c9c1a732e Update CI to show failing tests 2 years ago
Clemens Geibel 05edb62598 version bump 2 years ago
Clemens Geibel 2e7bce20a2 Version 4.0.3 2 years ago
Clemens Geibel ccfde9a447 Added missing tag variable 2 years ago
Clemens Geibel d2be6989d0 version bump 2 years ago
Clemens Geibel 92f234ae6e Version 4.0.2 2 years ago
Clemens Geibel 344b417c40 Added docker image tagging 2 years ago
Clemens Geibel 728915e887 version bump 2 years ago
Clemens Geibel 82290cbaec Version 4.0.1 2 years ago
Clemens Geibel 1e9cd59b50 Pin dda-backup to 1.0.5 2 years ago
jerger a9fab1d963 format 2 years ago
jerger 85eb5c8541 fix tests 2 years ago
jerger 2734125b8e improve cert naming 2 years ago
jerger 66aefb4c5c add renew to certificates 2 years ago
jerger 90acdc034e fix compile 2 years ago
jerger 16ab44be95 remove unused PV 2 years ago
jerger 44589b787b update deps 2 years ago
Clemens Geibel 16308798c0 Merge branch 'yaml-config-reader' into 'master'
Release Version 4.0.0

See merge request domaindrivenarchitecture/c4k-nextcloud!5
2 years ago
Clemens Geibel c49031da18 version bump 2 years ago
Clemens Geibel c2e2ea6c67 Version 4.0.0 2 years ago
Clemens Geibel 0d3a4c334a Merge branch 'yaml-config-reader' into 'master'
Configuration files can now be of type EDN and YAML.

See merge request domaindrivenarchitecture/c4k-nextcloud!4
2 years ago
Clemens Geibel ed60947087 New major version in development 2 years ago
Clemens Geibel 2dbc40fb0c Use c4k-common-clj v2.0.0 2 years ago
Clemens Geibel 9f94116777 Moved letsencrypt-issuer? back to c4k-common 2 years ago
Clemens Geibel 5b4e68ae2a Changed issuer keywords to strings 2 years ago
Clemens Geibel 775689b348 Added yaml config reader 2 years ago
jerger 34a3ca4728 version bump 2 years ago
jerger b1ad85fd6a Version 3.4.1 2 years ago
jerger 6b6cc630c6 fix backup credentials 2 years ago
jerger a224506caa adjust to new issuer naming 2 years ago
jerger 4dbe5367a7 version bump [skip-ci] 2 years ago
jerger 02a15fd708 Version 3.4.0 2 years ago
jerger c0345830ef upgrade to 22 2 years ago
jerger 6fb941b9a0 Version 3.3.0 2 years ago
jerger 7eb560a7f0 us v21 2 years ago
jerger 20b2659b89 improve doc 2 years ago
jerger a1cdb3f4fa Version 3.2.0 2 years ago
jerger ecca694f4c proceed to nextcloud20 2 years ago
jerger f35983c6b4 version bump [skip ci] 2 years ago
jerger 4e677385b4 Version 3.1.0 2 years ago
jerger 9f2977133a downgrade nc to 19 2 years ago
ansgarz 28de47db4d disable integrationtest as it needs fix 2 years ago
ansgarz 8f050d4736 fix test 2 years ago
ansgarz 44ed9dd0c2 fix pvc.yaml 2 years ago
jerger 484b165a81 fix alias 2 years ago
ansgarz 960e5ee613 add core test 2 years ago
ansgarz 2a0efa37d0 fix test 2 years ago
see 7006250375 mob 2 years ago
bom 4538cc5a24 mob 2 years ago
jerger aca8c7a397 add local-install 2 years ago
jerger f6598e68f6 traefic ingres proxy 2 years ago
bom a470dbc5fc fixed pvc test name 2 years ago
bom 48918d8d8c fixed test 2 years ago
ansgarz 7453c4edd9 mop add test 2 years ago
see 1c179daf2c updated pvc, mob 2 years ago
jerger 3a2f587709 mob 2 years ago
jerger 8b8a39ceb3 version bump 2 years ago
jerger 18526e8c08 Version 3.0.1 2 years ago
jerger ed1127edfb Merge branch 'master' of gitlab.com:domaindrivenarchitecture/c4k-nextcloud 2 years ago
jerger 200bb02853 adjust ci 2 years ago
Clemens Geibel f45105ba68 version bump 2 years ago
Clemens Geibel 471e920f60 Version 3.0.0 2 years ago
bom 4836f7a977 version bump 2 years ago
bom 7e9bd75cde Version 1.0.3 2 years ago
bom a49b07e7de v2.0.1 2 years ago
bom 2607f759c6 update project setup to fit convention 2 years ago
ansgarz 11b00bd525 [skip ci] add puml for integrationtest 2 years ago
bom 66cdecc048 removed SAST from ci 2 years ago
bom f27c101f48 fixed lein test 2 years ago
Mattis Böckle d228fdfd2a Merge branch 'local-integration-test' into 'master'
Local integration test

See merge request domaindrivenarchitecture/c4k-nextcloud!2
2 years ago
Mattis Böckle 8e03b1c11e Local integration test 2 years ago
jem 7b642db03c version bump 3 years ago
jem de67d4eba9 Version 1.0.2 3 years ago
Michael Jerger 3265b6aaaf Merge branch 'c4k_common_upgrade' into 'master'
Upgraded c4k-common

See merge request domaindrivenarchitecture/c4k-nextcloud!3
3 years ago
Clemens Geibel 20380ba193 Upgraded c4k-common 3 years ago
jem f943994afa Merge branch 'master' of gitlab.com:domaindrivenarchitecture/c4k-nextcloud 3 years ago
jem 8be078b09c backup&restore doc 3 years ago
Clemens Geibel 64585b8d39 Adjusted size of frontend screenshot 3 years ago
Clemens Geibel bac7cd5713 Added Screenshot of frontend 3 years ago

13
.gitignore vendored

@ -22,8 +22,17 @@ logs/
*.iml
.idea/
#valid-auth.edn
#valid-config.edn
# config files
my-auth.edn
my-config.edn
auth.edn
config.edn
# certificate
ca.crt
# chaches
.clj-kondo/.cache
.lsp/.cache/
.eastwood

@ -4,12 +4,20 @@ stages:
- security
- upload
- image
#- integrationtest
services:
- docker:19.03.12-dind
.img: &img
image: "domaindrivenarchitecture/ddadevops-dind:4.11.3"
services:
- docker:dind
before_script:
- export RELEASE_ARTIFACT_TOKEN=$MEISSA_REPO_BUERO_RW
- export IMAGE_DOCKERHUB_USER=$DOCKERHUB_USER
- export IMAGE_DOCKERHUB_PASSWORD=$DOCKERHUB_PASSWORD
- export IMAGE_TAG=$CI_COMMIT_TAG
.cljs-job: &cljs
image: domaindrivenarchitecture/shadow-cljs
image: "domaindrivenarchitecture/ddadevops-clj-cljs:4.11.3"
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
@ -17,60 +25,62 @@ services:
- .shadow-cljs/
- .m2
before_script:
- echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
- npm install
- export RELEASE_ARTIFACT_TOKEN=$MEISSA_REPO_BUERO_RW
- echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
- npm install
.clj-uploadjob: &clj
image: domaindrivenarchitecture/lein
.clj-job: &clj
image: "domaindrivenarchitecture/ddadevops-clj:4.11.3"
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .m2
before_script:
- mkdir -p /root/.lein
- echo "{:auth {:repository-auth {#\"clojars\" {:username \"${CLOJARS_USER}\" :password \"${CLOJARS_TOKEN_DOMAINDRIVENARCHITECTURE}\" }}}}" > ~/.lein/profiles.clj
- export RELEASE_ARTIFACT_TOKEN=$MEISSA_REPO_BUERO_RW
- mkdir -p /root/.lein
- echo "{:auth {:repository-auth {#\"clojars\" {:username \"${CLOJARS_USER}\" :password \"${CLOJARS_TOKEN_DOMAINDRIVENARCHITECTURE}\" }}}}" > ~/.lein/profiles.clj
test-cljs:
<<: *cljs
stage: build_and_test
script:
- shadow-cljs compile test
.tag_only: &tag_only
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never
- if: '$CI_COMMIT_TAG =~ /^[0-9]+\.[0-9]+\.[0-9]+$/'
test-clj:
<<: *clj
stage: build_and_test
script:
- lein test
- pyb test_clj
test-cljs:
<<: *cljs
stage: build_and_test
script:
- pyb test_cljs
test-schema:
<<: *clj
stage: build_and_test
script:
- lein uberjar
- java -jar target/uberjar/c4k-nextcloud-standalone.jar valid-config.edn valid-auth.edn | kubeconform --kubernetes-version 1.19.0 --strict --skip "Certificate,CronJob" -
- pyb test_schema
artifacts:
paths:
- target/uberjar
.report-frontend:
report-frontend:
<<: *cljs
stage: package
script:
- mkdir -p target/frontend-build
- shadow-cljs run shadow.cljs.build-report frontend target/frontend-build/build-report.html
- pyb report_frontend
artifacts:
paths:
- target/frontend-build/build-report.html
.package-frontend:
package-frontend:
<<: *cljs
stage: package
script:
- mkdir -p target/frontend-build
- shadow-cljs release frontend
- cp public/js/main.js target/frontend-build/c4k-nextcloud.js
- sha256sum target/frontend-build/c4k-nextcloud.js > target/frontend-build/c4k-nextcloud.js.sha256
- sha512sum target/frontend-build/c4k-nextcloud.js > target/frontend-build/c4k-nextcloud.js.sha512
- pyb package_frontend
artifacts:
paths:
- target/frontend-build
@ -79,63 +89,44 @@ package-uberjar:
<<: *clj
stage: package
script:
- sha256sum target/uberjar/c4k-nextcloud-standalone.jar > target/uberjar/c4k-nextcloud-standalone.jar.sha256
- sha512sum target/uberjar/c4k-nextcloud-standalone.jar > target/uberjar/c4k-nextcloud-standalone.jar.sha512
- pyb package_uberjar
artifacts:
paths:
- target/uberjar
sast:
variables:
SAST_EXCLUDED_ANALYZERS:
bandit, brakeman, flawfinder, gosec, kubesec, phpcs-security-audit,
pmd-apex, security-code-scan, sobelow, spotbugs
stage: security
before_script:
- mkdir -p builds && cp -r target/ builds/
include:
- template: Security/SAST.gitlab-ci.yml
package-native:
<<: *clj
stage: package
script:
- pyb package_native
artifacts:
paths:
- target/graalvm
upload-clj-prerelease:
release-to-clojars:
<<: *clj
<<: *tag_only
stage: upload
rules:
- if: '$CI_COMMIT_BRANCH == "master" && $CI_COMMIT_TAG == null'
script:
- lein deploy clojars
- pyb upload_clj
release:
image: registry.gitlab.com/gitlab-org/release-cli:latest
release-to-forgejo:
<<: *clj
<<: *tag_only
stage: upload
rules:
- if: '$CI_COMMIT_TAG != null'
artifacts:
paths:
- target/uberjar
- target/frontend-build
script:
- apk --no-cache add curl
- |
release-cli create --name "Release $CI_COMMIT_TAG" --tag-name $CI_COMMIT_TAG \
--assets-link "{\"name\":\"c4k-nextcloud-standalone.jar\",\"url\":\"https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/-/jobs/${CI_JOB_ID}/artifacts/file/target/uberjar/c4k-nextcloud-standalone.jar\"}" \
--assets-link "{\"name\":\"c4k-nextcloud-standalone.jar.sha256\",\"url\":\"https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/-/jobs/${CI_JOB_ID}/artifacts/file/target/uberjar/c4k-nextcloud-standalone.jar.sha256\"}" \
--assets-link "{\"name\":\"c4k-nextcloud-standalone.jar.sha512\",\"url\":\"https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/-/jobs/${CI_JOB_ID}/artifacts/file/target/uberjar/c4k-nextcloud-standalone.jar.sha512\"}" \
--assets-link "{\"name\":\"c4k-nextcloud.js\",\"url\":\"https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/-/jobs/${CI_JOB_ID}/artifacts/file/target/frontend-build/c4k-nextcloud.js\"}" \
--assets-link "{\"name\":\"c4k-nextcloud.js.sha256\",\"url\":\"https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/-/jobs/${CI_JOB_ID}/artifacts/file/target/frontend-build/c4k-nextcloud.js.sha256\"}" \
--assets-link "{\"name\":\"c4k-nextcloud.js.sha512\",\"url\":\"https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/-/jobs/${CI_JOB_ID}/artifacts/file/target/frontend-build/c4k-nextcloud.js.sha512\"}" \
- pyb publish_artifacts
nextcloud-image-test-publish:
image: domaindrivenarchitecture/devops-build:latest
backup-image-publish:
<<: *img
<<: *tag_only
stage: image
rules:
- if: '$CI_COMMIT_TAG != null'
script:
- cd infrastructure/docker-nextcloud && pyb image test publish
- cd infrastructure/backup && pyb image publish
backup-image-test-publish:
image: domaindrivenarchitecture/devops-build:latest
nextcloud-image-publish:
<<: *img
<<: *tag_only
stage: image
rules:
- if: '$CI_COMMIT_TAG != null'
script:
- cd infrastructure/docker-backup && pyb image test publish
- cd infrastructure/nextcloud && pyb image publish

@ -35,8 +35,20 @@ target/graalvm/c4k-nextcloud src/test/resources/valid-config.edn src/test/resour
* [Example Setup on Hetzner](doc/SetupOnHetzner.md)
* Backup and Restore
## Development & mirrors
Development happens at: https://repo.prod.meissa.de/meissa/c4k-nextcloud
Mirrors are:
* https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud (issues and PR, CI)
* https://github.com/DomainDrivenArchitecture/c4k-nextcloud
For more details about our repository model see: https://repo.prod.meissa.de/meissa/federate-your-repos
## License
Copyright © 2021 meissa GmbH
Licensed under the [Apache License, Version 2.0](LICENSE) (the "License")
Pls. find licenses of our subcomponents [here](doc/SUBCOMPONENT_LICENSE)
Pls. find licenses of our subcomponents [here](doc/SUBCOMPONENT_LICENSE)

@ -0,0 +1,233 @@
from os import environ
from subprocess import run
from pybuilder.core import init, task
from ddadevops import *
default_task = "dev"
name = 'c4k-nextcloud'
MODULE = 'not-used'
PROJECT_ROOT_PATH = '.'
@init
def initialize(project):
project.build_depends_on("ddadevops>=4.7.0")
input = {
"name": name,
"module": MODULE,
"stage": "notused",
"project_root_path": PROJECT_ROOT_PATH,
"build_types": [],
"mixin_types": ["RELEASE"],
"release_primary_build_file": "project.clj",
"release_secondary_build_files": [
"package.json",
"infrastructure/backup/build.py",
"infrastructure/nextcloud/build.py",
],
"release_artifact_server_url": "https://repo.prod.meissa.de",
"release_organisation": "meissa",
"release_repository_name": name,
"release_artifacts": [
f"target/graalvm/{name}",
f"target/uberjar/{name}-standalone.jar",
f"target/frontend-build/{name}.js",
],
"release_main_branch": "master",
}
build = ReleaseMixin(project, input)
build.initialize_build_dir()
@task
def test_clj():
run("lein test", shell=True, check=True)
@task
def test_cljs():
run("shadow-cljs compile test", shell=True, check=True)
run("node target/node-tests.js", shell=True, check=True)
@task
def test_schema():
run("lein uberjar", shell=True, check=True)
run(
"java -jar target/uberjar/c4k-nextcloud-standalone.jar "
+ "src/test/resources/nextcloud-test/valid-config.yaml "
+ "src/test/resources/nextcloud-test/valid-auth.yaml | "
+ "kubeconform --kubernetes-version 1.23.0 --strict --skip Certificate -",
shell=True,
check=True,
)
@task
def test():
test_clj()
test_cljs()
test_schema()
@task
def report_frontend(project):
run("mkdir -p target/frontend-build", shell=True, check=True)
run(
"shadow-cljs run shadow.cljs.build-report frontend target/frontend-build/build-report.html",
shell=True,
check=True,
)
@task
def package_frontend(project):
run("mkdir -p target/frontend-build", shell=True, check=True)
run("shadow-cljs release frontend", shell=True, check=True)
run(
"cp public/js/main.js target/frontend-build/c4k-nextcloud.js",
shell=True,
check=True,
)
run(
"sha256sum target/frontend-build/c4k-nextcloud.js > target/frontend-build/c4k-nextcloud.js.sha256",
shell=True,
check=True,
)
run(
"sha512sum target/frontend-build/c4k-nextcloud.js > target/frontend-build/c4k-nextcloud.js.sha512",
shell=True,
check=True,
)
@task
def package_uberjar(project):
run("lein uberjar", shell=True, check=True)
run(
"sha256sum target/uberjar/c4k-nextcloud-standalone.jar > target/uberjar/c4k-nextcloud-standalone.jar.sha256",
shell=True,
check=True,
)
run(
"sha512sum target/uberjar/c4k-nextcloud-standalone.jar > target/uberjar/c4k-nextcloud-standalone.jar.sha512",
shell=True,
check=True,
)
@task
def package_native(project):
run(
"mkdir -p target/graalvm",
shell=True,
check=True,
)
run(
"native-image " +
"--native-image-info " +
"--report-unsupported-elements-at-runtime " +
"--no-server " +
"--no-fallback " +
"--features=clj_easy.graal_build_time.InitClojureClasses " +
f"-jar target/uberjar/{project.name}-standalone.jar " +
"-H:IncludeResources=.*.yaml " +
"-H:Log=registerResource:verbose " +
f"-H:Name=target/graalvm/{project.name}",
shell=True,
check=True,
)
run(
f"sha256sum target/graalvm/{project.name} > target/graalvm/{project.name}.sha256",
shell=True,
check=True,
)
run(
f"sha512sum target/graalvm/{project.name} > target/graalvm/{project.name}.sha512",
shell=True,
check=True,
)
@task
def upload_clj(project):
run("lein deploy", shell=True, check=True)
@task
def lint(project):
run(
"lein eastwood",
shell=True,
check=True,
)
run(
"lein ancient check",
shell=True,
check=True,
)
@task
def inst(project):
package_uberjar(project)
package_native(project)
run(
f"sudo install -m=755 target/uberjar/{project.name}-standalone.jar /usr/local/bin/{project.name}-standalone.jar",
shell=True,
check=True,
)
run(
f"sudo install -m=755 target/graalvm/{project.name} /usr/local/bin/{project.name}",
shell=True,
check=True,
)
@task
def patch(project):
linttest(project, "PATCH")
release(project)
@task
def minor(project):
linttest(project, "MINOR")
release(project)
@task
def major(project):
linttest(project, "MAJOR")
release(project)
@task
def dev(project):
linttest(project, "NONE")
@task
def prepare(project):
build = get_devops_build(project)
build.prepare_release()
@task
def tag(project):
build = get_devops_build(project)
build.tag_bump_and_push_release()
@task
def publish_artifacts(project):
build = get_devops_build(project)
build.publish_artifacts()
def release(project):
prepare(project)
tag(project)
def linttest(project, release_type):
build = get_devops_build(project)
build.update_release_type(release_type)
test_clj()
test_cljs()
test_schema()
lint(project)

@ -0,0 +1,46 @@
# Backup Architecture details
![](backup.svg)
* we use restic to produce small & encrypted backups
* backup is scheduled at `schedule: "10 23 * * *"`
* Cloud stores files on `/var/jira`, these files are backuped. If you create a jira xml backup located in /var/jira this file will also be backed up.
* postgres db is backed up as pgdump
## Manual init the restic repository for the first time
1. Scale backup-restore deployment up:
`kubectl -n nextcloud scale deployment backup-restore --replicas=1`
1. exec into pod and execute restore pod
`kubectl -n nextcloud exec -it backup-restore -- /usr/local/bin/init.sh`
1. Scale backup-restore deployment down:
`kubectl -n nextcloud scale deployment backup-restore --replicas=0`
## Manual backup
1. Scale Cloud deployment down:
`kubectl -n nextcloud scale deployment cloud-deployment --replicas=0`
1. Scale backup-restore deployment up:
`kubectl -n nextcloud scale deployment backup-restore --replicas=1`
1. exec into pod and execute restore pod
`kubectl -n nextcloud exec -it backup-restore -- /usr/local/bin/backup.sh`
1. Scale backup-restore deployment down:
`kubectl -n nextcloud scale deployment backup-restore --replicas=0`
1. Scale Cloud deployment up:
`kubectl -n nextcloud scale deployment cloud-deployment --replicas=1`
## Manual restore
1. Scale Cloud deployment down:
`kubectl -n nextcloud scale deployment cloud-deployment --replicas=0`
2. Scale backup-restore deployment up:
`kubectl -n nextcloud scale deployment backup-restore --replicas=1`
3. exec into pod and execute restore pod
`kubectl -n nextcloud exec -it backup-restore -- /usr/local/bin/restore.sh`
4. Scale backup-restore deployment down:
`kubectl -n nextcloud scale deployment backup-restore --replicas=0`
5. Scale Cloud deployment up:
`kubectl -n nextcloud scale deployment cloud-deployment --replicas=1`

@ -39,34 +39,31 @@ npx shadow-cljs release frontend
## graalvm-setup
```
curl -LO https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0.2/graalvm-ce-java11-linux-amd64-21.0.0.2.tar.gz
curl -LO https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz
# unpack
tar -xzf graalvm-ce-java11-linux-amd64-21.0.0.2.tar.gz
tar -xzf graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz
sudo mv graalvm-ce-java11-21.0.0.2 /usr/lib/jvm/
sudo ln -s /usr/lib/jvm/graalvm-ce-java11-21.0.0.2 /usr/lib/jvm/graalvm
sudo ln -s /usr/lib/jvm/graalvm/bin/gu /usr/local/bin
sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/graalvm/bin/java 2
sudo mv graalvm-community-openjdk-21.0.2+13.1 /usr/lib/jvm/
sudo ln -s /usr/lib/jvm/graalvm-community-openjdk-21.0.2+13.1 /usr/lib/jvm/graalvm-21
sudo ln -s /usr/lib/jvm/graalvm-21/bin/gu /usr/local/bin
sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/graalvm-21/bin/java 2
sudo update-alternatives --config java
# install native-image in graalvm-ce-java11-linux-amd64-21.0.0.2/bin
sudo gu install native-image
sudo ln -s /usr/lib/jvm/graalvm/bin/native-image /usr/local/bin
sudo ln -s /usr/lib/jvm/graalvm-21/bin/native-image /usr/local/bin
# deps
sudo apt-get install build-essential libz-dev zlib1g-dev
# build
cd ~/repo/dda/c4k-cloud
cd ~/repo/c4k/c4k-nextcloud
lein uberjar
mkdir -p target/graalvm
lein native
# execute
./target/graalvm/c4k-cloud -h
./target/graalvm/c4k-cloud src/test/resources/valid-config.edn src/test/resources/valid-auth.edn
./target/graalvm/c4k-cloud src/test/resources/invalid-config.edn src/test/resources/invalid-auth.edn
./target/graalvm/c4k-nextcloud -h
./target/graalvm/c4k-nextcloud src/test/resources/nextcloud-test/valid-config.yaml src/test/resources/nextcloud-test/valid-auth.yaml
./target/graalvm/c4k-nextcloud src/test/resources/nextcloud-test/invalid-config.yaml src/test/resources/nextcloud-test/invalid-auth.yaml
```
## c4k-setup

@ -0,0 +1,22 @@
# Upgrade major or minor versions of nextcloud
## Nextcloud versions of c4k-nextcloud docker images
- 4.0.3: nextcloud 22
- 5.0.0: nextcloud 23
- 6.0.0: nextcloud 24
- 7.0.7: nextcloud 25.0.13
- 7.1.1: nextcloud 26.0.0 (manual publish) => attention - only upgrade to 26.0.0 is working
- 7.1.0: nextcloud 26.0.13 (manual publish)
- 7.2.0: nextcloud 27 (manual publish)
- 10.0.0: nextcloud 28.0.5
- 10.1.0: nextcloud 29.0.0
## Uprgrading process
1. Change the version of the docker image in the deployment to the next major version
- `kubectl -n=nextcloud edit deploy cloud-deployment`
- change `image: domaindrivenarchitecture/c4k-cloud:4.0.3`
2. Wait for the pod to finish restarting
3. Verify the website is working and https://URL/settings/admin/overview shows the correct version
4. Repeat until desired version is reached

@ -0,0 +1,41 @@
# Rename Database
## Start
1. Scale down cloud deployment
`k -n nextcloud scale deployment cloud-deployment --replicas 0`
## Change db-name in postgres
1. Connect to postgres-pod
`k -n nextcloud exec -it postgresql-... -- bash`
2. Connect to a database
`PGPASSWORD=$POSTGRES_PASSWORD psql -h postgresql-service -U $POSTGRES_USER postgres`
3. List available databases
`\l`
4. Rename database
`ALTER DATABASE cloud RENAME TO nextcloud;`
5. Verify
`\l`
6. Quit
`\q`
## Update postgres-config
1. Edit configmap
`k -n nextcloud edit configmap postgres-config`
2. Update postgres-db value
3. Save
## Update nextcloud db-name
1. Scale up nextcloud
`k -n nextcloud scale deployment cloud-deployment --replicas 1`
2. Connect
`k -n nextcloud exec -it cloud-deployment-... -- bash`
3. Update db value in config.php
`apt update`
`apt install vim`
`vim config/config.php`
4. Update dbname field
5. Verify server+website is working

@ -45,15 +45,17 @@ output "ipv4" {
## k8s minicluster
For k8s installation we use our [dda-k8s-crate](https://github.com/DomainDrivenArchitecture/dda-k8s-crate) with the following configuation:
For k8s installation we use our [provs](https://repo.prod.meissa.de/meissa/provs) with the following configuation:
```
{:user :k8s
:k8s {:external-ip "ip-from-above"}
:cert-manager :letsencrypt-prod-issuer
:persistent-dirs ["cloud", "postgres"]
}
postgres-db-user: "nextcloud"
postgres-db-password: "nextcloud-db-password"
nextcloud-admin-user: "cloudadmin"
nextcloud-admin-password: "cloudpassword"
aws-access-key-id: "aws-id"
aws-secret-access-key: "aws-secret"
restic-password: "restic-password"
```
## kubectl apply c4k-nextcloud

@ -0,0 +1,10 @@
# Upgrade with a new nextcloud version
1. Pull a new image
1. Trigger deployment
```
k3s crictl pull domaindrivenarchitecture/c4k-cloud
k3s crictl images
kubectl set env deployment cloud-deployment DEPLOY_DATE="$(date)"
```

@ -0,0 +1,294 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="297mm"
height="210mm"
viewBox="0 0 297 210"
version="1.1"
id="svg3835"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="backup.svg">
<defs
id="defs3829" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="401.60934"
inkscape:cy="468.05499"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-text-baseline="true"
inkscape:window-width="3072"
inkscape:window-height="1614"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1" />
<metadata
id="metadata3832">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-87)">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333311px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="74.461304"
y="214.22322"
id="text3897"><tspan
sodipodi:role="line"
id="tspan3895"
x="74.461304"
y="214.22322"
style="stroke-width:0.26458332">/var/jira</tspan><tspan
sodipodi:role="line"
x="74.461304"
y="219.51489"
style="stroke-width:0.26458332"
id="tspan3899">/var/postgres</tspan></text>
<path
id="path3843"
d="m 23.928181,109.95955 c -0.03502,0.28187 -0.06495,0.56441 -0.105072,0.8456 -0.241563,1.69302 -0.514704,3.37966 -0.718689,5.07821 -0.224627,1.87044 -0.2236,2.05097 -0.387224,3.95474 -0.182611,3.20929 -0.396631,6.42977 -0.33565,9.64677 0.01463,0.77188 0.06165,1.54281 0.09247,2.31421 0.2865,4.13208 0.623369,8.26573 1.257784,12.36151 0.473742,3.05847 1.070569,6.05824 1.647011,9.09919 1.371342,7.38573 2.932193,14.74091 4.003443,22.17939 0.711486,4.94039 0.783532,6.24004 1.270172,11.18791 0.62489,7.91962 1.08907,15.86308 1.106733,23.80963 -0.08352,4.61198 -0.593383,9.2019 -0.930801,13.79934 -0.193958,3.15149 -0.256831,6.30687 -0.50723,9.45493 -0.191466,2.01724 -0.649743,3.99296 -1.26169,5.92065 -0.422531,1.31219 -1.134943,2.50065 -1.669743,3.76541 -0.02201,0.10972 -0.134403,0.3286 0.03627,0.41461 0.102896,0.0519 0.222845,0.0601 0.336483,0.0792 0.417455,0.07 0.836634,0.12944 1.255877,0.18775 1.872573,0.26047 3.305635,0.43219 5.224412,0.67266 9.134991,1.26831 18.356659,1.75044 27.564432,2.12585 4.020296,0.0609 8.049791,0.2484 12.07031,0.0726 1.16719,-0.051 2.572668,-0.17725 3.745476,-0.27392 2.929988,-0.26622 5.864217,-0.46476 8.802372,-0.61181 2.745777,-0.20556 5.492565,-0.3765 8.232034,-0.65588 1.80018,-0.12366 3.573132,-0.4627 5.367809,-0.62978 2.47194,-0.14926 4.95085,-0.13045 7.42637,-0.1494 1.49367,-0.009 2.98732,-0.0254 4.48103,-0.0248 2.29679,-0.0599 4.59581,-0.14828 6.89038,-0.27668 0.81386,-0.0997 1.68932,-0.0697 2.46058,-0.40019 0.12174,-0.0522 0.45801,-0.26514 0.33841,-0.20823 -0.77384,0.3683 -1.53526,0.76213 -2.3029,1.14319 0,0 2.51167,-1.2405 2.51167,-1.2405 v 0 c -0.79711,0.61588 -1.57648,1.25544 -2.39134,1.84764 -0.10539,0.0766 -0.23564,0.11344 -0.36009,0.15199 -0.78823,0.24415 -1.62793,0.23535 -2.44043,0.31034 -1.41196,0.0678 -2.82453,0.11789 -4.23623,0.19148 -0.17293,0.009 -1.91647,0.10988 -2.19401,0.11936 -0.17739,0.006 -0.35499,2.6e-4 -0.53249,5.3e-4 -1.47242,-0.004 -2.94479,-0.0239 -4.41725,-0.0192 -2.48349,0.007 -4.97162,0.005 -7.449094,0.19777 -1.777994,0.18636 -3.542387,0.48844 -5.328734,0.60062 -2.743859,0.25998 -5.492994,0.45303 -8.242266,0.64644 -2.925051,0.13255 -5.843926,0.35386 -8.762105,0.59232 -1.275369,0.0943 -2.432024,0.19257 -3.715295,0.23243 -3.976204,0.12353 -7.955569,-0.10992 -11.929526,-0.19412 -6.311511,-0.28924 -12.61361,-0.67269 -18.91022,-1.19841 -1.661732,-0.13874 -3.324495,-0.26742 -4.983742,-0.43325 -1.260668,-0.126 -2.516693,-0.29475 -3.775038,-0.44212 -1.010235,-0.11141 -2.020361,-0.22381 -3.030704,-0.33422 -0.776195,-0.0848 -1.553652,-0.15844 -2.328907,-0.25145 -0.358395,-0.043 -1.828279,0.006 -1.987163,-0.72851 -0.02454,-0.11344 0.02479,-0.2308 0.03718,-0.3462 0.529586,-1.27373 1.273345,-2.45184 1.71838,-3.76221 0.628139,-1.91168 1.102071,-3.87248 1.315069,-5.87713 0.281196,-3.15784 0.392117,-6.32368 0.578982,-9.4878 0.346115,-4.60085 0.895514,-9.19023 0.98575,-13.80717 0.117658,-7.97861 -0.22843,-15.9623 -0.844523,-23.91625 -0.478076,-4.94937 -0.54664,-6.24035 -1.250995,-11.18235 -1.058987,-7.43023 -2.624648,-14.77189 -4.077173,-22.13128 -0.371913,-1.88541 -1.410546,-7.07391 -1.745556,-9.06111 -0.687537,-4.0783 -1.054877,-8.20269 -1.384652,-12.32221 -0.04044,-0.77119 -0.0992,-1.54163 -0.121307,-2.31355 -0.0923,-3.22357 0.137938,-6.45038 0.325406,-9.6657 0.151052,-1.87677 0.152788,-2.11389 0.368253,-3.9587 0.226945,-1.9431 0.526741,-3.87837 0.708071,-5.82662 0,0 2.49922,-1.27341 2.49922,-1.27341 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3845"
d="m 28.130875,108.00453 c 5.212191,0.57627 10.460583,0.70514 15.698888,0.82825 4.485651,0.0237 8.966081,0.25521 13.446953,0.43548 1.82303,0.0733 3.647096,0.12187 5.469533,0.20869 1.498195,0.0714 10.067176,0.57498 11.685537,0.66936 8.487032,0.51062 16.981302,0.91422 25.483994,0.99653 4.56085,0.0396 9.08507,-0.53046 13.60104,-1.08804 2.40321,-0.27519 4.81604,-0.44912 7.23241,-0.54969 0.46287,-0.0426 0.92916,-0.008 1.39242,-0.0399 0.49434,-0.0337 0.93148,-0.17323 1.41699,-0.0295 0.29303,0.22862 0.21115,0.5271 0.15648,0.85829 -0.0436,0.26401 -0.10151,0.52549 -0.14614,0.78933 -0.19575,1.15706 -0.28757,1.85842 -0.46203,3.0704 -0.61198,4.65348 -0.79895,9.36043 -0.89594,14.049 -0.0427,2.06422 -0.0653,4.12927 -0.0439,6.19381 0.0254,2.45295 0.12284,4.90463 0.18425,7.35695 0.48153,10.01687 1.49626,19.99668 2.22895,29.9961 0.23554,3.21446 0.57053,8.79293 0.77491,12.11225 0.0803,1.7862 0.16464,3.57223 0.24104,5.3586 0.19194,4.48776 0.19441,4.58821 0.30358,8.97704 0.08,3.21674 0.0712,4.4087 0.23315,7.6258 0.0606,1.20422 0.15109,2.40675 0.22663,3.61013 0.42017,5.78041 1.0165,11.54597 1.49742,17.32137 0.44429,3.51382 -0.078,7.0229 -0.49495,10.50984 -0.29104,1.84314 -0.35449,3.71791 -0.62928,5.56185 -0.0977,0.36571 -0.11623,0.52472 -0.29541,0.85607 -0.6173,1.14155 -2.46566,1.72568 -3.32773,2.08177 -0.1973,0.0815 -0.4255,-0.035 -0.63825,-0.0525 -1.12405,-0.13092 -2.21612,-0.46593 -3.2975,-0.78879 0,0 2.27468,-1.554 2.27468,-1.554 v 0 c 1.0698,0.31852 2.1536,0.64176 3.27325,0.71702 0.20072,-0.006 0.74975,-0.15519 0.60217,-0.019 -0.56743,0.52361 -1.2902,0.84877 -1.94491,1.25806 -0.0953,0.0596 0.18395,-0.13072 0.26548,-0.20817 0.30896,-0.29351 0.47998,-0.65737 0.58463,-1.06648 0.1146,-0.62083 0.17214,-1.24395 0.25,-1.87057 0.15476,-1.24543 0.32998,-2.48816 0.49009,-3.7329 0.44221,-3.47443 0.90709,-6.97153 0.54919,-10.47841 -0.39314,-5.80198 -0.95971,-11.58955 -1.373,-17.39009 -0.16694,-2.85115 -0.29084,-4.57227 -0.36291,-7.44826 -0.0319,-1.27522 -0.0208,-2.55119 -0.041,-3.82666 -0.076,-4.79717 -0.20739,-9.5941 -0.42868,-14.38687 -0.28729,-5.82808 -0.27671,-6.08872 -0.67926,-12.15673 -0.66433,-10.01409 -1.57629,-20.01014 -2.18762,-30.02802 -0.32945,-8.46033 -0.31545,-5.64351 -0.2831,-13.49137 0.0191,-4.63452 -0.0538,-9.3022 0.55233,-13.90778 0.15362,-1.26505 0.2577,-2.56066 0.48546,-3.81669 0.0217,-0.1195 0.0687,-0.2332 0.0945,-0.35187 0.025,-0.11466 0.0242,-0.0944 -0.0529,-0.12284 -0.27774,-0.038 -0.52963,-0.005 -0.80951,0.0191 -0.69672,0.0593 -0.40465,0.0348 -1.15318,0.0511 -0.25007,0.005 -0.50009,0.013 -0.75013,0.0195 -2.398,0.0884 -4.79305,0.25133 -7.17655,0.53493 -4.47608,0.50352 -8.96101,1.02749 -13.474878,0.95289 -2.786645,-0.0504 -4.346922,-0.0679 -7.187401,-0.16679 -6.047637,-0.21044 -12.086111,-0.6047 -18.125916,-0.96644 -1.888175,-0.11638 -3.775715,-0.2436 -5.664528,-0.34913 -8.359304,-0.46702 -16.731708,-0.72316 -25.102844,-0.83436 -5.323048,-0.11891 -10.646013,-0.25637 -15.95545,-0.68066 0,0 2.288922,-1.61708 2.288922,-1.61708 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3847"
d="m 193.19838,160.92997 c 0.5335,0.99245 1.40599,2.07766 2.29191,2.76011 0.62363,0.48041 1.29755,0.89487 1.98014,1.28704 0.77762,0.44676 1.57,0.87399 2.39467,1.22642 1.06766,0.45626 2.18116,0.79676 3.27174,1.19515 1.46006,0.34668 2.90737,0.7523 4.38018,1.04005 3.46844,0.67765 7.24048,1.11215 10.74925,1.45797 3.35367,0.33053 7.44918,0.61489 10.79743,0.74796 1.76205,0.07 3.52599,0.0789 5.28899,0.1183 2.7261,-0.0447 6.38393,-0.0253 9.1317,-0.36261 1.39512,-0.17125 2.78187,-0.42677 4.1487,-0.75455 2.71805,-0.65182 5.04542,-1.53001 7.58796,-2.65977 1.01883,-0.45271 2.00248,-0.98076 3.00372,-1.47114 2.00901,-1.31808 4.09153,-2.60725 5.81013,-4.30854 0.2469,-0.24442 0.47226,-0.50968 0.7084,-0.76452 0.9743,-1.16709 1.64367,-2.45964 2.2502,-3.84058 0,0 2.50494,-1.14891 2.50494,-1.14891 v 0 c -0.15213,0.34969 -0.54049,1.2568 -0.70974,1.58476 -0.4281,0.82955 -0.98118,1.5899 -1.52302,2.34633 -0.23675,0.26359 -0.46117,0.53881 -0.71028,0.79078 -0.65135,0.65881 -1.30146,1.18183 -2.04358,1.74594 -2.59143,1.96986 -5.38693,3.63452 -8.25788,5.16721 -0.99113,0.47505 -1.96536,0.9871 -2.9734,1.42514 -2.53897,1.10332 -4.88417,1.96936 -7.59298,2.59997 -1.37082,0.31912 -2.76107,0.56624 -4.15928,0.72757 -2.65887,0.30679 -6.44337,0.26647 -9.0692,0.29154 -4.32665,-0.1181 -6.54556,-0.13457 -10.91571,-0.44008 -1.72226,-0.12039 -3.44115,-0.28683 -5.15897,-0.4593 -3.52774,-0.35417 -7.35185,-0.77398 -10.84527,-1.42405 -1.50374,-0.27983 -2.98423,-0.67268 -4.47635,-1.00902 -1.11776,-0.39319 -2.25955,-0.72378 -3.35328,-1.17956 -0.83885,-0.34956 -1.63938,-0.78753 -2.43236,-1.23144 -0.71089,-0.39795 -1.42116,-0.80548 -2.07486,-1.29169 -0.42711,-0.31768 -0.78355,-0.72185 -1.1506,-1.10737 -0.80351,-0.84391 -0.76491,-0.85198 -1.28775,-1.67297 0,0 2.43445,-1.38614 2.43445,-1.38614 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3849"
d="m 190.18307,160.00292 c 2.00424,-2.85472 4.84564,-4.98907 7.55472,-7.1314 2.41218,-1.63 3.54608,-2.50276 6.71473,-3.77643 2.17758,-0.87531 7.3175,-1.69 9.37707,-2.01647 5.00434,-0.79326 5.8307,-0.80686 10.89647,-1.32614 6.71624,-0.64395 13.46511,-0.85066 20.20776,-0.97444 1.50289,-0.0276 3.00573,-0.0674 4.50887,-0.0707 1.33781,-0.003 2.6754,0.0346 4.01311,0.0519 1.15708,0.0887 2.31926,0.12592 3.47125,0.26597 1.86256,0.22645 3.82339,0.65977 5.62961,1.18349 1.25525,0.36398 2.45942,0.79614 3.62883,1.37788 0.42381,0.21083 0.82187,0.4699 1.2328,0.70485 1.19623,0.85324 0.65169,0.41677 1.64719,1.29225 0,0 -2.33434,1.44914 -2.33434,1.44914 v 0 c -0.95166,-0.85841 -0.42979,-0.42955 -1.57941,-1.26954 -0.39806,-0.23232 -0.78391,-0.487 -1.19421,-0.69697 -2.71335,-1.38851 -6.07218,-2.20444 -9.07148,-2.58285 -1.13521,-0.14322 -2.28065,-0.18843 -3.42098,-0.28265 -1.32364,-0.0246 -2.64706,-0.0696 -3.97092,-0.0739 -1.49078,-0.005 -2.98154,0.0217 -4.47213,0.0464 -6.72442,0.11145 -13.45204,0.34355 -20.15165,0.95691 -4.5776,0.48001 -6.372,0.59809 -10.89659,1.34855 -1.79029,0.29694 -3.58213,0.59897 -5.34984,1.00954 -1.41139,0.3278 -2.77219,0.84839 -4.17706,1.20315 -0.12363,0.0312 -0.26624,-0.11239 -0.37891,-0.0527 -0.66899,0.3546 -1.26153,0.83768 -1.89231,1.25651 -2.66631,2.09232 -5.45443,4.18036 -7.43991,6.96766 0,0 -2.55267,1.13995 -2.55267,1.13995 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3851"
d="m 271.68872,164.83536 c -0.0127,1.74752 -0.12738,3.50552 -0.0491,5.25222 0.1239,2.76402 0.52413,6.13937 0.8355,8.83661 0.20754,1.79771 0.43309,3.5933 0.64963,5.38995 0.56689,4.92216 1.13493,9.8446 1.65391,14.77212 0.11784,1.1188 0.24506,2.23686 0.3375,3.35804 0.0691,0.83754 0.098,1.6779 0.14692,2.51685 0,0 -2.30772,1.18831 -2.30772,1.18831 v 0 c -0.0233,-0.84789 -0.0225,-1.69678 -0.0697,-2.54368 -0.0632,-1.13305 -0.16462,-2.26371 -0.26143,-3.39439 -0.42363,-4.94827 -0.95422,-9.88746 -1.55602,-14.81705 -0.23063,-1.78972 -0.46164,-3.57941 -0.69193,-5.36918 -0.28557,-2.21921 -0.85466,-6.38358 -1.04156,-8.75811 -0.13528,-1.7184 -0.0665,-3.44122 -0.13952,-5.16118 0,0 2.49352,-1.27051 2.49352,-1.27051 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3853"
d="m 195.60386,172.0818 c -0.0651,0.4794 -0.14584,0.95692 -0.19518,1.43819 -0.19379,1.89011 -0.3049,3.99332 -0.3868,5.86731 -0.19254,4.40526 -0.18355,8.80255 -0.16306,13.21087 0.0403,4.10293 0.11093,8.20549 0.19664,12.30769 0.0134,0.64224 0.0912,4.58278 0.14929,5.46495 0.043,0.65245 0.13756,1.30046 0.20634,1.95068 0.27639,0.51376 0.41499,1.13045 0.82919,1.54127 0.52711,0.5228 1.22402,0.85441 1.89867,1.16428 1.89625,0.87098 4.04282,1.23653 6.08733,1.47647 3.9029,0.45803 7.86212,0.54041 11.7811,0.70475 7.64075,0.12222 15.29998,0.43674 22.93373,-0.0868 3.64098,-0.2497 5.99962,-0.57571 9.56465,-1.00445 3.83084,-0.47534 7.78869,-1.06074 11.08432,-3.23077 0.1174,-0.0773 -0.51343,0.15062 -0.41911,0.0464 0.43361,-0.47913 0.99636,-0.82315 1.49454,-1.23473 1.70629,-1.60527 3.52041,-3.08587 5.29876,-4.60806 0.42077,-0.32181 0.76028,-0.71441 1.07712,-1.13346 0,0 2.56246,-1.11086 2.56246,-1.11086 v 0 c -0.30729,0.45155 -0.63042,0.87882 -1.07796,1.20613 -1.80253,1.54921 -3.68192,3.0101 -5.40265,4.6543 -2.46313,2.06823 -1.60455,1.46471 -5.5653,3.81584 -0.68571,0.40703 -1.38404,0.79974 -2.11643,1.11513 -2.80683,1.20869 -5.87047,1.56384 -8.87252,1.9217 -3.3331,0.37247 -6.1303,0.72024 -9.50557,0.93997 -7.61323,0.49563 -15.24312,0.15276 -22.86126,0.0108 -3.28354,-0.11147 -8.63341,-0.22688 -12.01268,-0.57694 -2.11302,-0.21888 -4.30145,-0.57367 -6.25034,-1.48659 -0.71617,-0.33548 -1.45418,-0.69724 -2.01109,-1.25874 -0.43532,-0.43891 -0.5764,-1.09376 -0.86459,-1.64064 -0.059,-0.6626 -0.14586,-1.32331 -0.17689,-1.9878 -0.0271,-0.58076 -0.0458,-5.25701 -0.0476,-5.51961 -0.0284,-4.11731 -0.0757,-8.23445 -0.11467,-12.35166 -0.0206,-2.67387 -0.0621,-6.43756 -0.0341,-9.12418 0.014,-1.34823 0.0532,-2.6961 0.0871,-4.04398 0.0458,-1.8215 0.10238,-3.94926 0.21347,-5.80017 0.0285,-0.47489 0.0779,-0.94828 0.11687,-1.42242 0,0 2.49629,-1.21488 2.49629,-1.21488 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3855"
d="m 142.16697,190.72343 c 5.77242,0.10734 11.54659,0.0846 17.3198,0.0836 4.53725,-0.008 9.07893,0.0205 13.61217,-0.20134 0.33318,-0.0212 0.66639,-0.0416 0.99952,-0.0635 0.27,-0.0178 0.54072,-0.0274 0.80984,-0.0555 0.69715,-0.0729 1.38432,-0.23923 2.07276,-0.36617 0.14615,-0.017 0.2923,-0.0339 0.43845,-0.0509 0,0 -2.23815,1.67138 -2.23815,1.67138 v 0 c -0.14417,0.0214 -0.28835,0.0427 -0.43252,0.064 -1.27053,0.23212 -2.54377,0.41189 -3.84031,0.40563 -4.4826,0.14092 -8.96823,0.0588 -13.45213,0.0716 -5.84997,-0.001 -11.70082,-0.0221 -17.55005,0.0836 0,0 2.26062,-1.64243 2.26062,-1.64243 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3857"
d="m 180.63866,185.95955 c 0.39579,0.21823 0.76251,0.3614 1.00662,0.7924 0.50105,0.88465 0.27921,2.07038 -0.0491,2.96158 -0.13567,0.36833 -0.33831,0.7084 -0.50746,1.0626 -0.6136,0.8265 -0.68879,1.01307 -1.43598,1.69765 -0.47214,0.43258 -0.9632,0.77606 -1.51153,1.10078 -2.79757,1.6567 -2.05448,1.27539 -3.61662,2.04121 0,0 2.16488,-1.73245 2.16488,-1.73245 v 0 c 0.9952,-0.51297 1.25762,-0.6606 -1.1139,0.68573 -0.25618,0.14543 0.51442,-0.2886 0.7584,-0.45367 0.88751,-0.60049 1.64794,-1.34313 2.27191,-2.21521 0.17463,-0.33756 0.3814,-0.66033 0.52389,-1.01266 0.30297,-0.74912 0.61126,-1.91262 0.15791,-2.6843 -0.22325,-0.38003 -0.60929,-0.50405 -0.97199,-0.67479 0,0 2.32292,-1.56887 2.32292,-1.56887 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3859"
d="m 74.040039,202.1013 c 1.507289,1.67348 3.504721,2.75904 5.600263,3.52615 0.55113,0.20175 1.118431,0.35625 1.677646,0.53437 1.950511,0.48369 3.944366,0.76727 5.947238,0.9126 1.288558,0.0935 2.176814,0.1221 3.459017,0.0103 0.521981,-0.0455 1.038468,-0.14047 1.5577,-0.2107 1.265732,-0.2562 2.55479,-0.50869 3.735051,-1.05717 0.349396,-0.16237 1.38388,-0.658 1.011413,-0.55947 -1.058336,0.27997 -2.209734,1.36382 -0.511803,-0.0587 1.247434,-1.10126 2.285596,-2.39581 3.315695,-3.69331 0.466311,-0.58466 0.919351,-1.1802 1.363181,-1.78211 0,0 2.55374,-1.10497 2.55374,-1.10497 v 0 c -0.43793,0.61052 -0.89795,1.20514 -1.36142,1.79631 -0.44073,0.53921 -0.85326,1.10361 -1.3069,1.632 -0.63909,0.74439 -1.333603,1.44195 -2.034053,2.12772 -1.72271,1.48945 -0.892429,0.84756 -4.142402,2.79106 -0.331811,0.19842 -0.677235,0.37571 -1.032076,0.5292 -1.190781,0.51509 -2.476402,0.75178 -3.743634,0.98569 -1.438405,0.16989 -1.776455,0.25672 -3.256442,0.23322 -2.612707,-0.0415 -5.218718,-0.47649 -7.759948,-1.0515 -0.566111,-0.18297 -1.140685,-0.34157 -1.698329,-0.54891 -2.142085,-0.79644 -4.163666,-1.92417 -5.76861,-3.56946 0,0 2.394673,-1.44229 2.394673,-1.44229 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3861"
d="m 71.10673,201.52597 c 0.643126,-1.58881 1.656485,-2.71609 3.164761,-3.55887 3.806999,-2.12725 2.884733,-1.72346 5.86037,-2.62764 0.642199,-0.14271 1.277829,-0.3191 1.926595,-0.42813 2.456664,-0.41287 5.225613,-0.3823 7.69896,-0.0969 0.556775,0.0643 1.108614,0.16578 1.662919,0.24867 3.157416,0.55558 6.210628,1.53956 9.245585,2.54867 1.00864,0.36413 2.0228,0.71255 3.03419,1.06892 0,0 -2.27774,1.53781 -2.27774,1.53781 v 0 c -0.99895,-0.36538 -1.999434,-0.72646 -3.000634,-1.08563 -3.005698,-1.03649 -6.047787,-1.99591 -9.18978,-2.52817 -0.549254,-0.0795 -1.096296,-0.17624 -1.647759,-0.23864 -3.187039,-0.36062 -6.444607,-0.25475 -9.547738,0.59499 -0.622554,0.20012 -1.213901,0.58557 -1.867662,0.60037 -0.276881,0.006 0.861581,-0.67055 0.602853,-0.57174 -0.490368,0.18727 -0.913635,0.5244 -1.326774,0.8482 -0.84821,0.66478 -1.423202,1.52686 -1.803001,2.52113 0,0 -2.535145,1.16693 -2.535145,1.16693 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3863"
d="m 105.94426,203.6241 c -0.0774,3.13849 -0.0294,6.27793 -0.10347,9.41633 -0.0444,1.8556 -0.13938,3.70985 -0.29802,5.55909 0,0 -2.45094,1.21885 -2.45094,1.21885 v 0 c 0.20354,-1.85246 0.32489,-3.71286 0.37576,-5.57604 0.0789,-3.1158 0.048,-6.23358 -0.013,-9.34965 0,0 2.48971,-1.26858 2.48971,-1.26858 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3865"
d="m 73.248368,205.72606 c -0.0702,2.5347 -0.01323,5.07624 -0.187372,7.60759 -0.04694,0.68233 -0.126355,1.36203 -0.189529,2.04305 -0.401125,3.81892 -0.946928,7.62002 -1.401321,11.43247 0.01254,0.5006 -0.268473,1.65792 -0.04123,2.15876 0.243404,0.53646 1.04376,0.598 1.505339,0.69076 2.35145,0.34734 4.734378,0.36014 7.105465,0.3519 2.28845,-0.008 4.196141,-0.039 6.472481,-0.24556 0.983051,-0.0892 1.959581,-0.23966 2.939372,-0.35949 3.122198,-0.48599 6.242206,-1.16273 9.198364,-2.30184 1.451313,-0.55925 1.728583,-0.74629 3.070483,-1.43918 -0.37853,0.20119 -0.76335,0.81617 -1.13559,0.60358 -0.34286,-0.19582 0.64224,-0.46047 0.94735,-0.71108 0.8686,-0.71344 1.33821,-1.3312 1.95486,-2.24946 0,0 2.51536,-1.10287 2.51536,-1.10287 v 0 c -0.41359,0.64604 -0.61765,1.02496 -1.14832,1.59838 -1.44125,1.55737 -3.43512,2.50061 -5.228325,3.53907 -1.337117,0.66701 -1.624436,0.85266 -3.066981,1.38871 -2.94893,1.09582 -6.053064,1.74048 -9.157023,2.20116 -0.977085,0.11163 -1.951291,0.25229 -2.931258,0.33489 -2.344893,0.19767 -4.117057,0.21009 -6.475851,0.22832 -2.440538,0.0189 -4.900285,0.0622 -7.325659,-0.26607 -0.636019,-0.15702 -1.394045,-0.26647 -1.704671,-0.95979 -0.239847,-0.53535 0.06696,-1.72365 0.07386,-2.25979 0.52143,-3.81411 1.111699,-7.62021 1.468487,-11.45486 0.06027,-0.67507 0.133829,-1.34909 0.180817,-2.02521 0.174373,-2.50918 0.126362,-5.02365 0.07309,-7.53583 0,0 2.487811,-1.26761 2.487811,-1.26761 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3867"
d="m 35.834431,122.05478 c -0.02482,1.68544 -0.02981,3.37113 -0.03304,5.05673 0.0094,2.28586 -0.0057,4.5717 -0.008,6.85756 -0.0011,2.9198 -0.01577,5.83954 -0.0083,8.75935 0.0033,1.97579 0.02397,3.95148 0.03406,5.92723 0.0072,1.55377 -0.02784,3.10769 0.01495,4.66102 0.05444,0.33104 0.09041,1.52222 0.354116,1.78613 0.377682,0.37798 1.887767,0.43831 2.013063,0.44966 0.827985,0.075 1.659409,0.1054 2.489113,0.1581 4.551852,0.18 9.105723,-0.0311 13.651394,-0.26213 1.07778,-0.0293 2.14513,-0.10983 3.206377,-0.29364 0,0 -2.210163,1.65728 -2.210163,1.65728 v 0 c -1.046464,0.13666 -2.096428,0.19512 -3.152134,0.21796 -4.531821,0.18725 -9.067496,0.36587 -13.603571,0.19433 -0.858866,-0.0412 -1.719937,-0.0495 -2.576602,-0.12354 -0.674431,-0.0583 -1.710918,-0.0462 -2.256261,-0.64626 -0.252434,-0.27777 -0.320858,-1.5331 -0.368729,-1.87929 -0.04287,-1.55345 -0.02233,-3.10783 -0.03025,-4.66176 0.01011,-1.98732 0.03071,-3.97458 0.03406,-5.96194 0.0074,-2.91697 -0.0072,-5.83388 -0.0083,-8.75086 -0.0024,-2.28315 -0.01733,-4.5663 -0.008,-6.84945 -0.0032,-1.67438 -0.0081,-3.34884 -0.03304,-5.02306 0,0 2.499219,-1.27342 2.499219,-1.27342 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3869"
d="m 40.584712,121.9865 c 0.498113,0.11343 0.990994,0.25298 1.494343,0.34031 2.010733,0.34886 4.123611,0.54239 6.147109,0.70866 3.606906,0.29637 7.218821,0.45789 10.834672,0.58618 1.620785,0.0684 3.243352,0.0125 4.864481,0.0509 0.529473,0.0125 1.058884,0.036 1.587164,0.0737 0.678071,0.0484 1.283737,-0.0212 1.738008,0.5864 0.17522,0.23436 0.205161,0.54809 0.307742,0.82214 0.01598,0.37833 0.05977,0.75651 0.04791,1.13499 -0.02111,0.67338 -0.252058,2.49434 -0.325684,3.10731 -0.202919,1.68938 -0.434636,3.37405 -0.664421,5.05994 -0.494827,3.18499 -0.852848,6.38825 -1.115259,9.60013 -0.169127,2.15341 -0.195643,4.31361 -0.215466,6.47235 -0.0042,1.0658 -1.24e-4,2.13163 0.01016,3.19738 0.0019,0.18323 0.0646,0.37608 0.006,0.54969 -0.07552,0.22367 -0.260657,0.39369 -0.390983,0.59054 -1.025247,0.60637 -2.02066,1.26628 -3.075739,1.81911 -0.296063,0.15513 -0.634852,0.21099 -0.958445,0.29468 -0.503224,0.13015 -1.54963,0.32993 -2.071452,0.38149 -0.682532,0.0675 -1.496163,0.0528 -2.181407,0.0541 -0.822127,0.0169 -1.636073,-0.0573 -2.447608,-0.17561 0,0 2.267672,-1.5987 2.267672,-1.5987 v 0 c 0.792737,0.11176 1.58795,0.18319 2.39041,0.16609 1.42929,-0.0161 2.826375,-0.0932 4.205769,-0.50933 0.319016,-0.0962 1.179671,-0.57486 0.938112,-0.34534 -0.459462,0.43659 -1.080574,0.66273 -1.620861,0.99409 0.155152,-0.13571 0.375155,-0.22183 0.465452,-0.40713 0.08098,-0.16618 0.0021,-0.36971 0.0032,-0.55457 0.0056,-1.0709 0.0075,-2.14183 0.01413,-3.21273 0.01368,-2.17066 0.06919,-4.34188 0.236832,-6.50679 0.287692,-3.22057 0.653671,-6.43372 1.145921,-9.62991 0.223935,-1.68297 0.461496,-3.36444 0.658161,-5.0509 0.07077,-0.60684 0.273759,-2.37481 0.296183,-3.04662 0.01167,-0.34927 -0.02228,-0.69857 -0.03342,-1.04785 -0.07476,-0.224 -0.08296,-0.48281 -0.224274,-0.67202 -0.369726,-0.49501 -1.071184,-0.45973 -1.588992,-0.50526 -0.512035,-0.045 -1.025464,-0.0751 -1.539071,-0.0955 -1.592897,-0.0632 -3.188565,-0.0381 -4.78097,-0.11917 -3.607866,-0.1603 -7.213135,-0.34901 -10.815079,-0.61519 -2.097146,-0.15498 -4.23716,-0.31151 -6.322317,-0.62374 -0.527897,-0.079 -1.047128,-0.20787 -1.570694,-0.31181 0,0 2.28272,-1.5619 2.28272,-1.5619 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3871"
d="m 82.625876,125.72272 c -0.590052,1.9898 -1.079457,4.00817 -1.54796,6.02952 -0.682681,2.95934 -1.168435,5.95705 -1.498238,8.97478 -0.262927,2.55099 -0.303504,5.11635 -0.322953,7.67842 0.01564,1.67949 -0.0052,3.35782 -0.07779,5.03575 0.103463,0.18674 -0.110289,0.46148 -0.01212,0.65746 0.03164,0.0632 0.115509,0.0909 0.185066,0.10334 0.30395,0.0542 0.61368,0.0696 0.921459,0.094 1.525428,0.12113 1.960073,0.11184 3.638783,0.16671 0.892161,0.0144 1.78427,0.0325 2.676482,0.0432 1.03428,0.0124 2.068648,0.0358 3.102957,0.026 2.930279,-0.0279 5.856242,-0.19776 8.779586,-0.38465 0,0 -2.087144,1.53535 -2.087144,1.53535 v 0 c -4.862857,0.26507 -9.730195,0.43375 -14.601097,0.31891 -0.887127,-0.0159 -2.749844,-0.0202 -3.749027,-0.12622 -0.454885,-0.0483 -1.110398,0.002 -1.36597,-0.49673 -0.03415,-0.0666 0.01749,-0.66528 0.01879,-0.68467 0.111789,-1.68384 0.170061,-3.369 0.147976,-5.05701 0.02527,-2.57356 0.04294,-5.153 0.33243,-7.71367 0.333661,-3.01949 0.814113,-6.02018 1.458138,-8.98985 0.452032,-2.00988 0.955966,-4.00785 1.475766,-6.00112 0,0 2.524866,-1.20952 2.524866,-1.20952 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3873"
d="m 86.947041,125.7817 c 5.284819,0.22555 10.570421,0.42877 15.858099,0.57355 1.78635,0.10916 3.5911,-0.0218 5.3721,0.18996 0.415,0.0493 0.70451,0.11706 1.1035,0.19994 0.47456,0.18832 1.02456,0.1829 1.48017,0.42204 0.23318,0.12239 0.29224,0.21013 0.46889,0.39152 0.0504,0.0834 0.12362,0.15683 0.15132,0.25031 0.16054,0.54186 -0.0369,1.18359 -0.16114,1.70386 -0.0889,0.37233 -0.40365,1.58799 -0.48614,1.9086 -0.64307,2.33282 -1.04354,4.7138 -1.26108,7.12074 -0.15426,2.04713 -0.13376,4.10078 -0.2076,6.15119 0.007,1.32962 -0.12049,2.54741 -0.39619,3.8438 -0.32023,1.38543 -0.48611,2.79839 -0.59454,4.21414 -0.0767,0.64965 0.0209,1.37681 -0.25767,1.99155 -0.0439,0.0968 -0.11191,0.18072 -0.16786,0.27109 -2.51966,1.98133 -3.75158,2.11991 -6.53947,2.28631 -2.410197,0.11517 -4.819432,-0.10635 -7.222053,-0.27265 -0.767215,-0.0267 -1.527794,-0.10896 -2.285624,-0.22528 0,0 2.271609,-1.59845 2.271609,-1.59845 v 0 c 0.741993,0.11244 1.486681,0.19536 2.23687,0.23305 2.395603,0.17962 4.800908,0.39573 7.204228,0.23833 0.71464,-0.0543 1.19399,-0.0751 1.89255,-0.18502 0.25787,-0.0406 0.51515,-0.0879 0.76836,-0.15136 0.19939,-0.05 0.75232,-0.31085 0.58718,-0.18845 -0.99723,0.73917 -2.75674,1.57268 -1.49579,0.96392 0.0689,-0.0628 0.15271,-0.11253 0.20677,-0.18854 0.31807,-0.44727 0.2458,-1.4075 0.31087,-1.93129 0.12423,-1.42596 0.28572,-2.85186 0.5923,-4.25171 0.12036,-0.58224 0.25051,-1.16779 0.31548,-1.75982 0.0562,-0.51178 0.053,-0.79567 0.0765,-1.31868 0.0109,-0.24333 0.0243,-0.48653 0.0364,-0.72979 0.0903,-2.0584 0.0937,-4.11957 0.22766,-6.17604 0.0807,-0.93415 0.10478,-1.36811 0.2386,-2.29752 0.23583,-1.63795 0.61742,-3.2494 0.99635,-4.85857 0.25885,-1.05269 0.22449,-0.90335 0.4585,-1.88884 0.0798,-0.33626 0.3063,-1.12296 0.22387,-1.49443 -0.0161,-0.0726 -0.077,-0.12732 -0.11546,-0.19098 -0.49738,-0.47039 -1.21328,-0.49567 -1.84367,-0.69014 -2.07144,-0.43255 -4.20028,-0.33393 -6.30258,-0.45532 -5.315789,-0.20095 -10.631863,-0.41989 -15.950962,-0.50852 0,0 2.209703,-1.5925 2.209703,-1.5925 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3875"
d="m 39.42045,171.8741 c -0.386061,3.07114 -0.825233,6.13534 -1.193122,9.20898 -0.325438,2.75157 -0.460682,5.51909 -0.517205,8.2876 -0.07618,1.33576 0.122145,2.66699 0.530346,3.93752 0.251127,0.59229 0.386845,0.54578 1.048401,0.583 0.442587,0.0249 0.885439,0.0462 1.328516,0.0599 0.73439,0.0226 1.469117,0.0325 2.203674,0.0487 0.99631,0.011 1.992564,0.0299 2.988932,0.033 1.667436,0.005 4.801145,-0.0262 6.470452,-0.048 1.08346,-0.0141 4.085306,-0.0541 5.283252,-0.11613 0.606796,-0.0314 1.211231,-0.0983 1.816847,-0.14752 0.383124,-0.09 0.766249,-0.18008 1.149373,-0.27012 0,0 -2.171319,1.64692 -2.171319,1.64692 v 0 c -0.374234,0.0682 -0.748466,0.13633 -1.122701,0.2045 -0.593473,0.0351 -1.186278,0.0845 -1.780421,0.10546 -1.044802,0.0368 -4.32322,0.0576 -5.220382,0.0661 -3.179358,0.03 -6.358723,0.0678 -9.538287,0.0652 -0.758175,-0.002 -1.51641,0.004 -2.274523,-0.006 -0.466423,-0.006 -0.933749,-0.005 -1.398757,-0.0419 -0.752882,-0.0596 -0.969369,-0.18472 -1.234966,-0.83876 -0.40009,-1.30923 -0.605938,-2.67916 -0.512268,-4.04945 0.07915,-2.78506 0.218033,-5.56834 0.555382,-8.33603 0.378595,-3.03989 0.809051,-6.07462 1.099066,-9.1246 0,0 2.48971,-1.26857 2.48971,-1.26857 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3877"
d="m 41.127254,171.0983 c 5.502198,0.6054 11.022999,0.98873 16.548107,1.30717 1.769994,0.0896 3.08473,0.14105 4.816068,0.27928 0.783788,0.0626 2.59589,0.12526 3.235497,0.81271 0.149976,0.16119 0.1881,0.39815 0.282149,0.59722 -0.0058,0.28725 0.01892,0.57674 -0.0173,0.86176 -0.137467,1.08131 -0.633929,2.13435 -0.977966,3.15649 -0.409279,1.21599 -0.44527,1.37954 -0.802749,2.59214 -0.521033,1.85894 -0.765349,3.77645 -1.162063,5.66243 -0.0776,0.25012 -0.145298,0.50354 -0.232804,0.75037 -0.174321,0.49172 -0.402199,0.96322 -0.579366,1.45391 -0.271359,0.75157 -0.449863,1.51498 -0.612434,2.29541 0,0 -2.487181,1.20429 -2.487181,1.20429 v 0 c 0.160972,-0.7906 0.3293,-1.57549 0.594601,-2.3395 0.351806,-1.01315 0.210518,-0.45006 0.585753,-1.43782 0.09045,-0.2381 0.162351,-0.48285 0.243528,-0.72427 0.41207,-1.89958 0.691454,-3.82664 1.201462,-5.70447 0.307348,-1.04118 0.453091,-1.56165 0.792528,-2.60107 0.328207,-1.00503 0.787952,-2.01953 0.972253,-3.06702 0.04277,-0.24309 0.03952,-0.49205 0.05927,-0.73808 -0.06189,-0.15243 -0.07336,-0.33707 -0.185671,-0.45727 -0.579885,-0.62066 -2.361078,-0.71636 -3.054485,-0.78324 -1.752089,-0.16898 -2.91846,-0.225 -4.726493,-0.33904 -5.586902,-0.36182 -11.169819,-0.77655 -16.755512,-1.15302 0,0 2.262812,-1.62838 2.262812,-1.62838 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="39.6875"
y="135.41519"
id="text3881"><tspan
sodipodi:role="line"
id="tspan3879"
x="39.6875"
y="135.41519"
style="stroke-width:0.26458332">jira-pod</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="84.666664"
y="135.60417"
id="text3885"><tspan
sodipodi:role="line"
id="tspan3883"
x="84.666664"
y="135.60417"
style="stroke-width:0.26458332">backup</tspan><tspan
sodipodi:role="line"
x="84.666664"
y="143.54167"
style="stroke-width:0.26458332"
id="tspan3887">pod</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:4.23333333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="41.955357"
y="180.58334"
id="text3891"><tspan
sodipodi:role="line"
id="tspan3889"
x="41.955357"
y="180.58334"
style="stroke-width:0.26458332">postgres</tspan><tspan
sodipodi:role="line"
x="41.955357"
y="188.52084"
style="stroke-width:0.26458332"
id="tspan3893">pod</tspan></text>
<path
id="path3907"
d="m 52.944442,158.72263 c -0.494538,1.16082 -0.734864,2.40421 -0.908976,3.64743 -0.144328,1.19587 -0.152612,2.40227 -0.155803,3.6051 -0.0011,0.5429 0.0011,1.08579 0.0044,1.62868 0,0 -2.483165,1.26595 -2.483165,1.26595 v 0 c 0.0011,-0.54498 2.14e-4,-1.08995 0.0029,-1.63493 0.01069,-1.21331 -0.0028,-2.43073 0.139443,-3.63784 0.171741,-1.25572 0.411848,-2.50691 0.851694,-3.69971 0,0 2.549472,-1.17468 2.549472,-1.17468 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3909"
d="m 48.702891,196.58962 c -0.983491,1.38136 -1.620311,2.94593 -2.079914,4.56733 -0.20266,0.86633 -0.362188,1.75156 -0.359669,2.64457 0.0011,0.39477 0.03945,0.70759 0.07655,1.09786 0.133447,0.70089 0.12818,1.57125 0.544298,2.18748 0.0759,0.11239 0.181306,0.20175 0.271957,0.30262 0.145984,0.10334 0.279003,0.22801 0.437952,0.31002 0.476173,0.24569 1.311666,0.45462 1.778269,0.57179 1.466292,0.3682 2.942921,0.61885 4.435962,0.84728 2.846943,0.39365 5.69304,0.79395 8.53716,1.20799 1.030647,0.15529 2.067353,0.23849 3.107126,0.29421 0,0 -2.232737,1.6009 -2.232737,1.6009 v 0 c -1.037595,-0.0746 -2.073079,-0.16892 -3.10208,-0.32668 -2.831767,-0.43649 -5.66892,-0.83888 -8.507153,-1.23063 -1.506183,-0.23508 -3.003103,-0.48864 -4.485291,-0.85044 -0.620178,-0.15138 -1.307746,-0.30904 -1.879489,-0.62406 -0.174649,-0.0962 -0.320207,-0.23772 -0.480309,-0.35659 -0.105394,-0.1223 -0.226369,-0.23274 -0.316185,-0.36689 -0.43444,-0.64893 -0.433845,-1.54238 -0.57804,-2.27942 -0.03598,-0.37414 -0.08011,-0.75709 -0.08497,-1.13331 -0.01183,-0.91532 0.141254,-1.82249 0.345377,-2.71159 0.447873,-1.62994 1.06616,-3.21228 2.008486,-4.62608 0,0 2.562694,-1.12636 2.562694,-1.12636 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3911"
d="m 67.962922,208.49623 c 1.070838,0.31779 2.167284,0.54226 3.214373,0.93861 0.197241,0.0747 0.397279,0.14594 0.582877,0.2461 0.125605,0.0678 0.229637,0.16957 0.344458,0.25435 0.01669,0.12371 0.08987,0.25281 0.05009,0.37113 -0.04888,0.14537 -0.16351,0.27326 -0.293905,0.354 -0.928216,0.57473 -1.886839,1.10107 -2.85886,1.59814 -0.206107,0.1054 -0.440912,0.14168 -0.664032,0.20338 -0.717156,0.1983 -0.81847,0.20034 -1.564466,0.3399 -1.206381,0.11959 -2.377842,0.43781 -3.573502,0.61874 -0.447103,0.0779 -0.86301,0.25918 -1.280184,0.42923 0,0 2.194981,-1.72259 2.194981,-1.72259 v 0 c 0.430683,-0.15951 0.861899,-0.32128 1.320041,-0.38459 1.17993,-0.19528 2.348624,-0.4561 3.536698,-0.6044 0.660292,-0.13819 0.917766,-0.17416 1.553038,-0.37515 0.222552,-0.0704 0.846693,-0.37617 0.658627,-0.2379 -0.60353,0.44372 -1.297225,0.7514 -1.921076,1.16606 -0.110376,0.0734 0.256448,-0.0744 0.373182,-0.13719 0.04729,-0.0254 0.07108,-0.0805 0.106611,-0.12075 -0.497805,-0.36195 -0.972431,-0.50844 -1.562304,-0.6935 -0.832008,-0.26102 -1.685035,-0.4405 -2.523384,-0.67847 0,0 2.306741,-1.5651 2.306741,-1.5651 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3913"
d="m 39.426155,195.73705 c 0.130109,1.74138 0.315502,3.4774 0.411678,5.22191 0.02657,2.29955 0.218123,4.5906 0.346969,6.8854 0.181595,2.14019 0.03349,4.27787 -0.127632,6.41272 -0.167685,2.00592 -0.548558,3.98491 -0.761238,5.98502 -1.43e-4,0.0239 -0.03462,0.7161 0.05031,0.83327 0.08978,0.12385 0.629618,0.0619 0.766376,0.0481 0.409287,-0.0413 1.421601,-0.21601 1.769012,-0.27324 3.044381,-0.61198 6.140601,-0.86782 9.236567,-1.02681 2.907319,-0.14732 5.818301,-0.15465 8.728422,-0.17088 2.001536,-0.0442 4.002434,-0.11204 6.00371,-0.1659 0.51657,-0.009 1.030671,-0.0181 1.545387,-0.0615 0,0 -2.249906,1.65733 -2.249906,1.65733 v 0 c -0.509751,0.0241 -1.019328,0.0303 -1.529659,0.0352 -1.98863,0.0367 -3.976619,0.0997 -5.965323,0.13113 -2.895195,-10e-4 -5.791366,0.0239 -8.684,0.15555 -3.110183,0.17656 -6.218859,0.45175 -9.273397,1.09096 -0.592434,0.0975 -2.393484,0.57517 -2.8227,-0.10631 -0.09725,-0.1544 -0.05146,-0.83294 -0.04986,-0.92063 0.23949,-1.99988 0.613863,-3.98168 0.793954,-5.98933 0.152844,-2.12428 0.324363,-4.25145 0.143322,-6.38112 -0.126492,-2.29393 -0.30217,-4.58494 -0.351922,-6.8825 -0.101545,-1.74025 -0.254855,-3.47516 -0.481187,-5.20391 0,0 2.501122,-1.27438 2.501122,-1.27438 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3915"
d="m 66.072366,216.95851 c 0.159356,0.069 0.31765,0.1405 0.47807,0.20698 0.56293,0.2333 0.612868,0.25391 1.231924,0.41939 0.341617,0.0913 0.903883,0.17795 1.224502,0.38031 0.109281,0.069 0.172664,0.19232 0.258998,0.28847 -0.02923,0.15056 -0.0055,0.32217 -0.0877,0.45168 -0.102698,0.16184 -0.272053,0.27585 -0.436468,0.37439 -0.992952,0.59509 -2.007229,1.15454 -3.027447,1.70157 -0.833075,0.44669 -1.7858,0.70879 -2.675686,1.01244 -0.305697,0.10363 -0.611394,0.20726 -0.917094,0.31088 0,0 2.165753,-1.68434 2.165753,-1.68434 v 0 c 0.304175,-0.10313 0.608353,-0.20626 0.912529,-0.30939 0.62801,-0.21987 1.247357,-0.42545 1.861008,-0.68377 0.27492,-0.11573 1.052922,-0.55116 0.812953,-0.37399 -2.543275,1.87773 -2.042072,1.11792 -1.007078,0.65271 -0.05659,-0.0634 -0.09585,-0.14825 -0.169759,-0.19019 -0.312222,-0.17717 -0.882116,-0.28123 -1.199301,-0.36981 -0.602935,-0.16838 -1.18201,-0.38839 -1.759529,-0.62828 0,0 2.334326,-1.55905 2.334326,-1.55905 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3917"
d="m 51.503606,167.96544 c -0.08266,0.89345 -0.109286,1.78994 -0.201771,2.68247 -0.01302,0.12242 -0.02604,0.24483 -0.03904,0.36725 0,0 -2.508607,1.24347 -2.508607,1.24347 v 0 c 0.01418,-0.12277 0.02838,-0.24555 0.04257,-0.36833 0.101182,-0.88755 0.144767,-1.778 0.196094,-2.66975 0,0 2.510758,-1.25511 2.510758,-1.25511 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3919"
d="m 45.447285,198.11493 c 0.01156,-0.12851 0.02313,-0.25702 0.03471,-0.38552 0,0 2.503757,-1.2502 2.503757,-1.2502 v 0 c -0.0092,0.12687 -0.01847,0.25374 -0.0277,0.38061 0,0 -2.510759,1.25511 -2.510759,1.25511 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3921"
d="m 64.059876,171.53602 c 1.900489,-1.71523 3.942122,-3.26578 5.944502,-4.85871 1.85697,-1.49953 3.883628,-2.7665 5.94346,-3.96428 1.576517,-0.98722 3.241336,-1.80545 4.884642,-2.66746 0,0 -2.147583,1.72401 -2.147583,1.72401 v 0 c -0.665753,0.34578 -3.396488,1.79756 -0.192357,-0.0335 -2.067388,1.18774 -4.103844,2.44352 -5.971104,3.93239 -1.985666,1.5694 -4.009927,3.0999 -5.879319,4.80838 0,0 -2.582241,1.05918 -2.582241,1.05918 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3923"
d="m 77.394656,160.5203 c 1.71513,-0.51237 3.402428,-1.10991 5.106115,-1.65813 0.731046,-0.20514 1.445453,-0.47607 2.192218,-0.61835 0.104561,-0.0199 0.20833,-0.0604 0.314616,-0.0546 0.07719,0.004 0.14428,0.0555 0.216419,0.0833 0.03782,0.12287 0.115371,0.24007 0.113466,0.36862 -0.0043,0.28902 -0.259276,0.78355 -0.381381,1.01141 -0.3425,0.63913 -0.75638,1.23516 -1.172686,1.82705 -0.133842,0.17621 -0.267687,0.35242 -0.401532,0.52864 0,0 -2.54744,1.09328 -2.54744,1.09328 v 0 c 0.136983,-0.17389 0.273966,-0.34778 0.410946,-0.52168 0.421023,-0.57643 0.823592,-1.16024 1.177112,-1.78149 0.716511,-1.25915 -0.09667,0.13344 0.422593,-0.85095 0.01468,-0.0278 0.04181,-0.047 0.06272,-0.0706 -0.855752,0.009 -1.756891,0.50569 -2.587709,0.67547 -1.716987,0.54835 -3.422219,1.13217 -5.135367,1.69243 0,0 2.209911,-1.72442 2.209911,-1.72442 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3925"
d="m 91.683138,212.09182 c 1.137703,-1.27556 2.22654,-2.5865 3.263471,-3.9453 0.205557,-0.29666 0.41461,-0.59094 0.616672,-0.88999 0.201801,-0.29867 0.410565,-0.59327 0.594834,-0.90306 0.767257,-1.28989 1.24637,-2.68889 1.649878,-4.12529 0.522272,-2.45874 -0.09514,-4.92399 -0.664305,-7.31516 -0.480769,-1.80394 -1.205447,-3.52772 -1.834835,-5.28175 -0.298577,-0.8321 -0.5046,-1.46266 -0.781976,-2.29274 -0.695264,-2.33261 -0.985563,-4.7562 -1.379644,-7.1512 -0.210613,-1.35997 -0.401425,-2.72626 -0.525383,-4.09719 -0.104293,-1.69462 -0.09761,-3.39385 -0.106246,-5.09099 -0.0078,-0.97578 -0.01262,-1.95157 -0.01765,-2.92736 0,0 2.474648,-1.26073 2.474648,-1.26073 v 0 c -0.006,0.98012 -0.01124,1.96025 -0.0113,2.94039 0.0083,1.68507 0.0096,3.37227 0.125936,5.05414 0.125944,1.37044 0.28489,2.73904 0.477658,4.10158 0.364437,2.38643 0.652237,4.7988 1.351819,7.11689 0.817494,2.55338 1.826959,5.03793 2.613068,7.6012 0.501657,2.05518 1.054037,4.2044 0.903427,6.33968 -0.0258,0.36576 -0.10537,0.72574 -0.15806,1.08861 -0.392003,1.44997 -0.858281,2.89413 -1.614436,4.20269 -0.180864,0.31299 -0.392888,0.60693 -0.592895,0.90804 -0.200612,0.30204 -0.405952,0.60091 -0.60893,0.90137 -1.017805,1.34721 -2.073376,2.65982 -3.194034,3.92315 0,0 -2.581733,1.10302 -2.581733,1.10302 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<path
id="path3927"
d="m 86.290988,166.10648 c 1.277006,-1.25353 2.595866,-2.46288 3.881532,-3.70761 1.234541,-1.2677 2.435617,-2.17255 4.171458,-2.88723 0.218774,-0.0901 0.879158,0.68042 0.917866,0.72019 0.503224,0.62344 0.920787,1.30821 1.349386,1.98309 0,0 -2.385978,1.39024 -2.385978,1.39024 v 0 c -0.413814,-0.65854 -0.815473,-1.32949 -1.329338,-1.9175 -0.137113,-0.12254 -0.252312,-0.27528 -0.411338,-0.36762 -0.09482,-0.0551 -0.411628,0.006 -0.323577,-0.0591 0.633148,-0.4698 1.346676,-0.82077 2.032794,-1.20913 0.151402,-0.0857 -0.292542,0.18973 -0.426956,0.30018 -0.224541,0.18451 -0.861785,0.816 -1.046877,0.99661 -1.276379,1.23421 -2.592424,2.42705 -3.843401,3.6869 0,0 -2.585571,1.07098 -2.585571,1.07098 z"
inkscape:connector-curvature="0"
style="stroke-width:0.26458332" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="137.20535"
y="180.77232"
id="text3931"><tspan
sodipodi:role="line"
id="tspan3929"
x="137.20535"
y="180.77232"
style="stroke-width:0.26458332">restic - backup</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="206.375"
y="180.58334"
id="text3954"><tspan
sodipodi:role="line"
id="tspan3952"
x="206.375"
y="180.58334"
style="stroke-width:0.26458332">S3-Bucket</tspan><tspan
sodipodi:role="line"
x="206.375"
y="188.52084"
style="stroke-width:0.26458332"
id="tspan3956" /><tspan
sodipodi:role="line"
x="206.375"
y="196.45834"
style="stroke-width:0.26458332"
id="tspan3958">with folder /jira</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

@ -0,0 +1,30 @@
# Build images
## Prerequisites
See also https://pypi.org/project/ddadevops/
```bash
# Ensure that yout python3 version is at least Python 3.7!
sudo apt install python3-pip
pip3 install pip --upgrade --user
pip3 install pybuilder ddadevops deprecation --user
export PATH=$PATH:~/.local/bin
# terraform
pip3 install dda-python-terraform --user
# AwsMixin
pip3 install boto3 --user
# AwsMfaMixin
pip3 install boto3 mfa --user
```
In folder "docker-backup" resp. "docker-nextcloud":
```bash
# step test is optional
pyb image test publish
```

@ -0,0 +1,54 @@
from os import environ
from datetime import datetime
from pybuilder.core import task, init
from ddadevops import *
name = "c4k-cloud"
MODULE = "backup"
PROJECT_ROOT_PATH = "../.."
version = "10.2.1-dev"
@init
def initialize(project):
image_tag = version
if "dev" in image_tag:
image_tag += datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
input = {
"name": name,
"module": MODULE,
"stage": "notused",
"project_root_path": PROJECT_ROOT_PATH,
"build_types": ["IMAGE"],
"mixin_types": [],
"image_naming": "NAME_AND_MODULE",
"image_tag": f"{image_tag}",
}
project.build_depends_on("ddadevops>=4.7.0")
build = DevopsImageBuild(project, input)
build.initialize_build_dir()
@task
def image(project):
build = get_devops_build(project)
build.image()
@task
def drun(project):
build = get_devops_build(project)
build.drun()
@task
def test(project):
build = get_devops_build(project)
build.test()
@task
def publish(project):
build = get_devops_build(project)
build.dockerhub_login()
build.dockerhub_publish()

@ -1,4 +1,4 @@
FROM domaindrivenarchitecture/dda-backup
FROM domaindrivenarchitecture/dda-backup:latest
# Prepare Entrypoint Script
ADD resources /tmp

@ -1,6 +1,6 @@
#!/bin/bash
set -o pipefail
set -Eexo pipefail
function main() {
@ -11,7 +11,8 @@ function main() {
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD
file_env POSTGRES_USER
file_env RESTIC_DAYS_TO_KEEP 14
file_env RESTIC_DAYS_TO_KEEP 30
file_env RESTIC_MONTHS_TO_KEEP 12
backup-roles 'oc_'
backup-db-dump

@ -1,5 +1,7 @@
#!/bin/bash
set -exo pipefail
if test -f "/var/backups/config/config.orig"; then
rm /var/backups/config/config.php

@ -1,5 +1,7 @@
#!/bin/bash
set -exo pipefail
function main() {
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD

@ -1,5 +1,7 @@
#!/bin/bash
set -Eexo pipefail
function main() {
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD

@ -1,5 +1,7 @@
#!/bin/bash
set -Eexo pipefail
function main() {
file_env AWS_ACCESS_KEY_ID
file_env AWS_SECRET_ACCESS_KEY

@ -0,0 +1,21 @@
#!/bin/bash
set -exo pipefail
function main() {
{
install -m 0700 /tmp/entrypoint.sh /
install -m 0700 /tmp/entrypoint-start-and-wait.sh /
install -m 0700 /tmp/init.sh /usr/local/bin/
install -m 0700 /tmp/backup.sh /usr/local/bin/
install -m 0700 /tmp/restore.sh /usr/local/bin/
install -m 0700 /tmp/list-snapshots.sh /usr/local/bin/
install -m 0700 /tmp/start-maintenance.sh /usr/local/bin/
install -m 0700 /tmp/end-maintenance.sh /usr/local/bin/
cleanupDocker
} > /dev/null
}
source /tmp/install_functions_debian.sh
main

@ -0,0 +1,31 @@
#!/bin/bash
set -exo pipefail
function list-snapshot-files() {
if [ -z ${CERTIFICATE_FILE} ];
then
restic -r ${RESTIC_REPOSITORY}/${backup_file_path} snapshots
else
restic -r ${RESTIC_REPOSITORY}/${backup_file_path} snapshots --cacert ${CERTIFICATE_FILE}
fi
}
function main() {
file_env AWS_ACCESS_KEY_ID
file_env AWS_SECRET_ACCESS_KEY
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD
file_env POSTGRES_USER
list-snapshot-roles
list-snapshot-db
list-snapshot-files
}
source /usr/local/lib/functions.sh
source /usr/local/lib/file-functions.sh
source /usr/local/lib/pg-functions.sh
main

@ -1,8 +1,12 @@
#!/bin/bash
set -Eeo pipefail
set -Eexo pipefail
function main() {
local role_snapshot_id="${1:-latest}"
local db_snapshot_id="${2:-latest}"
local file_snapshot_id="${3:-latest}"
start-maintenance.sh
@ -15,14 +19,15 @@ function main() {
drop-create-db
restore-roles
restore-db
restore-directory '/var/backups/'
restore-roles ${role_snapshot_id}
restore-db ${db_snapshot_id}
restore-directory '/var/backups/' ${file_snapshot_id}
end-maintenance.sh
}
source /usr/local/lib/functions.sh
source /usr/local/lib/pg-functions.sh
source /usr/local/lib/file-functions.sh
main
main "$@"

@ -4,7 +4,10 @@ if [ ! -f "/var/backups/config/config.orig" ]; then
rm -f /var/backups/config/config.orig
cp /var/backups/config/config.php /var/backups/config/config.orig
# put nextcloud in maintenance mode
sed -i "s/);/ \'maintenance\' => true,\n);/g" /var/backups/config/config.php
chown www-data:root /var/backups/config/config.php
touch /var/backups/config/config.php

@ -1,49 +0,0 @@
from os import environ
from pybuilder.core import task, init
from ddadevops import *
import logging
name = 'c4k-cloud-backup'
MODULE = 'docker'
PROJECT_ROOT_PATH = '../..'
class MyBuild(DevopsDockerBuild):
pass
@init
def initialize(project):
project.build_depends_on('ddadevops>=0.12.4')
stage = 'notused'
dockerhub_user = environ.get('DOCKERHUB_USER')
if not dockerhub_user:
dockerhub_user = gopass_field_from_path('meissa/web/docker.com', 'login')
dockerhub_password = environ.get('DOCKERHUB_PASSWORD')
if not dockerhub_password:
dockerhub_password = gopass_password_from_path('meissa/web/docker.com')
config = create_devops_docker_build_config(
stage, PROJECT_ROOT_PATH, MODULE, dockerhub_user, dockerhub_password)
build = MyBuild(project, config)
build.initialize_build_dir()
@task
def image(project):
build = get_devops_build(project)
build.image()
@task
def drun(project):
build = get_devops_build(project)
build.drun()
@task
def test(project):
build = get_devops_build(project)
build.test()
@task
def publish(project):
build = get_devops_build(project)
build.dockerhub_login()
build.dockerhub_publish()

@ -1,12 +0,0 @@
#!/bin/bash
apt-get update > /dev/null;
install -m 0700 /tmp/entrypoint.sh /
install -m 0700 /tmp/entrypoint-start-and-wait.sh /
install -m 0700 /tmp/init.sh /usr/local/bin/
install -m 0700 /tmp/backup.sh /usr/local/bin/
install -m 0700 /tmp/restore.sh /usr/local/bin/
install -m 0700 /tmp/start-maintenance.sh /usr/local/bin/
install -m 0700 /tmp/end-maintenance.sh /usr/local/bin/

@ -1,10 +0,0 @@
FROM meissa-cloud-backup
RUN apt update
RUN apt -yqq --no-install-recommends --yes install curl default-jre-headless
RUN curl -L -o /tmp/serverspec.jar https://github.com/DomainDrivenArchitecture/dda-serverspec-crate/releases/download/2.0.0/dda-serverspec-standalone.jar
COPY serverspec.edn /tmp/serverspec.edn
RUN java -jar /tmp/serverspec.jar /tmp/serverspec.edn -v

@ -1,7 +0,0 @@
{:file [{:path "/usr/local/bin/init.sh" :mod "700"}
{:path "/usr/local/bin/backup.sh" :mod "700"}
{:path "/usr/local/bin/restore.sh" :mod "700"}
{:path "/usr/local/bin/start-maintenance.sh" :mod "700"}
{:path "/usr/local/bin/end-maintenance.sh" :mod "700"}
{:path "/entrypoint.sh" :mod "700"}
{:path "/entrypoint-start-and-wait.sh" :mod "700"}]}

@ -1,49 +0,0 @@
from os import environ
from pybuilder.core import task, init
from ddadevops import *
import logging
name = 'c4k-cloud'
MODULE = 'docker'
PROJECT_ROOT_PATH = '../..'
class MyBuild(DevopsDockerBuild):
pass
@init
def initialize(project):
project.build_depends_on('ddadevops>=0.12.7')
stage = 'notused'
dockerhub_user = environ.get('DOCKERHUB_USER')
if not dockerhub_user:
dockerhub_user = gopass_field_from_path('meissa/web/docker.com', 'login')
dockerhub_password = environ.get('DOCKERHUB_PASSWORD')
if not dockerhub_password:
dockerhub_password = gopass_password_from_path('meissa/web/docker.com')
config = create_devops_docker_build_config(
stage, PROJECT_ROOT_PATH, MODULE, dockerhub_user, dockerhub_password)
build = MyBuild(project, config)
build.initialize_build_dir()
@task
def image(project):
build = get_devops_build(project)
build.image()
@task
def drun(project):
build = get_devops_build(project)
build.drun()
@task
def test(project):
build = get_devops_build(project)
build.test()
@task
def publish(project):
build = get_devops_build(project)
build.dockerhub_login()
build.dockerhub_publish()

@ -1,11 +0,0 @@
#!/bin/bash
set -Eeo pipefail
apt update && apt -qqy install postgresql-client > /dev/null
mkdir /var/data
install -m 0700 /tmp/install-debug.sh /usr/local/bin/
install -m 0544 /tmp/upload-max-limit.ini /usr/local/etc/php/conf.d/
install -m 0544 /tmp/memory-limit.ini /usr/local/etc/php/conf.d/
install -m 0755 /tmp/entrypoint.sh /

@ -1,11 +0,0 @@
FROM meissa-cloud-app
RUN apt update
RUN mkdir /usr/share/man/man1/
RUN apt -yqq install --no-install-recommends --yes curl default-jre-headless
RUN curl -L -o /tmp/serverspec.jar https://github.com/DomainDrivenArchitecture/dda-serverspec-crate/releases/download/2.0.0/dda-serverspec-standalone.jar
COPY serverspec.edn /tmp/serverspec.edn
RUN java -jar /tmp/serverspec.jar /tmp/serverspec.edn -v

@ -1,2 +0,0 @@
{:file [{:path "/var/data"}
{:path "/entrypoint.sh" :mod "755"}]}

@ -0,0 +1,53 @@
from os import environ
from datetime import datetime
from pybuilder.core import task, init
from ddadevops import *
name = 'c4k-cloud'
MODULE = 'not_set'
PROJECT_ROOT_PATH = '../..'
version = "10.2.1-dev"
@init
def initialize(project):
image_tag = version
if "dev" in image_tag:
image_tag += datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
input = {
"name": name,
"module": MODULE,
"stage": "notused",
"project_root_path": PROJECT_ROOT_PATH,
"build_types": ["IMAGE"],
"mixin_types": [],
"image_naming": "NAME_ONLY",
"image_tag": f"{image_tag}",
}
project.build_depends_on("ddadevops>=4.7.0")
build = DevopsImageBuild(project, input)
build.initialize_build_dir()
@task
def image(project):
build = get_devops_build(project)
build.image()
@task
def drun(project):
build = get_devops_build(project)
build.drun()
@task
def test(project):
build = get_devops_build(project)
build.test()
@task
def publish(project):
build = get_devops_build(project)
build.dockerhub_login()
build.dockerhub_publish()

@ -1,4 +1,7 @@
FROM nextcloud:22
FROM nextcloud:29
# REQUIRES docker >= 2.10.10
# https://docs.docker.com/engine/release-notes/20.10/#201010
# Prepare Entrypoint Script
ADD resources /tmp

@ -1,5 +1,6 @@
#!/bin/sh
set -eu
#!/bin/bash
set -exo pipefail
# version_greater A B returns whether A > B
version_greater() {

@ -0,0 +1,20 @@
#!/bin/bash
set -exo pipefail
function main() {
{
upgradeSystem
apt-get install -qqy ca-certificates curl gnupg postgresql-client
mkdir /var/data
} > /dev/null
install -m 0700 /tmp/install-debug.sh /usr/local/bin/
install -m 0544 /tmp/upload-max-limit.ini /usr/local/etc/php/conf.d/
install -m 0544 /tmp/memory-limit.ini /usr/local/etc/php/conf.d/
install -m 0755 /tmp/entrypoint.sh /
cleanupDocker
}
source /tmp/install_functions_debian.sh
DEBIAN_FRONTEND=noninteractive DEBCONF_NOWARNINGS=yes main

@ -1,33 +1,33 @@
{
"name": "c4k-nextcloud",
"description": "Generate c4k yaml for a nextcloud deployment.",
"author": "meissa GmbH",
"version": "0.1.3-SNAPSHOT",
"homepage": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud#readme",
"repository": "https://www.npmjs.com/package/c4k-nextcloud",
"license": "APACHE2",
"main": "c4k-nextcloud.js",
"bin": {
"c4k-nextcloud": "./c4k-nextcloud.js"
},
"keywords": [
"cljs",
"nextcloud",
"k8s",
"c4k",
"deployment",
"yaml",
"convention4kubernetes"
],
"bugs": {
"url": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/issues"
},
"dependencies": {
"js-base64": "^3.6.1",
"js-yaml": "^4.0.0"
},
"devDependencies": {
"shadow-cljs": "^2.11.18",
"source-map-support": "^0.5.19"
}
}
"name": "c4k-nextcloud",
"description": "Generate c4k yaml for a nextcloud deployment.",
"author": "meissa GmbH",
"version": "10.2.1-SNAPSHOT",
"homepage": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud#readme",
"repository": "https://www.npmjs.com/package/c4k-nextcloud",
"license": "APACHE2",
"main": "c4k-nextcloud.js",
"bin": {
"c4k-nextcloud": "./c4k-nextcloud.js"
},
"keywords": [
"cljs",
"nextcloud",
"k8s",
"c4k",
"deployment",
"yaml",
"convention4kubernetes"
],
"bugs": {
"url": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/issues"
},
"dependencies": {
"js-base64": "^3.6.1",
"js-yaml": "^4.0.0"
},
"devDependencies": {
"shadow-cljs": "^2.11.18",
"source-map-support": "^0.5.19"
}
}

@ -1,19 +1,20 @@
(defproject org.domaindrivenarchitecture/c4k-nextcloud "1.0.2-SNAPSHOT"
(defproject org.domaindrivenarchitecture/c4k-nextcloud "10.2.1-SNAPSHOT"
:description "nextcloud c4k-installation package"
:url "https://domaindrivenarchitecture.org"
:license {:name "Apache License, Version 2.0"
:url "https://www.apache.org/licenses/LICENSE-2.0.html"}
:dependencies [[org.clojure/clojure "1.10.3"]
[org.clojure/tools.reader "1.3.4"]
[org.domaindrivenarchitecture/c4k-common-clj "0.3.2-SNAPSHOT"]]
:dependencies [[org.clojure/clojure "1.11.3"]
[org.clojure/tools.reader "1.4.2"]
[org.domaindrivenarchitecture/c4k-common-clj "6.3.0"]
[hickory "0.7.1" :exclusions [viebel/codox-klipse-theme]]]
:target-path "target/%s/"
:source-paths ["src/main/cljc"
"src/main/clj"]
:resource-paths ["src/main/resources"]
:repositories [["snapshots" :clojars]
["releases" :clojars]]
:deploy-repositories [["snapshots" :clojars]
["releases" :clojars]]
:deploy-repositories [["snapshots" {:sign-releases false :url "https://clojars.org/repo"}]
["releases" {:sign-releases false :url "https://clojars.org/repo"}]]
:profiles {:test {:test-paths ["src/test/cljc"]
:resource-paths ["src/test/resources"]
:dependencies [[dda/data-test "0.1.1"]]}
@ -21,21 +22,14 @@
:uberjar {:aot :all
:main dda.c4k-nextcloud.uberjar
:uberjar-name "c4k-nextcloud-standalone.jar"
:dependencies [[org.clojure/tools.cli "1.0.206"]
[ch.qos.logback/logback-classic "1.3.0-alpha4"
:dependencies [[org.clojure/tools.cli "1.1.230"]
[ch.qos.logback/logback-classic "1.5.6"
:exclusions [com.sun.mail/javax.mail]]
[org.slf4j/jcl-over-slf4j "2.0.0-alpha1"]]}}
[org.slf4j/jcl-over-slf4j "2.0.13"]
[com.github.clj-easy/graal-build-time "1.0.5"]]}}
:release-tasks [["test"]
["vcs" "assert-committed"]
["change" "version" "leiningen.release/bump-version" "release"]
["vcs" "commit"]
["vcs" "tag"]
["change" "version" "leiningen.release/bump-version"]]
:aliases {"native" ["shell"
"native-image"
"--report-unsupported-elements-at-runtime"
"--initialize-at-build-time"
"-jar" "target/uberjar/c4k-nextcloud-standalone.jar"
"-H:ResourceConfigurationFiles=graalvm-resource-config.json"
"-H:Log=registerResource"
"-H:Name=target/graalvm/${:name}"]})
["vcs" "tag" "v" "--no-sign"]
["change" "version" "leiningen.release/bump-version"]])

@ -4,7 +4,7 @@
"src/test/cljc"
"src/test/cljs"
"src/test/resources"]
:dependencies [[org.domaindrivenarchitecture/c4k-common-cljs "0.4.3"]
:dependencies [[org.domaindrivenarchitecture/c4k-common-cljs "6.3.0"]
[hickory "0.7.1"]]
:builds {:frontend {:target :browser
:modules {:main {:init-fn dda.c4k-nextcloud.browser/init}}
@ -12,5 +12,4 @@
:compiler-options {:optimizations :advanced}}
:test {:target :node-test
:output-to "target/node-tests.js"
:autorun true
:repl-pprint true}}}

@ -1,56 +1,15 @@
(ns dda.c4k-nextcloud.uberjar
(:gen-class)
(:require
[clojure.spec.alpha :as s]
[clojure.string :as cs]
[clojure.tools.reader.edn :as edn]
[expound.alpha :as expound]
[dda.c4k-common.uberjar :as uberjar]
[dda.c4k-nextcloud.nextcloud :as nextcloud]
[dda.c4k-nextcloud.core :as core]))
(def usage
"usage:
c4k-nextcloud {your configuraton file} {your authorization file}")
(s/def ::options (s/* #{"-h"}))
(s/def ::filename (s/and string?
#(not (cs/starts-with? % "-"))))
(s/def ::cmd-args (s/cat :options ::options
:args (s/?
(s/cat :config ::filename
:auth ::filename))))
(defn expound-config
[config]
(expound/expound ::core/config config))
(defn invalid-args-msg
[spec args]
(s/explain spec args)
(println (str "Bad commandline arguments\n" usage)))
(defn -main [& cmd-args]
(let [parsed-args-cmd (s/conform ::cmd-args cmd-args)]
(if (= ::s/invalid parsed-args-cmd)
(invalid-args-msg ::cmd-args cmd-args)
(let [{:keys [options args]} parsed-args-cmd
{:keys [config auth]} args]
(cond
(some #(= "-h" %) options)
(println usage)
:default
(let [config-str (slurp config)
auth-str (slurp auth)
config-edn (edn/read-string config-str)
auth-edn (edn/read-string auth-str)
config-valid? (s/valid? core/config? config-edn)
auth-valid? (s/valid? core/auth? auth-edn)]
(if (and config-valid? auth-valid?)
(println (core/generate config-edn auth-edn))
(do
(when (not config-valid?)
(println
(expound/expound-str core/config? config-edn {:print-specs? false})))
(when (not auth-valid?)
(println
(expound/expound-str core/auth? auth-edn {:print-specs? false})))))))))))
(uberjar/main-common
"c4k-nextcloud"
nextcloud/config?
nextcloud/auth?
core/config-defaults
core/k8s-objects
cmd-args))

@ -1,37 +1,40 @@
(ns dda.c4k-nextcloud.backup
(:require
[clojure.spec.alpha :as s]
#?(:cljs [shadow.resource :as rc])
[dda.c4k-common.yaml :as yaml]
[dda.c4k-common.base64 :as b64]
[dda.c4k-common.common :as cm]))
[dda.c4k-common.common :as cm]
[dda.c4k-common.predicate :as cp]
#?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]])))
(s/def ::aws-access-key-id cm/bash-env-string?)
(s/def ::aws-secret-access-key cm/bash-env-string?)
(s/def ::restic-password cm/bash-env-string?)
(s/def ::restic-repository cm/bash-env-string?)
(s/def ::aws-access-key-id cp/bash-env-string?)
(s/def ::aws-secret-access-key cp/bash-env-string?)
(s/def ::restic-password cp/bash-env-string?)
(s/def ::restic-repository cp/bash-env-string?)
#?(:cljs
(defmethod yaml/load-resource :backup [resource-name]
(case resource-name
"backup/config.yaml" (rc/inline "backup/config.yaml")
"backup/cron.yaml" (rc/inline "backup/cron.yaml")
"backup/secret.yaml" (rc/inline "backup/secret.yaml")
(throw (js/Error. "Undefined Resource!")))))
(get (inline-resources "backup") resource-name)))
(defn generate-config [my-conf]
(let [{:keys [restic-repository]} my-conf]
(->
(yaml/from-string (yaml/load-resource "backup/config.yaml"))
(yaml/load-as-edn "backup/config.yaml")
(cm/replace-key-value :restic-repository restic-repository))))
(defn generate-cron []
(yaml/from-string (yaml/load-resource "backup/cron.yaml")))
(defn generate-backup-restore-deployment [my-conf]
(let [backup-restore-yaml (yaml/load-as-edn "backup/backup-restore-deployment.yaml")]
(if (and (contains? my-conf :local-integration-test) (= true (:local-integration-test my-conf)))
(cm/replace-named-value backup-restore-yaml "CERTIFICATE_FILE" "/var/run/secrets/localstack-secrets/ca.crt")
backup-restore-yaml)))
(defn generate-secret [my-auth]
(let [{:keys [aws-access-key-id aws-secret-access-key restic-password]} my-auth]
(->
(yaml/from-string (yaml/load-resource "backup/secret.yaml"))
(yaml/load-as-edn "backup/secret.yaml")
(cm/replace-key-value :aws-access-key-id (b64/encode aws-access-key-id))
(cm/replace-key-value :aws-secret-access-key (b64/encode aws-secret-access-key))
(cm/replace-key-value :restic-password (b64/encode restic-password)))))

@ -1,53 +1,43 @@
(ns dda.c4k-nextcloud.core
(:require
[clojure.string :as cs]
[clojure.spec.alpha :as s]
#?(:clj [orchestra.core :refer [defn-spec]]
:cljs [orchestra.core :refer-macros [defn-spec]])
[dda.c4k-common.yaml :as yaml]
[dda.c4k-common.postgres :as postgres]
[dda.c4k-nextcloud.nextcloud :as nextcloud]
[dda.c4k-nextcloud.backup :as backup]))
(:require
#?(:clj [orchestra.core :refer [defn-spec]]
:cljs [orchestra.core :refer-macros [defn-spec]])
[dda.c4k-common.common :as cm]
[dda.c4k-common.predicate :as cp]
[dda.c4k-common.yaml :as yaml]
[dda.c4k-common.postgres :as postgres]
[dda.c4k-nextcloud.nextcloud :as nextcloud]
[dda.c4k-nextcloud.backup :as backup]
[dda.c4k-common.monitoring :as mon]
[dda.c4k-common.namespace :as ns]))
(def config-defaults {:issuer :staging})
(def config-defaults {:namespace "nextcloud"
:issuer "staging"
:pvc-storage-class-name "hcloud-volumes-encrypted"
:pv-storage-size-gb 200})
(def config? (s/keys :req-un [::nextcloud/fqdn]
:opt-un [::nextcloud/issuer ::nextcloud/nextcloud-data-volume-path
::postgres/postgres-data-volume-path ::restic-repository
::nextcloud/storage-size]))
(def auth? (s/keys :req-un [::postgres/postgres-db-user ::postgres/postgres-db-password
::nextcloud/nextcloud-admin-user ::nextcloud/nextcloud-admin-password
::aws-access-key-id ::aws-secret-access-key
::restic-password]))
(defn k8s-objects [config]
(into
[]
(concat [(yaml/to-string (postgres/generate-config :postgres-size :8gb))
(yaml/to-string (postgres/generate-secret config))]
(when (contains? config :postgres-data-volume-path)
[(yaml/to-string (postgres/generate-persistent-volume config))])
[(yaml/to-string (postgres/generate-pvc))
(yaml/to-string (postgres/generate-deployment))
(yaml/to-string (postgres/generate-service))]
(when (contains? config :nextcloud-data-volume-path)
[(yaml/to-string (nextcloud/generate-persistent-volume config))])
[(yaml/to-string (nextcloud/generate-secret config))
(yaml/to-string (nextcloud/generate-pvc))
(yaml/to-string (nextcloud/generate-deployment config))
(yaml/to-string (nextcloud/generate-service))
(yaml/to-string (nextcloud/generate-certificate config))
(yaml/to-string (nextcloud/generate-ingress config))]
(when (contains? config :restic-repository)
[(yaml/to-string (backup/generate-config config))
(yaml/to-string (backup/generate-secret config))
(yaml/to-string (backup/generate-cron))]))))
(defn-spec generate any?
[my-config config?
my-auth auth?]
(let [resulting-config (merge config-defaults my-config my-auth)]
(cs/join
"\n---\n"
(k8s-objects resulting-config))))
(defn-spec k8s-objects cp/map-or-seq?
[config nextcloud/config?
auth nextcloud/auth?]
(let [resolved-config (merge config-defaults config)]
(map yaml/to-string
(filter
#(not (nil? %))
(cm/concat-vec
(ns/generate resolved-config)
(postgres/generate (merge resolved-config {:postgres-size :8gb
:db-name "cloud"
:pv-storage-size-gb 50})
auth)
[(nextcloud/generate-secret auth)
(nextcloud/generate-pvc resolved-config)
(nextcloud/generate-deployment resolved-config)
(nextcloud/generate-service)]
(nextcloud/generate-ingress-and-cert resolved-config)
(when (:contains? resolved-config :restic-repository)
[(backup/generate-config resolved-config)
(backup/generate-secret auth)
(backup/generate-cron)
(backup/generate-backup-restore-deployment resolved-config)])
(when (:contains? resolved-config :mon-cfg)
(mon/generate (:mon-cfg resolved-config) (:mon-auth auth))))))))

@ -1,71 +1,72 @@
(ns dda.c4k-nextcloud.nextcloud
(:require
[clojure.spec.alpha :as s]
#?(:cljs [shadow.resource :as rc])
#?(:clj [orchestra.core :refer [defn-spec]]
:cljs [orchestra.core :refer-macros [defn-spec]])
[dda.c4k-common.yaml :as yaml]
[dda.c4k-common.ingress :as ing]
[dda.c4k-common.base64 :as b64]
[dda.c4k-common.prefixes :as cp]
[dda.c4k-common.common :as cm]))
[dda.c4k-common.predicate :as cp]
[dda.c4k-common.postgres :as postgres]
[dda.c4k-common.common :as cm]
[dda.c4k-common.monitoring :as mon]
#?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]])))
(s/def ::fqdn cp/fqdn-string?)
(s/def ::issuer cp/letsencrypt-issuer?)
(s/def ::restic-repository string?)
(s/def ::nextcloud-data-volume-path string?)
(s/def ::nextcloud-admin-user cp/bash-env-string?)
(s/def ::nextcloud-admin-password cp/bash-env-string?)
(s/def ::pvc-storage-class-name cp/pvc-storage-class-name?)
(s/def ::pv-storage-size-gb pos?)
(def config? (s/keys :req-un [::fqdn]
:opt-un [::issuer
::restic-repository
::pv-storage-size-gb
::pvc-storage-class-name
::mon/mon-cfg]))
(def auth? (s/keys :req-un [::postgres/postgres-db-user ::postgres/postgres-db-password
::nextcloud-admin-user ::nextcloud-admin-password
::aws-access-key-id ::aws-secret-access-key
::restic-password]
:opt-un [::mon/mon-auth]))
#?(:cljs
(defmethod yaml/load-resource :nextcloud [resource-name]
(case resource-name
"nextcloud/certificate.yaml" (rc/inline "nextcloud/certificate.yaml")
"nextcloud/deployment.yaml" (rc/inline "nextcloud/deployment.yaml")
"nextcloud/ingress.yaml" (rc/inline "nextcloud/ingress.yaml")
"nextcloud/persistent-volume.yaml" (rc/inline "nextcloud/persistent-volume.yaml")
"nextcloud/pvc.yaml" (rc/inline "nextcloud/pvc.yaml")
"nextcloud/service.yaml" (rc/inline "nextcloud/service.yaml")
"nextcloud/secret.yaml" (rc/inline "nextcloud/secret.yaml")
(throw (js/Error. "Undefined Resource!")))))
(defn generate-certificate [config]
(let [{:keys [fqdn issuer]} config
letsencrypt-issuer (str "letsencrypt-" (name issuer) "-issuer")]
(->
(yaml/from-string (yaml/load-resource "nextcloud/certificate.yaml"))
(assoc-in [:spec :commonName] fqdn)
(assoc-in [:spec :dnsNames] [fqdn])
(assoc-in [:spec :issuerRef :name] letsencrypt-issuer))))
(get (inline-resources "nextcloud") resource-name)))
(defn generate-deployment [config]
(defn-spec generate-deployment cp/map-or-seq?
[config config?]
(let [{:keys [fqdn]} config]
(-> (yaml/from-string (yaml/load-resource "nextcloud/deployment.yaml"))
(cm/replace-all-matching-values-by-new-value "fqdn" fqdn))))
(-> (yaml/load-as-edn "nextcloud/deployment.yaml")
(cm/replace-all-matching "fqdn" fqdn))))
(defn generate-ingress [config]
(let [{:keys [fqdn issuer]
:or {issuer :staging}} config
letsencrypt-issuer (str "letsencrypt-" (name issuer) "-issuer")]
(->
(yaml/from-string (yaml/load-resource "nextcloud/ingress.yaml"))
(assoc-in [:metadata :annotations :cert-manager.io/cluster-issuer] letsencrypt-issuer)
(cm/replace-all-matching-values-by-new-value "fqdn" fqdn))))
(defn generate-persistent-volume [config]
(let [{:keys [nextcloud-data-volume-path storage-size]} config]
(->
(yaml/from-string (yaml/load-resource "nextcloud/persistent-volume.yaml"))
(assoc-in [:spec :hostPath :path] nextcloud-data-volume-path)
;(assoc-in [:spec :capacity :storage] (str storage-size "Gi"))
)))
(defn-spec generate-ingress-and-cert cp/map-or-seq?
[config config?]
(ing/generate-ingress-and-cert
(merge
{:service-name "cloud-service"
:service-port 80
:fqdns [(:fqdn config)]}
config)))
(defn generate-pvc []
(yaml/from-string (yaml/load-resource "nextcloud/pvc.yaml")))
(defn-spec generate-pvc cp/map-or-seq?
[config (s/keys :req-un [::pv-storage-size-gb ::pvc-storage-class-name])]
(let [{:keys [pv-storage-size-gb pvc-storage-class-name]} config]
(->
(yaml/load-as-edn "nextcloud/pvc.yaml")
(assoc-in [:spec :resources :requests :storage] (str pv-storage-size-gb "Gi"))
(assoc-in [:spec :storageClassName] (name pvc-storage-class-name)))))
(defn generate-service []
(yaml/from-string (yaml/load-resource "nextcloud/service.yaml")))
(yaml/load-as-edn "nextcloud/service.yaml"))
(defn generate-secret [config]
(let [{:keys [nextcloud-admin-user nextcloud-admin-password]} config]
(defn-spec generate-secret cp/map-or-seq?
[auth auth?]
(let [{:keys [nextcloud-admin-user nextcloud-admin-password]} auth]
(->
(yaml/from-string (yaml/load-resource "nextcloud/secret.yaml"))
(yaml/load-as-edn "nextcloud/secret.yaml")
(cm/replace-key-value :nextcloud-admin-user (b64/encode nextcloud-admin-user))
(cm/replace-key-value :nextcloud-admin-password (b64/encode nextcloud-admin-password)))))

@ -1,31 +1,42 @@
(ns dda.c4k-nextcloud.browser
(:require
[clojure.tools.reader.edn :as edn]
[dda.c4k-common.common :as cm]
[dda.c4k-common.monitoring :as mon]
[dda.c4k-nextcloud.core :as core]
[dda.c4k-nextcloud.nextcloud :as nextcloud]
[dda.c4k-common.browser :as br]
[dda.c4k-common.postgres :as pgc]))
(defn generate-content
[]
(into [] (concat [(assoc (br/generate-needs-validation) :content
(into [] (concat (br/generate-input-field "fqdn" "Your fqdn:" "nextcloud-neu.prod.meissa-gmbh.de")
(br/generate-input-field "nextcloud-data-volume-path" "(Optional) Your nextcloud-data-volume-path:" "/var/nextcloud")
(br/generate-input-field "postgres-data-volume-path" "(Optional) Your postgres-data-volume-path:" "/var/postgres")
(br/generate-input-field "restic-repository" "(Optional) Your restic-repository:" "restic-repository")
(br/generate-input-field "issuer" "(Optional) Your issuer prod/staging:" "")
[(br/generate-br)]
(br/generate-text-area "auth" "Your auth.edn:" "{:postgres-db-user \"nextcloud\"
(defn generate-content []
(cm/concat-vec
[(assoc
(br/generate-needs-validation) :content
(cm/concat-vec
(br/generate-group "domain"
(cm/concat-vec (br/generate-input-field "fqdn" "Your fqdn:" "nextcloud-neu.prod.meissa-gmbh.de")
(br/generate-input-field "issuer" "(Optional) Your issuer prod/staging:" "")
(br/generate-input-field "pv-storage-size-gb" "(Optional) Your nextcloud storage size in GB" "8")
(br/generate-input-field "pvc-storage-class-name" "(Optional) Your storage class type (manual / local-path):" "local-path")
(br/generate-input-field "postgres-data-volume-path" "(Optional) Your postgres-data-volume-path:" "/var/postgres")
(br/generate-input-field "restic-repository" "(Optional) Your restic-repository:" "restic-repository")
(br/generate-input-field "mon-cluster-name" "(Optional) monitoring cluster name:" "keycloak")
(br/generate-input-field "mon-cluster-stage" "(Optional) monitoring cluster stage:" "test")
(br/generate-input-field "mon-cloud-url" "(Optional) grafana cloud url:" "https://prometheus-prod-01-eu-west-0.grafana.net/api/prom/push")))
(br/generate-group "credentials"
(br/generate-text-area "auth" "Your auth.edn:" "{:postgres-db-user \"nextcloud\"
:postgres-db-password \"nextcloud-db-password\"
:nextcloud-admin-password \"nextcloud-admin-password\"
:nextcloud-admin-user \"nextcloud-admin-user\"
:aws-access-key-id \"aws-id\"
:aws-secret-access-key \"aws-secret\"
:restic-password \"restic-password\"}"
"5")
[(br/generate-br)]
(br/generate-button "generate-button" "Generate c4k yaml"))))]
(br/generate-output "c4k-nextcloud-output" "Your c4k deployment.yaml:" "25"))))
:restic-password \"restic-password\"}
:mon-auth {:grafana-cloud-user \"your-user-id\"
:grafana-cloud-password \"your-cloud-password\"}"
"5"))
[(br/generate-br)]
(br/generate-button "generate-button" "Generate c4k yaml")))]
(br/generate-output "c4k-nextcloud-output" "Your c4k deployment.yaml:" "25")))
(defn generate-content-div
[]
@ -35,29 +46,40 @@
(generate-content)})
(defn config-from-document []
(let [nextcloud-data-volume-path (br/get-content-from-element "nextcloud-data-volume-path" :optional true)
(let [pv-storage-size-gb (br/get-content-from-element "pv-storage-size-gb" :optional true)
pvc-storage-class-name (br/get-content-from-element "pvc-storage-class-name" :optional true)
postgres-data-volume-path (br/get-content-from-element "postgres-data-volume-path" :optional true)
restic-repository (br/get-content-from-element "restic-repository" :optional true)
issuer (br/get-content-from-element "issuer" :optional true :deserializer keyword)]
issuer (br/get-content-from-element "issuer" :optional true)
mon-cluster-name (br/get-content-from-element "mon-cluster-name" :optional true)
mon-cluster-stage (br/get-content-from-element "mon-cluster-stage" :optional true)
mon-cloud-url (br/get-content-from-element "mon-cloud-url" :optional true)]
(merge
{:fqdn (br/get-content-from-element "fqdn")}
(when (some? nextcloud-data-volume-path)
{:nextcloud-data-volume-path nextcloud-data-volume-path})
(when (and (some? pv-storage-size-gb) (some? pvc-storage-class-name))
{:pv-storage-size-gb pv-storage-size-gb :pvc-storage-class-name pvc-storage-class-name})
(when (some? postgres-data-volume-path)
{:postgres-data-volume-path postgres-data-volume-path})
(when (some? restic-repository)
{:restic-repository restic-repository})
(when (some? issuer)
{:issuer issuer})
)))
(when (some? mon-cluster-name)
{:mon-cfg {:cluster-name mon-cluster-name
:cluster-stage (keyword mon-cluster-stage)
:grafana-cloud-url mon-cloud-url}}))))
(defn validate-all! []
(br/validate! "fqdn" ::nextcloud/fqdn)
(br/validate! "nextcloud-data-volume-path" ::nextcloud/nextcloud-data-volume-path :optional true)
(br/validate! "pv-storage-size-gb" ::nextcloud/pv-storage-size-gb :optional true)
(br/validate! "pvc-storage-class-name" ::nextcloud/pvc-storage-class-name :optional true)
(br/validate! "postgres-data-volume-path" ::pgc/postgres-data-volume-path :optional true)
(br/validate! "restic-repository" ::nextcloud/restic-repository :optional true)
(br/validate! "issuer" ::nextcloud/issuer :optional true :deserializer keyword)
(br/validate! "auth" core/auth? :deserializer edn/read-string)
(br/validate! "issuer" ::nextcloud/issuer :optional true)
(br/validate! "mon-cluster-name" ::mon/cluster-name :optional true)
(br/validate! "mon-cluster-stage" ::mon/cluster-stage :optional true)
(br/validate! "mon-cloud-url" ::mon/grafana-cloud-url :optional true)
(br/validate! "auth" nextcloud/auth? :deserializer edn/read-string)
(br/set-validated!))
(defn add-validate-listener [name]
@ -70,13 +92,19 @@
(.getElementById "generate-button")
(.addEventListener "click"
#(do (validate-all!)
(-> (core/generate
(config-from-document)
(br/get-content-from-element "auth" :deserializer edn/read-string))
(-> (cm/generate-common
(config-from-document)
(br/get-content-from-element "auth" :deserializer edn/read-string)
{}
core/k8s-objects)
(br/set-output!)))))
(add-validate-listener "fqdn")
(add-validate-listener "nextcloud-data-volume-path")
(add-validate-listener "pv-storage-size-gb")
(add-validate-listener "pvc-storage-class-name")
(add-validate-listener "postgres-data-volume-path")
(add-validate-listener "restic-repository")
(add-validate-listener "issuer")
(add-validate-listener "mon-cluster-name")
(add-validate-listener "mon-cluster-stage")
(add-validate-listener "mon-cloud-url")
(add-validate-listener "auth"))

@ -0,0 +1,87 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: backup-restore
namespace: nextcloud
spec:
replicas: 0
selector:
matchLabels:
app: backup-restore
strategy:
type: Recreate
template:
metadata:
labels:
app: backup-restore
app.kubernetes.io/name: backup-restore
app.kubernetes.io/part-of: cloud
spec:
containers:
- name: backup-app
image: domaindrivenarchitecture/c4k-cloud-backup
imagePullPolicy: IfNotPresent
command: ["/entrypoint-start-and-wait.sh"]
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-password
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
name: postgres-config
key: postgres-db
- name: POSTGRES_HOST
value: "postgresql-service:5432"
- name: POSTGRES_SERVICE
value: "postgresql-service"
- name: POSTGRES_PORT
value: "5432"
- name: AWS_DEFAULT_REGION
value: eu-central-1
- name: AWS_ACCESS_KEY_ID_FILE
value: /var/run/secrets/backup-secrets/aws-access-key-id
- name: AWS_SECRET_ACCESS_KEY_FILE
value: /var/run/secrets/backup-secrets/aws-secret-access-key
- name: RESTIC_REPOSITORY
valueFrom:
configMapKeyRef:
name: backup-config
key: restic-repository
- name: RESTIC_PASSWORD_FILE
value: /var/run/secrets/backup-secrets/restic-password
- name: CERTIFICATE_FILE
value: ""
volumeMounts:
- name: cloud-data-volume
mountPath: /var/backups
- name: backup-secret-volume
mountPath: /var/run/secrets/backup-secrets
readOnly: true
- name: cloud-secret-volume
mountPath: /var/run/secrets/cloud-secrets
readOnly: true
- name: rotation-credential-secret-volume
mountPath: /var/run/secrets/rotation-credential-secret
readOnly: true
volumes:
- name: cloud-data-volume
persistentVolumeClaim:
claimName: cloud-pvc
- name: cloud-secret-volume
secret:
secretName: cloud-secret
- name: backup-secret-volume
secret:
secretName: backup-secret
- name: rotation-credential-secret-volume
secret:
secretName: rotation-credential-secret
optional: true

@ -1,68 +0,0 @@
kind: Pod
apiVersion: v1
metadata:
name: backup-restore
labels:
app.kubernetes.io/name: backup-restore
app.kubernetes.io/part-of: cloud
spec:
containers:
- name: backup-app
image: domaindrivenarchitecture/c4k-cloud-backup
imagePullPolicy: IfNotPresent
command: ["/entrypoint-start-and-wait.sh"]
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-password
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
name: postgres-config
key: postgres-db
- name: POSTGRES_HOST
value: "postgresql-service:5432"
- name: POSTGRES_SERVICE
value: "postgresql-service"
- name: POSTGRES_PORT
value: "5432"
- name: AWS_DEFAULT_REGION
value: eu-central-1
- name: AWS_ACCESS_KEY_ID_FILE
value: /var/run/secrets/backup-secrets/aws-access-key-id
- name: AWS_SECRET_ACCESS_KEY_FILE
value: /var/run/secrets/backup-secrets/aws-secret-access-key
- name: RESTIC_REPOSITORY
valueFrom:
configMapKeyRef:
name: backup-config
key: restic-repository
- name: RESTIC_PASSWORD_FILE
value: /var/run/secrets/backup-secrets/restic-password
volumeMounts:
- name: cloud-data-volume
mountPath: /var/backups
- name: backup-secret-volume
mountPath: /var/run/secrets/backup-secrets
readOnly: true
- name: cloud-secret-volume
mountPath: /var/run/secrets/cloud-secrets
readOnly: true
volumes:
- name: cloud-data-volume
persistentVolumeClaim:
claimName: cloud-pvc
- name: cloud-secret-volume
secret:
secretName: cloud-secret
- name: backup-secret-volume
secret:
secretName: backup-secret
restartPolicy: OnFailure

@ -2,6 +2,7 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: backup-config
namespace: nextcloud
labels:
app.kubernetes.io/name: backup
app.kubernetes.io/part-of: cloud

@ -0,0 +1,8 @@
apiVersion: v1
kind: Secret
metadata:
name: rotation-credential-secret
namespace: nextcloud
type: Opaque
data:
rotation-credential: "dGVzdAo="

@ -2,12 +2,13 @@ apiVersion: batch/v1
kind: CronJob
metadata:
name: cloud-backup
namespace: nextcloud
labels:
app.kubernetes.part-of: cloud
spec:
schedule: "10 23 * * *"
successfulJobsHistoryLimit: 0
failedJobsHistoryLimit: 0
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
@ -18,12 +19,21 @@ spec:
imagePullPolicy: IfNotPresent
command: ["/entrypoint.sh"]
env:
- name: POSTGRES_USER_FILE
value: /var/run/secrets/cloud-secrets/postgres-user
- name: POSTGRES_DB_FILE
value: /var/run/secrets/cloud-secrets/postgres-db
- name: POSTGRES_PASSWORD_FILE
value: /var/run/secrets/cloud-secrets/postgres-password
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-password
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
name: postgres-config
key: postgres-db
- name: POSTGRES_HOST
value: "postgresql-service:5432"
- name: POSTGRES_SERVICE

@ -2,6 +2,7 @@ apiVersion: v1
kind: Secret
metadata:
name: backup-secret
namespace: nextcloud
type: Opaque
data:
aws-access-key-id: "aws-access-key-id"

@ -1,13 +0,0 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cloud-cert
namespace: default
spec:
secretName: cloud-secret
commonName: fqdn
dnsNames:
- fqdn
issuerRef:
name: letsencrypt-staging-issuer
kind: ClusterIssuer

@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: cloud-deployment
namespace: nextcloud
spec:
selector:
matchLabels:
@ -12,12 +13,13 @@ spec:
template:
metadata:
labels:
app: cloud-app
app.kubernetes.io/name: cloud-pod
app.kubernetes.io/application: cloud
redeploy: v3
spec:
containers:
- image: domaindrivenarchitecture/c4k-cloud
- image: domaindrivenarchitecture/c4k-cloud:8.0.0
name: cloud-app
imagePullPolicy: IfNotPresent
ports:

@ -1,29 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-cloud
annotations:
cert-manager.io/cluster-issuer: letsencrypt-staging-issuer
nginx.ingress.kubernetes.io/proxy-body-size: "256m"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
namespace: default
spec:
tls:
- hosts:
- fqdn
secretName: cloud-secret
rules:
- host: fqdn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: cloud-service
port:
number: 80

@ -1,15 +0,0 @@
kind: PersistentVolume
apiVersion: v1
metadata:
name: cloud-pv-volume
labels:
type: local
app.kubernetes.io/application: cloud
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
capacity:
storage: 200Gi
hostPath:
path: "/var/cloud"

@ -2,15 +2,14 @@ apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cloud-pvc
namespace: nextcloud
labels:
app.kubernetes.io/application: cloud
spec:
storageClassName: manual
storageClassName: REPLACEME
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi
selector:
matchLabels:
app.kubernetes.io/application: cloud
storage: REPLACEME

@ -2,6 +2,7 @@ apiVersion: v1
kind: Secret
metadata:
name: cloud-secret
namespace: nextcloud
type: Opaque
data:
nextcloud-admin-user: "admin-user"

@ -2,6 +2,7 @@ apiVersion: v1
kind: Service
metadata:
name: cloud-service
namespace: nextcloud
labels:
app.kubernetes.io/name: cloud-service
app.kubernetes.io/application: cloud

@ -8,7 +8,7 @@
(deftest should-generate-secret
(is (= {:apiVersion "v1"
:kind "Secret"
:metadata {:name "backup-secret"}
:metadata {:name "backup-secret", :namespace "nextcloud"}
:type "Opaque"
:data
{:aws-access-key-id "YXdzLWlk", :aws-secret-access-key "YXdzLXNlY3JldA==", :restic-password "cmVzdGljLXB3"}}
@ -18,6 +18,7 @@
(is (= {:apiVersion "v1"
:kind "ConfigMap"
:metadata {:name "backup-config"
:namespace "nextcloud"
:labels {:app.kubernetes.io/name "backup"
:app.kubernetes.io/part-of "cloud"}}
:data
@ -27,11 +28,11 @@
(deftest should-generate-cron
(is (= {:apiVersion "batch/v1"
:kind "CronJob"
:metadata {:name "cloud-backup", :labels {:app.kubernetes.part-of "cloud"}}
:metadata {:name "cloud-backup", :namespace "nextcloud", :labels {:app.kubernetes.part-of "cloud"}}
:spec
{:schedule "10 23 * * *"
:successfulJobsHistoryLimit 0
:failedJobsHistoryLimit 0
:successfulJobsHistoryLimit 1
:failedJobsHistoryLimit 1
:jobTemplate
{:spec
{:template
@ -42,9 +43,20 @@
:imagePullPolicy "IfNotPresent"
:command ["/entrypoint.sh"]
:env
[{:name "POSTGRES_USER_FILE", :value "/var/run/secrets/cloud-secrets/postgres-user"}
{:name "POSTGRES_DB_FILE", :value "/var/run/secrets/cloud-secrets/postgres-db"}
{:name "POSTGRES_PASSWORD_FILE", :value "/var/run/secrets/cloud-secrets/postgres-password"}
[{:valueFrom
{:secretKeyRef
{:name "postgres-secret",
:key "postgres-user"}},
:name "POSTGRES_USER"}
{:valueFrom
{:secretKeyRef
{:name "postgres-secret",
:key "postgres-password"}},
:name "POSTGRES_PASSWORD"}
{:valueFrom
{:configMapKeyRef
{:name "postgres-config", :key "postgres-db"}},
:name "POSTGRES_DB"}
{:name "POSTGRES_HOST", :value "postgresql-service:5432"}
{:name "POSTGRES_SERVICE", :value "postgresql-service"}
{:name "POSTGRES_PORT", :value "5432"}

@ -1,41 +0,0 @@
(ns dda.c4k-nextcloud.core-test
(:require
#?(:clj [clojure.test :refer [deftest is are testing run-tests]]
:cljs [cljs.test :refer-macros [deftest is are testing run-tests]])
[dda.c4k-nextcloud.core :as cut]))
(deftest should-k8s-objects
(is (= 16
(count (cut/k8s-objects {:fqdn "nextcloud-neu.prod.meissa-gmbh.de"
:postgres-db-user "nextcloud"
:postgres-db-password "nextcloud-db-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"
:issuer :prod
:nextcloud-data-volume-path "/var/nextcloud"
:postgres-data-volume-path "/var/postgres"
:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-pw"
:restic-repository "restic-repository"}))))
(is (= 14
(count (cut/k8s-objects {:fqdn "nextcloud-neu.prod.meissa-gmbh.de"
:postgres-db-user "nextcloud"
:postgres-db-password "nextcloud-db-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"
:issuer :prod
:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-pw"
:restic-repository "restic-repository"}))))
(is (= 11
(count (cut/k8s-objects {:fqdn "nextcloud-neu.prod.meissa-gmbh.de"
:postgres-db-user "nextcloud"
:postgres-db-password "nextcloud-db-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"
:issuer :prod
:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-pw"})))))

@ -2,82 +2,100 @@
(:require
#?(:clj [clojure.test :refer [deftest is are testing run-tests]]
:cljs [cljs.test :refer-macros [deftest is are testing run-tests]])
[dda.c4k-nextcloud.nextcloud :as cut]))
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as st]
[dda.c4k-common.yaml :as yaml]
[dda.c4k-nextcloud.nextcloud :as cut]
#?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]])))
(st/instrument)
#?(:cljs
(defmethod yaml/load-resource :nextcloud-test [resource-name]
(get (inline-resources "nextcloud-test") resource-name)))
(deftest validate-valid-resources
(is (s/valid? cut/config? (yaml/load-as-edn "nextcloud-test/valid-config.yaml")))
(is (s/valid? cut/auth? (yaml/load-as-edn "nextcloud-test/valid-auth.yaml")))
(is (not (s/valid? cut/config? (yaml/load-as-edn "nextcloud-test/invalid-config.yaml"))))
(is (not (s/valid? cut/auth? (yaml/load-as-edn "nextcloud-test/invalid-auth.yaml")))))
(deftest should-generate-secret
(is (= {:apiVersion "v1"
:kind "Secret"
:metadata {:name "cloud-secret"}
:metadata {:name "cloud-secret", :namespace "nextcloud"}
:type "Opaque"
:data
{:nextcloud-admin-user "Y2xvdWRhZG1pbg=="
:nextcloud-admin-password "Y2xvdWRwYXNzd29yZA=="}}
(cut/generate-secret {:nextcloud-admin-user "cloudadmin"
(cut/generate-secret {:postgres-db-user "postgres-user"
:postgres-db-password "postgres-password"
:aws-access-key-id "aws-key"
:aws-secret-access-key "aws-secret-key"
:restic-password "restic-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"}))))
(deftest should-generate-certificate
(is (= {:apiVersion "cert-manager.io/v1"
:kind "Certificate"
:metadata {:name "cloud-cert", :namespace "default"}
:spec
{:secretName "cloud-secret"
:commonName "xx"
:dnsNames ["xx"]
:issuerRef
{:name "letsencrypt-prod-issuer", :kind "ClusterIssuer"}}}
(cut/generate-certificate {:fqdn "xx" :issuer :prod}))))
(deftest should-generate-ingress
(is (= {:apiVersion "networking.k8s.io/v1"
:kind "Ingress"
:metadata
{:name "ingress-cloud"
:annotations
{:cert-manager.io/cluster-issuer
"letsencrypt-staging-issuer"
:nginx.ingress.kubernetes.io/proxy-body-size "256m"
:nginx.ingress.kubernetes.io/ssl-redirect "true"
:nginx.ingress.kubernetes.io/rewrite-target "/"
:nginx.ingress.kubernetes.io/proxy-connect-timeout "300"
:nginx.ingress.kubernetes.io/proxy-send-timeout "300"
:nginx.ingress.kubernetes.io/proxy-read-timeout "300"}
:namespace "default"}
:spec
{:tls [{:hosts ["xx"], :secretName "cloud-secret"}]
:rules
[{:host "xx"
:http
{:paths
[{:path "/"
:pathType "Prefix"
:backend
{:service
{:name "cloud-service", :port {:number 80}}}}]}}]}}
(cut/generate-ingress {:fqdn "xx"}))))
(deftest should-generate-persistent-volume
(is (= {:kind "PersistentVolume"
:apiVersion "v1"
:metadata {:name "cloud-pv-volume"
:labels {:type "local", :app.kubernetes.io/application "cloud"}}
:spec {:storageClassName "manual"
:accessModes ["ReadWriteOnce"]
:capacity {:storage "200Gi"}
:hostPath {:path "xx"}}}
(cut/generate-persistent-volume {:nextcloud-data-volume-path "xx"}))))
(deftest should-generate-ingress-and-cert
(is (= [{:apiVersion "cert-manager.io/v1",
:kind "Certificate",
:metadata
{:name "cloud-service",
:labels {:app.kubernetes.part-of "cloud-service"},
:namespace "default"},
:spec
{:secretName "cloud-service",
:commonName "somefqdn.de",
:duration "2160h",
:renewBefore "720h",
:dnsNames ["somefqdn.de"],
:issuerRef {:name "staging", :kind "ClusterIssuer"}}}
{:apiVersion "networking.k8s.io/v1",
:kind "Ingress",
:metadata
{:name "cloud-service",
:namespace "default",
:labels {:app.kubernetes.part-of "cloud-service"},
:annotations
{:traefik.ingress.kubernetes.io/router.entrypoints "web, websecure",
:traefik.ingress.kubernetes.io/router.middlewares
"default-redirect-https@kubernetescrd",
:metallb.universe.tf/address-pool "public"}},
:spec
{:tls [{:hosts ["somefqdn.de"], :secretName "cloud-service"}],
:rules
[{:host "somefqdn.de",
:http
{:paths
[{:pathType "Prefix",
:path "/",
:backend
{:service {:name "cloud-service", :port {:number 80}}}}]}}]}}]
(cut/generate-ingress-and-cert {:fqdn "somefqdn.de"}))))
(deftest should-generate-pvc
(is (= {:apiVersion "v1"
:kind "PersistentVolumeClaim"
:metadata {:name "cloud-pvc"
:namespace "nextcloud"
:labels {:app.kubernetes.io/application "cloud"}}
:spec {:storageClassName "local-path"
:accessModes ["ReadWriteOnce"]
:resources {:requests {:storage "50Gi"}}}}
(cut/generate-pvc {:pv-storage-size-gb 50 :pvc-storage-class-name "local-path"}))))
(deftest should-generate-deployment
(is (= {:apiVersion "apps/v1"
:kind "Deployment"
:metadata {:name "cloud-deployment"}
:metadata {:name "cloud-deployment", :namespace "nextcloud"}
:spec
{:selector {:matchLabels #:app.kubernetes.io{:name "cloud-pod", :application "cloud"}}
:strategy {:type "Recreate"}
:template
{:metadata {:labels {:app.kubernetes.io/name "cloud-pod", :app.kubernetes.io/application "cloud", :redeploy "v3"}}
{:metadata {:labels {:app "cloud-app", :app.kubernetes.io/name "cloud-pod", :app.kubernetes.io/application "cloud", :redeploy "v3"}}
:spec
{:containers
[{:image "domaindrivenarchitecture/c4k-cloud"
[{:image "domaindrivenarchitecture/c4k-cloud:8.0.0"
:name "cloud-app"
:imagePullPolicy "IfNotPresent"
:ports [{:containerPort 80}]
@ -93,11 +111,11 @@
[{:name "NEXTCLOUD_ADMIN_USER", :valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-user"}}}
{:name "NEXTCLOUD_ADMIN_PASSWORD"
:valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-password"}}}
{:name "NEXTCLOUD_TRUSTED_DOMAINS", :value "xx"}
{:name "NEXTCLOUD_TRUSTED_DOMAINS", :value "somefqdn.de"}
{:name "POSTGRES_USER", :valueFrom {:secretKeyRef {:name "postgres-secret", :key "postgres-user"}}}
{:name "POSTGRES_PASSWORD", :valueFrom {:secretKeyRef {:name "postgres-secret", :key "postgres-password"}}}
{:name "POSTGRES_DB", :valueFrom {:configMapKeyRef {:name "postgres-config", :key "postgres-db"}}}
{:name "POSTGRES_HOST", :value "postgresql-service:5432"}]
:volumeMounts [{:name "cloud-data-volume", :mountPath "/var/www/html"}]}]
:volumes [{:name "cloud-data-volume", :persistentVolumeClaim {:claimName "cloud-pvc"}}]}}}}
(cut/generate-deployment {:fqdn "xx"}))))
(cut/generate-deployment {:fqdn "somefqdn.de"}))))

@ -0,0 +1,7 @@
postgres-db-user: "nextcloud"
postgres-db-password: "nextcloud-db-password"
nextcloud-admin-user: "cloudadmin"
nextcloud-admin-password: "cloudpassword"
aws-accss-key-id: "aws-id"
aws-secret-access-key: "aws-secret"
restic-password: "restic-password"

@ -0,0 +1,5 @@
fqdns: "cloud.test.meissa-gmbh.de"
issuer: "none"
nextcloud-data-volume-path: "/var/cloud"
postgres-data-volume-path: "/var/postgres"
restic-repository: "s3:s3.amazonaws.com/your-bucket/your-folder"

@ -0,0 +1,10 @@
postgres-db-user: "nextcloud"
postgres-db-password: "nextcloud-db-password"
nextcloud-admin-user: "cloudadmin"
nextcloud-admin-password: "cloudpassword"
aws-access-key-id: "aws-id"
aws-secret-access-key: "aws-secret"
restic-password: "restic-password"
mon-auth:
grafana-cloud-user: "user"
grafana-cloud-password: "password"

@ -0,0 +1,9 @@
fqdn: "cloud.test.meissa-gmbh.de"
issuer: "staging"
nextcloud-data-volume-path: "/var/cloud"
postgres-data-volume-path: "/var/postgres"
restic-repository: "s3:s3.amazonaws.com/your-bucket/your-folder"
mon-cfg:
grafana-cloud-url: "url-for-your-prom-remote-write-endpoint"
cluster-name: "keycloak"
cluster-stage: "test"

@ -1,7 +0,0 @@
{:postgres-db-user "nextcloud"
:postgres-db-password "nextcloud-db-password"
:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"
:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-password"}

@ -1,5 +0,0 @@
{:fqdn "cloud.test.meissa-gmbh.de"
:issuer :staging
:nextcloud-data-volume-path "/var/cloud"
:postgres-data-volume-path "/var/postgres"
:restic-repository "s3:s3.amazonaws.com/your-bucket/your-folder"}
Loading…
Cancel
Save