Chinaunix首页 | 论坛 | 博客
  • 博客访问: 10168179
  • 博文数量: 1669
  • 博客积分: 16831
  • 博客等级: 上将
  • 技术积分: 12594
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-25 07:23
个人简介

柔中带刚,刚中带柔,淫荡中富含柔和,刚猛中荡漾风骚,无坚不摧,无孔不入!

文章分类

全部博文(1669)

文章存档

2023年(4)

2022年(1)

2021年(10)

2020年(24)

2019年(4)

2018年(19)

2017年(66)

2016年(60)

2015年(49)

2014年(201)

2013年(221)

2012年(638)

2011年(372)

分类: 系统运维

2017-08-06 11:01:43

openstack源码解析之虚机修改密码
http://blog.csdn.net/weixin_39400463/article/details/74294472


标签: openstacknova修改密码源码云计算
2017-07-04 10:23 35人阅读 评论(0) 收藏 举报
 分类: openstack(2)  
版权声明:本文为博主原创文章,未经博主允许不得转载。


本次以修改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/ 




好了,分享到此结束,大家有什么疑问,可以评论中提出,我会尽早回复大家!


       
阅读(1611) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~