Initial Commit

This commit is contained in:
2024-02-13 17:03:06 +00:00
commit 097fd27ed1
11 changed files with 574 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
compose/confluence-home
compose/jira-home
compose/pgdata
instance*

50
README.md Normal file
View 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
View File

@@ -0,0 +1,3 @@
JIRA_PORT=8080
CONFLUENCE_PORT=8090
CONFLUENCE_SYNCHRONY_PORT=8091

10
compose/db-init-script.sh Normal file
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}