2014年6月4日星期三

python 之图片无法显示 IOError: decoder zip not available



最近用 mezzanine 搭建了一个 blog, 后台管理 media-library 部分总是报错:


About the PIL Error — IOError: decoder zip not available


重新安装,看到安装后的结果是支持的:


*** ZLIB (PNG/ZIP) support available
重装了好几遍,还是没有用,使用模块 Pillow 的 2.3.0 版本安装后,页面可以成功打开了。


处理完那个问题,又有个新问题,就是中文的地址无法解析:

http://ip/%E4%BA%B2%E6%83%85/
'ascii' codec can't encode characters in position 35-36: ordinal not in range(128)
export LC_ALL='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'

mezzanine 的备份和迁移还需要关注一下。 这个虚拟主机还有半年左右就到期了。
About the PIL Error — IOError: decoder zip not available
*** ZLIB (PNG/ZIP) support available


'ascii' codec can't encode characters in position 35-36: ordinal not in range(128)

export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'

python 之学习检查 /etc/hosts 文件有效性


单线程版本:

#!/usr/bin/python

import os
import commands
f=open("/etc/hosts","r")

for line in f.readlines():
    ip=str(line.split()[0:1][0])
    if ip == '#' or ip == ' ':
        continue
    status, output = commands.getstatusoutput('ping -c 3 -w 5' +" " + ip)
    if status == 0:
        continue
    else:
        print "Warnning:" + ip + " is timed out!!!"
f.close


多线程版本:
#!/usr/bin/python
import os,re,sys
from threading import Thread

class testit(Thread):
   def __init__ (self,ip):
      Thread.__init__(self)
      self.ip = ip
      self.status = -1
   def run(self):
      pingaling = os.popen("ping -w5 -c2 "+self.ip,"r")
      while 1:
        line = pingaling.readline()
        if not line: break
        igot = re.findall(testit.lifeline,line)
        if igot:
            self.status = int(igot[0])
testit.lifeline = re.compile(r"(\d) received")
pinglist = []

f=open("/etc/hosts","r")

for line in f.readlines():
   ip = str(line.split()[0:1][0])
   if ip == '#' or ip == '':
        continue
   current = testit(ip)
   pinglist.append(current)
   current.start()

for pingle in pinglist:
    pingle.join()
    if pingle.status == 0:
       print pingle.ip + "is timed out!!"


一个 logrotate 不执行的分析


手动执行一下 logrotate 命令,看看是否成功:
[root@logs]# logrotate  -f /etc/logrotate.d/nginx
[root@logs]# ls -l
total 3064
-rw-r--r--. 1 nobody root   18391 Mar 12 14:43 access.log
-rw-r--r--. 1 root   root 3040520 Mar 12 14:43 access.log-20140312.bz2
-rw-r--r--. 1 nobody root     420 Mar 12 14:43 error.log
-rw-r--r--. 1 root   root   56056 Mar 12 14:43 error.log-20140312.bz2

debug 看一下具体的输出:
[root@logs]# logrotate -v -d -f /etc/logrotate.d/nginx
.........................
glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
glob finding old rotated logs failed
fscreate context set to unconfined_u:object_r:user_home_t:s0
renaming /home/nginx/logs/access.log to /home/nginx/logs/access.log-20140312
fscreate context set to unconfined_u:object_r:user_home_t:s0
renaming /home/nginx/logs/error.log to /home/nginx/logs/error.log-20140312
........................

fscreate 那行 发现有 selinux 的迹象,直接跑是没有问题的。有 selinux ,查一下 selinux 的日志 /var/log/audit/audit.log :
[root@audit]# cat audit.log |grep logrotate
type=AVC msg=audit(1394467201.627:1089499): avc:  denied  { read } for  pid=15146 comm="logrotate" name="logs" dev=sda2 ino=486722 scontext=system_u:system_r:logrotate_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir
type=SYSCALL msg=audit(1394467201.627:1089499): arch=c000003e syscall=2 success=no exit=-13 a0=7fffe254e8d0 a1=90800 a2=d8e2d1 a3=fffffffffffffff0 items=0 ppid=15144 pid=15146 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=170110 comm="logrotate" exe="/usr/sbin/logrotate" subj=system_u:system_r:logrotate_t:s0-s0:c0.c1023 key=(null)
type=AVC msg=audit(1394480282.021:1090340): avc:  denied  { read } for  pid=35936 comm="logrotate" name="logs" dev=sda2 ino=486722 scontext=system_u:system_r:logrotate_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir
........................

上面过滤的结果看,果然有发现。logrotate 的执行确实是被 deny 了。查看 selinux 的状态,是 enforcing 模式:
[root@logs]# sestatus 
SELinux status:                 enabled
SELinuxfs mount:                /selinux
Current mode:                   enforcing
Mode from config file:          enforcing
Policy version:                 24
Policy from config file:        targeted

解决方法:
方法一: 关闭 selinux ,临时修改  setenforce 0; 修改 /etc/selinux/config 启动禁用,还可修改 grub 选项禁启动,google 无忧。 
方法二:  学习一下 selinux 配置;怎么做。 我们可以回归到系统上,/var/log 看这个目录下的日志是可以轮询的,ls -Z |grep log* 来看 selinux 配置:
[root@log]# ls -Z /var/log/
drwxr-xr-x. root   root   system_u:object_r:consolekit_log_t:s0 ConsoleKit
-rw-------. root   root   system_u:object_r:var_log_t:s0   anaconda.ifcfg.log
-rw-------. root   root   system_u:object_r:var_log_t:s0   anaconda.log
-rw-------. root   root   system_u:object_r:var_log_t:s0   anaconda.program.log
-rw-------. root   root   system_u:object_r:var_log_t:s0   anaconda.storage.log
-rw-------. root   root   system_u:object_r:var_log_t:s0   anaconda.syslog
-rw-------. root   root   system_u:object_r:var_log_t:s0   anaconda.xlog
-rw-------. root   root   system_u:object_r:var_log_t:s0   anaconda.yum.log
drwxr-x---. root   root   system_u:object_r:auditd_log_t:s0 audit
-rw-r--r--. root   root   system_u:object_r:var_log_t:s0   boot.log
-rw-r--r--. root   root   system_u:object_r:var_log_t:s0   boot.log-20140223
........................

接下来,就是把 user_home_t 修改为 var_log_t , 也可以回到上面的 audit.log 部分 , 发现最后 t 的属性是 logrotate_t
[root@logs]# ls -Z
-rw-r--r--. nobody root unconfined_u:object_r:user_home_t:s0 access.log
-rw-r--r--. nobody root unconfined_u:object_r:user_home_t:s0 error.log
-rw-r--r--. root   root unconfined_u:object_r:user_home_t:s0 nginx.pid
[root@logs]# semanage fcontext -a -t var_log_t '/home/nginx/logs/(.*)?'
[root@logs]# restorecon -R -v /home/nginx/logs/
restorecon reset /home/nginx/logs/access.log context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:var_log_t:s0
restorecon reset /home/nginx/logs/error.log context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:var_log_t:s0
restorecon reset /home/nginx/logs/nginx.pid context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:var_log_t:s0
[root@logs]# ls -Z
-rw-r--r--. nobody root unconfined_u:object_r:var_log_t:s0 access.log
-rw-r--r--. nobody root unconfined_u:object_r:var_log_t:s0 error.log
-rw-r--r--. root   root unconfined_u:object_r:var_log_t:s0 nginx.pid
[root@logs]#

具体的行不行,当然还得系统来验证。

alter ignore table 的一次悲剧


增加一个字段:
ALTER TABLE `appinfo` ADD `user_id_56` VARCHAR(30) NOT NULL AFTER `user_id`;
mysql> select user_id_56 from appinfo limit 10;
+------------+
| user_id_56 |
+------------+
|            |
|            |
|            |
|            |
|            |
|            |
|            |
|            |
|            |
|            |
+------------+
10 rows in set (0.00 sec)

设置这个字段唯一:
mysql> ALTER TABLE  `appinfo` ADD UNIQUE (`user_id_56`);
ERROR 1062 (23000): Duplicate entry '' for key 'user_id_56'

mysql> set session old_alter_table=1; 
Query OK, 0 rows affected (0.00 sec)

再次 alter :
mysql> ALTER ignore TABLE  `appinfo` ADD UNIQUE (`user_id_56`);
Query OK, 3807 rows affected (0.28 sec)
Records: 3807  Duplicates: 3806  Warnings: 0

看到 duplicates 为 3806,结果悲了个剧,数据去哪了,就剩下一条记录

mysql> select user_id_56 from appinfo limit 10;
+------------+
| user_id_56 |
+------------+
|            |
+------------+
1 row in set (0.00 sec)

mysql> 

还好有个备份的旧数据可以用,挽回。

加一个非空的唯一字段正确做法原本可以这样
ALTER TABLE `appinfo` ADD `user_id_56` VARCHAR(30) UNQIUE COMMENT '绑定的56user_id' AFTER `user_id`;

直接把 unqiue 放到 add 中,旧的数据默认就是 NULL 了,随便拿一个来测试看看:

mysql@test> select * from c;
+----+
| id |
+----+
|  9 |
| 10 |
+----+
2 rows in set (0.00 sec)

mysql@test> ALTER TABLE c ADD `user_id_56` VARCHAR(30) UNIQUE  COMMENT 'test' AFTER id ;
Query OK, 2 rows affected (0.01 sec)               
Records: 2  Duplicates: 0  Warnings: 0

mysql@test> select * from c;
+----+------------+
| id | user_id_56 |
+----+------------+
|  9 | NULL       |
| 10 | NULL       |
+----+------------+
2 rows in set (0.00 sec)

并不是 delete 和 truncate 或者 drop 才可以丢数据,其它情况的 db 的操作仍然需要谨慎。