openstack源码解析之虚机修改密码
2017-07-04 10:23
204 查看
本次以修改centos操作系统虚机密码为例,给大家从源码级别讲解整个流程,希望对大家有所帮助。
修改密码的本质,就是修改对应的passwd和shadow文件,并且将修改后的文件注入到实例的镜像中。
来看下具体流程:
1,请求提交到了nova-api(nova/api/openstack/compute/server.py):
def _action_change_password(self, req, id, body):
...
self.compute_api.set_admin_password(context, server,
password, meta_item) ##请求发到对应的compute节点上执行set_admin_password操作
2,compute节点执行重置密码操作(nova/compute/manager.py):
def set_admin_password(self, context, instance, new_pass):
... ##获取信息,并且设置下数据库状态
self.driver.set_admin_password(context,
instance, network_info, new_pass) ##告诉driver,执行set_admin_password操作。
if current_power_state == power_state.RUNNING and \
inst_power_state == power_state.SHUTDOWN:
self._power_on(context, instance) ##判断执行的实例是否已经关机,关机的话,执行开机操作。
....
3,驱动执行设置密码,这里我用的是libvirt (nova/virt/libvirt/driver.py)
def set_admin_password(self, context, instance, network_info, admin_pass):
if instance.power_state != power_state.SHUTDOWN:
self.shutdown(instance) ##首先要执行关机操作,文件注入,需要关机。
...
##获取镜像路径。这里是injection_path = instance_path + '/disk'
disk.inject_data(image=injection_path,
admin_password=admin_pass,
partition=target_partition,
use_cow=CONF.use_cow_images,
mandatory=('files',)) ##执行注入操作
...
4,执行具体的操作 (nova/virt/disk/api.py)
def inject_data(image, key=None, net=None, metadata=None, admin_password=None,
files=None, partition=None, use_cow=False, mandatory=()):
...
fs = vfs.VFS.instance_for_image(image, fmt, partition)
首先来看语句fs = vfs.VFS.instance_for_image(image, fmt, partition),方法instance_for_image实现了尝试导入guestfs模块;如果guestfs模块导入成功,则继而导入类nova.virt.disk.vfs.guestfs.VFSGuestFS;如果guestfs模块导入不成功,则继而导入类nova.virt.disk.vfs.localfs.VFSLocalFS;从而实现了选择不同的文件系统类型(本地文件系统或来宾文件系统)对磁盘镜像的操作实现类;具体来看方法instance_for_image的代码实现
fs.setup()
==========================================================
这里我们来看下VFSGuestFS:
def setup(self):
self.handle = tpool.Proxy(guestfs.GuestFS(close_on_exit=False))
## 其中guestfs.GuestFS是一个c接口,作用是对一个image的操作,对image的读写,即对文件系统文件的读写。初始化的时候加载的
guestfs = __import__('guestfs')
我们接下来看下inject_data_into_fs这个方法
for inject in ('key', 'net', 'metadata', 'admin_password', 'files'):
inject_val = locals()[inject]
inject_func = globals()['_inject_%s_into_fs' % inject]
if inject_val:
try:
inject_func(inject_val, fs) ###直接跳转到def _inject_admin_password_into_fs(admin_passwd, fs)这个方法
注:这里采用字符串匹配的方式,分不同的情况调用不同的方法,来实现不同类型文件的注入,调用的具体方法有:
_inject_files_into_fs
_inject_metadata_into_fs
_inject_key_into_fs
_inject_net_into_fs
_inject_admin_password_into_fs
这里我们传入admin_password,所以调用的是_inject_admin_password_into_fs
5, 看下_inject_admin_password_into_fs
passwd_path = os.path.join('etc', 'passwd')
shadow_path = os.path.join('etc', 'shadow')
passwd_data = fs.read_file(passwd_path)
shadow_data = fs.read_file(shadow_path)
new_shadow_data = _set_passwd(admin_user, admin_passwd,
passwd_data, shadow_data)
### 读取/etc/passwd和/etc/shadow的内容,针对新的用户密码,替换之前的数据。
6,设置密码的方式
在现在的linux和unix系统中,用户的密码都保存在shadow文件中,因为密码关系到系统的安全,所以只有root用户才有读shadow文件的权
限。shadow中存放的内容是有着一定的格式的,看如下例子:
root:$1$v2wT9rQF$XSpGgoB93STC4EFSlgpjg1:14181:0:99999:7:::
冒号是分割符,分别代表着,每个字段分别代表着:
:用户名
:密码hash值
:密码修改距离1970年1月1日的时间
:密码将被允许修改之前的天数(0 表示“可在任何时间修改”)
:系统将强制用户修改为新密码之前的天数(1 表示“永远都不能修改”)
:密码过期之前,用户将被警告过期的天数(-1 表示“没有警告”)
:密码过期之后,系统自动禁用帐户的天数(-1 表示“永远不会禁用”)
:该帐户被禁用的天数(-1 表示“该帐户被启用”)
7,根据算法生成了新的数据,调用fs.replace_file(shadow_path,
new_shadow_data)
/nova/virt/disk/vfs/guestfs.py
def replace_file(self, path, content):
LOG.debug(_("Replace file path=%(path)s") % locals())
path = self._canonicalize_path(path)
self.handle.write(path, content)
##将内容写入对应文件。还有一个方法是append,是将内容写到最末尾,叫append_file。
8,如果出现重置密码失败,分享一个有用的方法:
guestmount -a disk -m /dev/vda1 --rw /mnt/ ##将系统映射到文件中
chroot /mnt/ /bin/sh ##会出来一个命令行,直接可以执行passwd .
umount /mnt/
好了,分享到此结束,大家有什么疑问,可以评论中提出,我会尽早回复大家!
修改密码的本质,就是修改对应的passwd和shadow文件,并且将修改后的文件注入到实例的镜像中。
来看下具体流程:
1,请求提交到了nova-api(nova/api/openstack/compute/server.py):
def _action_change_password(self, req, id, body):
...
self.compute_api.set_admin_password(context, server,
password, meta_item) ##请求发到对应的compute节点上执行set_admin_password操作
2,compute节点执行重置密码操作(nova/compute/manager.py):
def set_admin_password(self, context, instance, new_pass):
... ##获取信息,并且设置下数据库状态
self.driver.set_admin_password(context,
instance, network_info, new_pass) ##告诉driver,执行set_admin_password操作。
if current_power_state == power_state.RUNNING and \
inst_power_state == power_state.SHUTDOWN:
self._power_on(context, instance) ##判断执行的实例是否已经关机,关机的话,执行开机操作。
....
3,驱动执行设置密码,这里我用的是libvirt (nova/virt/libvirt/driver.py)
def set_admin_password(self, context, instance, network_info, admin_pass):
if instance.power_state != power_state.SHUTDOWN:
self.shutdown(instance) ##首先要执行关机操作,文件注入,需要关机。
...
##获取镜像路径。这里是injection_path = instance_path + '/disk'
disk.inject_data(image=injection_path,
admin_password=admin_pass,
partition=target_partition,
use_cow=CONF.use_cow_images,
mandatory=('files',)) ##执行注入操作
...
4,执行具体的操作 (nova/virt/disk/api.py)
def inject_data(image, key=None, net=None, metadata=None, admin_password=None,
files=None, partition=None, use_cow=False, mandatory=()):
...
fs = vfs.VFS.instance_for_image(image, fmt, partition)
首先来看语句fs = vfs.VFS.instance_for_image(image, fmt, partition),方法instance_for_image实现了尝试导入guestfs模块;如果guestfs模块导入成功,则继而导入类nova.virt.disk.vfs.guestfs.VFSGuestFS;如果guestfs模块导入不成功,则继而导入类nova.virt.disk.vfs.localfs.VFSLocalFS;从而实现了选择不同的文件系统类型(本地文件系统或来宾文件系统)对磁盘镜像的操作实现类;具体来看方法instance_for_image的代码实现
fs.setup()
==========================================================
这里我们来看下VFSGuestFS:
def setup(self):
self.handle = tpool.Proxy(guestfs.GuestFS(close_on_exit=False))
## 其中guestfs.GuestFS是一个c接口,作用是对一个image的操作,对image的读写,即对文件系统文件的读写。初始化的时候加载的
guestfs = __import__('guestfs')
我们接下来看下inject_data_into_fs这个方法
for inject in ('key', 'net', 'metadata', 'admin_password', 'files'):
inject_val = locals()[inject]
inject_func = globals()['_inject_%s_into_fs' % inject]
if inject_val:
try:
inject_func(inject_val, fs) ###直接跳转到def _inject_admin_password_into_fs(admin_passwd, fs)这个方法
注:这里采用字符串匹配的方式,分不同的情况调用不同的方法,来实现不同类型文件的注入,调用的具体方法有:
_inject_files_into_fs
_inject_metadata_into_fs
_inject_key_into_fs
_inject_net_into_fs
_inject_admin_password_into_fs
这里我们传入admin_password,所以调用的是_inject_admin_password_into_fs
5, 看下_inject_admin_password_into_fs
passwd_path = os.path.join('etc', 'passwd')
shadow_path = os.path.join('etc', 'shadow')
passwd_data = fs.read_file(passwd_path)
shadow_data = fs.read_file(shadow_path)
new_shadow_data = _set_passwd(admin_user, admin_passwd,
passwd_data, shadow_data)
### 读取/etc/passwd和/etc/shadow的内容,针对新的用户密码,替换之前的数据。
6,设置密码的方式
在现在的linux和unix系统中,用户的密码都保存在shadow文件中,因为密码关系到系统的安全,所以只有root用户才有读shadow文件的权
限。shadow中存放的内容是有着一定的格式的,看如下例子:
root:$1$v2wT9rQF$XSpGgoB93STC4EFSlgpjg1:14181:0:99999:7:::
冒号是分割符,分别代表着,每个字段分别代表着:
:用户名
:密码hash值
:密码修改距离1970年1月1日的时间
:密码将被允许修改之前的天数(0 表示“可在任何时间修改”)
:系统将强制用户修改为新密码之前的天数(1 表示“永远都不能修改”)
:密码过期之前,用户将被警告过期的天数(-1 表示“没有警告”)
:密码过期之后,系统自动禁用帐户的天数(-1 表示“永远不会禁用”)
:该帐户被禁用的天数(-1 表示“该帐户被启用”)
7,根据算法生成了新的数据,调用fs.replace_file(shadow_path,
new_shadow_data)
/nova/virt/disk/vfs/guestfs.py
def replace_file(self, path, content):
LOG.debug(_("Replace file path=%(path)s") % locals())
path = self._canonicalize_path(path)
self.handle.write(path, content)
##将内容写入对应文件。还有一个方法是append,是将内容写到最末尾,叫append_file。
8,如果出现重置密码失败,分享一个有用的方法:
guestmount -a disk -m /dev/vda1 --rw /mnt/ ##将系统映射到文件中
chroot /mnt/ /bin/sh ##会出来一个命令行,直接可以执行passwd .
umount /mnt/
好了,分享到此结束,大家有什么疑问,可以评论中提出,我会尽早回复大家!
相关文章推荐
- openstack源码解析之虚机创建
- OpenStack建立实例完整过程源码详细分析(13)----依据AMQP通信架构实现消息发送机制解析之二
- launcher修改--获取应用列表launcher源码解析
- OpenStack Nova-scheduler组件的源码解析(2)
- OpenStack Neutron LoadBalance源码解析(一)
- OpenStack之虚机热迁移代码解析
- 传智播客strus2源码解析~~~超NBstruts2错误提示位置修改--环境搭建
- 修改openstack Ubuntu镜像的默认用户的密码
- Openstack Cinder中建立volume过程的源码解析(6)----以及taskflow相关解析
- Openstack Cinder中建立volume过程的源码解析(5)----以及taskflow相关解析
- mysql创建用户、删除用户、创建root用户和修改用户密码,grant分配权限,查询测试,以及库中授权表解析
- xerces C++ 解析Utf8 xml中的非UTF 8字符。修改xerces源码XMLUTF8Transcoder.cpp
- OpenStack Nova-scheduler组件的源码解析(1)
- OpenStack建立实例完整过程源码详细分析(15)----依据AMQP通信架构实现消息接收机制解析之二
- Openstack Cinder中建立volume过程的源码解析(9)
- OpenStack Swift源码分析(5)----swift-ring-builder源代码解析之二
- OpenStack建立实例完整过程源码详细分析(12)----依据AMQP通信架构实现消息发送机制解析之一
- launcher修改--获取应用列表launcher源码解析
- (六)SSO之CAS框架扩展 修改CAS源码实现与ESS动态密码验证对接
- Android图案密码,手势锁源码解析