2016/03/29

將 CSV 檔案加上 UTF BOM 讓它可以在 Windows 被 EXCEL 正確的開啟沒有亂碼的問題


將 CSV 檔案加上 UTF BOM 讓它可以在 Windows 被 EXCEL 正確的開啟沒有亂碼的問題

在 UTF-8 文件中放置 BOM 主要是微軟系統的習慣。但是真的沒有必要帶拉!!!!

http://stackoverflow.com/questions/2223882/whats-different-between-utf-8-and-utf-8-without-bom
According to the Unicode standard, the BOM for UTF-8 files is not recommended:

圖片和內文不太相關



下面提供一種在 windows 上面,政治正確的解法。 XDXD

// ========================================================
// 產生現在的秒數
$time_string = date("YmdHis");

// 寫入 utf8 with BOM
function writeUTF8File($filename,$content)
{
    $f = fopen($filename, 'w');
    fwrite($f, pack("CCC", 0xef,0xbb,0xbf));
    fwrite($f,$content);
    fclose($f);
}

$f = 'uploads/private/'.$time_string.'.csv';
$fdir = 'uploads/private/';

// 檔案不存在就先建立檔案
if (!file_exists($fdir)) {
    mkdir($fdir);
}

writeUTF8File($f,$csv);

echo 'CSV 輸出完成,請點選連結下載。
';
// ========================================================

2016/03/28

取得 mysql 資料表中的「欄位名稱」以及「欄位註解」

取得 mysql 資料表中的「欄位名稱」以及「欄位註解」

在 MySQL 資料庫中,宣告資料表的過程,可以一併把欄位名稱寫在 COMMENT 選項中,如果在程式可以把這個 COMMENT 也抓出來配合欄位的名稱,可以產生自動把整個表 DUMP 出來成為一個 CSV 不就很方便。

圖片和內文不太相關


// -----------------------------------------------
$table='表格名稱';

// 資料庫中表的欄位抬頭資訊
$col_sql = "SELECT COLUMN_NAME,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '$table';";
$col = runSQL($col_sql);
// var_dump($col);

// 資料欄位
$sql = "SELECT * FROM `$table` WHERE 1;";
$row = runSQL($sql);
// var_dump($row);

$csv = '';

// 欄位名註解
//echo "

";
for($i=1;$i<$col[0];$i++){
//echo $col[$i]->COLUMN_COMMENT.", "; 
$csv = $csv.$col[$i]->COLUMN_COMMENT.", ";
}
$csv = $csv."\n";

// 欄位名稱
//echo "

";
for($i=1;$i<$col[0];$i++){
//echo $col[$i]->COLUMN_NAME.", "; 
$csv = $csv.$col[$i]->COLUMN_NAME.", ";
}
$csv = $csv."\n";

// 資料列取得欄位
//echo "

";
for($j=1;$j<$row[0];$j++){
for($i=1;$i<$col[0];$i++){
$k = $col[$i]->COLUMN_NAME;
//echo $row[$j]->$k.', ';
$csv = $csv.$row[$j]->$k.', ';
}
$csv = $csv."\n";
//echo "
";

}

//echo "

";
//echo " 共有 $i 欄  $j 列
";

$csv = $csv."\n 共有 $i 欄  $j 列 \n";

echo nl2br($csv);
// -----------------------------------------------

* 同時放在 github https://github.com/mtchang/ITCNotes/blob/master/mysql_get_tableinfo2csv
* runSQL() 函式請參考這一篇 http://blog.jangmt.com/2016/03/mysql-php-mysql-pdo.html

2016/03/27

mysql 中文亂碼的避免及 php mysql pdo 宣告取用方式

Mariadb 和 Mysql 都會有亂碼, 只要它預設編碼還是在 latin 的時還是一直會發生.

所以改成 utf8 編碼是一個對於東亞語系的文字,會比較方便。
UTF8 的介紹請看 wiki https://zh.wikipedia.org/wiki/UTF-8

xxx_bin (區分大小寫)
xxx_general_ci (不區分大小寫)

Collation 每個字符集的排序規則

http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html
在 mysql 資料庫中有兩個編碼系統 UCS2 及 UTF8
utf8 使用 1~3 bytes ,帶有 65536 個組合的編碼
utf32 與 utf8mb4 是完整的的 unicode ,差異在 utf32 固定 4 bytes ,而 utf8mb4 則是彈性使用 1~4 bytes 。
utf8mb4 從 MySQL 5.5.3 (released March 2010). 開始提供

目前預設的編碼系統為
xxx_general_ci (default)

為了中文語系使用不要出問題,建議修正如下:
-----------------------------------------------------
# 修正 mysql 的設定檔
[root@c7 my.cnf.d]# more /etc/my.cnf.d/my-huge.cnf 
[client]
default-character-set=utf8mb4

[code]
default-character-set=utf8mb4

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci

# restart mysql service


# 檢查系統的編碼變數
----------------------------
[root@c7 my.cnf.d]# mysql -u root -p
Enter password:
MariaDB [(none)]> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name            | Value              |
+--------------------------+--------------------+
| character_set_client     | utf8mb4            |
| character_set_connection | utf8mb4            |
| character_set_database   | utf8mb4            |
| character_set_filesystem | binary             |
| character_set_results    | utf8mb4            |
| character_set_server     | utf8mb4            |
| character_set_system     | utf8               |
| collation_connection     | utf8mb4_general_ci |
| collation_database       | utf8mb4_general_ci |
| collation_server         | utf8mb4_general_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)

character_set_filesystem 要維持 binary
character_set_system 是唯讀變數




# 配合 PHP 程式上我會宣告如下,寫用一個 function 來取用 mysql 。

// -----------------------------------------------------------------------------------------
// 請在根目錄下建立一個檔案 VERSION.txt 檔案內容放置 release or developer , 依據此變數自動判斷目前所在開發環境
$system_mode = file_get_contents("VERSION.txt");
//$system_mode = 'release';
//$system_mode = 'developer';
if($system_mode == 'developer') {
// sql DB infomation -- for developer
$dbhost ='localhost';
$dbname ='exampleDB';
$dbuser ='exampleUSER';
$dbpassword ='example';
}elseif($system_mode == 'release') {
// sql DB infomation -- for release
$dbhost ='localhost';
$dbname ='exampleDB';
$dbuser ='exampleUSER';
$dbpassword ='example';
}else{
// 沒有設定 STOP
die('System mode set error !!!');
}
// ----------------------------------------------------------------------
//
// 連接資料庫的的設定,預設將 set name utf8 開啟
//
try {
// 在 PDO 宣告的時候就要將編碼一併宣告。 ref.pdo-mysql.connection
global $dbh;
$dsn = "mysql:host=$dbhost;dbname=$dbname";
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4'); 
$dbh = new PDO($dsn, $dbuser, $dbpassword, $options);
} catch (PDOException $e) {
    print "DB connect Error!: " . $e->getMessage() . "
";

    die();
}

// ---------------------------------------------------------------------
// run SQL command then return $result
// $result[0] --> 資料數量, 如果為 0 表示沒有變動的列
// $result[1] ~ $result[n] --> 資料內容,從第一筆開始
// 使用方式 example:
// $result = runSQL($sql);
// var_dump($result);
// ---------------------------------------------------------------------
function runSQL($query)
{
global $dbh;
try {
$stmt = $dbh->prepare("$query");
$stmt->execute();
// 查詢到的數量, 放到此變數的 [0] 索引位置
$db_dump_result_all[0] = $stmt->rowCount();
$i=1;
// 以物件方式存變數物件取用以 $result->var 方式取用
while ($db_dump_result = $stmt->fetch(PDO::FETCH_OBJ))  {
$db_dump_result_all[$i] = $db_dump_result;
$i++;
}
} catch (PDOException $e) {
        return("DB connect Error!: $e->getMessage() , SQL: $query ");
        die();
}
return($db_dump_result_all);
}
// --------------------------------------------------------------------

以上放在 github 上https://github.com/mtchang/ITCNotes/blob/master/mysql_utf8mb4_pdo.txt


更多閱讀:
How to support full Unicode in MySQL databases https://mathiasbynens.be/notes/mysql-utf8mb4
utf8mb4 編碼使用的一些紀錄 https://twpug.net/discussion/8646/utf8mb4-%E7%B7%A8%E7%A2%BC%E4%BD%BF%E7%94%A8%E7%9A%84%E4%B8%80%E4%BA%9B%E7%B4%80%E9%8C%84
stackoverflow about utf8mb4  http://stackoverflow.com/tags/utf8mb4/info
維基百科 utf8 http://zh.wikipedia.org/wiki/UTF-8
解釋 mysql 的 Unicode Character Sets http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html




2016/03/23

PostgreSQL 9.4 in CentOS Linux 7 簡易安裝教學

PostgreSQL 9.4 in CentOS Linux 7

# 安裝下載
http://www.postgresql.org/download/linux/redhat/

# 安裝 REPO 來源檔
yum install http://yum.postgresql.org/9.4/redhat/rhel-6-x86_64/pgdg-redhat94-9.4-1.noarch.rpm -y

# 安裝主要資料庫程式
yum install postgresql94-server postgresql94-contrib -y
/usr/pgsql-9.4/bin/postgresql94-setup initdb
systemctl enable postgresql-9.4.service
systemctl start postgresql-9.4.service

# 裝好後所有的設定檔及紀錄檔都在 /var/lib/pgsql 這個目錄內
[root@c7 ~]# ls /var/lib/pgsql -la
total 8
drwx------.  3 postgres postgres   36 Mar 23 09:27 .
drwxr-xr-x. 70 root     root     4096 Mar 23 09:27 ..
drwx------.  4 postgres postgres   48 Mar 23 09:27 9.4
-rwx------.  1 postgres postgres  267 Mar 23 09:27 .bash_profile

# 確認帳號
[root@c7 ~]# id postgres
uid=26(postgres) gid=26(postgres) groups=26(postgres)

# 切換使用者,並且登入系統設定
[root@c7 ~]# su - postgres
-bash-4.2$ psql template1
psql (9.4.6)
Type "help" for help.

# 建立一個使用者為 mtchang 且將密碼修改為 1234 並且賦予 superuser 的權限。
template1=# CREATE USER mtchang WITH PASSWORD '1234';
CREATE ROLE
template1=# CREATE DATABASE mtchang OWNER mtchang ENCODING 'UTF8';
CREATE DATABASE
template1=# ALTER ROLE mtchang WITH superuser;
ALTER ROLE
template1=# \q
-bash-4.2$ exit
logout

# 登入測試
[root@c7 ~]# psql -h 127.0.0.1 -W -U mtchang
Password for user mtchang:
psql: FATAL:  Ident authentication failed for user "mtchang"

# 修正允許登入, 加入底下兩行
[root@c7 ~]# tail /var/lib/pgsql/9.4/data/pg_hba.conf  -n 15
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all         all         127.0.0.1/32          md5
host    all         all         192.168.1.0/24       md5

# 原來 Postgresql 的連線只開放本機 IP 可以存取,如果需要讓外面 IP 可以存取,需要打開預設的連線設定檔案
# data/postgresql.conf 將 listen_addresses = ‘localhost’ 修改為 listen_addresses = ‘*’ 結果如下:
[root@c7 ~]# cat /var/lib/pgsql/9.4/data/postgresql.conf | grep listen_address
listen_addresses = '*'

# 重新啟動 postgresql 服務
[root@c7 ~]# systemctl restart postgresql-9.4.service 

# 登入測試
[mtchang@c7 conf]$ psql -U mtchang -h 127.0.0.1 -W
Password for user mtchang:
psql (9.4.6)
Type "help" for help.

mtchang=# \l
                                  List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges  
-----------+----------+----------+-------------+-------------+-----------------------
 mtchang   | mtchang  | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
(4 rows)

mtchang=# \q

# postgresql 有很多管理工具,phppgadmin OR pgadmin3 都是很好的管理工具
#簡單介紹 pgadmin3 這個工具的使用

# postgresql 管理工具 pgadmin3 install
yum install pgadmin3


# pgadmin3設定畫面





# 連接後的畫面



# 更多資訊
psql 指令
-c 參數可以直接在命令列下 SQL 敘述句
-e 參數是將 SQL 的執行指令過程全部列出來

# postgresql 建立使用者的 SQL example
psql -h localhost -U postgres -W -e -c "CREATE USER jangmt WITH PASSWORD '密碼' ;"

# postgresql 建立資料庫的 SQL example
psql -h localhost -U postgres -W -e -c "CREATE DATABASE jangmtDB OWNER jangmt ENCODING 'UTF8';"

# postgresql 建立匯入資料庫的 SQL example
psql -h localhost -U jangmt -d jangmtdb -W -e -f sql.txt 

# postgresql pg_dump 可以將資料庫依需求匯出,以供備份或轉移系統使用。
pg_dump -f sql_dump.txt -h localhost -U jangmt -W jangmtdb

之前寫的舊版8.1安裝howto http://blog.jangmt.com/2011/04/rhelcentos-postgresql.html

PhpPgAdmin透過 web 介面來管理 postgresql 資料庫 http://phppgadmin.sourceforge.net/doku.php?id=faq_docs

2016/03/17

使用 SNMPD 的 TRAP(異常情況) 功能來觸發管理機制,以 UPS 不斷電系統的自動關機為範例


使用 SNMPD 的 TRAP(異常情況) 功能來觸發管理機制,以 UPS 不斷電系統的自動關機為範例

這篇文章主要說明,當你的 UPS 如果發現 AC(市電)斷電了,我該如何呼叫機器關機勒?
在各 UPS 的管理工具理,都有提供管理工具讓你設定在斷電後快快關閉電腦,但是如果一次要對大量的機器可能就需要付點費用,或是使用其他的方式達成。此文提供透過 UPS 的 SNMPTRAPD 在符合條件的 MIB 資訊被觸發時,就透過接收到的資訊傳遞給負責處理的程序。


介紹 SNMP 
------------
首先我們需要先了解何謂 SNMP 通訊協定,可以參考底下這篇文章
http://www.netadmin.com.tw/article_content.aspx?sn=1209100018


安裝軟體
------------
# Linux mint or ubuntu 的安裝
apt-get install snmp snmpd libsnmp-base libsnmp-dev snmp-mibs-downloader -y

# Linux CentOS 的安裝
yum install net-snmp net-snmp-agent-libs net-snmp-utils -y
systemctl enable snmptrapd.service 

在 /etc/snmp/snmptrapd.conf  可以看到預設的設定檔
這個設定可以在 'snmptrapd.conf(5)' 有詳細的說明如何設定 snmptrapd


設定 SNMPTRAPD 可以接收觸發的封包
------------------------------------
可以參考官方網站的說明
http://www.net-snmp.org/wiki/index.php/TUT:Configuring_snmptrapd

# -----------------
# 修改設定檔 /etc/snmp/snmptrapd.conf
# -----------------
# 這個是我參考官方網站後改寫的 /etc/snmp/snmptrapd.conf 範例
mint snmp # cat /etc/snmp/snmptrapd.conf
# 以 SNMP v2c 版本 , 通訊接收寫入的密碼是 public (很危險記得要改)
# SNMP v2c with community as public
authCommunity   log,execute,net public

# 底下這兩個 traphandle 是很常見的範例, 以 SNMPv2-MIB::coldStart 這個 MIB
# 來觸發後面的 command 動作 /etc/snmp/traps.sh cold
#traphandle SNMPv2-MIB::coldStart    /etc/snmp/traps.sh cold
#traphandle SNMPv2-MIB::warmStart    /etc/snmp/traps.sh warmStart

# 預設的觸發,可以在 traps.sh 產生的 traps.txt 看到紀錄
# 也可以從 /var/log/syslog(ubunut) or /var/log/message(centos) 看到紀錄
# traphandle default  /etc/snmp/traps.sh default

# 這個是 MEGATEC 測試後的 AC 斷電、復電的 MIB 值
# for UPSagent HDP801 (MEGATEC)
traphandle SNMPv2-SMI::mib-2.33.1.6.3.6     /etc/snmp/traps.sh HDP_AC_lost
traphandle SNMPv2-SMI::mib-2.33.1.6.3.2     /etc/snmp/traps.sh HDP_AC_restore
# 關於 MIB 會因為不同的 UPS 裝置送出的 MIB 值都不一樣,
# 實際請參考你的 UPS MIB 相對應的值
# 底下備註是不同 UPS 在實際斷電時, snmptrapd 接收到的 MIB LOG

# 寫一個 traps.sh 程式, 用來處理 snmptrapd 產生的 log 並且依據 log 產生對應的動作
mint snmp # cat /etc/snmp/traps.sh 
#!/bin/bash
# --------------------------------------------
# ref:http://www.net-snmp.org/wiki/index.php/TUT:Configuring_snmptrapd
# --------------------------------------------
logfile='/etc/snmp/traps.txt'

read host
read ip
vars=

while read oid val
do
  if [ "$vars" = "" ]
  then
    vars="$oid = $val"
  else
    vars="$vars, $oid = $val"
  fi
done

echo "trap: $1 $host $ip $vars" > $logfile

# ---------------------------------------------
# by mtchang 2016.3.17
# ---------------------------------------------
actionfile='/etc/snmp/action.txt'
ACstat=$(tail -n1 $logfile | cut -d: -f2 | cut -d" " -f2)

# log to debug 
echo "$ACstat $(whoami) $(date)"
echo "$ACstat $(whoami) $(date)" > $actionfile

if [[ "${ACstat}" == "HDP_AC_restore" ]]; then
    echo "shutdown -c 'Utility power has been restore'" >> $actionfile
    #echo "shutdown -c 'Utility power has been restore'" | bash
    #echo "ssh mtchang@192.168.1.181 'sudo /home/mtchang/cmd/snmptrapd_cancel_poweroff.sh'" | bash
    exit 0
elif [[ "${ACstat}" == "HDP_AC_lost" ]]; then
    echo "shutdown -h -P 3 'After 3 minutes will be Poweroff. The UPS is not on battery power'" >> $actionfile
    #echo "shutdown -h -P 3 'After 3 minutes will be Poweroff. The UPS is not on battery power'" | bash
    #echo "ssh mtchang@192.168.1.181 'sudo /home/mtchang/cmd/snmptrapd_poweroff.sh' &" | bash
    exit 0
else
    echo "ACstat=${ACstat},Nothing to do." >> $actionfile
    exit 1
fi

# 在 Linux ubuntu 上面的重新啟動
# 刪除 snmptrapd 及重新啟動, 因為沒有 script 所以連下三個指令,並看它是否工作
killall -e snmptrapd
snmptrapd 
netstat -antulp | grep snmp

# 在 Linux CentOS 上面的重新啟動
systemctl restart snmptrapd.service 
netstat -antulp | grep snmp


# 本機測試, 使用 snmptrap 產生模擬 snmptrap 封包, 測試觸發條件是否工作
mint snmp # pwd
/etc/snmp
mint snmp # snmptrap -d -v 2c -c public 127.0.0.1 "" SNMPv2-MIB::coldStart SNMPv2-MIB::coldStart s "test coldStart"

Sending 100 bytes to UDP: [127.0.0.1]:162->[0.0.0.0]:0
0000: 30 62 02 01  01 04 06 70  75 62 6C 69  63 A7 55 02    0b.....public.U.
0016: 04 62 25 BD  9A 02 01 00  02 01 00 30  47 30 0F 06    .b%........0G0..
0032: 08 2B 06 01  02 01 01 03  00 43 03 74  0B 62 30 17    .+.......C.t.b0.
0048: 06 0A 2B 06  01 06 03 01  01 04 01 00  06 09 2B 06    ..+...........+.
0064: 01 06 03 01  01 05 01 30  1B 06 09 2B  06 01 06 03    .......0...+....
0080: 01 01 05 01  04 0E 74 65  73 74 20 63  6F 6C 64 53    ......test coldS
0096: 74 61 72 74                                           tart

# 觸發的 log 檔紀錄
mint snmp # cat traps.txt 
trap: default localhost UDP: [127.0.0.1]:35655->[127.0.0.1]:162 SNMPv2-SMI::mib-2.1.3.0 = 0:21:07:30.90, SNMPv2-SMI::snmpModules.1.1.4.1.0 = SNMPv2-SMI::snmpModules.1.1.5.1, SNMPv2-SMI::snmpModules.1.1.5.1 = "test coldStart"

# 判斷後的 action 動作
mint snmp # cat action.txt
Thu Mar 17 10:48:00 CST 2016
Nothing to do.


# 上面的 log 也可以在系統的 /varlog/syslog (ubuntu) 看到, 在 centos 是 /var/log/message
mint snmp # tail /var/log/syslog -n 1
Mar 17 10:48:00 mint snmptrapd[14654]: localhost [UDP: [127.0.0.1]:35655->[127.0.0.1]:162]: Trap , SNMPv2-SMI::mib-2.1.3.0 = Timeticks: (7605090) 21:07:30.90, SNMPv2-SMI::snmpModules.1.1.4.1.0 = OID: SNMPv2-SMI::snmpModules.1.1.5.1, SNMPv2-SMI::snmpModules.1.1.5.1 = STRING: "test coldStart"


# 接下來從遠端機器送個封包,到這台機器. 測試看看遠端是否可以工作
[root@c7 ~]# snmptrap -v 2c -c public 192.168.1.181 "" SNMPv2-MIB::coldStart SNMPv2-MIB::coldStart s "test coldStart"

# 確認有收到, 但這太危險了. 所以要加強一下安全性
mint snmp # tail /var/log/syslog -n 1
Mar 17 10:51:20 mint snmptrapd[14654]: ip69168.cm.nsysu.edu.tw [UDP: [192.168.1.168]:36762->[192.168.1.181]:162]: Trap , SNMPv2-SMI::mib-2.1.3.0 = Timeticks: (607117) 1:41:11.17, SNMPv2-SMI::snmpModules.1.1.4.1.0 = OID: SNMPv2-SMI::snmpModules.1.1.5.1, SNMPv2-SMI::snmpModules.1.1.5.1 = STRING: "test coldStart"

# 還好他有支援 tcpwrapper 所以從 hosts.allow 設定一下限制可以收到封包的範圍
mint snmp # whereis snmptrapd
snmptrapd: /usr/sbin/snmptrapd /usr/share/man/man8/snmptrapd.8.gz
mint snmp # ldd /usr/sbin/snmptrapd  | grep libwrap
libwrap.so.0 => /lib/x86_64-linux-gnu/libwrap.so.0 (0x00007f14e6eca000)
mint snmp # tail -n 2 /etc/hosts.allow 
snmptrapd:192.168.1.181,192.168.1.168:allow
snmptrapd:ALL:deny


# 測試模擬 UPS agent HDP801 動作
# AC 斷電
snmptrap -v 2c -c public 192.168.1.181 "" SNMPv2-SMI::mib-2.33.1.6.3.6 SNMPv2-SMI::mib-2.33.1.6.3.6 s "The UPS is not on battery power"

# AC 復電
snmptrap -v 2c -c public 192.168.1.181 "" SNMPv2-SMI::mib-2.33.1.6.3.2 SNMPv2-SMI::mib-2.33.1.6.3.2 s "Utility power has been restore"

# 測試 MIB coldStart
snmptrap -d -v 2c -c public 192.168.1.181 "" SNMPv2-MIB::coldStart SNMPv2-MIB::coldStart s "test coldStart"

測試完成後就可以去 UPS 上面設定 snmptrap了



關於 Linux system 關機這件事
------------------
# 在 AC 斷電時,立即啟動關機程序。但是如果電又馬上來了,就會覺得 ooxx 。所以預設關機指令執行後三分鐘後才關電,但這時候如果電來了,就可以執行取消關機的工作。

# 本機三分鐘後關機
shutdown -h -P 3 'After 3 minutes will be Poweroff. The UPS is not on battery power'

# 本機取消關機
shutdown -c 'Utility power has been restore'

# 以上只是把本地端的電源關閉,無法關閉其他遠端的機器
# -----------------------------------------------------------------------------------------
# 如果要控制遠端的電腦來關機,你必須要有遠端的 root 權限。
# 並且透過 ssh key 認證來執行遠端的 script 來關機。
# 所以我把它寫成了關機的批次檔案,放在遠端的機器

# 本機取消關機
mint cmd # cat snmptrapd_cancel_poweroff.sh 
#!/bin/bash
shutdown -c 'Utility power has been restore'

# 本機三分鐘後關機
mint cmd # cat snmptrapd_poweroff.sh 
#!/bin/bash
shutdown -h -P 3 'After 3 minutes will be Poweroff. The UPS is not on battery power'

# 這裡的 test 帳號使一般使用者帳號,已經設定具有 sudo 權限,且不用密碼的 sudo 。
# 並且主機已經設定 ssh key 認證,可以遠端被登入。
# 測試遠端關機的動作
ssh mtchang@192.168.1.181 'sudo /home/mtchang/cmd/snmptrapd_poweroff.sh' &
# 測試遠端取消關機的動作
ssh mtchang@192.168.1.181 'sudo /home/mtchang/cmd/snmptrapd_cancel_poweroff.sh'


#=========================================
# 主文結束
#=========================================

MIB LOG 備註
--------------
# 型號: Phoenixtec USHA Smart II Card 在線式UPS 的 snmptrapd 觸發 LOG 紀錄
# ------------------------------------------------------------------------------------
# 使用該系統自訂的 MIB
# 行為:電源好像有問題
Mar 18 16:32:13 power snmptrapd[21992]: 2016-03-18 16:32:13 192.168.1.132 [UDP: [192.168.1.132]:161->[192.168.1.4]]:#012DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (61738343) 7 days, 3:29:43.43#011SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2468.1.2.1.2#011SNMPv2-SMI::enterprises.2468.1.2.1.2 = STRING: "Utility power not available"

# 行為:沒電,切換到電池供電模式
Mar 18 16:32:35 power snmptrapd[21992]: 2016-03-18 16:32:35 192.168.1.132 [UDP: [192.168.1.132]:161->[192.168.1.4]]:#012DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (61744393) 7 days, 3:30:43.93#011SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2468.1.2.1.2#011SNMPv2-SMI::enterprises.2468.1.2.1.1.2.4.0 = INTEGER: 80#011SNMPv2-SMI::enterprises.2468.1.2.1.1.2.5.0 = INTEGER: 121#011SNMPv2-SMI::enterprises.2468.1.2.1.1.2.2.0 = INTEGER: 61#011SNMPv2-SMI::enterprises.2468.1.2.1.2 = STRING: "The UPS has switched to battery backup power"

# 行為:UPS 沒有在電池供電模式了
Mar 18 16:32:55 power snmptrapd[21992]: 2016-03-18 16:32:55 192.168.1.132 [UDP: [192.168.1.132]:161->[192.168.1.4]]:#012DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (61744694) 7 days, 3:30:46.94#011SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2468.1.2.1.2#011SNMPv2-SMI::enterprises.2468.1.2.1.2 = STRING: "The UPS is not on battery power"

# 行為:原來是電來了
Mar 18 16:33:03 power snmptrapd[21992]: 2016-03-18 16:33:03 192.168.1.132 [UDP: [192.168.1.132]:161->[192.168.1.4]]:#012DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (61744748) 7 days, 3:30:47.48#011SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2468.1.2.1.2#011SNMPv2-SMI::enterprises.2468.1.2.1.2 = STRING: "Utility power has been restore"



# 型號:鼎堅 MegaTec Model: CX504 在線式
# ------------------------------------------------------------------------------------
# 使用該系統自訂的 MIB
# UPS 電池測試
Mar 11 15:46:22 c7 snmptrapd[6889]: 2016-03-11 15:46:22 192.168.1.132 [UDP: [192.168.1.132]:161->[192.168.1.168]:162]:#012DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (991179) 2:45:11.79#011SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2468.1.2.1.2#011SNMPv2-SMI::enterprises.2468.1.2.1.2 = STRING: "The testing is going on UPS"
# UPS 電池測試測試結束
Mar 11 15:46:32 c7 snmptrapd[6889]: 2016-03-11 15:46:32 192.168.1.132 [UDP: [192.168.1.132]:161->[192.168.1.168]:162]:#012DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (992101) 2:45:21.01#011SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2468.1.2.1.2#011SNMPv2-SMI::enterprises.2468.1.2.1.1.6.2.0 = INTEGER: 1#011SNMPv2-SMI::enterprises.2468.1.2.1.1.6.1.0 = INTEGER: 1#011SNMPv2-SMI::enterprises.2468.1.2.1.1.6.3.0 = INTEGER: 1#011SNMPv2-SMI::enterprises.2468.1.2.1.1.6.4.0 = INTEGER: 1457710859#011SNMPv2-SMI::enterprises.2468.1.2.1.1.6.5.0 = INTEGER: 1500#011SNMPv2-SMI::enterprises.2468.1.2.1.2 = STRING: "The testing of UPS is completed"

# AC 停電
#[root@c7 snmp]# cat traps.txt
#trap: HDP_AC_lost 192.168.1.132 UDP: [192.168.1.132]:162->[192.168.1.168]:162 DISMAN-EVENT-MIB::sysUpTimeInstance = 148:3:54:42.20, SNMPv2-MIB::snmpTrapOID.0 = SNMPv2-SMI::enterprises.935.0.5, SNMPv2-SMI::enterprises.935.0.5 = "UPS has switched to battery power."
# 顯示依據 shell script 的 action.txt 動作內容
#[root@c7 snmp]# cat action.txt
#HDP_AC_lost root Fri Mar 18 16:14:11 CST 2016
#shutdown -h -P 3 'After 3 minutes will be Poweroff. The UPS is not on battery power'


# AC 電來了
#[root@c7 snmp]# cat traps.txt
#trap: HDP_AC_restore 192.168.1.132 UDP: [192.168.1.132]:162->[192.168.1.168]:162 DISMAN-EVENT-MIB::sysUpTimeInstance = 148:3:55:28.20, SNMPv2-MIB::snmpTrapOID.0 = SNMPv2-SMI::enterprises.935.0.9, SNMPv2-SMI::enterprises.935.0.9 = "Utility power has been restored."
# 顯示依據 shell script 的 action.txt 動作內容
#[root@c7 snmp]# cat action.txt
#HDP_AC_restore root Fri Mar 18 16:14:58 CST 2016
#shutdown -c 'Utility power has been restore'


延伸閱讀
----------
UPS-MIB http://www.oidview.com/mibs/0/UPS-MIB.html
snmptrap 使用 http://www.net-snmp.org/wiki/index.php/TUT:snmptrap
snmptrapd 設定 http://www.net-snmp.org/wiki/index.php/TUT:Configuring_snmptrapd
man SNMPTRAP(1)
man snmptrapd.conf(5)