bitbucket-backup-clientでのバックアップがおかしくなったときの対応

Bitbucket Serverのバックアップをbitbucket-backup-clientを使ってcronで実行してます。
月曜の朝からBitbucketが使えないという連絡がSlackで入る・・・。

どうやら日曜日に実行したバックアップがおかしくなり月曜朝のバックアップもコケていた模様。

取り敢えずWebの画面からロック解除というのやってみる

f:id:gozuk16:20180305210539p:plain

キャンセルするには認証トークンを入力してください。これはBitbucketのログの中で探すことが出来ます。 と書いてあるけど何をキーに探すのやら。
取り敢えずググると公式文書がありました。

Using Bitbucket Server DIY Backup - Atlassian Documentation

Note that Bitbucket Server will still be locked in maintenance mode.
Repeat these steps using the "locked with" token (e.g. "7187ae1824ce1ede38a8e7de4bccf58d9a8e1a7a") 
to exit maintenance mode as well, and unlock Bitbucket Server.

↑と書いてあるのでログをあさって以下を見つけました。

atlassian-bitbucket-2018-03-04.log:2018-03-04 06:48:46,068
INFO  [http-nio-7991-exec-5] root @xxxxxxxxxxxxxxxx 10.x.x.x,127.0.0.1
"POST /mvc/admin/backups HTTP/1.0" c.a.s.i.m.DefaultMaintenanceService BACKUP started.
It may be canceled with token: ほにゃららtoken

ちょっと違うけど、このトークンでキャンセルできました!

が、次はメンテナンス画面になった。。。

f:id:gozuk16:20180305211004p:plain

メンテナンスのロック解除をやってみる

f:id:gozuk16:20180305211227p:plain

メンテナンスのキャンセル用認証トークンはまた別らしい・・・。
今度はログをあさっていろいろ試してみたら解除できました。

atlassian-bitbucket-2018-03-04.log:2018-03-04 06:48:45,618
INFO  [hz.hazelcast.cached.thread-5]
c.a.s.i.m.DefaultMaintenanceService The system has been locked for maintenance.
It may be unlocked with token: ほにゃららtoken

ふぃ〜。朝から疲れました。。。

Gradleでbuildすると1行目でいきなり"1: Invalid variable name."というエラーが出る

Groovyでちょっとした物を作り始めたら・・・

C:\home\gozu\projects\Foo\bar>gradlew jar
:compileJava UP-TO-DATE
:compileGroovy
startup failed:
C:\home\gozu\projects\Foo\bar\src\main\groovy\hogehoge.groovy: 1: Invalid variable name. Must start with a letter but was: ?
. At [1:1]  @ line 1, column 1.
   ?/*
   ^

1 error

:compileGroovy FAILED

FAILURE: Build failed with an exception.

ん?1行目?

あっ・・・(察し)
BOM付いてるじゃん。いつの間に・・・

Windows版 SourceTreeの文字化けを直す

Windows版のSourceTreeのUIで左側のブランチを選ぶところとかコミットログの日本語がお豆腐(□)になってしまってえらい困っていたのですが以下のサイトによるとWindowsUpdateの影響だったようです。
(Windows7で発症していてWindows10では発症していなかった。SourceTreeは両方とも2.4.7.0でした)

https://blog.hatena.ne.jp/gozuk16/gozuk16.hatenablog.com/entriescommunity.atlassian.com

KB4055532 が原因でMSから回避策が案内されているということでした。

https://support.microsoft.com/ja-jp/help/4074906/typeinitializationexception-or-fileformatexception-error-in-wpf-apps-t

↑をみるとアンインストールしてゴニョゴニョって書いてありましたが面倒なので、普通にWindowsUpdateで直らないかなーと思ってオプションを見てみると「Update for Microsoft .NET Framework 4.7.1 on Windows 7 SP and Windows Server 2008 R2 SP1 (KB4074906)」というのがあるので試しに入れてみました。

直りました!!!

MacのSlack(日本語設定)でWindowsと同じようにCtrl+Enterで送信する

諸事情あって日本語設定に変えざるをえないことになりました。
WindowsのSlackアプリではCtrl+Enterで送信ですが、MacになるとCommand+Enterなのが違和感があります。
しょうがないのでMacでもCtrl+Enterで送信できるようにKarabinerのprivate.xmlで定義を追加しました。

    <appdef>
        <appname>SLACK</appname>
        <equal>com.tinyspeck.slackmacgap</equal>
    </appdef>
    <item>
        <name>For Slack</name>
        <item>
            <name>Ctrl+Enter to post</name>
            <identifier>private.app_slack_post_with_ctrl_enter</identifier>
            <only>SLACK</only>
            <autogen>__KeyToKey__ KeyCode::RETURN, ModifierFlag::CONTROL_L, KeyCode::RETURN, ModifierFlag::COMMAND_L</autogen>
        </item>
    </item>

equal指定でSlackの時だけ、Ctrl+EnterをCommand+Enterに変えてるので特に悪影響は出てないはず。たぶん・・・

vim-markdownを入れた時にインサートモードが遅くなったときの回避法

随分前に rcmdnk/vim-markdown を入れて使ってたのですが、JekyllからHugoに乗り換えたのでアップデートしてfrontmatterの設定を追加したり、その他.vimrcをいじっていたら、インサートモードで入力してから文字が表示されるまでものすごく遅くなりました。

github.com

10秒以上遅延が発生するんでほんと困った。

ちなみに以下の設定は入れてありますが、遅い状況。

set synmaxcol=200
set lazyredraw
set ttyfast
set re=1

結論としては以下のような設定にすることでそれなりに早くなりました。

let g:vim_markdown_folding_disabled=1

let g:vim_markdown_liquid=1
let g:vim_markdown_math=0
let g:vim_markdown_frontmatter=1
let g:vim_markdown_toml_frontmatter=1
let g:vim_markdown_json_frontmatter=0

set nofoldenable

たぶんset nofoldenableがいけないのかなと思いましたがfoldしてほしくないので。。。
結局、vim_markdown_folding_disabled=1を組み合わせるとフォーマッタを効かせつつfolding無しでインサートモードでもそれなりのスピードで入力できるようになりました。

vim-markdown:TableFormat便利すぎるのでコレはすれられない。
素のtabularだけだと惜しい感じなんですよね。

なんか古い.vimrcみてたら整理したくなったけど今はやるべきではないと踏みとどまる理性はあったw

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を実行するジョブを記述します!

PowerShellでJenkinsのJNLP Slave起動のショートカットを作る

WindowsUpdateの自動実行が上手く動かないのに社内にWSUSが無いので手動やってたけど、いい加減バカバカしくなってきたのでJenkinsでなんとか出来ないか試行錯誤した過程でいろいろとノウハウを得たので忘れないようにメモしておく。

JenkinsのWindows Slaveを作る時に経験上Java Web Start(JNLP)でやるのが1番トラブルが少ないと思うのですが、いちいち設定するのが面倒なので多少楽にしようとあらかじめ作成した起動バッチのショートカットをAllUsersのスタートアップに作ります。

  • C:\jenkinsフォルダを作成
  • slave.jarをコピー
    • slave.jar は http://jenkins.example.com/jnlpJars/slave.jar にあります
  • 以下のJNLP起動バッチもコピーしてNODEとSECRETを自分のノードのものに書き換えます

NODEとSECRETは、Jenkinsの管理 > ノードの管理 > ノードを選択 > システム情報環境変数の所で見れます。
URLは、 http://jenkins.example.com/computer/${nodename}/systemInfo です。

@echo off

set NODE=win1
set SECRET=xxxxxxxxxxxxxx

cd C:\jenkins
start /min java -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -jar C:\jenkins\slave.jar -jnlpUrl http://jenkins.example.com/computer/%NODE%/slave-agent.jnlp -secret %SECRET%

C:\jenkinsにcdしているのはstartupから起動するとカレントディレクトリがC:\Windows\System32で起動するため想定しているのと違うjavaが起動してしまう事があったからです。
エンコーディングUTF-8にしているのはJenkinsのコンソールが文字化けしないようにしているためです。

  • 以下のショートカット作成PowerShellを流す
$WsShell = New-Object -ComObject WScript.Shell

$Shortcut = $WsShell.CreateShortcut($env:ALLUSERSPROFILE + "\Microsoft\Windows\Start Menu\Programs\Startup\jenkins-jnlp.lnk")
$Shortcut.TargetPath = "C:\jenkins\jenkins-jnlp.bat"
$Shortcut.IconLocation = "C:\jenkins\jenkins-jnlp.bat"
$Shortcut.Save()

念のために、デスクトップにも作りたければ以下のようにしておきます。

$Shortcut = $WsShell.CreateShortcut($env:PUBLIC + "\Desktop\jenkins-jnlp.lnk")
$Shortcut.TargetPath = "C:\jenkins\jenkins-jnlp.bat"
$Shortcut.IconLocation = "C:\jenkins\jenkins-jnlp.bat"
$Shortcut.Save()

全ユーザのデスクトップに出ます。

ちなみにWindows7より古いのは考慮してないです。
あとJREは入れてある想定・・・。