apcupsdをセットアップしたところ、COMMLOSTになる

APCUPSを遠隔から監視するため、apcupsdをセットアップしたところ、COMMLOSTエラーが出たため対応した時のメモ。

 

環境

  • Windows10 x64
  • apcupsd 3.14.12
  • PowerChuteインストール済

 

原因と対応

PowerChuteがすでにインストールされている環境にて、apcupsdをインストール・起動したためです。

PowerChuteがCOMポートを既に使用しており、apcupsdが同じCOMポートへアクセスしようとしてエラーとなっていました。

 
そのため、PowerChuteのエージェント(サービス名APC PBE Agent)を停止させた上で、apcupsdを起動したところ、問題なく動作しました。

 
PowerChuteとapcupsdは同時利用はダメですね。

ActiveDirectoryのSYSVOLのレプリケーションプロトコルをDFSRへ移行した

ActiveDirectoryのSYSVOLのレプリケーションプロトコルをDFSRへ移行した時のメモです。

SYSVOLについては以下が参考になります。

   
なお、作業は以下を参考に行います。

 

環境

移行前
  • Windows Server 2008R2
  • ドメイン機能レベルは2003
  • ActiveDiretory環境
  • ドメインコントローラは2台
    • 両方ともDFSRはセットアップしていない
    • 以下、プライマリドメインコントローラをPDC、セカンダリドメインコントローラをSDCと表記

 

移行後
  • Windows Server 2008R2
  • ドメイン機能レベルは2008
  • ActiveDiretory環境
  • ドメインコントローラは2台
    • PDCにDFSRをセットアップ

 

流れ

FRS から DFSR への移行 (SYSVOL) | Ask the Network & AD Support Teamにある、4) DFSR に安全に移行する為の手順に従って実施します。

 

PDCにて、現状の確認

SYSVOLのレプリケーションプロトコルとしてFRS・DFSRのどちらを使っているかは、Adsiedit.mscを実行し、スナップインから詳細を確認します。
Adsiedit: Active Directory

その結果、

  • CN=DFSR-GlobalSettings が存在しない
  • CN=File Replication Services は存在した

だったため、

ということが分かりました。

 

PDCにて、ドメインの機能レベルを2008以上に上げる

サーバーマネージャー > 役割 > Active Directory ドメイン サービス > Active Directory ユーザーとコンピューター > [対象ドメイン] で右クリック、ドメインの機能レベルの昇格を選択し、ドメインの機能レベルを2008以上にします。

 

PDCにて、ファイルサービスの役割サービスを追加

サーバーマネージャー > 役割 > ファイルサービス で右クリック、役割サービスの追加を選択します。

役割サービスの選択画面で、DFS 名前空間を選択し、追加します。

その後、Adsiedit.mscにて状態を確認すると、CN=DFSR-GlobalSettingsにデータが存在するようになりました。

 

移行作業
dfsrmig.exe /CreateGlobalObjects を実行
>dfsrmig.exe /CreateGlobalObjects

DFSR の現在のグローバル状態: '開始'
成功しました。

 
実行結果を確認します。

# 確認1
>dfsrmig.exe /GetGlobalState

DFSR の現在のグローバル状態: '開始'
成功しました。

# 確認2
>dfsrmig.exe /GetMigrationState

すべてのドメイン コントローラーがグローバル状態 ('開始') に移行しました。
移行状態が、すべてのドメイン コントローラー上で整合性のとれた状態になりました。
成功しました。

確認3:AD データベースの状態については、

  • ADSIエディターのルート(既存の名前付けコンテキスト)を右クリックし、最新の情報に更新
  • CN=Systemの下に、CN=DFSR-GlobalSettingsができている

と、確認が取れました。

 

dfsrmig.exe /SetGlobalState 1 を実行
>dfsrmig /SetGlobalState 1

DFSR の現在のグローバル状態: '開始'
新しい DFSR のグローバル状態: '準備完了'

'準備完了' 状態に移行します。DFSR サービスによってSYSVOL が SYSVOL_DFSR フォルダーにコピーされます。

いずれかの DC で移行を開始できない場合は、手動ポーリングを試行してください。
または、/CreateGlobalObjects オプションを指定して実行してください。
移行は 15 分から 1 時間までの任意の時点で開始できます。
成功しました。

 
実行結果を確認します。

# 確認1
>dfsrmig.exe /GetGlobalState

DFSR の現在のグローバル状態: '準備完了'
成功しました。

# 確認2
>dfsrmig.exe /GetMigrationState

次のドメイン コントローラーは、グローバル状態 ('準備完了') と同期していません:

ドメイン コントローラー (ローカル移行状態) - DC の種類
===================================================

Other_DC ('初期同期の待機中') - Writable DC

移行状態が、すべてのドメイン コントローラー上で整合性のとれた状態にまだなっていません。
AD の待ち時間が原因で状態の情報が最新になっていない可能性があります。

確認2が未完了でした。

そのため、イベントビューア > アプリケーションとサービスログ > DFS Replicationのログ にて、ID 80108014が出力されるのを待ったところ、

  • PDCでは、約5秒で完了
  • SDCでは、約5分ほどで完了

でした。

 
なお、ID 8014の出力後に、コマンドプロンプトにて確認したところ、

>dfsrmig.exe /GetMigrationState

すべてのドメイン コントローラーがグローバル状態 ('準備完了') に移行しました。
移行状態が、すべてのドメイン コントローラー上で整合性のとれた状態になりました。
成功しました。

完了していました。

 
また、PDCでは、

  • CN=System > CN=DFSR-GlobalSettings > CN=Domain System Volume > CN=Topologyの中に、各ドメインコントローラが存在
  • C:\Windows\SYSVOL_DFSRディレクトリが、プライマリドメインコントローラに存在

の確認も取れました。

 

dfsrmig.exe /SetGlobalState 2 を実行

ダウンタイムが発生するそうなので、使用中のユーザが少ない時間帯などに実行します。
リダイレクト済み状態への移行 - TechNet

>dfsrmig.exe /SetGlobalState 2

DFSR の現在のグローバル状態: '準備完了'
新しい DFSR のグローバル状態: 'リダイレクト済み'

'リダイレクト済み' 状態に移行します。SYSVOL 共有が、DFSR を使用してレプリケートされた SYSVOL_DFSRフォルダーに変更されます。

成功しました。

 
PDCにて結果を確認します。

>dfsrmig.exe /GetGlobalState

DFSR の現在のグローバル状態: 'リダイレクト済み'
成功しました。

グローバル状態は成功しているようです。

一方、

>dfsrmig.exe /GetMigrationState

次のドメイン コントローラーは、グローバル状態 ('リダイレクト済み') と同期していません:

ドメイン コントローラー (ローカル移行状態) - DC の種類
===================================================

<PDC名> ('準備完了') - Primary DC
<SDC名> ('準備完了') - Writable DC

移行状態が、すべてのドメイン コントローラー上で整合性のとれた状態にまだなっていません。
AD の待ち時間が原因で状態の情報が最新になっていない可能性があります。

他のDCへはまだ伝わっていないようです。

伝わるまでの時間を手元で計測したところ、イベントログにはID 80158017が1秒程度で出ていました。一方、dfsrmig.exe /GetMigrationStateにて

>dfsrmig.exe /GetMigrationState

すべてのドメイン コントローラーがグローバル状態 ('リダイレクト済み') に移行しました。
移行状態が、すべてのドメイン コントローラー上で整合性のとれた状態になりました。
成功しました。

と表示されるまでには、5分程度待ちました。

 
あとは、dfsrmig.exe /SetGlobalState 3を実行し、削除済にすれば完了です。

 

所要時間

参考程度となりますが、手元では

  • dfsrmig /SetGlobalState 1 は約5分
  • dfsrmig.exe /SetGlobalState 2 も約5分

でした。

ただ、dfsrmig.exe /SetGlobalState 2実行時に発生するダウンタイムについては、いつ発生していたのかは分かりませんでした。

 

その他参考

Python2 + Bottleで、XMLファイルそのものをレスポンスとして返す

Bottleでは、

@route("/xml")
def xml_response():
    response.content_type = 'xml/application'
    xml = '<?xml version="1.0" encoding="UTF-8"?><foo>Hello xml!</foo>'
    return xml

とすれば、XMLのレスポンスを返すことができます。
How to send xml/application format in bottle? - Stack Overflow

 
ただ、XMLファイルそのものをレスポンスとして返す方法で悩んだため、メモを残しておきます。

 

環境

  • Windows10 x64
  • Python 2.x
  • Bottle 0.12.9

 
なお、表示するXMLファイルは、

<?xml version="1.0" encoding="UTF-8"?>
<foo>Hello root dir xml!</foo>

のようなものとします。

 

XMLファイルの表示

CSSJavaScriptファイルと同様に、static_file()を使います。

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_DIR = os.path.join(BASE_DIR, "static")

@route("/root")
def xml_at_root():
    # ルート直下にxmlがある場合
    return static_file("root_dir.xml", root="")
    
@route("/static")
def xml_at_static_dir():
    # staticフォルダの下にxmlがある場合
    return static_file("static_dir.xml", root=os.path.join(STATIC_DIR, "xml"))

 
これで、ブラウザでアクセスした時に、上記のXMLファイルの内容が表示されます。

 

XMLファイルのダウンロード

XMLファイルを強制的にダウンロードしたい場合は、static_file()download引数を使います。

引数の値については、ソースコードのコメントにもありますが、

  • True : 元々のファイル名で、ダウンロード
  • 任意の値 : ファイル名を任意の値にして、ダウンロード

となります。
static_file() | bottle/bottle.py at 0.12.9 · bottlepy/bottle

@route("/download-original")
def download_xml():
    # 元ファイルの名前で、強制的にファイルをダウンロード
    return static_file("static_dir.xml", root=os.path.join(STATIC_DIR, "xml"), download=True)

@route("/download-rename")
def xml_dialog():
    # downloadに指定したファイル名で、強制的にファイルをダウンロード
    return static_file("static_dir.xml", root=os.path.join(STATIC_DIR, "xml"), download="rename.xml")

 

ソースコード

GitHubに上げました。
thinkAmi-sandbox/Bottle-sample: Bottle (python web framework) : sample codes

  • serve_xml.py
  • root_dir.xml
  • static/xml/static_dir.xml

が今回のファイルです。

 

参考

Python2 + Bottleで、別の端末からアクセスできるようにする

Bottleアプリを書いていた時に、

  • 自分の端末からはアクセス可能
  • LAN上の他の端末からはアクセス不可
  • ファイアウォールのポートは開いている

という状態になったので、調べた時のメモ。

 

環境

  • Windows10 x64
  • Python 2.x
  • Bottle 0.12.9

 

対応

run()の引数hostチュートリアルのまま(localhost)だったため、アクセスできませんでした。
python - How do I access bottle development server from another PC on the LAN? - Stack Overflow

 
hostの値ごとに調べてみると、

# hostデフォルト値は、127.0.0.1
# OK - localhost / 127.0.0.1 
# NG - 192.168.0.10 / hostname
# run(port=8080, debug=True, reloader=True)
# run(host="localhost", port=8080, debug=True, reloader=True)

# OK - 192.168.0.10 / hostname
# NG - localhost / 127.0.0.1
# run(host="192.168.0.10", port=8080, debug=True, reloader=True)
# run(host="<your hostname>", port=8080, debug=True, reloader=True)

# OK - ALL
run(host="0.0.0.0", port=8080, debug=True, reloader=True)

でした。

Bottle側で特に制限をかけたくなければ、host="0.0.0.0" で良さそうです。

 

参考

 

ソースコード

GitHubに上げました。lan_access.pyが今回のコードです。
thinkAmi-sandbox/Bottle-sample: Bottle (python web framework) : sample codes

Python2 + Bottleで、URL末尾のスラッシュの有無にかかわらず同じコンテンツを表示する

Bottleで、

  • /slash/
  • /slash

を同じURLと解釈してコンテンツを表示する際、

@route("/slash")
@route("/slash/")
def slash():
    return "Hello world!"

としていたのですが、他に良い方法がないかを調べた時のメモです。

 

環境

  • Windows10 x64
  • Python 2.x
  • Bottle 0.12.9

 

対応

Bottleの公式ドキュメントのレシピに記載がありました。before_requestフックを使うようです。
Recipes — Bottle 0.13-dev documentation

 
そのため、

@hook("before_request")
def strip_path():
    request.environ["PATH_INFO"] = request.environ["PATH_INFO"].rstrip("/")

@route("/slash")
def slash():
    return "Hello world!"

としたところ、/slash/であっても、Hello world!が表示されました。

 

Bottleのフックについて

Bottleのフックはどんなものがあるんだろうと思って調べたところ、公式ドキュメントに

  • before_request
  • after_request
  • app_reset

の3つのフックの記載がありました。
API Reference — Bottle 0.13-dev documentation

 

ソースコード

GitHubに上げました。trailing_slash.pyが今回のソースコードです。
thinkAmi-sandbox/Bottle-sample: Bottle (python web framework) : sample codes

Google I/O報告会 2016 in 信州に参加しました #io16jp #GDG信州

6/19に開催されたGoogle I/O報告会 2016 in 信州に参加しました。昨年は参加できなかったので、2年ぶりの参加です*1

 
会場は塩尻市塩尻インキュベーションプラザ(SIP)でした。いつもお世話になり、ありがとうございます。
塩尻インキュベーションプラザ

 
当日の様子はTogetterにまとめられています。
Google I/O Extended 報告会 Shinshu & Shikoku 2016 #io16jp #io16extended #gdgshikoku #gdg信州 - Togetterまとめ

 

内容

以前とは異なり、今回は同時開催のGDG四国とハングアウトで繋ぐという形でした。

四国会場は神山バレー・サテライトオフィス・コンプレックス。名前は知っていたのですが、道中や会場の外の様子がツイートで流れてきて、良さそうな雰囲気でした。
神山バレー・サテライトオフィス・コンプレックス

 
信州会場にはGoogle Developer Expert(GDE)の足立さん・矢倉さんにお越しいただきました。いつもながら、信州で凄い方からお話を聞けるのはありがたいです。

 
今の自分に直接関係するものは少なかったのですが、最近流行しているキーワードとその内容を知ることができてよかったです。

歴史的経緯や背景、国際的な状況などがセッション中の説明に含まれていたことから、その分野に詳しくない自分でも理解が進みやすかったので良かったです。

気になったキーワードとしては、

  • Freeform
  • Instant App
  • Espresso Test Recorder
  • Firebase
  • Progressive Web Apps (PWA)
  • Lighthouse

などがあり、後で調べてみようと思いました。

 
GDG四国との中継が終わった後は、GDG信州の小林さんによるセッション・GCPUG信州 キックオフ勉強会(7/23(土)、岡谷市のイルフプラザ)のお知らせもありました。

 
その後、GDEの足立さん・矢倉さん・古籏さんによるパネルディスカッションがありました。本編と異なり、ゆるい感じの質問と回答でGDEの方々が身近に感じられてとても良かったです。

 
他に、今年もガジェット展示会がありました。Apple IIヘブライ語のキーボード、なぜかそろばんなど、見ていて楽しい展示でした。レトロな表示も良かったです。

 

懇親会

今年も場所そのままで立食形式の懇親会がありました。過去に車で参加して飲めなかった、塩尻産のワインをいただきました。

懇親会では、勉強会で知り合った方とお話したり、実装で悩んでいるところを相談できたりと、楽しく過ごしました。ギークラボ長野Python勉強会にもいつか行こうと思いました。

また、ノベルティ大抽選会ではGoogle IO Extended Tシャツやノベルティセットをいただきました。ありがとうございました。

 
最後になりましたが、Google I/O報告会 2016 in 信州を開催・運営をされたみなさま、参加されたみなさま、本当にありがとうございました。

*1:6/19当日は、去年も参加してたと勘違いしてました...

Python2 + Bottleで、404ページを強制的に表示する

Bottleで404ページを強制的に表示したくて調べた時のメモです。

 

環境

  • Windows10 x64
  • Python 2.x
  • Bottle 0.12.9

 

調べたこと

どうやって実装するのが良いのか調べたところ、stackoverflowでabort()を使っている回答がありました。
python - Bottle.py error routing - Stack Overflow

回答では500ページでしたが、404ページでも使えそうでした。

 
ただ、公式ドキュメントのAPIリファレンスでabort()に関する情報がなかったため、ソースコードを読んだところ、例外HTTPErrorを発生させるためのショートカットでした。
bottle/bottle.py at 0.12.9 · bottlepy/bottle

次に、HTTPErrorを見ると、ステータスコードのデフォルトは500でしたが、引数として任意の値を渡せそうなため、404でもいけそうでした。
bottle/bottle.py at 0.12.9 · bottlepy/bottle

 
一方、Bottleのエラーをハンドリングする方法については、公式ドキュメントに記載がありました。

 

実装

force404.py

# -*- coding:utf-8 -*-
from bottle import route, run, abort, error

@route("/")
def top():
    abort(404, "go to 404")
    return "Hello world!"

@error(404)
def error404(error):
    return "Not Found!"

run(host="0.0.0.0", port=8080, debug=True, reloader=True)

と書いてpython force404.pyと実行し、ブラウザでアクセスしたところ、Not Found!が表示されました。

 

ソースコード

GitHubに上げました。リポジトリforce404.pyが今回のファイルです。
thinkAmi-sandbox/Bottle-sample: Bottle (python web framework) : sample codes