分享

Swift源码分析----swift-account-audit(2)

tntzbzc 发表于 2014-11-20 15:35:01 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 12775
本帖最后由 xioaxu790 于 2014-11-20 21:10 编辑
问题导读

1、如何实现递归验证container下每个object?
2、如何对账户的所有副本相关节点,进行遍历?
3、怎样 递归调用方法audit_container实现审计验证账户?





接续上篇:Swift源码分析----swift-account-audit(1)
转到3.2,来看方法audit_container的实现:
  1. def audit_container(self, account, name, recurse=False):
  2.         """
  3.         指定container的审计验证,并实现递归验证container下每个object;
  4.         """
  5.         if (account, name) in self.in_progress:
  6.             self.in_progress[(account, name)].wait()
  7.         if (account, name) in self.list_cache:
  8.             return self.list_cache[(account, name)]
  9.         self.in_progress[(account, name)] = Event()
  10.         print 'Auditing container "%s"' % name
  11.         
  12.         # # 指定指定account下的容器具体路径;
  13.         path = '/%s/%s' % (account, name)
  14.         
  15.         # 获取指定account下的容器列表;
  16.         account_listing = self.audit_account(account)
  17.         
  18.         consistent = True
  19.         if name not in account_listing:
  20.             consistent = False
  21.             print "  Container %s not in account listing!" % path
  22.         
  23.         # 获取指定name容器的所有副本的相关节点和分区号;
  24.         # 获取account/container/object所对应的分区号和节点(可能是多个,因为分区副本有多个,可能位于不同的节点上);
  25.         # 返回元组(分区,节点信息列表);
  26.         # 在节点信息列表中至少包含id、weight、zone、ip、port、device、meta;
  27.         part, nodes = self.container_ring.get_nodes(account, name.encode('utf-8'))
  28.         rec_d = {}
  29.         responses = {}
  30.         for node in nodes:
  31.             marker = ''
  32.             results = True
  33.             while results:
  34.                 try:
  35.                     conn = http_connect(node['ip'], node['port'],
  36.                                         node['device'], part, 'GET',
  37.                                         path.encode('utf-8'), {},
  38.                                         'format=json&marker=%s' %
  39.                                         quote(marker.encode('utf-8')))
  40.                     # 获取来自服务器的响应;
  41.                     resp = conn.getresponse()
  42.                     if resp.status // 100 != 2:
  43.                         self.container_not_found += 1
  44.                         consistent = False
  45.                         print('  Bad status GETting container "%s" on %s/%s' %
  46.                               (path, node['ip'], node['device']))
  47.                         break
  48.                     
  49.                     if node['id'] not in responses:
  50.                         responses[node['id']] = dict(resp.getheaders())
  51.                     results = simplejson.loads(resp.read())
  52.                 except Exception:
  53.                     self.container_exceptions += 1
  54.                     consistent = False
  55.                     print '  Exception GETting container "%s" on %s/%s' % \
  56.                         (path, node['ip'], node['device'])
  57.                     break
  58.                 if results:
  59.                     marker = results[-1]['name']
  60.                     for obj in results:
  61.                         obj_name = obj['name']
  62.                         if obj_name not in rec_d:
  63.                             rec_d[obj_name] = obj
  64.                         if (obj['last_modified'] !=
  65.                                 rec_d[obj_name]['last_modified']):
  66.                             self.container_obj_mismatch += 1
  67.                             consistent = False
  68.                             print("  Different versions of %s/%s "
  69.                                   "in container dbs." % (name, obj['name']))
  70.                             if (obj['last_modified'] >
  71.                                     rec_d[obj_name]['last_modified']):
  72.                                 rec_d[obj_name] = obj
  73.         obj_counts = [int(header['x-container-object-count'])
  74.                       for header in responses.values()]
  75.         if not obj_counts:
  76.             consistent = False
  77.             print "  Failed to fetch container %s at all!" % path
  78.         else:
  79.             if len(set(obj_counts)) != 1:
  80.                 self.container_count_mismatch += 1
  81.                 consistent = False
  82.                 print "  Container databases don't agree on number of objects."
  83.                 print "  Max: %s, Min: %s" % (max(obj_counts), min(obj_counts))
  84.         self.containers_checked += 1
  85.         self.list_cache[(account, name)] = rec_d
  86.         self.in_progress[(account, name)].send(True)
  87.         del self.in_progress[(account, name)]
  88.         
  89.         # 递归验证container下每个object;
  90.         if recurse:
  91.             for obj in rec_d.keys():
  92.                 self.pool.spawn_n(self.audit_object, account, name, obj)
  93.         if not consistent and self.error_file:
  94.             print >>open(self.error_file, 'a'), path
  95.         return rec_d3.2.1 获取指定account下的容器具体路径;
复制代码

3.2.2 调用方法audit_account实现获取指定account下的容器列表,验证当前指定容器是否包含其中;
3.2.3 获取指定name容器的所有副本的相关节点和分区号;
3.2.4 针对容器的所有副本相关节点,进行遍历,对于每个节点执行以下操作:
      通过HTTP应用GET方法远程获取节点的验证响应信息,通过响应信息的状态值,判断远程节点副本容器是否存在;
3.2.5 递归调用方法audit_object实现审计验证容器下每个object;

转到3.3,来看方法audit_account的实现:
  1. def audit_account(self, account, recurse=False):
  2.         """
  3.         指定account的审计验证,并实现递归验证account下每个container,并且进一步实现递归验证container下每个object;
  4.         """
  5.         if account in self.in_progress:
  6.             self.in_progress[account].wait()
  7.         if account in self.list_cache:
  8.             return self.list_cache[account]
  9.         self.in_progress[account] = Event()
  10.         print 'Auditing account "%s"' % account
  11.         consistent = True
  12.         path = '/%s' % account
  13.         
  14.         # 获取指定name账户的所有副本的相关节点和分区号;
  15.         # 获取account所对应的分区号和节点(可能是多个,因为分区副本有多个,可能位于不同的节点上);
  16.         # 返回元组(分区,节点信息列表);
  17.         # 在节点信息列表中至少包含id、weight、zone、ip、port、device、meta;
  18.         part, nodes = self.account_ring.get_nodes(account)
  19.         
  20.         responses = {}
  21.         for node in nodes:
  22.             marker = ''
  23.             results = True
  24.             while results:
  25.                 node_id = node['id']
  26.                 try:   
  27.                     # 建立一个HTTPConnection类的对象;
  28.                     # 并获取来自服务器的响应信息;
  29.                     conn = http_connect(node['ip'], node['port'],
  30.                                         node['device'], part, 'GET', path, {},
  31.                                         'format=json&marker=%s' %
  32.                                         quote(marker.encode('utf-8')))
  33.                     resp = conn.getresponse()
  34.                     if resp.status // 100 != 2:
  35.                         self.account_not_found += 1
  36.                         consistent = False
  37.                         print("  Bad status GETting account '%s' "
  38.                               " from %ss:%ss" %
  39.                               (account, node['ip'], node['device']))
  40.                         break
  41.                     results = simplejson.loads(resp.read())   
  42.                 except Exception:
  43.                     self.account_exceptions += 1
  44.                     consistent = False
  45.                     print("  Exception GETting account '%s' on %ss:%ss" %
  46.                           (account, node['ip'], node['device']))
  47.                     break
  48.                
  49.                 if node_id not in responses:
  50.                     responses[node_id] = [dict(resp.getheaders()), []]
  51.                 responses[node_id][1].extend(results)
  52.                 if results:
  53.                     marker = results[-1]['name']
  54.         
  55.         headers = [resp[0] for resp in responses.values()]
  56.         cont_counts = [int(header['x-account-container-count'])
  57.                        for header in headers]
  58.         if len(set(cont_counts)) != 1:
  59.             self.account_container_mismatch += 1
  60.             consistent = False
  61.             print("  Account databases for '%s' don't agree on"
  62.                   " number of containers." % account)
  63.             if cont_counts:
  64.                 print "  Max: %s, Min: %s" % (max(cont_counts),
  65.                                               min(cont_counts))
  66.         obj_counts = [int(header['x-account-object-count'])
  67.                       for header in headers]
  68.         if len(set(obj_counts)) != 1:
  69.             self.account_object_mismatch += 1
  70.             consistent = False
  71.             print("  Account databases for '%s' don't agree on"
  72.                   " number of objects." % account)
  73.             if obj_counts:
  74.                 print "  Max: %s, Min: %s" % (max(obj_counts),
  75.                                               min(obj_counts))
  76.         containers = set()
  77.         for resp in responses.values():
  78.             containers.update(container['name'] for container in resp[1])
  79.         self.list_cache[account] = containers
  80.         self.in_progress[account].send(True)
  81.         del self.in_progress[account]
  82.         self.accounts_checked += 1
  83.         if recurse:
  84.             for container in containers:
  85.                 self.pool.spawn_n(self.audit_container, account,
  86.                                   container, True)
  87.         if not consistent and self.error_file:
  88.             print >>open(self.error_file, 'a'), path
  89.         return containers3.3.1 获取指定账户的具体路径;
复制代码

3.3.2 获取指定name账户的所有副本的相关节点和分区号;
3.3.4 针对账户的所有副本相关节点,进行遍历,对于每个节点执行以下操作:
      通过HTTP应用GET方法远程获取节点的验证响应信息,通过响应信息的状态值,判断远程副本账户是否存在;
3.3.5 递归调用方法audit_container实现审计验证账户下每个container;
至此,这个脚本的账户/容器/脚本的审计验证流程分析完成,当然在具体审计验证过程中还有很多其他细节,这里不再赘述。

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条