HPCメモ

HPC(High Performance Computing)に関連したりしなかったりすることのメモ書き

M1 mac の Parallels に Fedora coreOS をインストールしてdockerを使う

2025/9/12 21:39 タイトル、および記事中の誤記を修正しました Fedora core linux → Fedora coreOS

WHY

docker の有料プランが値上りするので、解約しようと思ってたら docker desktop の商用利用は有償プランだけ!って言われた

じゃ、mac から docker desktop を捨ててしまえば良い

でも仕事でdocker必要だし、Linuxマシンを調達するか

それなら parallels は入ってるんだからそこにLinux入れれば良くね?

せっかくだし docker のホストに特化したOSを入れるぞ

というわけで Fedore coreOS をインストール ← イマココ

参考資料

その1 kb.parallels.com

その2 qiita.com

準備

fedora coreOS のLive DVD*1をこちらのwebページからダウンロードしてきます

Fedora CoreOS | The Fedora Project

intel macの方はx86_64のイメージを持って行ってください。

LiveCDから起動

しばらくは参考資料その1の流れに沿って進みます。

parallels のコントロールセンターを開き、右上にある + ボタンをクリックして新規作成画面へ行きます

windows linux または macOS をイメージファイルからインストール」を選択して、「続行」をクリックします

「またはファイルを選択」をクリックして、さきほどダウンロードした LiveDVD を選択し「続行」をクリックします

オペレーティングシステムを選択」のダイアログでは一旦「その他Linux」を選択して先に進み、名前を付ける段階で「Fedora coreOS」あたりの分かりやすい名前に変更してください。

「作成」をクリックすると、一瞬ブートローダーっぽい画面が表示されますが、そのままほおっておけばOSが起動します。

こちらの画面になったら、LiveCDからの起動は成功です。

インストール

ここからは参考資料その2の流れに沿ってインストールしていきます。 まずは設定ファイルのyamlを作っていきます (butaneというらしい)

variant: fcos
version: 1.6.0
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - <公開鍵>

<公開鍵>の部分は実際にはホストのmacからのログインで使える鍵ペアの公開鍵に置換えてください。

参考資料のもの(というか公式サイトのもの)とほぼ同じものですが、docker desktopの代わりに使う程度ならたぶん大丈夫でしょう :p

作成が終わったら、ignファイルに変換するためのbutaneというコマンドをインストールします。

brew install butane

インストールできたら、yamlを変換します。

butane --pretty --strict ignition.bu >ignition.ign

ignition.bu が先に作ったYAMLファイルで、ignition.ign が変換後のIGNファイルです。 ちなみに、変換後のignファイルはただのJSONらしい

% file ignition.ign 
ignition.ign: JSON data

中を見てみると

% cat ignition.ign 
{
  "ignition": {
    "version": "3.5.0"
  },
  "passwd": {
    "users": [
      {
        "name": "core",
        "sshAuthorizedKeys": [
            <公開鍵>
        ]
      }
    ]
  }
}

いや、もう直接JSONで書けばええやんwww

さてインストール作業に戻りましょうか。 次にhttpで仮想マシンからこのignファイルをとってこれるようにサーバを起動します。

ignファイルを置いたディレクトリに移動して、次のコマンドを実行してください。

% python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

実行中のターミナルはそのままにして、仮想マシンの方で続きの作業をします。

まずは、sudo fdisk -l をしてインストール先のデバイスを確認しましょう

loop0, loop1, sda の3つしか見えていないので、たぶんsdaにインストールすれば大丈夫でしょう。 もしUSBメモリとかをうっかりparallels側にマウントしていたら他のデバイスも見えるかもしれませんが、その辺は自己責任で*2 :p

念の為 df して sda がマウントされていないことを確認します。

最後に次のコマンドを実行して、仮想ディスクに Fedora coreOS をインストールします。

sudo coreos-installer install /dev/sda --ignition-url http://10.211.55.2:8000/ignition.ign --insecure-ignition

URLに含まれる 10.211.55.2仮想マシンから見たホストOSのIPアドレスです。 parallelsがデフォルト設定だと、たいていこのアドレスになるようですが、エラーがでるようならホスト側でifconfigして 10.211.55 で始まるIPアドレスを探してください。*3

次の表示が出たらインストール終了なので、 shutdown -h now して仮想マシンをシャットダウンします。

次にparallelsのコントロールセンターから設定を開いて CD/DVD にマウントしていたISOイメージをとりはずします。

再度マシンを起動すると sshdの設定をして coreユーザ のauthorized_keysに先程の公開鍵を書いてるっぽいログが見えます。 その直後に、ネットワークインタフェースの情報が出てくるので覚えておきましょう。(この例だと enp0s5 で始まる行で、IPアドレスは10.211.55.6です)

最後にホストOSのターミナルからsshでログインできるか試してみます。仮想マシン側のユーザ名 core を指定するのを忘れないようにしてください((私はpermission deniedになって一瞬固まりました orz)

ssh -l core 10.211.55.6

無事にログインできたら、次のような表示になるはずです。

% ssh -l core 10.211.55.6
Fedora CoreOS 42.20250818.3.0
Tracker: https://github.com/coreos/fedora-coreos-tracker
Discuss: https://discussion.fedoraproject.org/tag/coreos

core@localhost:~$ 

この環境では、dockerコマンドを実行する時にsudoが必要です。

core@localhost:~$  docker run hello-world
docker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head "http://%2Fvar%2Frun%2Fdocker.sock/_ping": dial unix /var/run/docker.sock: connect: permission denied

Run 'docker run --help' for more information

core@localhost:~$ sudo docker run hello-world   #こっちが正解
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
198f93fd5094: Pull complete 
Digest: sha256:54e66cc1dd1fcb1c3c58bd8017914dbed8701e2d8c74d9262e26bd9cc1642d31
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (arm64v8)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

これであなたのmacでもライセンスを気にせずに*4 docker が使えるようになりました :D

*1:839MBだったでギリギリCDには焼けなさげ

*2:これでうっかりやらかすとホストPC側のストレージをふっとばす可能性があるんですが、parallelsの仕組みが良く分かってないのでホスト側に付いてる物理デバイスがじかに見えるかどうか分からんのですT_T

*3:もしくは、仮想マシン内でarp -a しても見つかるかも

*4:parallelsのライセンスは要るけど、そこも嫌ならvirtual boxでもドゾー

macでOpenFOAM その1

最近macでOpenFOAMを動かす用事があったので調べていたのですが、イマドキのOpenFOAMはmacでも簡単に動かせるもんなんですね。*1

ESI版と財団版それぞれ、mac向けのドキュメントが用意されていて次の3パターンがあるようです。

  1. ESI版のdockerコンテナを動かす
  2. ESI版をappleのネイティブclangでビルド
  3. Canonical Multipass でunbutuのVMを作って、財団版のubuntuパッケージを入れる。

一応、財団版のdockerコンテナもありますが、こっちはv11までしか提供されていないようです。*2

どう考えても、ESI版のdockerを動かすのが一番お手軽そうですが、せっかくなので3パターンとも試してみましょう。

インストール先の環境

  • mac book air (Apple M1, mem16GB)
  • macOS Sonoma 14.5
  • Apple clang version 15.0.0 (clang-1500.3.9.4) Target: arm64-apple-darwin23.5.0
  • Docker version 26.1.4, build 5650f9b

ESIのdocker版

docker版のドキュメントはこちらにあります。

develop.openfoam.com

dockerhubで、"opencfd" で検索すると*3 、こちらのページのように "-run", "-default", "-dev" の3種類のコンテナが見つかります。*4

https://hub.docker.com/u/opencfd

さきほどのドキュメントには

-run : a small-footprint runtime-only image

-dev : runtime with OpenFOAM development environment

-default : just-give-me-everything image

としか書かれてなくて、実際何が入ってるのか良くわからないのですが、コンテナのページにあった情報だとそれぞれ次のものが入っているようです。

run dev default
applications and runtime libraries
source code and build tools ×
tutorials × ×

v2406のarm版だと、 run: 160.13 MB、dev: 325.56 MB、default: 363.01 MB となっていてdev部分のボリュームが大きいようですね。 今回はtutorialを何か流すのが目的なので、runのコンテナをpullし、別途ダウンロードしたソースコードアーカイブから チュートリアルだけをコンテナに送り込むことにします。

まず、次のコマンドでOpenFOAMのコンテナを起動します。

% docker run --name openfoam-esi-v2406 -it opencfd/openfoam-run  /bin/bash

別のターミナルを立ちあげて、次のコマンドを実行し、チュートリアルをコンテナに送り込みます。

% wget https://sourceforge.net/projects/openfoam/files/v2406/OpenFOAM-v2406.tgz/download
% tar xfz download
% docker cp OpenFOAM-v2406/tutorials openfoam-esi-v2406:/usr/lib/openfoam/openfoam2406/

これで準備完了です。

最初のコンテナを起動したターミナルからtutorialを実行します。今回は、simpleFoamのAroundBuildings というケースを流してみました。*5 各種環境変数は設定済のようなので、チュートリアルディレクトリのAllrunスクリプトを実行すれば計算できます。

% cd /usr/lib/openfoam/openfoam2406/tutorials/incompressible/simpleFoam/windAroundBuildings
% ./Allrun

実行が終わったら、後から立ちあげた方のターミナルで結果を回収してきます。

% mkdir result
% cd result
% docker cp openfoam-esi-v2406:/usr/lib/openfoam/openfoam2406/tutorials/incompressible/simpleFoam/windAroundBuildings/log.simpleFoam ./
% docker cp openfoam-esi-v2406:/usr/lib/openfoam/openfoam2406/tutorials/incompressible/simpleFoam/windAroundBuildings/postProcessing ./

結果は最後にまとめて見ることにします。

ESI版をネイティブ環境でコンパイルして実行

公式のwikiのこちらのページにmacでビルドするための情報がまとめられてます。

develop.openfoam.com

さきほどtutorialのデータを抜き出すためにダウンロードしたソースがあるので、これをビルドします。

ドキュメントの手順どおりにOpenFOAM用のbashrcをsourceすると

% source OpenFOAM-v2406/etc/bashrc 
openfoam (darwin): using clang instead of gcc
/Users/n_so5/opt/anaconda3/bin/mpicc: line 285: x86_64-apple-darwin13.4.0-clang: command not found
Warn: could not determine prefix for system-openmpi

だそうです。

今の環境はarm64なんで、x64_64用のclangが入っていないのは正常だし、そもそも分散並列で実行する予定は無いので無視したいところですが homebrewでインストールできるので、OpenMPIをインストールします。

brew install openmpi

ついでに、gccやらhwlocやら依存ライブラリが大量に導入される*6のでしばらく待ちましょう

インストールだけでは、anacondaの方のmpiを見にいって文句を言うので、.zshrcにあるanacondaの設定を一時的にコメントアウトし、 新しいターミナルを1枚開いてそちらでOpenFOAMのbashrcを読み込みます。

% source OpenFOAM-v2406/etc/bashrc 
openfoam (darwin): using clang instead of gcc

エラーが出なくなったので、まずは環境が問題ないかチェックします

% foamSystemCheck

Checking basic system...
-------------------------------------------------------------------------------
Shell:       zsh
[The zsh shell is generally okay to use]
Host:        MBA.local
OS:          Darwin version 23.5.0

System check: PASS
==================
Can continue to OpenFOAM installation.

OpenFOAMのディレクトリに移動する foam というコマンド*7が 用意されているのでこれでディレクトリを移動してからビルドします。

% foam
% /usr/bin/time -p ./Allwmake -s -l

さーて何時間待ちかなーと思っていたら15秒程で、エラー多すぎて落ちました

_LIBCPP_NODISCARD_EXT inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(float __x) _NOEXCEPT {
                                                                                      ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/cmath:608:12: error: no matching function for call to 'isinf'
    return std::isinf(__lcpp_x);
           ^~~~~~~~~~
(中略)
 
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.

こちらのページにmacOSでのビルドに関する情報がまとまってますが

building · Wiki · Development / openfoam · GitLab

といった感じの話しかなくて、isinfが見つからないなんて事態とは関係無さそうです。

念の為、APFSの設定を見てみると

あれ、Case-sensitive って書いてませんね。 念の為実験してみると

% touch A a 
% ls 
A

これが原因っぽいですね o....rz

仕方が無いので外付けのSSDでビルドすることにします。

空のSSDを接続して、ディスクユーティリティを起動し [消去] -> [APFS(大文字/小文字を区別] と選択して、再フォーマットした後ソースをアーカイブから再度展開して一連のビルド手順をやり直します。*8

% source OpenFOAM-v2406/etc/bashrc 
openfoam (darwin): using clang instead of gcc
% foam
%  /usr/bin/time -p ./Allwmake -s -l

私の環境では、2時間半ほどでビルドできましたが、ストレージの性能によっては大幅に前後すると思うので、参考程度に考えてください。

ビルドが終わったら、もう.zshrcのanaconda関連の設定は戻してしまっても大丈夫です。

最後に、外付けSSDからOpenFOAM-v2406ディレクトリをまるごと本体のSSDにコピーして*9 docker版と同じsimpleFoamのwindAroundBuildingsを実行します。

% cd tutorials/incompressible/simpleFoam/windAroundBuildings 
% ./Allrun

ここまでのまとめ

長くなってきたので、財団版の話は次回に回すとして、一旦ESI版の実行結果&性能を比較してみましょう。

windAroundBuildingsのデータは、400ステップ実行されています。 線形ソルバはGAMGを使っていて、thresholdが1e-5っぽいのでほとんど回ってませんが、一応最終ステップの実行時間を比較すると こんな感じになってます。

docker版: ExecutionTime = 194.74 s ClockTime = 195 s コンパイル版: ExecutionTime = 193.54 s ClockTime = 195 s

これだけ見た限りだと、ESI版を使う限りはdockerでやれば十分と言えそうです。

もちろん、解く問題によってはより {演算|メモリアクセス|ストレージ} 性能の違いに敏感なこともあるので どちらか一方がもっと早いということもありえそうですが、セットアップの手間も考えると、多少実行時間が長くなる程度ならdocker版を使いたいところです。

計算中にstreamlineを出力してくれているので、400stepでの可視化画像を置いておきます。

素人目には大差無いように見えます :)

*1:10年ちょっと前にやろうとした時はめっちゃパッチ当てなきゃ駄目だった

*2:v12のリリースノートに昔はdockerだったけどmultipassの方がperformanceが良いからこっちで提供するYOと書かれてたので、dockerは捨ててこっちに移行する方針の模様

*3:OpenFOAMで検索するとv11以前の財団版が大量にひっかかります www

*4:タグで分けてくれ・・・

*5:motorBike飽きた

*6:現在のインストール状況による

*7:実際は cd ${WM_PROJECT_DIR:?} への aliasです

*8:ソースコードcase-insensitiveなAPFS上で展開した時点で、既に大文字/小文字が違うだけのファイルが上書きされているので展開済のディレクトリを新しいディスクに移動してもエラーになります

*9:docker版とストレージ性能を揃えるためにコピーしましたが、今後OpenFOAMをカスタマイズして再ビルドしたりする場合は、大文字小文字を区別するファイルシステム上に置いておく必要があります。一度コピーすると

mocha であるイベントが発火した後に色々テストしたい時

テスト対象の関数がイベントベースの非同期関数で、あるイベント(ここでは"close"とします)が終わった後で何か値の検証をしたいって時に、今まで次のようなコードを書いていました。

it("should fire close", (done)=>
  hoge.on("close", ()=>{
    expect(huga).to.equal("piyo");
  });
});

これでも正常動作しているとテスト自体は問題無いんですが、expectでチェックしている項目がfailした時に、タイムアウトまで待たされる上に 落ちた場所も分かりません。

で、今まではテストにfailしたら、expectの前後にDEBUG printを入れてどのテストがfailなのか確認するところから作業してたんですが こんな感じでPromiseを使えば解決しました!!

it("should fire close", async ()=>{
  await new Promise((resolve)=>{
    hoge.on('close', resolve)
  })
  expect(huga).to.equal("piyo");
});

やってることはただの手動Promisifyなんですが、なんかasyncテストはPromiseを返す関数のものと思い込んでてなかなか思いつけなかったのがちょっとくやしい・・・

ただし、この形でもイベントが発火しなかった時は相変わらずタイムアウト待ちになるんですが、少なくともどこのテストでfailしたか一発で分かるようになったし タイムアウトになるのはイベントが発火しなかった時だけなので、今までよりずいぶんfail後の原因調査が捗ります。

浮動小数点数の比較

この記事は UdonTech Advent Calendar 2023の3日目の記事です。 なんか良い具合にネタが転がりこんできたので、もう一本穴埋め記事を投稿しときます :p

最近アドベントカレンダーを書いていたせいか、200イイネ突破みたいな感じでこちらの記事がfacebookのフィードに流れてきました。

qiita.com

この記事から派生して、浮動小数点数の比較ってどうやりゃ良いの?

qiita.com

というような記事も書かれていました。

元記事の是非はともかくとして浮動小数点数同士の比較については、こちらに良くまとまった記事があります。

Comparing Floating Point Numbers, 2012 Edition
randomascii.wordpress.com

10年ほど前の記事ですが、私が最初に見たのはもうちょっと前だったような気がします。

この記事では3つの比較方法について紹介されていて、ざっくりまとめると

  1. 二つの数の差の絶対値がマシンイプシロン(以降εとする)以下かどうか
  2. 二つの数の差の絶対値を、絶対値が大きい方の数の絶対値で割ったもの(相対誤差)がε以下かどうか
  3. ULP (一番下の1が立っているbit)でのとなりあう浮動小数点数の差 と比較して1ULP以下ならOK

注意する点として、0とある浮動小数点数との比較を行なう場合は、2、3の手法はほぼ無意味で1を使うべし といったあたりが挙げられてます。

じゃ実際のところ、数値計算ではどの判定方法を使っているかというと、たぶんどれも使ってません。

ここで挙げられている比較方法はテストなんかで、ある値が以前の値と等しいか?みたいな比較を行なう時には便利なんですが 数値計算の場合、「違う値が返ってきてるけど物理的には許容範囲」ということが多々あります。

というわけで、たいていの場合は1の絶対誤差を、物理的に意味のある許容誤差と比較するというのがよく用いられてるんじゃないかと。

AWSの請求関連のポリシー変更に対応する

この記事は UdonTech Advent Calendar 2023の10日目の記事です。

半年くらい前にAWSから "[Action required] Update your policies・・・" みたいなメールが来てたんですが、どうせたいしたことないだろうと高を括ってましたw

が、なんかよく見たらポリシーをアップデートしてないと Dec11以降は "AWS billing, Cost Management, Account consoles will be affected" とか書かれてるじゃないですか。 ちょっと本当にマズそうなので、(アドベントカレンダーのネタにもなるし)期限ギリギリでポリシー変更してみようと思います。

AWSからのメールに書かれてた、requiredなactionはこの2行だけでした。

The following policies need to be updated to include the new fine-grained actions:
Customer Managed|BillingFullAccess|arn:aws:iam::xxxxxxxxxxxx:policy/BillingFullAccess||

でもって、大量にドキュメントへのリンクを用意してくれてるんですが、ここは流行りに乗ってchatGPTに相談してみます。

https://chat.openai.com/share/177675dd-0e52-435d-b272-f7450de434fa

ふむ。JSONで新ポリシーのデータまでくれて至れり尽くせりですね。

さて、次はどうしましょうか? もしこの回答が有償サポートの窓口から返ってきたものなら言われるままに設定しても良さそうですが そこまで信用できる手順書でも無いので逐一検証してみましょう。

IAM ポリシーの特定 メールに記載されているポリシー BillingFullAccess がどの IAM ポリシーに関連しているかを特定します。IAM コンソールまたは AWS CLI を使用して確認できます。

こりゃそうですね。元々"BillingFullAccess"を設定していないIAMポリシーを変更したらセキュリティインシデントですw

IAM ポリシーの編集 該当する IAM ポリシーを開いて、新しい細かいアクションを追加します。具体的なアクションがメールに記載されているはずです。例えば、AWSの新しいサービスや機能に関連するアクションがあるかもしれません。

残念、具体的なアクションはメールに書いてくれてませんでした。 まーこのドキュメントにmappingを用意したよ! って書いてるんですが、元々 aws-portal:* とかいうクソデカ権限なので何を付ければ良いのやらさっぱり分かりませんo..rz

docs.aws.amazon.com

さて、どうしようかと思いながらドキュメントを見ていたら、「影響を受けるポリシーツール」なるものが提供されていました。

https://us-east-1.console.aws.amazon.com/poliden/home?region=us-east-1#/

初期状態では、ボタンの表示が一部隠れていますが「更新されたポリシーをコピー」の列を広げると「新しいポリシーをクリップボードにコピー」というボタンが現われます。

「新しいポリシーをクリップボードにコピー」をクリックしてポリシーのJSONデータをコピーして、右隣にある「IAMコンソールで編集」をクリックすると このポリシーの編集画面に行くので、元のJSONを削除してペーストしましょう。

保存すれば作業完了(のはず)です。

あれ?まだ手順書の検証をしてたはずなのに、作業が終わってしまった・・・

DDNSを捨てよIPアドレスを通知しよう

この記事は UdonTech Advent Calendar 2023の2日目の記事です。

   | \
   |∀ ゚) ダレモイナイ・・アナウメスルナラ イマノウチ
   |⊂
   |

一般のご家庭ではISP様の気分次第で*1割り当てられたIPアドレスが変わってしまうので、 外部からアクセスしたいんだけど、IPアドレスを知るためには同時に家庭内LANにも居ないといけないという ジレンマに悩まされていました。

解決策としてDDNS(Dynamic DNS)というのがこれまた古くから使われているんですが、年に数回外出先からsshで帰宅する程度にしか使わないので 名前を割り当てられるほどの大掛かりなサービス要らんのだけどなぁという気持ちもあって、なんとなくアレ使うの嫌なんですよね。

そもそも、一般に公開するサービスを提供するわけじゃないので誰にでも分かりやすいアドレスなんてものも不要だし、 むしろ名前でアクセスできると攻撃を受ける頻度が上がるだけじゃないだろうか(要出典)という気もします。

ところで、最近知ったのですが、一部のpublicなDNSに特殊なクエリを投げると自分の(DNS側から見た時の)IPアドレスを返してくれるそうです。

community.cisco.com

ということは、これを家庭内LANのマシン上で定期的に動かしつつ、IPアドレスが変わっていたら通知するシステムがあれば十分じゃないか!

ということで作りました :D

自分のIPアドレスを知る

これを実行するだけ。

dig myip.opendns.com @208.67.222.222 +short

+short オプションは、今回初めて知ったんですが便利ですね。 最初はsedでanswer sectionを抜き出して〜とかやってたんですが、このオプションをつければ単にIPアドレスだけ返してくれます。

通知する

そんなもんslackにDMで投げときゃ良いでしょ。 ってことで、こちらの記事を参考に incomming webhook を設定してcurlでポストします。

qiita.com

anton0825.hatenablog.com

デプロイメント

crontab -e

IPアドレスを調べてファイルに書き出し、前のIPアドレスとdiffとって違ってたらslackに投げるシェルスクリプトを作っておいて毎時5分くらいに動かします。

修正版

これで完成!!と思いきや、なんか定期的にIPアドレスが変わっていないのに通知が来る現象が起きました。

直前のIPアドレスとのdiffをとった時のログを見ると

1c1,4
< 192.168.0.1
---
> 
> ; <<>> DiG 9.10.6 <<>> myip.opendns.com @208.67.222.222 +short
> ;; global options: +cmd
> ;; connection timed out; no servers could be reached

あ、time outしとる・・・

というわけで、digが非ゼロで終了したら1分待ってリトライするようにして完成です(たぶん)((今のところ連続して同じIPアドレスが通知されたことは無いので、大丈夫そうだけど単にdigがエラーを返してないだけという可能性もあるので・・・)

需要は無さそうですが一応最終版のスクリプトを貼っておきます。

function onDetectNewGlobalIP(){
  #save difference 
  diff ${OUTPUTDIR}/globalIP.txt  ${OUTPUTDIR}/globalIP_new.txt

  #post to slack
  curl -X POST -H 'Content-type: application/json'\
   --data '{"text":"'$(cat ${OUTPUTDIR}/globalIP.txt)'"}' ${WEBHOOK_URL}
  rt=$?
  rm  ${OUTPUTDIR}/globalIP.txt 
  mv ${OUTPUTDIR}/globalIP_new.txt ${OUTPUTDIR}/globalIP.txt 
  return $rt
}

{
dig myip.opendns.com @208.67.222.222 +short  > ${OUTPUTDIR}/globalIP_new.txt
dig_rt=$?

error_count=0
while [ $dig_rt != 0 ]
do
  sleep 60
  dig myip.opendns.com @208.67.222.222 +short  > ${OUTPUTDIR}/globalIP_new.txt
  dig_rt=$?
  error_count=$(( ${error_count} + 1))
  if [ ${error_count} -gt  ${MAX_RETRY} ];then
    echo "dig failed more than ${MAX_RETRY} in a row"
    exit 1
  fi
done


if [ -f  ${OUTPUTDIR}/globalIP.txt ];then
  diff -q ${OUTPUTDIR}/globalIP_new.txt ${OUTPUTDIR}/globalIP.txt 
  if [ $? -ne 0 ];then
    echo 'global IP address is changed!'
  
    onDetectNewGlobalIP
  else
    echo 'global IP address is not changed!'
    rm ${OUTPUTDIR}/globalIP_new.txt 
  fi
else
  echo 'global IP address file does not exist'
  onDetectNewGlobalIP
fi

}  > ${OUTPUTDIR}/$(date +%Y%m%d-%H%M%S).log

OUTPUTDIR, WEBHOOK_URL, MAX_RETRYはそれぞれPC上のファイル置き場、slackに通知するためのwebhookのURL、MAX_RETRYはdigがエラーを返した時に リトライを行なう数です。

cronにこのスクリプトを仕込んで動かしつつ、cronで毎日1週間前のログを消すといった感じで運用していますが、今のところ快適に使えてます。

大前提としてルーターの設定などで外部からのsshアクセスは捌けるようにしておく必要がありますが、これで半年ほど使っていて特に問題なさそうです。

唯一の欠点は、淡々とIPアドレスが並んだslackの画面に往年の某掲示板を思い出してしまうところでしょうかね?

*1:嘘です、何かしらのアルゴリズムに基いて切り替わるはず

macvimからVimR(neovim)へ移行しました。

マカーになって以来、エディタはずっとmacvimを使ってたんですが、

という謎の現象が起きてて、しかもこれ明確に発生条件が絞り込めたのは、 行末から右移動しようとしたとき だけですが、 これ以外の状況でもちょくちょくフリーズしてました。

profileを取ると、よく槍玉に挙げられてるHighlight_Matching_Pairが最上位に居たんですが、こちらで紹介されていた paren-match pluginを導入しても挙動は変わらず*1

qiita.com

そもそも、プラグインを無効化したり、.vimrcを読まないで起動しても同じ現象が起きてたので 駄目元でneovimを導入してみたら、あっさり解決しましたo......rz

というわけで、急遽 macvimからneovim(のフロントエンドであるところのvimR)へ移行することにしたので作業内容をまとめておきます。

インストール

brew install vimr

設定の移行

こちらの記事を参考に

qiita.com

まずは、.vimrc をそのままneovimのinit.vimへコピーします。

mkdir -p ~/.config/nvim
cp ~/.vimrc  ~/.config/nvim/init.vim

続いて(私もこちらの記事の方と同じくPlugでプラグイン管理をしているので)、plug.vimをコピーします。 *2

mkdir -p ~/.local/share/nvim/site/autoload/
cp ~/.vim/autoload/plug.vim ~/.local/share/nvim/site/autoload/

ここで一旦、vimRを起動するとcolor schemaは効いてないは、 横に勝手にファイラーが追加されてていんたーねっとには公開し難いはと散々な状態です。

が、まぁとりあえず :PlugInstall しときましょう。

続いて、 settings メニューへ行き

  • General タブ -> After Last Window Closes を Quit に変更
  • Toolsタブ -> File BrowserとMarkdown Previewのチェックを外す
  • Appearanceタブ -> Default Fontを Monaco の18ポイントに変更

と変更します。

ここまでやって気付いたけど、これ .gvimrc に書いた設定が読まれてないだけみたいですね。

というわけで.gvimrcに入れていた設定のうち、フォントまわり以外を突っ込みます。

if has("gui_vimr")
  " カラースキームの設定
  set t_Co=256
  let g:solarized_termtrans=0
  let g:solarized_bold=0
  let g:solarized_underline=0
  let g:solarized_italic=0
  let g:solarized_visibility='high'
  set background=light
  colorscheme solarized

  "カーソル形状
  set guicursor=a:blinkon0
  " コマンドラインの高さ(GUI使用時)
  set cmdheight=1
  set laststatus=2

  " ビジュアル選択(D&D他)を自動的にクリップボードへ (:help guioptions_a)
  set guioptions+=a

  set mouse=a

  "Input Method関係の設定 (IME on時の余計な改行とかを防ぐ)
  set iminsert=0
  set imsearch=-1

endif

set guioptions+=a は効いてないっぽいですが、ビジュアル選択した状態で Ctrl-Cすれば普通にコピーできるので、当面はyankと使い分けていきます。

プラグインの変更

さて、これでもうエディタとしては問題無く使えるのですが ついでに前述の記事で紹介されてたプラグインを入れてみましょう。

markdown-preview

まず、previmを markdown-preview に変更します。

次の行*3を追加して、:PlugInstallします。

Plug 'iamcco/markdown-preview.nvim', { 'do': 'cd app && npm install' }

それから、previm関連のプラグイン(私の場合はprevimとopen-browser)の行を削除して、:PlugClean します。

これで適当なmarkdownファイルを開いて :MarkdownPreview すると、htmlでレンダリングされた結果がブラウザで表示されます。終了する時は :MarkdownPreviewStop としてください。

vimRにはmarkdownを表示する機能がもともとついていますが、画像が表示されなかったり、エディタと表示サイズが(縦方向に)揃えられてしまって、見難いなど色々と難がありました。しかも、こちらのプラグインを使うとmarkdownファイル側のカーソル位置に追従してhtmlの表示位置を変更してくれます!!!

previmにも無かった機能ですが、これがあるとめっちゃ便利そうなのでこの機に乗り換えてみました。

AquaSKKの設定

VimRでAquaSKKから日本語入力していると、文字種切り替え(q,l, C-jなど)がVimRにもわたってしまうようで qやら改行やらが入った文章を後から直す羽目に、ちょっと面倒です。

macvimでも何か設定してたような気がするんですが、思い出せないのでこちらの記事にあった空文字挿入の設定を追加してみます。

hamaco.hatenablog.jp

まず、VimRのbundleIDを調べるために、ターミナルでlsappinfoします。

lsappinfo info VimR
"VimR" ASN:0x0-0x1146145: 
    bundleID="com.qvacua.VimR"
    bundle path="/Applications/VimR.app"
    executable path="/Applications/VimR.app/Contents/MacOS/VimR"
    pid = 84650 type="Foreground" flavor=3 Version="20230103.174333" fileType="APPL" creator="????" Arch=ARM64 
    parentASN=ASN:0x1-0x14aa8: 
    launch time =  2023/04/18 14:27:23 ( 1 hours, 1 minutes, 51.2144 seconds ago )
    checkin time = 2023/04/18 14:27:23 ( 1 hours, 1 minutes, 51.0431 seconds ago )
    launch to checkin time: 0.171407 seconds

もし表示されなかったら、引数無しで実行してlessにでも流して、それっぽいエントリを探してくださいw

さて、bundleIDが "com.qvacua.VimR"だと分かったので、aquaSKKの環境設定を開いて 互換性タブに行き [追加]ボタンをクリックしてから新しい行に"com.qvacua.VimR"を入力します。 あと、空文字挿入の列にチェックを入れれば設定完了です。

これで、VimR上で日本語の文字種を切り替えたり、英語-日本語を行き来しても 余計な文字が入力されることはなくなりました。

おわりに

という感じで、急遽macvimからVimRへ乗り換えてみたのですが これまであったストレスフルな挙動が全部解消して、めっちゃ楽になりました。

あとは、gitのmergetoolとか色々設定していないのがあるんですが まぁその辺は公式のドキュメントにもあるので、おいおいやっていこうかと思います。

*1:プロファイラの結果は変わっていたので、正常に機能はしている

*2:記事中では、Neovim用のコマンドを実行=neovim用のディレクトリにplug.vimを再ダウンロードしているようですが、 vim用と同じものなので同じマシン内でコピーしました

*3:公式のドキュメントだとyarnを使えってなってるけど、npm installでももちろん大丈夫