#!/usr/bin/env bash source ./auto/helper-logic # Clear the screen and print the header PrintHeader # Ensure we are running as root EnsureRoot # Ensure stage 1 is complete EnsureStageIsComplete 1 # Define variables INITIAL_PASSWORD_FILE="/var/lib/jenkins/secrets/initialAdminPassword" NETWORK_INTERFACES=`ls /sys/class/net/ -1 |grep -v -w "lo" |grep -v docker |grep -v dummy |grep -v veth` #region Run SSH script cp ./auto/ssh-script.sh /var/lib/jenkins chown jenkins:jenkins /var/lib/jenkins/ssh-script.sh # This script create the SSH key, adds it to the trusted keys and trusts the host itself. echo "Running SSH script as jenkins user..." runuser -l jenkins -c "./ssh-script.sh" echo rm /var/lib/jenkins/ssh-script.sh > /dev/null 2>&1 #endregion #region Run GnuPG script cp ./auto/gpg-script.sh /var/lib/jenkins chown jenkins:jenkins /var/lib/jenkins/gpg-script.sh # This script generates the GnuPG key pair. echo "Running GnuPG script as jenkins user..." runuser -l jenkins -c "./gpg-script.sh" echo rm /var/lib/jenkins/gpg-script.sh > /dev/null 2>&1 #endregion #region Initial Jenkins user setup and ask for credentials function PrintUrls { echo for INTERFACE in $NETWORK_INTERFACES; do IP_ADDRESS=`ifconfig $INTERFACE | grep 'inet '| cut -d: -f2 | awk '{ print $2}'` if [[ $IP_ADDRESS != "" ]]; then echo -e "${GREEN}http://$IP_ADDRESS:8080$1${NOCOLOR}" fi done echo } if [ -f $INITIAL_PASSWORD_FILE ]; then # This is the first run (or the previous run never made it to finish creating an admin user). INITIAL_PASSWORD=`cat /var/lib/jenkins/secrets/initialAdminPassword` echo -e "Please open a web browser, and go to one of these URLs:" PrintUrls echo -e "Then, login using this password: ${GREEN}$INITIAL_PASSWORD${NOCOLOR}" echo read -p "Press enter when you are logged on." echo echo -e "Now click the \"${GREEN}Install suggested plugins${NOCOLOR}\" button" echo read -p "Press enter when the plugins are done installing." echo echo "When prompted, create the first admin user." echo read -p "Please enter the username you choose here, and press enter: " USERNAME echo echo "Just leave the default url, and continue until you are greeted with the Welcome page." echo else # This is a re-run, so the admin user has already been created. if ([ ! -f $USERNAME_FILE ] || [ ! -f $TOKEN_FILE ]); then # There is no USERNAME_FILE or TOKEN_FILE, so we ask the user to provide the username. echo -e "Please open a web browser, and go to one of these URLs:" PrintUrls echo -e "Then, login using the credentials you have created before." echo read -p "Please enter your username here: " USERNAME echo fi fi if ([ ! -f $USERNAME_FILE ] || [ ! -f $TOKEN_FILE ]); then # There is no USERNAME_FILE or TOKEN_FILE, so we ask the user to provide the token. echo echo "If you already have generated a token, and know it, skip this step and just enter it below instead of creating a new one." echo -e "Once you reach the Welcome page, please go to one of these URLs:" PrintUrls "/user/$USERNAME/security" echo -e "Here you click the \"${GREEN}Add new Token${NOCOLOR}\" button, followed by the \"${GREEN}Generate${NOCOLOR}\" button (leave the text field empty)." echo read -p "Please enter the generated token here, and press enter: " TOKEN echo fi if ([ -f $USERNAME_FILE ] && [ -f $TOKEN_FILE ]); then # If we get here, the files already exists (so the user wouldn't have been asked above) # So we read them instead. USERNAME=`cat $USERNAME_FILE` TOKEN=`cat $TOKEN_FILE` fi #endregion # Ensure the Jenkins CLI has been downloaded. EnsureJenkinsCli # Test the connection to make sure Jenkins is ready. TestJenkinsConnection $USERNAME $TOKEN #region Install needed plugins # If we make it here, we know the username and token is valid, and Jenkins is running. echo "Installing plugins..." echo declare -A plugins plugins["docker-plugin"]="Docker" plugins["docker-workflow"]="Docker Pipeline" plugins["copyartifact"]="Copy Artifact" plugins["ssh-agent"]="SSH Agent" plugins["pipeline-utility-steps"]="Pipeline Utility Steps" plugins["job-dsl"]="Job DSL" for key in "${!plugins[@]}" do if (java -jar jenkins-cli.jar -s http://172.17.17.17:8080 -auth $USERNAME:$TOKEN list-plugins $key > /dev/null 2>&1); then PrintOkIndicator "$key is already installed." else function InstallPlugin { java -jar jenkins-cli.jar -s http://172.17.17.17:8080 -auth $USERNAME:$TOKEN install-plugin $1 -deploy } Run "InstallPlugin $key" \ "Installing $key plugin..." \ "Failed to install $key plugin." \ "Installed $key plugin." fi done echo #endregion #region Configure number of executors # Find the number of CPU cores available to the machine. NUMBER_OF_CPU_CORES="$(nproc)" # If the number is less than 4, we bump it up to 4. NUMBER_OF_CPU_CORES=$(( $NUMBER_OF_CPU_CORES < 4 ? 4 : $NUMBER_OF_CPU_CORES)) # Does the number of exectutors match the number of CPU cores? if [ "$(xmlstarlet sel -t -v '//numExecutors' -n /var/lib/jenkins/config.xml 2>/dev/null)" -eq $NUMBER_OF_CPU_CORES ]; then # Yep. PrintOkIndicator "Executors already set to ${NUMBER_OF_CPU_CORES}." else # Nope, so we stop Jenkins StopJenkins function ChangeExecutorCount { # We need to send 2 to /dev/null, since xmlstarlet prints warnings about xml version to stderr. xmlstarlet ed -L -u "/hudson/numExecutors" -v "$1" $JENKINS_CONFIG_FILE 2>/dev/null } # Then we update the config to match the number of CPU cores. Run "ChangeExecutorCount ${NUMBER_OF_CPU_CORES}" \ "Changing executor count to ${NUMBER_OF_CPU_CORES}..." \ "Failed to change executor count to ${NUMBER_OF_CPU_CORES}." \ "Changed executor count to ${NUMBER_OF_CPU_CORES}." fi #endregion #region Configure labels # Has the labels been configured? if grep -q ec2_amd64 $JENKINS_CONFIG_FILE; then # Yep. PrintOkIndicator "Labels are already configured." else # Nope, so we stop Jenkins StopJenkins function ConfigureLabels { # We need to send 2 to /dev/null, since xmlstarlet prints warnings about xml version to stderr. xmlstarlet ed -L -u "/hudson/label" -v "Docker docker ec2_amd64" $JENKINS_CONFIG_FILE 2>/dev/null } # Then we update the config to include the labels. Run "ConfigureLabels" \ "Configuring labels..." \ "Failed to configure labels." \ "Configured labels." fi #endregion #region Configure environment variables # Does the config contain the environment variables? if grep -q ARM64_BUILD_DISABLED $JENKINS_CONFIG_FILE; then # Yep PrintOkIndicator "Environment variables are already configured." else # Nope, so we stop Jenkins StopJenkins function ConfigureEnvironmentVariables { # We need to send 2 to /dev/null, since xmlstarlet prints warnings about xml version to stderr. xmlstarlet ed -L -s "/hudson/globalNodeProperties" -t elem -n "hudson.slaves.EnvironmentVariablesNodeProperty" -v "" \ -s "//hudson.slaves.EnvironmentVariablesNodeProperty" -t elem -n "envVars" -v "" \ -s "//envVars" -t attr -n "serialization" -v "custom" \ -s "//envVars" -t elem -n "unserializable-parents" -v "" \ -s "//envVars" -t elem -n "tree-map" -v "" \ -s "//tree-map" -t elem -n "default" -v "" \ -s "//default" -t elem -n "comparator" -v "" \ -i "//comparator" -t attr -n "class" -v "java.lang.String\$CaseInsensitiveComparator" \ -s "//tree-map" -t elem -n "int" -v "5" \ -s "//tree-map" -t elem -n "string" -v "ARM64_BUILD_DISABLED" \ -s "//tree-map" -t elem -n "string" -v "true" \ -s "//tree-map" -t elem -n "string" -v "CUSTOM_BUILD_CHECK_DISABLED" \ -s "//tree-map" -t elem -n "string" -v "true" \ -s "//tree-map" -t elem -n "string" -v "CUSTOM_DOCKER_REPO" \ -s "//tree-map" -t elem -n "string" -v "172.17.17.17:5000" \ -s "//tree-map" -t elem -n "string" -v "DEV_PACKAGES_VYOS_NET_HOST" \ -s "//tree-map" -t elem -n "string" -v "jenkins@172.17.17.17" \ -s "//tree-map" -t elem -n "string" -v "NOT_VYOS" \ -s "//tree-map" -t elem -n "string" -v "$NOT_VYOS" \ $JENKINS_CONFIG_FILE 2>/dev/null } # Then we update the config to include the environment variables. Run "ConfigureEnvironmentVariables" \ "Configuring environment variables..." \ "Failed to configure environment variables." \ "Configured environment variables." fi #endregion #region Configure Global Libraries # Sometimes the GlobalLibraries config file isn't there yet. if [ ! -f $JENKINS_GLOBALLIBRARIES_FILE ]; then # If that is the case, we copy a clean config into where it should be. cp ./auto/org.jenkinsci.plugins.workflow.libs.GlobalLibraries.xml $JENKINS_GLOBALLIBRARIES_FILE fi # Is the Global Libraries configured? if grep -q "vyos-build" $JENKINS_GLOBALLIBRARIES_FILE; then if FixJenkinsGlobalLibraryRepository; then # Yep. PrintOkIndicator "Global libraries are already configured." fi else # Nope, so we stop Jenkins StopJenkins function ConfigureGlobalLibraries { # We need to send 2 to /dev/null, since xmlstarlet prints warnings about xml version to stderr. xmlstarlet ed -L \ -d "/org.jenkinsci.plugins.workflow.libs.GlobalLibraries/libraries/@class" \ -s "/org.jenkinsci.plugins.workflow.libs.GlobalLibraries/libraries" -t elem -n "org.jenkinsci.plugins.workflow.libs.LibraryConfiguration" -v "" \ -s "//org.jenkinsci.plugins.workflow.libs.LibraryConfiguration" -t elem -n "name" -v "vyos-build" \ -s "//org.jenkinsci.plugins.workflow.libs.LibraryConfiguration" -t elem -n "retriever" \ -i "//retriever" -t attr -n "class" -v "org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever" \ -s "//retriever" -t elem -n "clone" -v "false" \ -s "//retriever" -t elem -n "scm" \ -i "//scm" -t attr -n "class" -v "jenkins.plugins.git.GitSCMSource" \ -i "//scm" -t attr -n "plugin" -v "git@5.2.2" \ -s "//scm" -t elem -n "id" -v "9d202e32-1889-4391-91e5-1b3445f035fd" \ -s "//scm" -t elem -n "remote" -v "https://github.com/notvyos/vyos-build.git" \ -s "//scm" -t elem -n "credentialsId" \ -s "//scm" -t elem -n "traits" \ -s "//traits" -t elem -n "jenkins.plugins.git.traits.BranchDiscoveryTrait" \ -s "//org.jenkinsci.plugins.workflow.libs.LibraryConfiguration" -t elem -n "implicit" -v "false" \ -s "//org.jenkinsci.plugins.workflow.libs.LibraryConfiguration" -t elem -n "allowVersionOverride" -v "true" \ -s "//org.jenkinsci.plugins.workflow.libs.LibraryConfiguration" -t elem -n "includeInChangesets" -v "true" \ $JENKINS_GLOBALLIBRARIES_FILE 2>/dev/null } # Then we update the config to global libraries configuration. Run "ConfigureGlobalLibraries" \ "Configuring global libraries..." \ "Failed to configure global libraries." \ "Configured global libraries." fi #endregion #region Configure Docker Declarative Pipeline # Sometimes the Docker Declarative config file isn't there yet. if [ ! -f $JENKINS_DOCKERDECLARATIVE_FILE ]; then # If that is the case, we copy a clean config into where it should be. cp ./auto/org.jenkinsci.plugins.docker.workflow.declarative.GlobalConfig.xml $JENKINS_DOCKERDECLARATIVE_FILE fi # Is the Docker Declarative plugin configured? if grep -q "172.17.17.17" $JENKINS_DOCKERDECLARATIVE_FILE; then # Yep. PrintOkIndicator "Docker Declarativ Pipeline is already configured." else # Nope, so we stop Jenkins StopJenkins function ConfigureDockerDeclarativePipeline { # We need to send 2 to /dev/null, since xmlstarlet prints warnings about xml version to stderr. xmlstarlet ed -L \ -s "/org.jenkinsci.plugins.docker.workflow.declarative.GlobalConfig/registry" -t elem -n "url" -v "http://172.17.17.17:5000" \ $JENKINS_DOCKERDECLARATIVE_FILE 2>/dev/null } # Then we update the config to global libraries configuration. Run "ConfigureDockerDeclarativePipeline" \ "Configuring Docker Declarativ Pipeline..." \ "Failed to configure Docker Declarativ Pipeline." \ "Configured Docker Declarativ Pipeline." fi #endregion # Restart Jenkins if it was stopped. StartJenkins #region Add SSH credentials if (java -jar jenkins-cli.jar -s http://172.17.17.17:8080 -auth $USERNAME:$TOKEN get-credentials-as-xml system::system::jenkins _ SSH-dev.packages.vyos.net > /dev/null 2>&1); then PrintOkIndicator "SSH key credential has already been created." else function CreateSshKeyCredential { java -jar jenkins-cli.jar -s http://172.17.17.17:8080 -auth $USERNAME:$TOKEN create-credentials-by-xml system::system::jenkins _ << EOF GLOBAL SSH-dev.packages.vyos.net jenkins false `cat /var/lib/jenkins/.ssh/id_ed25519` EOF } # We have to create the credential, since it is missing. Run "CreateSshKeyCredential" \ "Creating SSH key credential..." \ "Failed to create SSH key credential." \ "SSH key credential has been created." fi #endregion echo echo "Part 2 of the installer is now done." echo "Please run part three (3-repositories.sh) to set up the reprepro repositories." # Create marker file CreateMarkerFile 2