From c8939b6af9014c959334c498497356f63120dd34 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Mon, 17 Oct 2022 16:16:03 -0400 Subject: [PATCH 1/4] tree: drop gangplank.groovy We've moved away from Gangplank for now in favour of `podman remote`: https://github.com/coreos/coreos-assembler/issues/2860 --- vars/gangplank.groovy | 203 ------------------------------------------ 1 file changed, 203 deletions(-) delete mode 100644 vars/gangplank.groovy diff --git a/vars/gangplank.groovy b/vars/gangplank.groovy deleted file mode 100644 index cabda03..0000000 --- a/vars/gangplank.groovy +++ /dev/null @@ -1,203 +0,0 @@ -// Run gangplank - -// Available parameters: -// artifacts: list -- list of artifacts to be built -// bucket: string -- name other minio bucket to use -// extraFlags: string -- Extra flags to use -// image: string -- Name of the image to be used -// mode: string -- Gangplank Mode -// workDir: string -- Cosa working directory - -def buildArtifact(params = [:]) { - gangplankCmd = _getMode(params) - gangplankCmd = _getArtifacts(params, gangplankCmd) - _runGangplank(gangplankCmd) -} - -// Available parameters: -// artifacts: list -- List of artifacts to be built -// extraFlags: string -- Extra flags to use -// image: string -- Name of the image to be used -// mode: string -- Gangplank Mode -// minioServeDir: string -- Location to service minio from -// workDir: string -- Cosa working directory - -def buildParallelArtifacts(params = [:]) { - gangplankCmd = _getMode(params) - if (params['artifacts']) { - def artifacts = params['artifacts'] - def configFile = startMinio(params) - - // Call one pod for each artifact in parallel - parallel artifacts.inject([:]) { d, i -> d[i] = { - startParallel(configFile, "${gangplankCmd} -A ${i} ") - }; d } - _finalize(params) - } -} - -// Available parameters: -// artifacts: list -- List of artifacts to be built -// extraFlags: string -- Extra flags to use -// singlePod: boolean -- Run generateSinglePod - -def generateSpec(params = [:]) { - if(params['singlePod']) { - gangplankCmd = "gangplank generateSinglePod " - } else { - gangplankCmd = "gangplank generate " - } - gangplankCmd = _getArtifacts(params, gangplankCmd) - gangplankCmd = _getFlags(params, gangplankCmd) - fileName = "/tmp/jobspec-${UUID.randomUUID()}.spec" - gangplankCmd += "--yaml-out ${fileName} " - _runGangplank(gangplankCmd) - return fileName -} - -// Available parameters: -// configFile: string -- Name of the Minio config file previously created -// gangplankCmd: string -- Gangplank command to run -def startParallel(configFile, gangplankCmd) { - gangplankCmd += "-m ${configFile}" - _runGangplank(gangplankCmd) -} - -// Available parameters: -// artifacts: list -- List of artifacts to be built -// extraFlags: string -- Extra flags to use -// image: string -- Name of the image to be used -// mode: string -- Gangplank Mode -// minioServeDir string -- Location to service minio from -// workDir: string -- Cosa working directory -def startMinio(params =[:]) { - def configFile = "/tmp/${UUID.randomUUID()}-minio.yaml" - def minioServeDir = params.get('minioServeDir', "/srv") - def gangplankCmd = "gangplank minio -m ${configFile} -d ${minioServeDir}" - - // Minio needs to run in background, JENKINS_NODE_COOKIE allows it - gangplankCmd = "export JENKINS_NODE_COOKIE=dontKillMe && nohup ${gangplankCmd} &" - _runGangplank(gangplankCmd) - // Workaround - Wait for minio to start - shwrap("sleep 0.5") - - return configFile -} - -def _runGangplank(gangplankCmd) { - try { - shwrap("${gangplankCmd}") - echo "Gangplank command finished successfully!" - } catch (Exception e) { - print(e) - currentBuild.result = 'ABORTED' - error("Error running gangplank.") - } -} - -// Available parameters: -// artifacts: list -- List of artifacts to be built -// extraFlags: string -- Extra flags to use -// mode: string -- Gangplank Mode -// spec: string -- Name of the spec file -def runSpec(params =[:]) { - if (params['spec']) { - gangplankCmd = _getMode(params) - gangplankCmd += "--spec ${params['spec']} " - _runGangplank(gangplankCmd) - } else { - error("runSpec requires a spec param.") - } -} - -// Available parameters: -// cmd: string -- the single command to run -// mode: string -- Gangplank Mode -// extraFlags: string -- Extra flags to use -def runSingleCmd(params = [:]) { - if (params['cmd']) { - gangplankCmd = _getMode(params) - gangplankCmd += " --singleCmd \"${params['cmd']}\"" - _runGangplank(gangplankCmd) - } else { - error("runSingleCmd requires a cmd param.") - } -} - -// A function to wrap runSpec and runSingleCmd based on params -// builder host. Accepts a params map with the usual parameters for -// a call to runSpec or runSingleCmd. -def runGangplank(params = [:]) { - if (params['spec']) { - runSpec(params) - } else { - runSingleCmd(params) - } -} - -def _finalize(params = [:]) { - gangplankCmd = "gangplank pod " - gangplankCmd = _getImage(params, gangplankCmd) - gangplankCmd = _getBucket(params, gangplankCmd) - gangplankCmd += " -A finalize" - _runGangplank(gangplankCmd) -} - -def _getArtifacts(params =[:], gangplankCmd) { - if (params['artifacts']) { - def artifacts = params['artifacts'].join(",") - gangplankCmd += "--build-artifact ${artifacts} " - return gangplankCmd - } - return gangplankCmd -} - -def _getBucket(params =[:], gangplankCmd) { - if (params['bucket']) { - gangplankCmd += "--bucket ${params['bucket']} " - return gangplankCmd - } - return gangplankCmd -} - -def _getFlags(params = [:], gangplankCmd) { - if (params['extraFlags']) { - gangplankCmd += params['extraFlags'] + " " - return gangplankCmd - } - return gangplankCmd -} - -def _getImage(params = [:], gangplankCmd) { - if (params['image']) { - gangplankCmd += "--image ${params['image']} " - return gangplankCmd - } - return gangplankCmd -} - -def _getArch(params = [:], gangplankCmd) { - if (params['arch']) { - gangplankCmd += "--arch ${params['arch']} " - return gangplankCmd - } - return gangplankCmd -} - -def _getMode(params = [:]) { - gangplankCmd = "gangplank " + params.get('mode', "pod") + " " - gangplankCmd = _getFlags(params, gangplankCmd) - gangplankCmd = _getImage(params, gangplankCmd) - gangplankCmd = _getArch(params, gangplankCmd) - gangplankCmd = _getWorkDir(params, gangplankCmd) - gangplankCmd = _getBucket(params, gangplankCmd) - return gangplankCmd -} - -def _getWorkDir(params = [:], gangplankCmd) { - if(params['cosaDir']) { - gangplankCmd += "--workDir ${utils.getCosaDir(params)} " - return gangplankCmd - } - return gangplankCmd -} From 4164e8723b5a8099e756c700bf95dff438abb0e7 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Mon, 17 Oct 2022 16:24:56 -0400 Subject: [PATCH 2/4] tree: drop cosaParallelCmds This was a good idea, but in practice the CoreOS pipeline implements a more sophisticated version of it which include list splitting. We could try to upstream that, but in the meantime, this is only used by one upstream CI right now (cosa's), so we'll just inline it there. The reason for this is that it uses `cosaCmd` and `cosaDir`, both things I'm trying to get rid of. --- vars/cosaParallelCmds.groovy | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 vars/cosaParallelCmds.groovy diff --git a/vars/cosaParallelCmds.groovy b/vars/cosaParallelCmds.groovy deleted file mode 100644 index 55efd7e..0000000 --- a/vars/cosaParallelCmds.groovy +++ /dev/null @@ -1,13 +0,0 @@ -// Run cosa commands in parallel -// Available parameters: -// cosaDir: string -- cosa working directory -// commands: []string -- list of commands to run -// user: string -- user account to run cosa commands - -def call(params = [:]) { - def commands = params['commands']; - - parallel commands.inject([:]) { d, i -> d[i] = { - utils.cosaCmd(cosaDir: params['cosaDir'], user: params['user'], args: "buildextend-${i.toLowerCase()}") - }; d } -} From aeb424e21c35e3969be4a760155af4d6bd8928c8 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Mon, 17 Oct 2022 16:36:03 -0400 Subject: [PATCH 3/4] cosaBuild: drop support for `make` and `makeDirs` Projects are now expected to be built in a separate pod (likely provisioned with `buildPod`) instead of building code directly in the cosa pod. --- vars/cosaBuild.groovy | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/vars/cosaBuild.groovy b/vars/cosaBuild.groovy index 5f481ae..0048785 100644 --- a/vars/cosaBuild.groovy +++ b/vars/cosaBuild.groovy @@ -4,8 +4,6 @@ // extraArgs: string -- Extra arguments to pass to `cosa build` // extraFetchArgs: string -- Extra arguments to pass to `cosa fetch` // gitBranch string -- Git Branch for fedora-coreos-config -// make: boolean -- Run `make && make install DESTDIR=...` -// makeDirs: []string -- Extra list of directories from which to `make && make install DESTDIR=...` // noForce: boolean -- Do not force a cosa build even if nothing changed // noStrict boolean -- Do not run cosa using `--strict' option // overlays: []string -- List of directories to overlay @@ -27,15 +25,6 @@ def call(params = [:]) { shwrap("cd ${cosaDir} && cosa init ${branchArg} https://github.com/coreos/fedora-coreos-config") } - if (params['make']) { - shwrap("make && make install DESTDIR=${cosaDir}/overrides/rootfs") - } - if (params['makeDirs']) { - params['makeDirs'].each{ - shwrap("make -C ${it} && make -C ${it} install DESTDIR=${cosaDir}/overrides/rootfs") - } - } - if (params['overlays']) { params['overlays'].each{ shwrap("rsync -av ${it}/ ${cosaDir}/overrides/rootfs") From d36222c29fa6cebe2eddc3cd0435626af450acba Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Mon, 17 Oct 2022 16:36:58 -0400 Subject: [PATCH 4/4] tree: drop support for `cosaDir` Support for the cosa directory being different from the working directory makes implementation details messier. Drop support for it. Callers can still have their cosa directories be different from the Jenkins workspace by first wrapping calls to the cosa APIs here in a call to `dir(cosaDir)`: ``` dir(cosaDir) { cosaBuild(skipKola: true) kola() kolaTestIso(skipMetal4k: true) } ``` The cosa directory currently needs to be a subdirectory of the workspace (see https://github.com/coreos/coreos-ci-lib/pull/124). --- vars/cosaBuild.groovy | 12 ++++-------- vars/kola.groovy | 25 +++++++++++-------------- vars/kolaTestIso.groovy | 18 ++++++++---------- vars/utils.groovy | 23 ----------------------- 4 files changed, 23 insertions(+), 55 deletions(-) diff --git a/vars/cosaBuild.groovy b/vars/cosaBuild.groovy index 0048785..b6743c7 100644 --- a/vars/cosaBuild.groovy +++ b/vars/cosaBuild.groovy @@ -1,6 +1,5 @@ // Build CoreOS, possibly with modifications. // Available parameters: -// cosaDir: string -- Cosa working directory // extraArgs: string -- Extra arguments to pass to `cosa build` // extraFetchArgs: string -- Extra arguments to pass to `cosa fetch` // gitBranch string -- Git Branch for fedora-coreos-config @@ -11,23 +10,20 @@ // skipKola: boolean -- Do not automatically run kola on resulting build def call(params = [:]) { stage("Build") { - def cosaDir = utils.getCosaDir(params) def extraFetchArgs = params.get('extraFetchArgs', ""); def extraArgs = params.get('extraArgs', ""); - shwrap("mkdir -p ${cosaDir}") - if (!params['skipInit']) { def branchArg = "" if (params['gitBranch']) { branchArg = "--branch ${params['gitBranch']}" } - shwrap("cd ${cosaDir} && cosa init ${branchArg} https://github.com/coreos/fedora-coreos-config") + shwrap("cosa init ${branchArg} https://github.com/coreos/fedora-coreos-config") } if (params['overlays']) { params['overlays'].each{ - shwrap("rsync -av ${it}/ ${cosaDir}/overrides/rootfs") + shwrap("rsync -av ${it}/ overrides/rootfs") } } if (!params['noStrict']) { @@ -38,8 +34,8 @@ def call(params = [:]) { extraArgs = "--force ${extraArgs}" } - shwrap("cd ${cosaDir} && cosa fetch ${extraFetchArgs}") - shwrap("cd ${cosaDir} && cosa build ${extraArgs}") + shwrap("cosa fetch ${extraFetchArgs}") + shwrap("cosa build ${extraArgs}") } if (!params['skipKola']) { diff --git a/vars/kola.groovy b/vars/kola.groovy index 257adad..1831740 100644 --- a/vars/kola.groovy +++ b/vars/kola.groovy @@ -3,7 +3,6 @@ // addExtTests: []string -- list of test paths to run // allowUpgradeFail boolean -- warn instead of fail on upgrade failure // arch: string -- the target architecture -// cosaDir: string -- cosa working directory // parallel: integer -- number of tests to run in parallel (default: # CPUs) // skipBasicScenarios boolean -- skip basic qemu scenarios // skipUpgrade: boolean -- skip running `cosa kola --upgrades` @@ -13,8 +12,6 @@ // disableRerun: boolean -- disable reruns of failed tests // marker: string -- some identifying text to add to uploaded artifact filenames def call(params = [:]) { - def cosaDir = utils.getCosaDir(params) - // this is shared between `kola run` and `kola run-upgrade` def platformArgs = params.get('platformArgs', ""); def buildID = params.get('build', "latest"); @@ -31,7 +28,7 @@ def call(params = [:]) { def token = shwrapCapture("uuidgen | cut -f1 -d-") // Create a unique output directory for this run of kola - def outputDir = shwrapCapture("cd ${cosaDir} && cosa shell -- mktemp -d ${cosaDir}/tmp/kola-XXXXX") + def outputDir = shwrapCapture("cosa shell -- mktemp -d tmp/kola-XXXXX") // list of identifiers for each run for log collection def ids = [] @@ -48,7 +45,7 @@ def call(params = [:]) { // src/config repo which is also automatically added. if (shwrapRc(""" test -d ${env.WORKSPACE}/tests/kola - configorigin=\$(cd ${cosaDir}/src/config && git config --get remote.origin.url) + configorigin=\$(cd src/config && git config --get remote.origin.url) gitorigin=\$(cd ${env.WORKSPACE} && git config --get remote.origin.url) test "\$configorigin" != "\$gitorigin" """) == 0) @@ -61,8 +58,8 @@ def call(params = [:]) { shwrap("mkdir -p /var/tmp/kola && ln -s ${env.WORKSPACE} /var/tmp/kola/${name}") } else { shwrap(""" - cd ${cosaDir} && cosa shell -- mkdir -p /var/tmp/kola - cd ${cosaDir} && cosa remote-session sync ${env.WORKSPACE}/ :/var/tmp/kola/${name}/ + cosa shell -- mkdir -p /var/tmp/kola + cosa remote-session sync ${env.WORKSPACE}/ :/var/tmp/kola/${name}/ """) } args += "--exttest /var/tmp/kola/${name}" @@ -87,23 +84,23 @@ def call(params = [:]) { // do a single run in that case. id = marker == "" ? "kola" : "kola-${marker}" ids += id - shwrap("cd ${cosaDir} && cosa kola run ${rerun} --output-dir=${outputDir}/${id} --build=${buildID} ${archArg} ${platformArgs} --parallel ${parallel} ${args} ${extraArgs}") + shwrap("cosa kola run ${rerun} --output-dir=${outputDir}/${id} --build=${buildID} ${archArg} ${platformArgs} --parallel ${parallel} ${args} ${extraArgs}") } else { // basic run if (!params['skipBasicScenarios']) { id = marker == "" ? "kola-basic" : "kola-basic-${marker}" ids += id - shwrap("cd ${cosaDir} && cosa kola run ${rerun} --output-dir=${outputDir}/${id} --basic-qemu-scenarios") + shwrap("cosa kola run ${rerun} --output-dir=${outputDir}/${id} --basic-qemu-scenarios") } // normal run (without reprovision tests because those require a lot of memory) id = marker == "" ? "kola" : "kola-${marker}" ids += id - shwrap("cd ${cosaDir} && cosa kola run ${rerun} --output-dir=${outputDir}/${id} --build=${buildID} ${archArg} ${platformArgs} --tag '!reprovision' --parallel ${parallel} ${args}") + shwrap("cosa kola run ${rerun} --output-dir=${outputDir}/${id} --build=${buildID} ${archArg} ${platformArgs} --tag '!reprovision' --parallel ${parallel} ${args}") // re-provision tests (not run with --parallel argument to kola) id = marker == "" ? "kola-reprovision" : "kola-reprovision-${marker}" ids += id - shwrap("cd ${cosaDir} && cosa kola run ${rerun} --output-dir=${outputDir}/${id} --build=${buildID} ${archArg} ${platformArgs} --tag reprovision ${args}") + shwrap("cosa kola run ${rerun} --output-dir=${outputDir}/${id} --build=${buildID} ${archArg} ${platformArgs} --tag reprovision ${args}") } } @@ -115,7 +112,7 @@ def call(params = [:]) { try { def id = marker == "" ? "kola-upgrade" : "kola-upgrade-${marker}" ids += id - shwrap("cd ${cosaDir} && cosa kola ${rerun} --output-dir=${outputDir}/${id} --upgrades --build=${buildID} ${archArg} ${platformArgs}") + shwrap("cosa kola ${rerun} --output-dir=${outputDir}/${id} --upgrades --build=${buildID} ${archArg} ${platformArgs}") } catch(e) { if (params["allowUpgradeFail"]) { warnError(message: 'Upgrade Failed') { @@ -137,9 +134,9 @@ def call(params = [:]) { } finally { for (id in ids) { // sanity check kola actually ran and dumped its output - shwrap("cd ${cosaDir} && cosa shell -- test -d ${outputDir}/${id}") + shwrap("cosa shell -- test -d ${outputDir}/${id}") // collect the output - shwrap("cd ${cosaDir} && cosa shell -- tar -c --xz ${outputDir}/${id} > ${env.WORKSPACE}/${id}-${token}.tar.xz || :") + shwrap("cosa shell -- tar -c --xz ${outputDir}/${id} > ${env.WORKSPACE}/${id}-${token}.tar.xz || :") archiveArtifacts allowEmptyArchive: true, artifacts: "${id}-${token}.tar.xz" } } diff --git a/vars/kolaTestIso.groovy b/vars/kolaTestIso.groovy index d0c13e0..a596bcf 100644 --- a/vars/kolaTestIso.groovy +++ b/vars/kolaTestIso.groovy @@ -1,7 +1,6 @@ // Run kola testiso // Available parameters: // arch: string -- the target architecture -// cosaDir: string -- cosa working directory // extraArgs: string -- extra arguments to pass to `kola testiso` // extraArgs4k: string -- extra arguments to pass to 4k `kola testiso` // extraArgsMultipath: string -- extra arguments to pass to multipath `kola testiso` @@ -16,7 +15,6 @@ // marker: string -- some identifying text to add to uploaded artifact filenames def call(params = [:]) { def arch = params.get('arch', "x86_64"); - def cosaDir = utils.getCosaDir(params) def extraArgs = params.get('extraArgs', ""); def extraArgs4k = params.get('extraArgs4k', ""); def extraArgsMultipath = params.get('extraArgsMultipath', ""); @@ -34,7 +32,7 @@ def call(params = [:]) { def token = shwrapCapture("uuidgen | cut -f1 -d-") // Create a unique output directory for this run of fcosKola - def outputDir = shwrapCapture("cd ${cosaDir} && cosa shell -- mktemp -d ${cosaDir}/tmp/kolaTestIso-XXXXX") + def outputDir = shwrapCapture("cosa shell -- mktemp -d tmp/kolaTestIso-XXXXX") // list of identifiers for each run for log collection def ids = [] @@ -44,7 +42,7 @@ def call(params = [:]) { def id = marker == "" ? "kola-testiso-metal" : "kola-testiso-metal-${marker}" ids += id def scenariosArg = scenarios == "" ? "" : "--scenarios ${scenarios}" - shwrap("cd ${cosaDir} && cosa kola testiso -S ${extraArgs} ${scenariosArg} --output-dir ${outputDir}/${id}") + shwrap("cosa kola testiso -S ${extraArgs} ${scenariosArg} --output-dir ${outputDir}/${id}") } if (!params['skipMetal4k']) { // metal4k test doesn't work on s390x for now @@ -55,7 +53,7 @@ def call(params = [:]) { def id = marker == "" ? "kola-testiso-metal4k" : "kola-testiso-metal4k-${marker}" ids += id def scenariosArg = scenarios4k == "" ? "" : "--scenarios ${scenarios4k}" - shwrap("cd ${cosaDir} && cosa kola testiso -S --qemu-native-4k ${extraArgs4k} ${scenariosArg} --output-dir ${outputDir}/${id}") + shwrap("cosa kola testiso -S --qemu-native-4k ${extraArgs4k} ${scenariosArg} --output-dir ${outputDir}/${id}") } } } @@ -63,7 +61,7 @@ def call(params = [:]) { testIsoRuns["${arch}:kola:multipath"] = { def id = marker == "" ? "kola-testiso-multipath" : "kola-testiso-multipath-${marker}" ids += id - shwrap("cd ${cosaDir} && cosa kola testiso -S --qemu-multipath ${extraArgsMultipath} --scenarios ${scenariosMultipath} --output-dir ${outputDir}/${id}") + shwrap("cosa kola testiso -S --qemu-multipath ${extraArgsMultipath} --scenarios ${scenariosMultipath} --output-dir ${outputDir}/${id}") } } if (!params['skipUEFI']) { @@ -76,9 +74,9 @@ def call(params = [:]) { testIsoRuns["${arch}:kola:uefi"] = { def id = marker == "" ? "kola-testiso-uefi" : "kola-testiso-uefi-${marker}" ids += id - shwrap("cd ${cosaDir} && cosa shell -- mkdir -p ${outputDir}/${id}") - shwrap("cd ${cosaDir} && cosa kola testiso -S --qemu-firmware=uefi ${extraArgsUEFI} --scenarios ${scenariosUEFI} --output-dir ${outputDir}/${id}/insecure") - shwrap("cd ${cosaDir} && cosa kola testiso -S --qemu-firmware=uefi-secure ${extraArgsUEFI} --scenarios ${scenariosUEFI} --output-dir ${outputDir}/${id}/secure") + shwrap("cosa shell -- mkdir -p ${outputDir}/${id}") + shwrap("cosa kola testiso -S --qemu-firmware=uefi ${extraArgsUEFI} --scenarios ${scenariosUEFI} --output-dir ${outputDir}/${id}/insecure") + shwrap("cosa kola testiso -S --qemu-firmware=uefi-secure ${extraArgsUEFI} --scenarios ${scenariosUEFI} --output-dir ${outputDir}/${id}/secure") } } } @@ -97,7 +95,7 @@ def call(params = [:]) { } } finally { for (id in ids) { - shwrap("cd ${cosaDir} && cosa shell -- tar -c --xz ${outputDir}/${id} > ${env.WORKSPACE}/${id}-${token}.tar.xz || :") + shwrap("cosa shell -- tar -c --xz ${outputDir}/${id} > ${env.WORKSPACE}/${id}-${token}.tar.xz || :") archiveArtifacts allowEmptyArchive: true, artifacts: "${id}-${token}.tar.xz" } } diff --git a/vars/utils.groovy b/vars/utils.groovy index ec0759e..21c0351 100644 --- a/vars/utils.groovy +++ b/vars/utils.groovy @@ -1,26 +1,3 @@ -def cosaCmd(params = [:]) { -// Available parameters: -// cosaDir: string -- cosa working directory -// args: string -- arguments to pass to `cosa` -// user: string -- user to run the cosa commands - def cosaDir = getCosaDir(params) - def args = params.get('args', ""); - - if(!params['user']) { - shwrap("cd ${cosaDir} && cosa ${args}") - } else { - shwrap("cd ${cosaDir} && sudo -u ${params['user']} cosa ${args}") - } -} - -def getCosaDir(params = [:]) { - if (params['cosaDir']) { - return params['cosaDir'] - } else { - return "/srv/coreos" - } -} - // This is like fileExists, but actually works inside the Kubernetes container. def pathExists(path) { return shwrapRc("test -e ${path}") == 0