added initial cloud files to c4k-nextcloud

This commit is contained in:
leo 2021-08-10 00:41:53 +02:00
parent 6732be46a5
commit 1c2f6b89f2
79 changed files with 1512 additions and 571 deletions

View file

@ -1,41 +1,5 @@
# convention 4 kubernetes: c4k-nextcloud
# meissa-cloud
[![Clojars Project](https://img.shields.io/clojars/v/org.domaindrivenarchitecture/c4k-nextcloud.svg)](https://clojars.org/org.domaindrivenarchitecture/c4k-nextcloud) [![pipeline status](https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/badges/master/pipeline.svg)](https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/-/commits/master)
# backup manuell triggern
[<img src="https://domaindrivenarchitecture.org/img/delta-chat.svg" width=20 alt="DeltaChat"> chat over e-mail](mailto:buero@meissa-gmbh.de?subject=community-chat) | [<img src="https://meissa-gmbh.de/img/community/Mastodon_Logotype.svg" width=20 alt="team@social.meissa-gmbh.de"> team@social.meissa-gmbh.de](https://social.meissa-gmbh.de/@team) | [Website & Blog](https://domaindrivenarchitecture.org)
## Purpose
c4k-nextcloud provides a k8s deployment for nextcloud containing:
* adjusted nextcloud docker image
* nextcloud
* ingress having a letsencrypt managed certificate
* postgres database
The package aims to a low load sceanrio.
## Status
This is under development.
## Manual restore
1) Scale Nextcloud deployment down:
kubectl scale deployment nextcloud --replicas=0
2) apply backup and restore pod:
kubectl apply -f src/main/resources/backup/backup-restore.yaml
3) exec into pod and execute restore pod
kubectl exec -it backup-restore -- /usr/local/bin/restore.sh
4) Scale Nextcloud deployment up:
kubectl scale deployment nextcloud --replicas=1
5) Update index of Nextcloud:
Nextcloud > Settings > System > Advanced > Indexing
## License
Copyright © 2021 meissa GmbH
Licensed under the [Apache License, Version 2.0](LICENSE) (the "License")
Pls. find licenses of our subcomponents [here](doc/SUBCOMPONENT_LICENSE)
# restore manuell triggern

View file

@ -3,28 +3,26 @@ from pybuilder.core import task, init
from ddadevops import *
import logging
name = 'c4k-cloud-backup'
name = 'meissa-cloud-backup'
MODULE = 'docker'
PROJECT_ROOT_PATH = '../..'
class MyBuild(DevopsDockerBuild):
pass
@init
def initialize(project):
project.build_depends_on('ddadevops>=0.12.4')
stage = 'prod'
project.build_depends_on('ddadevops>=0.6.1')
stage = 'notused'
dockerhub_user = environ.get('DOCKERHUB_USER')
if not dockerhub_user:
dockerhub_user = gopass_field_from_path('meissa/web/docker.com', 'login')
dockerhub_password = environ.get('DOCKERHUB_PASSWORD')
if not dockerhub_password:
dockerhub_password = gopass_password_from_path('meissa/web/docker.com')
tag = environ.get('CI_COMMIT_TAG')
if not tag:
tag = get_tag_from_latest_commit()
config = create_devops_docker_build_config(
stage, PROJECT_ROOT_PATH, MODULE, dockerhub_user, dockerhub_password, docker_publish_tag=tag)
stage, PROJECT_ROOT_PATH, MODULE, dockerhub_user, dockerhub_password)
build = MyBuild(project, config)
build.initialize_build_dir()
@ -39,13 +37,13 @@ def drun(project):
build = get_devops_build(project)
build.drun()
@task
def test(project):
build = get_devops_build(project)
build.test()
@task
def publish(project):
build = get_devops_build(project)
build.dockerhub_login()
build.dockerhub_publish()
@task
def test(project):
build = get_devops_build(project)
build.test()

View file

@ -3,6 +3,9 @@
set -o pipefail
function main() {
start-maintenance.sh
file_env AWS_ACCESS_KEY_ID
file_env AWS_SECRET_ACCESS_KEY
file_env POSTGRES_DB
@ -10,13 +13,15 @@ function main() {
file_env POSTGRES_USER
file_env RESTIC_DAYS_TO_KEEP 14
backup-roles ""
backup-roles 'oc_'
backup-db-dump
backup-fs-from-directory '/var/backups/' 'data/'
backup-directory '/var/backups/'
end-maintenance.sh
}
source /usr/local/lib/functions.sh
source /usr/local/lib/file-functions.sh
source /usr/local/lib/pg-functions.sh
source /usr/local/lib/file-functions.sh
main

View file

@ -0,0 +1,10 @@
#!/bin/bash
if test -f "/var/backups/config/config.orig"; then
rm /var/backups/config/config.php
mv /var/backups/config/config.orig /var/backups/config/config.php
chown www-data:root /var/backups/config/config.php
touch /var/backups/config/config.php
fi

View file

@ -4,7 +4,7 @@ function main() {
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD
file_env POSTGRES_USER
create-pg-pass
while true; do

View file

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

View file

@ -10,6 +10,6 @@ function main() {
}
source /usr/local/lib/functions.sh
source /usr/local/lib/file-functions.sh
source /usr/local/lib/pg-functions.sh
source /usr/local/lib/file-functions.sh
main

View file

@ -8,4 +8,5 @@ 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/restic-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/

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -o pipefail
function main() {
file_env AWS_ACCESS_KEY_ID
file_env AWS_SECRET_ACCESS_KEY
restic -r ${RESTIC_REPOSITORY}/pg-role snapshots
restic -r ${RESTIC_REPOSITORY}/pg-database snapshots
restic -r ${RESTIC_REPOSITORY}/files snapshots
}
source /usr/local/lib/functions.sh
source /usr/local/lib/file-functions.sh
main

View file

@ -4,6 +4,8 @@ set -Eeo pipefail
function main() {
start-maintenance.sh
file_env AWS_ACCESS_KEY_ID
file_env AWS_SECRET_ACCESS_KEY
@ -11,26 +13,16 @@ function main() {
file_env POSTGRES_PASSWORD
file_env POSTGRES_USER
# Im Nextcloud pod: /opt/atlassian-cloud-software-standalone/bin/stop-cloud.sh
# Restore latest snapshot into /var/backups/restic-restore
rm -rf /var/backups/restic-restore
restore-directory '/var/backups/restic-restore'
# Restore data dir backup
rm -rf /var/backups/data/*
cp -a /var/backups/restic-restore/data/* /var/backups/data
# Restore db
drop-create-db
restore-roles
restore-db
restore-directory '/var/backups/'
# /opt/atlassian-cloud-software-standalone/bin/start-cloud.sh
}
source /usr/local/lib/functions.sh
source /usr/local/lib/file-functions.sh
source /usr/local/lib/pg-functions.sh
source /usr/local/lib/file-functions.sh
main

View file

@ -0,0 +1,11 @@
#!/bin/bash
if [ ! -f "/var/backups/config/config.orig" ]; then
rm -f /var/backups/config/config.orig
cp /var/backups/config/config.php /var/backups/config/config.orig
sed -i "s/);/ \'maintenance\' => true,\n);/g" /var/backups/config/config.php
chown www-data:root /var/backups/config/config.php
touch /var/backups/config/config.php
fi

View file

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

View file

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

View file

@ -1,10 +0,0 @@
FROM ubuntu:20.04
ENV CLOUD_HOME="/var/cloud" \
DOWNLOAD_URL="https://product-downloads.atlassian.com/software/nextcloud/downloads" \
CLOUD_RELEASE="8.8.0"
# CLOUD_RELEASE="20.1.0"???
ADD resources /tmp/resources
RUN /tmp/resources/install.sh
USER 901:901

View file

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<cloud-database-config>
<name>defaultDS</name>
<delegator-name>default</delegator-name>
<database-type>postgres72</database-type>
<schema-name>public</schema-name>
<jdbc-datasource>
<url>jdbc:postgresql://postgresql-service:5432/cloud</url>
<driver-class>org.postgresql.Driver</driver-class>
<username>$CLOUD_DB_USER</username>
<password>$CLOUD_DB_PASSWORD</password>
<pool-min-size>20</pool-min-size>
<pool-max-size>20</pool-max-size>
<pool-max-wait>30000</pool-max-wait>
<validation-query>select 1</validation-query>
<min-evictable-idle-time-millis>60000</min-evictable-idle-time-millis>
<time-between-eviction-runs-millis>300000</time-between-eviction-runs-millis>
<pool-max-idle>20</pool-max-idle>
<pool-remove-abandoned>true</pool-remove-abandoned>
<pool-remove-abandoned-timeout>300</pool-remove-abandoned-timeout>
<pool-test-on-borrow>false</pool-test-on-borrow>
<pool-test-while-idle>true</pool-test-while-idle>
</jdbc-datasource>
</cloud-database-config>

View file

@ -1,44 +0,0 @@
#!/bin/bash
# usage: file_env VAR [DEFAULT]
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
function file_env() {
local var="$1"
local fileVar="${var}_FILE"
local def="${2:-}"
local varValue=$(env | grep -E "^${var}=" | sed -E -e "s/^${var}=//")
local fileVarValue=$(env | grep -E "^${fileVar}=" | sed -E -e "s/^${fileVar}=//")
if [ -n "${varValue}" ] && [ -n "${fileVarValue}" ]; then
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
exit 1
fi
if [ -n "${varValue}" ]; then
export "$var"="${varValue}"
elif [ -n "${fileVarValue}" ]; then
export "$var"="$(cat "${fileVarValue}")"
elif [ -n "${def}" ]; then
export "$var"="$def"
fi
unset "$fileVar"
}
function main() {
file_env "FQDN"
file_env "DB_USERNAME"
file_env "DB_PASSWORD"
xmlstarlet ed -L -u "/Server/Service/Connector[@proxyName='{subdomain}.{domain}.com']/@proxyName" \
-v "$FQDN" /opt/atlassian-cloud-software-standalone/conf/server.xml
xmlstarlet ed -L -u "/cloud-database-config/jdbc-datasource/username" \
-v "$DB_USERNAME" /app/dbconfig.xml
xmlstarlet ed -L -u "/cloud-database-config/jdbc-datasource/password" \
-v "$DB_PASSWORD" /app/dbconfig.xml
install -ocloud -gcloud -m660 /app/dbconfig.xml /var/cloud/dbconfig.xml
/opt/atlassian-cloud-software-standalone/bin/setenv.sh run
/opt/atlassian-cloud-software-standalone/bin/start-cloud.sh run
}
main

View file

@ -1,30 +0,0 @@
#!/bin/bash
function main() {
upgradeSystem
apt-get -qqy install curl openjdk-11-jre-headless xmlstarlet > /dev/null
adduser --system --disabled-login --home ${CLOUD_HOME} --uid 901 --group cloud
mkdir -p /app
cd /tmp
curl --location ${DOWNLOAD_URL}/atlassian-cloud-software-${CLOUD_RELEASE}.tar.gz \
-o atlassian-cloud-software-${CLOUD_RELEASE}.tar.gz
tar -xvf atlassian-cloud-software-${CLOUD_RELEASE}.tar.gz -C /tmp/
mv /tmp/atlassian-cloud-software-${CLOUD_RELEASE}-standalone \
/opt/atlassian-cloud-software-standalone
chown -R cloud:cloud /opt/atlassian-cloud-software-standalone
install -ocloud -gcloud -m744 /tmp/resources/entrypoint.sh /app/entrypoint.sh
install -ocloud -gcloud -m744 /tmp/resources/setenv.sh /opt/atlassian-cloud-software-standalone/bin/setenv.sh
install -ocloud -gcloud -m660 /tmp/resources/dbconfig.xml /app/dbconfig.xml
install -ocloud -gcloud -m660 /tmp/resources/server.xml /opt/atlassian-cloud-software-standalone/conf/server.xml
install -ocloud -gcloud -m660 /tmp/resources/logging.properties /opt/atlassian-cloud-software-standalone/conf/logging.properties
cleanupDocker
}
source /tmp/resources/install_functions.sh
main

View file

@ -1,69 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
handlers = java.util.logging.ConsoleHandler
.handlers = java.util.logging.ConsoleHandler
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
java.util.logging.ConsoleHandler.encoding = UTF-8
############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.AsyncFileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.AsyncFileHandler
# For example, set the org.apache.catalina.util.LifecycleBase logger to log
# each component that extends LifecycleBase changing state:
#org.apache.catalina.util.LifecycleBase.level = FINE
# To see debug messages in TldLocationsCache, uncomment the following line:
#org.apache.jasper.compiler.TldLocationsCache.level = FINE
# To see debug messages for HTTP/2 handling, uncomment the following line:
#org.apache.coyote.http2.level = FINE
# To see debug messages for WebSocket handling, uncomment the following line:
#org.apache.tomcat.websocket.level = FINE
# Suppress clearReferencesThreads and clearThreadLocalMap notifications on shutdown
org.apache.catalina.loader.WebappClassLoader.level = OFF
# Suppress some useless REST messages. See JRADEV-12212.
com.sun.jersey.server.impl.application.WebApplicationImpl.level = WARNING
com.atlassian.plugins.rest.doclet.level = WARNING
com.sun.jersey.api.wadl.config.WadlGeneratorLoader.level = WARNING
# Suppress log spam about the request body - https://cloud.atlassian.com/browse/JRASERVER-30406
com.sun.jersey.spi.container.servlet.WebComponent.level = SEVERE
com.sun.jersey.spi.container.servlet.WebComponent.filterFormParameters.level = SEVERE
# Suppress resources cache full warnings
org.apache.catalina.webresources.Cache.level = OFF

View file

@ -1,114 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
<!--Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
<Service name="Catalina">
<!--
==============================================================================================================
DEFAULT - Direct connector with no proxy for unproxied access to Nextcloud.
If using a http/https proxy, comment out this connector.
==============================================================================================================
-->
<!-- Relaxing chars because of JRASERVER-67974 -->
<!--
<Connector port="8080" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^&#x5c;&#x60;&quot;&lt;&gt;"
maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false"
maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443"
acceptCount="100" disableUploadTimeout="true" bindOnInit="false"/>
-->
<!--
==============================================================================================================
HTTP - Proxying Nextcloud via Apache or Nginx over HTTP
If you're proxying traffic to Nextcloud over HTTP, uncomment the below connector and comment out the others.
Ensure the proxyName and proxyPort are updated with the appropriate information if necessary as per the docs.
See the following for more information:
Apache - https://confluence.atlassian.com/x/4xQLM
nginx - https://confluence.atlassian.com/x/DAFmGQ
==============================================================================================================
-->
<!--
<Connector port="8080" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^&#x5c;&#x60;&quot;&lt;&gt;"
maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false"
maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443"
acceptCount="100" disableUploadTimeout="true" bindOnInit="false" scheme="http"
proxyName="<subdomain>.<domain>.com" proxyPort="80"/>
-->
<!--
==============================================================================================================
HTTPS - Proxying Nextcloud via Apache or Nginx over HTTPS
If you're proxying traffic to Nextcloud over HTTPS, uncomment the below connector and comment out the others.
Ensure the proxyName and proxyPort are updated with the appropriate information if necessary as per the docs.
See the following for more information:
Apache - https://confluence.atlassian.com/x/PTT3MQ
nginx - https://confluence.atlassian.com/x/DAFmGQ
==============================================================================================================
-->
<Connector port="8080" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^&#x5c;&#x60;&quot;&lt;&gt;"
maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false"
maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true"
acceptCount="100" disableUploadTimeout="true" bindOnInit="false" secure="true" scheme="https"
proxyName="{subdomain}.{domain}.com" proxyPort="443"/>
<!--
==============================================================================================================
AJP - Proxying Nextcloud via Apache over HTTP or HTTPS
If you're proxying traffic to Nextcloud using the AJP protocol, uncomment the following connector line
See the following for more information:
Apache - https://confluence.atlassian.com/x/QiJ9MQ
==============================================================================================================
-->
<!--
<Connector port="8009" URIEncoding="UTF-8" enableLookups="false" protocol="AJP/1.3"/>
-->
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context path="" docBase="${catalina.home}/atlassian-cloud" reloadable="false" useHttpOnly="true">
<Resource name="UserTransaction" auth="Container" type="javax.transaction.UserTransaction"
factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60"/>
<Manager pathname=""/>
<JarScanner scanManifest="false"/>
<Valve className="org.apache.catalina.valves.StuckThreadDetectionValve" threshold="120" />
</Context>
</Host>
<Valve className="org.apache.catalina.valves.AccessLogValve"
pattern="%a %{cloud.request.id}r %{cloud.request.username}r %t &quot;%m %U%q %H&quot; %s %b %D &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot; &quot;%{cloud.request.assession.id}r&quot;"/>
</Engine>
</Service>
</Server>

View file

@ -1,121 +0,0 @@
#
# If the limit of files that Nextcloud can open is too low, it will be set to this value.
#
MIN_NOFILES_LIMIT=16384
#
# One way to set the Nextcloud HOME path is here via this variable. Simply uncomment it and set a valid path like /cloud/home. You can of course set it outside in the command terminal. That will also work.
#
CLOUD_HOME="/var/cloud"
#
# Occasionally Atlassian Support may recommend that you set some specific JVM arguments. You can use this variable below to do that.
#
JVM_SUPPORT_RECOMMENDED_ARGS=""
#
# You can use variable below to modify garbage collector settings.
# For Java 8 we recommend default settings
# For Java 11 and relatively small heaps we recommend: -XX:+UseParallelGC
# For Java 11 and larger heaps we recommend: -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent
#
JVM_GC_ARGS="-XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent"
#
# The following 2 settings control the minimum and maximum given to the Nextcloud Java virtual machine. In larger Nextcloud instances, the maximum amount will need to be increased.
#
JVM_MINIMUM_MEMORY="4096m"
JVM_MAXIMUM_MEMORY="4096m"
#
# The following setting configures the size of JVM code cache. A high value of reserved size allows Nextcloud to work with more installed apps.
#
JVM_CODE_CACHE_ARGS='-XX:InitialCodeCacheSize=32m -XX:ReservedCodeCacheSize=512m'
#
# The following are the required arguments for Nextcloud.
#
JVM_REQUIRED_ARGS='-Djava.awt.headless=true -Datlassian.standalone=CLOUD -Dorg.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true -Dmail.mime.decodeparameters=true -Dorg.dom4j.factory=com.atlassian.core.xml.InterningDocumentFactory'
# Uncomment this setting if you want to import data without notifications
#
#DISABLE_NOTIFICATIONS=" -Datlassian.mail.senddisabled=true -Datlassian.mail.fetchdisabled=true -Datlassian.mail.popdisabled=true"
#-----------------------------------------------------------------------------------
#
# In general don't make changes below here
#
#-----------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------
# Prevents the JVM from suppressing stack traces if a given type of exception
# occurs frequently, which could make it harder for support to diagnose a problem.
#-----------------------------------------------------------------------------------
JVM_EXTRA_ARGS="-XX:-OmitStackTraceInFastThrow -Djava.locale.providers=COMPAT"
CURRENT_NOFILES_LIMIT=$( ulimit -Hn )
ulimit -Sn $CURRENT_NOFILES_LIMIT
ulimit -n $(( CURRENT_NOFILES_LIMIT > MIN_NOFILES_LIMIT ? CURRENT_NOFILES_LIMIT : MIN_NOFILES_LIMIT ))
PRGDIR=`dirname "$0"`
cat "${PRGDIR}"/cloudbanner.txt
CLOUD_HOME_MINUSD=""
if [ "$CLOUD_HOME" != "" ]; then
echo $CLOUD_HOME | grep -q " "
if [ $? -eq 0 ]; then
echo ""
echo "--------------------------------------------------------------------------------------------------------------------"
echo " WARNING : You cannot have a CLOUD_HOME environment variable set with spaces in it. This variable is being ignored"
echo "--------------------------------------------------------------------------------------------------------------------"
else
CLOUD_HOME_MINUSD=-Dcloud.home=$CLOUD_HOME
fi
fi
JAVA_OPTS="-Xms${JVM_MINIMUM_MEMORY} -Xmx${JVM_MAXIMUM_MEMORY} ${JVM_CODE_CACHE_ARGS} ${JAVA_OPTS} ${JVM_REQUIRED_ARGS} ${DISABLE_NOTIFICATIONS} ${JVM_SUPPORT_RECOMMENDED_ARGS} ${JVM_EXTRA_ARGS} ${CLOUD_HOME_MINUSD} ${START_CLOUD_JAVA_OPTS}"
export JAVA_OPTS
# DO NOT remove the following line
# !INSTALLER SET JAVA_HOME
echo ""
echo "If you encounter issues starting or stopping Nextcloud, please see the Troubleshooting guide at https://docs.atlassian.com/cloud/jadm-docs-088/Troubleshooting+installation"
echo ""
if [ "$CLOUD_HOME_MINUSD" != "" ]; then
echo "Using CLOUD_HOME: $CLOUD_HOME"
fi
# set the location of the pid file
if [ -z "$CATALINA_PID" ] ; then
if [ -n "$CATALINA_BASE" ] ; then
CATALINA_PID="$CATALINA_BASE"/work/catalina.pid
elif [ -n "$CATALINA_HOME" ] ; then
CATALINA_PID="$CATALINA_HOME"/work/catalina.pid
fi
fi
export CATALINA_PID
if [ -z "$CATALINA_BASE" ]; then
if [ -z "$CATALINA_HOME" ]; then
LOGBASE=$PRGDIR
LOGTAIL=..
else
LOGBASE=$CATALINA_HOME
LOGTAIL=.
fi
else
LOGBASE=$CATALINA_BASE
LOGTAIL=.
fi
PUSHED_DIR=`pwd`
cd $LOGBASE
cd $LOGTAIL
LOGBASEABS=`pwd`
cd $PUSHED_DIR
echo ""
echo "Server startup logs are located in $LOGBASEABS/logs/catalina.out"

View file

@ -1,5 +0,0 @@
# START INSTALLER MAGIC ! DO NOT EDIT !
CLOUD_USER="cloud" ##
# END INSTALLER MAGIC ! DO NOT EDIT !
export CLOUD_USER

View file

@ -1,8 +0,0 @@
FROM c4k-cloud
RUN curl -L -o /tmp/serverspec.jar \
https://github.com/DomainDrivenArchitecture/dda-serverspec-crate/releases/download/1.3.4/dda-serverspec-standalone.jar
COPY serverspec.edn /tmp/serverspec.edn
RUN java -jar /tmp/serverspec.jar /tmp/serverspec.edn -v

View file

@ -1,3 +0,0 @@
{:file [{:path "/app/entrypoint.sh"}
{:path "/var/cloud"}
{:path "/opt/atlassian-cloud-software-standalone"}]}

View file

@ -3,28 +3,26 @@ from pybuilder.core import task, init
from ddadevops import *
import logging
name = 'c4k-cloud'
name = 'meissa-cloud-app'
MODULE = 'docker'
PROJECT_ROOT_PATH = '../..'
class MyBuild(DevopsDockerBuild):
pass
@init
def initialize(project):
project.build_depends_on('ddadevops>=0.12.4')
stage = 'prod'
project.build_depends_on('ddadevops>=0.6.1')
stage = 'notused'
dockerhub_user = environ.get('DOCKERHUB_USER')
if not dockerhub_user:
dockerhub_user = gopass_field_from_path('meissa/web/docker.com', 'login')
dockerhub_password = environ.get('DOCKERHUB_PASSWORD')
if not dockerhub_password:
dockerhub_password = gopass_password_from_path('meissa/web/docker.com')
tag = environ.get('CI_COMMIT_TAG')
if not tag:
tag = get_tag_from_latest_commit()
config = create_devops_docker_build_config(
stage, PROJECT_ROOT_PATH, MODULE, dockerhub_user, dockerhub_password, docker_publish_tag=tag)
stage, PROJECT_ROOT_PATH, MODULE, dockerhub_user, dockerhub_password)
build = MyBuild(project, config)
build.initialize_build_dir()
@ -39,13 +37,13 @@ def drun(project):
build = get_devops_build(project)
build.drun()
@task
def test(project):
build = get_devops_build(project)
build.test()
@task
def publish(project):
build = get_devops_build(project)
build.dockerhub_login()
build.dockerhub_publish()
@task
def test(project):
build = get_devops_build(project)
build.test()

View file

@ -0,0 +1,8 @@
FROM nextcloud:19
# Prepare Entrypoint Script
ADD resources /tmp
RUN /tmp/install.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["apache2-foreground"]

View file

@ -0,0 +1,191 @@
#!/bin/sh
set -eu
# version_greater A B returns whether A > B
version_greater() {
[ "$(printf '%s\n' "$@" | sort -t '.' -n -k1,1 -k2,2 -k3,3 -k4,4 | head -n 1)" != "$1" ]
}
# return true if specified directory is empty
directory_empty() {
[ -z "$(ls -A "$1/")" ]
}
run_as() {
if [ "$(id -u)" = 0 ]; then
su -p www-data -s /bin/sh -c "$1"
else
sh -c "$1"
fi
}
# usage: file_env VAR [DEFAULT]
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
file_env() {
local var="$1"
local fileVar="${var}_FILE"
local def="${2:-}"
local varValue=$(env | grep -E "^${var}=" | sed -E -e "s/^${var}=//")
local fileVarValue=$(env | grep -E "^${fileVar}=" | sed -E -e "s/^${fileVar}=//")
if [ -n "${varValue}" ] && [ -n "${fileVarValue}" ]; then
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
exit 1
fi
if [ -n "${varValue}" ]; then
export "$var"="${varValue}"
elif [ -n "${fileVarValue}" ]; then
export "$var"="$(cat "${fileVarValue}")"
elif [ -n "${def}" ]; then
export "$var"="$def"
fi
unset "$fileVar"
}
if expr "$1" : "apache" 1>/dev/null; then
if [ -n "${APACHE_DISABLE_REWRITE_IP+x}" ]; then
a2disconf remoteip
fi
fi
if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UPDATE:-0}" -eq 1 ]; then
if [ -n "${REDIS_HOST+x}" ]; then
echo "Configuring Redis as session handler"
{
echo 'session.save_handler = redis'
# check if redis host is an unix socket path
if [ "$(echo "$REDIS_HOST" | cut -c1-1)" = "/" ]; then
if [ -n "${REDIS_HOST_PASSWORD+x}" ]; then
echo "session.save_path = \"unix://${REDIS_HOST}?auth=${REDIS_HOST_PASSWORD}\""
else
echo "session.save_path = \"unix://${REDIS_HOST}\""
fi
# check if redis password has been set
elif [ -n "${REDIS_HOST_PASSWORD+x}" ]; then
echo "session.save_path = \"tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}?auth=${REDIS_HOST_PASSWORD}\""
else
echo "session.save_path = \"tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}\""
fi
} > /usr/local/etc/php/conf.d/redis-session.ini
fi
installed_version="0.0.0.0"
if [ -f /var/www/html/version.php ]; then
# shellcheck disable=SC2016
installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')"
fi
# shellcheck disable=SC2016
image_version="$(php -r 'require "/usr/src/nextcloud/version.php"; echo implode(".", $OC_Version);')"
if version_greater "$installed_version" "$image_version"; then
echo "Can't start Nextcloud because the version of the data ($installed_version) is higher than the docker image version ($image_version) and downgrading is not supported. Are you sure you have pulled the newest image version?"
exit 1
fi
if version_greater "$image_version" "$installed_version"; then
echo "Initializing nextcloud $image_version (image) over $installed_version (installed) ..."
if [ "$installed_version" != "0.0.0.0" ]; then
echo "Upgrading nextcloud from $installed_version ..."
run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before
fi
if [ "$(id -u)" = 0 ]; then
rsync_options="-rlDog --chown www-data:root"
else
rsync_options="-rlD"
fi
rsync $rsync_options --delete --exclude-from=/upgrade.exclude /usr/src/nextcloud/ /var/www/html/
for dir in config data custom_apps themes; do
if [ ! -d "/var/www/html/$dir" ] || directory_empty "/var/www/html/$dir"; then
rsync $rsync_options --include "/$dir/" --exclude '/*' /usr/src/nextcloud/ /var/www/html/
fi
done
rsync $rsync_options --include '/version.php' --exclude '/*' /usr/src/nextcloud/ /var/www/html/
echo "Initializing finished"
#install
if [ "$installed_version" = "0.0.0.0" ]; then
echo "New nextcloud instance"
file_env NEXTCLOUD_ADMIN_PASSWORD
file_env NEXTCLOUD_ADMIN_USER
if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then
# shellcheck disable=SC2016
install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"'
if [ -n "${NEXTCLOUD_DATA_DIR+x}" ]; then
# shellcheck disable=SC2016
install_options=$install_options' --data-dir "$NEXTCLOUD_DATA_DIR"'
fi
file_env MYSQL_DATABASE
file_env MYSQL_PASSWORD
file_env MYSQL_USER
file_env POSTGRES_DB
file_env POSTGRES_PASSWORD
file_env POSTGRES_USER
install=false
if [ -n "${SQLITE_DATABASE+x}" ]; then
echo "Installing with SQLite database"
# shellcheck disable=SC2016
install_options=$install_options' --database-name "$SQLITE_DATABASE"'
install=true
elif [ -n "${MYSQL_DATABASE+x}" ] && [ -n "${MYSQL_USER+x}" ] && [ -n "${MYSQL_PASSWORD+x}" ] && [ -n "${MYSQL_HOST+x}" ]; then
echo "Installing with MySQL database"
# shellcheck disable=SC2016
install_options=$install_options' --database mysql --database-name "$MYSQL_DATABASE" --database-user "$MYSQL_USER" --database-pass "$MYSQL_PASSWORD" --database-host "$MYSQL_HOST"'
install=true
elif [ -n "${POSTGRES_DB+x}" ] && [ -n "${POSTGRES_USER+x}" ] && [ -n "${POSTGRES_PASSWORD+x}" ] && [ -n "${POSTGRES_HOST+x}" ]; then
echo "Installing with PostgreSQL database"
# shellcheck disable=SC2016
install_options=$install_options' --database pgsql --database-name "$POSTGRES_DB" --database-user "$POSTGRES_USER" --database-pass "$POSTGRES_PASSWORD" --database-host "$POSTGRES_HOST"'
install=true
fi
if [ "$install" = true ]; then
echo "starting nextcloud installation"
echo "$install_options"
max_retries=10
try=0
until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ]
do
echo "retrying install..."
try=$((try+1))
sleep 20s
done
if [ "$try" -gt "$max_retries" ]; then
echo "installing of nextcloud failed!"
exit 1
fi
if [ -n "${NEXTCLOUD_TRUSTED_DOMAINS+x}" ]; then
echo "setting trusted domains…"
NC_TRUSTED_DOMAIN_IDX=1
for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do
DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN"
run_as "php /var/www/html/occ config:system:set overwritehost --value=$DOMAIN"
NC_TRUSTED_DOMAIN_IDX=$(($NC_TRUSTED_DOMAIN_IDX+1))
done
fi
run_as "php /var/www/html/occ config:system:set overwriteprotocol --value=https"
else
echo "running web-based installer on first connect!"
fi
fi
#upgrade
else
run_as 'php /var/www/html/occ upgrade'
run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after
echo "The following apps have been disabled:"
diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1
rm -f /tmp/list_before /tmp/list_after
fi
fi
fi
exec "$@"

View file

@ -0,0 +1,3 @@
#!/bin/bash
apt update && apt -qqy install vim bash-completion less

View file

@ -0,0 +1,9 @@
#!/bin/bash
set -Eeo pipefail
mkdir /var/data
install -m 0700 /tmp/install-debug.sh /usr/local/bin/
install -m 0544 /tmp/upload-max-limit.ini /usr/local/etc/php/conf.d/
install -m 0544 /tmp/memory-limit.ini /usr/local/etc/php/conf.d/
install -m 0755 /tmp/entrypoint.sh /

View file

@ -0,0 +1,2 @@
memory_limit=5120M

View file

@ -0,0 +1,3 @@
post_max_size = 512M
upload_max_filesize = 512M

View file

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

View file

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

View file

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

View file

@ -0,0 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: backup-config
labels:
app.kubernetes.io/name: backup
app.kubernetes.io/part-of: cloud
data:
restic-repository: restic-repository

View file

@ -0,0 +1,9 @@
#!/bin/bash
kubectl delete --ignore-not-found=true -f backup-secret.yml
kubectl delete --ignore-not-found=true -f backup-config.yml
kubectl delete --ignore-not-found=true -f backup-cron.yml
kubectl apply -f backup-secret.yml
kubectl apply -f backup-config.yml
kubectl apply -f backup-cron.yml

View file

@ -0,0 +1,65 @@
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cloud-backup
labels:
app.kubernetes.part-of: cloud
spec:
schedule: "10 23 * * *"
successfulJobsHistoryLimit: 0
failedJobsHistoryLimit: 0
jobTemplate:
spec:
template:
spec:
containers:
- name: backup-app
image: domaindrivenarchitecture/meissa-cloud-backup
imagePullPolicy: IfNotPresent
command: ["/entrypoint.sh"]
env:
- name: POSTGRES_USER_FILE
value: /var/run/secrets/cloud-secrets/postgres-user
- name: POSTGRES_DB_FILE
value: /var/run/secrets/cloud-secrets/postgres-db
- name: POSTGRES_PASSWORD_FILE
value: /var/run/secrets/cloud-secrets/postgres-password
- name: POSTGRES_HOST
value: "postgresql-service:5432"
- name: POSTGRES_SERVICE
value: "postgresql-service"
- name: POSTGRES_PORT
value: "5432"
- name: AWS_DEFAULT_REGION
value: eu-central-1
- name: AWS_ACCESS_KEY_ID_FILE
value: /var/run/secrets/backup-secrets/aws-access-key-id
- name: AWS_SECRET_ACCESS_KEY_FILE
value: /var/run/secrets/backup-secrets/aws-secret-access-key
- name: RESTIC_REPOSITORY
valueFrom:
configMapKeyRef:
name: backup-config
key: restic-repository
- name: RESTIC_PASSWORD_FILE
value: /var/run/secrets/backup-secrets/restic-password
volumeMounts:
- name: cloud-data-volume
mountPath: /var/backups
- name: backup-secret-volume
mountPath: /var/run/secrets/backup-secrets
readOnly: true
- name: cloud-secret-volume
mountPath: /var/run/secrets/cloud-secrets
readOnly: true
volumes:
- name: cloud-data-volume
persistentVolumeClaim:
claimName: cloud-pvc
- name: cloud-secret-volume
secret:
secretName: cloud-secret
- name: backup-secret-volume
secret:
secretName: backup-secret
restartPolicy: OnFailure

View file

@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: backup-secret
type: Opaque
stringData:
aws-access-key-id: aws-access-key-id
aws-secret-access-key: aws-secret-access-key
restic-password: restic-password

View file

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

View file

@ -0,0 +1,45 @@
kind: Pod
apiVersion: v1
metadata:
name: cloud
labels:
app.kubernetes.io/name: cloud
spec:
shareProcessNamespace: true
containers:
- name: cloud-app
image: domaindrivenarchitecture/meissa-cloud-app
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
env:
- name: NEXTCLOUD_ADMIN_USER_FILE
value: /var/run/secrets/cloud-secrets/nextcloud-admin-user
- name: NEXTCLOUD_ADMIN_PASSWORD_FILE
value: /var/run/secrets/cloud-secrets/nextcloud-admin-password
- name: NEXTCLOUD_TRUSTED_DOMAINS
value: "{{fqdn}}"
- name: POSTGRES_USER_FILE
value: /var/run/secrets/cloud-secrets/postgres-user
- name: POSTGRES_PASSWORD_FILE
value: /var/run/secrets/cloud-secrets/postgres-password
- name: POSTGRES_DB_FILE
value: /var/run/secrets/cloud-secrets/postgres-db
- name: POSTGRES_HOST
value: "postgresql-service:5432"
volumeMounts:
- name: cloud-data-volume
mountPath: /var/www/html
- name: cloud-secret-volume
mountPath: /var/run/secrets/cloud-secrets
readOnly: true
volumes:
- name: cloud-data-volume
persistentVolumeClaim:
claimName: cloud-pvc
- name: cloud-secret-volume
secret:
secretName: cloud-secret
- name: backup-secret-volume
secret:
secretName: backup-secret

View file

@ -0,0 +1,22 @@
#!/bin/bash
kubectl delete --ignore-not-found=true -f cloud-ingress.yml
kubectl delete --ignore-not-found=true -f cloud-pod.yml
kubectl delete --ignore-not-found=true -f cloud-pvc.yml
kubectl delete --ignore-not-found=true -f cloud-service.yml
kubectl delete --ignore-not-found=true -f cloud-secret.yml
kubectl delete --ignore-not-found=true -f cloud-persistent-volume.yml
#Wait for postgres to be running
while [$POSTGRES = ""]
do
POSTGRES=$(kubectl get pods --selector=app=postgresql -o jsonpath='{.items[*].metadata.name}')
done
kubectl wait --for=condition=ready pod/$POSTGRES
kubectl apply -f cloud-persistent-volume.yml
kubectl apply -f cloud-secret.yml
kubectl apply -f cloud-service.yml
kubectl apply -f cloud-pvc.yml
kubectl apply -f cloud-pod.yml
kubectl apply -f cloud-ingress.yml

View file

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

View file

@ -0,0 +1,4 @@
#!/bin/bash
mkdir -p /var/cloud
install -d -m 0777 -o {{user}} -g {{user}} /var/cloud

View file

@ -0,0 +1,15 @@
kind: PersistentVolume
apiVersion: v1
metadata:
name: cloud-pv-volume
labels:
type: local
app: cloud
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
capacity:
storage: {{storage-size}}Gi #??? 30Gi?
hostPath:
path: "/var/cloud"

View file

@ -0,0 +1,25 @@
#!/bin/bash
SECONDS=0
while true; do
POD_STATUS="$(kubectl get pods --all-namespaces --field-selector=status.phase=Running | grep $1 )";
if [ ! -z "$POD_STATUS" ]
then
# pod = ready is not enough
sleep $4
break
fi
let duration=$SECONDS/60
# pallet needs a regular action, otherwise unwanted timeout after 5 min
echo "Seconds waited: ${SECONDS}"
if [ "$duration" -ge "$2" ]
then
exit 1
fi
sleep $3
done
exit 0

View file

@ -0,0 +1,16 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cloud-pvc
labels:
app: cloud
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{storage-size}}Gi #??? 30Gi?
selector:
matchLabels:
app: cloud

View file

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: cloud-secret
type: Opaque
stringData:
postgres-db: db-name
postgres-user: db-user-name
postgres-password: db-user-password
nextcloud-admin-user: admin-user
nextcloud-admin-password: admin-password

View file

@ -0,0 +1,9 @@
apiVersion: v1
kind: Service
metadata:
name: cloud-service
spec:
selector:
app.kubernetes.io/name: cloud #???
ports:
- port: 80

View file

@ -0,0 +1,15 @@
#!/bin/bash
echo -e "\n====================\n"
echo -e "cloud is running, ingress exists"
echo -e "\n====================\n"
kubectl get all
echo -e "\n====================\n"
echo -e "shows certificate with subject"
echo -e "CN={{fqdn}}"
echo -e "issuer: CN=Fake LE Intermediate X1"
echo -e "\n====================\n"
curl --insecure -v https://{{fqdn}}
echo -e "\n"

View file

@ -0,0 +1,15 @@
#!/bin/bash
kubectl delete --ignore-not-found=true -f postgres-deployment.yml
kubectl delete --ignore-not-found=true -f postgres-pvc.yml
kubectl delete --ignore-not-found=true -f postgres-service.yml
kubectl delete --ignore-not-found=true -f postgres-config.yml
kubectl delete --ignore-not-found=true -f postgres-secret.yml
kubectl delete --ignore-not-found=true -f postgres-persistent-volume.yml
kubectl apply -f postgres-persistent-volume.yml
kubectl apply -f postgres-secret.yml
kubectl apply -f postgres-config.yml
kubectl apply -f postgres-service.yml
kubectl apply -f postgres-pvc.yml
kubectl apply -f postgres-deployment.yml

View file

@ -0,0 +1,4 @@
#!/bin/bash
mkdir -p /var/postgres
install -d -m 0777 -o {{user}} -g {{user}} /var/postgres

View file

@ -0,0 +1,10 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
labels:
app: postgres
data:
postgresql.conf: |
max_connections = 1000
shared_buffers = 512MB

View file

@ -0,0 +1,49 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgresql
spec:
selector:
matchLabels:
app: postgresql
strategy:
type: Recreate
template:
metadata:
labels:
app: postgresql
spec:
containers:
- image: postgres
name: postgresql
env:
- name: POSTGRES_USER_FILE
value: /var/run/secrets/postgres-secrets/postgres-user
- name: POSTGRES_DB_FILE
value: /var/run/secrets/postgres-secrets/postgres-db
- name: POSTGRES_PASSWORD_FILE
value: /var/run/secrets/postgres-secrets/postgres-password
ports:
- containerPort: 5432
name: postgresql
cmd:
volumeMounts:
- name: postgresql
mountPath: /var/lib/postgresql/data
- name: postgres-secret-volume
mountPath: /var/run/secrets/postgres-secrets
readOnly: true
- name: postgres-config-volume
mountPath: /etc/postgresql/postgresql.conf
subPath: postgresql.conf
readOnly: true
volumes:
- name: postgresql
persistentVolumeClaim:
claimName: postgres-claim
- name: postgres-secret-volume
secret:
secretName: postgres-secret
- name: postgres-config-volume
configMap:
name: postgres-config

View file

@ -0,0 +1,15 @@
kind: PersistentVolume
apiVersion: v1
metadata:
name: postgres-pv-volume
labels:
type: local
app: postgresql
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
capacity:
storage: 10Gi
hostPath:
path: "/var/postgres"

View file

@ -0,0 +1,16 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-claim
labels:
app: postgresql
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
selector:
matchLabels:
app: postgresql

View file

@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: postgres-secret
type: Opaque
stringData:
postgres-db: cloud
postgres-user: {{db-user-name}}
postgres-password: {{db-user-password}}

View file

@ -0,0 +1,10 @@
---
apiVersion: v1
kind: Service
metadata:
name: postgresql-service
spec:
selector:
app: postgresql
ports:
- port: 5432

View file

@ -0,0 +1,8 @@
#!/bin/bash
echo -e "\n====================\n"
echo -e "postgres is running"
echo -e "\n====================\n"
kubectl get all
echo -e "\n"

View file

@ -0,0 +1,61 @@
(ns meissa.pallet.meissa-cloud.app
(:require
[schema.core :as s]
[dda.pallet.commons.secret :as secret]
[dda.config.commons.map-utils :as mu]
[dda.pallet.core.app :as core-app]
[dda.pallet.dda-config-crate.infra :as config-crate]
[dda.pallet.dda-user-crate.app :as user]
[dda.pallet.dda-k8s-crate.app :as k8s]
[meissa.pallet.meissa-cloud.convention :as convention]
[meissa.pallet.meissa-cloud.infra :as infra]))
(def with-cloud infra/with-cloud)
(def CloudConvention convention/CloudConvention)
(def CloudConventionResolved convention/CloudConventionResolved)
(def InfraResult convention/InfraResult)
(def CloudApp
{:group-specific-config
{s/Keyword (merge InfraResult
user/InfraResult
k8s/InfraResult)}})
(s/defn ^:always-validate
app-configuration-resolved :- CloudApp
[resolved-convention-config :- CloudConventionResolved
& options]
(let [{:keys [group-key] :or {group-key infra/facility}} options]
(mu/deep-merge
(k8s/app-configuration-resolved
(convention/k8s-convention-configuration resolved-convention-config) :group-key group-key)
{:group-specific-config
{group-key
(convention/infra-configuration resolved-convention-config)}})))
(s/defn ^:always-validate
app-configuration :- CloudApp
[convention-config :- CloudConvention
& options]
(let [resolved-convention-config (secret/resolve-secrets convention-config CloudConvention)]
(apply app-configuration-resolved resolved-convention-config options)))
(s/defmethod ^:always-validate
core-app/group-spec infra/facility
[crate-app
convention-config :- CloudConventionResolved]
(let [app-config (app-configuration-resolved convention-config)]
(core-app/pallet-group-spec
app-config [(config-crate/with-config app-config)
user/with-user
k8s/with-k8s
with-cloud])))
(def crate-app (core-app/make-dda-crate-app
:facility infra/facility
:convention-schema CloudConvention
:convention-schema-resolved CloudConventionResolved
:default-convention-file "cloud.edn"))

View file

@ -0,0 +1,93 @@
(ns meissa.pallet.meissa-cloud.convention
(:require
[schema.core :as s]
[dda.pallet.commons.secret :as secret]
[dda.config.commons.map-utils :as mu]
[clojure.spec.alpha :as sp]
[clojure.spec.test.alpha :as st]
[dda.pallet.dda-k8s-crate.convention :as k8s-convention]
[meissa.pallet.meissa-cloud.infra :as infra]
[clojure.string :as str]
[meissa.pallet.meissa-cloud.convention.bash :as bash]
[meissa.pallet.meissa-cloud.convention.bash-php :as bash-php]))
(def InfraResult {infra/facility infra/MeissaCloudInfra})
(s/def CloudConvention
{:user s/Keyword
:external-ip s/Str
:fqdn s/Str
:cert-manager (s/enum :letsencrypt-prod-issuer :letsencrypt-staging-issuer)
:db-user-password secret/Secret
:admin-user s/Str
:admin-password secret/Secret
:storage-size s/Int
:restic-repository s/Str
:aws-access-key-id secret/Secret
:aws-secret-access-key secret/Secret
:restic-password secret/Secret
(s/optional-key :u18-04) (s/enum true)})
(def CloudConventionResolved (secret/create-resolved-schema CloudConvention))
(sp/def ::user keyword?)
(sp/def ::external-ip string?)
(sp/def ::fqdn string?)
(sp/def ::cert-manager #{:letsencrypt-prod-issuer :letsencrypt-staging-issuer})
(sp/def ::db-user-password bash-php/bash-php-env-string?)
(sp/def ::admin-user bash-php/bash-php-env-string?)
(sp/def ::admin-password bash-php/bash-php-env-string?)
(sp/def ::storage-size int?)
(sp/def ::restic-repository string?)
(sp/def ::restic-password bash/bash-env-string?)
(sp/def ::aws-access-key-id bash/bash-env-string?)
(sp/def ::aws-secret-access-key bash/bash-env-string?)
(sp/def ::u18-04 #{true})
(def cloud-convention-resolved? (sp/keys :req-un [::user ::external-ip ::fqdn ::cert-manager
::db-user-password ::admin-user ::admin-password
::storage-size ::restic-repository ::restic-password
::aws-access-key-id ::aws-secret-access-key ]
:opt-un [::u18-04]))
(def cloud-spec-resolved nil)
(s/defn k8s-convention-configuration :- k8s-convention/k8sConventionResolved
[convention-config :- CloudConventionResolved]
{:pre [(sp/valid? cloud-convention-resolved? convention-config)]}
(let [{:keys [cert-manager external-ip user u18-04]} convention-config
cluster-issuer (name cert-manager)]
(if u18-04
{:user user
:k8s {:external-ip external-ip
:u18-04 true}
:cert-manager cert-manager}
{:user user
:k8s {:external-ip external-ip}
:cert-manager cert-manager})))
(s/defn ^:always-validate
infra-configuration :- InfraResult
[convention-config :- CloudConventionResolved]
(let [{:keys [cert-manager fqdn user db-user-password admin-user admin-password storage-size
restic-repository aws-access-key-id aws-secret-access-key restic-password]} convention-config
cluster-issuer (name cert-manager)
db-user-name "cloud"]
{infra/facility
{:user user
:backup {:restic-repository restic-repository
:aws-access-key-id aws-access-key-id
:aws-secret-access-key aws-secret-access-key
:restic-password restic-password}
:cloud {:fqdn fqdn
:secret-name (str/replace fqdn #"\." "-")
:cluster-issuer cluster-issuer
:db-name "cloud"
:db-user-password db-user-password
:db-user-name db-user-name
:admin-user admin-user
:admin-password admin-password
:storage-size (str storage-size)}
:postgres {:db-user-password db-user-password
:db-user-name db-user-name}}}))

View file

@ -0,0 +1,10 @@
(ns meissa.pallet.meissa-cloud.convention.bash
(:require
[clojure.spec.alpha :as s]))
(defn bash-env-string?
[input]
(and (string? input)
(not (re-matches #".*['\"\$]+.*" input))))
(s/def ::plain bash-env-string?)

View file

@ -0,0 +1,11 @@
(ns meissa.pallet.meissa-cloud.convention.bash-php
(:require
[clojure.spec.alpha :as s]
[meissa.pallet.meissa-cloud.convention.bash :as bash]))
(defn bash-php-env-string?
[input]
(and (bash/bash-env-string? input)
(not (re-matches #".*[\-\\\\]+.*" input))))
(s/def ::plain bash-php-env-string?)

View file

@ -0,0 +1,51 @@
(ns meissa.pallet.meissa-cloud.infra
(:require
[schema.core :as s]
[dda.pallet.core.infra :as core-infra]
[meissa.pallet.meissa-cloud.infra.backup :as backup]
[meissa.pallet.meissa-cloud.infra.cloud :as cloud]
[meissa.pallet.meissa-cloud.infra.postgres :as postgres]))
(def facility :meissa-cloud)
(def MeissaCloudInfra
(merge
{:user s/Keyword}
backup/MeissaBackupInfra
cloud/MeissaCloudInfra
postgres/MeissaPostgresInfra))
(s/defmethod core-infra/dda-init facility
[dda-crate config]
(let [facility (:facility dda-crate)
{:keys [user backup postgres cloud]} config
user-str (name user)]
(postgres/init facility user-str postgres)
(cloud/init facility user-str cloud)
(backup/init facility user-str backup)))
(s/defmethod core-infra/dda-install facility
[dda-crate config]
(let [facility (:facility dda-crate)
{:keys [user backup postgres cloud]} config
user-str (name user)]
(postgres/install facility user-str postgres)
(cloud/install facility user-str cloud)
(backup/install facility user-str backup)))
(s/defmethod core-infra/dda-configure facility
[dda-crate config]
(let [facility (:facility dda-crate)
{:keys [user backup postgres cloud]} config
user-str (name user)]
(postgres/configure facility user-str postgres)
(cloud/configure facility user-str cloud)
(backup/configure facility user-str backup)))
(def meissa-cloud
(core-infra/make-dda-crate-infra
:facility facility
:infra-schema MeissaCloudInfra))
(def with-cloud
(core-infra/create-infra-plan meissa-cloud))

View file

@ -0,0 +1,39 @@
(ns meissa.pallet.meissa-cloud.infra.backup
(:require
[schema.core :as s]
[dda.provision :as p]
[dda.provision.pallet :as pp]))
(s/def Backup
{:restic-repository s/Str
:aws-access-key-id s/Str
:aws-secret-access-key s/Str
:restic-password s/Str})
(def MeissaBackupInfra {:backup Backup})
(def backup "backup")
(defn init [facility user config])
(defn install
[facility user config]
(let [facility-name (name facility)]
(p/provision-log ::pp/pallet facility-name backup
::p/info "install")
(p/copy-resources-to-user
::pp/pallet user facility-name backup
[{:filename "backup-secret.yml" :config config}
{:filename "backup-config.yml" :config config}
{:filename "configure-as-user.sh"}
{:filename "backup-restore.yml"}
{:filename "backup-cron.yml"}])))
(defn configure
[facility user config]
(let [facility-name (name facility)]
(p/provision-log ::pp/pallet facility-name backup
::p/info "configure")
(p/exec-file-on-target-as-user
::pp/pallet user facility-name backup "configure-as-user.sh")
))

View file

@ -0,0 +1,57 @@
(ns meissa.pallet.meissa-cloud.infra.cloud
(:require
[schema.core :as s]
[dda.provision :as p]
[dda.provision.pallet :as pp]))
(s/def Cloud
{:fqdn s/Str
:secret-name s/Str
:cluster-issuer s/Str
:db-name s/Str
:db-user-name s/Str
:db-user-password s/Str
:admin-user s/Str
:admin-password s/Str
:storage-size s/Str})
(def MeissaCloudInfra {:cloud Cloud})
(def cloud "cloud")
(defn init
[facility user config]
(let [facility-name (name facility)]
(p/provision-log ::pp/pallet facility-name cloud
::p/info "init")
(p/copy-resources-to-tmp
::pp/pallet facility-name cloud
[{:filename "install-as-root.sh" :config {:user user}}])))
(defn install
[facility user config]
(let [facility-name (name facility)]
(p/provision-log ::pp/pallet facility-name cloud
::p/info "install")
(p/copy-resources-to-user
::pp/pallet user facility-name cloud
[{:filename "pod-running.sh"}
{:filename "cloud-persistent-volume.yml" :config config}
{:filename "cloud-secret.yml" :config config}
{:filename "cloud-service.yml"}
{:filename "cloud-pvc.yml" :config config}
{:filename "cloud-pod.yml" :config config}
{:filename "cloud-ingress.yml" :config config}
{:filename "configure-as-user.sh"}
{:filename "verify.sh" :config config}])
(p/exec-file-on-target-as-root
::pp/pallet facility-name cloud "install-as-root.sh")))
(defn configure
[facility user config]
(let [facility-name (name facility)]
(p/provision-log ::pp/pallet facility-name cloud
::p/info "configure")
(p/exec-file-on-target-as-user
::pp/pallet user facility-name cloud "configure-as-user.sh")))

View file

@ -0,0 +1,47 @@
(ns meissa.pallet.meissa-cloud.infra.postgres
(:require
[schema.core :as s]
[dda.provision :as p]
[dda.provision.pallet :as pp]))
(s/def Postgres {:db-user-name s/Str :db-user-password s/Str})
(def MeissaPostgresInfra {:postgres Postgres})
(def postgres "postgres")
(defn init
[facility user config]
(let [facility-name (name facility)]
(p/provision-log ::pp/pallet facility-name postgres
::p/info "init")
(p/copy-resources-to-tmp
::pp/pallet facility-name postgres
[{:filename "install-as-root.sh" :config {:user user}}])))
(defn install
[facility user config]
(let [facility-name (name facility)]
(p/provision-log ::pp/pallet facility-name postgres
::p/info "install")
(p/copy-resources-to-user
::pp/pallet user facility-name postgres
[{:filename "postgres-persistent-volume.yml"}
{:filename "postgres-secret.yml" :config config}
{:filename "postgres-config.yml"}
{:filename "postgres-service.yml"}
{:filename "postgres-pvc.yml"}
{:filename "postgres-deployment.yml" :config config}
{:filename "configure-as-user.sh"}
{:filename "verify.sh"}])
(p/exec-file-on-target-as-root
::pp/pallet facility-name postgres "install-as-root.sh")))
(defn configure
[facility user config]
(let [facility-name (name facility)]
(p/provision-log ::pp/pallet facility-name postgres
::p/info "configure")
(p/exec-file-on-target-as-user
::pp/pallet user facility-name postgres "configure-as-user.sh")))

View file

@ -1,41 +1,55 @@
(defproject org.domaindrivenarchitecture/c4k-cloud "0.1.3-SNAPSHOT"
:description "cloud c4k-installation package"
:url "https://domaindrivenarchitecture.org"
:license {:name "Apache License, Version 2.0"
:url "https://www.apache.org/licenses/LICENSE-2.0.html"}
:dependencies [[org.clojure/clojure "1.10.3"]
[org.clojure/tools.reader "1.3.4"]
[org.domaindrivenarchitecture/c4k-common-clj "0.2.8"]]
(defproject meissa/meissa-cloud "1.0.2-SNAPSHOT"
:description "Crate to install cloud"
:url "https://meissa-gmbh.de"
:license {:name "meissa commercial license"
:url "https://www.meissa-gmbh.de"}
:dependencies [[dda/dda-pallet "4.0.3"]
[dda/dda-k8s-crate "1.0.1"]
[orchestra "2021.01.01-1"]]
:target-path "target/%s/"
:source-paths ["src/main/cljc"
"src/main/clj"]
:resource-paths ["src/main/resources"]
:repositories [["snapshots" :clojars]
["releases" :clojars]]
:deploy-repositories [["snapshots" :clojars]
["releases" :clojars]]
:profiles {:test {:test-paths ["src/test/cljc"]
:resource-paths ["src/test/resources"]
:dependencies [[dda/data-test "0.1.1"]]}
:dev {:plugins [[lein-shell "0.5.0"]]}
:uberjar {:aot :all
:main dda.c4k-cloud.uberjar
:uberjar-name "c4k-cloud-standalone.jar"
:dependencies [[org.clojure/tools.cli "1.0.206"]
[ch.qos.logback/logback-classic "1.3.0-alpha4"
:exclusions [com.sun.mail/javax.mail]]
:source-paths ["main/src"]
:resource-paths ["main/resources"]
:repositories [["clojars" "https://clojars.org/repo"]
["snapshots"
"https://artifact.prod.meissa-gmbh.de/repository/maven-snapshots/"]
["releases"
"https://artifact.prod.meissa-gmbh.de/repository/maven-releases/"]]
:deploy-repositories [["snapshots" "https://artifact.prod.meissa-gmbh.de/repository/maven-snapshots/"]
["releases" "https://artifact.prod.meissa-gmbh.de/repository/maven-releases/"]]
:profiles {:dev {:source-paths ["integration/src"
"test/src"
"uberjar/src"]
:resource-paths ["integration/resources"
"test/resources"]
:dependencies
[[org.clojure/test.check "1.1.0"]
[dda/data-test "0.1.1"]
[dda/pallet "0.9.1" :classifier "tests"]
[ch.qos.logback/logback-classic "1.3.0-alpha5"]
[org.slf4j/jcl-over-slf4j "2.0.0-alpha1"]]
:plugins
[[lein-sub "0.3.0"]]
:leiningen/reply
{:dependencies [[org.slf4j/jcl-over-slf4j "1.8.0-beta2"]]
:exclusions [commons-logging]}}
:test {:test-paths ["test/src"]
:resource-paths ["test/resources"]
:dependencies [[dda/pallet "0.9.1" :classifier "tests"]]}
:uberjar {:source-paths ["uberjar/src"]
:resource-paths ["uberjar/resources"]
:aot :all
:main meissa.pallet.meissa-cloud.main
:uberjar-name "meissa-cloud-standalone.jar"
:dependencies [[org.clojure/tools.cli "1.0.194"]
[ch.qos.logback/logback-classic "1.3.0-alpha5"]
[org.slf4j/jcl-over-slf4j "2.0.0-alpha1"]]}}
:release-tasks [["test"]
["vcs" "assert-committed"]
:release-tasks [["vcs" "assert-committed"]
["change" "version" "leiningen.release/bump-version" "release"]
["vcs" "commit"]
["vcs" "tag"]
["change" "version" "leiningen.release/bump-version"]]
:aliases {"native" ["shell"
"native-image"
"--report-unsupported-elements-at-runtime"
"--initialize-at-build-time"
"-jar" "target/uberjar/c4k-cloud-standalone.jar"
"-H:ResourceConfigurationFiles=graalvm-resource-config.json"
"-H:Log=registerResource"
"-H:Name=target/graalvm/${:name}"]})
["deploy"]
["uberjar"]
["change" "version" "leiningen.release/bump-version"]
["vcs" "commit"]
["vcs" "push"]]
:local-repo-classpath true)

3
targets.edn Normal file
View file

@ -0,0 +1,3 @@
{:existing [{:node-name "cloud"
:node-ip "168.119.190.126"}]
:provisioning-user {:login "root"}}

View file

@ -0,0 +1,30 @@
{:input {:user :k8s
:external-ip "95.217.221.140"
:fqdn "cloud.test.meissa-gmbh.de"
:cert-manager :letsencrypt-staging-issuer
:db-user-password "test1234"
:admin-user "root"
:admin-password "test1234"
:storage-size 50
:restic-repository "test4321"
:aws-access-key-id "10"
:aws-secret-access-key "secret"
:restic-password "test4321"}
:expected {:meissa-cloud
{:user :k8s
:backup {:restic-repository "test4321"
:aws-access-key-id "10"
:aws-secret-access-key "secret"
:restic-password "test4321"}
:cloud {:fqdn "cloud.test.meissa-gmbh.de"
:secret-name "cloud-test-meissa-gmbh-de"
:cluster-issuer "letsencrypt-staging-issuer"
:db-name "cloud"
:db-user-password "test1234"
:db-user-name "cloud"
:admin-user "root"
:admin-password "test1234"
:storage-size "50"}
:postgres {:db-user-password "test1234"
:db-user-name "cloud"}}}
}

View file

@ -0,0 +1,30 @@
{:input {:user :k8s
:external-ip "95.217.221.140"
:fqdn "cloud.test.meissa-gmbh.de"
:cert-manager :letsencrypt-staging-issuer
:db-user-password "test1234"
:admin-user "root"
:admin-password "test1234"
:storage-size 50
:restic-repository "cloud"
:aws-access-key-id "10"
:aws-secret-access-key "secret"
:restic-password "test4321"}
:expected {:user :k8s, :k8s {:external-ip "95.217.221.140"},
:cert-manager :letsencrypt-staging-issuer}}
{:input {:user :k8s
:external-ip "95.217.221.140"
:fqdn "cloud.test.meissa-gmbh.de"
:cert-manager :letsencrypt-staging-issuer
:db-user-password "test1234"
:admin-user "root"
:admin-password "test1234"
:storage-size 50
:restic-repository "cloud"
:aws-access-key-id "10"
:aws-secret-access-key "secret"
:restic-password "test4321"
:u18-04 true}
:expected {:user :k8s, :k8s {:external-ip "95.217.221.140", :u18-04 true}
:cert-manager :letsencrypt-staging-issuer}}

View file

@ -0,0 +1,14 @@
{:input {:user :k8s
:external-ip "95.217.221.140"
:fqdn "cloud.test.meissa-gmbh.de"
:cert-manager :letsencrypt-staging-issuer
:db-user-password "test1234"
:admin-user "root"
:admin-password "test1234"
:storage-size 50
:restic-repository "test4321"
:aws-access-key-id "10"
:aws-secret-access-key "secret"
:restic-password "test4321"}
:expected true
}

View file

@ -0,0 +1,14 @@
{:input {:user :k8s
:external-ip "95.217.221.140"
:fqdn "cloud.test.meissa-gmbh.de"
:cert-manager :letsencrypt-staging-issuer
:db-user-password "test-1234"
:admin-user "root"
:admin-password "test1234"
:storage-size 50
:restic-repository "test4321"
:aws-access-key-id "10"
:aws-secret-access-key "secret"
:restic-password "test4321"}
:expected false
}

View file

@ -0,0 +1,14 @@
{:input {:user :k8s
:external-ip "95.217.221.140"
:fqdn "cloud.test.meissa-gmbh.de"
:cert-manager :letsencrypt-staging-issuer
:db-user-password "test1234"
:admin-user "root"
:admin-password "test1234"
:storage-size 50
:restic-repository "test4321"
:aws-access-key-id "1$0"
:aws-secret-access-key "secret"
:restic-password "test4321"}
:expected false
}

View file

@ -0,0 +1,31 @@
(ns meissa.pallet.meissa-cloud.app-test
(:require
[clojure.test :refer :all]
[schema.core :as s]
[meissa.pallet.meissa-cloud.app :as sut]))
(s/set-fn-validation! true)
(s/def test-convention-conf
{:user :k8s
:external-ip "12.121.111.121"
:fqdn "some.domain.de"
:cert-manager :letsencrypt-staging-issuer
:db-user-password "test1234"
:admin-user "root"
:admin-password "test1234"
:storage-size 50
:restic-repository "cloud"
:aws-access-key-id "10"
:aws-secret-access-key "secret"
:restic-password "test4321"})
(deftest app-config
(testing
"test plan-def"
(is (map? (sut/app-configuration-resolved test-convention-conf)))))
(deftest plan-def
(testing
"test plan-def"
(is (map? sut/with-cloud))))

View file

@ -0,0 +1,20 @@
(ns meissa.pallet.meissa-cloud.convention.bash-php-test
(:require
[clojure.test :refer :all]
[meissa.pallet.meissa-cloud.convention.bash-php :as sut]))
(deftest test-it
(is (= false
(sut/bash-php-env-string? 4)))
(is (= false
(sut/bash-php-env-string? "hal-lo")))
(is (= false
(sut/bash-php-env-string? "hal--lo")))
(is (= false
(sut/bash-php-env-string? "hal\\lo")))
(is (= true
(sut/bash-php-env-string? "test")))
(is (= true
(sut/bash-php-env-string? "test123")))
)

View file

@ -0,0 +1,22 @@
(ns meissa.pallet.meissa-cloud.convention.bash-test
(:require
[clojure.test :refer :all]
[meissa.pallet.meissa-cloud.convention.bash :as sut]))
(deftest test-it
(is (= false
(sut/bash-env-string? 4)))
(is (= false
(sut/bash-env-string? "1$0")))
(is (= false
(sut/bash-env-string? "'hallo")))
(is (= false
(sut/bash-env-string? "hallo\"")))
(is (= false
(sut/bash-env-string? "hall$o")))
(is (= true
(sut/bash-env-string? "test")))
(is (= true
(sut/bash-env-string? "test123")))
)

View file

@ -0,0 +1,18 @@
(ns meissa.pallet.meissa-cloud.convention-test
(:require
[clojure.test :refer :all]
[data-test :refer :all]
[meissa.pallet.meissa-cloud.convention :as sut]
[clojure.spec.alpha :as sp]))
(defdatatest should-generate-infra-for-convention [input expected]
(is (= expected
(sut/infra-configuration input))))
(defdatatest should-generate-k8s-convention [input expected]
(is (= expected
(sut/k8s-convention-configuration input))))
(defdatatest should-validate-input [input expected]
(is (= expected
(sp/valid? sut/cloud-convention-resolved? input))))

View file

@ -0,0 +1,2 @@
{:existing [{:node-name "localhost"
:node-ip "127.0.0.1"}]}

View file

@ -0,0 +1,50 @@
<configuration scan="true" scanPeriod="1 seconds" debug="false">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>
<appender name="PALLETFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/pallet.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/old/pallet.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>3</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{10} %msg%n</pattern>
</encoder>
</appender>
<logger name="clj-ssh.ssh" level="ERROR">
<appender-ref ref="PALLETFILE" />
</logger>
<logger name="pallet" level="DEBUG">
<appender-ref ref="PALLETFILE" />
</logger>
<logger name="pallet.ssh" level="ERROR">
<appender-ref ref="PALLETFILE" />
</logger>
<logger name="pallet.algo" level="ERROR">
<appender-ref ref="PALLETFILE" />
</logger>
<logger name="dda" level="DEBUG">
<appender-ref ref="PALLETFILE" />
</logger>
<logger name="meissa" level="DEBUG">
<appender-ref ref="PALLETFILE" />
</logger>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</configuration>

View file

@ -0,0 +1,57 @@
(ns meissa.pallet.meissa-cloud.main
(:gen-class)
(:require
[clojure.string :as str]
[clojure.tools.cli :as cli]
[dda.pallet.core.main-helper :as mh]
[dda.pallet.core.app :as core-app]
[meissa.pallet.meissa-cloud.app :as app]))
(def cli-options
[["-h" "--help"]
["-c" "--configure"]
["-t" "--targets example-targets.edn" "edn file containing the targets to install on."
:default "localhost-target.edn"]
["-v" "--verbose"]])
(defn usage [options-summary]
(str/join
\newline
["meissa-cloud installs & configures a single host kubernetes cluster with Cloud installed"
""
"Usage: java -jar meissa-cloud-standalone.jar [options] cloud.edn"
""
"Options:"
options-summary
""
"cloud.edn"
" - follows the edn format."
" - has to be a valid CloudConventionConfig"
""]))
(defn -main [& args]
(let [{:keys [options arguments errors summary help]} (cli/parse-opts args cli-options)
verbose (if (contains? options :verbose) 1 0)]
(cond
help (mh/exit 0 (usage summary))
errors (mh/exit 1 (mh/error-msg errors))
(not= (count arguments) 1) (mh/exit 1 (usage summary))
(:serverspec options) (if (core-app/existing-serverspec
app/crate-app
{:convention (first arguments)
:targets (:targets options)
:verbosity verbose})
(mh/exit-test-passed)
(mh/exit-test-failed))
(:configure options) (if (core-app/existing-configure
app/crate-app
{:convention (first arguments)
:targets (:targets options)})
(mh/exit-default-success)
(mh/exit-default-error))
:default (if (core-app/existing-install
app/crate-app
{:convention (first arguments)
:targets (:targets options)})
(mh/exit-default-success)
(mh/exit-default-error)))))