Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: add support for custom scripts in /docker-entrypoint.d and run custom scripts in order #133

Merged
merged 2 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 40 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
---

- [Voxpupuli Puppet Server container](#voxpupuli-puppet-server-container)
- [Note about environment caching](#note-about-environment-caching)
- [New version schema](#new-version-schema)
- [Configuration](#configuration)
- [Initialization Scripts](#initialization-scripts)
- [Persistance](#persistance)
- [How to Release the container](#how-to-release-the-container)
- [How to contribute](#how-to-contribute)
- [Transfer notice](#transfer-notice)
- [Transfer Notice](#transfer-notice)

---

Expand Down Expand Up @@ -90,42 +91,48 @@ The following environment variables are supported:

| Name | Usage / Default |
|--------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **PUPPETSERVER_HOSTNAME** | The DNS name used on the servers SSL certificate - sets the `server` in puppet.conf<br><br>Defaults to unset. |
| **CERTNAME** | The DNS name used on the servers SSL certificate - sets the `certname` in puppet.conf<br><br>Defaults to unset. |
| **DNS_ALT_NAMES** | Additional DNS names to add to the servers SSL certificate<br>**Note** only effective on initial run when certificates are generated |
| **PUPPETSERVER_PORT** | The port of the puppetserver<br><br>`8140` |
| **AUTOSIGN** | Whether or not to enable autosigning on the puppetserver instance. Valid values are `true`, `false`, and `/path/to/autosign.conf`.<br><br>Defaults to `true`. |
| **CA_ENABLED** | Whether or not this puppetserver instance has a running CA (Certificate Authority)<br><br>`true` |
| **CA_HOSTNAME** | The DNS hostname for the puppetserver running the CA. Does nothing unless `CA_ENABLED=false`<br><br>`puppet` |
| **CA_PORT** | The listening port of the CA. Does nothing unless `CA_ENABLED=false`<br><br>`8140` |
| **CA_ALLOW_SUBJECT_ALT_NAMES** | Whether or not SSL certificates containing Subject Alternative Names should be signed by the CA. Does nothing unless `CA_ENABLED=true`.<br><br>`false` |
| **INTERMEDIATE_CA** | Allows to import an existing intermediate CA. Needs `INTERMEDIATE_CA_BUNDLE`, `INTERMEDIATE_CA_CHAIN` and `INTERMEDIATE_CA_KEY`. See [Puppet Intermediat CA](https://www.puppet.com/docs/puppet/latest/server/intermediate_ca.html) |
| **INTERMEDIATE_CA_BUNDLE** | File path and name to the complete CA bundle (signing CA + Intermediate CA) |
| **INTERMEDIATE_CRL_CHAIN** | File path and name to the complete CA CRL chain |
| **INTERMEDIATE_CA_KEY** | File path and name to the private CA key |
| **PUPPET_REPORTS** | Sets `reports` in puppet.conf<br><br>`puppetdb` |
| **PUPPET_STORECONFIGS** | Sets `storeconfigs` in puppet.conf<br><br>`true` |
| **PUPPET_STORECONFIGS_BACKEND** | Sets `storeconfigs_backend` in puppet.conf<br><br>`puppetdb` |
| **PUPPETSERVER_MAX_ACTIVE_INSTANCES** | The maximum number of JRuby instances allowed<br><br>`1` |
| **PUPPETSERVER_MAX_REQUESTS_PER_INSTANCE** | The maximum HTTP requests a JRuby instance will handle in its lifetime (disable instance flushing)<br><br>`0` |
| **PUPPETSERVER_JAVA_ARGS** | Arguments passed directly to the JVM when starting the service<br><br>`-Xms1024m -Xmx1024m` |
| **USE_PUPPETDB** | Whether to connect to puppetdb<br>Sets `PUPPET_REPORTS` to `log` and `PUPPET_STORECONFIGS` to `false` if those unset<br><br>`true` |
| **PUPPETDB_SERVER_URLS** | The `server_urls` to set in `/etc/puppetlabs/puppet/puppetdb.conf`<br><br>`https://puppetdb:8081` |
| **PUPPETDB_HOSTNAME** | The DNS name of the puppetdb <br><br> Defaults to `puppetdb` |
| **PUPPETDB_SSL_PORT** | The TLS port of the puppetdb <br><br> Defaults to `8081` |
| **PUPPETSERVER_GRAPHITE_EXPORTER_ENABLED** | Activate the graphite exporter. Also needs **PUPPETSERVER_GRAPHITE_HOST** and **PUPPETSERVER_GRAPHITE_PORT**<br><br> Defaults to `false` |
| **PUPPETSERVER_GRAPHITE_HOST** | Only used if **PUPPETSERVER_GRAPHITE_EXPORTER_ENABLED** is set to `true`. FQDN or Hostname of the graphite server where puppet should push metrics to. <br><br> Defaults to `exporter` |
| **PUPPETSERVER_GRAPHITE_PORT** | Only used if **PUPPETSERVER_GRAPHITE_EXPORTER_ENABLED** is set to `true`. Port of the graphite server where puppet should push metrics to. <br><br> Default to `9109` |
| **PUPPETSERVER_ENVIRONMENT_TIMEOUT** | Configure the environment timeout<br><br> Defaults to `unlimited` |
| **PUPPETSERVER_ENABLE_ENV_CACHE_DEL_API** | Enable the puppet admin api endpoint via certificates to allow clearing environment caches<br><br> Defaults to `true` |
| **ENVIRONMENTPATH** | Set an environmentpath<br><br> Defaults to `/etc/puppetlabs/code/environments` |
| **HIERACONFIG** | Set a hiera_config entry in puppet.conf file<br><br> Defaults to `$confdir/hiera.yaml` |
| **CSR_ATTRIBUTES** | Provide a JSON string of the csr_attributes.yaml content. e.g. `CSR_ATTRIBUTES='{"custom_attributes": { "challengePassword": "foobar" }, "extension_requests": { "pp_project": "foo" } }'`<br><br> Defaults to empty JSON object `{}`<br> Please note that within a compose file, you must provide all environment variables as Hash and not as Array!<br> environment:<br> `CSR_ATTRIBUTES: '{"extension_request": {...}}'` |
| __PUPPETSERVER_HOSTNAME__ | The DNS name used on the servers SSL certificate - sets the `server` in puppet.conf<br><br>Defaults to unset. |
| __CERTNAME__ | The DNS name used on the servers SSL certificate - sets the `certname` in puppet.conf<br><br>Defaults to unset. |
| __DNS_ALT_NAMES__ | Additional DNS names to add to the servers SSL certificate<br>__Note__ only effective on initial run when certificates are generated |
| __PUPPETSERVER_PORT__ | The port of the puppetserver<br><br>`8140` |
| __AUTOSIGN__ | Whether or not to enable autosigning on the puppetserver instance. Valid values are `true`, `false`, and `/path/to/autosign.conf`.<br><br>Defaults to `true`. |
| __CA_ENABLED__ | Whether or not this puppetserver instance has a running CA (Certificate Authority)<br><br>`true` |
| __CA_HOSTNAME__ | The DNS hostname for the puppetserver running the CA. Does nothing unless `CA_ENABLED=false`<br><br>`puppet` |
| __CA_PORT__ | The listening port of the CA. Does nothing unless `CA_ENABLED=false`<br><br>`8140` |
| __CA_ALLOW_SUBJECT_ALT_NAMES__ | Whether or not SSL certificates containing Subject Alternative Names should be signed by the CA. Does nothing unless `CA_ENABLED=true`.<br><br>`false` |
| __INTERMEDIATE_CA__ | Allows to import an existing intermediate CA. Needs `INTERMEDIATE_CA_BUNDLE`, `INTERMEDIATE_CA_CHAIN` and `INTERMEDIATE_CA_KEY`. See [Puppet Intermediat CA](https://www.puppet.com/docs/puppet/latest/server/intermediate_ca.html) |
| __INTERMEDIATE_CA_BUNDLE__ | File path and name to the complete CA bundle (signing CA + Intermediate CA) |
| __INTERMEDIATE_CRL_CHAIN__ | File path and name to the complete CA CRL chain |
| __INTERMEDIATE_CA_KEY__ | File path and name to the private CA key |
| __PUPPET_REPORTS__ | Sets `reports` in puppet.conf<br><br>`puppetdb` |
| __PUPPET_STORECONFIGS__ | Sets `storeconfigs` in puppet.conf<br><br>`true` |
| __PUPPET_STORECONFIGS_BACKEND__ | Sets `storeconfigs_backend` in puppet.conf<br><br>`puppetdb` |
| __PUPPETSERVER_MAX_ACTIVE_INSTANCES__ | The maximum number of JRuby instances allowed<br><br>`1` |
| __PUPPETSERVER_MAX_REQUESTS_PER_INSTANCE__ | The maximum HTTP requests a JRuby instance will handle in its lifetime (disable instance flushing)<br><br>`0` |
| __PUPPETSERVER_JAVA_ARGS__ | Arguments passed directly to the JVM when starting the service<br><br>`-Xms1024m -Xmx1024m` |
| __USE_PUPPETDB__ | Whether to connect to puppetdb<br>Sets `PUPPET_REPORTS` to `log` and `PUPPET_STORECONFIGS` to `false` if those unset<br><br>`true` |
| __PUPPETDB_SERVER_URLS__ | The `server_urls` to set in `/etc/puppetlabs/puppet/puppetdb.conf`<br><br>`https://puppetdb:8081` |
| __PUPPETDB_HOSTNAME__ | The DNS name of the puppetdb <br><br> Defaults to `puppetdb` |
| __PUPPETDB_SSL_PORT__ | The TLS port of the puppetdb <br><br> Defaults to `8081` |
| __PUPPETSERVER_GRAPHITE_EXPORTER_ENABLED__ | Activate the graphite exporter. Also needs __PUPPETSERVER_GRAPHITE_HOST__ and __PUPPETSERVER_GRAPHITE_PORT__<br><br> Defaults to `false` |
| __PUPPETSERVER_GRAPHITE_HOST__ | Only used if __PUPPETSERVER_GRAPHITE_EXPORTER_ENABLED__ is set to `true`. FQDN or Hostname of the graphite server where puppet should push metrics to. <br><br> Defaults to `exporter` |
| __PUPPETSERVER_GRAPHITE_PORT__ | Only used if __PUPPETSERVER_GRAPHITE_EXPORTER_ENABLED__ is set to `true`. Port of the graphite server where puppet should push metrics to. <br><br> Default to `9109` |
| __PUPPETSERVER_ENVIRONMENT_TIMEOUT__ | Configure the environment timeout<br><br> Defaults to `unlimited` |
| __PUPPETSERVER_ENABLE_ENV_CACHE_DEL_API__ | Enable the puppet admin api endpoint via certificates to allow clearing environment caches<br><br> Defaults to `true` |
| __ENVIRONMENTPATH__ | Set an environmentpath<br><br> Defaults to `/etc/puppetlabs/code/environments` |
| __HIERACONFIG__ | Set a hiera_config entry in puppet.conf file<br><br> Defaults to `$confdir/hiera.yaml` |
| __CSR_ATTRIBUTES__ | Provide a JSON string of the csr_attributes.yaml content. e.g. `CSR_ATTRIBUTES='{"custom_attributes": { "challengePassword": "foobar" }, "extension_requests": { "pp_project": "foo" } }'`<br><br> Defaults to empty JSON object `{}`<br> Please note that within a compose file, you must provide all environment variables as Hash and not as Array!<br> environment:<br> `CSR_ATTRIBUTES: '{"extension_request": {...}}'` |

## Initialization Scripts

If you would like to do additional initialization, add a directory called `/docker-custom-entrypoint.d/` and fill it with `.sh` scripts.
These scripts will be executed at the end of the entrypoint script, before the service is ran.

You can also create sub-directories in `/docker-custom-entrypoint.d/` for scripts that have to run at different stages.

- `/docker-custom-entrypoint.d/` - scripts that run after the default entrypoint scripts, but before the puppetserver service is started.
- `/docker-custom-entrypoint.d/post-startup/` - scripts that run after the puppetserver service is started.
- `/docker-custom-entrypoint.d/sigterm-handler/` - scripts that run when the container receives a SIGTERM signal.
- `/docker-custom-entrypoint.d/post-execution/` - scripts that run after the puppetserver service has stopped.

## Persistance

Expand Down
118 changes: 108 additions & 10 deletions puppetserver/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,117 @@
#!/bin/bash
# bash is required to pass ENV vars with dots as sh cannot

set -e
set -o errexit # exit on any command failure; use `whatever || true` to accept failures
# use `if something; then` instead of `something; if [ $? -eq 0 ]; then`
# use `rv=0; something || rv=$?` if you really need the exact exit code
set -o pipefail # pipes fail when any command fails, not just the last one. Use: ( whatever || true ) | somethingelse
set -o nounset # exit on use of undeclared var, use `${possibly_undefined-}` to substitute the empty string in that case
# You can assign default values like this:
# `: ${possibly_undefined=default}`
# `: ${possibly_undefined_or_empty:=default}` will also replace an empty (but declared) value
# set -o xtrace

for f in /docker-entrypoint.d/*.sh; do
pid=0

echoerr() { echo "$@" 1>&2; }

echoerr "Entrypoint PID $$"

## Pre execution handler
pre_execution_handler() {
for f in /docker-entrypoint.d/*.sh; do
echo "Running $f"
"$f"
done

if [ -d /docker-custom-entrypoint.d/ ]; then
done
if [ -d /docker-custom-entrypoint.d/ ]; then
find /docker-custom-entrypoint.d/ -type f -name "*.sh" \
-exec chmod +x {} \;
-exec chmod +x {} \;
sync
find /docker-custom-entrypoint.d/ -type f -name "*.sh" \
-exec echo Running {} \; -exec {} \;
fi
for f in /docker-custom-entrypoint.d/*.sh; do
echo "Running $f"
"$f"
done
fi
}

## Post startup handler
post_startup_handler() {
if [ -d /docker-custom-entrypoint.d/ ]; then
if [ -d /docker-custom-entrypoint.d/post-startup/ ]; then
find /docker-custom-entrypoint.d/post-startup/ -type f -name "*.sh" \
-exec chmod +x {} \;
sync
for f in /docker-custom-entrypoint.d/post-startup/*.sh; do
echo "Running $f"
"$f"
done
fi
fi
}

## Post execution handler
post_execution_handler() {
if [ -d /docker-custom-entrypoint.d/ ]; then
if [ -d /docker-custom-entrypoint.d/post-execution/ ]; then
find /docker-custom-entrypoint.d/post-execution/ -type f -name "*.sh" \
-exec chmod +x {} \;
sync
for f in /docker-custom-entrypoint.d/post-execution/*.sh; do
echo "Running $f"
"$f"
done
fi
fi
}

## Sigterm Handler
sigterm_handler() {
echoerr "Catching SIGTERM"
if [ $pid -ne 0 ]; then
echoerr "sigterm_handler for PID '${pid}' triggered"
# the above if statement is important because it ensures
# that the application has already started. without it you
# could attempt cleanup steps if the application failed to
# start, causing errors.
if [ -d /docker-custom-entrypoint.d/ ]; then
if [ -d /docker-custom-entrypoint.d/sigterm-handler/ ]; then
find /docker-custom-entrypoint.d/sigterm-handler/ -type f -name "*.sh" \
-exec chmod +x {} \;
sync
for f in /docker-custom-entrypoint.d/sigterm-handler/*.sh; do
echo "Running $f"
"$f"
done
fi
fi
kill -15 "$pid"
wait "$pid"
post_execution_handler
fi
exit 143; # 128 + 15 -- SIGTERM
}

## Setup signal trap
# on callback execute the specified handler
trap sigterm_handler SIGTERM

## Initialization
pre_execution_handler

## Start Process
echoerr "Starting Puppetserver"
# run process in background and record PID
/opt/puppetlabs/bin/puppetserver "$@" &
pid="$!"

## Post Startup
post_startup_handler

## Wait forever until app dies
wait "$pid"
return_code="$?"

exec /opt/puppetlabs/bin/puppetserver "$@"
## Cleanup
post_execution_handler
# echo the return code of the application
exit $return_code
Loading