Skip to content

Commit

Permalink
Merge pull request #1 from codefresh-io/real-template
Browse files Browse the repository at this point in the history
Real template
  • Loading branch information
kosta709 authored Apr 19, 2017
2 parents 684fe91 + c9fe4bc commit 2cd26a2
Show file tree
Hide file tree
Showing 4 changed files with 256 additions and 21 deletions.
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ RUN tar xf "${GCLOUD_SDK_FILENAME}" && \
/google-cloud-sdk/bin/gcloud components install -q kubectl;

ADD cf-deploy-kubernetes.sh /cf-deploy-kubernetes
ADD template.sh /template.sh

# Set the default path to include all the commands
RUN \
ln -s /google-cloud-sdk/bin/kubectl /usr/local/bin/kubectl && \
chmod +x /cf-deploy-kubernetes
chmod +x /cf-deploy-kubernetes && \
chmod +x /template.sh

CMD ["bash"]

66 changes: 57 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
This is the source code for the `codefresh/cf-deploy-kubernetes` container.
This container is used to demonstrate a Kubernetes deployment using Codefresh.io

For a complete example, check:
https://github.com/codefresh-io/cf-deploy-kubernetes-demo

# Assumptions

The deployment script makes the following assumptions about your application and
Expand All @@ -14,9 +11,10 @@ Kubernetes configuration:
1. The application is deployed using the Kubernetes deployment API (versus the
the replication controller directly). For more information read
http://kubernetes.io/docs/user-guide/deployments/
2. The tested codebase has a yaml file that describes the Kubernetes deployment
2. The tested codebase has a yaml file (i.e. deployment.yml) that describes the Kubernetes deployment
parameters and configuration of your application.
3. At the moment, only the basic username/pass authentication is supported.
3. The script processes deployment.yml as a simple template where all `{{ ENV_VARIABLE }}` are replaced with a value of $ENV_VARIABLE deployment.yml
4. At the moment, only the basic username/pass authentication is supported.

# Configuration

Expand All @@ -28,9 +26,59 @@ before failing the build. Defaults to 120 (secs).
3. KUBERNETES_PASSWORD - The password for the Kubernetes cluster. Mandatory.
4. KUBERNETES_SERVER - The server (HTTPS endpoint) of the Kubernetes cluster's
API. Mandatory.
5. DOCKER_IMAGE_TAG - The docker tag to use for the deployment. Requires the
`deployment.yml` file to specify a `$DOCKER_IMAGE_TAG` variable so it can be
substitutes at deployment time.
6. FORCE_RE_CREATE_RESOURCE - Will force re-creation of the deployment

# Usage in codefresh.io

### deployment.yml

```yaml
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: api-svc
spec:
replicas: 1
template:
metadata:
annotations:
revision: "{{CF_REVISION}}"
labels:
app: api-svc
spec:
containers:
- name: apisvc
image: myrepo/apisvc:{{CF_BRANCH}}
ports:
- containerPort: 80
name: http

```

### codefresh.yml
```yaml
---
version: '1.0'

steps:
build:
type: build
working-directory: ${{initial-clone}}
image-name: $docker-image
tag: ${{CF_BRANCH}}
push:
type: push
candidate: ${{build}}
tag: ${{CF_BRANCH}}

deploy-to-kubernetes:
image: codefresh/cf-deploy-kubernetes
tag: latest
working-directory: ${{initial-clone}}
commands:
- /cf-deploy-kubernetes deployment.yml
environment:
- KUBERNETES_USER=${{KUBERNETES_USER}}
- KUBERNETES_PASSWORD=${{KUBERNETES_PASSWORD}}
- KUBERNETES_SERVER=${{KUBERNETES_SERVER}}
```
23 changes: 12 additions & 11 deletions cf-deploy-kubernetes.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#!/bin/bash

fatal() {
echo "ERROR: $1"
exit 1
}

readonly DEFAULT_NAMESPACE=default

deployment_file=${1:-deployment.yml}
Expand All @@ -9,11 +14,13 @@ deployment_file=${1:-deployment.yml}
[ -z "$KUBERNETES_USER" ] && echo "Please set KUBERNETES_USER" && exit 1;
[ -z "$KUBERNETES_PASSWORD" ] && echo "Please set KUBERNETES_PASSWORD" && exit 1;
[ -z "$KUBERNETES_SERVER" ] && echo "Please set KUBERNETES_SERVER" && exit 1;
[ -z "$DOCKER_IMAGE_TAG" ] && echo "Please set DOCKER_IMAGE_TAG" && exit 1;
# [ -z "$DOCKER_IMAGE_TAG" ] && echo "Please set DOCKER_IMAGE_TAG" && exit 1;

[ ! -f "${deployment_file}" ] && echo "Couldn't find $deployment_file file at $(pwd)" && exit 1;
sed -i "s/\$DOCKER_IMAGE_TAG/$DOCKER_IMAGE_TAG/g" $deployment_file
sed -i "s/\$UNIQ_ID/$(date '+%y-%m-%d_%H:%M:%S')/g" $deployment_file


DEPLOYMENT_FILE=${deployment_file}-$(date '+%y-%m-%d_%H-%M-%S').yml
$(dirname $0)/template.sh "$deployment_file" > "$DEPLOYMENT_FILE" || fatal "Failed to apply deployment template on $deployment_file"


echo "---> Setting up Kubernetes credentials..."
Expand All @@ -22,15 +29,9 @@ kubectl config set-cluster foo.kubernetes.com --insecure-skip-tls-verify=true --
kubectl config set-context foo.kubernetes.com/deployer --user=deployer --namespace=$DEFAULT_NAMESPACE --cluster=foo.kubernetes.com
kubectl config use-context foo.kubernetes.com/deployer

echo "---> Submittinig a deployment to Kubernetes..."
kubectl apply -f "$DEPLOYMENT_FILE" || fatal "Deployment Failed"

# Check if the cloned dir already exists from previous builds
if [ "$FORCE_RE_CREATE_RESOURCE" == "true" ]; then
echo "---> Submittinig a deployment to Kubernetes with --force flag..."
kubectl apply -f $deployment_file --force
else
echo "---> Submittinig a deployment to Kubernetes..."
kubectl apply -f $deployment_file
fi

echo "---> Waiting for a succesful deployment status..."

Expand Down
184 changes: 184 additions & 0 deletions template.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#!/bin/bash
#
# Very simple templating system that replaces {{VAR}} by the value of $VAR.
# Supports default values by writting {{VAR=value}} in the template.
#
# Copyright (c) 2017 Sébastien Lavoie
# Copyright (c) 2017 Johan Haleby
#
# By: https://github.com/johanhaleby/bash-templater
# Version: https://github.com/johanhaleby/bash-templater/commit/5ac655d554238ac70b08ee4361d699ea9954c941

# Replaces all {{VAR}} by the $VAR value in a template file and outputs it

readonly PROGNAME=$(basename $0)

config_file="<none>"
print_only="false"
silent="false"

usage="${PROGNAME} [-h] [-d] [-f] [-s] --
where:
-h, --help
Show this help text
-p, --print-envs
Don't do anything, just print the result of the variable expansion(s)
-e, --env-file
Specify a file to read variables from
-s, --silent
Don't print warning messages (for example if no variables are found)
examples:
VAR1=Something VAR2=1.2.3 ${PROGNAME} test.txt
${PROGNAME} test.txt -e my-variables.txt
${PROGNAME} test.txt -e my-variables.txt > new-test.txt"

if [ $# -eq 0 ]; then
echo "$usage"
exit 1
fi

while [[ $1 =~ ^(-(h|p|e|s)|--(help|print-envs|env-file|silent)) ]]
do
key=$1
value=$2

case $key in
-h|--help)
echo "$usage"
exit 0
;;
-p|--print)
print_only="true"
;;
-e|--env-file)
config_file="$2"
shift
;;
-s|--silent)
silent="true"
;;
*)
echo "Usage ERROR: Invalid Option $key"
echo "$usage"
exit 1
;;
esac
shift # past argument or value
done


if [[ ! -f "${1}" ]]; then
echo "You need to specify a template file" >&2
echo "$usage"
exit 1
fi

template="${1}"

if [ "$#" -ne 0 ]; then
while [ "$#" -gt 0 ]
do
case "$1" in
-h|--help)
echo "$usage"
exit 0
;;
-p|--print-envs)
print_only="true"
;;
-f|--file)
config_file="$2"
;;
-s|--silent)
silent="true"
;;
--)
break
;;
-*)
echo "Invalid option '$1'. Use --help to see the valid options" >&2
exit 1
;;
# an option argument, continue
*) ;;
esac
shift
done
fi

vars=$(grep -oE '\{\{[A-Za-z0-9_]+\}\}' "${template}" | sort | uniq | sed -e 's/^{{//' -e 's/}}$//')

if [[ -z "$vars" ]]; then
if [ "$silent" == "false" ]; then
echo "Warning: No variable was found in ${template}, syntax is {{VAR}}" >&2
fi
cat ${template}
exit 0
fi

# Load variables from file if needed
if [ "${config_file}" != "<none>" ]; then
if [[ ! -f "${config_file}" ]]; then
echo "The file ${config_file} does not exists" >&2
echo "$usage"
exit 1
fi

# Create temp file where & and "space" is escaped
tmpfile=`mktemp`
sed -e "s;\&;\\\&;g" -e "s;\ ;\\\ ;g" "${config_file}" > $tmpfile
source $tmpfile
fi

var_value() {
eval echo \$$1
}

replaces=""

# Reads default values defined as {{VAR=value}} and delete those lines
# There are evaluated, so you can do {{PATH=$HOME}} or {{PATH=`pwd`}}
# You can even reference variables defined in the template before
defaults=$(grep -oE '^\{\{[A-Za-z0-9_]+=.+\}\}' "${template}" | sed -e 's/^{{//' -e 's/}}$//')

for default in $defaults; do
var=$(echo "$default" | grep -oE "^[A-Za-z0-9_]+")
current=`var_value $var`

# Replace only if var is not set
if [[ -z "$current" ]]; then
eval $default
fi

# remove define line
replaces="-e '/^{{$var=/d' $replaces"
vars="$vars
$current"
done

vars=$(echo $vars | sort | uniq)

if [[ "$print_only" == "true" ]]; then
for var in $vars; do
value=`var_value $var`
echo "$var = $value"
done
exit 0
fi

# Replace all {{VAR}} by $VAR value
for var in $vars; do
value=`var_value $var`
if [[ -z "$value" ]]; then
if [ $silent == "false" ]; then
echo "Warning: $var is not defined and no default is set, replacing by empty" >&2
fi
fi

# Escape slashes
value=$(echo "$value" | sed 's/\//\\\//g');
replaces="-e 's/{{$var}}/${value}/g' $replaces"
done

escaped_template_path=$(echo $template | sed 's/ /\\ /g')
eval sed $replaces "$escaped_template_path"

0 comments on commit 2cd26a2

Please sign in to comment.