yaml, toml, json, hclの相互変換ツールsclevine/yjの紹介

yjっていうコマンド名多すぎ問題がある気がしますが、YAML, TOML, JSON, HCLの相互変換をしてくれるツールの紹介です。

tomlを使う必要があったのですが、いまいち形式になれてないのでjsonで見たいと思い探していました。

github.com

プルリクとissueが溜まっている感は少しあるので、別のコマンドを探すのが良いかもしれません。

インストール方法

brewとかで配布されているわけではないので、素直にgo getします。

$go get github.com/sclevine/yj

使い方

$yj --helpとすると雰囲気がつかめます

$ yj --help
Usage: yj [-][ytjcrneikh]

Convert between YAML, TOML, JSON, and HCL.

-x[x]  Convert using stdin. Valid options:
          -yj, -y = YAML to JSON (default)
          -yy     = YAML to YAML
          -yt     = YAML to TOML
          -yc     = YAML to HCL
          -tj, -t = TOML to JSON
          -ty     = TOML to YAML
          -tt     = TOML to TOML
          -tc     = TOML to HCL
          -jj     = JSON to JSON
          -jy, -r = JSON to YAML
          -jt     = JSON to TOML
          -jc     = JSON to HCL
          -cy     = HCL to YAML
          -ct     = HCL to TOML
          -cj, -c = HCL to JSON
          -cc     = HCL to HCL
-n     Do not covert inf, -inf, and NaN to/from strings (YAML in/out only)
-e     Escape HTML (JSON out only)
-i     Indent output (JSON or TOML out only)
-k     Attempt to parse keys as objects or numbers types (YAML out only)
-h     Show this help message

Error: invalid flags specified: l p

特筆すべきはこのコマンドは入力を標準入力で受け取ります。

つまり yj hoge.yml みたいにはできません。

この点を踏まえて実際に使ってみます。今回はtoml -> jsonを試してみます。

例題として使うtomlはこのサンプルです。

https://github.com/toml-lang/toml/blob/master/tests/example.toml

さてこれをsample.tomlで保存し、リダイレクトを使って実行します。

$ yj -tj < example.toml
{"clients":{"data":[["gamma","delta"],[1,2]],"hosts":["alpha","omega"]},"database":{"connection_max":5000,"enabled":true,"ports":[8001,8001,8002],"server":"192.168.1.1"},"owner":{"bio":"GitHub Cofounder & CEO\nLikes tater tots and beer.","dob":"1979-05-27T07:32:00Z","name":"Tom Preston-Werner","organization":"GitHub"},"products":[{"name":"Hammer","sku":738594937},{"color":"gray","name":"Nail","sku":284758393}],"servers":{"alpha":{"dc":"eqdc10","ip":"10.0.0.1"},"beta":{"country":"中国","dc":"eqdc10","ip":"10.0.0.2"}},"title":"TOML Example"}

いい感じですね。 さらにjq をパイプでつなげると見やすくなります。

$yj -tj < example.toml | jq .
{
  "clients": {
    "data": [
      [
        "gamma",
        "delta"
      ],
      [
        1,
        2
      ]
    ],
    "hosts": [
      "alpha",
      "omega"
    ]
  },
  "database": {
    "connection_max": 5000,
    "enabled": true,
    "ports": [
      8001,
      8001,
      8002
    ],
    "server": "192.168.1.1"
  },
  "owner": {
    "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.",
    "dob": "1979-05-27T07:32:00Z",
    "name": "Tom Preston-Werner",
    "organization": "GitHub"
  },
  "products": [
    {
      "name": "Hammer",
      "sku": 738594937
    },
    {
      "color": "gray",
      "name": "Nail",
      "sku": 284758393
    }
  ],
  "servers": {
    "alpha": {
      "dc": "eqdc10",
      "ip": "10.0.0.1"
    },
    "beta": {
      "country": "中国",
      "dc": "eqdc10",
      "ip": "10.0.0.2"
    }
  },
  "title": "TOML Example"
}

個人サイトをGitHubPagesベースに変えた

ということで個人サイトこと anatofuz.net をGitHubPagesベースかつhttpsに変更しました。

anatofuz.net

以前までの個人サイト

もともとこの個人サイトは、沖縄でGCPUGのイベントがあった際にLT駆動開発としてGoogle Domainドメインを買って作成したもの。なので当時のLTの資料は静的なHTMLにしてサイトにあげていたりした。

以前のサイトは資料にもある通り、Google Cloud Storageに置いたHTMLにDNSを対応させて表示させていた。Google Cloud Storageはトップドメインの表示に対応していなかったので、www.anatofuz.netのみで配信していた。

このときはhugoを使ってサイトを構築していたのだけれど、このサイトを作成したときのソースコードが消失しており、現状このサイトを更新しようとするとHTMLを生で編集する必要があった。さらにGoogle Cloud StorageのCLIPythonで書かれており、環境構築や使い勝手の面でよろしくないというとこがあった。

さらにGoogle Cloud Storageの場合httpsに対応していないので、Cloud Flareを中継してhttpsにするというクソ面倒な構成だった。

qiita.com (当時の構築をまとめたQiita)

GCPの無料枠を使い切ってしまったのか、最近毎月30円くらい請求されていて微妙にめんどうだったこともあるので、今回を機にGCPを落とす構成で作り直すことにした。

今回の変更

というわけで前回の反省を踏まえて

という3要素を全て満たすGitHubPagesでエイヤッと作ることにした。

hugoを使った構築

静的html作成ツールは色々あるが、個人的にgolangで書かれたhugoを気に入っているので今回もそれを採用した。 CSSjavascriptはあまり書きたくないので、雑にテーマをhugo公式から検索し aafuというテーマを選択した。

github.com

このテーマをそのまま使うでも良かったのだけれど

  • ブログは個人サイトではなくはてなブログへのリンクにする
  • リンク集などのアイコンと箇条書きを増やす
  • フォントを変更する
  • 改行コードを統一する

などの欲求があったので、これをforkしてパッチをあてたものを使った。

リポジトリ構成とデプロイ

hugoを使ったGitHub pagesへのデプロイは、なんやかんや公式のチュートリアルが一番しっかりしているので、それを見ながらやった。

gohugo.io

やり方をかいつまんでみると

  1. github pagesとして使うリポジトリと、hugoプロジェクトのリポジトリをそれぞれ作る
  2. hugoプロジェクトリポジトリの publicディレクトリに、 github pagesのリポジトリをsub moduleとして追加する
  3. デプロイスクリプトをコピってあとはそれを実行

みたいな感じだった。極めて楽ですね。

GitHubの2段階認証を有効化している関係で、httpではpushできないという罠があったので、適宜hugoプロジェクトの.git/module以下でsub moduleを指定している箇所をsshに変更するなどもした。

まぁデプロイスクリプトがあるけれど、いちいち手でやるのしんどいのでGitHub Actionに仕込みたいですねという気もする。

Google Cloud Storageの削除

プロジェクごと削除すると、プロジェクトで利用していたSotrageとかが一括で消えて便利。 間違えて消してしまった時様に、リカバリが出来る期間が一応あるらしい。

今回はリカバリする必要がないので、そのメールは無視して潔くプロジェクトごと消した。

ドメイン周り

ドメイン周りの変更はこのサイトがドンピシャだった。

dev.to

まずDNSのネームサーバーをGoogle Domainのものに変更した。 そのあとトップドメインgithub pagesにしたいのでカスタムレコードの @に以下のIPを追加した。

  • 185.199.111.153
  • 185.199.110.153
  • 185.199.109.153
  • 185.199.108.153

f:id:anatofuz:20200518173349j:plain

次に以前のwww.anatofuz.netにアクセスにきたものをanatofuz.netにリダイレクトさせたい。 これは合成レコードの設定をよしなにすれば出来るらしいので、設定してみた。

f:id:anatofuz:20200518173445j:plain

ここまでできたら次はCLoud Flare側のDNS関係の設定を削除し、GitHubリポジトリ設定から、転送先のURLをanatofuz.netに設定とhttpsへの対応ボタンを押して構築完了となった。

所感

やる気になれば手早く終わりましたね....。 Cloud Storageのものは、CLIで取得するのがめんどうだったので、 wget -rで雑に必要そうなものだけ抜き取るという運用でした。

まぁ個人サイトあるとたまに便利なので、こんな感じでデプロイとか管理がしやすい状況に保ちたいですね。

growiとhackmd(codimd)をhttpsで配信しながらhackmd連携を使う

研究室のwikiとして最近growiを使っている。

growiの構築には公式が出しているdocker-composeを使うのが便利で、研究室のwikiもこれを使って運用している。 さらにgrowiにはhackmdのOSSバージョンであるCodiMDを呼び出して使える機能があり、これも公式のdocker-composeをいい感じに編集することで実現できる。

今まではこれらをdocker-composeでlocalhostの3000番と3100番くらいで動かしておいて、dockerでなくaptで入れたsystemdで動かしているnginxでリバースプロキシしていた。 httpオンリー接続で元気に動かす運用だった。 とはいえ最近のインターネットはhttps通信をしたがるムーブがあるので、growiとhackmdをそれぞれhttpsで動かす方針でやってみた。

httpsでの配信

今回も公式のdocker-composeにある通り、httpsでの設定例を見て構築する。 公式がhttps配信のやり方を書いていて便利。

これはSteveLTN/https-portalのプロジェクトのDocker Imageを利用している。 github.com

https-portalはdocker-composeにドメインとリバースプロキシ先を書いておくと、よしなにLets'Encryptから証明書を持ってきて配置してくれる上にnginxでリバースプロキシしてくれる便利なツール。 READMEとかを見た感じ証明書の更新とかも勝手にやってくれるらしい。良いですね。

というわけでdocker-compose.override.yml に次くらいのものを書いておく

  https-portal:
    image: steveltn/https-portal:1
    ports:
      - '80:80'
      - '443:443'
    links:
      - app:app
    environment:
      DOMAINS: 'growi.cr.ie.u-ryukyu.ac.jp -> http://app:3000, hackmd.cr.ie.u-ryukyu.ac.jp -> http://hackmd:3000'
      STAGE: 'production'
      FORCE_RENEW: 'false'
      WEBSOCKET: 'true'
      CLIENT_MAX_BODY_SIZE: 0
    restart: unless-stopped
    volumes:
      - https-portal_data:/var/lib/https-portal

volumes:
  mariadb_data:
  https-portal_data:

ここまで書いてバシッと起動するとhackmdとgrowiがそれぞれhttpsで配信される。

hackmd連携の対応

とはいえスムーズに進まないのが人生で(?) growiのhackmd連携をしようとすると301のエラーが発生する。

Error: Error: Request failed with status code 301

なんでこうなるかはhttpsではなくhttpのhackmdにcurlするとわかる。

<head><title>301 Moved Permanently</title></head>

SteveLTN/https-portalはデフォルトの設定でhttpにアクセスに来たものを301でhttpsの方に引き渡している。 通常では問題ないのだけれど、growiのhackmd連携はwindow.postMessage を利用して行われている。

つまりwindow.postMessageでhttpアクセスに行ったところ301が出てしまって破滅しているため表示されないということになる。 この問題を回避するには、httpsとhttpを共存させれば良いということになる。

幸いSteveLTN/https-portalはnginxの設定をerbで書けば上書きできるらしいので、301ではなく直接リバースプロキシする様に設定を書き換える。

server {
    listen       80;
    server_name  <%= domain.name %>;


    location / {
              proxy_redirect                      off;
              proxy_set_header Host               $host;
              proxy_set_header X-Real-IP          $remote_addr;
              proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
              proxy_read_timeout          1m;
              proxy_connect_timeout       1m;
              proxy_pass  <%= domain.upstream %>;
    }

    # This helper sets up the path for the ACME server to verify that you own the site
    # Defaults to /.well-known/acme-challenge/
    <%= acme_challenge_location %>
}

ここで設定したドメイン名は <%= domain.name %> で、 リバースプロキシ先は <% domain.upstream > でそれぞれ設定出来る。

これをdocker-compose.override.ymlに以下のように書き加える。

    volumes:
      - https-portal_data:/var/lib/https-portal
      - ./hackmd.cr.ie.u-ryukyu.ac.jp.conf.erb:/var/lib/nginx-conf/hackmd.cr.ie.u-ryukyu.ac.jp.conf.erb:ro

ここまでしてdocker-compose upしなおすといい感じにhackmd連携が使える。めでたしめでたし。

コマンド一発でファイルをゼロクリアする

シェルスクリプトの講義のTAが明日あるので、入門unixシェルプログラミングを見ていたところ面白いコマンドがあったので。

ファイルを消さずにゼロクリアするコマンドの紹介。

>file
: >file

このいずれかの方法で出来るらしい。 >fileの場合は虚無をfileにリダイレクトしているのでゼロクリアされる。 : >file の場合は、 何もしないコマンドである: の実行結果がfileにリダイレクトされるので0クリアされる。

ちなみにzshで上書き防止をしていた場合は

: >| file

とかするといい感じにゼロクリアされる。

Twitterの特定のハッシュタグをmattermostに投稿するbotつくった

昨日学科のLT大会があった。 毎年LT大会ではツイートを流すスクリーンがあるのだけれど、リモート開催なので学科のmattermostにTwitterが流れる仕組みがあれば面白いかな〜と思い雑に実装した。

もともとTwitterAPIはアプリを申請していたので使用できる状況にあったのだけれど、User Streams APIが廃止されていたので出来るかどうか微妙だった。 軽く調べるとUser Streams APIの代わりにStreaming APIがあるらしく、この中のstatus filterを使えばだいたい行けそうだった。 鍵垢のツイートが取れないというのはあるが、まぁ...。

それとmattermostへのwebhookはslackのものをエンドポイントをmatrtermostにすればいいだけらしく、これもわりと簡単そうだった。

というわけで雑に検索して出てきたgolangTwitter API SDKと、slackへのメッセージSDKをいい感じにして実装した。

f:id:anatofuz:20200504075508j:plain

結構いい感じですね。

golangで実装していたので、手早くローカルからLinux用にビルドして、学科のubuntu VM上でsystemdをつかって動かしていた。 基本的には特に障害も無く元気に動いてたので良かった気がする。

まぁなんとなく一応リポジトリ作った。

github.com

実装おもしろポイント

ハッシュタグの大文字小文字が区別されない

今回はクエリパタメーターとして v.Set("track", "#ieLT") を渡している。 これはツイート中に#ieLTがあるツイートのみを抽出するものである。(学科LTのハッシュタグ)

TweetDeckやなどをつかっていると大文字小文字は区別されるので #IELT#ieLT は別物扱いになる。 しかしこのAPIか、 golangのライブラリの仕様かは定かではないが、大文字小文字の区別がなく #IELT も収集されてしまうので雑に#IELTが含まれていたら弾くようにした。

今回は変なbotは出なかったが、bot避けに軽度緯度で日本国内に限定するとかしても良いかもしれない。

Tweetプロフィール画像の高画質化

今回のAPIで取得できるプロフィール画像https://pbs.twimg.com/profile_images/1153141142998794240/Yt9814c5_normal.jpgと _normalがついている。

これだと実際の画像が の様にあまり画質が良くない(サイズが小さい)

個人的な趣味でなるたけ高画質で取ってきたかったので、雑に_normalを取り除いて https://pbs.twimg.com/profile_images/1153141142998794240/Yt9814c5.jpg なURLに変更すると

とそこそこ高画質化される

vimで特定のプログラミング言語のファイルをシンタックスハイライトさせないようにする

背景

解決方法

  • vimrcにこう書いておけばいい
 autocmd FileType perl6 setlocal syntax=off
  • Perl6なファイルを開いた場合だけ syntax=offにする

参考

Disable syntax highlighting depending on file size and type

fedoraのfirewall-cmdでsshのIP制御を行う

あらまし

以前までfedorasshなどのIP制御をする場合は/etc/hosts.deny/etc/hosts.allowをいい感じに編集することで行っていました。

www.thegeekdiary.com

しかし最近のfedoraではこれらが非推奨になっているらしく、公式のフォーラムなどを見てもfirewalldを使えとの回答があるので、こちらで行ってみます。

Changes/Deprecate TCP wrappers - Fedora Project Wiki

forums.fedoraforum.org

なおfirewalldに対応するfirewall-cmd以外を使う方法では、nftablesを使う方法があり、こちらに関してはこのエントリを見るといい様です。

knowledge.sakura.ad.jp

fedorasshのIP制御をする

試しに某大学のIPアドレス及びプライベートIPアドレス以外のsshログインを制御してみます。

現在の設定の確認にはfirewall-cmdの list-allオプションを使います

$firewall-cmd --list-all

FedoraServer
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client http https ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

この場合 FedoraServer というzoneが使われており、許可しているservicesがhttp, https, ssh, dhcpv6-clientであるという状態です。デフォルトですね。

すべてのsshのログインを弾く

すべてのsshアクセスを弾くにはservicesからsshを外せばいいです。

$firewall-cmd --remove-service=ssh --zone=FedoraServer --permanent

処理をしたら忘れずにリロードを実行します

$ firewall-cmd --reload

特定のIPからのsshを許可する

次に許可したいIPをTCPの22番ポートのアクセスを許可する設定にしていきます。(sshTCPで22番ポートを使うので)

IPとサブネットマスクの表現はCIDRが使えます。

$firewall-cmd --permanent --zone=FedoraServer --add-rich-rule="rule family="ipv4" source address="133.13.0.0/16" port protocol="tcp" port="22" accept"
$firewall-cmd --permanent --zone=FedoraServer --add-rich-rule="rule family="ipv4" source address="10.0.0.0/8" port protocol="tcp" port="22" accept"

処理をしたら忘れずにリロードを実行します

$ firewall-cmd --reload

ここまで出来たら再び --list-allで確認すればいい感じになると思います。 取り急ぎこんな感じで...