2012年5月31日

rhel6.0及centos6.0 忘记root密码解决办法

刚刚在装centos6.0系统时候,忘记了设定好的linux root用户密码。按照经验,进入单用户模式修改root密码。

但是在使用passwd进行修改时,啥反应都没有,没有提示没有错误。

后经过查找发现是centos6对此做了更改。

找到了别人的一个解决方法,特标记下。http://bazhuayu.blog.51cto.com/1441282/855908。自己验证了第一个解决方法是有效的,

下面的三条没有验证过,后期将会验证下看看具体效果,应该不会差。

下面是转载的解决方法:

重启,修改grup进入单用户模式,输入 passwd来更改root密码,结果意外的发现无论我怎么输都没反应,

不能修改密码。后来通过百度找到了原因。原来在6.0以后的版本中,直接输入 passwd是无效的!

这点与之前rhel 5是不同的!一共有四种方法可以修改密码。

1,进入单用户模式后,关闭selinux,再输入passwd即可修改密码。

2,修改/etc/passwd文件,将里面root行代表有密码的"x"删掉。

3,修改/etc/shadow文件,将里面root行加密的密文删掉。

4,通过光盘引导进入修复模式来修改。

详细截图可以参考原网页。

http://bazhuayu.blog.51cto.com/1441282/855908

posted @ 2012-05-31 14:15 hanxiangduo 阅读(7) 评论(0) 编辑

2012年2月23日

virt-manager 的 internal error Cannot find suitable emulator for x86_64 错误

在centos6.2启动virt-manager时,总提示如下错误:
internal error Cannot find suitable emulator for x86_64,在使用virsh version的时候,也会出现类似错误,还有无法定位qemu内部函数错误。
查看系统的qemu包,
rpm -qa | grep qemu
gpxe-roms-qemu-0.9.7-6.9.el6.noarch
qemu-img-0.12.1.2-2.209.el6_2.4.x86_64
qemu-kvm-0.12.1.2-2.209.el6_2.4.x86_64
qemu相关的包都已经安装。

通过google发现,有老外遇到了同样的问题,
http://barryp.org/blog/entries/make-sure-virtualization-enabled-bios/
原来是biso的虚拟化设置没有打开。
查看系统日志:/var/log/message
kernel: kvm: disabled by bios
重启机器,进入bios设置,cpu的虚拟化果然没有打开,重新设置后,virsh正常了。

posted @ 2012-02-23 16:13 hanxiangduo 阅读(169) 评论(0) 编辑

2012年1月15日

通过shell读取mysql数据

目前在修改eucalyptus的euca_conf脚本时,需要从mysql中读取一些数据信息,此时要用到shell去访问数据库。
通过查找得知,mysql可以直接执行sql的查询语句。通过对一些sql语句的简单封装,数据便可以得到了。
代码如下:
 

   #!/bin/bash
MYSQL=mysql #选用mysql程序
USER=root #设定用户名
PASSWORD="123456" #设定数据库的用户密码
DB=eucalyptus_auth #选定需要的数据库

COMMAND="select auth_user_query_id, auth_user_secretkey from auth_users where auth_user_name=\"admin\" " #查找需要的数据sql语句
declare count=`$MYSQL -u${USER} -p${PASSWORD} -D ${DB} -e "${COMMAND}" --skip-column-name` #执行mysql的查询,并将其记录到count中
for list in $count
do
echo " the item is $list"
done #读取得到的数据

看来,用shell访问数据库也是比较简单的。

posted @ 2012-01-15 09:39 hanxiangduo 阅读(78) 评论(0) 编辑

ftp虚拟用户添加

有时候,在设置ftp用户的时候,不必要登录系统,只是具有ftp用户功能,这是可以设置vsftp虚拟用户。
具体配置Vsftp的虚拟用户可以参考 http://www.cyberciti.biz/tips/centos-redhat-vsftpd-ftp-with-virtual-users.html.
本文介绍的主要内容也是从上文中提取出来的.

vsftp也是支持linux的pam(可插拨认证模块),一个登录ftp服务的用户也可以不必要是系统用户,
这样的配置对系统来说也更安全,对当前的项目来说,也更易修改用户密码.
需要的软件
当前环境centos5.5
Berkeley DB (version 4) \db4-utils
当前的系统中已经默认有db4,需要安装db4-utils工具
pam_userdb.so
已经有,在/lib/security/pam_userdb.so和/lib64/security/pam_userdb.so当中
Berkeley DB是vsftp采用pam认证的数据库文件支持,
pam_userdb.so,可参考 http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/sag-pam_userdb.html
是一个验证db4数据库中存储的用户名密码的pam认证库.

前期准备

安装db4-utils数据库工具:yum install db4-utils
配置vsftp的pam认证
 vim /etc/pam.d/vsftpd.virtual
将下列内容添加到上面的配置文件中
----
#%PAM-1.0
auth       required     pam_userdb.so db=/var/www/.images/vsftpd-virtual-user
account    required     pam_userdb.so db=/var/www/.images/vsftpd-virtual-user
session    required     pam_loginuid.so
----
''/var/www/.images/vsftpd-virtual-user''这个路径文件,是db4的数据库文件所在的地方,在实际使用时可以修改到合适的地方,
关于这个文件的生成将会在后面介绍.
配置vsftp,使得Vsftp支持虚拟用户

anonymous_enable=NO
local_enable=YES
virtual_use_local_privs=YES#允许虚拟用户登录
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
conxferlog_std_format=YES
nect_from_port_20=YES
listen=YES
pam_service_name=vsftpd.virtual#设置了pam的认证服务,与上面的pam配置是相对应的
guest_enable=YES
hide_ids=YES
userlist_enable=YES
tcp_wrappers=YES

具体实施:
比如要在django框架支持下的更改ftp的用户密码,下面是一个简单测试方案,为只有一个用户名密码的准备。

由于使用到了os模块,需要添加该系统模块:import os

def change_pass_by_pam( username='admin', new=None):
#generate s file
#generate the db4 db file
#copy it to the correct location
username = username
userpass = new
fp=open(PASSNAME,'w')
fp.write(username+"\n"+userpass+"\n")
#将新的密码写入到临时的一个文件中,PASSNAME位置任意,只要有权限即可
fp.writelines("\n")
#在文件最后一行加上一个换行符,不知为啥,不加的话,产生的密码数据库文件总是验证不对
fp.close()
try:
os.remove(VIRTUALUSERDB)
except OSError:
pass
try:
os.system("db_load -T -t hash -f "+PASSNAME+" "+VIRTUALUSERDB)
#使用db4的工具,从写入新密码的文件中生成db4 的数据库文件,这里的VIRTUALUSERDB于/etc/pam.d/vsftpd.virtual的db位置一致
except:
return false
try:
os.remove(PASSNAME)
#最终删除了临时的密码文件
except:
pass

测试效果

在实际修改时,可以实际测试一下,在非ftp服务器上采用ftp连接

[root@localhost ~]# ftp 192.168.0.201
Connected to 192.168.0.201.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (192.168.0.201:root): admin
331 Please specify the password.
Password:
此处的密码可以输入刚刚修改的密码
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.

登录成功说明,系统密码修改已经ok了.
还可以查看下ftp服务器的系统安全日志

tail -f /var/log/secure
Sep 2 17:38:32 NFS-Cloud-201 vsftpd: pam_userdb(vsftpd.virtual:auth): user `admin' denied access (incorrect password)
Sep 2 17:39:23 NFS-Cloud-201 vsftpd: pam_userdb(vsftpd.virtual:auth): user 'admin' granted access

可以清楚看到vsftp的pam认证过程.

posted @ 2012-01-15 09:33 hanxiangduo 阅读(76) 评论(0) 编辑

2012年1月14日

eucalyptus volume 的一些创建流程以及理解

目前eucalyptus中,数据的共享的逻辑卷采用aoe http://www.txrjy.com/baike/view.asp?ATA%20over%20Ethernet, http://support.coraid.com/support/linux/,
和iscsi, http://baike.baidu.com/view/120148.htm.目前在我们的测试机中使用的是iscsi,进行逻辑卷的共享设置.
在这些逻辑卷的实际测试使用中,在将卷绑定到虚拟机时,有时候会不够稳定,使卷无法绑定到虚拟机,或者是一个卷可以被多个虚拟机绑定,主要有以下三种情况:
1、connect_iscsi_target failed
这是由于iscsi的目标卷处于iactive状态,导致nc端在向目标卷发起连接登录的时候,无法连接,从而导致绑定失败.
但是目前这种错误难以重现.推测是sc服务重启后,卷处于iactive状态,而没有对目标卷进行激活处理.
具体查看目标机上的逻辑卷状态可以通过lvscan http://linux.die.net/man/8/lvscan进行查看,vgscan http://linux.die.net/man/8/vgscan查看逻辑卷组.
clc端的错误日志: 下面日志表明.clc在attachvolume时,收到了结果为空的返回值.

15:57:38 DEBUG [NioResponseHandler:cluster223-Worker-7] :1315900658432:NioResponseHandler:MSG_AWAIT_RESPONSE:MSG_POLL_INTERNAL:100:QueuedEventCallback.waitForResponse.354
15:57:38 DEBUG [NioResponseHandler:cluster223-Worker-7] :1315900658536:NioResponseHandler:MSG_AWAIT_RESPONSE:MSG_POLL_INTERNAL:100:QueuedEventCallback.waitForResponse.354
15:57:38 TRACE [QueuedEventCallback:New I/O client worker #2-12] <?xml version="1.0" encoding="UTF-8"?>
<euca:AttachVolumeResponseType xmlns:euca="http://msgs.eucalyptus.com">
<euca:BlockVolumeMessage>
<euca:EucalyptusMessage>
<euca:userId>admin</euca:userId>
<euca:_return>false</euca:_return>
<euca:statusMessage>ERROR</euca:statusMessage>
</euca:EucalyptusMessage>
</euca:BlockVolumeMessage>
<euca:attachedVolume>
<euca:attachTime>2011-09-13T07:57:38.565Z</euca:attachTime>
</euca:attachedVolume>
</euca:AttachVolumeResponseType>
15:57:38 DEBUG [VolumeAttachCallback:New I/O client worker #2-12]
<?xml version="1.0" encoding="UTF-8"?>
<AttachVolume xmlns="http://eucalyptus.ucsb.edu/">
<correlationId>cda55cc8-197d-4d3c-8382-24e7789930cb</correlationId>
<userId>admin</userId>
<return>true</return>
<volumeId>vol-5DE1063D</volumeId>
<instanceId>i-426E075E</instanceId>
<remoteDev>//,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w==</remoteDev>
<localDev>/dev/sdb</localDev>
</AttachVolume>

--------------------------------------------------------------------------------
15:57:38 DEBUG [VolumeAttachCallback:New I/O client worker #2-12] com.eucalyptus.util.EucalyptusClusterException: [AttachVolumeResponseType attachedVolume=AttachedVolume null null null null null Tue Sep 13 15:57:38 CST 2011 correlationId=null userId=admin effectiveUserId=null _return=false statusMessage=ERROR]
com.eucalyptus.util.EucalyptusClusterException: [AttachVolumeResponseType attachedVolume=AttachedVolume null null null null null Tue Sep 13 15:57:38 CST 2011 correlationId=null userId=admin effectiveUserId=null _return=false statusMessage=ERROR]

cc端的错误日志: cc端在向nc端发送添加逻辑卷指令时,nc端反馈出了一个错误信息.

[Tue Sep 13 15:59:55 2011][003491][EUCADEBUG ] AttachVolume(): params: userId=admin, volumeId=vol-5DE1063D, instanceId=i-426E075E, remoteDev=//,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w==, localDev=/dev/sdb
[Tue Sep 13 15:59:55 2011][003491][EUCADEBUG ] find_instanceCache(): found instance in cache 'i-426E075E/192.168.5.245/192.168.138.67'
[Tue Sep 13 15:59:55 2011][003491][EUCADEBUG ] ncClientCall(ncAttachVolume): called ncURL=http://192.168.5.45:8775/axis2/services/EucalyptusNC timeout=20
[Tue Sep 13 15:59:55 2011][007546][EUCADEBUG ] DEBUG: requested URI http://192.168.5.45:8775/axis2/services/EucalyptusNC
[Tue Sep 13 15:59:55 2011][007546][EUCADEBUG ] ncClientCall(ncAttachVolume): ppid=3491 client calling 'ncAttachVolume'
[Tue Sep 13 15:59:56 2011][007546][EUCAERROR ] ERROR: AttachVolume returned an error
nc端的错误日志: nc在向目标卷发起连接时,出现错误,连接失败从而在附加卷时出错.最终错误层层上达到clc端,造成在绑定卷时失败.
[Tue Sep 13 16:06:03 2011][029948][EUCAINFO ] doAttachVolume() invoked (id=i-426E075E vol=vol-5DE1063D remote=//,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w== local=/dev/sdb)
[Tue Sep 13 16:06:03 2011][029948][EUCAINFO ] connect_iscsi_target invoked (dev_string=//,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w==)
[Tue Sep 13 16:06:03 2011][029948][EUCADEBUG ] system_output(): [//usr/lib/eucalyptus/euca_rootwrap //usr/share/eucalyptus/connect_iscsitarget.pl //,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w==]
[Tue Sep 13 16:06:04 2011][029948][EUCAERROR ] ERROR: connect_iscsi_target failed
[Tue Sep 13 16:06:04 2011][029948][EUCAERROR ] AttachVolume(): failed to connect to iscsi target
[Tue Sep 13 16:06:04 2011][029948][EUCAERROR ] ERROR: doAttachVolume() failed error=1



2、 Requested operation is not valid
在nc的日志中有libvirt的错误信息:

libvirt: Requested operation is not valid: Xm driver only supports modifying persistent config (code=55)
AttachVolume() failed (err=-1) XML=<disk type='block'><driver name='phy'/><source dev='/dev/sde'/><target dev='sdq'/></disk>

3、在sc端重启后,逻辑卷显示错误.

在cloud重启后,无法显示卷绑定的实例,尽管这些卷正在被之用着。造成在clc端,卷可以被重复绑定。

因而,针对上述的三个主要问题,讲解一下在解决问题过程中,对eucalyptus中,卷管理的一些理解.


对eucalyptu中卷的管理分析,将从clc端开始,到nc端结束.
卷管理的具体实现 ¶

在clc端,处理volume请求在clc/modules/image-manager/src/main/java/com/eucalyptus/blockstorage/VolumeManager.java中,在这里可以处理volume请求的有:
CreateVolume、DeleteVolume、DescribeVolumes、AttachVolume、detach。对此,将会着重从CreateVolume、DescribeVolumes和AttachVolume作分析,查找AttachVolume失败的原因.
CreateVolume的大概流程:

CreateVolume,接收CreateVolumeType --> 对创建请求作一些预处理和约束,创建卷时必须有快照或是卷大小的参数 --> 获取sc的配置信息,地址 --> 将要创建的卷的信息计入到后台数据库中
--> 将创建卷的请求发送到sc端,
CreateStorageVolumeType req = new CreateStorageVolumeType( newId, request.getSize( ), request.getSnapshotId( ) ); StorageUtil.send( sc.getName( ), req );
--> clc的请求,由clc/modules/storage-controller/src/main/java/edu/ucsb/eucalyptus/cloud/ws/BlockStorage.java中的CreateStorageVolume接收处理,在其中作一些简单预处理,以及数据记录
--> 将创建volume发送到VolumeCreator,进行异步创建 --> VolumeCreator中的run在进行一些基本条件的判断,最终交由LogicalStorageManager的OverlayManager解决卷的创建问题
--> LogicalStorageManager是一个抽象类,在BlockStorageManagerFactory中将其实例化为
clc/modules/storage-controller/src/main/java/com/eucalyptus/storage/OverlayManager.java的OverlayManager,
最终在其中完成卷的创建工作,主要采用java调用一些系统命令完成,详细流程,可以参看具体的代码.

DescribeVolumes的处理流程:

 VolumeManager中的DescribeVolumes接收到查看卷请求 -->从数据库中读取存储的volume卷信息 -->从运行的虚拟机实例列表中读取绑定的卷的信息
-->clc/modules/core/src/main/java/com/eucalyptus/util/BlockStorageUtil.java中的BlockStorageUtil的getVolumeReply从sc中获取卷的信息,其中对数据库中存储的卷和虚拟机已经绑上的卷与
sc上存在的卷进行映射处理 -->最终反馈给了界面显示
从DescribeVolumes的简单流程中,可以看到在对volume的显示时与clc端数据库中存储的volume信息 虚拟机实例绑定的信息 以及具体sc上的卷的信息相关,这样的话,任何一个出问题,都有可能造成显示时的错误.

AttachVolume的处理流程

VolumeManager中的AttachVolume接收到绑定请求 --> 对绑定参数的合法性进行简单判断 --> 检查卷是否被重复绑定 --> 检查卷与实例是否在同一个cc上 -->从数据库中获取要绑定卷的地址信息
--> 从sc中检查卷的的一些基本状况 -->将绑定请求发至cc端new VolumeAttachCallback( request ).dispatch( cluster ); --> cc将绑定请求发送到nc -->
./node/handlers_xen.c中的doAttachVolume对绑定请求进行处理 -->通过./node/handlers.c中的connect_iscsi_target进行与远程卷的连接,至此大概的处理流程也已经结束.
上边的connect_iscsi_target是通过调用一个perl脚本处理的,脚本位置在tools/connect_iscsitarget.pl,安装后该文件在/usr/share/eucalyptus/connect_iscsitarget.pl中.
connect_iscsi_target failed的错误,也正是由于该文件调用失败得来的.

基于对volume卷管理的理解,现对于开头提到的三个bug进行更改:

bug1 connect_iscsi_target failed

从AttachVolume中可以看到,在绑定流程处理中,最终是通过nc的connect_iscsitarget.pl进行卷的绑定处理,从错误日志 也可以看出,要发起的目标地址是iqn.2009-06.com.eucalyptus.cluster223:store3
但是nc在连接该地址时连接不上,连接不上原因有二:一是clc端的volume中的远端地址信息过于陈旧;二是sc端的卷的确无法登录.通过查看sc可以看到,在volume中,卷的空间还在,
说明这些卷并未被删除,因此原因不在于clc,而是在于系统可能处于某个时段,sc的重启或是其他操作,使卷处于iactive状态.使的connect_iscsitarget.pl运行错误.
对connect_iscsitarget.pl的简单分析,可以看到nc登录绑定原端的volume卷时,主要是通过一些iscsiadm基本命令.手工运行这些连接命令,也是无法登录,在sc上查看,卷处于iactive状态.
由于该bug无法重现,因此预防措施是在sc重启时将目标卷重新进行激活,以尽量减少出错概率.
com.eucalyptus.storage.OverlayManager.VolumeEntityWrapperManager.exportVolume(LVMVolumeInfo lvmVolumeInfo) throws EucalyptusCloudException中在lvm卷为ISCSIManager
时,重新激活逻辑卷.exportVolume是sc在重新启动时调用的函数.Bootstrap.load -->BlockStorageBootstrapper.load -->BlockStorage?.ConvertVolumes? -->OverlayManager.checkPreconditions.

bug2 Requested operation is not valid

是传递的逻辑卷的参数不合法,在挂载设备时,设备名字/dev/sd[x][n],中x从a~p,n从0~15,否则就会出错,关于linux的scsi设备命名规范.
可以参加 http://publib.boulder.ibm.com/infocenter/dsichelp/ds6000ic/index.jsp?topic=%2Fcom.ibm.storage.smric.help.doc%2Ff2c_linuxscsilimit_2hsag9.html

bug3 在sc端重启后,逻辑卷显示错误

在eucalyptus-cloud重启后,在describevolume时,volume的显示发生问题,无法显示被绑定到的虚拟机实例。从而造成逻辑卷还没有被绑定的假象,结果使已经被绑定的逻辑卷还可以被重复绑定,造成数据的错误。
从DescribeVolumes的简单流程中,可以看到volume的显示与clc端的数据库信息volume、运行实例绑定的volume、和sc端存在的volume三者有关联。三者中的任何一个出错,都有可能造成volume的显示错误。
因此,在DescribeVolumes中,分别将获取上述三者的信息计入日志文件中。比如:

public DescribeVolumesResponseType DescribeVolumes( DescribeVolumesType request ) throws EucalyptusCloudException {
DescribeVolumesResponseType reply = ( DescribeVolumesResponseType ) request.getReply( );
EntityWrapper<Volume> db = getEntityWrapper( );
try {
String userName = request.isAdministrator( ) ? null : request.getUserId( );
LOG.debug("start describe volume invoke =================");
Map<String, AttachedVolume> attachedVolumes = new HashMap<String, AttachedVolume>( );
for ( VmInstance vm : VmInstances.getInstance( ).listValues( ) ) {
LOG.debug("==try get the instance volume ==hanxiangduo");
LOG.debug( LogUtil.dumpObject(vm) );
for ( AttachedVolume av : vm.getVolumes( ) ) {
LOG.debug("=================attached volume");
attachedVolumes.put( av.getVolumeId( ), av );
LOG.debug( LogUtil.dumpObject(av) );
}
}

List<Volume> volumes = db.query( Volume.ownedBy( userName ) );
List<Volume> describeVolumes = Lists.newArrayList( );
LOG.debug("== try get the volume from db== hanxiangduo");
LOG.debug(LogUtil.dumpObject(volumes));
for ( Volume v : volumes ) {
LOG.debug("==============volume from db");
if ( !State.ANNIHILATED.equals( v.getState( ) ) ) {
LOG.debug("add the avilable volume in describevolume");
LOG.debug( LogUtil.dumpObject(v) );
describeVolumes.add( v );
} else {
db.delete( v );
}
}
try {
ArrayList<edu.ucsb.eucalyptus.msgs.Volume> volumeReplyList = StorageUtil.getVolumeReply( attachedVolumes, describeVolumes );
reply.getVolumeSet( ).addAll( volumeReplyList );
} catch ( Exception e ) {
LOG.warn( "Error getting volume information from the Storage Controller: " + e );
LOG.debug( e, e );
}
db.commit( );
} catch ( Throwable t ) {
db.commit( );
}
return reply;
}

上边分别记录了在eucalyptus-cloud重启后从数据库中读取到的volume和从运行实例中读取到的绑定卷的信息。分析日志发现在重启后运行实例的volume卷信息为空。
但是,重启之后,从clc端的describeinstance日志中可以看到,其中是有实例volume卷的信息的,这说明是在从运行实例中获取绑定卷时出问题。cc端在向clc端返回的数据中,
是有虚拟机实例的volume信息。因此,问题只能出在clc端在获取从cc端instance实例信息赋值记录的过程中。
在clc端向cc请求运行的虚拟机实例信息,对clc端记录的虚拟机列表进行更新的过程大概是:
VmStateHandler.upstreamMessage( ChannelHandlerContext? ctx, MessageEvent e )
--> SystemState.handle( VmDescribeResponseType? request ) --> SystemState.updateVmInstance(final String originCluster, final VmInfo runVm)
-->VmInstance.setVolumes(final List<AttachedVolume?> volList );最终在这里实现对clc的实例列表进行赋值。
下面是原始的赋值代码:

 public void setVolumes( final List<AttachedVolume> newVolumes ) {
for ( AttachedVolume vol : newVolumes ) {
vol.setInstanceId( this.getInstanceId( ) );
vol.setStatus( "attached" );
}
Set<AttachedVolume> oldVolumes = Sets.newHashSet( this.getVolumes( ) );
this.volumes.retainAll( volumes );
this.volumes.addAll( volumes );
for ( AttachedVolume v : oldVolumes ) {
if ( "attaching".equals( v.getStatus( ) ) && !this.volumes.contains( v ) ) {
this.volumes.add( v );
}
}

通过分析上述代码,可以发现,在第一次赋值时,从cc端传递过来的volume信息是根本不能够被设置成功的。因此修改此处的setvolume实现,通过attachvolume的简单流程,已经绑定的卷不可以再被绑定,最终该bug解决。 这个bug已经有人提出,解决方法https://bugs.launchpad.net/eucalyptus/+bug/822505


posted @ 2012-01-14 10:44 hanxiangduo 阅读(105) 评论(0) 编辑

2012年1月13日

django 判断mysql中的bit(1)

问题:

django访问mysql数据库时,可以通过自醒的方式获取数据库中的字段。对于mysql中的bit字段,比较特殊,django无法识别, 它将其默认识别为models.TextField?(),这显然是不对的,在将其改为models.BooleanField()后,存储数据正确,数据库里可以查看到数据。 但是在if,else判断时均显示为true,无法进行判别。解决方法很简单,在判断字段时采用ord(field)就行。 看下面的例子就成。



示例:

比如在eucalyptus中,eucalyptus_auth数据库中,表auth_users定义如下:

id varchar(255) NO PRI NULL
last_update_timestamp datetime YES   NULL
version int(11) YES   NULL
auth_user_is_admin bit(1) YES    NULL
auth_user_is_enabled bit(1)  YES   NULL
auth_user_name varchar(255) YES UNI NULL
auth_user_password varchar(255)  YES   NULL
auth_user_query_id varchar(255) YES   NULL
auth_user_secretkey  varchar(255) YES   NULL
auth_user_token varchar(255) YES   NULL


             
 

 

 

 

 

 

 



其中,字段auth_user_is_admin,auth_user_is_enabled为bit(1)类型,在django通过数据库产生的model中,定义如下:

class AuthUsers(models.Model):
id = models.CharField(max_length=765, primary_key=True)
last_update_timestamp = models.DateTimeField(null=True, blank=True)
version = models.IntegerField(null=True, blank=True)
auth_user_is_admin = models.TextField(blank=True) # This field type is a guess
auth_user_is_enabled = models.TextField(blank=True) # This field type is a guess.
auth_user_name = models.CharField(unique=True, max_length=765, blank=True)
auth_user_password = models.CharField(max_length=765, blank=True)
auth_user_query_id = models.CharField(max_length=765, blank=True)
auth_user_secretkey = models.CharField(max_length=765, blank=True)
auth_user_token = models.CharField(max_length=765, blank=True)
class Meta:
db_table = u'auth_users'


django 无法识别mysql中的bit类型,如它的注释:This field type is a guess。在将其更改为 models.BooleanField()后,在检索数据时,无法直接通过if self.auth_user_is_admin进行bool的判断, 无论数据库中auth_user_is_admin是0或是1,if判断均为true,通过添加if ord(self.auth_user_is_admin):来对值进行转换,一切正常了。

posted @ 2012-01-13 23:43 hanxiangduo 阅读(146) 评论(0) 编辑

将eucalyptus数据库更改为Mysql

简介
项目中用到了eucalyptus的东西,在eucalyptus中,数据库采用的是hsqldb,一种轻量级的小型数据库,eucalyptu将其紧密地集成在系统当中。若是从外部访问eucalyptus数据信息,感觉颇为不便。故考虑将eucalyptu的数据库从hsqldb迁移到mysql中。这样的话,从外部可以很方便地访问需要的信息。下面介绍更改的过程,如有需要可以参考。

相关文件介绍
 eucalyptus中,访问数据库的部分采用了hibernate的封装,由hibernate屏蔽了底层数据库的差异性,因而在由hsqldb迁移到mysql中,无需对系统作出大的改动即可迁移成功。
在eucalyptu中,与数据库配置以及初始化相关的文件有:

1 clc/modules/database/conf/scripts/before_database.groovy
2 clc/modules/database/conf/scripts/after_database.groovy
3 clc/modules/database/conf/scripts/pools.groovy
4 clc/modules/database/conf/scripts/caches.groovy

上述的四个groovy文件是关于eucalyptu使用的数据库的初始化脚本,以及关于hibernate的配置,线程池的一些配置优化。
clc/modules/database/src/main/java/com/eucalyptus/bootstrap/LocalDatabaseBootstrapper.java
该文件是Database的的初始化过程,在其中通过调用上述的四个脚本文件完成eucalyptus的数据库的初始化操作,并且启动数据库服务。其服务的基本启动过程与其它eucalyptus服务启动类似,必须实现一些统一的Bootstrapper接口。
clc/modules/database/src/main/java/com/eucalyptus/bootstrap/DatabaseConfig.java
该文件是原始hsqldb数据库服务的基本配置,包括端口、数据库文件等。如果更换成mysql后,该文件没有存在的必要,可以删掉。
clc/modules/hsqldb/src/main/resources/com.eucalyptus.CloudServiceProvider
eucalyptus是以组件的形式,也就是component的方式连接建立起来的,上述文件就是关于db component的配置,其中有component的一些服务port和url等信息。比如此处要修改的数据库服务信息等。
clc/modules/core/src/main/java/com/eucalyptus/bootstrap/RemoteDatabaseBootstrapper.java
该文件不知道要作何用,但是其中有关于数据库密码的一些信息,直接设置到了eucalyptus运行环境的property中。这个property在pools.groovy中有用到,用于设置一些关于hibernate的信息,因而也需要对该文件进行一些简单的处理。

数据库初始化过程
上边是一些要用到可能需要修改的文件,在eucalyptus中,数据库的初始化过程简单介绍如下,基于自己理解,可能会有错误。clc/modules/msgs/src/main/java/com/eucalyptus/bootstrap/Bootstrap.java,这是clc java部分引导启动之后的第一个实例。执行component的初始化过程,初始化过程包括eucalyptus的服务的发现、加载、启动,各个component的初始化,配置文件的加载,其中包括LocalDatabaseBootstrapper服务,也就是在此处,对clc/modules/hsqldb/src/main/resources/com.eucalyptus.CloudServiceProvider的资源文件进行加载处理,并对component db做了初始化处理,其中包括db的url初始化,这是一个比较关键的信息。也只有在该url被完成之后,后续的hibernate对数据库进行初始化才可以进行。
在db component初始化完成后,剩余的将会交给hibernate进行数据库的初始化操作了。对数据库的初始化操作,主要集中在clc/modules/database/src/main/java/com/eucalyptus/bootstrap/LocalDatabaseBootstrapper.java,在bootstrapper中,对数据库的操作主要集中在load中的createDatabase,也就是在其中,执行上述的before_database.groovy、after_database.groovy,在脚本中完成对数据库的操作。

用到的基本原理
基于上述的一些服务启动过程解释,也就是只需要修改上述的一些文件就可以了。这其中需要了解的一些原理包括hibernate的annotation,groovy的lamba表达式,向groovy中变量参数的传递,数据库的连接池配置,hibernate连接数据库的property配置,mysql创建数据库的规则。此处不再赘述。可以通过详细的更改迁移过程了解。

具体改动过程
下面介绍具体实施中的改动过程:
具体的更改详细过程如下:
1、对com.eucalyptus.CloudServiceProvider进行更改配置

name=db 表示对应的component
euca.model.dns=db-model.xml 貌似是mule使用的xml配置文件
euca.model.dns.services=db-services.xml 貌似是mule使用的xml配置文件
euca.url.local=//127.0.0.1:3306/eucalyptus mysql数据库的url配置
euca.url.pattern=//%s:%d/eucalyptus url的匹配模式
euca.url.port=3306 mysql的默认端口
此处更改的文件在clc/modules/hsqldb/src/main/resources/com.eucalyptus.CloudServiceProvider

2、更改LocalDatabaseBootstrapper的实现
修改借口的实现包括start、run。在该类的实现中,主要是删除一些不必要的功能。
修改的文件在clc/modules/database/src/main/java/com/eucalyptus/bootstrap/LocalDatabaseBootstrapper.java

3、修改初始化groovy脚本
有一部分是直接借用于原来的脚本,并对此作出了部分更改。

下面是before_database.groovy脚本,先在mysql中创建好数据库

import com.eucalyptus.system.SubDirectory;
import com.eucalyptus.entities.PersistenceContexts;
import com.eucalyptus.bootstrap.Component;
import com.eucalyptus.util.*;

//init the db setting
//set the mysql char set to utf8
config ="default-character-set=utf8\ndefault-collation=utf8"
//此处是关于mysql的数据库初始化的一些基本配置,此处将其设置为utf8
//此处经过测试汉语不会出现乱码
//create the db file name create the new db file
//through the anonation from the db
Runtime runtime = null;
try
{
runtime = Runtime. getRuntime();
}
catch(Exception e)
{
e.printStackTrace();
System.exit(1)
}
//获取运行时用于更改创建的文件夹权限,以便mysql有权限进行读写操作
//此处采用的是执行linux命令的方式,java内部的api目前无法实现该功能
//此处是hibernate通过java的annotation获取到需要建立的数据库信息以及表的信息
//具体可以参考clc/modules/msgs/arc/main/java/com/eucalyptus/entities中的具体实现文件
PersistenceContexts.list( ).each{ context_name ->
db = new File("${SubDirectory.DB.toString()}/${context_name}");
opt = new File("${SubDirectory.DB.toString()}/${context_name}/db.opt");
//the db not exist create the db
if( !db.exists() ) {
db.mkdir();
//the mysql db.opt conf not exist
if( !opt.exists() ) {
opt.write(config);
}
//在mysql数据库中,创建一个空的数据库的一个简便方法就是在mysql的data文件夹下
//创建对应的数据库名字的文件夹即可,在该文件夹下的db.opt主要是用于配置该数据库的
//一些编码规则,规则比较简单,此处将编码配置为utf8
command = "chmod 777 -R " + "${SubDirectory.DB.toString()}/${context_name}";
try
{
runtime. exec(command);
//change the eucalyptus db file permission to mysql
}
catch(Exception e)
{
e.printStackTrace();
System.exit(1)
}
//在创建完成后,这些文件权限是755,属于eucalyptus用户所有
//mysql根本没有权限进行写入,会造成后期的table创建错误
//因此需要将权限开放给mysql用户
}
}




after_database.groovy脚本,完成对数据库中table表的创建

import com.eucalyptus.entities.PersistenceContexts;
import org.hibernate.ejb.*
import com.eucalyptus.util.*
import edu.ucsb.eucalyptus.cloud.ws.*;
//conf hibernate
//这是hibernate的一些property配置
hiber_config = [
'hibernate.archive.autodetection': 'jar, class, hbm',
'hibernate.show_sql': 'false',
'hibernate.format_sql': 'false',
'hibernate.connection.autocommit': 'true',
'hibernate.hbm2ddl.auto': 'update',
'hibernate.generate_statistics': 'true',
]

contexts = PersistenceContexts.list( );//list the db
//上述的contexts是数据库名列表,在before_database.groovy中已经使用过,
//列出的数据库已经创建完成了
//下面就是创建数据库中表的过程

contexts.each { String ctxName ->
String it = ctxName.replaceAll("eucalyptus_","")
pool_config = new pools(new Binding([context_name:it])).run()
//设置对应的数据库连接池
//正常情况下,每一个数据库对应一个独立的url
//比如eucalyptus_auth和eucalyptus_general分别对应的url是:
////127.0.0.1:3306/eucalyptus_auth”和“//127.0.0.1:3306/eucalyptus_general”
//通过传入pool.groovy中的 context_name进行对应连接池中url的设置

cache_config = new caches(new Binding([context_name:it])).run()
//这是hibernate的缓存设置,没有特别特殊的地方

config = new Ejb3Configuration();
LogUtil.logHeader( "Hibernate for ${ctxName}" ).log(hiber_config.inspect())
hiber_config.each { k, v -> config.setProperty(k, v) }
LogUtil.logHeader( "Pool for ${ctxName}").log( pool_config.inspect() )
pool_config.each { k, v -> config.setProperty(k, v) }
LogUtil.logHeader( "Cache for ${ctxName}").log( cache_config )
cache_config.each { k, v -> config.setProperty(k, v) }
entity_list = PersistenceContexts.listEntities( ctxName )
LogUtil.logHeader("Entities for ${ctxName}")
entity_list.each{ ent ->
LogUtil.log( ent.toString() )
config.addAnnotatedClass( ent )
}
//获取数据库所包含的表,此处通过annotation标记,只需知道对应table的类就可以
try {
PersistenceContexts.registerPersistenceContext("${ctxName}", config)
//注册table,并进行table的创建
} catch( Throwable t ) {
t.printStackTrace();
System.exit(1)
}
}



关于pools.groovy,主要就是上边提到的连接代理的问题,更改后的代码如下:

import com.eucalyptus.bootstrap.Component;
import org.logicalcobwebs.proxool.ProxoolFacade;
import com.eucalyptus.util.LogUtil;
//set hibernate username and passwd

db_pass = System.getProperty("euca.db.password")!=null && System.getProperty("euca.db.password").length()>1 ? System.getProperty("euca.db.password") : "123456";
//此处连接用的用户名暂设为root,密码为“123456”
ClassLoader.getSystemClassLoader().loadClass('org.logicalcobwebs.proxool.ProxoolDriver');
poolProps = [
'proxool.simultaneous-build-throttle': '16',
'proxool.minimum-connection-count': '16',
'proxool.maximum-connection-count': '128',
'proxool.house-keeping-test-sql': 'SELECT * FROM COUNTERS;',
'user': 'root',
'password': db_pass,
]

//set hibernate pool conf
p = new Properties();
p.putAll(poolProps)
String dbDriver = 'com.mysql.jdbc.Driver';

//set the proxool url
//just like mysql url jdbc:mysql://localhost:3306/db_name

String url = "proxool.eucalyptus_${context_name}:${dbDriver}:jdbc:mysql:${Component.db.uri.toASCIIString( )}_${context_name}";

//此处用到了db component的url信息
//context_name pass from after_database
LogUtil.logHeader( "Proxool config for ${context_name}" ).log( url ).log( poolProps )
ProxoolFacade.registerConnectionPool(url, p);

[
'hibernate.bytecode.use_reflection_optimizer': 'true',
'hibernate.cglib.use_reflection_optimizer': 'true',
'hibernate.dialect': 'org.hibernate.dialect.MySQLDialect',
'hibernate.connection.provider_class': 'org.hibernate.connection.ProxoolConnectionProvider',
'hibernate.proxool.pool_alias': "eucalyptus_${context_name}",
'hibernate.proxool.existing_pool': 'true'
]

4、RemoteDatabaseBootstrapper 的修改
在 RemoteDatabaseBootstrapper中,在服务加载的过程中,设置了eucalyptus的"euca.db.password"property,此处设置的password在pool中需要用到,并且为了扩展需要,密码也需要在mysql中进行设置,故没有在此处设置属性,只是在clc/modules/core/src/main/java/com/eucalyptus/bootstrap/RemoteDatabaseBootstrapper.java的81行,去掉了该设置语句。

5、添加必需的mysql jdbc包
由于连接mysql需要的对应的jdbc包,因而在clc的lib下添加了mysql-connector-java-5.1.18-bin.jar包,此包可以在mysql的官网下载.
6、修改eucalyptus中的euca_conf中的一些关于用户id的一些获取方法。也就是通过读数据库而已,比较简单。


 

更改后需要进行的系统配置:
1、首先配置mysql的 datadir和 max_connections
mysql的数据目录配置,在/etc/my.cnf文件中

    [mysqld]
datadir=/$EUCALYPTUS/eucalyptus/db
socket=/var/lib/mysql/mysql.sock
user=mysql
max_connections = 200

在eucalyptus首次安装后,进行自动化配置时,需要将 datadir的目录设置到eucalyptus的db目录下;同时 max_connections也必须设置,默认为101,但是在eucalyptus的连接池中配置为126,如果不进行修改,会造成数据库无法连接读取,出现异常。
2、配置mysql后,重新启动mysql数据库
/etc/init.d/mysqld restart
以将mysql的数据文件定位到设置好的目录下
3、设置mysql的用户名和密码
目前暂时用的是root:123456,密码可以通过 mysqladmin -u root password "123456",将其设置为 123456,当然密码也可以设置为其它,但是应当与/$EUCALYPTUS/etc/eucalyptus/cloud.d/scripts/pools.groovy中的密码相匹配。
但是这仅限于初次mysql的密码设置。
4、mysql重新启动后,修改eucalyptus的db目录权限
chmod 777 /$EUCALYPTUS/eucalyptus/db

 由于mysql服务重新启动后,会将db的权限更改为755,并且db文件夹属于mysql。如果不进行权限设置,在eucalyptus初次启动时没有权限向该文件夹下写数据。
至此eucalyptus的初始化配置已经基本完成,并且mysql或是eucalyptus的重启不会再有文件权限的困扰。当然,这些还需要更多环境的测试。
如果删除了db下的数据库文件,并且mysql重新启动过,则需要进行上述步骤4的操作。
如果eucalyptus进行重装,则基本配置过程同上述类似。


 

经过上边的过程,已经基本算是完结了。由于linux用户权限的问题,在使用的过程中上述的更改可能会造成使用不便。如果需要的话,可以考虑将db数据库目录与eucalyptus单独分开来,这样就不会有用户权限的困扰了。

上述的过程已经经过测试,并且可用。有需要的朋友可以参考下。

posted @ 2012-01-13 23:08 hanxiangduo 阅读(129) 评论(0) 编辑