SoftLayerはSoftLayer CLIと呼ばれるPythonベースのコマンドラインインタフェースを提供しています。
サーバーのリストを参照したり、サーバーをオーダーしたり、一部の設定を変更したりといった操作がコマンドラインから実行できるようになっています。わざわざPortalを開いて操作しなくてもよいので、ちょっとした状況の確認や、簡単な処理の自動化をするために使うことができます。
複雑な処理を実行したい場合は、PythonなどでAPIを使って一からプログラムを書くのがよいですが、CLIでほぼやりたいことができるけど、少しだけ情報を追加したい場合など、既存のCLIを少し拡張するだけ十分な場合もあるでしょう。
ここでは、Virtual Serverの稼働ホストをsl vs listコマンドで表示させるようにCLIを拡張してみます。
Virtual Serverの稼働ホストを取得する方法はShinobiLayer: Virtual Serverの作成者や稼動ホストのRack/Slot情報を確認するスクリプトを参考にしています。
CLIのインストール場所
CLIのファイルは、以下のパスのCLIというディレクトリにインストールされています。
OS | Path |
---|---|
Mac OS X | /Library/Python/2.7/site-packages/SoftLayer |
Linux | /usr/lib/python2.7/site-packages/SoftLayer |
Windows | ?? |
モジュール
CLIのファイルは、CLIコマンドの<module>の単位で分かれています。
$ sl <module> [<args>...]
該当のファイルを変更することで、そのmoduleを使ったコマンドの処理を変更することができます。
vs.pyを変更すればsl vs
コマンドの処理を変更できますし、server.pyを変更すればsl server
の処理を変更できます。
$ ls -l CLI/modules/*.py
-rw-r--r-- 1 root wheel 356 Jan 4 23:12 CLI/modules/__init__.py
-rw-r--r-- 1 root wheel 5679 Jan 4 23:12 CLI/modules/cdn.py
-rw-r--r-- 1 root wheel 6459 Jan 4 23:12 CLI/modules/config.py
-rw-r--r-- 1 root wheel 10400 Jan 4 23:12 CLI/modules/dns.py
-rw-r--r-- 1 root wheel 925 Jan 4 23:12 CLI/modules/filters.py
-rw-r--r-- 1 root wheel 14813 Jan 4 23:12 CLI/modules/firewall.py
-rw-r--r-- 1 root wheel 5193 Jan 4 23:12 CLI/modules/globalip.py
-rw-r--r-- 1 root wheel 908 Jan 4 23:12 CLI/modules/help.py
-rw-r--r-- 1 root wheel 5913 Jan 4 23:12 CLI/modules/image.py
-rw-r--r-- 1 root wheel 6057 Jan 4 23:12 CLI/modules/iscsi.py
-rw-r--r-- 1 root wheel 20026 Jan 4 23:12 CLI/modules/loadbal.py
-rw-r--r-- 1 root wheel 16126 Jan 4 23:12 CLI/modules/messaging.py
-rw-r--r-- 1 root wheel 6261 Jan 4 23:12 CLI/modules/metadata.py
-rw-r--r-- 1 root wheel 1484 Jan 4 23:12 CLI/modules/nas.py
-rw-r--r-- 1 root wheel 3376 Jan 4 23:12 CLI/modules/rwhois.py
-rw-r--r-- 1 root wheel 39683 Jan 4 23:12 CLI/modules/server.py
-rw-r--r-- 1 root wheel 4582 Jan 4 23:12 CLI/modules/snapshot.py
-rw-r--r-- 1 root wheel 4757 Jan 4 23:12 CLI/modules/sshkey.py
-rw-r--r-- 1 root wheel 5185 Jan 4 23:12 CLI/modules/ssl.py
-rw-r--r-- 1 root wheel 9760 Jan 4 23:12 CLI/modules/subnet.py
-rw-r--r-- 1 root wheel 1240 Jan 4 23:12 CLI/modules/summary.py
-rw-r--r-- 1 root wheel 8155 Jan 4 23:12 CLI/modules/ticket.py
-rw-r--r-- 1 root wheel 5015 Jan 4 23:12 CLI/modules/vlan.py
-rw-r--r-- 1 root wheel 42378 Jan 17 23:43 CLI/modules/vs.py
Manager
SoftLayer CLIは、APIを抽象化して使いやすくしたManagerと呼ばれるクラスを使用して実装されています。
Managerで取得できない情報は当然CLIでも利用できません。そのような場合には、Managerでデータを取得している部分を少し変更すれば対応できます。具体的には、Managerの処理の中で必要なObject Maskを追加して、Reference Propertyが取得できるようにしてあげます。
utils.py
様々な共通の処理を簡単に実行できるように、共通の関数やクラスが定義されています。
ひとまず、深くネストされたdictionaryデータを簡単に検索するのに使われるlookup()を理解しておけばよいでしょう。
def lookup(dic, key, *keys):
"""A generic dictionary access helper.
This helps simplify code that uses heavily nested dictionaries. It will
return None if any of the keys in *keys do not exist.
::
>>> lookup({'this': {'is': 'nested'}}, 'this', 'is')
nested
>>> lookup({}, 'this', 'is')
None
例えば以下の処理では、guestというVirtual_Guestオブジェクトのインスタンスに対して、Object Maskで取得されるRelational PropertiesをbillingItems -> orderItem -> order -> userRecord -> username という順にたどって、最終的にユーザー名を取得しています。
utils.lookup(guest, 'billingItem', 'orderItem', 'order', 'userRecord', 'username')
変更部分
managers/vs.py
- VSmangerのlist_instance()で、location.pathStringをObject Maskに追加
$ diff -U 10 managers/vs.py.orig managers/vs.py
--- managers/vs.py.orig 2015-01-17 23:41:45.000000000 +0900
+++ managers/vs.py 2015-01-17 23:42:52.000000000 +0900
@@ -81,21 +81,22 @@
'fullyQualifiedDomainName',
'primaryBackendIpAddress',
'primaryIpAddress',
'lastKnownPowerState.name',
'powerState',
'maxCpu',
'maxMemory',
'datacenter',
'activeTransaction.transactionStatus[friendlyName,name]',
'status',
- 'billingItem.orderItem.order.userRecord[username]'
+ 'billingItem.orderItem.order.userRecord[username]',
+ 'location.pathString'
]
kwargs['mask'] = "mask[%s]" % ','.join(items)
call = 'getVirtualGuests'
if not all([hourly, monthly]):
if hourly:
call = 'getHourlyVirtualGuests'
elif monthly:
call = 'getMonthlyVirtualGuests'
CLI/modules/vs.py
- 表のヘッダにlocationフィールドを追加
- lookup()でlocation.pathStringを取得
$ diff -U 10 CLI/modules/vs.py.orig CLI/modules/vs.py
--- CLI/modules/vs.py.orig 2015-01-04 23:12:47.000000000 +0900
+++ CLI/modules/vs.py 2015-01-18 00:58:01.000000000 +0900
@@ -87,34 +87,35 @@
domain=args.get('--domain'),
cpus=args.get('--cpu'),
memory=args.get('--memory'),
datacenter=args.get('--datacenter'),
nic_speed=args.get('--network'),
tags=tags)
table = formatting.Table([
'id', 'datacenter', 'host',
'cores', 'memory', 'primary_ip',
- 'backend_ip', 'active_transaction', 'owner'
+ 'backend_ip', 'location', 'active_transaction', 'owner'
])
table.sortby = args.get('--sortby') or 'host'
for guest in guests:
guest = utils.NestedDict(guest)
table.add_row([
guest['id'],
guest['datacenter']['name'] or formatting.blank(),
guest['fullyQualifiedDomainName'],
guest['maxCpu'],
formatting.mb_to_gb(guest['maxMemory']),
guest['primaryIpAddress'] or formatting.blank(),
guest['primaryBackendIpAddress'] or formatting.blank(),
+ utils.lookup(guest, 'location', 'pathString') or formatting.blank(),
formatting.active_txn(guest),
utils.lookup(guest, 'billingItem', 'orderItem', 'order',
'userRecord', 'username') or formatting.blank(),
])
return table
class VSDetails(environment.CLIRunnable):
"""
実行結果
$ sl vs list --sortby=location
:.........:............:............................:.......:........:.................:...............:.......................:....................:.....................:
: id : datacenter : host : cores : memory : primary_ip : backend_ip : location : active_transaction : owner :
:.........:............:............................:.......:........:.................:...............:.......................:....................:.....................:
: 6954216 : hkg02 : vyattama01.ibm.com : 1 : 1G : 119.81.xxx.x : 10.110.2.210 : hkg02.rk12.sl01 : - : aaaa@jp.ibm.com :
: 6030072 : sng01 : idera01.softlayer.com : 1 : 2G : 119.81.xx.xx : 10.64.234.87 : sng01.rk238.sl08 : - : bbbbbbb@jp.ibm.com :
: 7688858 : sng01 : centos1.softlayer.com : 1 : 1G : 119.81.xxx.xxx : 10.64.234.79 : sng01.rk238.sl17 : - : bbbbbbb@jp.ibm.com :
: 7629262 : tok02 : tok01.softlayer.com : 1 : 2G : 161.202.xx.xx : 10.132.2.216 : tok02.sr01.rk122.sl17 : - : ccccccc@jp.ibm.com :
: 7642180 : tok02 : mywin01.softlayer.com : 1 : 2G : 161.202.xx.xx : 10.132.2.213 : tok02.sr01.rk122.sl22 : - : ccccccc@jp.ibm.com :
: 7684248 : tok02 : docker-centos7.example.com : 1 : 1G : 161.202.xx.xx : 10.132.2.214 : tok02.sr01.rk126.sl21 : - : dddddddd@jp.ibm.com :
:.........:............:.............................:.......:........:.................:...............:.......................:....................:.....................:
簡単ですね。
データのRelational Propertyの関連がわかっていれば、同じように必要なObject Maskを追加して、lookup()で必要なデータを取得して表示することができます。
Relational Propertyの辿り方
今回の場合は、
- VSmanger内部でAccountサービスオブジェクトのgetVirtualGuests()メソッドを呼び出して、Virtual_Guestオブジェクトのリストを取得
- Virtual_Guestには、Relational Propertyとしてlocationプロパティ(Location)が関連付けられている
- さらにそのLocationオブジェクトにはpathStringがRelational Propertyとして定義されている(pathStringは稼働ホストの情報を表す)
という形で、データが関連付けられています。
この関連付けは、Data Typesからオブジェクトを検索してRelational Propertyを辿っていくことで確認できます。
Relational PropertyについてはShinobiLayer: SoftLayer API 次の一歩: データ型オブジェクト(2) - Qiitaが詳しいので、合わせて参照ください。