Python for the Oracle DBA on Mac OS X Lion (1)

作为一个技术人员,不学习一门编程语言,人生是不完整的。
是Shell是Perl还是Python,哪个简单哪个好用,哪个更适合Oracle DBA,这不是本文的范围,俗话说,萝卜青菜,各有所爱。

Mac OS X中自带Python(实际上也自带Shell和Perl),在Lion之后,由于64bit Oracle客户端无法在Mac中正常运行,导致一系列的麻烦。在Python中连接Oracle数据库,通常是使用cx_Oracle扩展模块。如果是Windows或者CentOS/Redhat/OEL Linux可以直接在cx-oracle.sourceforge.net下载相应的安装文件,但是对于Mac而言,却必须下载源码,自行编译。需要解决64bit问题和Oracle Instant Client配置问题。

文本大部分内容参考Andy Chan的Tutorial: How to Install Python Oracle Module “cx_Oracle” on Mac OS X Lion

在作一切操作之前,请先确认已经安装了XCode,并且安装了Command Line Tools,否则会在最后编译安装cx_Oracle的时候报错:unable to execute llvm-gcc-4.2: No such file or directory

1. 安装Oracle Instant Client,由于众所周知的64bit客户端在Mac OS X Lion中回发生“Segmentation fault: 11”的错误,因此必须下载32bit版本。
编译cx_Oracle需要下载如下图的两个安装文件,不过实际上我是除了Basic Lite之外都下载安装了。具体安装步骤及其它设置可以参看之前我的文章:How to use Oracle Instant Client in Mac OS X Lion

2. Oracle Instant Client的安装实际上就是解压,然后将生成的目录放在$PATH环境变量中,我将解压后的目录放在:/Applications/Utilities/instantclient,目录中的内容如下:

bogon:instantclient Kamus$ ls -l
total 204152
-rw-r--r--@  1 Kamus  staff       278 Apr  1  2009 BASIC_README
-rw-r--r--@  1 Kamus  staff       276 Apr  1  2009 JDBC_README
-rw-r--r--@  1 Kamus  staff       282 Apr  1  2009 SQLPLUS_README
drwxr-xr-x   3 Kamus  admin       102 Aug  9  2011 bin
-rw-r--r--@  1 Kamus  staff   1609607 Feb  2  2008 classes12.jar
-rwxr-xr-x@  1 Kamus  staff     30556 Apr  1  2009 genezi
-rwxr-xr-x@  1 Kamus  staff      1555 Aug  9  2011 glogin.sql
drwxr-xr-x  13 Kamus  admin       442 Jul 22 01:38 lib
lrwxr-xr-x   1 Kamus  admin        20 Jul 22 01:38 libclntsh.dylib -> libclntsh.dylib.10.1
-rwxr-xr-x@  1 Kamus  staff  21537536 Mar 31  2009 libclntsh.dylib.10.1
-rwxr-xr-x@  1 Kamus  staff     31788 Mar 25  2009 libheteroxa10.dylib
-rwxr-xr-x@  1 Kamus  staff     31788 Mar 25  2009 libheteroxa10.jnilib
-rwxr-xr-x@  1 Kamus  staff   1683924 Feb 11  2009 libnnz10.dylib
-rwxr-xr-x@  1 Kamus  staff   1142284 Feb 11  2009 libocci.dylib.10.1
-rwxr-xr-x@  1 Kamus  staff  72626824 Apr  1  2009 libociei.dylib
-rwxr-xr-x@  1 Kamus  staff    106184 Mar 25  2009 libocijdbc10.dylib
-rwxr-xr-x@  1 Kamus  staff    106184 Mar 25  2009 libocijdbc10.jnilib
-rwxr-xr-x@  1 Kamus  staff    933744 Mar 25  2009 libsqlplus.dylib
-rwxr-xr-x@  1 Kamus  staff   1442316 Feb 11  2009 libsqlplusic.dylib
drwxr-xr-x   3 Kamus  admin       102 Jul 30  2011 network
-rw-r--r--@  1 Kamus  staff   1555682 Feb  2  2008 ojdbc14.jar
-rw-r--r--@  1 Kamus  staff   1646178 Jan 23  2008 orai18n.jar
drwxr-xr-x@  7 Kamus  admin       238 Apr  1  2009 sdk
drwxr-xr-x   3 Kamus  admin       102 Aug  9  2011 sqlplus

其中需要注意的是:
1) libclntsh.dylib是需要手工创建的链接。

ln -s libclntsh.dylib.10.1 libclntsh.dylib

2) lib目录,在默认解压以后,没有该目录,需要手工创建,然后将所有lib*复制到该目录中。否则在安装cx_Oracle的时候会报错:无法找到正确的ORACLE_HOME。我的lib目录中文件列表如下:

bogon:instantclient Kamus$ ls -l lib
total 194656
lrwxr-xr-x  1 Kamus  admin        20 Jul 22 01:38 libclntsh.dylib -> libclntsh.dylib.10.1
-rwxr-xr-x@ 1 Kamus  admin  21537536 Jul 22 01:36 libclntsh.dylib.10.1
-rwxr-xr-x@ 1 Kamus  admin     31788 Jul 22 01:36 libheteroxa10.dylib
-rwxr-xr-x@ 1 Kamus  admin     31788 Jul 22 01:36 libheteroxa10.jnilib
-rwxr-xr-x@ 1 Kamus  admin   1683924 Jul 22 01:36 libnnz10.dylib
-rwxr-xr-x@ 1 Kamus  admin   1142284 Jul 22 01:36 libocci.dylib.10.1
-rwxr-xr-x@ 1 Kamus  admin  72626824 Jul 22 01:36 libociei.dylib
-rwxr-xr-x@ 1 Kamus  admin    106184 Jul 22 01:36 libocijdbc10.dylib
-rwxr-xr-x@ 1 Kamus  admin    106184 Jul 22 01:36 libocijdbc10.jnilib
-rwxr-xr-x@ 1 Kamus  admin    933744 Jul 22 01:36 libsqlplus.dylib
-rwxr-xr-x@ 1 Kamus  admin   1442316 Jul 22 01:36 libsqlplusic.dylib

3. 修改环境变量,将以下行添加到~/.bash_profile文件中。

export ORACLE_HOME=/Applications/Utilities/instantclient
export LD_LIBRARY_PATH=$ORACLE_HOME
export DYLD_LIBRARY_PATH=$ORACLE_HOME
export SQLPATH=$ORACLE_HOME
export PATH=$PATH:$ORACLE_HOME/bin
#for cx_Oracle,这是必须的,强制Python使用32位版本
export VERSIONER_PYTHON_PREFER_32_BIT=yes 

4. 启动新的Terminal窗口,先安装pip,pip是Python的包管理软件,使用pip可以方便地从网络上直接安装需要的Python模块。

sudo easy_install pip

5. 安装cx_Oracle

sudo pip install cx_Oracle

安装过程中产生的类似如下这些警告,可以忽略:

/Applications/Utilities/instantclient/sdk/include/nzt.h:2746: warning: function declaration isn’t a prototype
......
Connection.c:283: warning: implicit conversion shortens 64-bit value into a 32-bit value
......

最终显示如下信息表示安装成功:

Successfully installed cx-Oracle

6. 最后测试一下cx_Oracle是否工作正常。具体语法参看:cx_Oracle 5.1.2 documentation

bogon:~ Kamus$ python
Python 2.7.1 (r271:86832, Aug  5 2011, 03:30:24) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from cx_Oracle import connect
>>> conn=connect('kamus/oracle@www.enmotech.com:1521/orcl')
>>> curs = conn.cursor()
>>> curs.execute("select * from v$version")
<__builtin__.OracleCursor on >
>>> rows = curs.fetchall()
##以下报错是Python语法对于强制代码缩进的体现,如果for循环中的语句开头没有缩进,则会报错。
>>> for i in range(len(rows)):
... print rows[i][0]
  File "", line 2
    print rows[i][0]
        ^
IndentationError: expected an indented block 
##在print前增加两个空格即可
>>> for i in range(len(rows)):
...   print rows[i][0]
... 
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE	11.2.0.3.0	Production
TNS for Solaris: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production

How to resolve setlocale warning in OEL6

默认安装的Oracle Enterprise Linux 6,在用户登录以后,通常会有以下警告:

Last login: Tue Jun 19 16:52:19 2012 from 192.168.2.1
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8)

并且在执行oerr等命令的时候,也会先产生警告,比如:

$ oerr ora 10046
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
	LANGUAGE = (unset),
	LC_ALL = (unset),
	LC_CTYPE = "UTF-8",
	LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
10046, 00000, "enable SQL statement timing"
// *Cause:
// *Action:

其实也并不太影响使用,但是比较烦躁。

解决方法:

vi /etc/sysconfig/i18n

默认的内容可能是:

LANG="en_US.UTF-8"
SYSFONT="latarcyrheb-sun16"

需要添加一行LC_ALL的设置,如下:

LANG="en_US.UTF-8"
LC_ALL="en_US.UTF-8"
SYSFONT="latarcyrheb-sun16"

再重新登录,就一切OK了。

备注:为什么会有i18n这样古怪名字的配置文件,实际上i18n是internationalization的所写,表示从i到n之间有18个字母。

How to use iperf to test network bandwith

测试Linux机器之间的网络互联带宽,有一个很简单的工具,iperf

下载的是源码,编译过程如下:

./configure
make
make install

安装完毕以后,iperf的路径:

# which iperf
/usr/local/bin/iperf

然后在需要测试的两台Linux机器上,一台启动服务器模式。

# iperf -s
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------

另外一台启动客户端模式,其中IP地址为启动服务器模式的机器的IP,稍等片刻,即可出现测试结果。

# iperf -c 192.168.0.19
------------------------------------------------------------
Client connecting to 192.168.0.19, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[  3] local 192.168.0.18 port 16265 connected with 192.168.0.19 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec   114 MBytes  95.5 Mbits/sec

同时,启动服务器模式的机器上也会显示:

[  4] local 192.168.0.19 port 5001 connected with 192.168.0.18 port 16265
[ ID] Interval       Transfer     Bandwidth
[  4]  0.0-10.1 sec   114 MBytes  94.9 Mbits/sec

可知,这两台机器之间的互联带宽仅仅达到百兆网的速度。

How to Install apk to Android Devices from Mac OS X

在Mac OS X中我们可以使用Android SDK直接将下载到电脑中的apk文件安装到Android设备中。

1. 下载Android SDK,可以从Android Developers网站直接下载,也可以通过MacPorts安装。我采取后一种方式。

$ sudo port install android
Password:
--->  Fetching archive for android
--->  Attempting to fetch android-16_0.darwin_11.x86_64.tbz2 from http://packages.macports.org/android
--->  Fetching android
--->  Attempting to fetch android-sdk_r16-macosx.zip from http://dl.google.com/android
--->  Attempting to fetch android-appbundles-r89422.tar.gz from http://distfiles.macports.org/android
--->  Verifying checksum(s) for android
--->  Extracting android
--->  Configuring android
--->  Building android
--->  Staging android into destroot
--->  Installing android @16_0
--->  Activating android @16_0
--->  Cleaning android

然后通过port contents命令可以获知Android SDK的安装路径。在我的机器上是/opt/local/share/java/android-sdk-mac_x86。

$ port contents android
Port android contains:
  /Applications/MacPorts/Developer/.localized
  ......
  /opt/local/share/java/android-sdk-mac_x86/tools/adb_has_moved.txt
  /opt/local/share/java/android-sdk-mac_x86/tools/android
  ......

默认安装的Android SDK是没有adb命令(该命令用于安装apk程序)的,需要运行Android SDK and AVD Manager来进行额外的下载安装。

2. 安装SDK Platform-tools

cd /opt/local/share/java/android-sdk-mac_x86/tools
sudo ./android

会显示以下界面,在第一次运行的时候,Android SDK Platform-tools的状态是未安装的,因此我们需要选中该组件,然后点击右下方的“Install packages”按钮。而此处的截图是安装完毕以后的情况。

3. 安装apk软件,当然,这里先要用数据线将Android设备连接到Mac电脑上。

##adb命令是安装到platform-tools目录中,而非上一步android命令所在的tools目录。
$ cd /opt/local/share/java/android-sdk-mac_x86/platform-tools
##先探测是否可以正确识别设备,有设备号和device字样表示正确识别。
$ ./adb devices
List of devices attached 
01839c14	device
##安装apk软件,本例中安装的是高德移动导航
$ ./adb install /tmp/Autonavi_v1.2.apk
3225 KB/s (4027409 bytes in 1.219s)
	pkg: /data/local/tmp/Autonavi_v1.2.apk
Success

How to Use Port in Mac OS X to Install New Utilities

假设我们想要在Mac OS X中安装:
MySQL,这是一个开源的免费的数据库,当然备Oracle收购之后有一些变化。
postgreSQL,这又是另外一个开源的免费的数据库。
perl,这是一种流行的编程语言。
lua,这又是另外一种流行的编程语言。
watch,这是一个实用程序,可以默认每隔2秒重复执行某条命令,比如你想监控一个目录下的文件生成情况,这条命令就很有用。
tree,这是一个实用程序,可以提供类似于ls -R的功能,但是输出是更加直观的树状结构。

当然,我们可以在网络中一个一个地找这些程序,然后一个一个地安装,用不同的安装方法,但是,你也可以选择非常简单的方法,这就是本文要介绍的MacPorts。

在Linux中如果我们要安装一些软件,要解决各个软件之间的包依赖性关系,我们会使用到apt-get(Ubuntu)或者yum(Redhat,CentOS)或者zypper(openSUSE),如果你熟悉一些Linux的话,对于这些软件包管理程序应该有所耳闻。而MacPorts正是在Mac OS X上的软件包管理程序。

安装MacPorts最简单的方法是直接下载dmg文件,双击安装 - Lion版安装文件 | Snow Leopard版安装文件

MacPorts安装完以后,我们就可以通过命令行的方式来安装其它软件了,可以参看具体命令文档。以下列出常用的命令:

1. 更新本地软件库列表,该命令可以不定时多次执行(sudo以后需要输入密码,输入你自己用户的密码即可)。

sudo port selfupdate

2. 列出软件库中有哪些软件,注意,该命令会输出大量软件名称,因此建议添加more来查看,或者使用后面的search命令。

port list | more

3. 检索需要安装的软件。

port search 

当然,还有更精确地搜索,比如如果直接port search tree会出现上百个结果,但是如果执行以下命令,就只会出现一个结果。

$ port search --name --exact tree
tree @1.6.0 (sysutils)
    display tree-view of directories with optional color/HTML output

4. 列出已经通过port安装的软件。

port installed

5. 安装软件,一些具有依赖性的软件会连带自动安装,比如安装LUA,会安装ncurses和readline。

sudo port install 

6. 卸载软件。

sudo port uninstall 

7. 清理未成功安装的软件,比如一些软件由于编译问题或者其它原因没有安装成功。

sudo port clean --all 

8. 查看安装的软件都安装了哪些内容。

port contents 

比如查看tree都安装了哪些内容。

$ port contents tree
Port tree contains:
  /opt/local/bin/tree
  /opt/local/share/doc/tree/CHANGES
  /opt/local/share/doc/tree/LICENSE
  /opt/local/share/doc/tree/README
  /opt/local/share/man/man1/tree.1.gz

9. 升级当前安装过的软件。

sudo port upgrade 

升级全部有新版本的软件。升级以后将会保留以前的旧版本,只是将旧版本设置为Inactive。

sudo port upgrade outdated

当确认新版本软件工作正常以后,可以通过以下命令删除所有旧版本软件。

sudo port uninstall inactive

或者通过以下命令,删除指定的旧版本软件。

sudo port uninstall makedepend @1.0.2_0

如果想在升级的时候就直接删除旧版本软件,可以在upgrade时使用-u参数。

sudo port -u upgrade 

10. Troubleshooting
由于MacPorts与Xcode联系紧密,因此如果在升级完操作系统(比如从10.8升级到10.9),可能之前运行正常的MacPorts就无法使用了,比如出现以下报错。

localhost:~ Kamus$ sudo port selfupdate

WARNING: Improper use of the sudo command could lead to data loss
or the deletion of important system files. Please double-check your
typing when using sudo. Type "man sudo" for more information.

To proceed, enter your password, or type Ctrl-C to abort.

Password:
--->  Updating MacPorts base sources using rsync
MacPorts base version 2.1.2 installed,
MacPorts base version 2.2.1 downloaded.
--->  Updating the ports tree
--->  MacPorts base is outdated, installing new version 2.2.1
Installing new MacPorts release in /opt/local as root:admin; permissions 0755; Tcl-Package in /Library/Tcl

Error: /opt/local/bin/port: port selfupdate failed: Error installing new MacPorts base: command execution failed
localhost:~ Kamus$ sudo port selfupdate
--->  Updating MacPorts base sources using rsync
MacPorts base version 2.1.2 installed,
MacPorts base version 2.2.1 downloaded.
--->  Updating the ports tree
--->  MacPorts base is outdated, installing new version 2.2.1
Installing new MacPorts release in /opt/local as root:admin; permissions 0755; Tcl-Package in /Library/Tcl

Error: /opt/local/bin/port: port selfupdate failed: Error installing new MacPorts base: command execution failed

解决方法是将Xcode的Command Line Tools再安装一遍,通过以下方法。

$ sudo xcode-select --install

然后再运行port命令就功能正常了。

localhost:~ Kamus$ sudo port selfupdate
--->  Updating MacPorts base sources using rsync
MacPorts base version 2.1.2 installed,
MacPorts base version 2.2.1 downloaded.
--->  Updating the ports tree
--->  MacPorts base is outdated, installing new version 2.2.1
Installing new MacPorts release in /opt/local as root:admin; permissions 0755; Tcl-Package in /Library/Tcl


The ports tree has been updated. To upgrade your installed ports, you should run
  port upgrade outdated

Oracle Datafiles & Block Device & Parted & Udev

需求:
1. 使用裸设备作为Oracle数据文件,而且要跳过操作系统或者其它软件提供的卷管理(比如Linux下的LVM)。
2. 由于small datafile限制,有大量磁盘分区需要创建。

以下测试环境操作系统为CentOS 6.0,如果你的操作是RHEL6或者OEL6,也同样适用,如果是RHEL5或者OEL5,那么udev部分的命令是不相同的。但是只需要在操作系统中man udev,查看一下相应的语法即可,思路是相同的。

解决方案:
1. 使用parted命令,脚本式创建多个分区,使用gpt类型分区表,这样可以创建大量primary分区,而如果使用msdos分区,则必须要要创建extend分区,然后再创建logical分区,这样在后面的udev规则文件中,还需要将extend分区排除出去,比较麻烦。

在我的测试环境中,对于/dev/sdc磁盘进行操作,分了11个分区,每个50M。

parted -s /dev/sdc mklabel gpt 
parted -s /dev/sdc unit MB mkpart primary 1 50 
parted -s /dev/sdc unit MB mkpart primary 50 100 
parted -s /dev/sdc unit MB mkpart primary 100 150 
parted -s /dev/sdc unit MB mkpart primary 150 200 
parted -s /dev/sdc unit MB mkpart primary 250 300 
parted -s /dev/sdc unit MB mkpart primary 300 350 
parted -s /dev/sdc unit MB mkpart primary 350 400 
parted -s /dev/sdc unit MB mkpart primary 400 450 
parted -s /dev/sdc unit MB mkpart primary 450 500 
parted -s /dev/sdc unit MB mkpart primary 500 550 
parted -s /dev/sdc unit MB mkpart primary 550 600

如果在生产环境的Oracle数据库中,block_size=2K的表空间,单个数据文件最大8G,可以使用:

parted -s /dev/sdc unit GB mkpart primary 1 8 

2. 设置udev规则。如何在CentOS 6中设置udev,可以参看我之前的文章 - How to use udev for Oracle ASM in Oracle Linux 6

vi /etc/udev/rules.d/99-oracle.rules

添加如下行:

KERNEL=="sd?[1-9]", SUBSYSTEM=="block", PROGRAM=="/sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/$name", RESULT=="36000c293bd690056ce6834434765d3f4", NAME="oradisk0$number", SYMLINK="mapper/$name", OWNER="oracle",  GROUP="dba", MODE="0660"
KERNEL=="sd?1[0-9]", SUBSYSTEM=="block", PROGRAM=="/sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/$name", RESULT=="36000c293bd690056ce6834434765d3f4", NAME="oradisk$number", SYMLINK="mapper/$name", OWNER="oracle",  GROUP="dba", MODE="0660"

重启udev服务:

start_udev

然后可以发现/dev/mapper下的链接都成功创建,并且指向规则中定义的块设备名称。

# ls -l /dev/mapper/
total 0
crw-rw----. 1 root root 10, 58 Dec 29 03:29 control
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk01 -> ../oradisk01
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk02 -> ../oradisk02
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk03 -> ../oradisk03
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk04 -> ../oradisk04
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk05 -> ../oradisk05
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk06 -> ../oradisk06
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk07 -> ../oradisk07
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk08 -> ../oradisk08
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk09 -> ../oradisk09
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk10 -> ../oradisk10
lrwxrwxrwx. 1 root root     12 Dec 29 03:29 oradisk11 -> ../oradisk11

注意,此时/dev目录下,sdc1至sdc11设备都不再存在了,但是我们可以通过比较设备的major号和minor号来确认绑定是正确的。

# ls -l /dev/mapper/oradisk01
lrwxrwxrwx. 1 root root 12 Dec 29 03:29 /dev/mapper/oradisk01 -> ../oradisk01
# ls -l /dev/oradisk01
brw-rw----. 1 oracle dba 8, 33 Dec 29 03:29 /dev/oradisk01
# cat /proc/partitions | grep 33
   8       33      48128 sdc1

3. 直接使用/dev/mapper/oradisk*作为数据文件
由于在Oracle 10.2.0.2以后,Oracle已经可以用O_DIRECT标志直接打开块设备,而不是像以前版本那样,如果要跳过操作系统缓存直接读写磁盘设备,必须要用使用字符设备。在以前的版本中,因为要使用字符设备,所以才需要用raw命令去将某一个块设备映射为一个裸设备(字符设备)。而在Oracle 10.2.0.2以后则可以直接使用块设备(比如/dev/sdc1,比如udev映射以后的/dev/oradisk01,这些都是块设备),不过,虽然Oracle 10.2.0.2以后,Oracle可以直接读取块设备,但是在Oracle 11g以前,这个特性还不被OUI支持,如果要在OUI中使用,则需要使用符号链接(symbolic links),如我们用udev创建的/dev/mapper/oradisk*。
也就是在Oracle 10.2.0.2以后,Oracle 11g以前,需要使用/dev/mapper/oradisk*这样的符号链接作为数据文件。
在Oracle 11g以后,可以使用符号链接,也可以直接使用/dev/oradisk*作为数据文件。

如果你们认为有更优的最佳实践,欢迎讨论。当然我们也可以使用lvm或者Oracle ASM来处理数据文件的存储,这不在本文讨论范围内。

BTW: 一个有趣的bug?在测试中发现,如果在udev创建完符号链接之后,再使用parted来查看链接的分区情况,则会导致链接消失,而映射前的sdc1设备名重新出现。重启udev服务也无法将链接重新创建,但是用parted重新查看sdc1设备,则链接又重新出现,sdc1又重新消失。求解释。

--正常情况下有符号链接
[root@localhost ~]# ls -l /dev/mapper/oradisk01
lrwxrwxrwx. 1 root root 12 Dec 29 03:29 /dev/mapper/oradisk01 -> ../oradisk01
--映射前的sdc1设备是不存在的
[root@localhost ~]# ls -l /dev/sdc1
ls: cannot access /dev/sdc1: No such file or directory
--用parted检查链接,或者检查/dev/oradisk01块设备,效果是一样的
[root@localhost ~]# parted /dev/mapper/oradisk01
GNU Parted 2.1
Using /dev/mapper/oradisk01
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) q                                                                
--链接消失
[root@localhost ~]# ls -l /dev/mapper/oradisk01
ls: cannot access /dev/mapper/oradisk01: No such file or directory
--映射的块设备还在
[root@localhost ~]# ls -l /dev/oradisk01
brw-rw----. 1 oracle dba 8, 33 Dec 29 03:29 /dev/oradisk01
--原先的sdc1设备出现
[root@localhost ~]# ls -l /dev/sdc1
brw-rw----. 1 root disk 8, 33 Dec 29 04:29 /dev/sdc1
--重新用parted检查sdc1
[root@localhost ~]# parted /dev/sdc1
GNU Parted 2.1
Using /dev/sdc1
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) q                                                                
--符号链接重新出现
[root@localhost ~]# ls -l /dev/mapper/oradisk01
lrwxrwxrwx. 1 root root 12 Dec 29 04:38 /dev/mapper/oradisk01 -> ../oradisk01
--sdc1重新消失
[root@localhost ~]# ls -l /dev/sdc1
ls: cannot access /dev/sdc1: No such file or directory

How to set Safari to use PAC file in Mac OS X Lion

目标
通过设置Safari的自动proxy切换,实现浏览网页的时候,如果是GFW的站点则自动通过Proxy,如果不是,则不使用Proxy。这样保证浏览国内网站时候速度够快,而浏览GFW的网站也没有问题,全自动,无需手工干预。

操作系统和浏览器
Mac OS X Lion + Safari 5.1(当然低版本的Safari也同样可以这样设置)。如果浏览器是Firefox,可以直接用autoproxy插件,如果浏览器是Chrome,可以用Switchy!插件。

需要下载的软件
1. SSH Tunnel Manager,在Mac App Store中搜索安装即可。
要使用该软件,首先要求有一个可以通过ssh访问的国外虚拟主机,通常有这样主机的,大概也都知道该如何设置ssh端口转发了,所以不再赘述,要注意的是,监听的端口可以随便设置,我设置为7080。如果使用本文中的pac文件,那么也必须要设置为7080。

2. autoproxy.pac脚本,该脚本可以从AutoProxy2PAC站点下载。很可惜,这个站点本身需要翻墙,不过我已经将我自己用的pac文件放在这里,可以下载使用,在SSH Tunnel Manager中必须设置本地端口是7080。

启动SSH Tunnel Manager
连接设置好的ssh会话,检查本地端口是否已经被正常监听。注意最后两行末尾的LISTEN字样,表示已经监听在本地的7080端口上,这意味着任何通过socks代理发送到本地7080端口的请求,都会通过ssh转发到国外的虚拟主机,然后从国外访问GFWed的网站,再通过ssh返回请求的页面。基本上是这样的方式完成翻墙。

Kamus$ netstat -a|grep 7080
tcp4       0      0  localhost.7080         localhost.37233        ESTABLISHED
tcp4       0      0  localhost.37233        localhost.7080         ESTABLISHED
tcp4       0      0  localhost.7080         localhost.37232        ESTABLISHED
tcp4       0      0  localhost.37232        localhost.7080         ESTABLISHED
tcp4       0      0  localhost.7080         localhost.37231        ESTABLISHED
tcp4       0      0  localhost.37231        localhost.7080         ESTABLISHED
tcp4       0      0  localhost.7080         localhost.36407        ESTABLISHED
tcp4       0      0  localhost.36407        localhost.7080         ESTABLISHED
tcp4       0      0  localhost.7080         localhost.36187        FIN_WAIT_2 
tcp4      37      0  localhost.36187        localhost.7080         CLOSE_WAIT 
tcp4       0      0  localhost.7080         *.*                    LISTEN     
tcp6       0      0  localhost.7080         *.*                    LISTEN  

设置Safari
这是最重要的步骤。
1. 开启Mac OS X Lion中的Web Sharing,实际上就是启动本地的www服务器。如下图,在System Preferences中的Sharing页面里。

2. 将下载的proxy.pac文件复制到~/Sites目录下。

Kamus$ ls ~/Sites
images		index.html	proxy.pac

3. 修改Safari的代理配置,选择自动代理配置,如下图。这里要注意的是URL部分必须是http开头的路径,而不能是本地目录样式的路径,这也是为什么上面第一步要开启Web Sharing的原因。这个问题的解释参看:Proxy Pac files no longer work in Mac OS X Lion

保存以后,尝试登陆一下twitter.com,再尝试登陆一下weibo.com。好了,祝大家翻墙愉快。

How to use udev for Oracle ASM in Oracle Linux 6

大部分在网上可以找到的文档都是在RHEL5或者OEL5中设置udev,udev对于Linux而言最大的作用是防止操作系统重新启动以后,作为ASM磁盘使用的盘符发生变化。
比如说Tim Hall的文章:UDEV SCSI Rules Configuration for ASM in Oracle Linux 5
比如说Maclean的文章:利用UDEV服务解决RAC ASM存储设备名

但是在OEL6或者RHEL6中,这一切都有所变化。

主要的变化是:
1. scsi_id的命令语法发生了变化,scsi_id -g -u -s这样的命令不再有效。
2. udevtest命令已经没有了,整合到了udevadm中。

可以参考Redhat的官方文档(这个文档中本身有一些错误,在udev rules中漏了–device=,正确的方法参看下面的第3步):
Configuring persistent storage in Red Hat Enterprise Linux 6

步骤如下:
1. 编辑/etc/scsi_id.config文件,如果该文件不存在,则创建该文件,添加如下行:

options=--whitelisted --replace-whitespace

备注:在我的测试中,此步骤可以省略。

2. 获取需要绑定为ASM Disk的磁盘uuid,比如我们要使用/dev/sdc和/dev/sdd作为ASM磁盘,那么:

# scsi_id --whitelisted --replace-whitespace --device=/dev/sdc
1ATA_VBOX_HARDDISK_VB36a9e548-1838194a
# scsi_id --whitelisted --replace-whitespace --device=/dev/sdd
1ATA_VBOX_HARDDISK_VB9808fc7f-cdf35030

3. 编写udev rules文件,PROGRAM中写scsi_id命令,RESULT中写上面命令中返回的uuid,这跟OEL5中没什么区别,只是scsi_id命令的语法发生变化了。

vi /etc/udev/rules.d/99-oracle-asmdevices.rules
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM=="/sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/$name", RESULT=="1ATA_VBOX_HARDDISK_VB36a9e548-1838194a", NAME="asm-disk1",  OWNER="grid",  GROUP="dba", MODE="0660"
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM=="/sbin/scsi_id --whitelisted --replace-whitespace --device=/dev/$name", RESULT=="1ATA_VBOX_HARDDISK_VB9808fc7f-cdf35030", NAME="asm-disk2",  OWNER="grid",  GROUP="dba", MODE="0660"

4. 用udevadm进行测试,注意udevadm命令不接受/dev/sdc这样的挂载设备名,必须是使用/sys/block/sdc这样的原始设备名。

udevadm test /sys/block/sdc
udevadm info --query=all --path=/sys/block/sdc
udevadm info --query=all --name=asm-disk1

在显示中,有类似如下输出,表示测试正确,/dev/sdc设备在udev启动以后将会绑定为/dev/asm-disk1:

udevadm_test: UDEV_LOG=6
udevadm_test: DEVPATH=/devices/pci0000:00/0000:00:0d.0/host4/target4:0:0/4:0:0:0/block/sdc
udevadm_test: MAJOR=8
udevadm_test: MINOR=32
udevadm_test: DEVNAME=/dev/asm-disk1
udevadm_test: DEVTYPE=disk
udevadm_test: ACTION=add
udevadm_test: SUBSYSTEM=block

5. 启动udev

# /sbin/start_udev

6. 检查设备是否正确绑定

# ls -l /dev/asm*
brw-rw---- 1 grid dba 8, 32 Oct 26 21:24 /dev/asm-disk1
brw-rw---- 1 grid dba 8, 48 Oct 26 21:17 /dev/asm-disk2

How to delete photos from Photo Stream in iOS5

不管你相信不相信,目前你无法从iOS5的Photo Stream中删除单张照片,这似乎保持了Apple的一贯作风,简单粗暴,要么全部删除,要么等着存满1000张把以前的顶掉。

Photo Stream并不是一个同步机制,他仅仅是在Wifi可用的场景下进行照片的Push工作,比如你从iPhone的Camera Roll里面删除一张照片,这并不会影响已经push到Photo Stream中的照片,所以想靠这种方法来删除Photo Stream中的单张照片也是不可行的。

我们现在可以作的就是删除Photo Stream中的所有图片,但是我们上面提到了Photo Stream并不是同步的机制,因此假设你有两个设备,一个iPhone(运行着iOS5),一个Macbook(运行着Mac OS-X Lion 10.7.2以及iPhoto 9.2),并且还有网络上的iCloud.com,你需要手动在这三个地方都删除掉图片。

1. 删除iOS5中的Photo Stream图片
在Settings->iCloud->Photo Stream中,将选项设置为Off,会提示将删除所有Photo Stream中的图片,确认之后即可完成删除。

2. 删除iPhoto中的Photo Stream图片
在Preferences->Photo Stream中,将Enable Photo Stream前面的勾去掉,也会提示将删除所有Photo Stream中的图片,确认之后即可以完成删除。

3. 删除iCloud中的Photo Stream图片
登陆iCloud.com,点击右上角的用户名,点击Advanced,点击Reset Photo Stream,仍然会提示删除,确认完成。