Unyablog.

のにれんのブログ

This AVD's configuration is missing a kernel file! Please ensure the file "kernel-qemu" is in the same location as your system image.

久しぶりに Android Studio を立ち上げて、公式エミュレータを作って立てたらこの事象に遭遇して立ち上がらなかった。x86_64 だとエミュレーターは立ち上がるが、画面がブラックアウトし、

resizing partition e2fsck failed with exit code 8

とログには出ている。

解決策

Android SDK Tools をアップデートする。

自分の場合、Android SDK Tools を android.bat (または android) 経由で更新していたのだけど、このときに 25 -> 26 へのアップデートが降ってこなかった。多分 26 で android コマンドが deprecated になって GUI がなくなった関係だろう。

Android Studio 経由でアップデートすると、Android SDK Tools 26 が降ってきて、 AVD を作り直すと使えるようになった。

android.bat はもう GUI では使えなさそう?なので諦めて Android StudioSDK Manager を使いましょう。

stackoverflow.com

zsh: typeset -Ug PATH

自分の zshrc 内では、$PATH の重複を排除するために typeset -U PATH と書いていた。

普段はこれで上手く行くが、関数内で source ~/.zshrc すると zshrc 内でエラーが沢山出た。

$ cat ~/.zshrc
...
function reload_zshrc {
  source ~/.zshrc
}
...

$ reload_zshrc
...
zsh:17: command not found: find
zsh:17: command not found: find
...

source 内では command not found となっているが、 reload_zshrc した後も $PATH は変わらず、コマンドも使えていた。 また、関数を経由せずに source ~/.zshrc とした時は正常に動いていた。

原因

これは、typeset は関数内の場合、 ローカル変数を作成 し、関数が終わったら unset するという挙動によるものである。

          Except  as  noted  below for control flags that change the behavior, a parameter is
          created for each name that does not already refer to one.  When inside a  function,
          a  new  parameter is created for every name (even those that already exist), and is
          unset again when the function completes.  See `Local  Parameters'  in  zshparam(1).
          The  same  rules  apply  to  special  shell  parameters, which retain their special
          attributes when made local.

Ubuntu Manpage: zshbuiltins - zsh built-in commands

なので、 reload_zshrc の中で typset -U PATH することで PATH の内容が初期化されてしまい、 command not found となっていた。

echo $PATH # /usr/local/bin:/bin: ...
typeset -U PATH
echo $PATH # (Empty output)

対処

これを防ぐためには、 typset -g で global scope の PATH を使用するようにする。

          -g     The -g (global) means that any resulting parameter will not be restricted to
                 local  scope.   Note  that this does not necessarily mean that the parameter
                 will be global, as the flag will apply to any existing  parameter  (even  if
                 unset)  from an enclosing function.  This flag does not affect the parameter
                 after creation, hence it has no effect when listing existing parameters, nor
                 does the flag +g have any effect except in combination with -m (see below).

Ubuntu Manpage: zshbuiltins - zsh built-in commands

echo $PATH # /usr/local/bin:/bin: ...
typeset -gU PATH
echo $PATH # /usr/local/bin:/bin: ...

systemd の dbus のパス

よく混乱するのでメモ。

Init としての systemd

/run/systemd/private

systemd 専用の direct な socket。 なので、ここに投げたら直接 systemd に飛ぶ*1。 systemctl などはここに投げている。

systemd が直接 bind / listen しているので、 dbus-monitor で見たりはできない。はず。

/run/systemd/private Used internally as communication channel between systemctl(1) and the systemd process. This is an AF_UNIX stream socket. This interface is private to systemd and should not be used in external projects.OSOCKADDR_UN_LEN

https://www.freedesktop.org/software/systemd/man/systemd.html#/run/systemd/private

/run/dbus/system_bus_socket

こちらは system bus と呼ばれるもので、 dbus-daemon が作成している。/etc/dbus-1/system.d/foo.conf に然るべき設定を置けば dbus-monitor --system で monitor できる。

DebuggingDBus - Ubuntu Wiki

systemctl の場合、 systemd の private で機能が足りない時に使われる。

例えば systemd-run --wait など*2

systemd --user 時

/run/user/$uid/systemd/private

これは systemd --user が作成する同様の private な socket。 systemctl --user を使うとこちらに飛ぶ。

/run/user/$uid/bus

これは session bus と呼ばれるもので、ユーザーのセッションごとに作られるもの。自分の環境だと dbus-daemon によってここに作られる。 このパスは $DBUS_SESSION_BUS_ADDRESS に入る事が多い。

system bus と同様に、 /etc/dbus-1/session.d/foo.conf で設定できる。

GUIsystemd --user に対する method_call はここに投げると良さそう。

*1:A よって A みたいな文章だ

*2: ref/unref が足りないらしい

Debian で systemd --user 時に dbus-daemon を起動する

systemd を user 単位で動かした際、主に CUI 環境では*1dbus-daemon は systemd が内部で用いるものしか生成されない*2

このような状況で、dbus 経由で systemd 等を触りたい場合は dbus-user-session を入れると良い。

Debian -- stretch の dbus-user-session パッケージに関する詳細

このパッケージの実体は systemd unit (/usr/lib/systemd/user/dbus.{service,socket} など) である。stretch の時点ではファイルを設置しているだけなので、実際に dbus-daemon を起動するには

$ systemctl start dbus --user

などとする。

そうすれば、 /run/user/$uid/bus ができて使えるようになる。

$ busctl --user tree
Service org.freedesktop.DBus:
Only root object discovered.

Service org.freedesktop.systemd1:
└─/org
  └─/org/freedesktop
...

busctl さっき知ったけど便利。

*1:gnome など dbus 使う GUI 環境で使っていれば gnome-session が dbus-daemon を起動してくれる

*2:/run/user/$uid/systemd/private がそれ

Jenkins でローカルレポジトリを github のレポジトリに同期する

Jenkins でローカルにあるレポジトリから github に同期したい。pipline で行う場合、 GitPublisher Plugin が使えないので、自分で git push する必要がある。

1. cred-idgithub にアクセスするためのユーザー名とトークンを Jenkins の credential に登録する。
2. Declarative pipeline で以下のスクリプトを書く。
withCredentials(
        [usernamePassword(
            credentialsId: 'cred-id',
            passwordVariable: 'GIT_TOKEN',
            usernameVariable: 'GIT_USERNAME'
            )]
        ) {
    sh('git push https://${GIT_USERNAME}:${GIT_TOKEN}@github.com/foo/bar master')
}

これで、 withCredentialsGIT_TOKENトークンが入り、 GIT_USERNAME にユーザー名が入る*1

3. ローカルレポジトリに Jenkinsfile を push して、そのレポジトリから pipeline project を設定する。

ここで、Jenkins のプロジェクトの設定で Additional Behaviours -> Check out to specific local branch を加えて Branch name を ** または空欄にする必要がある。何故なら、初期状態ではワークスペース上の git はブランチから外れているからである*2

参考

[JENKINS-28335] Step to run Git commands w/ credentials & tool (was: GitPublisher support) - Jenkins JIRA

*1:変数部はコンソールでは ** と表示される

*2:pipeline 上で checkout しても良い

Actions on Google SDK を用いた Action の開発で詰まった点

Google Assistant 用のアプリケーションを開発するときは Actions on Google SDK を使う。

よくあるのは Dialogflow 経由で設定して Firebase などで返答を決定するものだが、 Actions on Google SDK というものもある。

これを使えば、json で Action について記述して、gactions コマンドでデプロイすることができる*1

https://developers.google.com/actions/sdk/

基本的にドキュメントに書いてあるとおりなのだが、詰まった点をいくつか。

Dialogflow から Actions SDK に変更する時

$ gactions test では Dialogflow から変更されない。 $ gactions update を行うことで、 Dialogflow から Actions SDK にターゲットが変更される。

1プロジェクト1Actionなのは微妙に不便 *2

初めの呼びかけ以降は基本的に生のテキストが降ってくる

intent に独自の intent を記述して、 queryPattern に反応する語句とパースする変数を書くとその intent が使えるようになるのだが、これは最初だけである。 一度でも app.ask を行うと、 app.intent.TEXT 等のはじめからある intent しか降ってこないので注意。

For the first conversation turn, the intent will refer to the intent of the action that is being triggered. For subsequent conversation turns, the intent will be a built-in intent. For example, if the expected input is actions.intent.OPTION, then the the intent specified here will either be actions.intent.OPTION if the Google Assistant was able to satisfy that intent, or actions.intent.TEXT if the user provided other information.

https://developers.google.com/actions/reference/rest/Shared.Types/AppRequest#Input

要するに、

「Ok Google、○○ に XX と言って」

のような言い方をしないとパースされない。 Dialogflow を使えってことらしい(↓で Google のエンジニアが言っている)。

queryPattern の変数は前後に空白を置く

空白を置かないと反応しない。

"$color:SchemaOrg_Color の服を教えて"

個人用の Action に使っていたのだけど、微妙なので Alexa skill も使ってみたい。

*1:この時にプレビューの expire を指定できるので100年ぐらいにしようという目論見だった。しかし、もうじきそのオプションは消えるらしい

*2:Action だけ削除ができないのも難点

systemd-nspawn に関するメモ (--as-pid2 / ネットワーク関係)

--as-pid2

指定されたものを pid 2 で実行する。pid 1 には STUBINIT が入り、pid 1 に課せられた仕事を代わりにやってくれる(シグナル処理等)。何か(実質)シングルプロセスで立ち上げたい時はコレ使ってると良さそう。

root@piyo:~# systemd-nspawn --machine hoge -n --settings=no --as-pid2 bash
Spawning container hoge on /var/lib/machines/hoge.  
Press ^] three times within 1s to kill container
root@hoge:/# ps auxwwf 
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  56984  3044 ?        Ss   06:41   0:00 STUBINIT
root         2  0.0  0.1  18220  3176 ?        Ss   06:41   0:00 bash
root         3  0.0  0.1  36636  2752 ?        R+   06:41   0:00  \_ ps auxwwf

https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html#-a

ネットワーク関係

--port --network-veth --network-bridge などを使う場合、親子ともに systemd-networkd が立ち上がっているべきである。

systemd 自体は ve-hoge 等のデバイスを新たに作る。この prefix がついていると、 /lib/systemd/network/80-container-***.network が反映されて諸々の設定が行われる。

コンテナ側も同様で、 host0/lib/systemd/network/80-container-host0.network で設定がなされるので systemd-networkd が立ち上がっていないと上手く動かないことがある。*1

https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html#-n

--port

--port (ポートフォワーディング)の場合、 IPMasquerade が使われているので、 systemd-networkd は必須。

このポートフォワーディングには iptables の NAT が使われており、 # iptables -L -t nat でその様子を眺めることが出来る。DebianUbuntu の場合、古い (systemd 231-5 より前) と iptables の lib がない状態でコンパイルされてて IPMasquerade は使うことが出来ない。

$ sudo machinectl start hoge

$ sudo iptables -t nat -L -v
Chain PREROUTING (policy ACCEPT 2 packets, 200 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DNAT       tcp  --  any    any     anywhere             anywhere             tcp dpt:2000 ADDRTYPE match dst-type LOCAL to:10.0.0.2:2000

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 2 packets, 126 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DNAT       tcp  --  any    any     anywhere            !127.0.0.0/8          tcp dpt:2000 ADDRTYPE match dst-type LOCAL to:10.0.0.2:2000

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

ちなみに !127.0.0.0/8 となっていることからも分かる通り、親コンテナからはポートフォワーディングは見えないので注意。外部 IP などから確認する必要がある。

github.com

#787480 - build with iptables support - Debian Bug report logs

*1:DHCP を使っているので networking でも初期状態でまあまあ上手くはいく。