2015年2月8日 星期日

Service APIs of python-swiftclient

python-swiftclient 是一個 OpenStack swift 的 client tool 簡而言之就是 command line interface(CLI).

之前有想過如何可以直接使用 swiftclient 裡面的 library 直接與 swift APIs 做溝通,省去寫 http client 與 APIs 的攥寫時間,這是一個很單純的問題。就 code 的邏輯是一定沒問題,只是怎麼做比較漂亮,那個地方是插入點,就值得花點時間研究。

作法一: 直接利用 shell.st_FUNCTION 來做,把所需參數倒入即可

  • 缺點:需要處理 swiftclient output 的非同步問題,已經處理完 APIs ,但是回來的 buffer 內容就是少些東西。
  • 優點:很直覺,直接把參數帶在function後面即可。
#!/usr/bin/env python

import socket
from os import environ
from optparse import OptionParser
from swiftclient import shell
from swiftclient import RequestException
from swiftclient.exceptions import ClientException
from swiftclient.multithreading import OutputManager

def options():
    parser = OptionParser()
    parser.add_option('-A', '--auth', dest='auth',
                    default=environ.get('ST_AUTH'))
    parser.add_option('-V', '--auth-version',
                    default=environ.get('ST_AUTH_VERSION',
                                        (environ.get('OS_AUTH_VERSION',
                                                    '1.0'))))
    parser.add_option('-U', '--user', dest='user',
                    default=environ.get('ST_USER'))
    parser.add_option('-K', '--key', dest='key',
                    default=environ.get('ST_KEY'))

    parser.add_option('--os_user_id')
    parser.add_option('--os_user_domain_id')
    parser.add_option('--os_user_domain_name')
    parser.add_option('--os_tenant_id')
    parser.add_option('--os_tenant_name')
    parser.add_option('--os_project_id')
    parser.add_option('--os_project_domain_id')
    parser.add_option('--os_project_name')
    parser.add_option('--os_project_domain_name')
    parser.add_option('--os_service_type')
    parser.add_option('--os_endpoint_type')
    parser.add_option('--os_auth_token')
    parser.add_option('--os_storage_url')
    parser.add_option('--os_region_name')
    parser.add_option('--verbose')
    parser.add_option('--insecure', default='True')
    return parser

def stat(*args):
    args = ('',) + args
    with OutputManager() as output:
        parser = options()
        try:
            shell.st_stat(parser, list(args), output)
        except (ClientException, RequestException, socket.error) as err:
            output.error(str(err))

print 'show swift cluster stat'
stat() 

輸出

$ ./wrapper_swiftcleint.py 
show swift cluster stat
                                Account: AUTH_demo
                             Containers: 4
                                Objects: 5679
                                  Bytes: 468730045
Containers in policy "standard-replica": 4
   Objects in policy "standard-replica": 5679
     Bytes in policy "standard-replica": 468730045
                      Meta Temp-Url-Key: f270afa2-0552-43c6-ada0-0688d92c083d
                          Accept-Ranges: bytes
                             Connection: keep-alive
                            X-Timestamp: 1422242407.75372
                             X-Trans-Id: txb135b30b90384105bf100-0054d728c8
                           Content-Type: text/plain; charset=utf-8

做法二:利用 SwiftService class (Hight Level APIs 或稱為 Service APIs)

  • 優點:該有的都有,output 是一個 dicitionary,處理起來挺方便的。
#!/usr/bin/env python

import json
from swiftclient.service import SwiftService

client_opts = {'insecure': True}

with SwiftService(options=client_opts) as swift:
    stat_output = swift.stat()
    print json.dumps(stat_output, indent=2)

輸出
$ ./highlevel-swiftclient.py 
{
  "headers": {
    "content-length": "0", 
    "x-account-storage-policy-standard-replica-container-count": "4", 
    "accept-ranges": "bytes", 
    "connection": "keep-alive", 
    "x-account-object-count": "5679", 
    "x-timestamp": "1422242407.75372", 
    "x-account-meta-temp-url-key": "f270afa2-0552-43c6-ada0-0688d92c083d", 
    "x-trans-id": "tx56fe3088a81f4696ad79d-0054d72c57", 
    "date": "Sun, 08 Feb 2015 09:28:55 GMT", 
    "x-account-storage-policy-standard-replica-bytes-used": "468730045", 
    "x-account-container-count": "4", 
    "content-type": "text/plain; charset=utf-8", 
    "x-account-bytes-used": "468730045", 
    "x-account-storage-policy-standard-replica-object-count": "5679"
  }, 
  "container": null, 
  "success": true, 
  "action": "stat_account", 
  "items": [
    [
      "Account", 
      "AUTH_demo"
    ], 
    [
      "Containers", 
      4
    ], 
    [
      "Objects", 
      "5679"
    ], 
    [
      "Bytes", 
      "468730045"
    ], 
    [
      "Containers in policy \"standard-replica\"", 
      "4"
    ], 
    [
      "Objects in policy \"standard-replica\"", 
      "5679"
    ], 
    [
      "Bytes in policy \"standard-replica\"", 
      "468730045"
    ]
  ], 
  "object": null
}

其實方法一,是我原本處理的方式。一直到今天才發現這個 blueprint: Move high-level functionality from bin/swift into importable/testable library ,而且已經完成。而且解釋了為什麼需要做這 Service APIs (就是我所遇到的問題),下次做之前一定要『多看,多聽,多問』。

另外關於這個 Patch Review ,不免可以發現其實在 OpenStack 下的 project 已經算是有很完整的 Code review (Gerrit) 以及 continuous integration (Jenkins + Zuul + Gerrit) ,這個 patch 經歷的四個月,而且都是在線上討論完成,而且經過 Code review 與 CI 的洗禮,品質相對會比較穩定。

不過 python-swiftclient 的 performance 真的挺不好的,很慢啊!Head 5k 的 Objects 需要 10分鐘,不過也是因為它每次去取得資料都會去做一次 Auth,難怪會這麼慢。

沒有留言: