Compare commits

...

79 commits
10.0.0 ... main

Author SHA1 Message Date
f8905804a3 bump version to: 10.5.4-SNAPSHOT 2025-01-30 14:02:43 +01:00
86a60f5077 release: 10.5.3 2025-01-30 14:02:43 +01:00
8bff19048b fmt 2025-01-30 13:58:13 +01:00
dfc3480cb8 add closing bracket to js 2025-01-30 13:38:09 +01:00
fc6131fecd format 2025-01-30 12:51:49 +01:00
6383b2070f bump version to: 10.5.3-SNAPSHOT 2025-01-30 10:19:06 +01:00
96cad6d063 release: 10.5.2 2025-01-30 10:19:06 +01:00
218074027d fix default config for js 2025-01-30 10:14:36 +01:00
edd0e14cae moved backup process 2025-01-24 15:06:00 +01:00
3deabdf223 bump version to: 10.5.2-SNAPSHOT 2025-01-23 16:40:25 +01:00
4080415640 release: 10.5.1 2025-01-23 16:40:25 +01:00
8bf97fb5c6 fix tests 2025-01-21 13:02:30 +01:00
e4e2878eb1 add the missing config.edn 2025-01-17 16:26:26 +01:00
080fda82f4 restic-pwd is auth 2025-01-14 12:56:23 +01:00
3bfcfa72c8 remove unused 2025-01-14 12:56:12 +01:00
bd0c808644 updates for doc / test 2025-01-13 16:02:12 +01:00
020d9559e1 bump version to: 10.5.1-SNAPSHOT 2025-01-13 13:59:09 +01:00
427532ab7e release: 10.5.0 2025-01-13 13:59:09 +01:00
1003aa7a27 backup: use config data instead of code 2025-01-13 13:50:45 +01:00
jem
6c7c38b25b Merge pull request 'password-rotation' (#3) from password-rotation into main
Reviewed-on: #3
2025-01-13 10:24:50 +00:00
d3f77e0f23 describe pw change process 2025-01-13 11:02:44 +01:00
d6dcf6d08d change password 2025-01-11 16:28:01 +01:00
91985c7bb7 Merge branch 'main' into password-rotation 2025-01-11 15:33:33 +01:00
6a04396984 bump version to: 10.4.5-SNAPSHOT 2025-01-11 15:13:18 +01:00
7b3143beca release: 10.4.4 2025-01-11 15:13:18 +01:00
a0e47d74fc fix browser 2025-01-11 15:11:44 +01:00
bd22b84a32 bump version to: 10.4.4-SNAPSHOT 2025-01-11 14:48:25 +01:00
a06409fadf release: 10.4.3 2025-01-11 14:48:25 +01:00
27987dfc8b refactor to fix spec location 2025-01-11 14:27:12 +01:00
051f152232 add restic-new password 2025-01-11 13:32:09 +01:00
b22ace7c6a update version 2025-01-11 13:17:10 +01:00
ad16cb52bd bump version to: 10.4.3-SNAPSHOT 2025-01-11 11:36:12 +01:00
58eccda7a7 release: 10.4.2 2025-01-11 11:36:12 +01:00
242ebdc2ff cleanup image & update test 2025-01-11 11:32:17 +01:00
5f69b54f15 use newest version 2025-01-11 11:07:43 +01:00
78af31036e fix config 2025-01-11 11:07:17 +01:00
1c596889ad fine grained restore config 2025-01-10 08:34:59 +01:00
2aec56fbd6 one step back - ubuntu24 does not contain pg17 2025-01-09 20:19:38 +01:00
d748a36559 adjust doc 2025-01-09 20:10:18 +01:00
71bd701d13 bump version to: 10.4.2-SNAPSHOT 2025-01-09 18:53:22 +01:00
d489eee954 release: 10.4.1 2025-01-09 18:53:22 +01:00
939523bc2e use new nextcloud 2025-01-09 18:34:31 +01:00
29fc04830a adjust upgrade doc 2025-01-09 15:15:57 +01:00
0b9739fdb6 bump version to: 10.4.1-SNAPSHOT 2025-01-09 14:21:29 +01:00
164b691bc9 release: 10.4.0 2025-01-09 14:21:28 +01:00
9685f07e46 bump version to: 10.3.1-SNAPSHOT 2025-01-09 14:07:56 +01:00
6e1cc7bda2 release: 10.3.0 2025-01-09 14:07:56 +01:00
304bb3c967 update dep 2025-01-09 14:03:43 +01:00
jem
e26d67a40c Merge pull request 'refactor for new backup' (#1) from new-backup into main
Reviewed-on: #1
2025-01-09 12:58:39 +00:00
8cb6bf6b28 Merge branch 'main' into new-backup 2025-01-09 13:35:41 +01:00
jem
9fc9687a08 Merge pull request 'feat: upgrade-and-fix-postgres' (#2) from upgrade-and-fix-postgres into main
Reviewed-on: #2
2025-01-09 12:11:44 +00:00
20c66235c0 upgrade nextcloud 2025-01-09 12:55:51 +01:00
741b720632 upgrade versions 2025-01-09 12:55:40 +01:00
394959d158 update db 2025-01-09 12:54:27 +01:00
711ceecefc upgrade versions 2025-01-09 09:24:46 +01:00
dad69a180b versions update 2025-01-08 16:52:21 +01:00
6de3e47bd2 update refactoring 2024-12-31 11:09:22 +01:00
03b0b85247 refactor to babashka driven backup 2024-12-30 14:21:27 +01:00
67ec0f58eb implement backup & snapshot 2024-12-28 18:30:49 +01:00
d7ce373d87 refactoring - split config & auth 2024-12-28 09:59:43 +01:00
d1a8479598 update federation 2024-08-05 08:57:40 +02:00
c4832b1107 remove unused 2024-06-07 17:19:07 +02:00
7e3312e285 switch to main 2024-05-31 17:17:16 +02:00
f636f7ffc3 update deps 2024-05-31 17:17:07 +02:00
bba6bbe830 bump version to: 10.2.1-SNAPSHOT 2024-05-31 17:03:56 +02:00
8388d72517 release: 10.2.0 2024-05-31 17:03:56 +02:00
f2b583c060 adjust version 2024-05-31 16:58:27 +02:00
5a3aca38cf use new fkt 2024-05-31 16:48:33 +02:00
4764d1db67 use the new pcv defaults 2024-05-31 16:43:06 +02:00
8aef785bdc reenable lint & native build 2024-05-31 16:42:51 +02:00
5eb83f78a0 update deps 2024-05-31 16:14:26 +02:00
d997e470a0 remove integration tests 2024-05-31 16:14:12 +02:00
bom
dc86531454 Fix default storage class
Our default was not actually valid
2024-05-17 15:15:16 +02:00
ca0d4ac7b2 add the upgrade experience 2024-04-26 15:38:28 +02:00
bom
e4666a592e bump version to: 10.1.1-SNAPSHOT 2024-04-26 14:53:08 +02:00
bom
fa48d9762a release: 10.1.0 2024-04-26 14:53:08 +02:00
bom
6a278ece0d Upgrade nextcloud 2024-04-26 14:52:19 +02:00
dda45d92d6 update instructions 2024-04-26 13:07:05 +02:00
bom
c69c9da659 bump version to: 10.0.1-SNAPSHOT 2024-04-26 10:27:14 +02:00
67 changed files with 604 additions and 1136 deletions

6
.gitignore vendored
View file

@ -22,12 +22,6 @@ logs/
*.iml *.iml
.idea/ .idea/
# config files
my-auth.edn
my-config.edn
auth.edn
config.edn
# certificate # certificate
ca.crt ca.crt

View file

@ -4,7 +4,6 @@ stages:
- security - security
- upload - upload
- image - image
#- integrationtest
.img: &img .img: &img
image: "domaindrivenarchitecture/ddadevops-dind:4.11.3" image: "domaindrivenarchitecture/ddadevops-dind:4.11.3"
@ -130,23 +129,3 @@ nextcloud-image-publish:
stage: image stage: image
script: script:
- cd infrastructure/nextcloud && pyb image publish - cd infrastructure/nextcloud && pyb image publish
#.nextcloud-integrationtest:
# stage: integrationtest
# image: registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/3.7.1-kube-1.20.11-alpine-3.14
# services:
# - name: registry.gitlab.com/gitlab-org/cluster-integration/test-utils/k3s-gitlab-ci/releases/v1.22.2-k3s2
# alias: k3s
# script:
# - apk add curl sudo bash
# - apk add wget curl bash sudo openjdk8
# - wget -P /etc/apk/keys/ https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
# - apk add --no-cache --repository=https://apkproxy.herokuapp.com/sgerrand/alpine-pkg-leiningen leiningen
#
# - mkdir -p ${HOME}/.kube/
# - curl -f k3s:8081 > ${HOME}/.kube/config
# - kubectl version
# - kubectl cluster-info
# - echo "---------- Integration test -------------"
# - pwd
# - cd ./src/test/resources/local-integration-test/ && ./setup-local-s3-on-k3d.sh

View file

@ -41,7 +41,8 @@ Development happens at: https://repo.prod.meissa.de/meissa/c4k-nextcloud
Mirrors are: Mirrors are:
* https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud (issues and PR, CI) * https://codeberg.org/meissa/c4k-nextcloud (Issues and PR)
* https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud (CI)
* https://github.com/DomainDrivenArchitecture/c4k-nextcloud * https://github.com/DomainDrivenArchitecture/c4k-nextcloud
For more details about our repository model see: https://repo.prod.meissa.de/meissa/federate-your-repos For more details about our repository model see: https://repo.prod.meissa.de/meissa/federate-your-repos
@ -49,6 +50,6 @@ For more details about our repository model see: https://repo.prod.meissa.de/mei
## License ## License
Copyright © 2021 meissa GmbH Copyright © 2021, 2022, 2023, 2024 meissa GmbH
Licensed under the [Apache License, Version 2.0](LICENSE) (the "License") 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)

View file

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

View file

@ -33,7 +33,7 @@ def initialize(project):
f"target/uberjar/{name}-standalone.jar", f"target/uberjar/{name}-standalone.jar",
f"target/frontend-build/{name}.js", f"target/frontend-build/{name}.js",
], ],
"release_main_branch": "master", "release_main_branch": "main",
} }
build = ReleaseMixin(project, input) build = ReleaseMixin(project, input)
@ -153,11 +153,11 @@ def upload_clj(project):
@task @task
def lint(project): def lint(project):
#run( run(
# "lein eastwood", "lein eastwood",
# shell=True, shell=True,
# check=True, check=True,
#) )
run( run(
"lein ancient check", "lein ancient check",
shell=True, shell=True,
@ -167,17 +167,17 @@ def lint(project):
@task @task
def inst(project): def inst(project):
package_uberjar(project) package_uberjar(project)
# package_native(project) package_native(project)
run( run(
f"sudo install -m=755 target/uberjar/{project.name}-standalone.jar /usr/local/bin/{project.name}-standalone.jar", f"sudo install -m=755 target/uberjar/{project.name}-standalone.jar /usr/local/bin/{project.name}-standalone.jar",
shell=True, shell=True,
check=True, check=True,
) )
# run( run(
# f"sudo install -m=755 target/graalvm/{project.name} /usr/local/bin/{project.name}", f"sudo install -m=755 target/graalvm/{project.name} /usr/local/bin/{project.name}",
# shell=True, shell=True,
# check=True, check=True,
# ) )
@task @task

View file

@ -1,6 +0,0 @@
{:fqdn "cloudhost"
:issuer :staging
:nextcloud-data-volume-path "/var/cloud"
:postgres-data-volume-path "/var/postgres"
:restic-repository "s3://k3stesthost/mybucket"
:local-integration-test true}

View file

@ -1,46 +1,8 @@
# Backup Architecture details # Backup Architecture details
![](backup.svg) Use process documented at https://repo.prod.meissa.de/meissa/dda-backup/src/branch/main/docs/Backup.md
* we use restic to produce small & encrypted backups Parameters are:
* 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. **deployment-name**: none - deployment must not be scaled down.
2. **deployment-namespace**: nextcloud
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 the restic repository for the first time
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`

View file

@ -5,15 +5,18 @@
- 4.0.3: nextcloud 22 - 4.0.3: nextcloud 22
- 5.0.0: nextcloud 23 - 5.0.0: nextcloud 23
- 6.0.0: nextcloud 24 - 6.0.0: nextcloud 24
- 7.0.0: nextcloud 25 - 7.0.7: nextcloud 25.0.13
- 7.1.0: nextcloud 26 (manual publish) - 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) - 7.2.0: nextcloud 27 (manual publish)
- 8.0.6: nextcloud 28 - 10.0.0: nextcloud 28.0.5
- 10.1.0: nextcloud 29.0.0
- 10.4.2: nextcloud 30
## Uprgrading process ## Uprgrading process
1. Change the version of the docker image in the deployment to the next major version 1. Change the version of the docker image in the deployment to the next major version
- `kubectl edit deploy cloud-deployment` - `kubectl -n=nextcloud edit deploy cloud-deployment`
- change `image: domaindrivenarchitecture/c4k-cloud:4.0.3` - change `image: domaindrivenarchitecture/c4k-cloud:4.0.3`
2. Wait for the pod to finish restarting 2. Wait for the pod to finish restarting
3. Verify the website is working and https://URL/settings/admin/overview shows the correct version 3. Verify the website is working and https://URL/settings/admin/overview shows the correct version

View file

@ -1,294 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 144 KiB

View file

@ -6,7 +6,7 @@ from ddadevops import *
name = "c4k-cloud" name = "c4k-cloud"
MODULE = "backup" MODULE = "backup"
PROJECT_ROOT_PATH = "../.." PROJECT_ROOT_PATH = "../.."
version = "10.0.0" version = "10.5.4-dev"
@init @init

View file

@ -1,5 +1,7 @@
FROM domaindrivenarchitecture/dda-backup:latest FROM domaindrivenarchitecture/dda-backup:5.3.0
# Prepare Entrypoint Script # Prepare Entrypoint Script
ADD resources /tmp ADD resources /tmp
RUN /tmp/install.sh RUN /tmp/install.bb
RUN init.bb
#ADD resources2 /tmp

View file

@ -0,0 +1,34 @@
#!/usr/bin/env bb
(require
'[babashka.tasks :as t]
'[dda.backup.core :as bc]
'[dda.backup.config :as cfg]
'[dda.backup.restic :as rc]
'[dda.backup.postgresql :as pg]
'[dda.backup.backup :as bak])
(def config (cfg/read-config "/usr/local/bin/config.edn"))
(defn prepare!
[]
(bc/create-aws-credentials! (:aws-config config))
(pg/create-pg-pass! (:db-config config)))
(defn restic-repo-init!
[]
(rc/init! (:file-config config))
(rc/init! (:db-role-config config))
(rc/init! (:db-config config)))
(defn restic-backup!
[]
(bak/backup-file! (:file-config config))
(bak/backup-db-roles! (:db-role-config config))
(bak/backup-db! (:db-config config)))
(t/shell "start-maintenance.sh")
(prepare!)
(restic-repo-init!)
(restic-backup!)
(t/shell "end-maintenance.sh")

View file

@ -1,28 +0,0 @@
#!/bin/bash
set -Eexo pipefail
function main() {
start-maintenance.sh
file_env AWS_ACCESS_KEY_ID
file_env AWS_SECRET_ACCESS_KEY
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD
file_env POSTGRES_USER
file_env RESTIC_DAYS_TO_KEEP 30
file_env RESTIC_MONTHS_TO_KEEP 12
backup-roles 'oc_'
backup-db-dump
backup-directory '/var/backups/'
end-maintenance.sh
}
source /usr/local/lib/functions.sh
source /usr/local/lib/pg-functions.sh
source /usr/local/lib/file-functions.sh
main

View file

@ -0,0 +1,4 @@
{:deps {org.clojure/spec.alpha {:mvn/version "0.4.233"}
orchestra/orchestra {:mvn/version "2021.01.01-1"}
aero/aero {:mvn/version "1.1.6"}
org.domaindrivenarchitecture/dda-backup {:local/root "/usr/local/lib/dda-backup"}}}

View file

@ -0,0 +1,3 @@
{:deps {org.clojure/spec.alpha {:mvn/version "0.4.233"}
orchestra/orchestra {:mvn/version "2021.01.01-1"}
org.domaindrivenarchitecture/dda-build {:mvn/version "0.2.0"}}}

View file

@ -0,0 +1,27 @@
#!/usr/bin/env bb
(require
'[dda.backup.core :as bc]
'[dda.backup.config :as cfg]
'[dda.backup.restic :as rc])
(def config (cfg/read-config "/usr/local/bin/config.edn"))
(def file-pw-change-config (merge (:file-config config)
{:new-password-file (bc/env-or-file "RESTIC_NEW_PASSWORD_FILE")}))
(def db-role-pw-change-config (merge (:db-role-config config)
{:new-password-file (bc/env-or-file "RESTIC_NEW_PASSWORD_FILE")}))
(def db-pw-change-config (merge (:db-config config)
{:new-password-file (bc/env-or-file "RESTIC_NEW_PASSWORD_FILE")}))
(defn prepare!
[]
(bc/create-aws-credentials! (:aws-config config)))
(defn change-password!
[]
(rc/change-password! file-pw-change-config)
(rc/change-password! db-pw-change-config)
(rc/change-password! db-role-pw-change-config))
(prepare!)
(change-password!)

View file

@ -0,0 +1,59 @@
{:restic-repo {:password-file #env-or-file "RESTIC_PASSWORD_FILE"
:restic-repository #env-or-file "RESTIC_REPOSITORY"}
:file-config #merge [#ref [:restic-repo]
{:backup-path "files"
:execution-directory "/var/backups"
:restore-target-directory "/var/backups/"
:files ["."]}]
:file-restore-config #merge [#ref [:restic-repo]
{:backup-path "files"
:restore-target-directory "/var/backups/"
:clean-up-elements [".htaccess"
".reuse/"
".user.ini"
"3rdparty/"
"apps/"
"composer.json"
"composer.lock"
"console.php"
"core/"
"cron.php"
"custom_apps/"
"data/"
"dist/"
"index.html"
"index.php"
"lib/"
"ocs/"
"ocs-provider/"
"package-lock.json"
"package.json"
"public.php"
"remote.php"
"resources"
"robots.txt"
"status.php"
"themes/"
"version.php"]}]
:db-config #merge [#ref [:restic-repo] {:backup-path "pg-database"
:pg-host #env-or-file "POSTGRES_SERVICE"
:pg-port #env-or-file "POSTGRES_PORT"
:pg-db #env-or-file "POSTGRES_DB"
:pg-user #env-or-file "POSTGRES_USER"
:pg-password #env-or-file "POSTGRES_PASSWORD"}]
:db-role-config #merge [#ref [:restic-repo] {:backup-path "pg-role"
:pg-role-prefix "oc_"
:pg-host #env-or-file "POSTGRES_SERVICE"
:pg-port #env-or-file "POSTGRES_PORT"
:pg-db #env-or-file "POSTGRES_DB"
:pg-user #env-or-file "POSTGRES_USER"
:pg-password #env-or-file "POSTGRES_PASSWORD"}]
:aws-config {:aws-access-key-id #env-or-file "AWS_ACCESS_KEY_ID"
:aws-secret-access-key #env-or-file "AWS_SECRET_ACCESS_KEY"}
:dry-run {:dry-run true :debug true}}

View file

@ -1,19 +0,0 @@
#!/bin/bash
set -exo pipefail
function main() {
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD
file_env POSTGRES_USER
create-pg-pass
while true; do
sleep 1m
done
}
source /usr/local/lib/functions.sh
source /usr/local/lib/pg-functions.sh
main

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -Eexo pipefail
function main() {
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD
file_env POSTGRES_USER
create-pg-pass
/usr/local/bin/backup.sh
}
source /usr/local/lib/functions.sh
source /usr/local/lib/pg-functions.sh
main

View file

@ -0,0 +1,3 @@
#!/usr/bin/env bb
(println "initialized")

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -Eexo pipefail
function main() {
file_env AWS_ACCESS_KEY_ID
file_env AWS_SECRET_ACCESS_KEY
init-role-repo
init-database-repo
init-file-repo
}
source /usr/local/lib/functions.sh
source /usr/local/lib/pg-functions.sh
source /usr/local/lib/file-functions.sh
main

View file

@ -0,0 +1,20 @@
#!/usr/bin/env bb
(require
'[dda.image.ubuntu :as ub]
'[dda.image.install :as in])
(ub/upgrade-system!)
(in/install! "bb-backup.edn" :target-name "bb.edn" :mod "0440")
(in/install! "config.edn" :mod "0440")
(in/install! "init.bb")
(in/install! "backup.bb")
(in/install! "restore.bb")
(in/install! "list-snapshots.bb")
(in/install! "change-password.bb")
(in/install! "start-maintenance.sh")
(in/install! "end-maintenance.sh")
(in/install! "restore.bb")
(in/install! "wait.bb")
(ub/cleanup-container!)

View file

@ -1,21 +0,0 @@
#!/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

View file

@ -0,0 +1,21 @@
#!/usr/bin/env bb
(require
'[dda.backup.core :as bc]
'[dda.backup.config :as cfg]
'[dda.backup.restic :as rc])
(def config (cfg/read-config "/usr/local/bin/config.edn"))
(defn prepare!
[]
(bc/create-aws-credentials! (:aws-config config)))
(defn list-snapshots!
[]
(rc/list-snapshots! (:file-config config))
(rc/list-snapshots! (:db-role-config config))
(rc/list-snapshots! (:db-config config)))
(prepare!)
(list-snapshots!)

View file

@ -1,31 +0,0 @@
#!/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

View file

@ -0,0 +1,26 @@
#!/usr/bin/env bb
(require
'[babashka.tasks :as t]
'[dda.backup.core :as bc]
'[dda.backup.config :as cfg]
'[dda.backup.postgresql :as pg]
'[dda.backup.restore :as rs])
(def config (cfg/read-config "/usr/local/bin/config.edn"))
(defn prepare!
[]
(bc/create-aws-credentials! (:aws-config config))
(pg/create-pg-pass! (:db-config config)))
(defn restic-restore!
[]
(pg/drop-create-db! (:db-config config))
(rs/restore-db-roles! (:db-role-config config))
(rs/restore-db! (:db-config config))
(rs/restore-file! (:file-restore-config config)))
(t/shell "start-maintenance.sh")
(prepare!)
(restic-restore!)
(t/shell "end-maintenance.sh")

View file

@ -1,33 +0,0 @@
#!/bin/bash
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
file_env AWS_ACCESS_KEY_ID
file_env AWS_SECRET_ACCESS_KEY
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD
file_env POSTGRES_USER
drop-create-db
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 "$@"

View file

@ -0,0 +1,19 @@
#!/usr/bin/env bb
(require
'[dda.backup.core :as bc]
'[dda.backup.config :as cfg]
'[dda.backup.postgresql :as pg])
(def config (cfg/read-config "/usr/local/bin/config.edn"))
(defn prepare!
[]
(bc/create-aws-credentials! (:aws-config config))
(pg/create-pg-pass! (:db-config config)))
(defn wait! []
(while true
(Thread/sleep 1000)))
(prepare!)
(wait!)

View file

@ -0,0 +1,3 @@
{:deps {org.clojure/spec.alpha {:mvn/version "0.4.233"}
orchestra/orchestra {:mvn/version "2021.01.01-1"}
org.domaindrivenarchitecture/dda-backup {:local/root "/usr/local/lib/dda-backup"}}}

View file

@ -0,0 +1,9 @@
export RESTIC_PASSWORD_FILE=/tmp/file_password
export RESTIC_REPOSITORY=/var/restic-repo
export POSTGRES_SERVICE=dummy
export POSTGRES_PORT=dummy
export POSTGRES_DB=dummy
export POSTGRES_USER=dummy
export POSTGRES_PASSWORD=dummy
export AWS_ACCESS_KEY_ID=dummy
export AWS_SECRET_ACCESS_KEY=dummy

View file

@ -0,0 +1 @@
oldPassword

View file

@ -0,0 +1,51 @@
#!/usr/bin/env bb
(require
'[babashka.fs :as fs])
(-> "/usr/local/bin/config.clj" fs/file load-file)
(require '[babashka.tasks :as tasks]
'[dda.backup.core :as bc]
'[dda.backup.restic :as rc]
'[dda.backup.postgresql :as pg]
'[dda.backup.backup :as bak]
'[dda.backup.restore :as rs]
'[config :as cf])
(defn prepare!
[]
(tasks/shell "mkdir" "-p" "/var/backups/")
(tasks/shell "mkdir" "-p" "/var/restic-repo/")
(spit "/var/backups/file" "I was here"))
(defn restic-repo-init!
[]
(rc/init! cf/file-config)
(rc/init! (merge cf/db-role-config cf/dry-run))
(rc/init! (merge cf/db-config cf/dry-run)))
(defn restic-backup!
[]
(bak/backup-file! cf/file-config)
(bak/backup-db-roles! (merge cf/db-role-config cf/dry-run))
(bak/backup-db! (merge cf/db-config cf/dry-run)))
(defn list-snapshots!
[]
(rc/list-snapshots! cf/file-config)
(rc/list-snapshots! (merge cf/db-role-config cf/dry-run))
(rc/list-snapshots! (merge cf/db-config cf/dry-run)))
(defn restic-restore!
[]
(pg/drop-create-db! (merge cf/db-config cf/dry-run))
(rs/restore-db-roles! (merge cf/db-role-config cf/dry-run))
(rs/restore-db! (merge cf/db-config cf/dry-run))
(rs/restore-file! cf/file-restore-config))
(prepare!)
(restic-repo-init!)
(restic-backup!)
(list-snapshots!)
(restic-restore!)

View file

@ -0,0 +1,4 @@
FROM c4k-cloud-backup:latest
ADD resources /tmp/
RUN RESTIC_PASSWORD_FILE=/tmp/file_password RESTIC_NEW_PASSWORD_FILE=/tmp/new_file_password RESTIC_REPOSITORY=restic-repo POSTGRES_SERVICE=dummy POSTGRES_PORT=dummy POSTGRES_DB=dummy POSTGRES_USER=dummy POSTGRES_PASSWORD=dummy AWS_ACCESS_KEY_ID=dummy AWS_SECRET_ACCESS_KEY=dummy /tmp/test.bb

View file

@ -0,0 +1,4 @@
{:deps {org.clojure/spec.alpha {:mvn/version "0.4.233"}
orchestra/orchestra {:mvn/version "2021.01.01-1"}
aero/aero {:mvn/version "1.1.6"}
org.domaindrivenarchitecture/dda-backup {:local/root "/usr/local/lib/dda-backup"}}}

View file

@ -0,0 +1 @@
oldPassword

View file

@ -0,0 +1 @@
newPassword

View file

@ -0,0 +1,67 @@
#!/usr/bin/env bb
(require '[babashka.tasks :as tasks]
'[dda.backup.core :as bc]
'[dda.backup.config :as cfg]
'[dda.backup.restic :as rc]
'[dda.backup.postgresql :as pg]
'[dda.backup.backup :as bak]
'[dda.backup.restore :as rs])
(def config (cfg/read-config "/usr/local/bin/config.edn"))
(def file-pw-change-config (merge (:file-config config)
{:new-password-file (bc/env-or-file "RESTIC_NEW_PASSWORD_FILE")}))
(defn prepare!
[]
(tasks/shell "mkdir" "-p" "/var/backups/")
(spit "/var/backups/file" "I was here")
(tasks/shell "mkdir" "-p" "/var/restore"))
(defn restic-repo-init!
[]
(rc/init! (:file-config config))
(rc/init! (merge (:db-role-config config)
(:dry-run config)))
(rc/init! (merge (:db-config config)
(:dry-run config))))
(defn restic-backup!
[]
(bak/backup-file! (:file-config config))
(bak/backup-db-roles! (merge (:db-role-config config)
(:dry-run config)))
(bak/backup-db! (merge (:db-config config)
(:dry-run config))))
(defn list-snapshots!
[]
(rc/list-snapshots! (:file-config config))
(rc/list-snapshots! (merge (:db-role-config config)
(:dry-run config)))
(rc/list-snapshots! (merge (:db-config config)
(:dry-run config))))
(defn restic-restore!
[]
(pg/drop-create-db! (merge (:db-config config)
(:dry-run config)))
(rs/restore-db-roles! (merge (:db-role-config config)
(:dry-run config)))
(rs/restore-db! (merge (:db-config config)
(:dry-run config)))
(rs/restore-file! (merge (:file-restore-config config)
(:dry-run config))))
(defn change-password!
[]
(println "change-password!")
(rc/change-password! file-pw-change-config))
(prepare!)
(restic-repo-init!)
(restic-backup!)
(list-snapshots!)
(restic-restore!)
(change-password!)

View file

@ -6,7 +6,7 @@ from ddadevops import *
name = 'c4k-cloud' name = 'c4k-cloud'
MODULE = 'not_set' MODULE = 'not_set'
PROJECT_ROOT_PATH = '../..' PROJECT_ROOT_PATH = '../..'
version = "10.0.0" version = "10.5.4-dev"
@init @init
def initialize(project): def initialize(project):

View file

@ -1,4 +1,4 @@
FROM nextcloud:28 FROM nextcloud:30
# REQUIRES docker >= 2.10.10 # REQUIRES docker >= 2.10.10
# https://docs.docker.com/engine/release-notes/20.10/#201010 # https://docs.docker.com/engine/release-notes/20.10/#201010

View file

@ -2,7 +2,7 @@
"name": "c4k-nextcloud", "name": "c4k-nextcloud",
"description": "Generate c4k yaml for a nextcloud deployment.", "description": "Generate c4k yaml for a nextcloud deployment.",
"author": "meissa GmbH", "author": "meissa GmbH",
"version": "10.0.0", "version": "10.5.4-SNAPSHOT",
"homepage": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud#readme", "homepage": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud#readme",
"repository": "https://www.npmjs.com/package/c4k-nextcloud", "repository": "https://www.npmjs.com/package/c4k-nextcloud",
"license": "APACHE2", "license": "APACHE2",
@ -23,11 +23,11 @@
"url": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/issues" "url": "https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/issues"
}, },
"dependencies": { "dependencies": {
"js-base64": "^3.6.1", "js-base64": "^3.7.7",
"js-yaml": "^4.0.0" "js-yaml": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"shadow-cljs": "^2.11.18", "shadow-cljs": "^2.28.20",
"source-map-support": "^0.5.19" "source-map-support": "^0.5.21"
} }
} }

View file

@ -1,11 +1,11 @@
(defproject org.domaindrivenarchitecture/c4k-nextcloud "10.0.0" (defproject org.domaindrivenarchitecture/c4k-nextcloud "10.5.4-SNAPSHOT"
:description "nextcloud c4k-installation package" :description "nextcloud c4k-installation package"
:url "https://domaindrivenarchitecture.org" :url "https://domaindrivenarchitecture.org"
:license {:name "Apache License, Version 2.0" :license {:name "Apache License, Version 2.0"
:url "https://www.apache.org/licenses/LICENSE-2.0.html"} :url "https://www.apache.org/licenses/LICENSE-2.0.html"}
:dependencies [[org.clojure/clojure "1.11.3"] :dependencies [[org.clojure/clojure "1.12.0"]
[org.clojure/tools.reader "1.4.2"] [org.clojure/tools.reader "1.5.0"]
[org.domaindrivenarchitecture/c4k-common-clj "6.2.3"] [org.domaindrivenarchitecture/c4k-common-clj "9.0.1"]
[hickory "0.7.1" :exclusions [viebel/codox-klipse-theme]]] [hickory "0.7.1" :exclusions [viebel/codox-klipse-theme]]]
:target-path "target/%s/" :target-path "target/%s/"
:source-paths ["src/main/cljc" :source-paths ["src/main/cljc"
@ -23,9 +23,9 @@
:main dda.c4k-nextcloud.uberjar :main dda.c4k-nextcloud.uberjar
:uberjar-name "c4k-nextcloud-standalone.jar" :uberjar-name "c4k-nextcloud-standalone.jar"
:dependencies [[org.clojure/tools.cli "1.1.230"] :dependencies [[org.clojure/tools.cli "1.1.230"]
[ch.qos.logback/logback-classic "1.5.6" [ch.qos.logback/logback-classic "1.5.16"
:exclusions [com.sun.mail/javax.mail]] :exclusions [com.sun.mail/javax.mail]]
[org.slf4j/jcl-over-slf4j "2.0.13"] [org.slf4j/jcl-over-slf4j "2.0.16"]
[com.github.clj-easy/graal-build-time "1.0.5"]]}} [com.github.clj-easy/graal-build-time "1.0.5"]]}}
:release-tasks [["test"] :release-tasks [["test"]
["vcs" "assert-committed"] ["vcs" "assert-committed"]

View file

@ -4,7 +4,7 @@
"src/test/cljc" "src/test/cljc"
"src/test/cljs" "src/test/cljs"
"src/test/resources"] "src/test/resources"]
:dependencies [[org.domaindrivenarchitecture/c4k-common-cljs "6.2.3"] :dependencies [[org.domaindrivenarchitecture/c4k-common-cljs "9.0.1"]
[hickory "0.7.1"]] [hickory "0.7.1"]]
:builds {:frontend {:target :browser :builds {:frontend {:target :browser
:modules {:main {:init-fn dda.c4k-nextcloud.browser/init}} :modules {:main {:init-fn dda.c4k-nextcloud.browser/init}}

View file

@ -2,14 +2,14 @@
(:gen-class) (:gen-class)
(:require (:require
[dda.c4k-common.uberjar :as uberjar] [dda.c4k-common.uberjar :as uberjar]
[dda.c4k-nextcloud.nextcloud :as nextcloud]
[dda.c4k-nextcloud.core :as core])) [dda.c4k-nextcloud.core :as core]))
(defn -main [& cmd-args] (defn -main [& cmd-args]
(uberjar/main-common (uberjar/main-cm
"c4k-nextcloud" "c4k-nextcloud"
nextcloud/config? core/config?
nextcloud/auth? core/auth?
core/config-defaults core/config-defaults
core/k8s-objects core/config-objects
core/auth-objects
cmd-args)) cmd-args))

View file

@ -1,40 +1,52 @@
(ns dda.c4k-nextcloud.backup (ns dda.c4k-nextcloud.backup
(:require (:require
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
[dda.c4k-common.yaml :as yaml] #?(:clj [orchestra.core :refer [defn-spec]]
[dda.c4k-common.base64 :as b64] :cljs [orchestra.core :refer-macros [defn-spec]])
[dda.c4k-common.common :as cm] [dda.c4k-common.yaml :as yaml]
[dda.c4k-common.predicate :as cp] [dda.c4k-common.base64 :as b64]
#?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]]))) [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 cp/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 ::aws-secret-access-key cp/bash-env-string?)
(s/def ::restic-password cp/bash-env-string?) (s/def ::restic-password cp/bash-env-string?)
(s/def ::restic-new-password cp/bash-env-string?)
(s/def ::restic-repository cp/bash-env-string?) (s/def ::restic-repository cp/bash-env-string?)
(s/def ::config (s/keys :req-un [::restic-repository]))
(s/def ::auth (s/keys :req-un [::restic-password ::aws-access-key-id ::aws-secret-access-key]
:opt-un [::restic-new-password]))
#?(:cljs #?(:cljs
(defmethod yaml/load-resource :backup [resource-name] (defmethod yaml/load-resource :backup [resource-name]
(get (inline-resources "backup") resource-name))) (get (inline-resources "backup") resource-name)))
(defn generate-config [my-conf] (defn-spec generate-config map?
[my-conf ::config]
(let [{:keys [restic-repository]} my-conf] (let [{:keys [restic-repository]} my-conf]
(-> (->
(yaml/load-as-edn "backup/config.yaml") (yaml/load-as-edn "backup/config.yaml")
(cm/replace-key-value :restic-repository restic-repository)))) (cm/replace-key-value :restic-repository restic-repository))))
(defn generate-cron [] (defn-spec generate-cron map?
(yaml/from-string (yaml/load-resource "backup/cron.yaml"))) []
(yaml/from-string (yaml/load-resource "backup/cron.yaml")))
(defn generate-backup-restore-deployment [my-conf] (defn-spec generate-backup-restore-deployment map?
(let [backup-restore-yaml (yaml/load-as-edn "backup/backup-restore-deployment.yaml")] [conf ::config]
(if (and (contains? my-conf :local-integration-test) (= true (:local-integration-test my-conf))) (yaml/load-as-edn "backup/backup-restore-deployment.yaml"))
(cm/replace-named-value backup-restore-yaml "CERTIFICATE_FILE" "/var/run/secrets/localstack-secrets/ca.crt")
backup-restore-yaml)))
(defn generate-secret [my-auth] (defn-spec generate-secret map?
(let [{:keys [aws-access-key-id aws-secret-access-key restic-password]} my-auth] [auth ::auth]
(-> (let [{:keys [aws-access-key-id aws-secret-access-key
(yaml/load-as-edn "backup/secret.yaml") restic-password restic-new-password]} auth]
(cm/replace-key-value :aws-access-key-id (b64/encode aws-access-key-id)) (as-> (yaml/load-as-edn "backup/secret.yaml") res
(cm/replace-key-value :aws-secret-access-key (b64/encode aws-secret-access-key)) (cm/replace-key-value res :aws-access-key-id (b64/encode aws-access-key-id))
(cm/replace-key-value :restic-password (b64/encode restic-password))))) (cm/replace-key-value res :aws-secret-access-key (b64/encode aws-secret-access-key))
(cm/replace-key-value res :restic-password (b64/encode restic-password))
(if (contains? auth :restic-new-password)
(assoc-in res [:data :restic-new-password] (b64/encode restic-new-password))
res))))

View file

@ -1,45 +1,66 @@
(ns dda.c4k-nextcloud.core (ns dda.c4k-nextcloud.core
(:require (:require
#?(:clj [orchestra.core :refer [defn-spec]] [clojure.spec.alpha :as s]
:cljs [orchestra.core :refer-macros [defn-spec]]) #?(:clj [orchestra.core :refer [defn-spec]]
[dda.c4k-common.common :as cm] :cljs [orchestra.core :refer-macros [defn-spec]])
[dda.c4k-common.predicate :as cp] [dda.c4k-common.common :as cm]
[dda.c4k-common.yaml :as yaml] [dda.c4k-common.predicate :as cp]
[dda.c4k-common.postgres :as postgres] [dda.c4k-common.yaml :as yaml]
[dda.c4k-nextcloud.nextcloud :as nextcloud] [dda.c4k-common.postgres :as postgres]
[dda.c4k-nextcloud.backup :as backup] [dda.c4k-nextcloud.nextcloud :as nextcloud]
[dda.c4k-common.monitoring :as mon] [dda.c4k-nextcloud.backup :as backup]
[dda.c4k-common.namespace :as ns])) [dda.c4k-common.monitoring :as mon]
[dda.c4k-common.namespace :as ns]))
(def default-storage-class :local-path) (def config-defaults {:namespace "nextcloud"
:issuer "staging"
:pvc-storage-class-name "hcloud-volumes-encrypted"
:pv-storage-size-gb 200})
(def config-defaults {:issuer "staging"}) (def config? (s/merge ::nextcloud/config
::backup/config))
(defn-spec k8s-objects cp/map-or-seq? (def auth? (s/merge ::nextcloud/auth
[config nextcloud/config? ::backup/auth))
auth nextcloud/auth?]
(let [nextcloud-default-storage-config {:pvc-storage-class-name default-storage-class
:pv-storage-size-gb 200}] (defn-spec config-objects cp/map-or-seq?
[config config?]
(let [resolved-config (merge config-defaults config)]
(map yaml/to-string (map yaml/to-string
(filter (filter
#(not (nil? %)) #(not (nil? %))
(cm/concat-vec (cm/concat-vec
(ns/generate (merge {:namespace "nextcloud"} config)) (ns/generate resolved-config)
(postgres/generate {:postgres-size :8gb (postgres/generate-config (merge resolved-config {:postgres-image "postgres:16"
:db-name "cloud" :postgres-size :8gb
:pv-storage-size-gb 50 :db-name "cloud"
:pvc-storage-class-name default-storage-class :pv-storage-size-gb 50}))
:namespace "nextcloud"} [(nextcloud/generate-pvc resolved-config)
auth) (nextcloud/generate-deployment resolved-config)
[(nextcloud/generate-secret auth)
(nextcloud/generate-pvc (merge nextcloud-default-storage-config config))
(nextcloud/generate-deployment config)
(nextcloud/generate-service)] (nextcloud/generate-service)]
(nextcloud/generate-ingress-and-cert (merge {:namespace "nextcloud"} config)) (nextcloud/generate-ingress-and-cert resolved-config)
(when (:contains? config :restic-repository) (when (:contains? resolved-config :restic-repository)
[(backup/generate-config config) [(backup/generate-config resolved-config)
(backup/generate-secret auth)
(backup/generate-cron) (backup/generate-cron)
(backup/generate-backup-restore-deployment config)]) (backup/generate-backup-restore-deployment resolved-config)])
(when (:contains? config :mon-cfg) (when (:contains? resolved-config :mon-cfg)
(mon/generate (:mon-cfg config) (:mon-auth auth)))))))) (mon/generate-config)))))))
(defn-spec auth-objects cp/map-or-seq?
[config config?
auth auth?]
(let [resolved-config (merge config-defaults config)]
(map yaml/to-string
(filter
#(not (nil? %))
(cm/concat-vec
(postgres/generate-auth (merge resolved-config {:postgres-size :8gb
:db-name "cloud"
:pv-storage-size-gb 50})
auth)
[(nextcloud/generate-secret auth)]
(when (:contains? resolved-config :restic-repository)
[(backup/generate-secret auth)])
(when (:contains? resolved-config :mon-cfg)
(mon/generate-auth (:mon-cfg resolved-config) (:mon-auth auth))))))))

View file

@ -14,23 +14,20 @@
(s/def ::fqdn cp/fqdn-string?) (s/def ::fqdn cp/fqdn-string?)
(s/def ::issuer cp/letsencrypt-issuer?) (s/def ::issuer cp/letsencrypt-issuer?)
(s/def ::restic-repository string?)
(s/def ::nextcloud-admin-user cp/bash-env-string?) (s/def ::nextcloud-admin-user cp/bash-env-string?)
(s/def ::nextcloud-admin-password 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 ::pvc-storage-class-name cp/pvc-storage-class-name?)
(s/def ::pv-storage-size-gb pos?) (s/def ::pv-storage-size-gb pos?)
(def config? (s/keys :req-un [::fqdn] (s/def ::config (s/keys :req-un [::fqdn]
:opt-un [::issuer :opt-un [::issuer
::restic-repository
::pv-storage-size-gb ::pv-storage-size-gb
::pvc-storage-class-name ::pvc-storage-class-name
::mon/mon-cfg])) ::mon/mon-cfg]))
(def auth? (s/keys :req-un [::postgres/postgres-db-user ::postgres/postgres-db-password (s/def ::auth (s/keys :req-un [::postgres/postgres-db-user ::postgres/postgres-db-password
::nextcloud-admin-user ::nextcloud-admin-password ::nextcloud-admin-user ::nextcloud-admin-password
::aws-access-key-id ::aws-secret-access-key ::aws-access-key-id ::aws-secret-access-key]
::restic-password]
:opt-un [::mon/mon-auth])) :opt-un [::mon/mon-auth]))
#?(:cljs #?(:cljs
@ -38,13 +35,13 @@
(get (inline-resources "nextcloud") resource-name))) (get (inline-resources "nextcloud") resource-name)))
(defn-spec generate-deployment cp/map-or-seq? (defn-spec generate-deployment cp/map-or-seq?
[config config?] [config ::config]
(let [{:keys [fqdn]} config] (let [{:keys [fqdn]} config]
(-> (yaml/load-as-edn "nextcloud/deployment.yaml") (-> (yaml/load-as-edn "nextcloud/deployment.yaml")
(cm/replace-all-matching-values-by-new-value "fqdn" fqdn)))) (cm/replace-all-matching "fqdn" fqdn))))
(defn-spec generate-ingress-and-cert cp/map-or-seq? (defn-spec generate-ingress-and-cert cp/map-or-seq?
[config config?] [config ::config]
(ing/generate-ingress-and-cert (ing/generate-ingress-and-cert
(merge (merge
{:service-name "cloud-service" {:service-name "cloud-service"
@ -64,7 +61,7 @@
(yaml/load-as-edn "nextcloud/service.yaml")) (yaml/load-as-edn "nextcloud/service.yaml"))
(defn-spec generate-secret cp/map-or-seq? (defn-spec generate-secret cp/map-or-seq?
[auth auth?] [auth ::auth]
(let [{:keys [nextcloud-admin-user nextcloud-admin-password]} auth] (let [{:keys [nextcloud-admin-user nextcloud-admin-password]} auth]
(-> (->
(yaml/load-as-edn "nextcloud/secret.yaml") (yaml/load-as-edn "nextcloud/secret.yaml")

View file

@ -2,38 +2,42 @@
(:require (:require
[clojure.tools.reader.edn :as edn] [clojure.tools.reader.edn :as edn]
[dda.c4k-common.common :as cm] [dda.c4k-common.common :as cm]
[dda.c4k-common.monitoring :as mon]
[dda.c4k-nextcloud.core :as core] [dda.c4k-nextcloud.core :as core]
[dda.c4k-nextcloud.nextcloud :as nextcloud] [dda.c4k-common.browser :as br]))
[dda.c4k-common.browser :as br]
[dda.c4k-common.postgres :as pgc]))
(defn generate-content [] (defn generate-content []
(cm/concat-vec (cm/concat-vec
[(assoc [(assoc
(br/generate-needs-validation) :content (br/generate-needs-validation) :content
(cm/concat-vec (cm/concat-vec
(br/generate-group "domain" (br/generate-group
(cm/concat-vec (br/generate-input-field "fqdn" "Your fqdn:" "nextcloud-neu.prod.meissa-gmbh.de") "config"
(br/generate-input-field "issuer" "(Optional) Your issuer prod/staging:" "") (br/generate-text-area
(br/generate-input-field "pv-storage-size-gb" "(Optional) Your nextcloud storage size in GB" "8") "config" "Your config.edn:"
(br/generate-input-field "pvc-storage-class-name" "(Optional) Your storage class type (manual / local-path):" "local-path") "{:fqdn \"cloud.your.domain\"
(br/generate-input-field "postgres-data-volume-path" "(Optional) Your postgres-data-volume-path:" "/var/postgres") :issuer \"staging\"
(br/generate-input-field "restic-repository" "(Optional) Your restic-repository:" "restic-repository") :pv-storage-size-gb \"400\"
(br/generate-input-field "mon-cluster-name" "(Optional) monitoring cluster name:" "keycloak") :pvc-storage-class-name \"local-path\"
(br/generate-input-field "mon-cluster-stage" "(Optional) monitoring cluster stage:" "test") :postgres-data-volume-path \"/var/postgres\"
(br/generate-input-field "mon-cloud-url" "(Optional) grafana cloud url:" "https://prometheus-prod-01-eu-west-0.grafana.net/api/prom/push"))) :restic-repository \"s3://yourbucket/your-repo\"
(br/generate-group "credentials" :mon-cfg {:cluster-name \"cloud\"
(br/generate-text-area "auth" "Your auth.edn:" "{:postgres-db-user \"nextcloud\" :cluster-stage \"test\"
:postgres-db-password \"nextcloud-db-password\" :grafana-cloud-url \"https://prometheus-prod-01-eu-west-0.grafana.net/api/prom/push\"}}"
:nextcloud-admin-password \"nextcloud-admin-password\" "9"))
:nextcloud-admin-user \"nextcloud-admin-user\" (br/generate-group
:aws-access-key-id \"aws-id\" "auth"
:aws-secret-access-key \"aws-secret\" (br/generate-text-area
:restic-password \"restic-password\"} "auth" "Your auth.edn:"
:mon-auth {:grafana-cloud-user \"your-user-id\" "{:postgres-db-user \"nextcloud\"
:grafana-cloud-password \"your-cloud-password\"}" :postgres-db-password \"nextcloud-db-password\"
"5")) :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\"}
:mon-auth {:grafana-cloud-user \"your-user-id\"
:grafana-cloud-password \"your-cloud-password\"}}"
"9"))
[(br/generate-br)] [(br/generate-br)]
(br/generate-button "generate-button" "Generate c4k yaml")))] (br/generate-button "generate-button" "Generate c4k yaml")))]
(br/generate-output "c4k-nextcloud-output" "Your c4k deployment.yaml:" "25"))) (br/generate-output "c4k-nextcloud-output" "Your c4k deployment.yaml:" "25")))
@ -45,42 +49,10 @@
:content :content
(generate-content)}) (generate-content)})
(defn config-from-document []
(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)
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 (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! [] (defn validate-all! []
(br/validate! "fqdn" ::nextcloud/fqdn) (br/validate! "config" core/config? :deserializer edn/read-string)
(br/validate! "pv-storage-size-gb" ::nextcloud/pv-storage-size-gb :optional true) (br/validate! "auth" core/auth? :deserializer edn/read-string)
(br/validate! "pvc-storage-class-name" ::nextcloud/pvc-storage-class-name :optional true) (br/set-form-validated!))
(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)
(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] (defn add-validate-listener [name]
(-> (br/get-element-by-id name) (-> (br/get-element-by-id name)
@ -92,19 +64,14 @@
(.getElementById "generate-button") (.getElementById "generate-button")
(.addEventListener "click" (.addEventListener "click"
#(do (validate-all!) #(do (validate-all!)
(-> (cm/generate-common (-> (cm/generate-cm
(config-from-document) (br/get-content-from-element "config" :deserializer edn/read-string)
(br/get-content-from-element "auth" :deserializer edn/read-string) (br/get-content-from-element "auth" :deserializer edn/read-string)
{} core/config-defaults
core/k8s-objects) core/config-objects
core/auth-objects
false
false)
(br/set-output!))))) (br/set-output!)))))
(add-validate-listener "fqdn") (add-validate-listener "config")
(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")) (add-validate-listener "auth"))

View file

@ -21,7 +21,7 @@ spec:
- name: backup-app - name: backup-app
image: domaindrivenarchitecture/c4k-cloud-backup image: domaindrivenarchitecture/c4k-cloud-backup
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
command: ["/entrypoint-start-and-wait.sh"] command: ["wait.bb"]
env: env:
- name: POSTGRES_USER - name: POSTGRES_USER
valueFrom: valueFrom:
@ -57,8 +57,8 @@ spec:
key: restic-repository key: restic-repository
- name: RESTIC_PASSWORD_FILE - name: RESTIC_PASSWORD_FILE
value: /var/run/secrets/backup-secrets/restic-password value: /var/run/secrets/backup-secrets/restic-password
- name: CERTIFICATE_FILE - name: RESTIC_NEW_PASSWORD_FILE
value: "" value: /var/run/secrets/backup-secrets/restic-new-password
volumeMounts: volumeMounts:
- name: cloud-data-volume - name: cloud-data-volume
mountPath: /var/backups mountPath: /var/backups

View file

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

View file

@ -17,7 +17,7 @@ spec:
- name: backup-app - name: backup-app
image: domaindrivenarchitecture/c4k-cloud-backup image: domaindrivenarchitecture/c4k-cloud-backup
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
command: ["/entrypoint.sh"] command: ["backup.bb"]
env: env:
- name: POSTGRES_USER - name: POSTGRES_USER
valueFrom: valueFrom:

View file

@ -19,7 +19,7 @@ spec:
redeploy: v3 redeploy: v3
spec: spec:
containers: containers:
- image: domaindrivenarchitecture/c4k-cloud:8.0.0 - image: domaindrivenarchitecture/c4k-cloud:10.4.2
name: cloud-app name: cloud-app
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:

View file

@ -2,8 +2,12 @@
(:require (:require
#?(:clj [clojure.test :refer [deftest is are testing run-tests]] #?(:clj [clojure.test :refer [deftest is are testing run-tests]]
:cljs [cljs.test :refer-macros [deftest is are testing run-tests]]) :cljs [cljs.test :refer-macros [deftest is are testing run-tests]])
[clojure.spec.test.alpha :as st]
[dda.c4k-nextcloud.backup :as cut])) [dda.c4k-nextcloud.backup :as cut]))
(st/instrument `cut/generate-secret)
(st/instrument `cut/generate-config)
(st/instrument `cut/generate-cron)
(deftest should-generate-secret (deftest should-generate-secret
(is (= {:apiVersion "v1" (is (= {:apiVersion "v1"
@ -11,8 +15,25 @@
:metadata {:name "backup-secret", :namespace "nextcloud"} :metadata {:name "backup-secret", :namespace "nextcloud"}
:type "Opaque" :type "Opaque"
:data :data
{:aws-access-key-id "YXdzLWlk", :aws-secret-access-key "YXdzLXNlY3JldA==", :restic-password "cmVzdGljLXB3"}} {:aws-access-key-id "YXdzLWlk",
(cut/generate-secret {:aws-access-key-id "aws-id" :aws-secret-access-key "aws-secret" :restic-password "restic-pw"})))) :aws-secret-access-key "YXdzLXNlY3JldA==",
:restic-password "cmVzdGljLXB3"}}
(cut/generate-secret {:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-pw"})))
(is (= {:apiVersion "v1"
:kind "Secret"
:metadata {:name "backup-secret", :namespace "nextcloud"}
:type "Opaque"
:data
{:aws-access-key-id "YXdzLWlk",
:aws-secret-access-key "YXdzLXNlY3JldA==",
:restic-password "cmVzdGljLXB3"
:restic-new-password "bmV3LXJlc3RpYy1wdw=="}}
(cut/generate-secret {:aws-access-key-id "aws-id"
:aws-secret-access-key "aws-secret"
:restic-password "restic-pw"
:restic-new-password "new-restic-pw"}))))
(deftest should-generate-config (deftest should-generate-config
(is (= {:apiVersion "v1" (is (= {:apiVersion "v1"
@ -41,7 +62,7 @@
[{:name "backup-app" [{:name "backup-app"
:image "domaindrivenarchitecture/c4k-cloud-backup" :image "domaindrivenarchitecture/c4k-cloud-backup"
:imagePullPolicy "IfNotPresent" :imagePullPolicy "IfNotPresent"
:command ["/entrypoint.sh"] :command ["backup.bb"]
:env :env
[{:valueFrom [{:valueFrom
{:secretKeyRef {:secretKeyRef

View file

@ -0,0 +1,19 @@
(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]])
[clojure.spec.alpha :as s]
[dda.c4k-common.yaml :as yaml]
[dda.c4k-nextcloud.core :as cut]
#?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]])))
#?(: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")))))

View file

@ -2,24 +2,20 @@
(:require (:require
#?(:clj [clojure.test :refer [deftest is are testing run-tests]] #?(:clj [clojure.test :refer [deftest is are testing run-tests]]
:cljs [cljs.test :refer-macros [deftest is are testing run-tests]]) :cljs [cljs.test :refer-macros [deftest is are testing run-tests]])
[clojure.spec.alpha :as s] #?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]])
[clojure.spec.test.alpha :as st]
[dda.c4k-common.yaml :as yaml] [dda.c4k-common.yaml :as yaml]
[dda.c4k-nextcloud.nextcloud :as cut] [clojure.spec.test.alpha :as st]
#?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]]))) [dda.c4k-nextcloud.nextcloud :as cut]))
(st/instrument) (st/instrument `cut/generate-secret)
(st/instrument `cut/generate-ingress-and-cert)
(st/instrument `cut/generate-pvc)
(st/instrument `cut/generate-deployment)
#?(:cljs #?(:cljs
(defmethod yaml/load-resource :nextcloud-test [resource-name] (defmethod yaml/load-resource :nextcloud-test [resource-name]
(get (inline-resources "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 (deftest should-generate-secret
(is (= {:apiVersion "v1" (is (= {:apiVersion "v1"
:kind "Secret" :kind "Secret"
@ -80,10 +76,10 @@
:namespace "nextcloud" :namespace "nextcloud"
:labels {:app.kubernetes.io/application "cloud"}} :labels {:app.kubernetes.io/application "cloud"}}
:spec {:storageClassName "local-path" :spec {:storageClassName "local-path"
:accessModes ["ReadWriteOnce"] :accessModes ["ReadWriteOnce"]
:resources {:requests {:storage "50Gi"}}}} :resources {:requests {:storage "50Gi"}}}}
(cut/generate-pvc {:pv-storage-size-gb 50 :pvc-storage-class-name "local-path"})))) (cut/generate-pvc {:pv-storage-size-gb 50 :pvc-storage-class-name "local-path"}))))
(deftest should-generate-deployment (deftest should-generate-deployment
(is (= {:apiVersion "apps/v1" (is (= {:apiVersion "apps/v1"
:kind "Deployment" :kind "Deployment"
@ -95,7 +91,7 @@
{:metadata {:labels {:app "cloud-app", :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 :spec
{:containers {:containers
[{:image "domaindrivenarchitecture/c4k-cloud:8.0.0" [{:image "domaindrivenarchitecture/c4k-cloud:10.4.2"
:name "cloud-app" :name "cloud-app"
:imagePullPolicy "IfNotPresent" :imagePullPolicy "IfNotPresent"
:ports [{:containerPort 80}] :ports [{:containerPort 80}]

View file

@ -1,84 +0,0 @@
# Usage
`setup-local-s3.sh [BUCKET_NAME]`:
- [BUCKET_NAME] is optional, "mybucket" will be used if not specified
- sets up a k3s instance
- installs a localstack pod
- creates http and https routing to localstack via localhost
- saves the self-signed certificate as ca.crt
- uses the certificate to initialize a restic repo at `https://k3stesthost/BUCKET_NAME`
Note: In case of not being able to connect to "k3stesthost/health", you might need to ensure that the ingress' ip matches with the required host names: k3stesthost and cloudhost. With `sudo k3s kubectl get ingress` you can view the ingress' ip (e.g. 10.0.2.15), then add a line to file "/etc/hosts" e.g. `10.0.2.15 k3stesthost cloudhost`
`start-k3s.sh`:
- creates and starts a k3s instance
`k3s-uninstall.sh`:
- deletes everything k3s related
## Other useful commands
- `sudo k3s kubectl get pods`
- `curl k3stesthost/health`
expected: `{"services": {"s3": "running"}, "features": {"persistence": "disabled", "initScripts": "initialized"}}`
#### Requires AWS-CLI
- create bucket `aws --endpoint-url=http://k3stesthost s3 mb s3://mybucket`
- list buckets `aws --endpoint-url=http://k3stesthost s3 ls`
- upload something `aws --endpoint-url=http://k3stesthost s3 cp test.txt s3://mybucket`
- check files `aws --endpoint-url=http://k3stesthost s3 ls s3://mybucket`
## Run docker locally
```
docker pull docker:19.03.12-dind
docker run -d --privileged --name integration-test docker:19.03.12-dind
docker exec integration-test sh -c "apk add bash"
```
Set up docker container integration-test:
```
docker cp ../../../../../c4k-nextcloud/ integration-test:/
docker exec -it integration-test sh
cd /c4k-nextcloud/src/test/resources/local-integration-test
./setup-docker.sh
```
## Deploy nextcloud
### Requirements
* leiningen (install with: `sudo apt install leiningen` )
* In the project's root execute: `lein uberjar`
* Change file "valid-config.edn" according to your settings (e.g. `:fqdn "cloudhost"` and `:restic-repository "s3://k3stesthost:mybucket"`).
### Deploy to k3s
* Create and deploy the k8s yaml:
`java -jar target/uberjar/c4k-nextcloud-standalone.jar valid-config.edn valid-auth.edn | sudo k3s kubectl apply -f -`
Some of the steps may take some min to be effective, but eventually nextcloud should be available at: https://cloudhost
### Deploy to k3d
k3d is a k3s system which is running inside of a container. To install k3d run `curl -s https://raw.githubusercontent.com/rancher/k3d/main/install.sh | bash` or have a look at https://k3d.io/v5.0.3/ .
* Start a k3d cluster to deploy s3, nextcloud and test backup and restore on it: `./setup-local-s3-on-k3d.sh`
Some steps may take a couple of minutes to be effective, but eventually nextcloud should be available at: https://cloudhost
#### Remove k3d cluster
`k3d cluster delete nextcloud`
## Test in local gitlab runner
See https://stackoverflow.com/questions/32933174/use-gitlab-ci-to-run-tests-locally
This needs to be done in the project root
`docker run -d --name gitlab-runner --restart always -v $PWD:$PWD -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest`
`docker exec -it -w $PWD gitlab-runner gitlab-runner exec docker nextcloud-integrationtest --docker-privileged --docker-volumes '/var/run/docker.sock:/var/run/docker.sock'`

View file

@ -1,20 +0,0 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: localstack-cert
namespace: default
spec:
secretName: localstack-secret
commonName: k3stesthost
dnsNames:
- k3stesthost
issuerRef:
name: selfsigning-issuer
kind: ClusterIssuer
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigning-issuer
spec:
selfSigned: {}

View file

@ -1,44 +0,0 @@
@startuml
autonumber
skinparam sequenceBox {
borderColor White
}
participant gitlab_runner
box "outer container" #LightBlue
participant .gitlab_ci
participant PreparingCommands
participant test_script
end box
box "k3s" #CornSilk
participant k3s_api_server
participant backup_pod
end box
gitlab_runner -> k3s_api_server: run k3s as container
gitlab_runner -> .gitlab_ci : run
.gitlab_ci -> PreparingCommands : Install packages (curl bash ...)
.gitlab_ci -> PreparingCommands : get k3s_api_server config for k3s_api_server
.gitlab_ci -> test_script : run
test_script -> k3s_api_server: apply cert-manager
test_script -> k3s_api_server: apply localstack
test_script -> k3s_api_server: enable tls / create certificates
test_script -> k3s_api_server: apply cloud
test_script -> k3s_api_server: create backup_pod (by scale to 1)
test_script -> backup_pod: backup
test_script -> backup_pod: restore
@enduml

View file

@ -1,17 +0,0 @@
# Set the default kube context if present
DEFAULT_KUBE_CONTEXTS="$HOME/.kube/config"
if test -f "${DEFAULT_KUBE_CONTEXTS}"
then
export KUBECONFIG="$DEFAULT_KUBE_CONTEXTS"
fi
# Additional contexts should be in ~/.kube/custom-contexts/
CUSTOM_KUBE_CONTEXTS="$HOME/.kube/custom-contexts"
mkdir -p "${CUSTOM_KUBE_CONTEXTS}"
OIFS="$IFS"
IFS=$'\n'
for contextFile in `find "${CUSTOM_KUBE_CONTEXTS}" -type f -name "*.yml"`
do
export KUBECONFIG="$contextFile:$KUBECONFIG"
done
IFS="$OIFS"

View file

@ -1,65 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: localstack
spec:
selector:
matchLabels:
app: localstack
strategy:
type: Recreate
template:
metadata:
labels:
app: localstack
spec:
containers:
- image: localstack/localstack
name: localstack-app
imagePullPolicy: IfNotPresent
env:
- name: SERVICES
value: s3
---
# service
apiVersion: v1
kind: Service
metadata:
name: localstack-service
spec:
selector:
app: localstack
ports:
- port: 4566
---
apiVersion: v1
kind: Secret
metadata:
name: localstack-secret
type: Opaque
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-localstack
annotations:
cert-manager.io/cluster-issuer: selfsigning-issuer
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/redirect-entry-point: https
namespace: default
spec:
tls:
- hosts:
- k3stesthost
secretName: localstack-secret
rules:
- host: k3stesthost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: localstack-service
port:
number: 4566

View file

@ -1,48 +0,0 @@
#!/bin/bash
set -x
docker volume create k3s-server
name='inttst'
[[ $(docker ps -f "name=$name" --format '{{.Names}}') == $name ]] || docker run --name $name -d --privileged --tmpfs /run --tmpfs /var/run --restart always -e K3S_TOKEN=12345678901234 -e K3S_KUBECONFIG_OUTPUT=./kubeconfig.yaml -e K3S_KUBECONFIG_MODE=666 -v k3s-server:/var/lib/rancher/k3s:z -v $(pwd):/output:z -p 6443:6443 -p 80:80 -p 443:443 rancher/k3s server --cluster-init --tls-san k3stesthost --tls-san cloudhost
docker ps
export timeout=30; while ! docker exec $name sh -c "test -f /var/lib/rancher/k3s/server/kubeconfig.yaml"; do if [ "$timeout" == 0 ]; then echo "ERROR: Timeout while waiting for file."; break; fi; sleep 1; ((timeout--)); done
mkdir -p $HOME/.kube/
docker cp $name:/var/lib/rancher/k3s/server/kubeconfig.yaml $HOME/.kube/config
if [ "$timeout" == 0 ]
then
echo -------------------------------------------------------
find / -name "kubeconfig.yaml";
echo -------------------------------------------------------
docker ps -a
echo -------------------------------------------------------
exit 1
fi
echo "127.0.0.1 kubernetes" >> /etc/hosts
apk add wget curl bash sudo openjdk8
wget -P /etc/apk/keys/ https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
apk add --no-cache --repository=https://apkproxy.herokuapp.com/sgerrand/alpine-pkg-leiningen leiningen
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.22.0/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv ./kubectl /usr/local/bin/kubectl
sleep 20 #allow some time to startup k3s
docker ps -a
swapoff -a # can this be removed ?
export KUBECONFIG=$HOME/.kube/config
pwd
cd ./c4k-nextcloud/src/test/resources/local-integration-test && ./setup-local-s3-on-k3d.sh

View file

@ -1,60 +0,0 @@
#!/bin/bash
set -x
function main()
{
# enable tls for k3s with cert-manager
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml
kubectl apply -f localstack.yaml
until kubectl apply -f certificate.yaml
do
echo "[INFO] Waiting for certificate ..."
sleep 30
done
# wait for ingress to be ready
bash -c 'external_ip=""; while [ -z $external_ip ]; do echo "[INFO] Waiting for end point..."; external_ip=$(kubectl get ingress -o jsonpath="{$.items[*].status.loadBalancer.ingress[*].ip}"); [ -z "$external_ip" ] && sleep 10; done; echo "End point ready - $external_ip";'
export INGRESS_IP=$(kubectl get ingress ingress-localstack -o=jsonpath="{.status.loadBalancer.ingress[0].ip}")
cd ../../../../ # c4k-nextcloud project root
lein uberjar
java -jar target/uberjar/c4k-nextcloud-standalone.jar config-local.edn auth-local.edn | kubectl apply -f -
CLOUD_POD=$(kubectl get pod -l app=cloud-app -o name)
kubectl wait $CLOUD_POD --for=condition=Ready --timeout=240s
# wait for nextcloud config file available
timeout 180 bash -c "kubectl exec -t $POD -- bash -c \"until [ -f /var/www/html/config/config.php ]; do sleep 10; done\""
# ensure an instance of pod backup-restore
kubectl scale deployment backup-restore --replicas 1
# wait for localstack health endpoint
echo "$INGRESS_IP k3stesthost cloudhost" >> /etc/hosts
until curl --fail --silent k3stesthost/health | grep -oe '"s3": "available"' -oe '"s3": "running"'
do
curl --fail k3stesthost/health
echo "[INFO] Waiting for s3 running"
sleep 10
done
BACKUP_POD=$(kubectl get pod -l app=backup-restore -o name)
kubectl wait $BACKUP_POD --for=condition=Ready --timeout=240s
kubectl exec -t $BACKUP_POD -- bash -c "echo \"$INGRESS_IP k3stesthost cloudhost\" >> /etc/hosts"
kubectl exec -t $BACKUP_POD -- /usr/local/bin/init.sh
echo ================= BACKUP =================
kubectl exec -t $BACKUP_POD -- /usr/local/bin/backup.sh
sleep 10 # avoid race conditions
echo ================= RESTORE =================
kubectl exec -t $BACKUP_POD -- /usr/local/bin/restore.sh
}
main "$@"

View file

@ -1,34 +0,0 @@
function main()
{
local bucket_name="${1:-mybucket}"; shift
./start-k3s.sh
sudo k3s kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml
sudo k3s kubectl apply -f localstack.yaml
until sudo k3s kubectl apply -f certificate.yaml
do
echo "*** Waiting for certificate ... ***"
sleep 10
done
echo
echo
echo "[INFO] Waiting for localstack health endpoint"
until curl --connect-timeout 3 -s -f -o /dev/null "k3stesthost/health"
do
sleep 5
done
echo
sudo k3s kubectl get secret localstack-secret -o jsonpath="{.data.ca\.crt}" | base64 --decode > ca.crt
#aws --endpoint-url=http://localhost s3 mb s3://$bucket_name
export RESTIC_PASSWORD="test-password"
restic init --cacert ca.crt -r s3://k3stesthost/$bucket_name
}
main $@

View file

@ -1,9 +0,0 @@
function main()
{
./start-k3s.sh
sudo k3s kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml
}
main

View file

@ -1 +0,0 @@
KUBECONFIG=~/.kube/custom-contexts/k3d-config.yml k3d cluster create nextcloud --k3s-arg '--tls-san cloudhost@loadbalancer' --port 80:80@loadbalancer --port 443:443@loadbalancer --api-port 6443 --kubeconfig-update-default

View file

@ -1 +0,0 @@
curl -sfL https://get.k3s.io | K3S_NODE_NAME=k3stesthost INSTALL_K3S_EXEC='--tls-san cloudhost' sh -

View file

@ -5,6 +5,7 @@ nextcloud-admin-password: "cloudpassword"
aws-access-key-id: "aws-id" aws-access-key-id: "aws-id"
aws-secret-access-key: "aws-secret" aws-secret-access-key: "aws-secret"
restic-password: "restic-password" restic-password: "restic-password"
restic-new-password: "restic-new-password"
mon-auth: mon-auth:
grafana-cloud-user: "user" grafana-cloud-user: "user"
grafana-cloud-password: "password" grafana-cloud-password: "password"