GtiHub Actionsでfork元の更新を定期的にfetchする
forkしてちょっとだけ変更を加えてそのまま放置…
その間にも、fork元はコミットが進んでいるかも。
fork元の先進的な変更点は取り入れたいけれど、自分が変更したところは上書きされたくない!
そんなときはGitHub Actionsを使ってみようという話。
この記事は、SLP KBIT AdventCalendar2022 5日目の記事です。
おおまかな手順
- clone
git remote add upstream https://github.com/upstream/repository.git
git fetch upstream main
git rebase -X ours upstream/main main
git push -f origin main
とすると、fork元の変更を取り入れた後に、自分の変更が加えられる。
これを毎日実行すると、fork元で更新があれば取り入れ、自分が変更したコミットはその上に積まれる。
注意点:
- 自分で変更を加えたファイルは、fork元で更新があってもそれを検知できない(変更差分の判定から除外するため)
- 変更したファイルが多いと不適
- actions/checkout の
with: fetch-depth: 0
を設定しておかなければrebaseに失敗する(デフォルトではコミット履歴は1つしか取得しないため) - workflowファイルが更新された場合、tokenが
secrets.GITHUB_TOKEN
だと失敗する(権限がないため)- よって、token は PAT(Personal Access Token)を使う。
作り方: https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-tokendocs.github.com
権限はrepo
とworkflow
でよい。 作ったらリポジトリのsecretに登録しておく。ここでは登録名をPAT
にした場合の例を書いている。
- よって、token は PAT(Personal Access Token)を使う。
更新の有無を確認する
自分が変更を加えたファイルを除き、変更があるか否かを確認する。
自分が変更したファイルはここにパスを追記して更新の確認から除外しておかなければならない。
git diff main upstream/main --name-only -- ':!own/modified/file'
force pushする
rebase したことにより、コミット履歴が書き換わっている。
よってpush時はforceオプションを使用する。
--force-with-lease
を使ってもいいが、fetchしているため使用するメリットはない。
更新がなかった場合のearly exit
更新がなかった場合はさっさと処理を終了したい。
しかしexit 0
としても次のstepは実行されてしまう。
かといってexit 1
などと異常終了するとactionが失敗したとみなされ、失敗メールがうっとおしい。
そのため今回は変数に更新成功か失敗かを記し、以降のstepではその変数をifで確認して実行させるように対処している。
Example
README.md
に変更を加えて、他のファイルはfork元の変更を取り入れる場合。
毎日03:12にチェックを行う。
update用のactionを .github/workflows/update.yaml
に作成:
on: schedule: - cron: '12 3 * * *' env: UPSTREAM_URL: "https://github.com/upstream/repository.git" jobs: update: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: fetch-depth: 0 token: ${{ secrets.PAT }} - name: update id: update run: | git config --local user.name "${GITHUB_ACTOR}" # メールアドレスをこれにするとbotとしてコミットされる git config --local user.email "github-actions[bot]@users.noreply.github.com" git remote add upstream "${{ env.UPSTREAM_URL }}" git fetch --quiet upstream main # 自分が変更したファイルは更新の確認から除外する if [ -n "$(git diff main upstream/main --name-only -- ':!README.md' ':!.github/workflows/update.yaml')" ]; then echo "Update to follow the upstream repository." git rebase -X ours upstream/main main git remote set-url origin "https://${{ secrets.PAT }}@github.com/${GITHUB_REPOSITORY}.git" git push --force-with-lease origin ${GITHUB_REF#refs/heads/} echo "::set-output name=UPDATE_STAT::ok" else echo "No update found." echo "::set-output name=UPDATE_STAT::fail" exit 0 fi - name: update success report if: ( steps.update.outputs.UPDATE_STAT == 'ok' ) run: echo successflly updated! - name: no update report if: ( steps.update.outputs.UPDATE_STAT == 'fail' ) run: echo not updated.
ansibleでmysqlにinsertしたらData too long for columnだけど手動だと成功する
結論: 環境変数 LANG (LC_ALL) を UTF-8 対応のにする
やりたかったこと:
mysql -uuser -ppassword < insert_data.sql
のansible化
ansibleではこのようなタスクを定義:
- name: insert data shell: mysql -uuser -ppassword < insert_data.sql
実行するとエラー
mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1406 (22001) at line 6: Data too long for column 'hoge' at row 1 mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1452 (23000) at line 3: Cannot add or update a child row: a foreign key constraint fails (`huga`.`piyo`, CONSTRAINT `piyo_1` FOREIGN KEY (`puyo`) REFERENCES `puyo` (`poyo`))
(パスワード直書きはこの際置いておく)
ググると、 Data too long エラーの解決策は、sql_mode を strict じゃないのにするといいらしい。
しかし、同じデータを使っている他のサーバの sql_mode は全く同じ内容で、しかも strict も存在する。
謎すぎるためとりあえずシェルに入って手動で実行してみる。
$ mysql -uuser -ppassword < insert_data.sql
…できた。??
手動ではできたということは、コマンドの実行環境が違う疑いが持てる。
# ログインシェルのbashで試行 - name: shell with login shell shell: bash -lc "mysql -uuser -ppassword < insert_data.sql" # become (sudo) なしで試行 - name: shell without become shell: mysql -uuser -ppassword < insert_data.sql become: no
どちらもだめ。
仕方ないので現在の変数定義をみてみる。
- name: show login shell environments shell: bash -lc declare become: no
手動でシェルに入って見てみた分と比較。(どちらも一部抜粋)
--- 手動でシェルに入った分 +++ ansibleでの分 -BASH=/bin/bash -BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extquote:force_fignore:globasciiranges:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath +BASH=/usr/bin/bash +BASHOPTS=checkwinsize:cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath IFS=$' \t\n' -LANG=C.UTF-8 +LANG=C +LC_ALL=C +LC_CTYPE=C.UTF-8 +LC_MESSAGES=C
BASHOPTSが微妙に違うな〜などと見ていると、あれ、LANG系が全然違うぞと。
そういえばinsertするデータは日本語が入ってたなと。
試しにLANGをCにして実行してみる
LANG=C mysql -uuser -ppassword < insert_data.sql
無事に失敗!
ということで犯人はansibleが勝手に環境変数を変えた結果のLANGでした。
なのでansibleではこのようなタスクを定義して対処:
- name: insert data shell: LC_ALL=C.UTF-8 mysql -uuser -ppassword < insert_data.sql
うー、それにしてもなんで変数が変わってるのか…。
こんな記事
もあることからansible側を掘らないとわからないかも。
とりあえず対処できたのでヨシ!
tour of go で学んだ Error() の定義と呼び方
問題 https://go-tour-jp.appspot.com/methods/20
検証コード Go Playground - The Go Programming Language
Error() の実行
Error() を実行させるためには、 error インタフェースを満たす値を fmt の print系の関数に渡してやる。
print系関数の中身では、渡された引数の error をチェックして not nil なら Error() を実行するような動きになるため。
// func ReturnErrFn() error {}
fmt.Println(ReturnErrFn())
「error インタフェースを満たす値」とは、Error() メソッドを呼び出せる型のこと。
func (e ErrNegativeSqrt) Error() string { return fmt.Sprintf("Err: ErrNegativeSqrt: %v", float64(e)) }
つまり、ある変数がこのメソッドを呼び出せるなら、その変数は error インタフェースを満たしている。(error インタフェースは Error() メソッドのみを実装しているため)
よってその変数を fmt の print系に渡せば、通常のprintではなく Error() が実行される。
Error() メソッドのレシーバは変数かポインタか?
ポインタレシーバにすると、呼び出し元の変数はポインタでなければならない。
func (e *ErrNegativeSqrt) Error() string { return fmt.Sprintf("Err: ErrNegativeSqrt: %v", float64(e)) } // ok fmt.Println(RetErr(&errNegativeSqrt)) // fail fmt.Println(RetErr(errNegativeSqrt))
対して変数レシーバの場合、呼び出し元は変数でもポインタでもどちらでもよい。
func (e ErrNegativeSqrt) Error() string { return fmt.Sprintf("Err: ErrNegativeSqrt: %v", float64(e)) } // ok fmt.Println(RetErr(&errNegativeSqrt)) // ok fmt.Println(RetErr(errNegativeSqrt))
有効な error インタフェース値の返却方法?
なんからの関数で error を返却する場合、エラーとなる書き方がある。
type ErrNegativeSqrt float64 func RetErr(x float64) error { // fail return &ErrNegativeSqrt(x) // fail var errNegativeSqrt *ErrNegativeSqrt = &(ErrNegativeSqrt(x)) return errNegativeSqrt // ok var errNegativeSqrt ErrNegativeSqrt = ErrNegativeSqrt(x) return &errNegativeSqrt // ok (error == nil なのでこれを print しても Error() は実行されない) var errNegativeSqrt *ErrNegativeSqrt return errNegativeSqrt }
一旦現在のスコープの変数にコピーしてからそのアドレスを返却する必要がありそう。
実行結果(右辺)のアドレスはその行が終了した時点でdropされて dangling pointer のようになっているのだろうか。。
chrome os flex 導入メモ
chrome os flex (早期アクセス版) を導入したときのメモ
機器: DELL Inspilon 5505 (AMD Ryzen 4500U) サポート対象外機器
Wireguard VPN を使う
インストールしなくても組み込みで使える。
設定 > ネットワーク > 接続を追加 > 組み込みのVPNを追加
ネームサーバーの指定はカンマ区切りで4つ。
VSCode を使う
オンにしておく。
次に、vscode公式から .deb
ファイルをダウンロード
chrome os のLinux開発環境は、debian bullseyeなので、debファイルからアプリケーションをインストールできる。
ファイル から、ダウンロードしてきた .deb
ファイルをダブルクリックしてインストール。
Setting syncをするためには、terminal から gnome-keyring
をインストールしておく。決めたパスワードは毎回聞かれるので覚えておく。
このままでは日本語入力ができないため、fcitx5-mozcを入れる。
インストールするのは fcitx5
, fcitx5-mozc
。
入れただけでは起動しないので、systemd unit ファイルを /usr/local/lib/systemd/system/fcitx5.service
として作る。
[Unit] Description=fcitx5 After=fcitx5.service [Service] Type=simple ExecStart=/usr/bin/fcitx5 Restart=always User=<ユーザー名> Group=<ユーザー名のプライマリグループ> Environment='XDG_RUNTIME_DIR=/run/user/<UserのUID>' [Install] WantedBy=multi-user.target
/etc/environment
に環境変数を設定しておく。
GTK_IM_MODULE=fcitx QT_IM_MODULE=fcitx XMODIFIERS=@im=fcitx
有効化しておくと日本語入力が可能になる。
firefoxを入れる
chrome os 側でtarから利用はできないため、Linuxアプリとして入れなければならない。
debパッケージをubuntuのリポジトリからDLしてきてダブルクリック。
使用感
良い:
- UIがきれい
- debパッケージをインストールできる
- wireguardが使える
- Linux(manjaro)で頻繁発生していたフリーズ現象は確認していない
- Linux(ubuntu)で発生していた文鎮化現象は確認していない
悪い:
- setkeycodes のような key remapができない
- ショートカットキーがUS配列
- wireguardを使うとブラウジングが遅い、apt update先に接続待ちが発生する
- hdmiマルチディスプレイがたまに反応しない
- Lidを閉じたときにたまに画面がブラックアウトする
- firefoxの全画面表示ができない(F11では可能)
- (firefox)たまにフォントのドットが荒くなる。
- (firefox)動画を視聴しているとたまにテアリングが発生する
- 頻繁に動画がピンク色になる
早期アクセス版かつサポート対象外機器なので動作が不安定なのは仕方ない
GitHub Actionsでフォーマッタかけてpushするjob
フォーマッタかけるの,人手だと忘れる.
- run: | cargo fmt if [ -n "$(git diff)" ]; then git config --local user.name "${GITHUB_ACTOR}" git config --local user.email "${GITHUB_ACTOR}@users.noreply.github.com" git remote set-url origin "https://${{ secrets.GITHUB_TOKEN }}@github.com/${GITHUB_REPOSITORY}.git" git add . git commit -m "fmt: ${GITHUB_SHA::7}" git push origin ${GITHUB_REF#refs/heads/} fi
commitするユーザーをgithub-actions botにしたくば,user.email
をgithub-actions[bot]@users.noreply.github.com
に変える.
そしたら画像のようにoctocatのアイコンが現れる.
OpenWrtをスイッチ化してWireGuardを入れた
この記事は、SLP KBIT AdventCalendar2021 24日目の記事です。
多くのメンバーが面白い記事を書いてくれています。ぜひどうぞ。
さて、今年のアドカレでは、最近勉強し始めたRustでシェルでも作ってみようかな、と考えていました。
しかしながら、師走というだけあり、色々と忙しくなってしまい、、できませんでした!(また今度そのうちやります)
ということで、過去に下書きとして残していた記事(というよりメモ)を整えて、今年の僕のアドカレ担当分とします。
作業用BGMに毎年恒例の薪燃え見てます。ずっと見てられる。
この記事は、「自宅のOpenWrtルーターをWireGuard用のサーバーとして使っていたが、2重ルーターになってたのとメインのルーターの物理ポートが足りなくなったのでVPNサーバ兼スイッチングハブにした」という内容です。
こんな感じになる:
使用するルーター: Buffalo WZR-HP-AG300H
OpenWrtのバージョン: OpenWrt 21.02.1
コマンドラインではなく、LuCI(Webインタフェース)を使って操作していきます。
IPv6は使用していません。
switch化
WANポートのインタフェースを消すので、OpenWrtのLANポートと操作用PCをLANケーブルで繋いで作業を行います。
事前準備として、メインルーターとOpenWrtはこの時点では繋がないでおきます。
また、パスワードの設定は済ませておきます。(設定していないと、IPアドレスが変わったときに認証されないようです)
作業場所: Network -> Interfaces
- WAN, WAN6を消す
- LANをEdit
- Networks -> Devicesタブの
br-lan
の設定でEnable IPv6
のチェックを外してIPv6無効化- br-lanのBridge portsにはeth0.1とeth1を指定
- Save & Apply
- カウントダウンが開始する。残り70sぐらいになったら設定が適用されていると思われるので、以下の操作をカウントダウン中に行う(0になれば失敗します。もう一度チャレンジしましょう)
設定が反映されインターネットに接続できていることを確認できればOK
WireGuardを入れる
- UDPを利用し、L3トンネルを実現します。
- 公開鍵を使って認証したPeer同士で通信が可能になります。
作業場所: System -> Software
- Update lists... を押してパッケージリストをアップデート
- 次のパッケージをインストールします:
luci-app-wireguard
,luci-proto-wireguard
luci-app-wireguard
を入れたらluci-proto-wireguard
も一緒に入るかも。- System -> Reboot から 再起動
- Networks -> Interfaces -> Add new interface でwireguard用のインタフェースを作成する
- インタフェース名: wg0
- protocol: WireGuardVPN
- port: 51820 (なんでもいい)
- FW: lanにしてたがなんでもいいと思う
- Peers: 以下の事項に注意しながら適当に埋める。
こんな感じになる:
作成後に設定を変えるときは、Editで編集してSave&ApplyしてインタフェースのRestartをする。
メインルータの設定
ポート変換などの機能で OpenWRTのLANインタフェースのIPのUDPポート51820に インターネットから来るUDP 51820 のトラフィックを投げるように設定する。
Client Peerの設定
クライアントにあたるPeerの設定を書く。
Windowsなら、クライアントソフトのAdd Tunel -> Add empty tunnelで作成し、Editで書いていく。
[Interface] PrivateKey = <PrivateKey> ListenPort = 51820 Address = wg0のAllowedIPs/32 DNS = <DNS> [Peer] PublicKey = <PubKey> PresharedKey = <PSK> AllowedIPs = 0.0.0.0/0 Endpoint = <dnshostname>:51820
client peerのpubkeyを先ほどのwg0インタフェースのpeerに登録する。
wgwan用トラフィックルールの作成
WGはどうもNATでないと動作しない(WANに来たトラフィックを見ている?)みたい?なので、wg0がリッスンするNATデバイスをつくってやることにする。
作業場所: Network -> Firewall
Add からゾーン(ここでは wgwan とする)を作成する。
これらのforwardingsなどの設定は、既存のwanゾーンに合わせている。
ただし、wgwanのForwardはAcceptにしている。(もしかしたらrejectでいいかもしれない)
作成したら、Traffic Rules タブに移動する。
Addからルールを作成する。
Incoming IPv4, Protocol UDP, From wgwan To this device, port 51820, Accept input
メモによると、このままだとルータに有線接続した際にipでluciにアクセスできなかったとのことで allow WAN -> device:80,443 とするルールを追加していました。
wg0用NATインタフェースの作成
作業場所: Network -> Interfaces
- Add new interface でインタフェースを作成
Phew!
以上です。
当時の記憶があまりないので色々検証できてないですが、現状動いているので多分これで動きます。
メモをみるとSwitchデバイス(eth0.1あたり)やルーティングテーブルいじったり、迷走してましたね。。。
ちなみに、固定IPはお金がかかるので、DDNS(NoIP)を登録して使っています。
(あ、日付変わってた…メリークリスマス!🎅)
ansible_user, remote_user などの違いと使い分け [変数 != キーワード]
Ansibleの実行ユーザーとそのパスワードに使われる変数の使い分け
同じような変数(?)が複数あり、どれを使えばいいのか迷ったため。
調べていくと、変数とキーワードの違いが分かっていなかったため少し混乱した。
remote_user
リモートにsshでログインするユーザー名。キーワード。
playbookのキーワードとは、変数ではなく、設定値である。
変数は、あくまで変更を容易くする"データ"であり、playbookの実行やansibleによる状態の記述を補助するものとして扱う。
つまり、キーワードとは、お馴染みのtasks
やwhen
などと同じ分類のものである。…と言われるとわかりやすいと思う。
playbookの
と書いているのは、他にもrole
, block
, task
のキーワードがあるためである。これらの種類によって、各場所(必要なインデントの量)が変わる。
キーワードは変数ではないため、gather_facts: no
と変数を設定しても意味がない。
- hosts: test_server # これは(playbookの)キーワード。効果を発揮する。 gather_facts: no vars: # これは変数。特に意味がない。 gather_facts: no roles: - role: test
キーワードで設定されたものは、対応する変数によって上書きされ得る。
例えば、become: yes
と、キーワードを設定していても、変数の定義でansible_become: no
とすれば、権限昇格されない。
- hosts: test_server # これはキーワード become: yes vars: # この変数でbecomeの可否が上書きされる ansible_become: no roles: - role: test
ansible_user
同じくsshでログインするユーザー名。これは変数。
特殊な変数 Special Variables — Ansible Documentation
ansible_ssh_user
同上(古いので非推奨1)
ansible_password
sshのpassword。変数。
さらに、becomeのpasswordとしても使える。そのため、これを設定しておけばansible_become_password
は書かなくてもよい。
2021.07.17 修正
SSHを公開鍵認証で接続できているなら、これは書かなくてもよい。ただし、ansible_become_password
は必須。
ansible_ssh_password
同上(古いので非推奨2)
ansible_become_password
becomeのpassword。変数。
これをsshのpasswordとして使うことはできない。
ansible_become_pass
同上(古いので非推奨3)
(余談)ansible.cfgについて
become_user
やremote_user
などのキーだけでなく、ANSIBLE_REMOTE_USER
のような環境変数としての記述もできる。
キーと環境変数一覧 Ansible Configuration Settings — Ansible Documentation
しかし、ここにはpasswordについてのキー、環境変数は定義されていない。
...結局
ユーザー名とパスワードのセットで書いておきたいし、group_varsにansible_user
とansible_password
を書いておくのでFAにしようと思う。
Ref
Controlling how Ansible behaves: precedence rules — Ansible Documentation