OpenVPN 3 の Python エラー: 直すのは道具であり、システムの Python ではない
トレースバックが示すのは、フロントエンドを実行したインタープリターであり、トンネルを所有するサービスではありません。システム全体を切り替える前に、この二つを比べてください。
VPN 管理コマンドを実行した瞬間にトレースバックが現れると、まず別の Python を導入しようとしたり、システムの既定値をどこか別の場所へ向けようとしたりします。その衝動は、互いに何の関係もない二つのランタイムを混同しています。一方はオペレーティングシステムとその同梱ツールに属し、もう一方はあなたが構築しているプロジェクトに属します。後者を満たすために前者を変えると、動いていたデスクトップがパッケージマネージャーを失います。
比べる価値があるのは、実際に失敗したコンポーネントと、あなたが変更する権利を持つランタイムとの間です。両者が同じ対象であることは、ほとんどありません。
一つのように見える二つの Python の問い
第一の問いは、トレースバックを出力したプログラムを動かしたのはどのインタープリターか、です。第二は、自分のプロジェクトはどのインタープリターを使うべきか、です。端末ではどちらも python3 と打てば答えが出るため同じに見えますが、持ち主も更新経路も影響範囲も異なります。
システムのツールは、ディストリビューションが同梱したインタープリターと、そのインタープリターの ABI に対してビルドされたコンパイル済みモジュールに縛られます。プロジェクトは、あなたがそれ用に作った環境に縛られます。システムの既定値を移すと前者がマシン上の全ツールで一度に変わり、環境を作れば後者が一つのディレクトリだけ変わります。
そのうち一分で元に戻せるのは、片方だけです。元に戻せるのは前者ではありません。
エラーを出したのはどのコンポーネントか
何よりも先に、トレースバックの最初の行と、それを出力した実行ファイルを読みます。コマンドラインのフロントエンド、特権サービス、API バインディングは別々の部品であり、そのすべてが Python というわけでもありません。
command -v openvpn3
head -n 1 "$(command -v openvpn3)"
dpkg -S "$(command -v openvpn3)" 2>/dev/null
systemctl status openvpn3-service-client --no-pagerスクリプトの最初の行は使うインタープリターを指定しており、それがトレースバックの出どころです。パッケージへの問い合わせはそのファイルの所有者を教え、誰が変更してよいかを決めます。サービスの状態は、実際にセッションを確立する特権バックエンドが動いているかどうかという、まったく別の問いに答えます。
モジュールのインポートエラー、D-Bus のアクティベーション拒否、認証情報の拒否は三つの異なる段階です。インポートエラーはセッションが存在する前に起きるので、VPN の設定をどれだけ変えても直りませんし、サービスが正常でも直りません。メッセージをこの三段階のどれかに振り分けることが、実際の最初の一歩です。
プロジェクトの環境が直せることと直せないこと
プロジェクトの環境が解くのは、あるアプリケーションが必要とする正確なライブラリのバージョンを他のすべてから切り離して用意するというプロジェクトの問題です。それは確かに有用で、失敗しているプログラムが自分のスクリプトなら正しい道具です。
uv run --python 3.11 app.py
python3 -c 'import openvpn3; print(openvpn3.__file__)'二つ目のコマンドは、あるインタープリターからどのバインディングのコピーが見えるかを示し、パッケージが無いのか隠されているのかを見分ける最速の方法です。失敗しているスクリプトが使うインタープリターで実行し、たまたま動く別のものでは実行しないでください。
プロジェクトの環境にできないのは、ディストリビューションが同梱したフロントエンドの修復です。そのプログラムの依存関係はパッケージマネージャーが選んだインタープリター向けにビルドされており、プロジェクトの環境で動かせば失敗するか、誰もサポートしない混成物になります。環境変数でパスを注入するのは、手間が増えただけの同じ誤りです:ツールが読み込むものは変えたのに、試験した相手は変えていません。その交換が修正に見えるのは、次のインポートに突き当たるまでの間だけです。
システムのインタープリターを向け直すのが罠である理由
既定のインタープリターを変えるのは、一つのコマンドでトレースバックが直るように見えるので魅力的です。しかしホスト上の同梱 Python ツールすべてが前提にしているものを壊し、障害は後になって無関係な場所で現れます。
代替の選択機構は等価な実装を切り替えるために設計されたもので、古いコンパイル済みモジュールの下に新しい言語を入れるためのものではありません。コンパイル済み拡張は特定の ABI 向けにビルドされるので、昨日インポートできたモジュールが、パッケージを一つも削除していないのに今日は読み込めないことがあります。
人が見つける助言には、名前に関する罠もあります。バージョン表記のない python コマンドはディストリビューションや環境をまたいで一つの普遍的な意味を持たず、特定のメジャーバージョンの固定の同義語として扱うと、書いたマシンでしか効かない修正になります。ブログ記事のポリシーではなく、目の前のシステムのポリシーを読んでください。
分けて行う受け入れ試験
最後に置くべき試験は二つあり、片方に通っても他方については何も言えません。一つ目は、サポート対象のクライアントコマンドが、その同梱先のインタープリターで動くことです。二つ目は、特権サービスがセッションを確立し、トンネルが通信を運ぶことです。
openvpn3 sessions-list
openvpn3-service-client --help 2>/dev/null | head -n 3
ip -4 addr show tun0作業中は、とくに VPN が唯一の管理アクセスを運んでいる場合は、マシンに入る独立した経路を確保しておいてください。システムのインタープリターの変更は、途中でそのアクセスを失わせうる類の編集そのものです。
失敗がシステムツールのモジュール欠落なら、修正はサポートされた手順によるパッケージ操作です。失敗が自分のプロジェクトのバージョン競合なら、修正は環境です。二つのどちらを選ぶかが判断のすべてであり、それはどのプログラムがトレースバックを出力したかで決まります。