Posts for: #2023/04

リリース前テストを完了

0時に寝て6時に起きた。昨日は晩ご飯の買いものに行こうと早めに帰ろうとしたら雨降りでそのまま帰って家でだらだらしてた。

リリース前テスト

来週の火曜日がリリース日になる。4月から3週間ほどかけて行ってきたテストケースを完了した。致命的な不具合もなく、テストの過程でみつかった不具合も修正済みで予定していたテストが完了となった。ここ2週間ほど、テストして issue が登録されると、私が細心の注意を払って内容を精査して、即日で fix して検証したりしていた。それもあってテストでみつけた不具合はほとんど fix した。あとはリリースのためのパッケージングやドキュメント作成、インフラ作業などへ移っていく。アプリケーションの振る舞いに影響を与えるものではないので私の中では肩の荷がおりてプレッシャーも軽減されて少し安心できた。よかった。よかった。

docker hub のプライベートリポジトリ

先日 docker hub の rate limit に引っかかったこともあり、docker hub の有償アカウントを使うことになった。team プランは5人以上必要らしいので pro アカウントで契約してもらった。有償アカウントなら無制限のプライベートリポジトリを提供できる。docker hub でリポジトリを作成していて、いまさらながらにリポジトリ名にスラッシュを含められないことに気付いた。基本的にはハイフン区切りでスラッシュの代替する名前になっていた。これまで自分で docker image を扱ってこなかったので今更ながらに気付いた。

社内のコンテナレジストリから docker hub のプライベートリポジトリへの promotion のスクリプトを書いていた。bash の連想配列を使ってコンテナレジストリのマッピングを定義してあとは pull/push するコードを書くだけ。

declare -A repos
repos["internal-my-repo1"]="external/my-repo1"
repos["internal-my-repo2"]="external/my-repo2"
for internal in "${!repos[@]}"; do
  external="${repos[$key]}"
  echo "pull from: $internal"
  echo "push to  : $external"
done

コワーキングのオンラインイベント

月例のカフーツさんのオンラインイベントに参加した。先月の所感はここ 。promotion のスクリプトを書いていたら20分ほど遅れてから参加。今日の話題は chatgpt だった。少し前に 雑談会 したので歴史や原理的な仕組みなど、調べたことを参加者と共有しながら今後の社会の変化などを議論していた。私も関心のある内容なのでおもしろかった。いまや私は日々の開発業務にも chatgpt を使って調べものをしたりサンプルコードを書いてもらうのが普通になりつつある。そのうち ide と連携してテストコードの叩き台なども書かせるようにしてみたい。

いとうさんは chatgpt をみて、人間は働く意欲がなくなるのではないかといった懸念を表明されていた。いまのところ、ドメイン知識をもっている人がより効率よく働けるようになるツールでしかないという私の認識だが、あと3年ぐらいしたら人間を遥かに超えていって、chatgpt の出力をそのまま業務に応用する日も来るかもしれない。llm というのは次にくるもっともらしい単語を膨大な学習データから統計的に選択しているだけで、実際には内容を理解していないし、人間のように創造的な行為もできない。大雑把に言えば、インターネットの空気を読んで発言すれば人間っぽいというのはすごいことだし、便利で役に立つし、働き方も変わっていくだろうけれど、その延長上で変わる世の中が、私の人生における行動に影響を与えるほどではないと考えている。そういった話をする過程であんちぽさんの言う「価値観を育てる」という文脈が頭の中に残っていて、llm ぐらいでは揺らぎそうにはない気がしている。

ただ it 業界以外にもこんなに話題が拡散しているプロダクトはそうそうないので世の中をどんどん変革していくのだろうというのは、異業種の人たちと話していても実感できた。

unix crypt(3) をよくわかってなかった

0時に寝て2回ほど起きて7時に起きた。わりと気分がよい方。

unix の crypt(3) というライブラリ実装

google の Admin console の api の REST Resource: usershashFunction として crypt を選択してハッシュ化したパスワードを連携できる。

crypt - C crypt ライブラリに準拠しています。DES、MD5(ハッシュ プレフィックス $1$)、SHA-256(ハッシュ プレフィックス $5$)、SHA-512(ハッシュ プレフィックス $6$)ハッシュ アルゴリズムをサポートします。

この crypt というのは単純に sha256 や sha512 でハッシュ化すればよいわけではなく、歴史的経緯でそれぞれの os ごとにある crypt ライブラリの実装に依存しているらしい。

$ man 3 crypt

おそらく google のドキュメントがいう C crypt ライブラリというのは glibc のことを指していると考えてよいと思うが、go の準標準パッケージである golang.org/x/crypto を探してもその実装は存在しない。これも推測だが、仕様が曖昧なものを go の開発者は実装しようとしないのだと思う。とはいえ、c の crypt ライブラリをラップして go から使うのも面倒と言えば面倒なので誰かが crypt ライブラリを真似て野良実装して、それが一部で使われていたりするようにみえる。しかし、なぜかそのオリジナルを作った開発者はそのコードのリポジトリを削除していて、ソースコードのコピーがまわりまわって、いま github.com/GehirnInc/crypt で保守されているらしい。このライブラリを使ってエンコードすると c の crypt ライブラリの出力と一致することは確認できた。この実装をみれば、単純にエンコードすればよいといったものではないことが伺えるので pure go のライブラリとして共有されているのは有り難い。

このライブラリを使ってハッシュ化した文字列と c 言語のコードも chatgpt に書いてもらっていくつか一致することは検証できた。デバッグしていて、もう1つ salt を生成も特定の文字しか使えないのでうっかり乱数を使って文字列生成していると間違ってしまう。

var saltChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./")

func GenerateSalt(method Method) []byte {
	var b = make([]byte, 16)
	charsLength := len(saltChars)
	for i := range b {
		b[i] = saltChars[rand.Intn(charsLength)]
	}
	var salt []byte
	switch method {
	case SHA256:
		salt = append([]byte("$5$"), b...)
	case SHA512:
		salt = append([]byte("$6$"), b...)
	default:
		panic(fmt.Sprintf("unsupported salt method: %s", method))
	}
	return salt
}

ここで生成した salt を使って github.com/GehirnInc/crypt を使うとこんな感じで crypt を使って google のユーザーアカウント連携ができる。

func Crypt(password, salt []byte) (string, error) {                              
    if len(salt) < 3 {                                                           
        return "", fmt.Errorf("invalid salt: %s", string(salt))                  
    }                                                                            
                                                                                 
    var crypter crypt.Crypter                                                    
    switch string(salt[0:3]) {                                                   
    case "$5$":                                                                  
        crypter = crypt.SHA256.New()                                             
    case "$6$":                                                                  
        crypter = crypt.SHA512.New()                                             
    default:                                                                     
        return "", fmt.Errorf("unsupported salt prefix: %s", string(salt[0:3]))  
    }                                                                            
    hashed, _ := crypter.Generate(password, salt)                                
    err := crypter.Verify(hashed, password)                                      
    return hashed, err                                                           
}

ハッシュ化した文字列が正しいかどうかは実際に google にログインしてみないと判別できないのでわりとデバッグや検証に時間がかかった。

リファレンス

カスタム overlay モジュールを完全にマスターした

0時に寝て何度か起きて7時に起きた。変な夢をみた気がするが、どんな夢だったかは思い出せない。

openldap のカスタム overlay モジュールのデバッグ

先週末から openldap のカスタム overlay モジュール の開発やデバッグをしている。openldap のソースコードや gdb のデバッグのやり方にも慣れてきて私の中でも理解度が増してきた。

openldap サーバーのデバッグログは次のコードが設定されている。

#define LDAP_DEBUG_TRACE  0x0001

このコードを slapd.conf の loglevel に設定するとデバッグログを出力できるようになる。

loglevel stats 0x0001 ...

このときに ppolicy の overlay モジュールがどのタイミングで呼ばれるかをデバッグログを確認しながら検証した。

overlay ppolicy
ppolicy_hash_cleartext on

結論から言うと次の2点になる。

  • overlay は slapd.conf の後ろに書いた方のカスタムモジュールが先に実行される
  • ppolicy_hash_cleartext は ppolicy_add のタイミングで平文パスワードをハッシュ化している
    • gdb でデバッグすると op->o_request->oq_add->rs_modlist も op->o_request->oq_add->rs_e->e_attrs も同じアドレスを指す
    • overlay の処理は db に書き込む前と後の2つのタイミングがある
slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt );
...
pa->a_vals[0].bv_val = hpw.bv_val;
pa->a_vals[0].bv_len = hpw.bv_len;

カスタム overlay モジュールを使って openldap からパスワードを取得するには次の順番で処理が行われることを理解しておく必要がある。

  1. mycustom_add <= このタイミングで平文パスワードを取得しないといけない
  2. ppolicy_add <= このタイミングで平文のパスワードをハッシュ化する
  3. mycustom_add_response <= このタイミングではすでにパスワードがハッシュ化されている

openldap のことを何も知らない素人が chatgpt と一緒にデバッグしてこのことを2日で理解できた。開発のやり方が変わっていく予兆を感じた。

yubikey bio を購入してみた

0時に寝て7時に起きた。午前中は洗濯して、昨日届いたお肉を焼いて朝ご飯にしながらドラクエタクトやってた。

yubikey bio の購入

デスクトップマシンが不調だった1-2ヶ月ほど m2 macbook air でお仕事をしていた。デスクトップマシンと比べて明らかに便利だったことがある。1password にログインするときに os のシステムアカウントも利用できて、具体的には指紋認証によりパスワード入力を必要としなかった。デフォルトでは2週間ごとにパスワード入力を必要とする設定になっているが、これも無効にすることもできる。パスワードを忘れないように1ヶ月に1回ぐらいは手入力してもよいかもしれない。生体認証はその精度にまだ懸念はあるそうだけど、こういった日常的な認証における用途ならそれほど高い精度を要求しないことに気付いた。私は個人でお仕事しているから日常でオフィスに保管している物理的なデバイスを盗むのは難しい。他にも linux で使える指紋認証のデバイスを探してみた。しかし、現時点では usb の指紋認証デバイスは windows 一択になっていて linux はサポートされていない。YubiKey ぐらいしか、私はみつけることができなかった。

YubiKey Bio - FIDO Edition をオンラインストアで購入した。船便で購入したので届くまで1ヶ月ほどかかる。急ぐものではないので気長に待つ。

YubiKey Bio - FIDO Edition
$90

Shipping & handling
Economy - 10-20 Working Days - No tracking available
$5

Duties, taxes and/or carrier subcharges
$14.68 USD

日本にお店がないので輸入扱いで関税がかかるのかな?また会計システムに登録するときに税金の計上方法を調べる必要がありそう。

自分たちでやろうとしないことを他人は助けられない

他社のプロジェクト開発のお手伝いでプロジェクトマネージャーとしてこの半年をマネジメントしてきて分かるようになったことが1つある。米軍がアフガニスタンから撤退するときの方便のようにみかけ、ロシアのウクライナ侵攻のときにウクライナ軍が善戦して西側諸国の支持を得たことでその正しさを再確認できた言葉がある。

バイデン大統領は演説で「当事国の軍隊が戦う意思がないのにアメリカが戦うわけにはいかない」という趣旨を繰り返した。

アフガニスタン崩壊と日本への教訓

2月からプロジェクトの開発遅れがみえていてスケジュール調整している。プロジェクトの開発がうまくいかないことの全責任は私にあることは間違いない。その点には一切の懸念も疑問もない。昨今の働き方改革で有休取得が大事なことも理解していて、平均して取得するなら毎月1-2日休むことになる。それは理解できるが、開発が遅延していても有休で休み、その遅延をマネージャである私が休出して開発を肩代わりするという調整を1ヶ月以上続けてきて、この歪みは開発やプロジェクトにとってよくないということもわかってきた。

私個人のモチベーション管理にも多少の影響はあるが、私は指示されて休出しているわけではなく、自分の目的のためにやっているのでこの影響はそれほど重要ではない。

なにが問題かというとプロダクトオーナーシップを開発者がもたないという点にある。私はお手伝いであるから、いずれいなくなる。周りからどうみえようと最終的にプロダクトオーナーシップは契約形態としてもてない。そして、お手伝い先の開発メンバーがもつようになるのが望ましい。しかし、そういう雰囲気はみえない。これまで他社の人間がマネージャーをやっているようなプロジェクトに私が参加したことがなかったためにそういった視点がなかった。そして、私は自分がイニシアティブをもって開発するプロダクトはすべてプロダクトオーナーシップをもって臨んできた。そのため、開発者に裁量を与えることで必然的にプロダクトオーナーシップをもつようになると信じてきたが、いまのやり方だとそうならない気がしている。なぜならば、放っておいても問題になる前に私が勝手に対応してしまうために開発者のインセンティブやモチベーションを阻害してしまうからだ。

プロジェクトにおけるスケジュールや品質を担保するためにはマネージャーである私が一定の尽力をするのは合理的ではある。一方でそれをやり過ぎることで開発メンバーのプロダクトオーナーシップを遠ざけてしまう。プロダクトオーナーシップをもっていない開発者が休出してまで開発に尽力する意味など普通にはない。仮に私が開発メンバーでもそう思うだろう。昔の上長 がやっていたことをみて私が学んだことを、外部の人間として開発メンバーに教えることはとても難しいことを理解できた。

休出デバッグ

昨日は久しぶりに飲みに行っきて1時に寝て8時に起きた。

ストレッチ

外がだいぶ暖かくなってきて散歩に行く機会も増えてきた気がする。今日の開脚幅は開始前157cmで、ストレッチ後159cmだった。先週と違って今週は忙しくて座っている時間が大幅に増えた。そして、その分の右腰の張りは強かった。腰の張り具合はその週の忙しさや労働時間で推測できるぐらいにはわかってきた。それ以外はだいたい可もなく不可もなくな感じだったと思う。

淡路牛の受け取り

姉からお肉が届くという連絡があったので日時を調整して受け取った。島サラダフェア2022 という懸賞に応募していたのが当たったらしい。5000円相当の淡路牛らしい。お正月に食べるようなお肉だと言えば伝わるかな。A賞の5名のうちの1人がここにいるので総応募数は推して知るべし。姉が言うには全然応募ないらしい。こういうの調べて真面目に応募してメルカリで売るみたいなことやったらそれなりに儲かるのかもしれない。運営はマーケティングのやり方を変えた方がいいんじゃないかとか心配になって話していた。

openldap の overlay のデバッグ

午後から昨日の続き。chatgpt と一緒に openldap サーバーのカスタム overlay モジュールのデバッグをしていた。昨日の時点では2つの問題があることを確認できていた。今日は個々の問題の詳細をデバッグしながらワークアラウンドとして動かすためのコードを書いた。1つはビルドの問題じゃないかと思える不可思議な現象が起きていて、もう1つは openldap の ppolicy の仕様とカスタム overlay モジュールの仕様のどちらが正しいのかを設計者に確認する必要がある。15年ぶりぐらいに c 言語のコードを書いている。かなり怪しいけど、gdb をインタラクティブな repl のようにして振る舞いを確認しながら書いている。カスタム overlay モジュールでエラーが発生すると openldap はその処理をスキップするようにみえて、なんのログも出ない。細かくログ出力してどこまで動いたのかを確認しながら開発するとよさそうな雰囲気がわかった。

oss な開発は chatgpt が猛威を振るう予感

2時に寝て6時半に起きた。開発の追い込みが佳境に入ってきて集中力が増してきた。

chatgpt と一緒にデバッグ

openldap サーバーの拡張の仕組みに Overlays がある。c 言語でカスタム overlay を実装することで openldap サーバーに任意のフック処理を実装できる。いまやっていることはパスワードの追加や更新をフックしてそのパスワードを id 連携するためのモジュールを開発している。というか、開発済みだと聞いていたモジュールが意図したように動かないのでデバッグしている。例えば ppolicy という overlay を使って次のように設定すると、平文で送ったパスワードをディレクトリサービスの db へ格納する前に平文からパスワードをハッシュ化してくれる。この変換はパスワード変更を overlay でフックして実装されている。

overlay ppolicy
ppolicy_hash_cleartext on

overlay は slapd.conf に設定した順番に実行されるようで、それぞれの overlay に依存関係がある場合は実際の処理にも影響がある。そんな openldap サーバーの拡張モジュールの開発を引き継ぐことになったが、私がまったく openldap サーバーのことをわかっていないので chatgpt を使って理解しながらデバッグしている。これがそれなりにうまくいっていて調査が捗った。但し、chatgpt が教えてくれたことなので完全に正しいかどうかの保証がない。振る舞いで検証できるものはともかく、そうじゃないものは最後に有識者に正しいかどうかを確認する必要がある。

例えば、次のような ldif エントリーをサンプルとして、パスワードは userPassword という属性で扱う。ここで userPassword だけコロンが2重 (::) になっていることがわかる。これは属性の値が base64 でエンコーディングされていることを意味している。こういった2重コロンのような短いキーワードを検索で調べるのは難しい。chatgpt ならピンポイントに答えてくれる。

dn: uid=jdoe,ou=users,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: jdoe
cn: John Doe
givenName: John
sn: Doe
mail: jdoe@example.com
userPassword:: e1NTSEF9bm9ZMU5kdzN3WUdSbFhpdDJUaTY5UW9SeXpXaklEeXc=

openldap は oss だし、ドキュメントもインターネット上にあるので構造体の定義や c 言語のサンプルコードも書いてくれる。それらが完全に正しいか、私には判断できないが、openldap のソースコードで調査するところの当たりをつけるには十分な情報を返してくれる。カスタム overlay を開発するときの主要なエントリーポイントと ldap 操作のタグ名は次になる。

  • bi_op_bind: バインド(認証)操作に対応するエントリーポイント、LDAP_REQ_BIND
  • bi_op_search: 検索操作に対応するエントリーポイント、LDAP_REQ_SEARCH
  • bi_op_compare: 比較操作に対応するエントリーポイント、LDAP_REQ_COMPARE
  • bi_op_modify: 修正(属性の追加、削除、変更)操作に対応するエントリーポイント、LDAP_REQ_MODIFY
  • bi_op_modrdn: エントリ名の変更 (MODIFY RDN) 操作に対応するエントリーポイント、LDAP_REQ_MODRDN
  • bi_op_add: エントリの追加操作に対応するエントリーポイント、LDAP_REQ_ADD
  • bi_op_delete: エントリの削除操作に対応するエントリーポイント、LDAP_REQ_DELETE
  • bi_op_abandon: 中止操作に対応するエントリーポイント、LDAP_REQ_ABANDON
  • bi_op_extended: 拡張操作に対応するエントリーポイント、LDAP_REQ_EXTENDED

例えば、LDAP_REQ_ADD は ldap.h で次のように定義されている。

#define LDAP_REQ_ADD        ((ber_tag_t) 0x68U) /* application + constructed */

これを gdb でデバッグしてタグを確認するときは次のように Operation 構造体内の o_tag をチェックすればよい。gdb で16進数表示するときは /x を指定する。

(gdb) print /x op->o_tag
$8 = 0x68

ppolicy よりも前にカスタム overlay を設定すれば平文のパスワードにアクセスできそうにみえるのだけど、gdb でデバッグしているとハッシュ化済みのパスワードになっていた。

あと稼働している openldap サーバーに gdb で attach してデバッグする方法も chatgpt に聞きながら行った。やりたい操作に対して gdb のコマンドを教えてもらってすぐに検証してフィードバックからさらに質問できるのでインタラクティブな repl のような環境と chatgpt は相性がよいように思えた。gdb のコマンドを覚えておく必要も、ググる必要もないことに気付いた。

近況報告

元同僚と 約1年ぶりの近況報告 の雑談会をしてきた。これで3回目かな。毎年の恒例行事のようになってきた。兵庫県の住みたい街ランキングでいつも上位にある 西宮市 でカレーを食べて、バーで飲んできた。三ノ宮から西宮は快速で15分程度の距離。すぐ行ける場所なんだが、とくに行く機会がなかったので神戸に引っ越してきて5年以上経つのに電車で行ったのは今回が初めてになる。いつも通り近況を聞きながら、みんな私と同じぐらいの世代なので今後のキャリアの方向性などを話していた。

私は起業して税金やその仕組みに関心をもつようになり、起業する前より少し詳しくなった。知人から節税相談を受けることもある。税金の基本的な考え方として、1つの大きな収入に対して節税することはできない。自由に使えるお金がほしかったら基本的に節税できない。税金をたくさん払って貯金するしかない。一方で個人と会社に資産を分割したり、共済や基金を活用することで手取りの収入は減るが、支払う税金は少なくなって中長期でみると資産が増える。例えば、共済や基金に積み立てたお金は原則としては退職所得で戻ってくるので、ずっと優遇された 退職所得の所得税 により、最終的に支払う税金が少なくなるからである。これが税金を支払う基本的な考え方。自分の手元にお金を残した上で税金を払いたくないが、どうすればよいか?とよく聞かれるが、そんなことはできないというのが模範回答になる。元同僚も私もそうなのだが、もはや自分の生活にお金をあまり必要としていない。私が節税の仕組みを調べたり実践したりするのは、税金の仕組みを学ぶために過ぎない。ただ知識として学ぶよりも、実際に実践して運用してみる方が学びになる。

以前の 出張もくもく会 の後で懇親会のときにそのうち資本主義は新しい制度にとって変わられるのではないかという話題があった。それは行き過ぎた資本主義の弊害と、資本主義である限り40時間/週の労働時間から抜け出すには資本家になるしかなくて、人類はすでにこれだけ技術があるのだからもっと多くの人が今よりも働かずに食べていけるのではないかと多くの人が考えている。私の場合も、実質は自分のやりたいことしかやってなくて、自分のために働きながらも、老後のために一応はお金をもらっておくみたいな働き方になっている。この考え方は資本主義の次の制度へ移行するときに活きてくればいいなと思う。

rpm のパッケージングを作り直す

1時に寝て何度か起きてあまり眠れなかった。昨日は遅くに帰ってきて晩ご飯を遅くに食べたので寝ていて吐き気がしてうまく眠れなかった。寝る前に食べることはできないみたい。

rpm パッケージング再び

ビルドができるようになったモジュール を rpm でパッケージングする。rpm でのビルドもできる状態で渡してもらえたので私が開発したモジュールを追加してパッケージングを修正する。rpm のパッケージングを行うのも5年ぶりといったところ。コンテナに慣れてしまって rpm を使うことはもうないと思っていたけれど、まだまだ現役であることを実感する。spec ファイルは普通に読めるので既存の設定や、他の rpm パッケージの spec ファイルの記述などもみながら、自分のモジュールで必要な設定を追加していく。久しぶりだったわりには順調に作業が進捗して2-3時間もやっていて追加の修正をして、実際にインストールして動作確認もできた。

rpm のマクロを確認する。

$ rpm --eval "%{_libdir}"
/usr/lib64

あるサーバーサービスを systemd 経由で実行させる。内部的に環境変数を使っている。systemd の EnvironmentFile で環境変数を設定したファイルへのパスを指定できる。例えば、次のように EnvironmentFile にパスを設定する。

[Service]
Type=simple
EnvironmentFile=/opt/path/to/my.env
ExecStart=/opt/path/to/bin/my-service
KillMode=process
StartLimitBurst=2
Restart=on-abnormal
User=ldap
Group=ldap

この環境変数にはパスワードのような機密情報も含むので rpm の %files で root 権限でのみ読めるようにアクセス制限を設定する。systemd 自体は root 権限で動くので環境変数の設定は root が行って my-service は ldap のユーザー/グループ権限で動く。

%attr(600,root,root) %config(noreplace) %{_sysconfdir}/path/to/my.env

ローカルのゲスト os に開発環境を作る

0時に寝て7時に起きた。いろいろうまくいってない。

vagrant 再び

rpm でパッケージングされた openldap サーバーの動作検証をするために vagrant で rockylinux/8 Vagrant box の環境を構築する。 rockylinux 8 だと次のようなエラーが発生した。

VBoxManage: error: Failed to open OVF file 'path/to/.vagrant.d/boxes/rockylinux-VAGRANTSLASH-8/7.0.0/virtualbox/box.ovf' (VERR_FILE_NOT_FOUND)

既知のバグとして次の forum にワークアラウンドが書かれている。

uefi なマシンのせいなのかな?詳細を理解していないけど Vagrantfile を次のようにする。

Vagrant.configure("2") do |config|
  config.vm.box = "rockylinux/8"
  config.vm.provider "virtualbox" do |domain|
    domain.customize ["modifyvm", :id, "--firmware", "efi"]
  end
end

修正済みのイメージをダウンロードするようにメタデータを作成する。

$ vi box-metadata.json
{
  "name" : "rockylinux/8",
  "description" : "Rocky Linux 8 7.0.0 Bugfix",
  "versions" : [
    {
      "version" : "7.0.1-20221213.0",
      "providers" : [
        {
          "name" : "virtualbox",
          "url" : "http://dl.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-Vagrant-Vbox-8.7-20221213.0.x86_64.box"
        }
      ]
    }
  ]
}

再度 vagrant の環境を作り直す。

$ vagrant box add box-metadata.json
$ rm -rf .vagrant/  # 古い設定を削除
$ vagrant up

vagrant を使うのも4年ぶりになるかな。コンテナに慣れてしまうと久しぶり感がある。使い方を忘れていて調べながらやってた。

vagrant にポートフォワーディングの設定を追加

$ vi Vagrantfile
...
  config.vm.network "forwarded_port", guest: 389, host: 1389   # ldap
  config.vm.network "forwarded_port", guest: 636, host: 1636   # ldaps
...

これでホスト os からゲスト os へ接続できる。

==> default: Forwarding ports...
    default: 389 (guest) => 1389 (host) (adapter 1)
    default: 636 (guest) => 1636 (host) (adapter 1)
    default: 22 (guest) => 2222 (host) (adapter 1)

ここでは ldap サーバーに対して Apache Directory Studio で接続できるように ssh のポートフォワーディングを設定している。

scp でファイルを転送

config を出力する。ssh の秘密鍵へのパス設定をしてくれるので scp のオプションに指定しなくて済む。

$ vagrant ssh-config > ssh.config

ポート番号も config に記載されているけれど、それは指定しないと scp できなかった。

$ scp -P 2200 -F ssh.config path/to/myfile vagrant@localhost:

vagrant ユーザーのパスワードも聞かれて vagrant を指定すればコピーできた。config を作ってもあまり便利ではなかった。

vagrant-scp というプラグインがあるのでインストールしてみる。

$ vagrant plugin install vagrant-scp

次のようにして使う。この方が簡単。

$ vagrant scp path/to/myfile ./  # 仮想マシンのホームディレクトリにコピーされる

リリースまで残り2週間

0時に寝て4時に起きて6時半に起きた。最近は以前より眠れるようになりつつある。今日は定例会議とバグ調査とコードレビューと検証をしていたらすぐに1日終わってしまった。

ビルド問題の解決

2月の上旬 から問題を認識していて、ある c 言語のモジュールが正常にビルドできない問題がようやく解決されてビルドできるようになった。libtool を使ってライブラリをビルドしていて、歴史的経緯からシンボル名の書き換えが必要だったみたい。2週間後にリリースされるモジュールの開発前の状態でビルドが通ったのがいまという状況。ここから私がそのモジュールに対して追加の開発を行う。本来の私のお仕事ではないけど、このモジュール開発の私が負う方がチームとしての成果が大きいと判断した。

ビルドができるようになるまで2ヶ月程待ったことになる。普通に考えたらリリース延期だが、担当者の割り当ての課題もあって、もうこれは不可抗力としてそのままリリースしようと思う。おそらく誰もこの件に関して本来の開発の在り方についての言及しないと私は考えている。おそらく品質も信頼できないものだと推測する。残りの2週間で追加の開発を一目散に駆けて成るように成るのを私も受け入れることにしようと思う。

サーバーサイド開発とセマフォ

0時に寝て7時に起きた。

web api サーバーへの負荷テスト

web api サーバーへ数百から数千件の同時リクエストを送ってエラーが発生しないことを確認する。チームのメンバーがテストを実施していたら producer がメッセージを送信するときに rabbitmq との接続エラーがいくつか発生した。いくつか対応方法を考えられるが、既存のコードを大きく変更せず解決するものとしてセマフォを導入してみた。自分で作っても難しいものではないが、golang.org/x/sync/semaphore で準標準パッケージとして提供されている。次のように簡単に使える。

sem := semaphore.NewWeighted(maxConcurrentSessions)
...
ctx := context.Background()
if err := sem.Acquire(ctx, 1); err != nil {
    return err
}
defer sem.Release(1)

これで rabbitmq との同時接続数を制御する。rabbitmq 側もどのぐらいの接続を受け付けるかは Networking and RabbitMQ を参照して設定で制御できる。デフォルトは 128 となっているので 1024 ぐらいまで増やしてみた。

サーバーサイド開発のおもしろさの1つとしてボトルネックは移動するという概念がある。必ずどこかにニーポイント (ボトルネック) は現れるので意図したパフォーマンスや負荷を耐えるようにリソース制限をしてサーバーが堅牢になるよう調整する。この手の作業はサーバーサイドエンジニアをやってきた私の得意とするところ。

ubuntu の環境構築

0時に寝て8時に起きた。昨日は出張から遅くに帰ってきたのでバテた。

ストレッチ

昨日はもくもく会で遅くに帰ってきたので毎週のストレッチを土曜日から日曜日に変更していた。ここ1-2ヶ月ほどでは最も調子がよかった。今週は出張していて普段より健康的な生活をしていた。というのは、お手伝い先のオフィスでは原則として私は9-18時でしか働けないため、業務の都合でずっと座りっぱなしにならない。例えば、自社のオフィスだとだいたい8時から始業して遅いと23時ぐらいまでずっと座りっぱなしになってしまう。たまたまホテルもいつもよりも離れた場所にとり、10分ほど歩く距離だったのでちょうどよかった。帰ってからホテルで2-3時間作業していたりもするのだが、それでも同じ姿勢でずっと座り続けている方が体にとってはよくないことがわかる。今日の開脚幅は開始前152cmで、ストレッチ後156cmだった。座っている時間が短かったために腰の張りはほとんどなかった。

ubuntu 22.04 lts の環境構築

先日 マシンに ubuntu をインストールした 続きの話し。東京出張があったり、開発の終盤でいろいろやっている中で開発環境を作り直すインセンティブが低かったので環境構築が遅くなった。過去の環境構築の issue が残っているのでそれをみながらやれば5-6時間もあれば作り直せた。結論から言って、マシンスペックが上がって、os も新しいものに変わったので開発環境としてはめちゃくちゃ快適になった。好みだが、私はリソースの潤沢なデスクトップマシンに linux をインストールして開発するのが一番しっくりくる。主観的に感情的にその構成が好きだというもの。

realforce の bluetooth キーボードの設定をするのにもう1つキーボードが必要なことに気付いた。私は bluez というツールを使って bluetooth キーボードのペアリングをしている。ペアリングするためには bluez の bluetoothctl という cli から操作してペアリングを行う。realforce のキーボードは有線/bluetooth 接続を両方同時につなぐことはできないため、bluetooth 接続するためには別のキーボードを接続して cli 操作しないといけない。

$ bluetoothctl
[bluetooth]# power on
[bluetooth]# agent on
[bluetooth]# scan on

bluetooth キーボードから接続要求を送る。

...
[NEW] Device F6:9D:A5:41:B7:1F REALFORCE_2
...
[bluetooth]# info F6:9D:A5:41:B7:1F
Device F6:9D:A5:41:B7:1F (random)
	Name: REALFORCE_2
	Alias: REALFORCE_2
	Appearance: 0x03c1
	Icon: input-keyboard
	Paired: no
	Trusted: no
	Blocked: no
	Connected: no
	LegacyPairing: no
	UUID: Human Interface Device    (00001812-0000-1000-8000-00805f9b34fb)
	RSSI: -51

マシンからデバイスを検出したらデバイス情報を確認してペアリングを実行する。

[bluetooth]# pair F6:9D:A5:41:B7:1F
Attempting to pair with F6:9D:A5:41:B7:1F
[CHG] Device F6:9D:A5:41:B7:1F Connected: yes
[agent] Passkey: ***

これでペアリングが実行されて bluetooth 接続できるようになる。ubuntu 20.04 lts の頃より進化しているのは接続/切断時に電池の残量も表示されるようになった。キーボードには充電池を使っているので地味に嬉しい。残量が少なくなってきたら帰るときに充電を仕掛けて帰れる。

今回の環境構築で1つはまったものがある。vagrant の仮想環境として virtualbox を使う。secure boot のために virtualbox をインストールするときにパスワードを mok (Machine-Owner Key) に登録しないといけない。この作業手順が分からなくて右往左往していた。インストール時に mok のダイアログが表示されてパスワードを登録するが、この後に os を再起動して bios 起動時に特別なダイアログが表示されて mok に登録したいパスワードを入力する。アプリケーションのインストール時に bios の設定が必要という概念が私の頭の中になくて分からなかった。これをやらないと virtualbox サービスが正常に起動しない。調べていると ubuntu 標準の virtualbox は壊れていて 3rd party の contrib なパッケージを使えという古い記事も出てくる。22.04 なら ubuntu 標準の virtualbox でも問題なく、mok の登録後に systemd から virtualbox サービスが起動することを確認した。再起動後の mok のダイアログは1度しか出てこないのでうっかり見逃してしまったら再設定しないといけない。次の cli で再設定できる。

sudo dpkg-reconfigure virtualbox-dkms