initial commit

This commit is contained in:
Jose Diaz-Gonzalez
2015-08-23 18:56:11 -04:00
commit 1fcd7dee4a
8 changed files with 517 additions and 0 deletions

16
.editorconfig Normal file
View File

@@ -0,0 +1,16 @@
root = true
[*]
insert_final_newline = true
indent_style = space
indent_size = 2
[Makefile]
insert_final_newline = true
indent_style = tab
indent_size = 4
[*.mk]
insert_final_newline = true
indent_style = tab
indent_size = 4

7
LICENSE.txt Normal file
View File

@@ -0,0 +1,7 @@
Copyright (C) 2015 Jose Diaz-Gonzalez
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

95
README.md Normal file
View File

@@ -0,0 +1,95 @@
# dokku mysql (beta)
Official mysql plugin for dokku. Currently installs mysql 5.7.
## requirements
- dokku 0.3.25+
- docker 1.6.x
## installation
```
cd /var/lib/dokku/plugins
git clone https://github.com/dokku/dokku-mysql-plugin.git mysql
dokku plugins-install-dependencies
dokku plugins-install
```
## commands
```
mysql:alias <name> <alias> Set an alias for the docker link
mysql:clone <name> <new-name> NOT IMPLEMENTED
mysql:connect <name> Connect via mysql to a mysql service
mysql:create <name> Create a mysql service
mysql:destroy <name> Delete the service and stop its container if there are no links left
mysql:export <name> Export a dump of the mysql service database
mysql:expose <name> <port> NOT IMPLEMENTED
mysql:import <name> <file> NOT IMPLEMENTED
mysql:info <name> Print the connection information
mysql:link <name> <app> Link the mysql service to the app
mysql:list List all mysql services
mysql:logs <name> [-t] Print the most recent log(s) for this service
mysql:restart <name> Graceful shutdown and restart of the service container
mysql:unexpose <name> <port> NOT IMPLEMENTED
mysql:unlink <name> <app> Unlink the mysql service from the app
```
## usage
```shell
# create a mysql service named lolipop
dokku mysql:create lolipop
# you can also specify the image and image
# version to use for the service
# it *must* be compatible with the
# official mysql image
export MYSQL_IMAGE="mysql"
export MYSQL_IMAGE_VERSION="5.5"
dokku mysql:create lolipop
# get connection information as follows
dokku mysql:info lolipop
# lets assume the ip of our mysql service is 172.17.0.1
# a mysql service can be linked to a
# container this will use native docker
# links via the docker-options plugin
# here we link it to our 'playground' app
# NOTE: this will restart your app
dokku mysql:link lolipop playground
# the above will expose the following environment variables
#
# DATABASE_URL=mysql://mysql:SOME_PASSWORD@172.17.0.1:3306/lolipop
# DATABASE_NAME=/playground/DATABASE
# DATABASE_PORT=tcp://172.17.0.1:3306
# DATABASE_PORT_3306_TCP=tcp://172.17.0.1:3306
# DATABASE_PORT_3306_TCP_PROTO=tcp
# DATABASE_PORT_3306_TCP_PORT=3306
# DATABASE_PORT_3306_TCP_ADDR=172.17.0.1
# you can customize the environment
# variables through a custom docker link alias
dokku mysql:alias lolipop MYSQL_DATABASE
# you can also unlink a mysql service
# NOTE: this will restart your app
dokku mysql:unlink lolipop playground
# you can tail logs for a particular service
dokku mysql:logs lolipop
dokku mysql:logs lolipop -t # to tail
# finally, you can destroy the container
dokku mysql:destroy playground
```
## todo
- implement mysql:clone
- implement mysql:expose
- implement mysql:import

286
commands Executable file
View File

@@ -0,0 +1,286 @@
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
source "$(dirname "$0")/../common/functions"
source "$(dirname "$0")/functions"
MYSQL_IMAGE=${MYSQL_IMAGE:="mysql"}
MYSQL_IMAGE_VERSION=${MYSQL_IMAGE_VERSION:="5.7"}
MYSQL_ROOT=/var/lib/dokku/services/mysql
PLUGIN_COMMAND_PREFIX="mysql"
PLUGIN_DATA_ROOT=$MYSQL_ROOT
PLUGIN_SERVICE="MySQL"
PLUGIN_IMAGE=$MYSQL_IMAGE
PLUGIN_IMAGE_VERSION=$MYSQL_IMAGE_VERSION
if [[ ! -d $PLUGIN_DATA_ROOT ]]; then
dokku_log_fail "$PLUGIN_SERVICE: Please run: sudo dokku plugins-install"
fi
if ! command -v mysql &>/dev/null; then
dokku_log_fail "$PLUGIN_SERVICE: Please run: sudo dokku plugins-install-dependencies"
fi
if ! command -v mysqldump &>/dev/null; then
dokku_log_fail "$PLUGIN_SERVICE: Please run: sudo dokku plugins-install-dependencies"
fi
case "$1" in
$PLUGIN_COMMAND_PREFIX:alias)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
[[ -z $3 ]] && dokku_log_fail "Please specify an alias for the service"
verify_service_name "$2"
SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"; ALIAS_FILE="$SERVICE_ROOT/ALIAS"
mkdir -p "$SERVICE_ROOT" || dokku_log_fail "Unable to create service directory"
touch "$ALIAS_FILE"
echo "$3" > "$ALIAS_FILE"
;;
$PLUGIN_COMMAND_PREFIX:create)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
[[ ! -d "$PLUGIN_DATA_ROOT/$2" ]] || dokku_log_fail "$PLUGIN_SERVICE service $2 already exists"
SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"; LINKS_FILE="$SERVICE_ROOT/LINKS"
if ! docker images | grep -e "^$PLUGIN_IMAGE " | grep -q " $PLUGIN_IMAGE_VERSION " ; then
dokku_log_fail "$PLUGIN_SERVICE image $PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION not found"
fi
mkdir -p "$SERVICE_ROOT" || dokku_log_fail "Unable to create service directory"
mkdir -p "$SERVICE_ROOT/data" || dokku_log_fail "Unable to create service data directory"
rootpassword=$(date +%s | sha256sum | base64 | head -c 16)
password=$(date +%s | sha256sum | base64 | head -c 16)
echo "$rootpassword" > "$SERVICE_ROOT/ROOTPASSWORD"
echo "$password" > "$SERVICE_ROOT/PASSWORD"
touch "$LINKS_FILE"
dokku_log_info1 "Starting container"
ID=$(docker run --name "dokku.mysql.$SERVICE" -v "$SERVICE_ROOT/data:/var/lib/mysql" -e "MYSQL_ROOT_PASSWORD=$rootpassword" -e MYSQL_USER=mysql -e "MYSQL_PASSWORD=$password" -e "MYSQL_DATABASE=$SERVICE" -d "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION")
echo "$ID" > "$SERVICE_ROOT/ID"
dokku_log_verbose_quiet "Waiting for container to be ready"
sleep 10
dokku_log_info2 "$PLUGIN_SERVICE container created: $SERVICE"
dokku "$PLUGIN_COMMAND_PREFIX:info" "$SERVICE"
;;
$PLUGIN_COMMAND_PREFIX:destroy)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"; LINKS_FILE="$SERVICE_ROOT/LINKS"
[[ -s "$LINKS_FILE" ]] && dokku_log_fail "Cannot delete linked service"
[[ "$3" == "force" ]] && DOKKU_APPS_FORCE_DELETE=1
if [[ -z "$DOKKU_APPS_FORCE_DELETE" ]]; then
dokku_log_warn "WARNING: Potentially Destructive Action"
dokku_log_warn "This command will destroy $SERVICE $PLUGIN_SERVICE service."
dokku_log_warn "To proceed, type \"$SERVICE\""
echo ""
read -p "> " service_name
if [[ "$service_name" != "$SERVICE" ]]; then
dokku_log_warn "Confirmation did not match $SERVICE. Aborted."
exit 1
fi
fi
dokku_log_info1 "Deleting $SERVICE"
if [[ -f "$SERVICE_ROOT/ID" ]]; then
ID=$(cat "$SERVICE_ROOT/ID")
dokku_log_verbose_quiet "Deleting container data"
docker exec -it "$ID" chmod -R 777 /var/lib/mysql
dokku_log_verbose_quiet "Stopping container"
docker stop "$ID" > /dev/null
docker kill "$ID" > /dev/null
sleep 1
dokku_log_verbose_quiet "Removing container"
docker rm -v "$ID" > /dev/null
sleep 1
fi
dokku_log_verbose_quiet "Removing data"
rm -rf "$SERVICE_ROOT"
dokku_log_info2 "$PLUGIN_SERVICE container deleted: $SERVICE"
;;
$PLUGIN_COMMAND_PREFIX:link)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
[[ -z $3 ]] && dokku_log_fail "Please specify an app to run the command on"
verify_app_name "$3"
verify_service_name "$2"
APP="$3"; SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"; LINKS_FILE="$SERVICE_ROOT/LINKS"
mkdir -p "$SERVICE_ROOT" || dokku_log_fail "Unable to create service directory"
touch "$LINKS_FILE"
echo "$APP" >> "$LINKS_FILE"
sort "$LINKS_FILE" -u -o "$LINKS_FILE"
dokku_log_info1 "Restarting app $APP"
dokku ps:restart "$APP"
;;
$PLUGIN_COMMAND_PREFIX:unlink)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
[[ -z $3 ]] && dokku_log_fail "Please specify an app to run the command on"
verify_app_name "$3"
verify_service_name "$2"
APP="$3"; SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"; LINKS_FILE="$SERVICE_ROOT/LINKS"
mkdir -p "$SERVICE_ROOT" || dokku_log_fail "Unable to create service directory"
touch "$LINKS_FILE"
sed -i "/^$3\$/d" "$LINKS_FILE"
sort "$LINKS_FILE" -u -o "$LINKS_FILE"
dokku_log_info1 "Restarting app $APP"
dokku ps:restart "$APP"
;;
$PLUGIN_COMMAND_PREFIX:export)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
PASSWORD=$(cat "$SERVICE_ROOT/PASSWORD")
IP=$(get_container_ip "$ID")
mysqldump --host "$IP" --port 3306 --user mysql --password "$PASSWORD" "$SERVICE"
;;
$PLUGIN_COMMAND_PREFIX:import)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"
dokku_log_fail "Not yet implemented"
;;
$PLUGIN_COMMAND_PREFIX:logs)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
ID=$(cat "$SERVICE_ROOT/ID")
if [[ $3 == "-t" ]]; then
DOKKU_LOGS_ARGS="--follow"
else
DOKKU_LOGS_ARGS="--tail 100"
fi
docker logs "$DOKKU_LOGS_ARGS" "$ID"
;;
$PLUGIN_COMMAND_PREFIX:restart)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
ID=$(cat "$SERVICE_ROOT/ID")
docker restart --time=10 "$ID"
dokku_log_info1 "Please call dokku ps:restart on all linked apps"
;;
$PLUGIN_COMMAND_PREFIX:connect)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
ID=$(cat "$SERVICE_ROOT/ID")
IP=$(get_container_ip "$ID")
PASSWORD=$(cat "$SERVICE_ROOT/PASSWORD")
mysql --host "$IP" --port 3306 --user mysql -password "$PASSWORD"
;;
$PLUGIN_COMMAND_PREFIX:info)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"; SERVICE_URL=$(service_url "$SERVICE")
echo " DSN: $SERVICE_URL"
;;
$PLUGIN_COMMAND_PREFIX:list)
CONTAINERS=$(ls $PLUGIN_DATA_ROOT 2> /dev/null)
if [[ -z $CONTAINERS ]]; then
echo "There are no $PLUGIN_SERVICE services"
else
echo "$PLUGIN_SERVICE services:"
for CONTAINER in $CONTAINERS; do
echo " - $CONTAINER"
done
fi
;;
$PLUGIN_COMMAND_PREFIX:clone)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"
dokku_log_fail "Not yet implemented"
;;
$PLUGIN_COMMAND_PREFIX:expose)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"; PORT_FILE="$SERVICE_ROOT/PORT"; DESTINATION_FILE="$SERVICE_ROOT/IPTABLES_DESTINATION"
[[ -f "$PORT_FILE" ]] && PORT=$(cat "$PORT_FILE") && dokku_log_fail "Service $SERVICE already exposed on port $PORT"
ID=$(cat "$SERVICE_ROOT/ID")
IP=$(get_container_ip "$ID")
PORT=$(get_random_port)
echo "$PORT" > "$PORT_FILE"
echo "$IP:3306" > "$DESTINATION_FILE"
iptables -t nat -A DOCKER -p tcp --dport "$PORT" -j DNAT --to-destination "$IP:3306"
dokku_log_info1 "Service $SERVICE exposed on port $PORT"
;;
$PLUGIN_COMMAND_PREFIX:unexpose)
[[ -z $2 ]] && dokku_log_fail "Please specify a name for the service"
verify_service_name "$2"
SERVICE="$2"; SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"; PORT_FILE="$SERVICE_ROOT/PORT"; DESTINATION_FILE="$SERVICE_ROOT/IPTABLES_DESTINATION"
[[ ! -f "$PORT_FILE" ]] && dokku_log_fail "Service not exposed"
ID=$(cat "$SERVICE_ROOT/ID")
IP=$(get_container_ip "$ID")
PORT=$(cat "$PORT_FILE")
DESTINATION=$(cat "$DESTINATION_FILE")
iptables -t nat -D DOCKER -p tcp --dport "$PORT" -j DNAT --to-destination "$DESTINATION"
rm -rf "$PORT_FILE"
;;
help)
cat && cat<<EOF
$PLUGIN_COMMAND_PREFIX:alias <name> <alias>, Set an alias for the docker link
$PLUGIN_COMMAND_PREFIX:create <name>, Create a $PLUGIN_SERVICE service
$PLUGIN_COMMAND_PREFIX:destroy <name>, Delete the $PLUGIN_SERVICE service and stop its container if there are no links left
$PLUGIN_COMMAND_PREFIX:link <name> <app>, Link the $PLUGIN_SERVICE service to the app
$PLUGIN_COMMAND_PREFIX:unlink <name> <app>, Unlink the $PLUGIN_SERVICE service from the app
$PLUGIN_COMMAND_PREFIX:export <name>, Export a dump of the $PLUGIN_SERVICE service database
$PLUGIN_COMMAND_PREFIX:import <name> <file>, NOT IMPLEMENTED
$PLUGIN_COMMAND_PREFIX:connect <name>, Connect via mysql to a $PLUGIN_SERVICE service
$PLUGIN_COMMAND_PREFIX:logs <name> [-t], Print the most recent log(s) for this service
$PLUGIN_COMMAND_PREFIX:restart <name>, Graceful shutdown and restart of the service container
$PLUGIN_COMMAND_PREFIX:info <name>, Print the connection information
$PLUGIN_COMMAND_PREFIX:list, List all $PLUGIN_SERVICE services
$PLUGIN_COMMAND_PREFIX:clone <name> <new-name>, NOT IMPLEMENTED
$PLUGIN_COMMAND_PREFIX:expose <name> <port>, NOT IMPLEMENTED
$PLUGIN_COMMAND_PREFIX:unexpose <name> <port>, NOT IMPLEMENTED
EOF
;;
*)
exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
;;
esac

14
dependencies Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
case "$DOKKU_DISTRO" in
ubuntu)
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" --force-yes -qq -y mysql-client-5.5
;;
opensuse)
zypper -q in -y mysql-client
;;
esac

27
docker-args Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
source "$(dirname "$0")/../common/functions"
source "$(dirname "$0")/functions"
STDIN=$(cat)
APP="$1"
PLUGIN_DATA_ROOT=/var/lib/dokku/services/mysql
output=""
for i in $PLUGIN_DATA_ROOT/*; do
[[ -d $i ]] || continue
SERVICE=$(echo "$i" | cut -d'/' -f 7)
LINKS_FILE="$PLUGIN_DATA_ROOT/$SERVICE/LINKS"
ALIAS="$(service_alias "$SERVICE")"
SERVICE_URL="$(service_url "$SERVICE")"
if [[ -f "$LINKS_FILE" ]]; then
while read line; do
if [[ "$line" == "$APP" ]]; then
output="$output --link dokku.mysql.$SERVICE:$ALIAS --env ${ALIAS}_URL=$SERVICE_URL"
break
fi
done < "$LINKS_FILE"
fi
done
echo "$STDIN$output"

54
functions Executable file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
PLUGIN_DATA_ROOT=/var/lib/dokku/services/mysql
PLUGIN_SERVICE="MySQL"
get_random_port() {
local port=$RANDOM
local quit=0
while [ "$quit" -ne 1 ]; do
netstat -a | grep $port >> /dev/null
if [ $? -gt 0 ]; then
quit=1
else
port=$((port + 1))
fi
done
echo $port
}
get_container_ip() {
docker inspect --format '{{ .NetworkSettings.IPAddress }}' "$1"
}
verify_service_name() {
local SERVICE="$1"
[[ ! -n "$SERVICE" ]] && dokku_log_fail "(verify_service_name) SERVICE must not be null"
[[ ! -d "$PLUGIN_DATA_ROOT/$SERVICE" ]] && dokku_log_fail "$PLUGIN_SERVICE service $SERVICE does not exist"
return 0
}
service_alias() {
local SERVICE="$1"
local ALIAS_FILE="$PLUGIN_DATA_ROOT/$SERVICE/ALIAS"
verify_service_name "$1"
if [[ -f "$ALIAS_FILE" ]]; then
cat "$ALIAS_FILE"
else
echo "DATABASE"
fi
}
service_url() {
local SERVICE="$1";
local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
verify_service_name "$1"
local ID="$(cat "$SERVICE_ROOT/ID")"
local IP="$(get_container_ip "$ID")"
local PASSWORD="$(cat "$SERVICE_ROOT/PASSWORD")"
echo "mysql://mysql:$PASSWORD@$IP:3306/$SERVICE"
}

18
install Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
MYSQL_IMAGE="mysql"
MYSQL_IMAGE_VERSION=5.7
MYSQL_ROOT=/var/lib/dokku/services/mysql
PLUGIN_DATA_ROOT=$MYSQL_ROOT
PLUGIN_SERVICE="MySQL"
PLUGIN_IMAGE=$MYSQL_IMAGE
PLUGIN_IMAGE_VERSION=$MYSQL_IMAGE_VERSION
if ! docker images | grep -e "^$PLUGIN_IMAGE " | grep -q $PLUGIN_IMAGE_VERSION ; then
docker pull $PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION
fi
mkdir -p $PLUGIN_DATA_ROOT || echo "Failed to create $PLUGIN_SERVICE directory"
chown dokku:dokku $PLUGIN_DATA_ROOT