2017年2月27日月曜日

Ubuntu Classic Server 16.04 on Raspberry Pi3 で固定IPに変更

タイトル通りの単純な話のはずだったんだけど、なかなかうまくいかなかったので、エントリアップ。
最初に、ありがちな/etc/network/interfacesの最後に
    # eth0設定
    auto eth0
    iface eth0 inet static
      address 172.20.XX.XX
      network 172.20.0.0
      netmask 255.255.0.0
      broadcast 172.20.255.255
      gateway 172.20.YY.YY
な感じで、追加したんだけど、起動してみたら確かに、指定したアドレスのIPを持ってたんだけど、それとは「別に」DHCPでもアドレスを取得していてそっちでもアクセスできちゃう。

さらに気持ち悪いことに、ifconfigをやってみると、なぜかDHCPで取ってきたアドレスだけ表示されて、↑で指定したアドレスが見えない。
{なんじゃろなー・・・}
と思い /etc/network/interfaces を見てみると、
    source /etc/network/interfaces.d/*.cfg
てな行があったので、
{こいつか}
と探すと、/etc/network/interfaces.d/50-cloud-init.cfgがいた、このページを見た感じ、これ変えりゃ行けるっぽかったので、このファイルに設定を移して、rebootすると、指定アドレスでなくDHCPになっている。

{オレなんかミスったか?} 
/etc/network/interfaces.d/50-cloud-init.cfg を見ると編集前の状態に戻っている。
{はっーー!? なんじゃそりゃ?} 
もう一回やったが、全く同じ現象・・・
どうやら、cloud-initさんとやらが起動時に勝手に書き換えちゃってくれているらしい。

ちょっと調べると、ビンゴなタイトル「how to set static ip in ubuntu 16.04 on raspberry pi 3 (cloud-init)?」のページがあったんだけど、回答はついてなくて、コメントで
「sudo apt remove cloud-init やったら動いたょ」
「えーっ。cloud-init使う方法ないの?」
みたいなやりとりがあって微妙。

他にもIP変えようとして、苦労して解決したけどcloud-initへの怒り丸出しなページ も発見、しかし、うちのケースには役に立たずがっかり。

{うー。ちゃんとしたドキュメント見つからないなーー。}
とさまよっていると、RedHatのユーザー向けページに「cloud-init に関する FAQ」 なんてやつを発見。結構丁寧に書いてあるが、↑で最初に書いたような設定を、meta-data ファイルに書けとの司令。

{うーむ、meta-data ファイルって何・・? っていうか、どこ・・?}
公式 見ても、ググっても何か埒あかないので、頭来て、
sudo find / 2>/dev/null | grep meta-data
で、ルートから探してやったら、
    /var/lib/cloud/seed/nocloud-net/meta-data 
{なんすかそこは? 見つかんないよそれは・・・}
で、その見つけたファイルに
network-interfaces: |
  auto lo
  iface lo inet loopback

  auto eth0
    iface eth0 inet static
    address 172.20.XX.XX
    network 172.20.0.0
    netmask 255.255.0.0
    broadcast 172.20.255.255
    gateway 172.20.YY.YY
bootcmd:
  - ifdown eth0
  - ifup eth0
って追加したらやっとまともに動きました。

動きはしたんですが、 /etc/network/interfaces.d/50-cloud-init.cfg はdhcpのままなんすよね。/etcをgrepしても、↑で指定したアドレスを含むファイルは無いようだし、cloud-init 全然理解してないです。

2017年1月18日水曜日

c++で、scala風ifをやりたい

scalaをしばらくやっていると、c++を書いた時にifが値を返さないのでトサカにくることがある。

三項演算子とラムダ式を使えばもちろんできるんだけど、超絶汚くなる。けど、マクロにしたら案外すっきりしたので、記事アップ。
// scala風if
#define IF(COND) (COND)?[&](){
#define ELSE ;}():[&](){
#define ENDIF ;}()
#define IFRES return
こんな感じ。c++11以降ね。使うときは、
// scala風if sample1
    const int i = 5;
    const auto s = IF(i == 4) {
        cout << "case true" << endl;
        IFRES "if true!";
    } ELSE {
        cout << "case false" << endl;
        IFRES "if false!";
    } ENDIF;

    cout << s << endl;
そこそこ見やすい。ENDIFが必要なのは勘弁してね。
c++は、中括弧の最後の値が中括弧全体の値にならないので、IFの戻り値にしたい値にIFRESを付けてね。
IFRESは、ただのreturnなんだけど、直にreturnって書くと関数全体のreturnに見えてしまい、わけわからなくなるので、このキーワードを使います。
逆に言うと、IFやELSEの中から関数の外へ直接return出来ないので、あしからず。returnしたい人は、別にifの戻り値が欲しいわけじゃないので普通のifを使ってください。

あと、ENDIFマクロの最後にセミコロンをあえて含めずに、使うときにセミコロンをつけるようにしたのは、コンストラクタの初期化子でも使いやすくしたかったから。

IFとかELSEの後がブロックでなくてもOK。
// scala風if sample2
    const int i = 5;
    const auto s = IF(i == 4) IFRES "if true!"
                   ELSE IFRES "if false!"
                   ENDIF;
    cout << s << endl;