Initial Commit
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
compose/confluence-home
|
||||
compose/jira-home
|
||||
compose/pgdata
|
||||
instance*
|
||||
50
README.md
Normal file
50
README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Setup
|
||||
|
||||
```
|
||||
# As root on Rocky Linux
|
||||
./machine-setup.sh
|
||||
|
||||
mkdir -p compose
|
||||
cd compose
|
||||
docker-compose up -d
|
||||
# JIRA_PORT=8080
|
||||
# CONFLUENCE_PORT=8090
|
||||
# Set up your instance with license and
|
||||
```
|
||||
|
||||
## Template Instance Setup
|
||||
|
||||
The template instances for Jira and Confluence are located in [./compose](./compose)
|
||||
|
||||
```
|
||||
cd compose
|
||||
# Start Instance
|
||||
docker-compose up -d
|
||||
# Stop Instance
|
||||
```
|
||||
|
||||
On Confluence you need to install the BaseURL Plugin from here:
|
||||
[OBR](https://marketplace.atlassian.com/download/apps/1220470/version/1000010)
|
||||
[Marketplace](https://marketplace.atlassian.com/archive/1220470)
|
||||
|
||||
The Plugin is required to change the Base URL on Confluence via REST
|
||||
|
||||
Those instances are cloned.
|
||||
|
||||
### Update Jira/Confluence Version
|
||||
|
||||
To update your Academy Instances update the Image Version in the Compose File
|
||||
|
||||
|
||||
## Creating an Academy environment
|
||||
|
||||
!!! Shut Down the Template Instance before creating Academy Instances !!!
|
||||
!!! Otherwise weird things™ might happen !!!
|
||||
|
||||
```
|
||||
# Initialize and start instances - Will take a while (up to 30 minutes)
|
||||
# 20 Instances need about 128 GB RAM, so choose your instance size appropriately
|
||||
./startAcademyEnvironment --instances 20 --admin 0
|
||||
# When you are done
|
||||
./startAcademyEnvironment --instances 20 --admin 0 --destroy
|
||||
```
|
||||
3
compose/.env
Normal file
3
compose/.env
Normal file
@@ -0,0 +1,3 @@
|
||||
JIRA_PORT=8080
|
||||
CONFLUENCE_PORT=8090
|
||||
CONFLUENCE_SYNCHRONY_PORT=8091
|
||||
10
compose/db-init-script.sh
Normal file
10
compose/db-init-script.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
CREATE ROLE confluence WITH LOGIN PASSWORD 'test123';
|
||||
CREATE ROLE jira WITH LOGIN PASSWORD 'test123';
|
||||
EOSQL
|
||||
|
||||
createdb -O confluence -E utf8 --lc-collate=en_US.utf8 --lc-ctype=en_US.utf8 confluence
|
||||
createdb -O jira -E UNICODE -l C -T template0 jira
|
||||
53
compose/docker-compose.yaml
Normal file
53
compose/docker-compose.yaml
Normal file
@@ -0,0 +1,53 @@
|
||||
version: '3'
|
||||
services:
|
||||
db:
|
||||
image: postgres
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./db-init-script.sh:/docker-entrypoint-initdb.d/init.sh
|
||||
- ./pgdata:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=test123
|
||||
jira:
|
||||
restart: unless-stopped
|
||||
image: atlassian/jira-software:latest
|
||||
environment:
|
||||
- ATL_JDBC_URL=jdbc:postgresql://db/jira
|
||||
- ATL_JDBC_USER=jira
|
||||
- ATL_JDBC_PASSWORD=test123
|
||||
- ATL_DB_TYPE=postgres72
|
||||
- ATL_DB_DRIVER=org.postgresql.Driver
|
||||
- JVM_MAXIMUM_MEMORY=1024m
|
||||
volumes:
|
||||
- ./jira-home:/var/atlassian/application-data/jira
|
||||
ports:
|
||||
- ${JIRA_PORT}:8080
|
||||
depends_on:
|
||||
- db
|
||||
ulimits:
|
||||
nproc: 65535
|
||||
nofile:
|
||||
soft: 26677
|
||||
hard: 46677
|
||||
|
||||
confluence:
|
||||
restart: unless-stopped
|
||||
image: atlassian/confluence:latest
|
||||
environment:
|
||||
- ATL_JDBC_URL=jdbc:postgresql://db/confluence
|
||||
- ATL_JDBC_USER=confluence
|
||||
- ATL_JDBC_PASSWORD=test123
|
||||
- ATL_DB_TYPE=postgresql
|
||||
- JVM_MAXIMUM_MEMORY=1024m
|
||||
ports:
|
||||
- ${CONFLUENCE_PORT}:8090
|
||||
- ${CONFLUENCE_SYNCHRONY_PORT}:8091
|
||||
volumes:
|
||||
- ./confluence-home:/var/atlassian/application-data/confluence
|
||||
depends_on:
|
||||
- db
|
||||
ulimits:
|
||||
nproc: 65535
|
||||
nofile:
|
||||
soft: 26677
|
||||
hard: 46677
|
||||
196
createJCAppLink
Executable file
196
createJCAppLink
Executable file
@@ -0,0 +1,196 @@
|
||||
#!/bin/bash
|
||||
|
||||
#############################################################################
|
||||
###
|
||||
### this script creates a bi-directional application link between a Jira
|
||||
### and a Confluence instance.
|
||||
###
|
||||
### Simply provide base URLs for both applications as well as a user account
|
||||
### with admin privileges on both systems.
|
||||
###
|
||||
### (c) 2018 anaron GmbH
|
||||
### Author(s): Korbinian Weidinger
|
||||
### Heinz Jürgen Letsch
|
||||
###
|
||||
#############################################################################
|
||||
|
||||
|
||||
########## DEFAULTS/PARAMETERS #########
|
||||
JIRAAPPLABEL="Jira Schulungsumgebung"
|
||||
CONFAPPLABEL="Confluence Schulungsumgebung"
|
||||
CHEADER=/tmp/cheader
|
||||
CURLVERBOSITY="-s -S -w %{http_code}"
|
||||
CURLVERBOSITY="-s -S "
|
||||
|
||||
for i in "$@"
|
||||
do
|
||||
case $i in
|
||||
-j=*|--JIRA=*)
|
||||
JIRA="${i#*=}"
|
||||
;;
|
||||
-l=*|--JIRAlabel=*)
|
||||
JIRAAPPLABEL="${i#*=}"
|
||||
;;
|
||||
-c=*|--CONFLUENCE=*)
|
||||
CONFLUENCE="${i#*=}"
|
||||
;;
|
||||
-k=*|--CONFLUENCElabel=*)
|
||||
CONFAPPLABEL="${i#*=}"
|
||||
;;
|
||||
-u=*|--username=*)
|
||||
USERNAME="${i#*=}"
|
||||
;;
|
||||
-p=*|--password=*)
|
||||
PASSWORD="${i#*=}"
|
||||
;;
|
||||
-d|--debug)
|
||||
debug=true
|
||||
CURLVERBOSITY="-D /tmp/header"
|
||||
;;
|
||||
*)
|
||||
# unknown option
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$debug" == "true" ]]
|
||||
then
|
||||
echo "jira: $JIRA"
|
||||
echo "confluence: $CONFLUENCE"
|
||||
echo "username: $USERNAME"
|
||||
echo "password: $PASSWORD"
|
||||
echo "jiraLabel: $JIRAAPPLABEL"
|
||||
echo "confLabel: $CONFAPPLABEL"
|
||||
echo
|
||||
curlverbosity="-D ${CHEADER} -w %{http_code}" # save response header in debug mode
|
||||
curlverbosity="-D ${CHEADER} " # save response header in debug mode
|
||||
fi
|
||||
|
||||
|
||||
|
||||
#################### FUNCTIONS ###################
|
||||
|
||||
###
|
||||
# show brief parameter summary
|
||||
###
|
||||
usage() {
|
||||
echo -e "\nUsage:\n$0 \n\
|
||||
-u|--username=<username> \n\
|
||||
-p|--password=<password> \n\
|
||||
-j|--jira=<jiraURL> \n\
|
||||
-c|--confluence=<confluenceURL> \n\
|
||||
[-l|--jiralabel=<jiraAppLabel>] \n\
|
||||
[-k|--confluencelabel=<confluenceAppLabel>]\n"
|
||||
}
|
||||
|
||||
|
||||
###
|
||||
# perform oauth authentication for given token/id
|
||||
# params: baseUrl id
|
||||
###
|
||||
doOauth()
|
||||
{
|
||||
response=$(curl ${CURLVERBOSITY} -u ${USERNAME}:${PASSWORD} -X PUT $1/rest/applinks/3.0/status/$2/oauth \
|
||||
-H 'content-type: application/json' \
|
||||
-H "origin: $1" \
|
||||
-d '{"incoming":{"enabled":true,"twoLoEnabled":true,"twoLoImpersonationEnabled":true},"outgoing":{"enabled":true,"twoLoEnabled":true,"twoLoImpersonationEnabled":true}}')
|
||||
if [[ "${debug}" == "true" ]]; then
|
||||
cat ${CHEADER}
|
||||
echo ${response}
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
###
|
||||
# create an application link entity
|
||||
# params: baseUrl schema
|
||||
###
|
||||
createAppLink()
|
||||
{
|
||||
response=$(curl ${CURLVERBOSITY} \
|
||||
-u ${USERNAME}:${PASSWORD} \
|
||||
-H "X-Atlassian-Token: no-check" \
|
||||
-H "Origin: $1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST $1/rest/applinks/3.0/applicationlinkForm/createAppLink \
|
||||
-d "$2"
|
||||
)
|
||||
if [[ "${debug}" == "true" ]]; then
|
||||
echo ${CHEADER}
|
||||
echo ${response}
|
||||
fi
|
||||
|
||||
id=$(echo ${response} | grep -oP '(?<=<id>).*?(?=</id>)')
|
||||
if [[ -z ${id} ]]; then
|
||||
|
||||
$(echo {$response} | grep -oPq '502 Bad Gateway')
|
||||
badGW=$?;
|
||||
$(echo {$response} | grep -oPq 'error status=\"400\"')
|
||||
exists=$?;
|
||||
if [ "$badGW" == "0" ]; then
|
||||
echo " error: instance not running!"
|
||||
else
|
||||
if [ "$exists" == "0" ]; then
|
||||
echo " link already exists"
|
||||
else
|
||||
echo "ERROR: could not create app link on $1: ${response}"
|
||||
fi
|
||||
fi
|
||||
exit 1;
|
||||
fi
|
||||
#echo "got applink ID: ${id}"
|
||||
doOauth $1 ${id}
|
||||
}
|
||||
|
||||
|
||||
###
|
||||
# prepare required data for applink creation
|
||||
# params: application appLabel baseUrlLink
|
||||
# application: jira|confluence
|
||||
# appLabel: label of applink shown in admin GUI
|
||||
# baseUrlLink: baseURL of system to be linked to
|
||||
###
|
||||
getApplinkSchema(){
|
||||
echo "{
|
||||
\"applicationLink\":
|
||||
{
|
||||
\"typeId\":\"$1\",
|
||||
\"name\":\"$2\",
|
||||
\"displayUrl\":\"$3\",
|
||||
\"rpcUrl\":\"$3\",
|
||||
\"isPrimary\":true,
|
||||
\"isSystem\":false
|
||||
},
|
||||
\"username\":\"$username\",
|
||||
\"password\":\"$password\",
|
||||
\"customRpcURL\":false,
|
||||
\"rpcUrl\":\"null\",
|
||||
\"createTwoWayLink\":false,
|
||||
\"orphanedTrust\":null,
|
||||
\"configFormValues\":
|
||||
{
|
||||
\"trustEachOther\":true,
|
||||
\"shareUserbase\":true
|
||||
}
|
||||
}"
|
||||
}
|
||||
|
||||
|
||||
|
||||
#################### BODY ###################
|
||||
|
||||
###
|
||||
# check if required parameters are set
|
||||
###
|
||||
if [[ -z "${JIRA}" ]] || [[ -z "${CONFLUENCE}" ]] || [[ -z "${USERNAME}" ]] || [[ -z "${PASSWORD}" ]]
|
||||
then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
###
|
||||
# create link on both systems
|
||||
###
|
||||
createAppLink ${JIRA} "$(getApplinkSchema "confluence" "${CONFAPPLABEL}" "${CONFLUENCE}")"
|
||||
createAppLink ${CONFLUENCE} "$(getApplinkSchema "jira" "${JIRAAPPLABEL}" "${JIRA}")"
|
||||
12
machine-setup.sh
Normal file
12
machine-setup.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
yum install -y docker perl
|
||||
systemctl enable --now docker
|
||||
VERSION=v4.40.5
|
||||
BINARY=yq_linux_amd64
|
||||
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -O - |\
|
||||
tar xz && mv ${BINARY} /usr/bin/yq
|
||||
|
||||
|
||||
96
setupAcademyInstancev2.pl
Executable file
96
setupAcademyInstancev2.pl
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.010;
|
||||
use Getopt::Long qw(GetOptions);
|
||||
use FileHandle;
|
||||
|
||||
my $instance;
|
||||
my $destroy = '';
|
||||
my $brokenAppLink = '';
|
||||
my $brokenBaseURL = '';
|
||||
|
||||
GetOptions('instance=s' => \$instance,
|
||||
'destroy' => \$destroy,
|
||||
'brokenAppLink' => \$brokenAppLink,
|
||||
'brokenBaseURL' => \$brokenBaseURL) or usage();
|
||||
|
||||
# check parameters
|
||||
if (!(defined $instance && $instance >= 0)) { usage(); }
|
||||
|
||||
# set some defaults
|
||||
my $maxWait = 600; # seconds to wait for instance to come up
|
||||
my $waitCycle = 10;
|
||||
my $URLStem = "http://academy.scandio.net";
|
||||
my $ComposeFolder = "instance$instance";
|
||||
# Port stem for instance e.g. 8000
|
||||
# 8080 -> Jira
|
||||
# 8090 -> Confluence
|
||||
my $PortStem = 8000+($instance*100);
|
||||
my $JiraPort = $PortStem+80;
|
||||
my $ConfluencePort = $PortStem+90;
|
||||
my $ConfluenceSynchronyPort = $PortStem+91;
|
||||
|
||||
if ($destroy) {
|
||||
print "Destroying Instance $instance\n";
|
||||
system("cd $ComposeFolder && docker-compose down");
|
||||
system("rm -rf $ComposeFolder");
|
||||
exit(0);
|
||||
}
|
||||
# Copy Template folder to $ComposeFolder
|
||||
`rsync -a compose/ $ComposeFolder`;
|
||||
|
||||
|
||||
# Write new .env file with new ports
|
||||
my $FHenv = new FileHandle("${ComposeFolder}/.env", "w");
|
||||
unless ($FHenv) { die( "cannot create file ${ComposeFolder}/.env" );}
|
||||
$FHenv->print("JIRA_PORT=$JiraPort\n");
|
||||
$FHenv->print("CONFLUENCE_PORT=$ConfluencePort\n");
|
||||
$FHenv->print("CONFLUENCE_SYNCHRONY_PORT=$ConfluenceSynchronyPort\n");
|
||||
$FHenv->close;
|
||||
|
||||
# Start the Compose Stack
|
||||
print "Starting instance $instance...\n";
|
||||
system("cd $ComposeFolder && docker-compose up -d");
|
||||
|
||||
|
||||
# wait for instance to come up, set new BaseURL
|
||||
my $result;
|
||||
my $resultConfluence;
|
||||
my $resultJira;
|
||||
my $waited = 0;
|
||||
if (!$brokenAppLink) {
|
||||
do {
|
||||
print " waiting for instance to become available (" . $waited . "s)...\n";
|
||||
$waited += $waitCycle;
|
||||
sleep $waitCycle;
|
||||
$resultJira = system("./updateJiraBaseURL --baseurl=${URLStem}:${JiraPort} -u=admin -p=admin");
|
||||
$resultConfluence = system("./updateConfluenceBaseURL --baseurl=${URLStem}:${ConfluencePort} -u=admin -p=admin > /dev/null 2>&1");
|
||||
} while (($resultJira ne "0" || $resultConfluence ne "0") && $waited < $maxWait);
|
||||
}
|
||||
|
||||
if (!$brokenBaseURL) {
|
||||
system ("./createJCAppLink -j=${URLStem}:${JiraPort} -c=${URLStem}:${ConfluencePort} -u=admin -p=admin");
|
||||
}
|
||||
|
||||
# check if update was successful
|
||||
if ($waited >= $maxWait)
|
||||
{
|
||||
print "Instance not available after $waited seconds";
|
||||
print "baseURL not updated - aborting\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# restart container to activate context changes
|
||||
print " restarting container to activate new configuration\n";
|
||||
system("cd $ComposeFolder && docker-compose up --force-recreate -d");
|
||||
|
||||
exit 0;
|
||||
|
||||
|
||||
|
||||
sub usage
|
||||
{
|
||||
print "Usage: $0 --instance INSTANCENO [--destroy] [--brokenAppLink] [--brokenBaseURL\n";
|
||||
exit 1;
|
||||
}
|
||||
56
startAcademyEnvironment
Executable file
56
startAcademyEnvironment
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use threads;
|
||||
use 5.010;
|
||||
use Getopt::Long qw(GetOptions);
|
||||
|
||||
my $instanceCount;
|
||||
my $adminEnv;
|
||||
my $offset;
|
||||
my $destroy = '';
|
||||
|
||||
|
||||
|
||||
GetOptions('instances=s' => \$instanceCount,
|
||||
'admin=s' => \$adminEnv,
|
||||
'offset=i' => \$offset,
|
||||
'destroy' => \$destroy);
|
||||
|
||||
|
||||
# check parameters
|
||||
if (!(defined $instanceCount && length $instanceCount > 0)) { usage(); }
|
||||
if (!(defined $offset)) {
|
||||
print "No Offset specified; Setting Offset to 0\n";
|
||||
$offset = 0;
|
||||
}
|
||||
if (!(defined $adminEnv && length $adminEnv > 0)) { usage(); }
|
||||
if ($adminEnv != "1") { $adminEnv = 0 }
|
||||
|
||||
my $startArgs = "";
|
||||
if ($adminEnv) {
|
||||
$startArgs = "--brokenAppLink --brokenBaseURL";
|
||||
}
|
||||
if ($destroy) {
|
||||
$startArgs = "$startArgs --destroy";
|
||||
}
|
||||
|
||||
|
||||
my @threads;
|
||||
# start as many instances as specified
|
||||
for (my $i=$offset; $i<$instanceCount+$offset; $i++)
|
||||
{
|
||||
push @threads, async {system ("./setupAcademyInstancev2.pl -instance $i $startArgs")};
|
||||
}
|
||||
|
||||
for (@threads) {
|
||||
$_->join();
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage
|
||||
{
|
||||
print "Usage: $0 --instances INSTANCECOUNT --admin [0|1]\n";
|
||||
exit 1;
|
||||
}
|
||||
48
updateConfluenceBaseURL
Executable file
48
updateConfluenceBaseURL
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.010;
|
||||
use Getopt::Long qw(GetOptions);
|
||||
|
||||
|
||||
my $username;
|
||||
my $password;
|
||||
my $serverurl;
|
||||
my $baseurl;
|
||||
my $updateURL;
|
||||
my $updateArgs;
|
||||
my $response;
|
||||
my $cmd;
|
||||
my $isJira;
|
||||
|
||||
GetOptions('username=s' => \$username,
|
||||
'password=s' => \$password,
|
||||
'baseurl=s' => \$baseurl) or usage();
|
||||
|
||||
if (!defined $username) { $username = "admin" }
|
||||
if (!defined $password) { $password = "admin" }
|
||||
if (!defined $baseurl) { usage(); }
|
||||
|
||||
$updateURL = "$baseurl/rest/base-url/1.0/base-url?baseUrl=$baseurl";
|
||||
$updateArgs = "-X PUT -H \"X-Atlassian-Token: no-check\" -u \"$username:$password\"";
|
||||
|
||||
# use curl to update the baseURL
|
||||
$cmd = "curl -s -S -o /dev/null -w %{http_code} $updateArgs $updateURL";
|
||||
print "updating BaseURL with: $cmd\n";
|
||||
$response = `$cmd`;
|
||||
print "http response: $response\n";
|
||||
|
||||
|
||||
if ($response == "200") { print "Confluence baseURL updated successfully\n"; }
|
||||
else {
|
||||
if ($response == "404") { print "FAILED: this Confluence instance does not support BaseURL updates. Install AddOn to add support!\n"; }
|
||||
else { print "FAILED: http status code on update: $response\n"; exit 1;}
|
||||
}
|
||||
exit 0;
|
||||
|
||||
sub usage
|
||||
{
|
||||
print "Usage: $0 --baseurl newBaseURL [--username adminUsername] [--password adminPassword]\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
46
updateJiraBaseURL
Executable file
46
updateJiraBaseURL
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use 5.010;
|
||||
use Getopt::Long qw(GetOptions);
|
||||
|
||||
|
||||
my $username;
|
||||
my $password;
|
||||
my $serverurl;
|
||||
my $baseurl;
|
||||
my $updateURL;
|
||||
my $updateArgs;
|
||||
my $response;
|
||||
my $cmd;
|
||||
my $isJira;
|
||||
|
||||
GetOptions('username=s' => \$username,
|
||||
'password=s' => \$password,
|
||||
'baseurl=s' => \$baseurl) or usage();
|
||||
|
||||
if (!defined $username) { $username = "admin" }
|
||||
if (!defined $password) { $password = "admin" }
|
||||
if (!defined $baseurl) { usage(); }
|
||||
|
||||
$updateURL = "$baseurl/rest/api/2/settings/baseUrl";
|
||||
$updateArgs = "-X PUT -H \"X-Atlassian-Token: no-check\" -u \"$username:$password\" -H \"Content-Type:application/json\" -d \"$baseurl\"";
|
||||
|
||||
|
||||
# use curl to update the baseURL
|
||||
$cmd = "curl -s -S -o /dev/null -w %{http_code} $updateArgs $updateURL";
|
||||
print "updating BaseURL with: $cmd\n";
|
||||
$response = `$cmd`;
|
||||
print "http response: $response\n";
|
||||
|
||||
|
||||
if ($response == "204") { print "Jira baseURL updated successfully\n"; }
|
||||
else { print "FAILED: http status code on update: $response\n"; exit 1; }
|
||||
exit 0;
|
||||
|
||||
sub usage
|
||||
{
|
||||
print "Usage: $0 --baseurl newBaseURL [--username adminUsername] [--password adminPassword]\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user