diff --git a/src/com/redhat/ci/Utils.groovy b/src/com/redhat/ci/Utils.groovy index c783152..b88dcea 100644 --- a/src/com/redhat/ci/Utils.groovy +++ b/src/com/redhat/ci/Utils.groovy @@ -2,30 +2,37 @@ package com.redhat.ci import com.redhat.ci.hosts.ProvisionedHost import com.redhat.ci.provisioner.ProvisioningConfig +import com.redhat.ci.provisioner.ProvisioningException +import com.redhat.ci.provisioner.Mode /** * Utility class to perform actions upon CI hosts. */ class Utils { + private static final String SUDO = 'sudo' + private static final String NO_SUDO = '' + private static final String INSTALL_FILE = 'install.sh' + /** * Attemps to install Ansible. */ @SuppressWarnings('GStringExpressionWithinString') - static void installAnsible(Script script, ProvisionedHost host = null) { - installWrapper(script, host) { - h -> - script.sh ''' - sudo yum install python-devel openssl-devel libffi-devel -y && - sudo mkdir -p /home/jenkins && - sudo chown --recursive ${USER}:${USER} /home/jenkins && - sudo pip install --upgrade pip && - sudo pip install --upgrade setuptools && - sudo pip install --upgrade ansible - ''' - if (h == null) { + static void installAnsible(Script script, ProvisioningConfig config, ProvisionedHost host = null) { + genericInstall(script, config, host) { + privileged, sh -> + String sudo = privileged ? SUDO : NO_SUDO + sh(""" + ${sudo} yum install python-devel openssl-devel libffi-devel -y && + ${sudo} mkdir -p /home/jenkins && + ${sudo} chown --recursive \${USER}:\${USER} /home/jenkins && + ${sudo} pip install --upgrade pip && + ${sudo} pip install --upgrade setuptools && + ${sudo} pip install --upgrade ansible + """) + if (host == null) { return } - h.ansibleInstalled = true + host.ansibleInstalled = true } } @@ -33,8 +40,9 @@ class Utils { * Attempts to install SSH and Beaker credentials. */ static void installCredentials(Script script, ProvisioningConfig config, ProvisionedHost host = null) { - installWrapper(script, host) { - h -> + genericInstall(script, config, host) { + privileged, sh -> + String sudo = privileged ? SUDO : NO_SUDO script.withCredentials([ script.file(credentialsId:config.keytabCredentialId, variable:'KEYTAB'), script.usernamePassword(credentialsId:config.krbPrincipalCredentialId, @@ -46,14 +54,13 @@ class Utils { script.file(credentialsId:config.bkrConfCredentialId, variable:'BKRCONF'), ]) { script.env.HOME = '/home/jenkins' - script.sh """ - sudo yum install -y krb5-workstation || yum install -y krb5-workstation - sudo cp ${script.KRBCONF} /etc/krb5.conf || cp ${script.KRBCONF} /etc/krb5.conf - sudo mkdir -p /etc/beaker || mkdir -p /etc/beaker - sudo cp ${script.BKRCONF} /etc/beaker/client.conf || - cp ${script.BKRCONF} /etc/beaker/client.conf - sudo chmod 644 /etc/krb5.conf || chmod 644 /etc/krb5.conf - sudo chmod 644 /etc/beaker/client.conf || chmod 644 /etc/beaker/client.conf + sh(""" + ${sudo} yum install -y krb5-workstation + ${sudo} cp ${script.KRBCONF} /etc/krb5.conf + ${sudo} mkdir -p /etc/beaker + ${sudo} cp ${script.BKRCONF} /etc/beaker/client.conf + ${sudo} chmod 644 /etc/krb5.conf + ${sudo} chmod 644 /etc/beaker/client.conf kinit ${script.KRB_PRINCIPAL} -k -t ${script.KEYTAB} mkdir -p ~/.ssh cp ${script.SSHPRIVKEY} ~/.ssh/id_rsa @@ -62,9 +69,9 @@ class Utils { chmod 644 ~/.ssh/id_rsa.pub eval "\$(ssh-agent -s)" ssh-add ~/.ssh/id_rsa - """ - if (h != null) { - h.credentialsInstalled = true + """) + if (host != null) { + host.credentialsInstalled = true } } } @@ -74,23 +81,24 @@ class Utils { * Attempts to install and configure the RHPKG tool. */ @SuppressWarnings('LineLength') - static void installRhpkg(Script script, ProvisionedHost host = null) { - installWrapper(script, host) { - h -> - script.sh ''' - echo "pkgs.devel.redhat.com,10.19.208.80 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAplqWKs26qsoaTxvWn3DFcdbiBxqRLhFngGiMYhbudnAj4li9/VwAJqLm1M6YfjOoJrj9dlmuXhNzkSzvyoQODaRgsjCG5FaRjuN8CSM/y+glgCYsWX1HFZSnAasLDuW0ifNLPR2RBkmWx61QKq+TxFDjASBbBywtupJcCsA5ktkjLILS+1eWndPJeSUJiOtzhoN8KIigkYveHSetnxauxv1abqwQTk5PmxRgRt20kZEFSRqZOJUlcl85sZYzNC/G7mneptJtHlcNrPgImuOdus5CW+7W49Z/1xqqWI/iRjwipgEMGusPMlSzdxDX4JzIx6R53pDpAwSAQVGDz4F9eQ==" | sudo tee -a /etc/ssh/ssh_known_hosts + static void installRhpkg(Script script, ProvisioningConfig config, ProvisionedHost host = null) { + genericInstall(script, config, host) { + privileged, sh -> + String sudo = privileged ? SUDO : NO_SUDO + sh(""" + echo "pkgs.devel.redhat.com,10.19.208.80 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAplqWKs26qsoaTxvWn3DFcdbiBxqRLhFngGiMYhbudnAj4li9/VwAJqLm1M6YfjOoJrj9dlmuXhNzkSzvyoQODaRgsjCG5FaRjuN8CSM/y+glgCYsWX1HFZSnAasLDuW0ifNLPR2RBkmWx61QKq+TxFDjASBbBywtupJcCsA5ktkjLILS+1eWndPJeSUJiOtzhoN8KIigkYveHSetnxauxv1abqwQTk5PmxRgRt20kZEFSRqZOJUlcl85sZYzNC/G7mneptJtHlcNrPgImuOdus5CW+7W49Z/1xqqWI/iRjwipgEMGusPMlSzdxDX4JzIx6R53pDpAwSAQVGDz4F9eQ==" | ${sudo} tee -a /etc/ssh/ssh_known_hosts - echo "Host pkgs.devel.redhat.com" | sudo tee -a /etc/ssh/ssh_config - echo "IdentityFile /home/jenkins/.ssh/id_rsa" | sudo tee -a /etc/ssh/ssh_config + echo "Host pkgs.devel.redhat.com" | ${sudo} tee -a /etc/ssh/ssh_config + echo "IdentityFile /home/jenkins/.ssh/id_rsa" | ${sudo} tee -a /etc/ssh/ssh_config - sudo yum install -y yum-utils git + ${sudo} yum install -y yum-utils git curl -L -O http://download.devel.redhat.com/rel-eng/internal/rcm-tools-rhel-7-server.repo - sudo yum-config-manager --add-repo rcm-tools-rhel-7-server.repo - sudo yum install -y rhpkg + ${sudo} yum-config-manager --add-repo rcm-tools-rhel-7-server.repo + ${sudo} yum install -y rhpkg git config --global user.name "jenkins" - ''' - if (h != null) { - h.rhpkgInstalled = true + """) + if (host != null) { + host.rhpkgInstalled = true } } } @@ -100,16 +108,44 @@ class Utils { * If a provisioned host with a non-null displayName is passed in, the install step will be * attempted on that host; otherwise, the install with target the current node. */ - static void installWrapper(Script script, ProvisionedHost host, Closure install) { + static void genericInstall(Script script, ProvisioningConfig config, ProvisionedHost host, Closure installWrapper) { // Installation should occur on current node - if (host == null || host.displayName == null) { - install(host) + if (host == null) { + installWrapper(NO_SUDO) { + shCommand -> + script.sh(shCommand) + } + return + } + + // Installation should occur on target host (JNLP) + if (config.mode == Mode.JNLP) { + if (!host.displayName) { + throw new ProvisioningException('Installing in SSH mode but displayName is invalid.') + } + + script.node(host.displayName) { + installWrapper(SUDO) { + shCommand -> + script.sh(shCommand) + } + } return } - // Installation should occur on target host - script.node(host.displayName) { - install(host) + // Installation should occur on target host (SSH) + if (config.mode == Mode.SSH) { + if (!host.hostname) { + throw new ProvisioningException('Installing in SSH mode but hostname is invalid.') + } + + installWrapper(NO_SUDO) { + shCommand -> + script.writeFile(file:INSTALL_FILE, text:shCommand) + String runCommandOnHost = 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ' + + "-i ~/.ssh/id_rsa root@${host.hostname} < ${INSTALL_FILE}" + script.sh(runCommandOnHost) + } } } } diff --git a/src/com/redhat/ci/provisioners/LinchPinProvisioner.groovy b/src/com/redhat/ci/provisioners/LinchPinProvisioner.groovy index 3c282de..bea570d 100644 --- a/src/com/redhat/ci/provisioners/LinchPinProvisioner.groovy +++ b/src/com/redhat/ci/provisioners/LinchPinProvisioner.groovy @@ -86,7 +86,7 @@ class LinchPinProvisioner extends AbstractProvisioner { // In JNLP mode, we can install Ansible so the user can run playbooks // (Already installed in SSH mode) if (config.installAnsible) { - Utils.installAnsible(script, host) + Utils.installAnsible(script, config, host) } // In JNLP mode, install provisioning credentials directly on the provisioned host @@ -98,7 +98,7 @@ class LinchPinProvisioner extends AbstractProvisioner { // We can install the RHPKG tool if the user intends to use it. if (config.installRhpkg) { - Utils.installRhpkg(script, host) + Utils.installRhpkg(script, config, host) } } catch (e) { script.echo("Exception: ${e.message}") diff --git a/test/PipelineTestScript.groovy b/test/PipelineTestScript.groovy index 688b2cf..a2dd0ce 100644 --- a/test/PipelineTestScript.groovy +++ b/test/PipelineTestScript.groovy @@ -132,6 +132,11 @@ class PipelineTestScript extends Script { body() } + Closure writeFile = { + args -> + LOG.info("writeFile(${args})") + } + PipelineTestScript() { binding.with { currentBuild = [ diff --git a/test/com/redhat/ci/UtilsTest.groovy b/test/com/redhat/ci/UtilsTest.groovy index cc2bbf4..49ce23c 100644 --- a/test/com/redhat/ci/UtilsTest.groovy +++ b/test/com/redhat/ci/UtilsTest.groovy @@ -4,6 +4,7 @@ import org.junit.Test import org.junit.Before import com.redhat.ci.hosts.ProvisionedHost import com.redhat.ci.provisioner.ProvisioningConfig +import com.redhat.ci.provisioner.Mode /** * Tests the install script wrapper. @@ -12,13 +13,14 @@ class UtilsTest { private static final String INSTALLED = 'Installed' private static final String TEST_HOSTNAME = 'test-host' private static final String NODE_STEP = 'node' - private ProvisionedHost host = null + private ProvisionedHost validHost = null + private ProvisionedHost invalidHost = null private ProvisioningConfig config = null private PipelineTestScript script = null private final Closure genericInstall = { - host -> - script.sh(INSTALLED) + sudo, sh -> + sh(INSTALLED) } private final Closure node = { @@ -35,30 +37,31 @@ class UtilsTest { @Before void init() { - host = new ProvisionedHost() + validHost = new ProvisionedHost(hostname:TEST_HOSTNAME, displayName:TEST_HOSTNAME) + invalidHost = new ProvisionedHost() config = new ProvisioningConfig() script = new PipelineTestScript(node:node, sh:sh) } @Test void shouldInstallAnsibleOnProvisionedHost() { - assert(host.ansibleInstalled == false) - Utils.installAnsible(script, host) - assert(host.ansibleInstalled == true) + assert(validHost.ansibleInstalled == false) + Utils.installAnsible(script, config, validHost) + assert(validHost.ansibleInstalled == true) assert(script.testLog.contains(INSTALLED)) } @Test void shouldInstallAnsibleOnCurrentHost() { - Utils.installAnsible(script) + Utils.installAnsible(script, config) assert(script.testLog.contains(INSTALLED)) } @Test void shouldInstallCredentialsOnProvisionedHost() { - assert(host.credentialsInstalled == false) - Utils.installCredentials(script, config, host) - assert(host.credentialsInstalled == true) + assert(validHost.credentialsInstalled == false) + Utils.installCredentials(script, config, validHost) + assert(validHost.credentialsInstalled == true) assert(script.testLog.contains(INSTALLED)) } @@ -70,36 +73,61 @@ class UtilsTest { @Test void shouldInstallRhpkgOnProvisionedHost() { - assert(host.rhpkgInstalled == false) - Utils.installRhpkg(script, host) - assert(host.rhpkgInstalled == true) + assert(validHost.rhpkgInstalled == false) + Utils.installRhpkg(script, config, validHost) + assert(validHost.rhpkgInstalled == true) assert(script.testLog.contains(INSTALLED)) } @Test void shouldInstallRhpkgOnCurrentHost() { - Utils.installRhpkg(script) + Utils.installRhpkg(script, config) assert(script.testLog.contains(INSTALLED)) } @Test - void installWrapperShouldntWrapNullHost() { - Utils.installWrapper(script, null, genericInstall) + void genericInstallShouldntWrapNullHost() { + Utils.genericInstall(script, config, null, genericInstall) assert(script.testLog.contains(INSTALLED)) assert(!script.testLog.contains(NODE_STEP)) } @Test - void installWrapperShouldntWrapNamelessHost() { - Utils.installWrapper(script, host, genericInstall) + void genericInstallShouldntInstallOnNamelessHostInSSHMode() { + config.mode = Mode.SSH + Boolean exceptionOccured = false + try { + Utils.genericInstall(script, config, invalidHost, genericInstall) + } catch (e) { + exceptionOccured = true + } + assert(exceptionOccured) + } + + @Test + void genericInstallShouldntInstallOnNamelessHostInJNLPMode() { + config.mode = Mode.JNLP + Boolean exceptionOccured = false + try { + Utils.genericInstall(script, config, invalidHost, genericInstall) + } catch (e) { + exceptionOccured = true + } + assert(exceptionOccured) + } + + @Test + void genericInstallShouldntWrapNamedHostInSSHMode() { + config.mode = Mode.SSH + Utils.genericInstall(script, config, validHost, genericInstall) assert(script.testLog.contains(INSTALLED)) assert(!script.testLog.contains(NODE_STEP)) } @Test - void installWrapperShouldWrapNamedHost() { - host.displayName = TEST_HOSTNAME - Utils.installWrapper(script, host, genericInstall) + void genericInstallShouldWrapNamedHostInJNLPMode() { + config.mode = Mode.JNLP + Utils.genericInstall(script, config, validHost, genericInstall) assert(script.testLog.contains(INSTALLED)) assert(script.testLog.contains(NODE_STEP)) assert(script.testLog.contains(TEST_HOSTNAME)) diff --git a/vars/installBrewPkgs.groovy b/vars/installBrewPkgs.groovy index 5e61608..389fda0 100644 --- a/vars/installBrewPkgs.groovy +++ b/vars/installBrewPkgs.groovy @@ -1,5 +1,5 @@ -@SuppressWarnings('GStringExpressionWithinString') -void call(Map params) { +void call(Map params, Boolean privileged = false) { + String sudo = privileged ? 'sudo' : '' Boolean taskRepoCreated = false if (params.CI_MESSAGE != '') { tid = getTaskId(params.CI_MESSAGE) @@ -11,14 +11,14 @@ void call(Map params) { } if (taskRepoCreated == true) { - sh ''' - sudo yum install -y yum-utils + sh """ + ${sudo} yum install -y yum-utils URL=\$(cat task-repo.properties | grep TASK_REPO_URLS= | sed 's/TASK_REPO_URLS=//' | sed 's/;/\\n/g') - sudo yum-config-manager --add-repo \${URL} - sudo cat /etc/yum.repos.d/*download.eng.bos.redhat.com* - sudo sed -i 's/gpgcheck=1/gpgcheck=0/g' /etc/yum.repos.d/*download.eng.bos.redhat.com* - echo "gpgcheck=0" | sudo tee -a /etc/yum.repos.d/*download.eng.bos.redhat.com* - sudo yum clean all - ''' + ${sudo} yum-config-manager --add-repo \${URL} + ${sudo} cat /etc/yum.repos.d/*download.eng.bos.redhat.com* + ${sudo} sed -i 's/gpgcheck=1/gpgcheck=0/g' /etc/yum.repos.d/*download.eng.bos.redhat.com* + echo "gpgcheck=0" | ${sudo} tee -a /etc/yum.repos.d/*download.eng.bos.redhat.com* + ${sudo} yum clean all + """ } }