ようへいの日々精進XP

よかろうもん

Supercharged AWS CLI = SAWS メモ(2)〜リソース補完を追加してみる〜

tl;dr

前回の続き。 触ってみただけではつまらないのでリソース補完を追加してみたのでメモ。


DynamoDB のテーブル名を補完してみる

追加実装の概要

  1. リソースリストを取得、管理する resources.py に取得したいリソース方法を記述する(aws dynamodb list-tables --query TableNames --output text を実行する)
  2. コマンドの補完機能が実装されている completer.py に対象のリソースとどのオプションがある場合にリソースリストを出力するかを定義する(--list-table オプションを利用した際にリソース(テーブル)一覧を表示する)

実際の修正

  • resources.py(リソースの取得、管理)
--- resources.py.bk  2015-09-23 11:14:46.000000000 +0900
+++ resources.py  2015-09-23 11:50:49.000000000 +0900
@@ -67,13 +67,14 @@
         """
 
         INSTANCE_IDS, INSTANCE_TAG_KEYS, INSTANCE_TAG_VALUES, \
-            BUCKET_NAMES = range(4)
+            BUCKET_NAMES = range(4) 
 
     def __init__(self,
                  log_exception,
                  refresh_instance_ids=True,
                  refresh_instance_tags=True,
-                 refresh_bucket_names=True):
+                 refresh_bucket_names=True,
+                 refresh_dynamodb_table_names=True):  # added by inokappa
         """Initializes AwsResources.
 
         Args:
@@ -94,23 +95,32 @@
         self.instance_tag_values = set()
         self.bucket_names = []  # TODO: Make this 'private'
         self.s3_uri_names = []  # TODO: Make this 'private'
+        self.dynamodb_table_names = [] # added by inokappa
+
         self.refresh_instance_ids = refresh_instance_ids
         self.refresh_instance_tags = refresh_instance_tags
         self.refresh_bucket_names = refresh_bucket_names
+        self.refresh_dynamodb_table_names = refresh_dynamodb_table_names # added by inokappa
+
         self.INSTANCE_IDS_MARKER = '[instance ids]'
         self.INSTANCE_TAG_KEYS_MARKER = '[instance tag keys]'
         self.INSTANCE_TAG_VALUES_MARKER = '[instance tag values]'
         self.BUCKET_NAMES_MARKER = '[bucket names]'
+        self.DYNAMODB_TABLE_NAMES_MARKER = '[dynamodb table names]' # added by inokapp
+
         self.INSTANCE_IDS = '--instance-ids'
         self.EC2_TAG_KEY = '--ec2-tag-key'
         self.EC2_TAG_VALUE = '--ec2-tag-value'
         self.EC2_STATE = '--ec2-state'
         self.BUCKET = '--bucket'
         self.S3_URI = 's3:'
+        self.DYNAMODB_TABLE = '--table-name'
+
         self.QUERY_INSTANCE_IDS_CMD = 'aws ec2 describe-instances --query "Reservations[].Instances[].[InstanceId]" --output text'
         self.QUERY_INSTANCE_TAG_KEYS_CMD = 'aws ec2 describe-instances --filters "Name=tag-key,Values=*" --query Reservations[].Instances[].Tags[].Key --output text'
         self.QUERY_INSTANCE_TAG_VALUES_CMD = 'aws ec2 describe-instances --filters "Name=tag-value,Values=*" --query Reservations[].Instances[].Tags[].Value --output text'
         self.QUERY_BUCKET_NAMES_CMD = 'aws s3 ls'
+        self.QUERY_DYNAMODB_TABLE_NAMES_CMD = 'aws dynamodb list-tables --query TableNames --output text' # added by inokapp
         self.log_exception = log_exception
 
     def refresh(self, force_refresh=False):
@@ -150,6 +160,9 @@
             if self.refresh_bucket_names:
                 print('  Refreshing bucket names...')
                 self.query_bucket_names()
+            if self.refresh_dynamodb_table_names:
+                print('  Refreshing DynamoDB table names...')
+                self.query_dynamodb_table_names()
             print('Done refreshing')
         try:
             self.save_resources_to_file(file_path)
@@ -224,6 +237,21 @@
                 except:
                     # Ignore blank lines
                     pass
+   
+    # added by inokappa
+    def query_dynamodb_table_names(self):
+        """Queries and stores DynamoDB table names from AWS.
+
+        Args:
+            * None.
+
+        Returns:
+            None.
+        """
+        output = self.query_aws(self.QUERY_DYNAMODB_TABLE_NAMES_CMD)
+        if output is not None:
+            output = re.sub('\n', ' ', output)
+            self.dynamodb_table_names = output.split()
 
     def add_bucket_name(self, bucket_name):
         """Adds the bucket name to our bucket resources.
@@ -317,3 +345,7 @@
             fp.write(self.BUCKET_NAMES_MARKER + '\n')
             for bucket_name in self.bucket_names:
                 fp.write(bucket_name + '\n')
+            # added by inokapp
+            fp.write(self.DYNAMODB_TABLE_NAMES_MARKER + '\n')
+            for dynamodb_table_name in self.dynamodb_table_names:
+                fp.write(dynamodb_table_name + '\n')

実際のリソース取得は...

        self.QUERY_DYNAMODB_TABLE_NAMES_CMD = 'aws dynamodb list-tables --query TableNames --output text' # added by inokapp

上記のように AWS CLI を叩いているのが解る。これが saws 起動時、F5 でリフレッシュされる度に実行されてリソースリストが生成、更新される。

  • completer.py(コマンドオプションの補完機能)
% diff -u completer.py.bk completer.py
--- completer.py.bk     2015-09-23 16:20:43.000000000 +0900
+++ completer.py        2015-09-23 16:20:50.000000000 +0900
@@ -112,13 +112,15 @@
                                       self.resources.EC2_TAG_VALUE,
                                       self.resources.EC2_STATE,
                                       self.resources.BUCKET,
-                                      self.resources.S3_URI],
+                                      self.resources.S3_URI,
+                                      self.resources.DYNAMODB_TABLE],
                                      [self.resources.instance_ids,
                                       self.resources.instance_tag_keys,
                                       self.resources.instance_tag_values,
                                       self.ec2_states,
                                       self.resources.bucket_names,
-                                      self.resources.s3_uri_names]))
+                                      self.resources.s3_uri_names,
+                                      self.resources.dynamodb_table_names]))
 
     def refresh_resources(self, force_refresh=False):
         """Convenience function to refresh resources for completion.

補完されてるの図

f:id:inokara:20150923163301p:plain

キタキタ。とりあえず、動いている。

取得されたリソース情報はテキストファイルに保存されているので確認してみる。

% cat /opt/boxen/homebrew/lib/python2.7/site-packages/saws/data/RESOURCES.txt | grep -A 5 dynamo 
[dynamodb table names]
soramame
soramame-2015-09-22

ちゃんとテキストファイルにも記録されている。


おわり

Pull Request してみたいけど

試しにリソース補完機能を拡張してみたが、以下の点が気になったのでメモ。

  • 追加サービスのリソース取得の実装を全て resources.py に書くのは大変そう
  • resources.py と completer.py の 2 つのファイルを修正するのも大変そう

も少し調べたりして Pull Request or Issue をチャレンジしてみたい。