Commit 5a790a1d authored by Matthew Clemente's avatar Matthew Clemente

Initial commit

parents
Pipeline #76535777 failed with stage
in 1 minute and 4 seconds
CI_PROJECT_NAMESPACE=mjclemente
\ No newline at end of file
.secrets/*
\ No newline at end of file
image: docker:stable
## Helpful post regarding sequential jobs: https://about.gitlab.com/2016/07/29/the-basics-of-gitlab-ci/
stages:
- build
- deploy
variables:
## When using dind (Docker in Docker) service we need to instruct docker, to talk with the daemon started inside of the service. The daemon is available with a network connection instead of the default /var/run/docker.sock socket.
##
## The 'docker' hostname is the alias of the service container as described at
## https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services
DOCKER_HOST: tcp://docker:2375/
## When using dind, it's wise to use the overlayfs driver for improved performance.
DOCKER_DRIVER: overlay2
## Used for building, tagging, and pushing the image
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH/cfml
services:
- docker:dind
## https://stackoverflow.com/questions/49173988/how-to-get-commit-date-and-time-on-gitlab-ci
before_script:
## We're gonna log into the gitlab registry, as that's where these images are stored (https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker-executor)
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
## Needed to get the date from the commit sha, for the build tag. The stable Docker image is on Alpine Linux (https:// git-scm.com/download/linux)
- apk add git
## So we can see what's going on in the logs
- docker info
## Use git `show` with --format=%ci option to get ISO 8601 date stamp of commit (http://schacon.github.io/git/ git-show#_pretty_formats)
- export COMMIT_TIME=$(git show -s --format=%ci $CI_COMMIT_SHA)
## Just use the first 10 characters of the timestamp (example: 2019-03-19)
- export COMMIT_TIME_SHORT=$( echo $COMMIT_TIME | head -c10 )
## Combine both into a date/sha tag
- export BUILD_TAG="${COMMIT_TIME_SHORT}_$CI_COMMIT_SHORT_SHA"
build:
stage: build
only:
- deploy
script:
## enable buildkit support
- export DOCKER_BUILDKIT=1
## Build the image, with the build tag and the latest tag
- docker build --tag $CONTAINER_IMAGE:$BUILD_TAG --tag $CONTAINER_IMAGE:latest -f ./build/cfml/Dockerfile .
## List images, so we can confirm success
- docker image ls
## Push with the build tag
- docker push $CONTAINER_IMAGE:$BUILD_TAG
## Push with latest
- docker push $CONTAINER_IMAGE:latest
deploy:
stage: deploy
only:
- deploy
except:
variables:
- $CI_COMMIT_MESSAGE =~ /Initial commit/i
- $CI_COMMIT_MESSAGE =~ /skip deploy/i
- $CI_COMMIT_MESSAGE =~ /don't deploy/i
script:
## SSH portion is taken from https://docs.gitlab.com/ee/ci/ssh_keys/#ssh-keys-when-using-the-docker-executor
## Install ssh-agent if not already installed
- 'which ssh-agent || ( apk update && apk add openssh-client )'
## Run ssh-agent (inside the build environment)
- eval $(ssh-agent -s)
## Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store. We're using tr to fix line endings which makes ed25519 keys work without extra base64 encoding. (https://gitlab.com/gitlab-examples/ssh-private-key/issues/1#note_48526556)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
## Create the SSH directory and give it the right permissions
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
## Use the contents of the SSH_KNOWN_HOSTS variable as your known hosts, so that we can SSH in
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
## Extract the host IP from the known hosts file, so that we don't need to set it manually
- export HOST_IP=$( grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])' ~/.ssh/known_hosts | head -1 )
## Enable SSH functionality made possible in 18.0.9 to switch our context to the remote server
- export DOCKER_HOST=ssh://[email protected]${HOST_IP}
## Deploy the stack - registry auth is for gitlab
- docker stack deploy -c docker-compose.yml -c docker-compose.prod.yml basetest --with-registry-auth
\ No newline at end of file
MIT License
Copyright (c) 2019 Matthew J. Clemente
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.
\ No newline at end of file
# Starter Swarm Template - ColdFusion <!-- omit in toc -->
The goal of this project is to provide a basic template for beginning to use and understand Docker Swarm in the context of an Adobe ColdFusion application. It provides a pattern and structure for working with:
- Matching Local and Production development environments
- Use of a private registry
- CI/CD pipeline for building and deploying to your Swarm
- Use of environment variables
- Management of sensitive information via secrets
- An approach to managing/adding/rotating secrets
Container orchestration in production requires a lot more than this (certs, load balancers, monitoring, etc), but this framework should provide a ColdFusion-focused foundation for understanding, developing, and deploying with Docker Swarm.
*Note that this project is specifically tailored for Adobe ColdFusion. If you're interested in using Lucee CFML with Docker Swarm, check out this project:* [`starter-swarm-cfml`](https://gitlab.com/mjclemente/starter-swarm-cfml)
## Table of Contents <!-- omit in toc -->
- [Prerequisites](#prerequisites)
- [Project Steps](#project-steps)
- [Initial repository configuration](#initial-repository-configuration)
- [Local Development](#local-development)
- [Setting up your Gitlab deployment SSH key](#setting-up-your-gitlab-deployment-ssh-key)
- [Creating the Swarm](#creating-the-swarm)
- [Verifying the SSH host keys](#verifying-the-ssh-host-keys)
- [Secret Management](#secret-management)
- [Deployment (CI/CD)](#deployment-cicd)
## Prerequisites
Before getting started with this project, there are a few things that you'll need to have in place.
- **Gitlab account**: We'll host the repository with Gitlab, so that we can use their integrated container registry and CI/CD pipeline. It's really nice to have everything in one place. It's even nicer when it's free. [Register for Gitlab here](https://gitlab.com/users/sign_in#register-pane).
- **DigitalOcean account**: We need somewhere to host and deploy our Swarm. While the code here should work in the context of any cloud provider, I'll be using DigitalOcean in my instructions and examples. [Create a DigitalOcean account here](https://m.do.co/c/8acbd6928587) ($50 referral credit).
- **Docker for Mac/Windows**: Along with local development, we'll leverage the functionality added in Docker 18.09 to manage our remote Docker hosts from our local machine. [Get Docker Desktop here](https://www.docker.com/products/docker-desktop).
## Project Steps
### Initial repository configuration
1. First, after logging into your Gitlab account, you'll need to fork this repository using the Gitlab.com interface. This copies it to your Gitlab account, where we can configure the private image registry and CI/CD operations.
2. Clone your copy of the repository and navigate into it (If you haven't [set up an SSH key for your Gitlab account](https://docs.gitlab.com/ee/gitlab-basics/create-your-ssh-keys.html), you'll need to do that first).
```bash
git clone [email protected]:YOUR-USERNAME/starter-swarm-coldfusion.git
cd starter-swarm-coldfusion
```
3. In the project root, make a copy of `.env.example` and name it `.env`. Within the `.env` file, replace my Gitlab namespace, `mjclemente`, with your own.
4. The next step will be to create the files that will hold your administrator passwords. These will not be in version control and will be provided to the Docker image as secrets (more on that later). For now, you just need to generate them, so in the project root, run:
```bash
mkdir .secrets
echo "commandbox" > .secrets/cfml.admin.password.dev
echo $(openssl rand -base64 20) > .secrets/cfml.admin.password.v1
```
We'll be circling back to Gitlab account configuration, but before we do, we need to set up a deployment SSH key to use.
### Local Development
You'll be able to develop locally by running `docker-compose up` from the root of the project. This will spin up a CommandBox server and the project will be served on [http://127.0.0.1:8080/](http://127.0.0.1:8080/). Changes you make will be reflected immediately. Because it's local, we leave the ColdFusion Administrator accessible at [http://127.0.0.1:8080/CFIDE/administrator](http://127.0.0.1:8080/CFIDE/administrator), with the password generated earlier (commandbox).
Once your ready to deploy, we can move on.
### Setting up your Gitlab deployment SSH key
1. We're going to set up a new deployment SSH key, just for Gitlab. This is separate from the primary SSH key that you use for your Gitlab account. Gitlab's CI/CD jobs will use this key to deploy to the Swarm on your DigitalOcean servers (don't worry, we'll get around to setting them up too).
1. In your terminal, run the command to create and name an SSH key:
```bash
ssh-keygen -t ed25519 -C "Gitlab Deployment Key"
```
For the sake of organization, we'll use the same name for this key when adding it to Gitlab and DigitalOcean later on.
2. When prompted, provide a custom location for it to be stored - remember, you're not going to be using this as your default SSH key - it's just for Gitlab deployment. For mine, I used: `/Users/myuser/.ssh/gitlab_com_rsa`
3. When prompted for a passphrase, **leave it blank**.
4. This will create two files for you, the public and the private:
- `Users/youruser/.ssh/gitlab_com_rsa`
- `Users/youruser/.ssh/gitlab_com_rsa.pub `
5. Add the public key to your DigitalOcean account. This way we can make sure it's added to Droplets that we will be creating for the Swarm. ([DO Guide](https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/to-account/))
6. Next, add the same public key to the Gitlab repository as a [deploy key](https://docs.gitlab.com/ee/ssh/README.html#per-repository-deploy-keys). Within the repository, navigate to **Settings > Repository > Deploy Keys**. Here, you'll add the **public key**. It does not need write access.
7. Finally, we're going to configure the private key. Within the repository's **Settings > CI/CD > Variables**, create a new *protected* variable. For the Input variable key, enter `SSH_PRIVATE_KEY` and in the Value field paste the content of the private key that you created. You won't be able to mask these variables. Check the option so that it's protected and then save it. Once we set up our Swarm, we'll circle back to these environment variables to add our known hosts.
### Creating the Swarm
We're going to need to create a new Swarm. I put a script together that handles the entire process for you: [Swarm Creation Script](https://github.com/mjclemente/do-swarm-create). It uses [`doctl`](https://www.digitalocean.com/community/tutorials/how-to-use-doctl-the-official-digitalocean-command-line-client), DigitalOcean's command line tool, to do most of the work.
If you run that script with the default settings, it will spin up three Docker hosts, add your SSH keys, and init a Swarm that you'll be able to manage from your local command line. Set the environment variable `DO_MANAGER_COUNT=1` if you only want to deal with one host to begin with.
If you're going to use an existing Swarm, be sure to add your SSH key and the Gitlab Deployment SSH key to the Droplets.
### Verifying the SSH host keys
For optimal security, we will also [verify the SSH host keys](https://docs.gitlab.com/ee/ci/ssh_keys/#verifying-the-ssh-host-keys) of the manager node that we'll be deploying to. This is done by scanning them and adding them as a CI/CD environment variable as well.
1. From a trusted network (such as on the host itself), we'll scan the Droplet's public IP:
```bash
ssh-keyscan 1.2.3.4
```
2. Take the output of this command and again navigate to the repository's **Settings > CI/CD > Variables**. As with the `SSH_PRIVATE_KEY`, we'll add this as a second protected environment variable with the key `SSH_KNOWN_HOSTS`.
3. Protected environment variables are only made available to protected branches, so we need to update the setting for our deployment branch. Navigate to **Settings > Repository > Protected Branches**. In the Branch field, select `deploy`. Restrict merge and push permissions to Maintainers, then click Protect to apply the settings.
### Secret Management
Secrets must be created on the Swarm before you can deploy your application to it. This is because the `CF_ADMINPASSWORD` environment variable depends on a secret; it can't be used until the secret is set.
In order to deploy the secrets to the Swarm, we'll use the script `./build/deploy-secrets.sh`. When you run this script it will prompt you for SSH credentials to your Droplet. You can get the IP of the Droplet from your DigitalOcean account and you should be able to use `[email protected]`. This is needed in order to SSH into the Swarm to create the secrets. The script provides an explanation of what it does.
### Deployment (CI/CD)
\ No newline at end of file
{
"adminPassword": "${CF_ADMINPASSWORD}",
"adminAllowConcurrentLogin": true,
"adminAllowedIPList": "",
"adminLoginRequired": true,
"adminRDSEnabled": "false",
"adminRDSLoginRequired": "false",
"adminRDSUserIDRequired": true,
"adminRootUserID": "admin",
"adminUserIDRequired": false,
"ajaxDebugWindowEnabled": false,
"allowApplicationVarsInServletContext": false,
"allowExtraAttributesInAttrColl": true,
"applicationMangement": true,
"applicationMaximumTimeout": "2,0,0,0",
"applicationMode": "curr2driveroot",
"applicationTimeout": "2,0,0,0",
"blockedExtForFileUpload": "AS,ASP,ASPX,BIN,DMG,CFC,CFM,CFML,CFR,CFSWF,EXE,HBXML,JSP,JSPX,JWS,MXML,PHP,SWC,SWS",
"CFaaSGeneratedFilesExpiryTime": 30,
"CFFormScriptDirectory": "",
"clientStorage": "",
"clientStorageLocations": {
"Cookie": {
"description": "Client based text file.",
"disableGlobals": false,
"name": "Cookie",
"purgeEnable": true,
"purgeTimeout": 10,
"type": "COOKIE"
},
"Registry": {
"description": "System registry.",
"disableGlobals": false,
"name": "Registry",
"purgeEnable": true,
"purgeTimeout": 90,
"type": "REGISTRY"
}
},
"clientStoragePurgeInterval": 67,
"compileExtForCFInclude": "*",
"componentCacheEnabled": true,
"debuggingEnabled": false,
"debuggingIPList": "127.0.0.1,0:0:0:0:0:0:0:1",
"debuggingReportExecutionTimes": true,
"debuggingReportExecutionTimesMinimum": 250,
"debuggingReportExecutionTimesTemplate": "summary",
"debuggingShowDatabase": true,
"debuggingShowException": true,
"debuggingShowGeneral": true,
"debuggingShowTrace": true,
"debuggingShowVariableApplication": false,
"debuggingShowVariableCGI": true,
"debuggingShowVariableClient": true,
"debuggingShowVariableCookie": true,
"debuggingShowVariableForm": true,
"debuggingShowVariableRequest": false,
"debuggingShowVariables": true,
"debuggingShowVariableServer": false,
"debuggingShowVariableSession": true,
"debuggingShowVariableURL": true,
"debuggingTemplate": "/WEB-INF/debug/classic.cfm",
"disableInternalCFJavaComponents": false,
"disallowUnamedAppScope": false,
"dotNetClientPort": "6086",
"dotNetInstallDir": "Z:\\cfusion\\jnbridge",
"dotNetPort": "6085",
"dotNetProtocol": "tcp",
"dotNotationUpperCase": true,
"errorStatusCode": true,
"eventGatewayConfigurations": [
{
"killontimeout": true,
"starttimeout": 30,
"type": "SMS",
"class": "coldfusion.eventgateway.sms.SMSGateway",
"description": "Handles SMS text messaging"
},
{
"killontimeout": true,
"starttimeout": 30,
"type": "XMPP",
"class": "coldfusion.eventgateway.im.XMPPGateway",
"description": "Handles XMPP instant messaging"
},
{
"killontimeout": true,
"starttimeout": 30,
"type": "SAMETIME",
"class": "coldfusion.eventgateway.im.SAMETIMEGateway",
"description": "Handles Lotus SAMETIME instant messaging"
},
{
"killontimeout": true,
"starttimeout": 30,
"type": "DirectoryWatcher",
"class": "examples.watcher.DirectoryWatcherGateway",
"description": "Watches a directory for file changes"
},
{
"killontimeout": true,
"starttimeout": 30,
"type": "Socket",
"class": "examples.socket.SocketGateway",
"description": "Listens on a socket"
},
{
"killontimeout": true,
"starttimeout": 30,
"type": "CFML",
"class": "coldfusion.eventgateway.cfml.CfmlGateway",
"description": "Handles asynchronous events through CFCs"
},
{
"killontimeout": true,
"starttimeout": 30,
"type": "JMS",
"class": "examples.JMS.JMSGateway",
"description": "Handles Java Messaging Service messages"
},
{
"killontimeout": true,
"starttimeout": 30,
"type": "ActiveMQ",
"class": "examples.ActiveMQ.JMSGateway",
"description": "Handles Apache ActiveMQ JMS messages"
},
{
"killontimeout": false,
"starttimeout": 30,
"type": "DataServicesMessaging",
"class": "coldfusion.eventgateway.flex.FlexMessagingGateway",
"description": "Handles Data Services Messaging messages"
},
{
"killontimeout": true,
"starttimeout": 30,
"type": "FMS",
"class": "coldfusion.eventgateway.fms.FMSGateway",
"description": "Handles Flash Media Server shared objects"
},
{
"killontimeout": true,
"starttimeout": 30,
"type": "DataManagement",
"class": "coldfusion.eventgateway.flex.FlexDataManagementGateway",
"description": "Notifies Data Management Services of data changes"
}
],
"eventGatewayEnabled": false,
"eventGatewayInstances": [
{
"mode": "MANUAL",
"cfcPaths": [
"{cf.rootdir}/gateway/cfc/examples/menu/main.cfc"
],
"configurationPath": "{cf.rootdir}/gateway/config/sms-test.cfg",
"gatewayId": "SMS Menu App - 5551212",
"type": "SMS"
}
],
"eventGatewayMaxQueueSize": 10,
"eventGatewayThreadpoolSize": 1,
"FlashRemotingEnable": true,
"flexDataServicesEnable": false,
"generalErrorTemplate": "default",
"googleMapKey": "",
"inMemoryFileSystemAppLimit": 20,
"inMemoryFileSystemEnabled": true,
"inMemoryFileSystemLimit": 100,
"inspectTemplate": "always",
"logCORBACalls": false,
"logMaxArchives": 10,
"logMaxFileSize": 5000,
"logSlowRequestsEnabled": false,
"logSlowRequestsThreshold": 30,
"mailConnectionTimeout": 60,
"mailDefaultEncoding": "UTF-8",
"mailLogEnabled": false,
"mailLogSeverity": "warning",
"mailSpoolInterval": 15,
"maxCFCFunctionRequests": 15,
"maxCFThreads": 10,
"maxFlashRemotingRequests": 5,
"maxOutputBufferSize": 1024,
"maxReportRequests": 8,
"maxTemplateRequests": 25,
"maxWebServiceRequests": 5,
"missingErrorTemplate": "default",
"monitoringServiceHost": "0.0.0.0",
"monitoringServicePort": "5500",
"nullSupport": false,
"ORMSearchIndexDirectory": "",
"perAppSettingsEnabled": true,
"postParametersLimit": 100,
"postSizeLimit": 20,
"queryCacheSize": 100,
"QueryInternalCacheEnabled": false,
"requestQueueTimeout": 60,
"requestQueueTimeoutPage": "",
"requestTimeout": "0,0,0,60",
"requestTimeoutEnabled": true,
"RMISSLEnable": false,
"RMISSLKeystore": "",
"robustExceptionEnabled": false,
"sandboxEnabled": false,
"saveClassFiles": true,
"schedulerClusterDatasource": "",
"schedulerLogFileExtensions": "log,txt",
"schedulerLoggingEnabled": false,
"scriptProtect": "FORM,URL,COOKIE,CGI",
"secureJSON": false,
"secureJSONPrefix": "//",
"secureProfileEnabled": false,
"serverCFC": "Server",
"serverCFCEenabled": false,
"sessionCookieDisableUpdate": false,
"sessionCookieHTTPOnly": true,
"sessionCookieSecure": true,
"sessionCookieTimeout": 946080000,
"sessionManagement": true,
"sessionMaximumTimeout": "2,0,0,0",
"sessionStorageHost": "",
"sessionStorageLocation": "memory",
"sessionStoragePassword": "",
"sessionStoragePort": 0,
"sessionStorageTimeout": 2000,
"sessionTimeout": "0,0,20,0",
"sessionType": "cfml",
"templateCacheSize": 1024,
"throttleThreshold": 4,
"totalThrottleMemory": 200,
"UDFTypeChecking": false,
"useUUIDForCFToken": true,
"watchConfigFilesForChangesEnabled": false,
"watchConfigFilesForChangesExtensions": "xml,properties",
"watchConfigFilesForChangesInterval": 120,
"websocketEnabled": false,
"whitespaceManagement": "smart"
}
\ No newline at end of file
{
"name": "starter.swarm.coldfusion",
"version": "0.0.1"
}
\ No newline at end of file
{
"name":"starter.swarm.coldfusion",
"debug":false,
"app":{
"sessionCookieSecure":true,
"sessionCookieHTTPOnly":true
},
"jvm":{
"heapSize":512,
"minHeapSize":256
},
"web":{
"directoryBrowsing":false,
"http":{
"port":8080
},
"SSL":{
"enable":true,
"port":8443
},
"webroot":"wwwroot"
}
}
\ No newline at end of file
<h1>Starter Swarm Template - ColdFusion</h1>
<h2>Hello, we're in the container!</h2>
<cfscript>
writeOutput( "<p>What time is it CFSummit? <i>#timeformat( now(), 'short' )#?</i></p><p><b>Sounds like it's container time.</b></p>" );
</cfscript>
\ No newline at end of file
## Using the pre-built Ortus image with CF 2018 installed already
## https://hub.docker.com/r/ortussolutions/commandbox/
FROM ortussolutions/commandbox:adobe2018-alpine-2.6.1
## Copy in our build / config file(s)
COPY ./build/cfml/config/ /config/
## Copy our app into the app dir. JSON configuration files stay outside of webroot
COPY ./app ${APP_DIR}
## Install our box.json dependencies.
WORKDIR $APP_DIR
RUN box install
\ No newline at end of file
#!/bin/bash
## This script needs SSH access to one of the host nodes that already has Docker Swarm set up
## Set some colors for fun. Thanks to https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
## Confirm DOCKER_HOST
if [ -z ${DOCKER_HOST+x} ]; then
read -p "
We need an SSH user with access to one of the Swarm managers in order to create the secrets.
Please enter your Swarm Host SSH credentials in the format [email protected]: " SWARM_SSH_CREDENTIALS;
## Switch context to the remote server
export DOCKER_HOST=ssh://$SWARM_SSH_CREDENTIALS
printf "\n${GREEN}%s${NC}\n" "Thank you."
else
## Switch context to the remote server
export DOCKER_HOST=$DOCKER_HOST
fi
## Provide prompt to make sure that user knows what they're doing
while true; do
read -p "
This script will loop through the local /.secrets directory of this project and create secrets in your remote Swarm based on the name and contents of the files that it finds.
This will be done using the credentials: $DOCKER_HOST
Do you wish to continue? " yn
case $yn in
[Yy]* ) printf "\n${GREEN}%s${NC}\n" "Proceeding with secret creation."; break;;
[Nn]* ) printf "\n${RED}%s${NC}\n" "Secret creation cancelled."; exit;;
* ) printf "\n%s\n" "Please answer yes or no.";;
esac
done
printf "\n%s\n" "Confirming SSH access via $DOCKER_HOST"
IS_SWARM_MANAGER=false
SSH_CONNECTION_FAILED=0
{
IS_SWARM_MANAGER=$( docker info --format "{{.Swarm.ControlAvailable}}" )
} || {
IS_SWARM_MANAGER=false
SSH_CONNECTION_FAILED=1
}
if [ "$SSH_CONNECTION_FAILED" -eq 1 ]; then
printf "\n${RED}%s${NC}\n" "SSH connection failed. Sometimes this happens due to rate-limiting. Please confirm that the Swarm host is accessible. Secret creation cancelled."
exit
fi
if [ "$IS_SWARM_MANAGER" != true ]; then
printf "\n${RED}%s${NC}\n" "Either a Swarm has not been init on the host or it is not a manager. Secret creation cancelled.";
exit
fi
printf "\n${GREEN}%s${NC}\n" "SSH access to Swarm manager confirmed."
## Let's get the directory the script is in. Thanks to https://stackoverflow.com/questions/59895/get-the-source-directory-of-a-bash-script-from-within-the-script-itself
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
## Dependent on the structure of this repository to work. We're switching from build -> .secrets directory
DIR=$( sed 's+/build+/.secrets+g' <(echo $DIR) )
## We're going to cd into the .secrets directory for our loop
cd $DIR
## Get a list of the current secrets from the Swarm
SECRETS=$(docker secret ls --quiet --format "{{.Name}}")
## Convert the list to an array
SECRETS=($SECRETS)
printf "\n%s\n" "Found ${#SECRETS[@]} existing secret(s)."
## Sleeps here are to attempt to slow down consecutive calls via SSH, in case the firewall has rate limits
sleep 2
printf "\n%s\n" "Preparing to create secrets."
sleep 2
## Thank you https://stackoverflow.com/questions/3685970/check-if-a-bash-array-contains-a-value