やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

PC起動時に自動でニュース取得したいがエラー(systemd)

 systemdは失敗した記憶しかない。

やりたいこと

 PC起動時に自動でニュース取得スクリプトを実行させたい。

方法

 起動時や定時などのタイミングで何かを行うにはOS固有のしくみを使うことになると思われる。スケジューラと呼ばれたりもする?

 Linux(Debian9(Raspbian stretch))ではいくつかのしくみがある。 このうちsystemdが推奨。

コード

実行するスクリプト

 以下、前回のコードを実行する。

 これに加えて、それを実行するためのBashスクリプトを用意する。

get_news.sh

#!/bin/bash
run() {
    GetFeeds() { local SCRIPT_DIR="$(cd $(dirname $0); pwd)"; cat "$SCRIPT_DIR/feeds.txt"; }
    MakeWorkDir() { local work_dir=/tmp/work; mkdir -p "$work_dir"; cd "$work_dir"; }; MakeWorkDir;
    echo "PC起動時に実行したよ。: $(pwd)" > "systemd_run.txt"
    local run_sh="/home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/run.sh"
    echo "$(GetFeeds)" | "$run_sh"
}
run
exit 0

 feeds.txtはフィードURLを改行区切りにしたテキストファイル。

権限付与とシバング

chmod 755 get_news.sh
chmod 755 get_news.py
シバング 拡張子
#!/bin/bash .sh
#!/usr/bin/env python3 .py

 権限付与とシバングがないせいでsystemdエラーになることがよくあるらしい。

環境

 systemdで実行するとき、Pythonのパッケージをルート権限でインストールしていないと怒られるらしい。

 そこで、以下のようにルート権限で必要なパッケージをインストールした。

sudo -H pip3 install pytz
sudo -H pip3 install tzlocal
sudo -H pip3 install selenium
sudo -H pip3 install beautifulsoup4
sudo -H pip3 install lxml
sudo -H pip3 install readability-lxml
sudo -H pip3 install html2text

 同じパッケージを2つもインストールとか、完全にディスクの無駄遣いだろ……。

systemd

 サービス作成。

/etc/systemd/system/get_news.service

[Unit]
Description=ニュースを取得する。
After=local-fs.target network-online.target 
Requires=local-fs.target network-online.target

[Service]
EnvironmentFile=/home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/env.txt
ExecStart=/home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/get_news.sh
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target

 [Service]User=???キーがある。これを使えばルート権限でのパッケージ入手は不要? だったらいいな。

キー 意味
Unit.After このサービスは指定したサービスの後で起動する
Unit.Requires このサービスは指定したサービスが必須でありそれの起動が失敗すればこれも失敗する
Service.EnvironmentFile 環境変数を設定したファイルパスを指定する
Service.ExecStart サービス起動したときに実行するコマンド
Service.Restart サービスプロセス停止時の再起動条件(no,always,...)
Service.Type 実行コマンドとメインプロセスの関係(simple,forking,oneshot
Install.WantedBy enable時に指定したUnitの.wantsディレクトリにリンクを作る

 env.txtは、PATH=...のように環境変数を設定したコードがかかれたファイル。

systemctl enable get_news
systemctl start get_news
systemctl status get_news

 startすると、なぜか認証ダイアログが出てシステムログイン認証? を求められた。3回も。間違うと怒られる。

f:id:ytyaru:20190928082544p:plain f:id:ytyaru:20190928082549p:plain

Failed to start get_news.service: Access denied
See system logs and 'systemctl status get_news.service' for details.

 statusをみるとstatus=203/EXECエラー。

● get_news.service - ニュースを取得する。
   Loaded: loaded (/etc/systemd/system/get_news.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Fri 2019-09-27 21:06:11 JST; 11h ago
  Process: 498 ExecStart=/home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/get_news.sh (code=exited, status=203/EXEC)
 Main PID: 498 (code=exited, status=203/EXEC)

 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Failed with result 'exit-code'.
 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Service hold-off time over, scheduling restart.
 9月 27 21:06:11 raspberrypi systemd[1]: Stopped ニュースを取得する。.
 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Start request repeated too quickly.
 9月 27 21:06:11 raspberrypi systemd[1]: Failed to start ニュースを取得する。.
 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Unit entered failed state.
 9月 27 21:06:11 raspberrypi systemd[1]: get_news.service: Failed with result 'exit-code'.

 ログを見てもよくわからん。上記以上の情報が見つからない。

/var/log/syslog

Sep 27 21:06:10 raspberrypi systemd[1]: Started ニュースを取得する。.
Sep 27 21:06:10 raspberrypi systemd[1]: Starting /etc/rc.local Compatibility...
Sep 27 21:06:10 raspberrypi systemd[1]: Starting Daily apt download activities...
Sep 27 21:06:10 raspberrypi systemd[468]: get_news.service: Failed at step EXEC spawning /home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/get_news.sh: Exec format error
Sep 27 21:06:10 raspberrypi systemd[1]: Started Permit User Sessions.
Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Main process exited, code=exited, status=203/EXEC
Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Unit entered failed state.
Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Failed with result 'exit-code'.
...
Sep 27 21:06:10 raspberrypi systemd[1]: Starting Hold until boot process finishes up...
Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Service hold-off time over, scheduling restart.
Sep 27 21:06:10 raspberrypi systemd[1]: Stopped ニュースを取得する。.

/var/log/deamon.log

Sep 27 21:06:10 raspberrypi systemd[468]: get_news.service: Failed at step EXEC spawning /home/pi/root/sys/workflow/script/py/Python.News.20190927123127/src/get_news.sh: Exec format error
Sep 27 21:06:10 raspberrypi systemd[1]: Started Permit User Sessions.
Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Main process exited, code=exited, status=203/EXEC
Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Unit entered failed state.
Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Failed with result 'exit-code'.
Sep 27 21:06:10 raspberrypi systemd[1]: Starting Light Display Manager...
Sep 27 21:06:10 raspberrypi systemd[1]: Started /etc/rc.local Compatibility.
Sep 27 21:06:10 raspberrypi systemd[1]: Starting Terminate Plymouth Boot Screen...
Sep 27 21:06:10 raspberrypi systemd[1]: Starting Hold until boot process finishes up...
Sep 27 21:06:10 raspberrypi systemd[1]: get_news.service: Service hold-off time over, scheduling restart.
Sep 27 21:06:10 raspberrypi systemd[1]: Stopped ニュースを取得する。.

所感

 動かん……。原因不明。簡単なPythonスクリプトだけなら動かせたのだが……。

 なんというか、Windowsのスタートアップみたいに、ショートカット登録するだけで実行できたりしないの? OSブートの仕組みを少しは理解していないと設定できないとか、難解すぎるだろ。そんなの知らなくても自動実行したいんだよ!

情報源

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux