LoginSignup
0
0

More than 5 years have passed since last update.

Jenkins + PowerShell で出力書式がおかしくなる場合の対処

Posted at

ニッチな条件のバグ踏み抜いたのでメモ

TL;DR

  • 同じものを踏んだ場合は、以下のどれかで対処する。
    • Write-HostWrite-Information を利用しない、Write-Warning 等で代替する。
    • returnStdOut の場合はログを諦める。
    • PowerShellが直るのを待つ。
    • Jenkinsを64bit版に変更する。

環境

OS/MW バージョン
Windows Server 6.3.9600.0(2012 R2)
Jenkins 2.73.3(32bit)
PowerShell 5.0.10586.117

何が起きたか

JenkinsからPowerShellに連携して、PowerShellの途中でOutputとは別にログを表示しようとした時に
Format-List されて出力されていた。

JenkinsFile
node {
    def out = powershell returnStdout: true, script: 'Write-Host "Hello World."; "some output"'
    echo "PSResult = ${out}"
}
期待するログメッセージ
Hello World.
PSResult = some output
実際のログメッセージ
WriteInformationStream : True
MessageData            : Hello World.
Source                 : Write-Host
TimeGenerated          : 2017/11/29 20:43:20
Tags                   : {PSHOST}
User                   : ****\****
Computer               : ****
ProcessId              : 131196
NativeThreadId         : 21572
ManagedThreadId        : 14

PSResult = some output

なんか Format-List かかってるらしい!?

原因

簡単に上げると以下の感じで。

  • JVM + Jenkinsを32ビットで構築していたため、PowerShellも32ビットで動作していた
  • 出力内容を返すオプションを付けるとInformationのストリームリダイレクトが使われていた

PowerShell側の原因

32ビット版PowerShellにリダイレクトでフォーマットが変わるバグがあるらしい。
https://github.com/PowerShell/PowerShell/issues/2147

まさにこの挙動だった。
試したところ 6(Information) だとダメ、3~5(Warning,Verbose,Debug)だと大丈夫だったので
まさにピンポイントで踏んだらしい。

64ビット版の PowerShell ではこれが発生しないので開発チームでも優先度は低そうで、
github上でも post-6.0.0 としてタグが付いているので、直るのはまだ来年まではかかりそう。

Jenkins側の原因

アーキテクチャによる問題

構築当初にあまりちゃんと調査できてなかったこともあり、JVMとJenkinsを32ビットバージョンで構築していた。
そのためと思われるがPowerShellの実行も32ビット版が起動されているらしい。
(情報ソースはないので想像含む)

プラグインによる問題

Jenkins の PowerShell Plugin は returnStdOut を付けると標準出力の結果を戻り値として保持できるが、
その際にstdout以外の各ストリームをOutputにリダイレクトして、ファイルに保存してから表示するらしい。
該当ソースコード
ここで 6>&1 が付いてることによって、32ビットの問題と掛け合わせて見事にバグを踏み抜いている。

対応方法

64ビット環境で構築

一から環境を作るなら、JVMの64ビット版をインストールするとJenkinsが64ビット環境として稼働するらしい(?)
stack overflow
64ビットのJenkinsであればPowerShellも64ビット側が使われるので、一番きれいな方法はこれ。

returnStdOut を使わない

スクリプト実行をしたいだけで出力結果を変数などに拾う必要がなければ、returnStdOut を付けないだけでも解決する。

returnStdOutがない例
node {
    powershell 'Write-Host "Hello World."'
}

これなら渡した内容がそのまま出力される。

information以外のストリームに流す

元々PowerShellからのコンフィグを読みたくて returnStdOut は必須だったので、今回採用した方法がこれで。
Information以外ならなんでも大丈夫だけど、ErrorはStopかけている、VerboseとDebugは表示すると量が多いので
Warningがまだマシな感じで。

Warningストリームに流す
node {
    def out = powershell returnStdOut: true, script: '''\
$WarningPreference = "Continue"
Write-Warning "Hello World."
"some output"
'''
    echo "PSResult = ${out}"
}
出力結果
Hello World.
PSResult = some output

気にしない

そもそも余計な表示が増えるだけで他への動作影響はないので、気にしないのもありで。


参考

PowerShell Issue #2147
PowerShell Plugin

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0