tracker_client.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # filename: tracker_client.py
  4. import struct
  5. import socket
  6. from datetime import datetime
  7. from fdfs_client.fdfs_protol import *
  8. from fdfs_client.connection import *
  9. from fdfs_client.exceptions import (
  10. FDFSError,
  11. ConnectionError,
  12. ResponseError,
  13. InvaildResponse,
  14. DataError
  15. )
  16. from fdfs_client.utils import *
  17. def parse_storage_status(status_code):
  18. try:
  19. ret = {
  20. FDFS_STORAGE_STATUS_INIT : lambda : 'INIT',
  21. FDFS_STORAGE_STATUS_WAIT_SYNC : lambda : 'WAIT_SYNC',
  22. FDFS_STORAGE_STATUS_SYNCING : lambda : 'SYNCING',
  23. FDFS_STORAGE_STATUS_IP_CHANGED : lambda : 'IP_CHANGED',
  24. FDFS_STORAGE_STATUS_DELETED : lambda : 'DELETED',
  25. FDFS_STORAGE_STATUS_OFFLINE : lambda : 'OFFLINE',
  26. FDFS_STORAGE_STATUS_ONLINE : lambda : 'ONLINE',
  27. FDFS_STORAGE_STATUS_ACTIVE : lambda : 'ACTIVE',
  28. FDFS_STORAGE_STATUS_RECOVERY : lambda : 'RECOVERY'
  29. }[status_code]()
  30. except KeyError:
  31. ret = 'UNKNOW'
  32. return ret
  33. class Storage_info(object):
  34. def __init__(self):
  35. self.status = 0
  36. self.ip_addr = ''
  37. self.domain_name = ''
  38. self.src_ip_addr = ''
  39. self.version = ''
  40. self.totalMB = ''
  41. self.freeMB = ''
  42. self.upload_prio = 0
  43. self.join_time = datetime.fromtimestamp(0).isoformat()
  44. self.up_time = datetime.fromtimestamp(0).isoformat()
  45. self.store_path_count = 0
  46. self.subdir_count_per_path = 0
  47. self.storage_port = 23000
  48. self.storage_http_port = 80
  49. self.curr_write_path = 0
  50. self.total_upload_count = 0
  51. self.success_upload_count = 0
  52. self.total_append_count = 0
  53. self.success_append_count = 0
  54. self.total_modify_count = 0
  55. self.success_modify_count = 0
  56. self.total_truncate_count = 0
  57. self.success_truncate_count = 0
  58. self.total_setmeta_count = 0
  59. self.success_setmeta_count = 0
  60. self.total_del_count = 0
  61. self.success_del_count = 0
  62. self.total_download_count = 0
  63. self.success_download_count = 0
  64. self.total_getmeta_count = 0
  65. self.success_getmeta_count = 0
  66. self.total_create_link_count = 0
  67. self.success_create_link_count = 0
  68. self.total_del_link_count = 0
  69. self.success_del_link_count = 0
  70. self.total_upload_bytes = 0
  71. self.success_upload_bytes = 0
  72. self.total_append_bytes = 0
  73. self.success_append_bytes = 0
  74. self.total_modify_bytes = 0
  75. self.success_modify_bytes = 0
  76. self.total_download_bytes = 0
  77. self.success_download_bytes = 0
  78. self.total_sync_in_bytes = 0
  79. self.success_sync_in_bytes = 0
  80. self.total_sync_out_bytes = 0
  81. self.success_sync_out_bytes = 0
  82. self.total_file_open_count = 0
  83. self.success_file_open_count = 0
  84. self.total_file_read_count = 0
  85. self.success_file_read_count = 0
  86. self.total_file_write_count = 0
  87. self.success_file_write_count = 0
  88. self.last_source_sync = datetime.fromtimestamp(0).isoformat()
  89. self.last_sync_update = datetime.fromtimestamp(0).isoformat()
  90. self.last_synced_time = datetime.fromtimestamp(0).isoformat()
  91. self.last_heartbeat_time = datetime.fromtimestamp(0).isoformat()
  92. self.if_trunk_server = 0
  93. #fmt = |-status(1)-ipaddr(16)-domain(128)-srcipaddr(16)-ver(6)-52*8-|
  94. self.fmt = '!B %ds %ds %ds %ds 52QB' % (IP_ADDRESS_SIZE, \
  95. FDFS_DOMAIN_NAME_MAX_LEN,
  96. IP_ADDRESS_SIZE, \
  97. FDFS_VERSION_SIZE)
  98. def set_info(self, bytes_stream):
  99. (self.status, ip_addr, domain_name, \
  100. src_ip_addr, version, join_time,up_time, \
  101. totalMB, freeMB, self.upload_prio, \
  102. self.store_path_count, self.subdir_count_per_path, \
  103. self.storage_port, self.storage_http_port, \
  104. self.curr_write_path, \
  105. self.total_upload_count, self.success_upload_count, \
  106. self.total_append_count, self.success_append_count, \
  107. self.total_modify_count, self.success_modify_count, \
  108. self.total_truncate_count,self.success_truncate_count, \
  109. self.total_setmeta_count, self.success_setmeta_count, \
  110. self.total_del_count, self.success_del_count, \
  111. self.total_download_count,self.success_download_count, \
  112. self.total_getmeta_count, self.success_getmeta_count, \
  113. self.total_create_link_count, self.success_create_link_count, \
  114. self.total_del_link_count, self.success_del_link_count, \
  115. self.total_upload_bytes, self.success_upload_bytes, \
  116. self.total_append_bytes, self.total_append_bytes, \
  117. self.total_modify_bytes, self.success_modify_bytes, \
  118. self.total_download_bytes, self.success_download_bytes, \
  119. self.total_sync_in_bytes, self.success_sync_in_bytes, \
  120. self.total_sync_out_bytes, self.success_sync_out_bytes, \
  121. self.total_file_open_count, self.success_file_open_count, \
  122. self.total_file_read_count, self.success_file_read_count, \
  123. self.total_file_write_count, self.success_file_write_count, \
  124. last_source_sync, last_sync_update, last_synced_time, \
  125. last_heartbeat_time, self.if_trunk_server) \
  126. = struct.unpack(self.fmt, bytes_stream)
  127. try:
  128. self.ip_addr = ip_addr.strip('\x00')
  129. self.domain_name = domain_name.strip('\x00')
  130. self.version = version.strip('\x00')
  131. self.src_ip_addr = src_ip_addr.strip('\x00')
  132. self.totalMB = appromix(totalMB, FDFS_SPACE_SIZE_BASE_INDEX)
  133. self.freeMB = appromix(freeMB, FDFS_SPACE_SIZE_BASE_INDEX)
  134. except ValueError, e:
  135. raise ResponseError('[-] Error: disk space overrun, can not represented it.')
  136. self.join_time = datetime.fromtimestamp(join_time).isoformat()
  137. self.up_time = datetime.fromtimestamp(up_time).isoformat()
  138. self.last_source_sync = datetime.fromtimestamp(last_source_sync).isoformat()
  139. self.last_sync_update = datetime.fromtimestamp(last_sync_update).isoformat()
  140. self.last_synced_time = datetime.fromtimestamp(last_synced_time).isoformat()
  141. self.last_heartbeat_time = \
  142. datetime.fromtimestamp(last_heartbeat_time).isoformat()
  143. return True
  144. def __str__(self):
  145. '''Transform to readable string.'''
  146. s = 'Storage information:\n'
  147. s += '\tip_addr = %s (%s)\n' % (self.ip_addr, parse_storage_status(self.status))
  148. s += '\thttp domain = %s\n' % self.domain_name
  149. s += '\tversion = %s\n' % self.version
  150. s += '\tjoin time = %s\n' % self.join_time
  151. s += '\tup time = %s\n' % self.up_time
  152. s += '\ttotal storage = %s\n' % self.totalMB
  153. s += '\tfree storage = %s\n' % self.freeMB
  154. s += '\tupload priority = %d\n' % self.upload_prio
  155. s += '\tstore path count = %d\n' % self.store_path_count
  156. s += '\tsubdir count per path = %d\n' % self.subdir_count_per_path
  157. s += '\tstorage port = %d\n' % self.storage_port
  158. s += '\tstorage HTTP port = %d\n' % self.storage_http_port
  159. s += '\tcurrent write path = %d\n' % self.curr_write_path
  160. s += '\tsource ip_addr = %s\n' % self.src_ip_addr
  161. s += '\tif_trunk_server = %d\n' % self.if_trunk_server
  162. s += '\ttotal upload count = %ld\n' % self.total_upload_count
  163. s += '\tsuccess upload count = %ld\n' % self.success_upload_count
  164. s += '\ttotal download count = %ld\n' % self.total_download_count
  165. s += '\tsuccess download count = %ld\n' % self.success_download_count
  166. s += '\ttotal append count = %ld\n' % self.total_append_count
  167. s += '\tsuccess append count = %ld\n' % self.success_append_count
  168. s += '\ttotal modify count = %ld\n' % self.total_modify_count
  169. s += '\tsuccess modify count = %ld\n' % self.success_modify_count
  170. s += '\ttotal truncate count = %ld\n' % self.total_truncate_count
  171. s += '\tsuccess truncate count = %ld\n' % self.success_truncate_count
  172. s += '\ttotal delete count = %ld\n' % self.total_del_count
  173. s += '\tsuccess delete count = %ld\n' % self.success_del_count
  174. s += '\ttotal set_meta count = %ld\n' % self.total_setmeta_count
  175. s += '\tsuccess set_meta count = %ld\n' % self.success_setmeta_count
  176. s += '\ttotal get_meta count = %ld\n' % self.total_getmeta_count
  177. s += '\tsuccess get_meta count = %ld\n' % self.success_getmeta_count
  178. s += '\ttotal create link count = %ld\n' % self.total_create_link_count
  179. s += '\tsuccess create link count = %ld\n' % self.success_create_link_count
  180. s += '\ttotal delete link count = %ld\n' % self.total_del_link_count
  181. s += '\tsuccess delete link count = %ld\n' % self.success_del_link_count
  182. s += '\ttotal upload bytes = %ld\n' % self.total_upload_bytes
  183. s += '\tsuccess upload bytes = %ld\n' % self.success_upload_bytes
  184. s += '\ttotal download bytes = %ld\n' % self.total_download_bytes
  185. s += '\tsuccess download bytes = %ld\n' % self.success_download_bytes
  186. s += '\ttotal append bytes = %ld\n' % self.total_append_bytes
  187. s += '\tsuccess append bytes = %ld\n' % self.success_append_bytes
  188. s += '\ttotal modify bytes = %ld\n' % self.total_modify_bytes
  189. s += '\tsuccess modify bytes = %ld\n' % self.success_modify_bytes
  190. s += '\ttotal sync_in bytes = %ld\n' % self.total_sync_in_bytes
  191. s += '\tsuccess sync_in bytes = %ld\n' % self.success_sync_in_bytes
  192. s += '\ttotal sync_out bytes = %ld\n' % self.total_sync_out_bytes
  193. s += '\tsuccess sync_out bytes = %ld\n' % self.success_sync_out_bytes
  194. s += '\ttotal file open count = %ld\n' % self.total_file_open_count
  195. s += '\tsuccess file open count = %ld\n' % self.success_file_open_count
  196. s += '\ttotal file read count = %ld\n' % self.total_file_read_count
  197. s += '\tsuccess file read count = %ld\n' % self.success_file_read_count
  198. s += '\ttotal file write count = %ld\n' % self.total_file_write_count
  199. s += '\tsucess file write count = %ld\n' % self.success_file_write_count
  200. s += '\tlast heartbeat time = %s\n' % self.last_heartbeat_time
  201. s += '\tlast source update = %s\n' % self.last_source_sync
  202. s += '\tlast sync update = %s\n' % self.last_sync_update
  203. s += '\tlast synced time = %s\n' % self.last_synced_time
  204. return s
  205. def get_fmt_size(self):
  206. return struct.calcsize(self.fmt)
  207. class Group_info(object):
  208. def __init__(self):
  209. self.group_name = ''
  210. self.freeMB = ''
  211. self.trunk_freeMB = ''
  212. self.count = 0
  213. self.storage_port = 0
  214. self.store_http_port = 0
  215. self.active_count = 0
  216. self.curr_write_server = 0
  217. self.store_path_count = 0
  218. self.subdir_count_per_path = 0
  219. self.curr_trunk_file_id = 0
  220. self.fmt = '!%ds 10Q' % (FDFS_GROUP_NAME_MAX_LEN + 1)
  221. return None
  222. def __str__(self):
  223. s = 'Group information:\n'
  224. s += '\tgroup name = %s\n' % self.group_name
  225. s += '\tdisk free space = %s\n' % self.freeMB
  226. s += '\ttrunk free space = %s\n' % self.trunk_freeMB
  227. s += '\tstorage server count = %d\n' % self.count
  228. s += '\tstorage port = %d\n' % self.storage_port
  229. s += '\tstorage HTTP port = %d\n' % self.store_http_port
  230. s += '\tactive server count = %d\n' % self.active_count
  231. s += '\tcurrent write server index = %d\n' % self.curr_write_server
  232. s += '\tstore path count = %d\n' % self.store_path_count
  233. s += '\tsubdir count per path = %d\n' % self.subdir_count_per_path
  234. s += '\tcurrent trunk file id = %d\n' % self.curr_trunk_file_id
  235. return s
  236. def set_info(self, bytes_stream):
  237. (group_name, freeMB, trunk_freeMB, self.count, self.storage_port, \
  238. self.store_http_port, self.active_count, self.curr_write_server, \
  239. self.store_path_count, self.subdir_count_per_path, self.curr_trunk_file_id) \
  240. = struct.unpack(self.fmt, bytes_stream)
  241. try:
  242. self.group_name = group_name.strip('\x00')
  243. self.freeMB = appromix(freeMB, FDFS_SPACE_SIZE_BASE_INDEX)
  244. self.trunk_freeMB = appromix(trunk_freeMB, FDFS_SPACE_SIZE_BASE_INDEX)
  245. except ValueError:
  246. raise DataError('[-] Error disk space overrun, can not represented it.')
  247. def get_fmt_size(self):
  248. return struct.calcsize(self.fmt)
  249. class Tracker_client(object):
  250. '''Class Tracker client.'''
  251. def __init__(self, pool):
  252. self.pool = pool
  253. def tracker_list_servers(self, group_name, storage_ip = None):
  254. '''
  255. List servers in a storage group
  256. '''
  257. conn = self.pool.get_connection()
  258. th = Tracker_header()
  259. ip_len = len(storage_ip) if storage_ip else 0
  260. if ip_len >= IP_ADDRESS_SIZE:
  261. ip_len = IP_ADDRESS_SIZE - 1
  262. th.pkg_len = FDFS_GROUP_NAME_MAX_LEN + ip_len
  263. th.cmd = TRACKER_PROTO_CMD_SERVER_LIST_STORAGE
  264. group_fmt = '!%ds' % FDFS_GROUP_NAME_MAX_LEN
  265. store_ip_addr = storage_ip or ''
  266. storage_ip_fmt = '!%ds' % ip_len
  267. try:
  268. th.send_header(conn)
  269. send_buffer = struct.pack(group_fmt, group_name) + \
  270. struct.pack(storage_ip_fmt, store_ip_addr)
  271. tcp_send_data(conn, send_buffer)
  272. th.recv_header(conn)
  273. if th.status != 0:
  274. raise DataError('[-] Error: %d, %s' % (th.status, os.strerror(th.status)))
  275. recv_buffer, recv_size = tcp_recv_response(conn, th.pkg_len)
  276. si = Storage_info()
  277. si_fmt_size = si.get_fmt_size()
  278. recv_size = len(recv_buffer)
  279. if recv_size % si_fmt_size != 0:
  280. errinfo = '[-] Error: response size not match, expect: %d, actual: %d' \
  281. % (th.pkg_len, recv_size)
  282. raise ResponseError(errinfo)
  283. except ConnectionError:
  284. raise
  285. finally:
  286. self.pool.release(conn)
  287. num_storage = recv_size / si_fmt_size
  288. si_list = []
  289. i = 0
  290. while num_storage:
  291. si.set_info(recv_buffer[(i * si_fmt_size) : ((i + 1) * si_fmt_size)])
  292. si_list.append(si)
  293. si = Storage_info()
  294. num_storage -= 1
  295. i += 1
  296. ret_dict = {}
  297. ret_dict['Group name'] = group_name
  298. ret_dict['Servers'] = si_list
  299. return ret_dict
  300. def tracker_list_one_group(self, group_name):
  301. conn = self.pool.get_connection()
  302. th = Tracker_header()
  303. th.pkg_len = FDFS_GROUP_NAME_MAX_LEN
  304. th.cmd = TRACKER_PROTO_CMD_SERVER_LIST_ONE_GROUP
  305. #group_fmt: |-group_name(16)-|
  306. group_fmt = '!%ds' % FDFS_GROUP_NAME_MAX_LEN
  307. try:
  308. th.send_header(conn)
  309. send_buffer = struct.pack(group_fmt, group_name)
  310. tcp_send_data(conn, send_buffer)
  311. th.recv_header(conn)
  312. if th.status != 0:
  313. raise DataError('[-] Error: %d, %s' % (th.status, os.strerror(th.status)))
  314. recv_buffer, recv_size = tcp_recv_response(conn, th.pkg_len)
  315. group_info = Group_info()
  316. group_info.set_info(recv_buffer)
  317. except ConnectionError:
  318. raise
  319. finally:
  320. self.pool.release(conn)
  321. return group_info
  322. def tracker_list_all_groups(self):
  323. conn = self.pool.get_connection()
  324. th = Tracker_header()
  325. th.cmd = TRACKER_PROTO_CMD_SERVER_LIST_ALL_GROUPS
  326. try:
  327. th.send_header(conn)
  328. th.recv_header(conn)
  329. if th.status != 0:
  330. raise DataError('[-] Error: %d, %s' % (th.status, os.strerror(th.status)))
  331. recv_buffer, recv_size = tcp_recv_response(conn, th.pkg_len)
  332. except:
  333. raise
  334. finally:
  335. self.pool.release(conn)
  336. gi = Group_info()
  337. gi_fmt_size = gi.get_fmt_size()
  338. if recv_size % gi_fmt_size != 0:
  339. errmsg = '[-] Error: Response size is mismatch, except: %d, actul: %d' \
  340. % (th.pkg_len, recv_size)
  341. raise ResponseError(errmsg)
  342. num_groups = recv_size / gi_fmt_size
  343. ret_dict = {}
  344. ret_dict['Groups count'] = num_groups
  345. gi_list = []
  346. i = 0
  347. while num_groups:
  348. gi.set_info(recv_buffer[i * gi_fmt_size : (i + 1) * gi_fmt_size])
  349. gi_list.append(gi)
  350. gi = Group_info()
  351. i += 1
  352. num_groups -= 1
  353. ret_dict['Groups'] = gi_list
  354. return ret_dict
  355. def tracker_query_storage_stor_without_group(self):
  356. '''Query storage server for upload, without group name.
  357. Return: Storage_server object'''
  358. conn = self.pool.get_connection()
  359. th = Tracker_header()
  360. th.cmd = TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE
  361. try:
  362. th.send_header(conn)
  363. th.recv_header(conn)
  364. if th.status != 0:
  365. raise DataError('[-] Error: %d, %s' % (th.status, os.strerror(th.status)))
  366. recv_buffer, recv_size = tcp_recv_response(conn, th.pkg_len)
  367. if recv_size != TRACKER_QUERY_STORAGE_STORE_BODY_LEN:
  368. errmsg = '[-] Error: Tracker response length is invaild, '
  369. errmsg += 'expect: %d, actual: %d' \
  370. % (TRACKER_QUERY_STORAGE_STORE_BODY_LEN, recv_size)
  371. raise ResponseError(errmsg)
  372. except ConnectionError:
  373. raise
  374. finally:
  375. self.pool.release(conn)
  376. #recv_fmt |-group_name(16)-ipaddr(16-1)-port(8)-store_path_index(1)|
  377. recv_fmt = '!%ds %ds Q B' % (FDFS_GROUP_NAME_MAX_LEN, IP_ADDRESS_SIZE - 1)
  378. store_serv = Storage_server()
  379. (group_name, ip_addr, \
  380. store_serv.port, store_serv.store_path_index) = struct.unpack(recv_fmt, recv_buffer)
  381. store_serv.group_name = group_name.strip('\x00')
  382. store_serv.ip_addr = ip_addr.strip('\x00')
  383. return store_serv
  384. def tracker_query_storage_stor_with_group(self, group_name):
  385. '''Query storage server for upload, based group name.
  386. arguments:
  387. @group_name: string
  388. @Return Storage_server object
  389. '''
  390. conn = self.pool.get_connection()
  391. th = Tracker_header()
  392. th.cmd = TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE
  393. th.pkg_len = FDFS_GROUP_NAME_MAX_LEN
  394. th.send_header(conn)
  395. group_fmt = '!%ds' % FDFS_GROUP_NAME_MAX_LEN
  396. send_buffer = struct.pack(group_fmt, group_name)
  397. try:
  398. tcp_send_data(conn, send_buffer)
  399. th.recv_header(conn)
  400. if th.status != 0:
  401. raise DataError('Error: %d, %s' % (th.status, os.strerror(th.status)))
  402. recv_buffer, recv_size = tcp_recv_response(conn, th.pkg_len)
  403. if recv_size != TRACKER_QUERY_STORAGE_STORE_BODY_LEN:
  404. errmsg = '[-] Error: Tracker response length is invaild, '
  405. errmsg += 'expect: %d, actual: %d' \
  406. % (TRACKER_QUERY_STORAGE_STORE_BODY_LEN, recv_size)
  407. raise ResponseError(errmsg)
  408. except ConnectionError:
  409. raise
  410. finally:
  411. self.pool.release(conn)
  412. #recv_fmt: |-group_name(16)-ipaddr(16-1)-port(8)-store_path_index(1)-|
  413. recv_fmt = '!%ds %ds Q B' % (FDFS_GROUP_NAME_MAX_LEN, IP_ADDRESS_SIZE - 1)
  414. store_serv = Storage_server()
  415. (group, ip_addr, \
  416. store_serv.port, store_serv.store_path_index) = struct.unpack(recv_fmt, recv_buffer)
  417. store_serv.group_name = group.strip('\x00')
  418. store_serv.ip_addr = ip_addr.strip('\x00')
  419. return store_serv
  420. def _tracker_do_query_storage(self,group_name, filename, cmd):
  421. '''
  422. core of query storage, based group name and filename.
  423. It is useful download, delete and set meta.
  424. arguments:
  425. @group_name: string
  426. @filename: string. remote file_id
  427. @Return: Storage_server object
  428. '''
  429. conn = self.pool.get_connection()
  430. th = Tracker_header()
  431. file_name_len = len(filename)
  432. th.pkg_len = FDFS_GROUP_NAME_MAX_LEN + file_name_len
  433. th.cmd = cmd
  434. th.send_header(conn)
  435. #query_fmt: |-group_name(16)-filename(file_name_len)-|
  436. query_fmt = '!%ds %ds' % (FDFS_GROUP_NAME_MAX_LEN, file_name_len)
  437. send_buffer = struct.pack(query_fmt, group_name, filename)
  438. try:
  439. tcp_send_data(conn, send_buffer)
  440. th.recv_header(conn)
  441. if th.status != 0:
  442. raise DataError('Error: %d, %s' % (th.status, os.strerror(th.status)))
  443. recv_buffer, recv_size = tcp_recv_response(conn, th.pkg_len)
  444. if recv_size != TRACKER_QUERY_STORAGE_FETCH_BODY_LEN:
  445. errmsg = '[-] Error: Tracker response length is invaild, '
  446. errmsg += 'expect: %d, actual: %d' % (th.pkg_len, recv_size)
  447. raise ResponseError(errmsg)
  448. except ConnectionError:
  449. raise
  450. finally:
  451. self.pool.release(conn)
  452. #recv_fmt: |-group_name(16)-ip_addr(16)-port(8)-|
  453. recv_fmt = '!%ds %ds Q' % (FDFS_GROUP_NAME_MAX_LEN, IP_ADDRESS_SIZE - 1)
  454. store_serv = Storage_server()
  455. (group_name, ipaddr, store_serv.port) = struct.unpack(recv_fmt, recv_buffer)
  456. store_serv.group_name = group_name.strip('\x00')
  457. store_serv.ip_addr = ipaddr.strip('\x00')
  458. return store_serv
  459. def tracker_query_storage_update(self, group_name, filename):
  460. '''
  461. Query storage server to update(delete and set_meta).
  462. '''
  463. return self._tracker_do_query_storage(group_name, filename, \
  464. TRACKER_PROTO_CMD_SERVICE_QUERY_UPDATE)
  465. def tracker_query_storage_fetch(self, group_name, filename):
  466. '''
  467. Query storage server to download.
  468. '''
  469. return self._tracker_do_query_storage(group_name, filename, \
  470. TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ONE)