2024-11-16 22:50:41 -05:00
pipeline {
agent any
parameters {
2024-11-17 15:01:57 -05:00
string ( name: 'servicename' , description: "service name" )
2024-11-16 22:50:41 -05:00
string ( name: 'svcdesc' , description: "service description" )
2024-11-21 13:02:37 -05:00
string ( name: 'targetHost' , description: "system to live on" , defaultValue: "moloryb.lan" )
2024-11-19 11:49:50 -05:00
booleanParam ( name: 'database' , description: "service has a database" , defaultValue: true )
2024-11-17 15:01:57 -05:00
}
environment {
2024-11-21 13:02:37 -05:00
//pw_linuxserviceaccount=""
//pw_productiondatabase=""
//pw_developmentdatabase=""
//SUDOER=credentials('') //going to be set based on target host
2024-11-21 00:13:06 -05:00
SUDOERSSH = credentials ( '2c48e1a9-22b2-455c-9959-6b29e86d3fb5' )
2024-11-21 13:02:37 -05:00
JENKINS = credentials ( 'f1192e74-dfe0-402f-a189-703482d914fe' )
GITEATOKEN = credentials ( 'd0e86441-2157-405f-8539-a9a9010c6ecf' )
2024-11-17 15:01:57 -05:00
}
2024-11-16 22:50:41 -05:00
stages {
2024-11-17 16:02:56 -05:00
stage ( "environment setup" ) {
2024-11-16 22:50:41 -05:00
steps {
script {
2024-11-17 15:01:57 -05:00
if ( servicename . isEmpty ( ) ) {
error ( "servicename mandatory" )
}
if ( servicename . contains ( ' ' ) ) {
error ( "servicename cannot have spaces. try dashes." )
2024-11-16 22:50:41 -05:00
}
2024-11-17 16:02:56 -05:00
switch ( targetHost ) {
2024-11-19 11:49:50 -05:00
case "alloces.lan" :
2024-11-19 02:07:51 -05:00
SUDOER = credentials ( 'a674f816-2b35-4d60-ba60-7b66e86f3c5c' )
2024-11-21 00:13:06 -05:00
case "moloryb.lan" :
SUDOER = credentials ( '1f3b965e-bcc0-4074-99f2-b64dddbf7de7' )
2024-11-17 16:02:56 -05:00
break
default :
2024-11-19 11:49:50 -05:00
error ( "target host not recognized. btw: yes .lan, all lowercase." )
2024-11-17 16:02:56 -05:00
}
2024-11-19 11:49:50 -05:00
env . pw_linuxserviceaccount = sh ( returnStdout: true , script: "mktemp -u XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" )
2024-11-17 16:02:56 -05:00
echo env . pw_linuxserviceaccount
2024-11-19 11:49:50 -05:00
env . pw_productiondatabase = sh ( returnStdout: true , script: "mktemp -u XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" )
2024-11-17 16:02:56 -05:00
echo env . pw_productiondatabase
2024-11-19 11:49:50 -05:00
env . pw_developmentdatabase = sh ( returnStdout: true , script: "mktemp -u XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" )
2024-11-17 16:02:56 -05:00
echo env . pw_developmentdatabase
2024-11-16 22:50:41 -05:00
}
}
}
stage ( "gitea project" ) {
steps {
2024-11-17 16:02:56 -05:00
sh "" "
curl - X 'POST' \
2024-11-21 13:02:37 -05:00
'https://gitea.arg.rip/api/v1/repos/greyn/_template-service/generate' \
2024-11-17 16:02:56 -05:00
- H 'accept: application/json' \
2024-11-21 13:02:37 -05:00
- H 'Authorization: token ${env.GITEATOKEN}' \
2024-11-17 16:02:56 -05:00
- H 'Content-Type: application/json' \
- d ' {
2024-11-19 02:07:51 -05:00
"description" : "${svcdesc}" ,
"git_content" : true ,
"git_hooks" : true ,
"labels" : true ,
"name" : "${servicename}" ,
"owner" : "greyn" ,
"private" : false ,
"protected_branch" : true ,
"topics" : true ,
"webhooks" : true
} '
2024-11-17 16:02:56 -05:00
"" "
2024-11-19 02:07:51 -05:00
}
}
stage ( "jenkins pipeline" ) {
steps {
2024-11-21 13:02:37 -05:00
//the bad news is that it looks like it's not allowed to trigger just any old job remotely
//the good news is that this seems to pick it up pretty reliably
//sh """
// curl -X POST -L --user ${env.JENKINS_USR}:${env.JENKINS_PSW} \
// alloces.lan:8080/job/gitea.arg.rip/build
// """
2024-11-19 02:07:51 -05:00
timeout ( time: 5 , unit: 'MINUTES' ) {
sh "" "
strRes = ""
2024-11-21 13:02:37 -05:00
while [ - z "\$strRes" ] ;
2024-11-19 02:07:51 -05:00
do
sleep 5 ;
2024-11-21 13:02:37 -05:00
strRes = \ $ ( curl - X GET - s - u $ { env . JENKINS_USR } : '${env.JENKINS_PSW}' \
alloces . lan : 8080 /job/ gitea . arg . rip /api/ json \
| jq ".jobs.[] | select(.name==\"${env.servicename}\")" )
2024-11-19 02:07:51 -05:00
done
"" "
2024-11-17 23:25:14 -05:00
}
2024-11-19 02:07:51 -05:00
sshagent ( [ 'f42347e9-e3b5-44af-a1af-c5e7b9775fee' ] ) {
2024-11-17 23:25:14 -05:00
sh "" "
2024-11-19 02:07:51 -05:00
git clone 'ssh://git@gitea.arg.rip:8022/greyn/${servicename}.git'
pushd $ { servicename }
2024-11-19 11:49:50 -05:00
dbstartline = \ $ ( sed - n '/---dbstart---]/=' Jenkinsfile )
dbendline = \ $ ( sed - n '/---dbend---/=' Jenkinsfile )
2024-11-17 23:25:14 -05:00
"" "
2024-11-19 11:49:50 -05:00
script { //there's no "if" "step" so any "if" must be in a "script" step
if ( params . database ) {
sh "" "
sed - i - e '${dbstartline}d;${dbendline}d;' Jenkinsfile
databasecredsid = \ $ ( uuidgen )
CRUMB = \ $ ( curl - s 'http://${env.JENKINS_USR}:${env.JENKINS_PSW}@alloces.lan:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)' )
echo $CRUMB
curl - H $CRUMB - X POST 'http://${env.JENKINS_USR}:${env.JENKINS_PSW}@alloces.lan:8080/job/gitea.arg.rip/job/${servicename}/credentials/store/folder/domain/greyn%20services/createCredentials' \
- - data - urlencode ' json = {
"" : "0" ,
"credentials" : {
"scope" : "GLOBAL" ,
"id" : "$databasecredsid" ,
"secret" : "Host=${targetHost};Database=${servicename};Username=${servicename};Password=${env.pw_productiondatabase};IncludeErrorDetail=true;" ,
"description" : "database connection string" ,
"\$class" : "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl"
}
} '
sed - i 's/productiondatabase_connectionString=creds/productiondatabase_connectionString=credentials(' $databasecredsid ')/' Jenkinsfile
git add .
git commit - m "set up for database"
"" "
}
else {
sh "" "
sed - i - e '${dbstartline},${dbendline}d;' Jenkinsfile
git add .
git commit - m "stripped database lines"
"" "
}
2024-11-19 02:07:51 -05:00
sh "" "
2024-11-19 11:49:50 -05:00
popd
2024-11-19 02:07:51 -05:00
2024-11-19 11:49:50 -05:00
env . usernameCredsId = \ $ ( uuidgen )
2024-11-19 02:07:51 -05:00
2024-11-19 11:49:50 -05:00
CRUMB = \ $ ( curl - s 'http://${env.JENKINS_USR}:${env.JENKINS_PSW}@alloces.lan:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)' )
2024-11-19 02:07:51 -05:00
echo $CRUMB
curl - H $CRUMB - X POST 'http://${env.JENKINS_USR}:${env.JENKINS_PSW}@alloces.lan:8080/job/gitea.arg.rip/job/${servicename}/credentials/store/folder/domain/greyn%20services/createCredentials' \
- - data - urlencode ' json = {
"" : "0" ,
"credentials" : {
"scope" : "GLOBAL" ,
2024-11-19 11:49:50 -05:00
"id" : "$env.usernameCredsId" ,
"username" : "${servicename}" ,
"password" : "${env.pw_linuxserviceaccount}" ,
"description" : "service account login" ,
"\$class" : "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl"
2024-11-19 02:07:51 -05:00
}
} '
2024-11-19 11:49:50 -05:00
certCredsId = \ $ ( uuidgen )
2024-11-19 02:07:51 -05:00
2024-11-19 11:49:50 -05:00
ssh - keygen - t ed25519 - f "${servicename}" - N ""
privatekeycontent = \ $ ( cat $ { servicename } ) )
pubkeycontent = \ $ ( cat $ { servicename } . pub ) )
CRUMB = \ $ ( url - s 'http://${env.JENKINS_USR}:${env.JENKINS_PSW}@alloces.lan:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)' )
echo $CRUMB
curl - H $CRUMB - X POST 'http://${env.JENKINS_USR}:${env.JENKINS_PSW}@alloces.lan:8080/job/gitea.arg.rip/job/${servicename}/credentials/store/folder/domain/greyn%20services/createCredentials' \
- - data - urlencode ' json = {
"" : "0" ,
"credentials" : {
"scope" : "GLOBAL" ,
"id" : "$env.usernameCredsId" ,
"username" : "${servicename}" ,
"password" : "" ,
"privateKeySource" : {
"stapler-class" : "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource" ,
"privateKey" : "$privatekeycontent" ,
} ,
"description" : "${servicename}" ,
"stapler-class" : "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
} ,
"description" : "service account ssh" ,
"\$class" : "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
}
} '
privatekeycontent =
2024-11-19 02:07:51 -05:00
2024-11-19 11:49:50 -05:00
sed - i 's/linuxServiceAccount=creds/linuxServiceAccount=credentials(' $ { env . usernameCredsId } ')/' Jenkinsfile
sed - i 's/targetHost=string/targetHost="${targetHost}"/' Jenkinsfile
2024-11-19 02:07:51 -05:00
2024-11-19 11:49:50 -05:00
"" "
sh "" "
git push
popd
"" "
}
2024-11-17 16:02:56 -05:00
}
2024-11-17 15:01:57 -05:00
}
}
2024-11-16 22:50:41 -05:00
stage ( "service account" ) {
steps {
script {
2024-11-17 16:02:56 -05:00
sshagent ( [ SUDOERSSH ] )
{
2024-11-19 11:49:50 -05:00
sh "" "ssh -tt ${SUDOER_USR}@${targetHost} username=${servicename} password=${env.pw_linuxserviceaccount} pubkeycontent=${env.pubkeycontent} 'echo " $SUDOER_PSW " | sudo - Sv & & bash - s ' << ' ENDSSH '
2024-11-17 16:02:56 -05:00
useradd - m - s /bin/ bash $username
echo "$username:$password" | chpasswd
loginctl enable - linger $username
2024-11-19 02:07:51 -05:00
cd ~ /home/ $username
mkdir . ssh
pushd . ssh
echo $pubkeycontent > authorized_keys
popd
chown - R $username : $username . ssh
2024-11-17 16:02:56 -05:00
ENDSSH
2024-11-19 11:49:50 -05:00
"" "
2024-11-17 16:02:56 -05:00
}
2024-11-16 22:50:41 -05:00
}
}
}
2024-11-17 13:24:01 -05:00
stage ( "db init" ) {
when { expression { return params . database } }
steps {
//i'm pretty sure "update" with nothing will init?
//meaning we don't have to init, first update will init
script {
2024-11-17 16:02:56 -05:00
sshagent ( [ SUDOERSSH ] )
{
2024-11-19 11:49:50 -05:00
sh "" "ssh -tt SUDOER_USR@${targetHost} servicename=$servicename pw_productiondatabase=${env.pw_productiondatabase} pw_developmentdatabase=${env.pw_developmentdatabase} 'echo " $SUDOER_PSW " | sudo - Sv & & bash - s ' << ' ENDSSH '
2024-11-17 16:02:56 -05:00
sudo - u postgres psql & & bash - s < < 'ENDPSQL'
create database $servicename ;
create user $servicename with encrypted password '$pw_productiondatabase' ;
grant all privileges on database $servicename to $servicename ;
ENDPSQL
service_dev = "${servicename}_dev"
sudo - u postgres psql & & bash - s < < 'ENDPSQL'
create database $service_dev ;
create user $service_dev with encrypted password '$pw_developmentdatabase' ;
grant all privileges on database $service_dev to $service_dev ;
ENDPSQL
2024-11-19 11:49:50 -05:00
ENDSSH "" "
2024-11-17 16:02:56 -05:00
}
2024-11-17 13:24:01 -05:00
}
}
}
2024-11-16 22:50:41 -05:00
stage ( "initial service setup" ) {
steps {
2024-11-19 02:07:51 -05:00
sshagent ( [ SUDOERSSH ] )
{
sh 'scp $servicename.service $servicename@${targetHost}:~/.config/systemd/user/$servicename.service'
2024-11-19 11:49:50 -05:00
sh "" "ssh -tt SUDOER_USR@${targetHost} servicename=$servicename pw_productiondatabase=${env.pw_productiondatabase} pw_developmentdatabase=${env.pw_developmentdatabase} 'echo " $SUDOER_PSW " | sudo - Sv & & bash - s ' << ' ENDSSH '
2024-11-19 02:07:51 -05:00
sudo - u $ { servicename } & & bash - s < < 'ENDASSERVICE'
systemctl - - user daemon - reload
systemctl - - user enable $servicename . service
ENDASSERVICE
2024-11-19 11:49:50 -05:00
ENDSSH "" "
2024-11-19 02:07:51 -05:00
}
2024-11-16 22:50:41 -05:00
}
}
2024-11-19 11:49:50 -05:00
}
post {
failure {
2024-11-21 13:02:37 -05:00
matrixSendMessage https: true , hostname: 'greyn.club' , port: 8448 , accessTokenCredentialsId: '040b63d1-2f14-4692-badb-114bddd7c5a5' , roomId: '!QmOCACetHdGDlNFsZP:greyn.club' , body: '1-click service failed :(' , formattedBody: "1-click service <b>failed</b> :("
2024-11-19 11:49:50 -05:00
}
success {
2024-11-21 13:02:37 -05:00
matrixSendMessage https: true , hostname: 'greyn.club' , port: 8448 , accessTokenCredentialsId: '040b63d1-2f14-4692-badb-114bddd7c5a5' , roomId: '!QmOCACetHdGDlNFsZP:greyn.club' , body: '1-click service success! go pick up the credentials!' , formattedBody: '1-click service success! go pick up the credentials!'
2024-11-19 11:49:50 -05:00
//TODO: archiveArtifacts the password data, then store them somewhere
2024-11-17 16:02:56 -05:00
}
2024-11-16 22:50:41 -05:00
}
}