ninigi.log

作業ログ。ネットワーク, python, RoR, Reactなど。

RFC6749 The OAuth2.0 Authorization Frameworkを読む

OAuth2.0を勉強しなければいけなくなったのだけれど、ちょっと調べてもよくわからない。日本語の記事を読んでも、たぶん自分には前提となる知識が抜けているのかいまいちわからない。

自分は原典厨なので、OAuth2.0についてのRFCを読んでそれをまとめることにした。 メモ的な意味をかねてここに要約を書いた。

Abstract

OAuth2.0 authorization frameworkはサードパーティのアプリケーションに,HTTPサービスへの制限されたアクセス権を取得できるようにさせるための仕組みである.

1. Intorduction

従来のクライアント・サーバによる認証モデルでは,クライアントがサーバにリソースオーナの認証情報を用いて認証して,サーバに対して制限されたアクセス権をリクエストする. サードパーティのアプリケーションにリソースへのアクセスを提供するためには,リソースオーナがサードパーティアプリに対して認証情報を共有する必要があった.

  • サードパーティアプリケーションは,今後も使うためにリソースオーナの認証情報を保持することが求められる.これは典型的には平文のパスワードを保持する.
  • サーバは,パスワード固有のセキュリティ面での弱さがあるのにも関わらず,パスワード認証をサポートすることを求められる.
  • サードパーティアプリは,オーナのリソースに対して過剰に広いアクセス権を得ることになる.さらに,オーナはリソースの一部に対するアクセス制限をかけることもできない.
  • リソースオーナは個々のサードパーティアプリに対してアクセス権を取り消すことができない.そうするためには全てのサードパーティアプリのアクセス権を取り消し,サードパーティアプリのパスワードも変更しなくてはならない.
  • サードパーティアプリが侵害されると,エンドユーザのパスワードも侵害されそのパスワードによって保護されている全てのデータも侵害されてしまう.

OAuthは,authorization layerの導入とリソースオーナの役割とクライアントの役割を切り離すことでこれらの問題に取り組む. OAuthでは,クライアントはリソースオーナによって管理され・リソースサーバにホスティングされているリソースに対するアクセスを要求する. さらにクライアントはリソースオーナの認証情報とは異なる認証情報を発行してもらうことになる.

保護されたリソースにアクセスするためにリソースオーナの認証情報を利用する代わりに,クライアントはアクセストーク(特定のスコープ・有効期限・その他のアクセス属性が記された文字列)を取得する. アクセストークンは,認証サーバからサードパーティクライアントに対してリソースオーナの許可を得て,発行される. クライアントはアクセストークンを,リソースサーバに設定された保護されたリソースに対するアクセスにために用いる.

例えば,エンドユーザ(リソースオーナ)は,印刷サービス(クライアント)に,写真共有サービス(リソースサーバ)に保存されている保護された写真に対するアクセス権を,ユーザ名とパスワードを印刷サービスに共有することなく,許可することができる. 代わりに,ユーザは写真共有サービスに信頼されているサーバ(認証サーバ)を直接認証し,印刷サービスに特定の委譲認証情報(アクセストークン)を発行する.

この詳細は,HTTPを用いるように設計されている. HTTPを使用しない任意のプロトコル上でのOAuthの利用は,範囲外とする.

OAuth1.0プロトコルは,informationalな文章として発行され,小さなアドホックコミュニティの成果物だった. 本文章でのインターネット標準の仕様は,OAuth1.0の運用経験およびいくつかのユースケースの追加とより広いIEFTコミュニティから集められた拡張性の要求を基に設計されている. 2つのバージョンはおそらくネットワーク上に共存してもよく,実装では両方をサポートしてもよいだろう. しかし,この文章で策定することで,新たな実装がOAuth2.0をサポートしていき,OAuth1.0に関しては現在運用されているもののみがサポートするようになることを意図している. OAuth2.0プロトコルは,OAuth1.0と実装面の細部はほとんど共有していない. そのためOAuth1.0で慣れ親しんだ実装者は,構造と詳細については何の仮定もせずにこの文章を読むべきである.

1.1 Roles

OAuthは4つの役割を定義している.

  • リソースオーナ このエンティティは,保護されたリソースに対するアクセス権を許可することができる.リソースオーナが人間である場合は,エンドユーザのことを指す.

  • リソースサーバ 保護されたリソースをホスティングしているサーバ. このエンティティは,保護されたリソースに対するアクセストークンを利用したリクエストに対して,許可と応答を行う.

  • クライアント リソースオーナの代わりに,リソースオーナから許可を得て,保護されたリソースに対するリクエストを行うアプリケーション. "クライアント"という用語は,特定の実装の特徴を暗喩しているわけではない(例えば,アプリケーションはサーバで実行されていてもいいし,デスクチェアで実行されていてもいいし,他のデバイスで実行されていてもよい).

  • 認証サーバ リソースオーナの認証・認可の取得が成功した後に,クライアントに対してアクセストークンを発行するサーバ.

認可サーバとリソースサーバのインタラクションはこの仕様の範囲外とする. 認可サーバはリソースサーバと同じ場合もあるし,異なるサーバの場合もある. 1つの認可サーバは,複数のリソースサーバに許可されるアクセストークンを発行 することができる.

--- 6 / 75 page , 2020.1.19

OpenAPI / Swagger overview

動機

"APIのインタフェースをSwaggerを使って定義しておきますね"

何を言っているのかわからなかった。

やりたいこと

Swaggerで何ができるのか、何をしたいから使うのか、どうやって使うのかを知りたい。

やったこと

  • swaggerのドキュメントを読んで理解するために必要そうなところをまとめた
  • OpenAPIのフォーマットにそってAPIを定義してみた

Swaggerとは

swagger.io

Swagger is the most widely used tooling ecosystem for developing APIs with the OpenAPI Specification (OAS).

API開発のためのエコシステム、なるほど。OpenAPI Specifiactionがわからない。

OpenAPI Specificationとは

おそらく知りたかったのはこっち。

swagger.io

RESTful APIのためのインタフェース。サービスの提供するものを、

  • 人にもコンピュータにも検索・理解がしやすい形で
  • ソースコード・ドキュメント・ネットワークトラフィックにアクセスせずに
  • 検索・理解することができる

OpenAPIの定義は様々な用途に使うことができる。

  • APIドキュメント生成
  • 様々な言語でサーバ・クライアントの生成

仕様があればドキュメントを生成することもできるし、簡単なサーバ・クライアントを自動で作ることもできるということ?できそう。

つまりOpenAPIはAPI仕様を定義するためのフォーマットということ。

OpenAPIの仕様

フォーマット

JSONもしくはYAMLで書かれる

ドキュメント構造

複数のファイルに分割することができ、どちらにするかは自由。 分割する場合は、$refフィールドによって参照する。

分割した場合、ルートとなるファイルはopenapi.jsonまたはopenapi.ymlとすることが推奨されている。

OpenAPIとSwaggerの違い

結局Swaggerが何かわからなくなった。 公式ドキュメントのA Brief History Lessonのセクションによると

  • SwaggerというAPIの仕様記述のフレームワーク・エコシステムが存在した
  • 2015年にLinux Foundationに寄付されOpenAPI Specificationという名前に変更
  • Swaggerの書式をベースにしてAPI記述フレームワークの標準を策定するための団体であるOpenAPI Initiative (OAI)が設立
  • 現在はOpenAPIを記述するためのツールが他にも存在している

Swaggerをベースに標準規格であるOpenAPIの仕様が決められたけど、OpenAPIを記述するためのフレームワークはSwagger以外にもあるよということらしい。

www.publickey1.jp

現在でSwaggerといったらOASを記述するためのツールという意味合い?

qiita.com

チュートリアル

OpenAPIのフォーマットでAPIの仕様を書く。

良さそうだったのでVSCodeのSwagger Viewerを使いながら書いてみる。良さそうというのは書いたyaml/jsonをいい感じに見せてくれるのでわかりやすそうだった。

インストールは以下を参考にして行った。

qiita.com

最小構成

ドキュメントでrequiredとなっているフィールドは埋めないと描画してくれないので注意。 OASの仕様に載っている例を流し込んだ。openapiのバージョンはよくわからなかったので適当に設定した。

f:id:ninigishi:20200110224048p:plain

左でyamlを書いて右でそれをいい感じに見せてくれる。

wine on ubuntu18.04でKindle for PCを動かす

動機

Kindleで買った技術書を大きい画面でメモしながら読みたい。Ubuntu 18.04を普段遣いしているのでubuntu18.04上で読みたい。

Kindleで買った本をAndroidiOSアプリ以外で読む方法は2つある*1

  1. Kindle Cloud Reader
  2. Kindle for PC

1は一見良さそうだが本によっては対応していない。 手持ちの本で試したところマンガは全部読めたが、技術書はほとんど読めなかった。 技術書を大画面で読みたいというのが最初の動機だったのでKindle Cloud Readerは却下。 マンガを読みたいだけならKindle Cloud Readerで良さそう。

2についてはWindows版とMac版しかないため、Windows版のアプリをlinuxで動かす必要がある。

LinuxWindowsアプリを動かすには、1) 仮想環境上でWindowsごと動かす、2) wineで動かすの2つの選択肢がある。 本を読むのにわざわざVirtual Boxを動かすのはちょっと嫌だったのでwineで動かすことにした。

環境

  • Ubuntu: 18.04
  • wine: 4.0.3
  • winetricks: 20191224-next

Kindle for PCをwineで起動

はじめに、自前でダウンロードしたKindle for PCを動かす方法は既知のバグによりうまくいかなかった。 winetricksで用意されているものを動かしたところうまくいったのでその方法から書く。

wineのインストール

wineのインストールは公式wikiのガイド*2に従った。

sudo dpkg --add-architecture i386
wget -nc https://dl.winehq.org/wine-builds/winehq.key
sudo apt-key add winehq.key
sudo apt-add-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ bionic main'
sudo atp update
sudo apt install --install-recommends winehq-stable

Ubuntuのバージョンによって4行目のURLが異なり、6行目についてはstable, devel, stagingの3つから選べる。

winetricksのダウンロード

wineHQ公式wiki*3に従う。

cd ~/Downloads
wget  https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
chmod +x winetricks

これは公式ドキュメントには書いていないが、利便性のためパスの通っている場所に置く。

sudo mv winetricks /usr/local/bin/

winetricksによるwineの設定

ここからは手探りでやったのでもっと良い方法はありそう。

winetricks arch=32
winetricks allfonts
winetricks kindle

winetricks arch=32 では32bit版として動かすように設定している。 64bit版で動かしたところ警告メッセージが出たため。 一度64bit版で動かしてしまった場合は、一旦~/.wine を削除かリネームする必要がある。prefixオプションで指定しても良さそう。

winetricks allfonts では必要なフォントをインストールしている。 日本語が豆腐になってしまったため。 allがどの範囲を指すのかわからないが結構時間がかかった。 参考

winetricks kindle ではあらかじめ用意されていたKindle for PCの実行ファイルを実行している。 winetricksにはあらかじめいくつかのアプリが用意されており、winetricks apps list で一覧を見ることができる。

Kindle for PCの起動

winetricks kindleを実行した時点で起動する。 デスクトップにショートカットができるのでそこから起動する。 本当はコマンドラインから起動したいが、調べていない。

動いている様子。 f:id:ninigishi:20200109110602p:plain

[x] 自前のKindle for PCの実行

うまくいかなかった方法。

自分でAmazonストアから無料で購入してダウンロードしたKindle for PCを動かす方法。wineのインストールまでは同じ手順で行ったが結局うまくいかなかった。一応書き残しておく。 参考

wineの初期設定

32bit版で設定。

WINEARCH=win32 wineboot

フォントの設定。~/.wine/user.regに追記。

[Software\\Wine\\Fonts\\Replacements]
"MS Gothic"="TakaoEx\x30b4\x30b7\x30c3\x30af"
"MS PGothic"="TakaoEx\x30b4\x30b7\x30c3\x30af"
"MS Sans Serif"="TakaoEx\x30b4\x30b7\x30c3\x30af"
"MS Shell Dlg"="TakaoEx\x30b4\x30b7\x30c3\x30af"
"MS UI Gothic"="TakaoEx\x30b4\x30b7\x30c3\x30af"

Kindle for PCのダウンロード

Amazon ストアからKindle for PC(Windows)をダウンロード。 ¥0で購入する必要がある。

wineでKindle for PCの起動

ファイル名に日本語が入っているのが気持ち悪いがめんどくさいのでそのまま。

wine ~/Downloads/Kindle_for_PC_Windows_ダウンロード.exe

エラー

このようなポップアップとエラーログが流れて起動しない。 f:id:ninigishi:20200108180214p:plain エラーログ抜粋

[ERROR][VersionInfo] Build version is not of the form major.minor.patch.revision

ググったところ公式フォーラムにも同じ質問がある。 forum.winehq.org

意外と根が深そうな問題。 Kindle for PCのバージョンが古ければ動くという記述もあるが、動かないという記述もある。

以下読んで試したけど上手く行かなかった記事たち。

  • 同じ現象に関する記事

askubuntu.com

bugs.winehq.org

bugs.winehq.org

  • 関連する記事

bugs.winehq.org

askubuntu.com

お手上げ。

Python3 SQL Server 2016 接続設定

動機

Python3 からリモートの SQL Server 2016 に接続したい。

PythonからSQL Serverに接続する際に情報が少なくて調べるのが大変だったのでまとめた。 ローカルホスト上にSQL Serverを立てて接続する方法などはたくさん出てくるがリモートサーバへの接続やWindows以外のOSからの接続方法などは断片的な情報しか出てこない。

環境

サーバー

クライアント

SQL Server・クライアントPCそれぞれの現状

SQL Serverの状況

  • リモートのSQL Serverは正常に動作
  • SQL Serverへのローカルからの接続は成功
    • SQL StudioでWindows認証(後述)を用いて接続

クライアントPCの状況

  • Pythonのモジュールpyodbcインストール済み
  • コマンドラインツールsqlcmdインストール済み
  • Pythonpyodbcにおけるドライバーのエラーは解決済み(他の記事に書く)

サーバとクライアントのネットワーク状況

問題

Pythonスクリプト上で接続しようとすると失敗する。

接続用のスクリプト

conn = pyodbc.connect(
    'DRIVER={/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.4.so.1.1};'
    'Server=10.0.0.124;'
    'UID=user1;'
    'PWD=pass;'
    'Database=master;'
)

このスクリプトを実行時のエラー

Traceback (most recent call last):
  File "dbtest.py", line 7, in <module>
    conn = pyodbc.connect('DRIVER={/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.4.so.1.1};'
pyodbc.OperationalError: ('HYT00', '[HYT00] [Microsoft][ODBC Driver 17 for SQL Server]Login timeout expired (0) (SQLDriverConnect)')

IPアドレス、UID、PWDは合っていることは確認済み。

ここからでは何が原因かわからないため、CLIからコマンドを叩く。

接続試行用のコマンド

> sqlcmd -S 10.0.0.124 -U user1
Password:

コマンド実行時のエラー

Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : Login timeout expired.
Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : TCP Provider: Error code 0x102.
Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : A network-related or instance-specific error has occurred while establishing a connection to SQL Server. Server is not found or not accessible. Check if instance name is correct and if SQL Server is configured to allow remote connections. For more information see SQL Server Books Online..

接続自体ができていないということがわかった。Windows Server側の設定が必要らしいのでこれについてまとめていく。

SQL Server 接続設定

リモートからの接続の許可

f:id:ninigishi:20190911155413p:plain リモートからの接続を許可にチェックを入れる

TCP/IPによる接続を許可

SQL Server Configuration Managerを起動する。 f:id:ninigishi:20190911155537p:plain

SQL Server Configuration Manager は日本語では SQL Server 構成マネージャー。

f:id:ninigishi:20190911155738p:plain

[SQL Server ネットワークの構成] >> [SQL EXPRESSのプロトコル] を選択。

右ペインのTCP/IP を右クリックして、プロパティを選択。以下のようなポップアップが開く。

f:id:ninigishi:20190911160024p:plain

Enabledを"はい"に変更。[IPアドレス]タブを選択。

f:id:ninigishi:20190911160211p:plain

一番下の [IP ALL] の欄の[TCP port] の値を1433 にする。別に他の値でも良いが、Windows SQL Serverのデフォルトポートは1433。

適用ボタンをクリック。設定を適用するためにはサービスの再起動が必要。

f:id:ninigishi:20190911160535p:plain

左ペインで [SQL Serverのサービス] を選択。右ペインの [SQL Server] を右クリックして[再起動] を選択。サービスの再起動が行われる。

これで、SQL Server的にはTCP/1433 でコネクションが張れるようになった。

Windowsはデフォルトでファイアウォールが設定されているので、次にポートの開放を行う必要がある。

Windows Firewall の設定

Windows Firewallを起動する。名前はちょと違うかもしれない(手元にWindows環境がないので確認できない)。

[新規の受信規則] を選択して新たなルールを追加する。

f:id:ninigishi:20190911161139p:plain

ポートベースで許可を行う。プログラムベースの方がスマートかもしれない。

f:id:ninigishi:20190911161213p:plain

TCPにチェックを入れる。[特定のローカルポート]の値を1433にする。先程違うポート番号を設定した場合はそれを入れる。

f:id:ninigishi:20190911161332p:plain

接続を許可するにチェックを入れる。

f:id:ninigishi:20190911161402p:plain

ここは自分のポリシーに従って。今回は全部許可にした。

f:id:ninigishi:20190911161434p:plain

今作成しているファイアウォールのルールに名前をつける。適当に。

SQL Serverの認証設定

ここまでで接続自体はできるようになっていて欲しいが、できない。SQL Serverには"Windows 認証" と "SQL Server 認証"の2つのユーザ認証方式をサポートしている。

Windows認証の仕組みはどうなっているのかよくわからないが、ユーザ名だけで認証できるようだ。今回は、ユーザ名とパスワードによって認証を行う一般的な認証を行いたい。従って、SQL ServerSQL Server認証を許可しなければならない。

環境構築の段階で設定していればここは飛ばして良い。

f:id:ninigishi:20190911163005p:plain

[SQL Server認証モードとWindows認証モード] にチェックを入れ、[適用] をクリック。

ここでもサービスを再起動する必要があるので、先程同様にSQL Serverのサービスを再起動する。

この時点で、接続自体はできるようになった。

> sqlcmd -S 10.0.0.124 -U user1
Password:
1>

プロンプトに 1> と表示され、接続できていることが確認できた。

pythonで冒頭のスクリプトを叩いてもエラーが発生しないことが確認できた。

netbox-dockerのホスト移植

動機

  • 現在ホストA上でnetboxをdocker-composeで動かしている。
  • これをデータも含めてホストBに移行したい

自分のサーバ上でとりあえず試運用していた。よさそうだったので、監視サーバに移行させたい。

環境

便宜上以下のように表記する。

  • 移行元のサーバ: src server
  • 移行先のサーバ: dst server
  • 作業用のPC: local

src server

  • Ubuntu 16.04
  • docker: 18.09.6

dst server

  • Ubuntu: 16.04
  • docker: 19.03.2

現状確認

src serverでのnetboxの状況を確認する。

netbox-communityのgithubで公開されているdocker-composeをそのまま動かしている。

github.com

docker-compose ps
            Name                           Command               State                Ports             
--------------------------------------------------------------------------------------------------------
netbox-docker_netbox-worker_1   python3 /opt/netbox/netbox ...   Up                                     
netbox-docker_netbox_1          /opt/netbox/docker-entrypo ...   Up                                     
netbox-docker_nginx_1           nginx -c /etc/netbox-nginx ...   Up      80/tcp, 0.0.0.0:32769->8080/tcp
netbox-docker_postgres_1        docker-entrypoint.sh postgres    Up      5432/tcp                       
netbox-docker_redis_1           docker-entrypoint.sh sh -c ...   Up      6379/tcp    

redisはなんのために使っているんだろうか。 docker-compose.yml の中身を見てみると、netboxnetbox-workerdepends_on されている。 セッション管理とかかな?

普通に作られていればコンテナ自体を移植する必要はないはず。 docker pullすれば同じコンテナが入るはずだから、データだけを移植すればいい。 移行すべきデータはpostgres のデータのみになる。

やるべきこと

README.mdに正解があった。

  • To create a database backup run docker-compose exec postgres sh -c 'pg_dump -cU $POSTGRES_USER $POSTGRES_DB' | gzip > db_dump.sql.gz
  • To restore that database backup run gunzip -c db_dump.sql.gz | docker exec -i $(docker-compose ps -q postgres) sh -c 'psql -U $POSTGRES_USER $POSTGRES_DB'.

netboxの移行

dst serverの設定

dockerのインストール

dockerとdocker-composeが入っていなければインストールする必要がある。

docs.docker.com

docs.docker.com

netbox-dockerのセットアップ

README.mdに従う。

github.com

$ git clone https://github.com/netbox-community/netbox-docker.git

# docker-compose pull
# docker-compose up -d

データの移行

@src server: データを出力。

# docker-compose exec postgres sh -c 'pg_dump -cU $POSTGRES_USER $POSTGRES_DB' | gzip > db_dump.sql.gz

@local: src serverで出力したデータをコピーして、dst serverに送信。

$ scp host-a:~/netbox-docker/db_dump.sql.gz /tmp
$ scp /tmp/db_dump.sql.gz host-b:~/

@dst server: データを解凍してSQLを実行。

# gunzip -c db_dump.sql.gz | docker exec -i $(docker-compose ps -q postgres) sh -c 'psql -U $POSTGRES_USER $POSTGRES_DB'

これで完了。

ただ自分の環境ではこれだけではうまくいかなかったので、以下にエラー&ワークアラウンドを書いた。

エラー&ワークアラウンド

エラー

https://example.com:32768 に行ってみるとデータが追加されていない。おかしい。適当にvlanを手動で追加してみると以下のような画面が。

f:id:ninigishi:20190907122919p:plain

[o] src serverでnetboxのバージョン更新後に移行

@src host

docker-compose down
git clone -b master https://github.com/netbox-community/netbox-docker.git
docker-compose up -d

この後にデータ移行の処理をもう一度やるとdst serverで正常に稼働した。

src serverにnetbox-dockerを入れたのは数カ月前だったので、おそらくその間にnetboxがアップデートされてしまったことが原因。 netboxのバージョンが上がったからデータベースのカラムが変更されてしまった?

あまりこのエラーは起こらなそう。

[x] migrate.pyを実行

うまくいかなかった方法。

エラーメッセージの通りにmigrationを実行。

# docker-compose exec netbox /bin/bash

bash-5.0# python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, circuits, contenttypes, dcim, extras, ipam, secrets, sessions, taggit, tenancy, users, virtualization
Running migrations:
  Applying extras.0019_tag_taggeditem...Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 82, in _execute
    return self.cursor.execute(sql)
psycopg2.errors.DuplicateTable: relation "extras_tag" already exists


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 323, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 364, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 83, in wrapped
    res = handle_func(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/migrate.py", line 234, in handle
    fake_initial=fake_initial,
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/executor.py", line 117, in migrate
    state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/executor.py", line 245, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/migration.py", line 124, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "/usr/local/lib/python3.7/site-packages/django/db/migrations/operations/models.py", line 92, in database_forwards
    schema_editor.create_model(model)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/base/schema.py", line 307, in create_model
    self.execute(sql, params or None)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/base/schema.py", line 137, in execute
    cursor.execute(sql, params)
  File "/usr/local/lib/python3.7/site-packages/cacheops/transaction.py", line 99, in execute
    result = self._no_monkey.execute(self, sql, params)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.7/site-packages/django/db/utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 82, in _execute
    return self.cursor.execute(sql)
django.db.utils.ProgrammingError: relation "extras_tag" already exists

なんかうまくいかない。

[x] --fakeオプション付でmigrate.pyを実行

うまくいかなかった方法。

調べた結果--fakeオプションを付けて実行すると動くらしい。

# bash-5.0# python3 manage.py migrate --fake
Operations to perform:
  Apply all migrations: admin, auth, circuits, contenttypes, dcim, extras, ipam, secrets, sessions, taggit, tenancy, users, virtualization
Running migrations:
  Applying extras.0019_tag_taggeditem... FAKED
  Applying circuits.0015_custom_tag_models... FAKED
  Applying virtualization.0009_custom_tag_models... FAKED
  Applying tenancy.0006_custom_tag_models... FAKED
  Applying secrets.0006_custom_tag_models... FAKED
  Applying ipam.0025_custom_tag_models... FAKED
  Applying dcim.0070_custom_tag_models... FAKED
  Applying extras.0020_tag_data... FAKED
  Applying extras.0021_add_color_comments_changelog_to_tag... FAKED
  Applying dcim.0071_device_components_add_description... FAKED
  Applying dcim.0072_powerfeeds... FAKED
  Applying dcim.0073_interface_form_factor_to_type... FAKED
  Applying extras.0022_custom_links... FAKED
  Applying extras.0023_fix_tag_sequences... FAKED
  Applying extras.0024_scripts... FAKED
  Applying extras.0025_objectchange_time_index... FAKED
  Applying ipam.0026_prefix_ordering_vrf_nulls_first... FAKED
  Applying ipam.0027_ipaddress_add_dns_name... FAKED

上手く行った風だけど動かない…さっきと同じエラー画面が表示される。

github.com

よくわからない。

Install Zabbix 4.0 on Ubuntu 16.04

動機

研究室ネットワークのSNMP監視がしたい。

現状ではcactiが動いているがUIがイケてないし、cactiの勉強をしてアップデートするよりは新しいのを入れて勉強していきたい。   とりあえず自分のサーバにいれて動かしてみてよさそうだったら監視サーバに移行する。

環境

環境構築

MySQLのインストール

Zabbix 4.0ではMySQL8.0をサポートしているらしい。

現環境には既に使用されているMySQL 5.7が入っている。アップデートするのは面倒だし、8.0が必須ではなさそうなので8.0はパス。

Zabbix 4.0の環境構築

公式ドキュメントに従う。 www.zabbix.com

2つの選択肢がある。

  • dockerで
  • サーバにインストール

今回は勉強のためにもサーバにインストールすることにした。

dockerで入れるの簡単だけど、なんか味気ないしサーバにインストールしていく。次やる機会があったらdockerでやる。

実際に手を動かしてインストールした方が愛着がわく

リポジトリの追加

$ cd /tmp
# wget https://repo.zabbix.com/zabbix/4.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_4.0-3+xenial_all.deb
# dpkg -i zabbix-release_4.0-3+xenial_all.deb
# apt update

Zabbix 4.0のインストール

# apt -y install zabbix-server-mysql zabbix-frontend-php zabbix-agent

データベースの作成

$ mysql -u root -p
mysql> create database zabbix character set utf8 collate utf8_bin;
mysql> grant all privileges on zabbix.* to zabbix@localhost identified by 'password';
mysql> quit;

Zabbixが使うデータベースの設定。passwordは設定したいものに変更する。

初期データの投入

zcat /usr/share/doc/zabbix-server-mysql*/create.sql.gz | mysql -uzabbix -p zabbix

そこそこ時間がかかる。zcat は圧縮したファイルの中身を表示するためのコマンド。

参考

確認

$ mysql -uroot -p
mysql> use zabbix;
mysql > show tables;
+----------------------------+
| Tables_in_zabbix           |
+----------------------------+
| acknowledges               |
| actions                    |
| alerts                     |
| application_discovery      |
| application_prototype      |
| application_template       |
| applications               |

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

| usrgrp                     |
| valuemaps                  |
| widget                     |
| widget_field               |
+----------------------------+
144 rows in set (0.00 sec)

なにやらいろんなデータが投入されている。

MySQLとの接続設定

パスワードの情報をいれる

sudo vim /etc/zabbix/zabbix_server.conf

124行目付近にDBPassword=hogehogeを追記。hogehogeは先程設定したパスワード。

### Option: DBPassword
#   Database password.
#   Comment this line if no password is used.
#
# Mandatory: no
# Default:
DBPassword= hogehoge

Zabbix のフロントエンド用のPHPの設定

タイムゾーンを設定する必要がある。

sudo vim /etc/zabbix/apache.conf

20行目と30行目にそれぞれタイムゾーンの設定をする場所がある。入っているPHPのバージョンの部分だけを変えればよさそう。

# php_value date.timezone Europe/Riga

現環境にはPHP 7.3が入っていたので、 <IfModule mod_php7.c></IfModule> の方を変更

- # php_value date.timezone Europe/Riga
+ php_value date.timezone Asia/Tokyo

Rigaってどこだ

Zabbixの起動

# systemctl restart zabbix-server zabbix-agent apache2
# systemctl enable zabbix-server zabbix-agent apache2

enableでは起動時にZabbixを起動するように設定。

Start Zabbix server and agent processes and make it start at system boot:

Zabbixの設定

http://server_ip_or_name/zabbix にアクセス。

トップ画面はこう。[Next] を選択

f:id:ninigishi:20190906232309p:plain
Zabbixのトップ画面

自分の環境ではここで以下のような画面が出てエラーが起きたのでエラー&ワークアラウンドに書いた。

f:id:ninigishi:20190906232215p:plain
Zabbixフロントエンド設定

エラーが起きなければ適当に設定していく。設定した画面を張った。

f:id:ninigishi:20190906235730p:plain

f:id:ninigishi:20190907000138p:plain

f:id:ninigishi:20190907000248p:plain

Zabbixへのログイン

f:id:ninigishi:20190907000354p:plain

www.zabbix.com 初期ユーザ・パスワードなどはここに書いてある。グローバルで動かしていたので早急にパスワードを変更する。

f:id:ninigishi:20190907000734p:plain [Administrations] >> [Users] >> [Admin] の順にクリック、次の画面で[Change Password]をクリックして変更。

とりあえず、ここまでが導入だと思うので一旦終了。snmpの設定などはまた今度。

エラー & ワークアラウンド

エラー

なにやらエラーっぽいのが表示されている。何かが足りないらしい。

f:id:ninigishi:20190906232215p:plain
Zabbixフロントエンド設定

ワークアラウンド

PHP bcmath extension missing (PHP configuration parameter --enable-bcmath).
PHP gd extension missing (PHP configuration parameter --with-gd).
PHP gd PNG image support missing.
PHP gd JPEG image support missing.
PHP gd FreeType support missing.
PHP xmlwriter extension missing.
PHP xmlreader extension missing.
sudo apt install php-bcmath
php-bcmath is already the newest version (2:7.3+69+ubuntu16.04.1+deb.sury.org+2+php7.3).

??? よく見るとZabbixで認識しているPHPのバージョンとターミナルで php --version としたときのバージョンが違う。これが原因っぽい。

php7.1をアンインストール。

sudo apt purge php7.1-*
sudo systemctl restart apache2

...起動しなくなった。/etc/zabbix/appache.conf も何故か消えた。

今まで叩いたコマンドを振り返るとzabbix-frontend-php がそれっぽいのでこれをもう一回叩く。

sudo apt -y install zabbix-frontend-php

普通にインストールが始まったからpurgeしたときにこれも飛んでいったらしい。/etc/zabbix/apache.conf も復活した。

sudo vim /etc/zabbix/apache.conf
sudo systemctl restart apache2

なんかPHPソースコードが表示される。沼った。わけわからん。適当にググっていたら以下のサイトを見つけたので、その通りにやる。

gn000.sakura.ne.jp

ls /etc/apache2/mods-enabled/ | grep php

ない。リンクを貼る。

cd /etc/apache2/mods-enabled
sudo ln -s ../mods-available/php7.3.load ./
sudo ln -s ../mods-available/php7.3.conf ./

これで復旧した。