WSUSでmovecontent完了後、sqlserverがCPU 100%に貼りついて何もできなくなった話

結論

WSUSサーバのディスク容量が逼迫してきたので、HDDを増設しContentを移動したが、 (この環境では)movecontentしないでアンインストール& 再インストール時にWsusContentのpathを変更した方がよかった。

経緯

HDD増設後NTFSフォーマットして、新ドライブ下フォルダにWsusContentを移動

> cd "C:\Program Files\Update Services\Tools" 
> wsusutil.exe movecontent F:\WSUS F:\move.log

wsustil.exeが完了、コマンドプロンプトに戻ってきた。 上記move.logの内容は下記のとおりで正常に終わったぽい。

2015-05-08T11:58:50 Successfully stopped WsusService.
2015-05-08T11:58:50 Beginning content file location change to F:\WSUS
2015-05-08T13:11:16 Successfully copied content files.
2015-05-08T13:11:16 Successfully copied application files.
2015-05-08T13:11:30 Successfully changed WUS configuration.
2015-05-08T13:11:31 Successfully changed IIS virtual directory path.
2015-05-08T13:11:31 Successfully removed existing local content network shares.
2015-05-08T13:11:31 Successfully created local content network shares.
2015-05-08T13:11:31 Successfully changed registry value for content store directory.
2015-05-08T13:11:31 Successfully changed content file location.
2015-05-08T13:11:33 Successfully started WsusService.
2015-05-08T13:11:33 Content integrity check and repair...
2015-05-08T13:11:37 Initiated content integrity check and repair.

で、WSUS管理コンソールを開いたら応答がなく、 タスクマネージャーで確認したら、sqlserver(Windows Internal Databaseを使用)が CPUを食い尽くしていた。(4コア機なので実際は25%)

WSUSのログ"C:\Program Files\Update Services\LogFiles\SoftwareDistribution.log"を確認すると、SQLserverへの接続がタイムアウトしたというエラーが出ている。 上記move.logの最後にあるように、wsusutil.exeの実行は終了しても その後wsusservice実行の中で整合性チェック&repairが呼出されるらしい。

この処理に要する時間は、更新の数に依存するらしいが目安は不明。 以下のURLによれば「in some cases several days」もあり得るという。

https://social.technet.microsoft.com/Forums/en-US/99df985b-f88b-471b-9b66-fd92203de323/wsus-not-working-after-movecontent?forum=winserverwsus

開発の都合で、多数の製品を同期しており更新の数は多かった。 (管理コンソールが開かなくなったので確認できていない。 WsusContent下のファイル数でいえば3万ぐらいだったと思う)

結局、1週間たってもCPU貼りつき状態のままだったのでアンインストール&再インストールした。 ネットワーク環境の問題もあるので一般化できないが、メタデータ同期+コンテンツDLしなおしで3日必要だった。

環境

  • Windows Server 2008 R2
    • Windows Internal Database
    • WSUS 3.0 SP2

GAEアプリケーションを HRDに移行

移行といっても「GAEに移行した」のとおり、static contentをservletで公開しているだけなのでdashboardのdeprecate警告を消したかっただけ。

Master/Slave から HRD への移行にあるようにM/Sなアプリケーションを複製し、HRDなアプリケーションを作成。
DataStoreを使ってないのでMigration Toolを実行することもなし。
ついでにApp Engine SDKを最新化したら、appengine-web.xmlに<threadsafe>指定が必須になってたらしく追記。

参考:appengine-web.xml does not contain a <threadsafe> element

独自ドメインで公開しているアプリケーションをどうやって設定するのか忘れてしまっていた。

GAEアプリケーションは、http://some-appid.appspot.comという感じのURLで公開される。
(2年前の話なので今も同じかわからないが)独自ドメインで公開する場合は、そのドメインでGoogle Appsを利用できるようにしておいて、Google Appsから利用するサービスとして登録する。

このサイトの場合、

  1. breeze.ccドメインのDNSに、ghs.google.comを指すCNAMEレコードとしてpassing.breeze.ccを登録する(ここの場合、既に登録済)
  2. GAEのダッシュボードから、移行後アプリケーションのApplication Settings→Domain Setup→Add Domainでドメイン名追加(ここならbreeze.cc)
  3. Google Appsのダッシュボードから、設定→「(移行前アプリケーション) の設定」で、http://passing.breeze.cc/を削除
  4. 同様に「(移行後アプリケーション)の設定」で、http://passing.breeze.cc/を追加

という感じ。

redmineの プラグインを 2.0から 2.1に移行する

前回と似たような話。

自分ところのプラグインでredmine 2.1向けに影響があったのは以下のとおり。

  1. prototype/script.aculo.us→ jQuery
  2. wikiマクロ出力の変化

1はなんというか地道にjQuery向けに書きなおした。

2。今まではwikiマクロからStringを返すとhtml(を表す文字列)だったけど、HTMLエスケープされるように変わった。htmlとして出力してという表明が必要になった。といってもhtml_safeメソッドを呼んであげるだけ。
wikiマクロの中から例外を飛ばしてエラーメッセージを出したい時に、例外オブジェクトに与えるmesageをhtmlエスケープしてあげないといけない不自然さがなくなったのはよかった。

     macro  :graphviz_me do |wiki_content_obj, args|
m = WikiGraphvizHelper::Macro.new(self, wiki_content_obj)
m.graphviz_me(args, params[:id]).html_safe
end

https://github.com/tckz/redmine-wiki_graphviz_plugin
https://github.com/tckz/redmine_wiki_preview_ext
https://github.com/tckz/redmine_wiki_astah

redmine 2.1におけるwikiマクロに関する最も大きな変化は、マクロの引数に複数行テキストを使用できるようになったことだなー。

#3061 Let macros optionally match over multiple lines and ignore single curly braces

今までredmine本体に手を入れないといけなかったWiki External Filter Pluginがそのまま動くようにできるから、対応図種が豊富なこれでいいやん、て。

redmineの プラグインを 2.0用に移行する

Redmineによるタスクマネジメント実践技法

redmine 2.0がリリースされて一ヶ月ちょい。
新featureが出てくる前に自作のプラグインも移行しておかないとなーと思いつつ放置してたんだけど、やっと手をつけた。

以下のURLを参考にした。

Redmine 2.0.xにプラグインを移植する
Redmine2.0へのプラグインのマイグレーションについて


自分のところでひっかかったこと。

  • RAILS_ROOTが使えない
     → Rails.root
  • RAILS_DEFAULT_LOGGERが使えない
     →Rails.logger
  • RAILS_ROOT/vendor/plugin/が変更された
     →RAILS_ROOT/plugin/
  • routesの定義の仕方
     →ActionController::Routing::Routes.draw からRedmineApp::Application.routes.drawに
    RedmineApp::Application.routes.draw do
      match 'projects/:project_id/wiki/:id/graphviz', :to => 'wiki_graphviz#graphviz'
    end
    
  • テンプレートのファイル名が変わった
     →*.rhtml から *.html.erbに
  • テスト用webサーバ他のコマンドが変わった
     →./script/sever から ./script/rails server に
     →./script/runner から ./script/rails runner に
  • ActionController::Base.cache_configured? がprivateになった
     →意図が違うが ActionController::Base.perform_caching で代替


ここからはredmine 2.0への移行じゃなくて、ruby 1.8から1.9に変えたことでひっかかったこと。

  • String#eachがなくなった
     →String#each_line とか
  • proc+ブロックで得たProcオブジェクトのブロック内でreturnしたら呼び出し元メソッドがreturnした
    これを知らなくてすごく悩んだ。
    Redmineのviewフック内でコントローラにrender_to_stringをsendしている。
    テンプレート内でクロージャ(proc由来のProcオブジェクト)を使ってtrue/falseを返しているつもりだったのだけど、viewフックメソッドからtrueが返る状態になってしまった。
    lambdaに変更した。


それぞれremdine-2.0ブランチ
https://github.com/tckz/redmine-wiki_graphviz_plugin
https://github.com/tckz/redmine_wiki_preview_ext
https://github.com/tckz/redmine_wiki_astah


でも、redmine 2.0系のfeatureが増えてくるまでは、運用環境は1.4系のままかな。

redmineの wikiのプレビュー表示を移動可能にする

ss.png redmineの wikiマクロで graphviz その4で編集中の内容で画像を描画できるようになった。
だけど、プレビュー表示領域は編集領域の下方にあるため、dotをちょっと直して→画像確認→ちょっと直す、ということを繰り返そうと思うと都度上下に行ったり来たりしないといけないので面倒。

プレビュー領域をドラッグして見やすい位置に移動したい。右側とか。

ということで、wikiページ編集のプレビュー表示をドラッグ可能にするwiki_preview_extプラグイン
https://github.com/tckz/redmine_wiki_preview_ext


viewのフックを使って所定のコントローラ×アクションの場合に、javascriptコードを差し込んでドラッグ可能にする。
    class ViewListener < Redmine::Hook::ViewListener
def view_layouts_base_body_bottom(context)
context[:controller].send(:render_to_string,
:template => 'wiki_preview_ext/body_bottom',
:layout => false,
:locals => {:context => context})
end
end
redmine 1.3はscript.aculo.usを使っているのでこれをそのまま使わせてもらい、Draggableでdiv#previewをまるごと移動できるようにした。
    new Draggable(preview, {scroll: window});
preview.setStyle({cursor: "move"});
ノブを付けたかったけど、プレビュー機能がdiv配下をAjax.Updaterで更新しているのと、当該要素周辺の構造は変えないようにしたかったのでdiv全体にDraggable適用した。

wikにオートプレビュー機能を追加するプラグインは既にあって、編集と同時にプレビュー更新することができる。
既存のオートプレビュープラグインと併用するか、wiki_preview_extプラグインのオートプレビュー機能をプラグイン設定画面で有効にする。


redmineの wikiマクロで graphviz その4

その3」を書いたのが3年以上前なのか。
redmineのwikiにgraphvizを使った画像を埋め込めるようにするマクロ。
https://github.com/tckz/redmine-wiki_graphviz_plugin

graphviz_meマクロは、このマクロが埋め込まれているwikiページ全体をdotとみなして画像描画する。
wiki編集中のプレビューの際に、wikiマクロに渡ってくるモデル(WIkiContent)が保存済のもののため、今現在編集している内容で描画できていなかった。(一旦保存する必要があった)
よくよく考えてみれば、wikiマクロが呼び出されたときのselfがviewを指しているのでリクエストのパラメータも取得できるのだった。
マクロの挙動がformの構造に依存するのはイヤだと思いつつも、保存しないでプレビューできたほうがマシか。

編集中テキストのプレビューの場合は画像をdataスキームでimg@srcに直接入れちゃうことにした。

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg・・・TkSuQmCC">
古いブラウザだと表示できないけど。
画像部分の通信サイズが大きくなるけどレスポンス一回で画像もHTMLも返せると、取得した編集中テキストをまるごと受け取って画像を返すactionを新設しなくていい。


環境:
CentOS 6.2 x64
ruby-1.8.7-p352
mysql-server-5.1.61
graphviz-2.26.0
redmine-1.3.0
 

redmine 1.3.0にしたら wiki絡みの展開順が変わってた

自作のwikiマクロの引数で、wikiリンクと同じ記法でリポジトリ上のリソースを指定させている。
{{macro(source:path/to/file)}}
redmine 1.3.0からwikiリンクとマクロの展開順が変わり、先にwikiリンクが処理されるようになったみたい。
冒頭のマクロ引数に対してHTMLリンクに展開済の文字列(HTML)が渡ってくるようになった。

  Redmine::WikiFormatting::Macros.register do
    desc '略'
    macro :some_macro do |wiki_content_obj, args|
    end
end
1.2.xの場合、args[0]に「source:path/to/file」
1.3.0の場合、args[0]に「<a href="http://passing.breeze.cc/mt/projects/sample/repository/entry/path/to/file" class="source">source:path/to/file</a>」
という文字列が渡ってくる。

「!」をつけると展開抑止になるので当面これで回避。
{{macro(!source:path/to/file)}}

あるいは引数の受け取り方を変えて
{{macro(param=source:path/to/file)}}
とすればHTMLリンクに展開されず引数を受け取れる。


jenkinsの DRY pluginで CPD

jenkinsを使って継続的インテグレーションを行なっている。
数年前はCruiseControl .NETを使っていたのだけど、hudsonを試したときユーザフレンドリーさに打たれて乗り換えた)

以前からmakeなどで1手順ビルドできる仕組みを作ることにはこだわりがあった。
たけど、単にビルドの1手順化だけでなく、
  •  複数の環境でビルドしたものを統合(CIサーバに集約)
  •  リポジトリのコミットとビルドを結びつけ(さらにITSのチケットに結びつく)
  •  複数の環境で自動テスト実行、その結果とビルドの結びつけ
  •  ビルドのログやテストのログなど記録をとる(確認したいときにすぐ辿れる)
継続的インテグレーション入門 開発プロセスを自動化する47の作法
ということを手間なく繰り返し可能とする仕組みには大きな意味があると思う。

SCM、自動テスト、ITSそれぞれ単独でも役立つけど、
ビルドとこれらを結びつけられるCIの存在は大きい。


で、そのビルドと結びついた記録を取りたいものの1つがコードメトリクス。
気にしている指標はいくつかあるけど、コードクローンについて。

コードクローンの検出にCPD(PMD)を使っている。
CPDのレポートxmlをjenkinsのDRY Pluginに食わせるだけ。ビルドごとの静的解析の結果をとりまとめてくれるプラグインでトレンドを見ることができる。
正直に言えばjenkinsのビュー内でコードクローン部分そのものを見るのはあまり意味が無いというかかえって見づらいと思っている。eclipseにPMDプラグインをインストールしてクローン部分にアクセスする方が便利。
あくまでjenkins上では時系列(ビルド)でコードクローンの増減を概観したい。


ここの環境ではjenkinsのmasterをlinux上で動かしている。
CPDの実行はWindowsスレーブ上で行なっている。
入力はSJIS(MS932)でエンコードされたjavaソース。
jenkinsのslave配下でjavaモジュールのビルドをantで行う。同様にantでCPDのレポートを作成している。

PMDのlib下jarをCLASSPATHに指定してantタスクを定義
    <path id="cp.cpd">
        <fileset dir="${pmd.lib}">
            <include name="*.jar"/>
        </fileset>
    </path>

    <taskdef name="cpd" classpathref="cp.cpd" classname="net.sourceforge.pmd.cpd.CPDTask" />

cpdタスクを実行
    
<cpd encoding="Windows-31J" minimumTokenCount="100" format="xml" language="java" outputFile="${reports.cpd}/cpd.xml"> <fileset dir="${src.dir}"> <include name="**/*.java"/> </fileset> </cpd>

で、後はjenkinsのワークスペースに出力されたxmlのpathをDry Pluginの入力に設定するだけ。


当初、cpdタスクの入力エンコーディングを"MS932"にしていた。出力XMLのxml宣言にあるencodingも"MS932"になるのだけどこのままDry Pluginに読み込ませようとするとエラーになってしまう。
Dry Pluginのソースをgithubからcloneして、自動テストの入力xmlのencodingをMS932に書き換えて実行したらスタックトレースに
「Invalid encoding name "MS932".」と出ていた。
org.apache.xerces.*が使われるから?


環境:

Windows 7 x64
 JDK6 u26 x86
 ant-1.8.2
CentOS 5.6 x64
 JDK u26 x64
 ant-1.8.1

MT5に移行した

「GAEに移行した」で書いたようにここのサイトは、手元のサーバ上においてMTで編集/生成した静的HTMLを、GAEのアプリケーションにリソースとして組み込みServletで返しているだけなので、MT4でもMT5でも関係ないといえばない。

MT4のときはSQLiteを使っていたので、MySQLに移行せざるを得なかった。
  • [MT4]システムメニューからバックアップ
  • [MT4]MySQLにMT用のDBとユーザを作成
  • [MT4]mt-config.cgiを書き換えてMySQLを参照する設定に。
  • [MT4]この状態でmt.cgiにアクセスすると新規セットアップになるので、適当に。
  • [MT4]システムメニューからバックアップを復元
  • [MT5]MT5のファイルをおいてアップグレード→再構築
てな感じで移行自体はできたんだけど、よく見るとカテゴリのリンクがまったく張られていない。
なんでかと思ったら全ての記事からカテゴリの情報が消えてた!!

ちまちまちまちま全記事にカテゴリを設定しなおすはめに。
記事の一括編集でカテゴリ設定できることに途中まで気がつかず無駄にしんどかった。あーぁ。

結果的に過去のエントリを見返すことになったのだけど、今も使ってるアプリ/OSSが結構古いバージョンのときから使ってたので驚いた。

環境:
 CentOS 5.5 x86
  MovableType 5.04


Arduinoと ATtiny2313で SPI

気がついたら前回工作してから半年もたってた。
SN3E0090.jpg

ArduinoからATtinyに指示を送ってモーターの制御をする、てなことをやるつもり。で、まずはSPIで指示を送り、これに従って何かする、ことをやってみたい。

 ※以下の内容は単にやってみたことの記録です。すべて無保証で、障害・損害・不利益・不都合に対し、筆者は一切の責任を負いません。

SPI自体についてはこのへんを参照。
なんでSPIを選んだかというと、
I2Cよりも、仕組みが単純、転送速度も速くできるみたいだから。

  • Arduinoをマスター、AVR ATtiny2313Vをスレーブとする。
  • ATtiny2313にはSSがないみたいなので、PB4をLOWにしたらスレーブ選択、という体(てい)で。
  • マスターから送ったデータ8ビットを、スレーブ側でLED点灯で表現(面倒だったのでLEDは4つ。下位4ビットだけ・・・)&前回データを反転したものをマスターに返すことで、通信がうまくいったことを確認する。Arduino側はスレーブから受け取ったデータをSerialに書きだす。
ATtiny2313は、外部クリスタル8Mhzを使用かつCKDIV8を無効にしているので、システムクロックは8Mhz。
電源はUSBからArduinoに給電。ATtinyはArduinoから出ている5Vを使う。
spi_test.PNG


マスター:
最近公開されたarduino 0022ではSPIが標準ライブラリになっているので、マスター側はこれを利用した。

#include <SPI.h>
#include <util/delay.h>

void setup()
{
Serial.begin(9600);

SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV8);
SPI.setDataMode(SPI_MODE0);

pinMode(2, OUTPUT);
digitalWrite(2, HIGH);

uint8_t d = 0;
for (;;)
{
digitalWrite(2, LOW);
uint8_t a = SPI.transfer(d);
digitalWrite(2, HIGH);

Serial.print(d, HEX);
Serial.write(", ");
Serial.println(a, HEX);
d++;
_delay_ms(300);
}
}


void loop()
{
}


スレーブ:

試しながら学ぶAVR入門―マイコンの基礎と電子工作とWindowsアプリケーションの作り方 (SkiLL up mycomputerシリーズ)
スレーブ側は、ATtinyのデータシートに、アセンブリ言語で書かれた実装例があるので、ニーモニックの説明を見つつC言語に書き下してみた。
ニーモニックについてはデータシートに説明がある。

外部割り込みがどういう挙動か知りたかったこともあり、SS相当のPB4で割り込みがかかるようにした。
PB4がLOWになったら受信開始。8ビット受信する。受信にあたりマスターへの送信データは、前回受け取ったデータをビット反転したものとした。特に意味はない。
受け取った8ビットのうち下位4ビットのON/OFFをPB0~PB3につないだLEDに反映する。


#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>


#define USCK PB7
#define MOSI PB5
#define MISO PB6


volatile uint8_t triggered = 0;

ISR(PCINT_vect)
{
if (!bit_is_set(PINB, 4))
{
triggered = 1;
}
}

uint8_t spi_slave_receive(uint8_t send)
{
USIDR = send;
USISR = (1<<USIOIF);
while (!(USISR & (1<<USIOIF)));
uint8_t receive = USIDR;

return receive;
}

void spi_slave_init()
{
USICR = (1<<USIWM0)|(1<<USICS1);

// MISO(PB6)は出力に
DDRB |= _BV(MISO);
// MOSI(PB5)/USCKは入力に
DDRB &= ~(_BV(MOSI) | _BV(USCK));

// MOSI(PB5)/USCK(PB7)プルアップ
PORTB |= (_BV(MOSI) | _BV(USCK));
}

int main(void)
{
spi_slave_init();

// LED(PB0..PB3)は出力に
DDRB |= _BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3);

// LEDを消灯
PORTB &= ~(_BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3));

// PB4プルアップ
PORTB |= _BV(PB4);

// PB4の変化割込み
GIMSK |= _BV(PCIE);
PCMSK |= _BV(PB4);

sei();

uint8_t d = 0x00;
for (;;)
{
while (!triggered)
{
}

// PB4がLOWになった

// clear
triggered = 0;


// 1バイト受信+送信
d = spi_slave_receive(~d);


// display bits as LED
for (int i = 0, check = 1; i < 4; i++, check*=2)
{
if (d & check)
{
PORTB |= check;
}
else
{
PORTB &= ~(check);
}
}
}
}


おわり:
ようやくマイコン間で8ビット転送できるようになった。
普段やってることは、重層な抽象化レイヤの上に成り立っているので、8ビットどころかネットワークを超えて簡単に送り放題だし、RPCでもなんでもいくらでもやりようがある。たまにこうやってプリミティブなところから積み上げるのもいい訓練になるなと思った。

環境:
 Windows 7 x64 Ultimate
  arduino 0022
  AVR Studio 4.18 + SP3
  WinAVR 20100110
Arduino Duemilanove
AVR ATtiny 2313V