Jenkinsfile内で指定した複数nodeで同じジョブを流す

テストとかビルドではあんまりやらないんでしょうけど・・・
WindowsUpdateの自動実行続きです。

例えば、host1 host2 host3 と対象としたいSlaveがあって、host2が生きていなければスキップしたいです。
でもJenkinsはしつこく待つのでnodeが生きてるときだけジョブを走らせます。

  • ノードを定義してジョブをぐるぐる回す。
def targets = ["host1", "host2", "host3"]

targets.each {
    node(it) {
        echo it
    }
}

これで定義したノード3つで同じジョブが実行されます。
でも、これだとノードが止まっているとそこでジョブ全体が止まってしまいます。

  • ノードが生きてるかチェックする

Jenkinsのスクリプトコンソールで以下のスクリプトを流してみます。

println jenkins.model.Jenkins.instance.getComputer('host1').isOnline()
println jenkins.model.Jenkins.instance.getComputer('host2').isOnline()

結果

true
false

ノードがオンラインかどうか取れました!
getComputer()の引数にはホスト名ではなくノード名を渡します。
ちなみにノードが存在しないとヌルポが返ります。

  • Jenkinsfileの中で実行するノードを判定する

上の2つを組み合わせるとこんな感じ。

def targets = ["host1", "host2", "host3"]

targets.each {
    if (jenkins.model.Jenkins.instance.getComputer(it).isOnline()) {
        node(it) {
            echo it
        }
    }
}

これでうまくいくと思いきや以下のようなエラーが出ます。

org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod jenkins.model.Jenkins getInstance
    at org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.StaticWhitelist.rejectStaticMethod(StaticWhitelist.java:189)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor$12.reject(SandboxInterceptor.java:348)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:381)
    at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:282)
    at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:286)
    at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
    at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
    at WorkflowScript.run(WorkflowScript:5)
    at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.each(CpsDefaultGroovyMethods:2030)
    at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.each(CpsDefaultGroovyMethods:2015)
    at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.each(CpsDefaultGroovyMethods:2056)
    at WorkflowScript.run(WorkflowScript:4)
    at ___cps.transform___(Native Method)
    at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:74)
    at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
    at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:66)
    at sun.reflect.GeneratedMethodAccessor303.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
    at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
    at com.cloudbees.groovy.cps.Next.step(Next.java:83)
    at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
    at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
    at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122)
    at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261)
    at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:19)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:35)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:32)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:32)
    at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:330)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$100(CpsThreadGroup.java:82)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:242)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:230)
    at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
    at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Finished: FAILURE

これはScript Security Pluginが許可されないメソッドを呼び出したときに出しているものだそうです。

qiita.com

なので、 Jenkinsの管理 > In-process Script Approval へ行き、エラーになっているメソッドを Approve します。
1つだけでなく繰り返し出るので何度か確認してください。

これで、実行できるようになるはずです。

次はいよいよPowerShellでWindowsUpdateを実行するジョブを記述します!