Switch to argparse for better client libary support.
Docs changed too to reflect better count support (--count). Removed v2 api implementation example (Archive resource). We can always revisit once we nail down how archive retrieval will work. Change-Id: I79d1929a14fe51d36ecc5c54707902d5e772ad89
This commit is contained in:
parent
312dbbdb1c
commit
0d491a9366
392
README.md
392
README.md
@ -3,166 +3,300 @@ klugman
|
||||
|
||||
Python library and cmdline tools for accessing Quincy.
|
||||
|
||||
|
||||
Examples:
|
||||
Using Klugman as a client library:
|
||||
|
||||
```
|
||||
$ klugman
|
||||
Usage:
|
||||
klugman.py [options] <command> [<args>...]
|
||||
klugman.py (-h | --help)
|
||||
klugman.py --version
|
||||
from klugman import v1
|
||||
|
||||
events = v1.Events('http://www.example.com:8000')
|
||||
data = events.get_events_count(name='compute.instance.update')
|
||||
|
||||
$ klugman -h
|
||||
Klugman - cmdline and client library for StackTach.v3
|
||||
streams = v1.Streams('http://www.example.com:8000')
|
||||
data = streams.get_streams(state='completed', details=True)
|
||||
```
|
||||
|
||||
Usage:
|
||||
klugman.py [options] <command> [<args>...]
|
||||
klugman.py (-h | --help)
|
||||
klugman.py --version
|
||||
Command-line Examples:
|
||||
|
||||
Options:
|
||||
-h --help Show this help message
|
||||
--version Show klugman version
|
||||
--debug Debug mode
|
||||
-a, --api_version <api_version>
|
||||
Which API version to use [default: latest]
|
||||
--url <url> StackTach.v3 server url [default: http://localhost:8000]
|
||||
```
|
||||
$ klugman http://127.0.0.1 streams -h
|
||||
usage: klugman url streams [-h] [--name trigger_name] [--from datetime]
|
||||
[--to datetime] [--traits trait_list] [--details]
|
||||
[--state {active,firing,expiring,error,expire_error,completed,retry_fire,retry_expire}]
|
||||
[--count | --id stream_id]
|
||||
|
||||
For a list of possible StackTach commands, use:
|
||||
klugman help
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--name trigger_name Return streams of type trigger_name.
|
||||
--from datetime Return streams last updated after datetime
|
||||
--to datetime Return streams last updated before datetime
|
||||
--traits trait_list Return streams with specific distinguishing traits.
|
||||
--details Return full event details.
|
||||
--state {active,firing,expiring,error,expire_error,completed,retry_fire,retry_expire}
|
||||
Only return streams in this state.
|
||||
--count Return a count of streams matching filter criteria.
|
||||
--id stream_id Return a single specific stream by id.
|
||||
|
||||
|
||||
$ klugman help
|
||||
Klugman - StackTach.v3 client
|
||||
|
||||
Usage:
|
||||
klugman.py [options] streams [<args>...]
|
||||
klugman.py num-streams [<args>...] [options]
|
||||
klugman.py [options] archives [<args>...]
|
||||
|
||||
Options:
|
||||
-h, --help show command options
|
||||
|
||||
|
||||
$ klugman num-streams
|
||||
$ klugman http://stacktach3-api01.example.com:8000 streams --count
|
||||
+----------+-------+
|
||||
| Property | Value |
|
||||
+----------+-------+
|
||||
| count | 19 |
|
||||
| count | 44216 |
|
||||
+----------+-------+
|
||||
|
||||
$ klugman num-streams --state completed
|
||||
$ klugman http://stacktach3-api01.example.com:8000 streams --count --state completed
|
||||
+----------+-------+
|
||||
| Property | Value |
|
||||
+----------+-------+
|
||||
| count | 4 |
|
||||
| count | 42571 |
|
||||
+----------+-------+
|
||||
|
||||
$ klugman num-streams --state active
|
||||
+----------+-------+
|
||||
| Property | Value |
|
||||
+----------+-------+
|
||||
| count | 15 |
|
||||
+----------+-------+
|
||||
|
||||
$ klugman streams -h
|
||||
usage:
|
||||
klugman.py streams [options]
|
||||
$ klugman http://stacktach3-api01.example.com:8000 streams
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Section | Property | Value |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Stream | id | 44171 |
|
||||
| Stream | state | active |
|
||||
| Stream | name | test_trigger |
|
||||
| Stream | first_event | 2015-04-22 21:06:09.400561 |
|
||||
| Stream | last_event | 2015-04-22 21:07:17.317974 |
|
||||
| Stream | fire_timestamp | None |
|
||||
| Stream | expire_timestamp | 2015-04-24 21:07:17.317974 |
|
||||
| D.Trait | instance_id | 3ed27346-5906-4790-9b6e-e095e5b0cfa4 |
|
||||
| D.Trait | timestamp | TimeRange from datetime.datetime(2015, 4, 22, 0, 0) to datetime.datetime(2015, 4, 23, 0, 0) |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
|
||||
options:
|
||||
--id <id>
|
||||
get stream with id
|
||||
--details
|
||||
return events with each stream
|
||||
--state <state>
|
||||
return streams in state
|
||||
--older_than <datetime>
|
||||
list streams where first_event < <datetime>
|
||||
--younger_than <datetime>
|
||||
list streams where last_event > <datetime>
|
||||
--trigger_name <name>
|
||||
list streams with given trigger definition
|
||||
--distinguishing_traits <dtraits>
|
||||
list stream with specific distriquishing traits
|
||||
|
||||
Stream states:
|
||||
collecting - collecting events
|
||||
ready - ready for processing
|
||||
triggered - being processed
|
||||
processed - processing completed
|
||||
error - pipeline processing failed
|
||||
commit_error - pipeline result commit failed
|
||||
|
||||
Distinguishing trait format:
|
||||
"trait:value;trait:value;..."
|
||||
|
||||
|
||||
$ klugman streams
|
||||
+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Property | Value |
|
||||
+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| id | 17 |
|
||||
| state | completed |
|
||||
| name | test_trigger |
|
||||
| first_event | 2015-01-31 13:21:50.679800 |
|
||||
| last_event | 2015-01-31 13:36:46.981800 |
|
||||
| fire_timestamp | 2015-01-30 18:52:03.196602 |
|
||||
| expire_timestamp | 2015-01-31 14:36:46.981800 |
|
||||
| distinguishing_traits | {u'instance_id': u'bd8b66f6-745b-45ce-b9c2-43010f8d9cdf', u'timestamp': TimeRange from datetime.datetime(2015, 1, 31, 0, 0) to datetime.datetime(2015, 2, 1, 0, 0)} |
|
||||
| events | None |
|
||||
+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
$ klugman streams --distinguishing_traits instance_id:1438620b-e426-4911-81cd-e5f82219a390
|
||||
...
|
||||
|
||||
|
||||
$ klugman streams --older_than 01-31-2015T13:30
|
||||
...
|
||||
|
||||
$ klugman streams --older_than 01-31-2015T13:30 --state completed
|
||||
...
|
||||
|
||||
$ klugman events --traits=os_distro:com.redhat
|
||||
$ klugman http://stacktach3-api01.example.com:8000 streams --id 44171 --detail
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Section | Property | Value |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Stream | id | 44171 |
|
||||
| Stream | state | active |
|
||||
| Stream | name | test_trigger |
|
||||
| Stream | first_event | 2015-04-22 21:06:09.400561 |
|
||||
| Stream | last_event | 2015-04-22 21:15:05.962515 |
|
||||
| Stream | fire_timestamp | None |
|
||||
| Stream | expire_timestamp | 2015-04-24 21:15:05.962515 |
|
||||
| D.Trait | instance_id | 3ed12384-5906-4790-9b6e-e095e5b0cfa4 |
|
||||
| D.Trait | timestamp | TimeRange from datetime.datetime(2015, 4, 22, 0, 0) to datetime.datetime(2015, 4, 23, 0, 0) |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
Events:
|
||||
+--------------------+------------------------------------------+
|
||||
| Property | Value |
|
||||
+--------------------+------------------------------------------+
|
||||
| _mark | 1 |
|
||||
| bandwidth_in | 537783 |
|
||||
| bandwidth_out | 19189871 |
|
||||
| disk_gb | 160 |
|
||||
| display_name | Instance_296624 |
|
||||
| disk_gb | 40 |
|
||||
| display_name | my_ubuntu1404 |
|
||||
| ephemeral_gb | 0 |
|
||||
| event_type | compute.instance.update |
|
||||
| instance_flavor | 4GB Standard Instance |
|
||||
| instance_flavor_id | 5 |
|
||||
| instance_id | 60c52a73-ec8e-47bc-81eb-eee38931a60e |
|
||||
| instance_type | 4GB Standard Instance |
|
||||
| launched_at | 2014-04-17 11:40:15.321940 |
|
||||
| memory_mb | 4096 |
|
||||
| message_id | 8eca72ba-3adb-4354-aaa4-f61980549e07 |
|
||||
| host | nova-api05.example.com |
|
||||
| instance_flavor | 1GB Standard Instance |
|
||||
| instance_flavor_id | 3 |
|
||||
| instance_id | 3ed23782-5906-4790-9b6e-e095e5b0cfa4 |
|
||||
| instance_type | 1GB Standard Instance |
|
||||
| memory_mb | 1024 |
|
||||
| message_id | a58e25ed-01f3-42d8-8979-5f1603ab2468 |
|
||||
| os_architecture | x64 |
|
||||
| os_distro | com.redhat |
|
||||
| os_version | 6.3 |
|
||||
| request_id | req-511c28a6-c6ec-4173-a124-7c92989e443c |
|
||||
| root_gb | 160 |
|
||||
| service | publisher-189550 |
|
||||
| state | active |
|
||||
| state_description | powering-off |
|
||||
| tenant_id | 854126 |
|
||||
| timestamp | 2015-03-03 20:13:56.560940 |
|
||||
| user_id | 366869 |
|
||||
| os_distro | com.ubuntu |
|
||||
| os_version | 14.04 |
|
||||
| request_id | req-758de1f9-03e9-4337-af7d-d9efe3efc730 |
|
||||
| root_gb | 40 |
|
||||
| service | api |
|
||||
| state | building |
|
||||
| state_description | scheduling |
|
||||
| tenant_id | 1234 |
|
||||
| timestamp | 2015-04-22 21:06:09.400561 |
|
||||
| user_id | 4567 |
|
||||
| vcpus | 1 |
|
||||
+--------------------+------------------------------------------+
|
||||
+--------------------+------------------------------------------+
|
||||
| Property | Value |
|
||||
+--------------------+------------------------------------------+
|
||||
| disk_gb | 40 |
|
||||
| display_name | my_ubuntu1404 |
|
||||
| ephemeral_gb | 0 |
|
||||
| event_type | compute.instance.update |
|
||||
| host | c-88-77-44-2 |
|
||||
| instance_flavor | 1GB Standard Instance |
|
||||
| instance_flavor_id | 3 |
|
||||
| instance_id | 3ed23782-5906-4790-9b6e-e095e5b0cfa4 |
|
||||
| instance_type | 1GB Standard Instance |
|
||||
| memory_mb | 1024 |
|
||||
| message_id | dbb6a5c0-08b8-45c8-85b4-a77b2b876bc3 |
|
||||
| os_architecture | x64 |
|
||||
| os_distro | com.ubuntu |
|
||||
| os_version | 14.04 |
|
||||
| request_id | req-758de1f9-03e9-4337-af7d-d9efe3efc730 |
|
||||
| root_gb | 40 |
|
||||
| service | None |
|
||||
| state | building |
|
||||
| state_description | |
|
||||
| tenant_id | 1234 |
|
||||
| timestamp | 2015-04-22 21:06:09.888688 |
|
||||
| user_id | 4567 |
|
||||
| vcpus | 1 |
|
||||
+--------------------+------------------------------------------+
|
||||
|
||||
|
||||
$ klugman http://stacktach3-api01.example.com:8000 streams --traits instance_id:633fe23b-7c6a-dead-beef-55fcc6803cbc
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Section | Property | Value |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Stream | id | 43993 |
|
||||
| Stream | state | active |
|
||||
| Stream | name | test_trigger |
|
||||
| Stream | first_event | 2015-04-22 18:21:28.462931 |
|
||||
| Stream | last_event | 2015-04-22 18:21:28.462931 |
|
||||
| Stream | fire_timestamp | None |
|
||||
| Stream | expire_timestamp | 2015-04-24 18:21:28.462931 |
|
||||
| D.Trait | instance_id | 633fe23b-7c6a-dead-beef-55fcc6803cbc |
|
||||
| D.Trait | timestamp | TimeRange from datetime.datetime(2015, 4, 22, 0, 0) to datetime.datetime(2015, 4, 23, 0, 0) |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Section | Property | Value |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Stream | id | 43992 |
|
||||
| Stream | state | active |
|
||||
| Stream | name | test_trigger |
|
||||
| Stream | first_event | 2015-04-22 18:21:27.905027 |
|
||||
| Stream | last_event | 2015-04-22 18:24:18.985118 |
|
||||
| Stream | fire_timestamp | None |
|
||||
| Stream | expire_timestamp | 2015-04-24 18:24:18.985118 |
|
||||
| D.Trait | instance_id | 633fe23b-7c6a-dead-beef-55fcc6803cbc |
|
||||
| D.Trait | timestamp | TimeRange from datetime.datetime(2015, 4, 22, 0, 0) to datetime.datetime(2015, 4, 23, 0, 0) |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
|
||||
$ klugman http://stacktach3-api01.example.com:8000 streams --state completed
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Section | Property | Value |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
| Stream | id | 43498 |
|
||||
| Stream | state | completed |
|
||||
| Stream | name | test_trigger |
|
||||
| Stream | first_event | 2015-04-20 00:00:18.740466 |
|
||||
| Stream | last_event | 2015-04-20 00:00:18.740466 |
|
||||
| Stream | fire_timestamp | 2015-04-22 11:53:37.441695 |
|
||||
| Stream | expire_timestamp | 2015-04-22 00:00:18.740466 |
|
||||
| D.Trait | instance_id | 7080633a-ffa3-dead-beef-d1549b4ac049 |
|
||||
| D.Trait | timestamp | TimeRange from datetime.datetime(2015, 4, 19, 0, 0) to datetime.datetime(2015, 4, 20, 0, 0) |
|
||||
+---------+------------------+---------------------------------------------------------------------------------------------+
|
||||
|
||||
$ klugman http://127.0.0.1 events -h
|
||||
usage: klugman url events [-h] [--name event_name] [--from datetime]
|
||||
[--to datetime] [--traits trait_list]
|
||||
[--count | --msg_id message_id]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--name event_name Return events of type event_name.
|
||||
--from datetime Return events generated before datetime
|
||||
--to datetime Return events generated after datetime
|
||||
--traits trait_list Return events with specific traits.
|
||||
--count Return a count of events matching filter criteria.
|
||||
--msg_id message_id Return a single specific event by message id.
|
||||
|
||||
|
||||
$ klugman http://stacktach3-api01.example.com:8000 events
|
||||
+--------------------+------------------------------------------+
|
||||
| Property | Value |
|
||||
+--------------------+------------------------------------------+
|
||||
| _mark | 6544b |
|
||||
| disk_gb | 80 |
|
||||
| display_name | My_Display_Name |
|
||||
| ephemeral_gb | 0 |
|
||||
| event_type | compute.instance.update |
|
||||
| host | c-11-22-33-4 |
|
||||
| instance_flavor | 2GB Standard Instance |
|
||||
| instance_flavor_id | 4 |
|
||||
| instance_id | 85240caf-71cf-dead-beef-6735298e6090 |
|
||||
| instance_type | 2GB Standard Instance |
|
||||
| memory_mb | 2048 |
|
||||
| message_id | c49d08be-dae5-4740-8f04-fb4cc27ac2fa |
|
||||
| os_architecture | x64 |
|
||||
| os_distro | org.centos |
|
||||
| os_version | 7 |
|
||||
| request_id | req-16b4995e-8a14-4b25-bd1c-ba68e82773f7 |
|
||||
| root_gb | 80 |
|
||||
| service | None |
|
||||
| state | building |
|
||||
| state_description | spawning |
|
||||
| tenant_id | 725 |
|
||||
| timestamp | 2015-04-22 21:43:29.940846 |
|
||||
| user_id | 945 |
|
||||
| vcpus | 2 |
|
||||
+--------------------+------------------------------------------+
|
||||
|
||||
$ klugman events --msg_id=8eca72ba-3adb-4354-aaa4-f61980549e07
|
||||
...
|
||||
|
||||
$ klugman http://stacktach3-api01.example.com:8000 events --name compute.instance.create.end
|
||||
+--------------------+------------------------------------------+
|
||||
| Property | Value |
|
||||
+--------------------+------------------------------------------+
|
||||
| _mark | 6547e |
|
||||
| disk_gb | 80 |
|
||||
| display_name | My_Display_Name |
|
||||
| ephemeral_gb | 0 |
|
||||
| event_type | compute.instance.create.end |
|
||||
| host | c-11-22-33-4 |
|
||||
| instance_flavor | 2GB Standard Instance |
|
||||
| instance_flavor_id | 4 |
|
||||
| instance_id | 0c30d4be-409d-dead-beef-6d8a3744e80f |
|
||||
| instance_type | 2GB Standard Instance |
|
||||
| launched_at | 2015-04-22 21:46:04 |
|
||||
| memory_mb | 2048 |
|
||||
| message | Success |
|
||||
| message_id | 51bd735f-9817-4940-9826-5b057bf51f70 |
|
||||
| os_architecture | x64 |
|
||||
| os_distro | com.microsoft.server |
|
||||
| os_version | 2012.0 |
|
||||
| rax_options | 4 |
|
||||
| request_id | req-108e129d-49fd-1213-8e93-3f5595fd4d6c |
|
||||
| root_gb | 80 |
|
||||
| service | compute |
|
||||
| state | active |
|
||||
| state_description | |
|
||||
| tenant_id | 3334 |
|
||||
| timestamp | 2015-04-22 21:46:05.066171 |
|
||||
| user_id | 3848 |
|
||||
| vcpus | 2 |
|
||||
+--------------------+------------------------------------------+
|
||||
|
||||
|
||||
$ klugman events --name=compute.instance.power_off.end
|
||||
...
|
||||
$ klugman http://stacktach3-api01.example.com:8000 events --name compute.instance.create.end --count
|
||||
+----------+-------+
|
||||
| Property | Value |
|
||||
+----------+-------+
|
||||
| count | 10280 |
|
||||
+----------+-------+
|
||||
|
||||
$ klugman events --from="2015-03-04T22:25" --to="2015-03-04T22:45"
|
||||
|
||||
$ klugman http://stacktach3-api01.example.com:8000 events --msg_id 047d9d5c-9190-4b85-9963-35d4cd095d07
|
||||
+--------------------+------------------------------------------+
|
||||
| Property | Value |
|
||||
+--------------------+------------------------------------------+
|
||||
| disk_gb | 80 |
|
||||
| display_name | My_Display_Name |
|
||||
| ephemeral_gb | 0 |
|
||||
| event_type | compute.instance.create.end |
|
||||
| host | c-11-22-33-4 |
|
||||
| instance_flavor | 2GB Standard Instance |
|
||||
| instance_flavor_id | 4 |
|
||||
| instance_id | b3c1be31-0ebe-4d6d-9663-b617eabac421 |
|
||||
| instance_type | 2GB Standard Instance |
|
||||
| launched_at | 2015-04-22 18:02:03 |
|
||||
| memory_mb | 2048 |
|
||||
| message | Success |
|
||||
| message_id | 047d9d5c-9190-4b85-9963-35d4cd095d07 |
|
||||
| os_architecture | x64 |
|
||||
| os_distro | org.debian |
|
||||
| os_version | 7 |
|
||||
| rax_options | 0 |
|
||||
| request_id | req-597b08a3-faef-425a-8f63-b91abcb1e1dd |
|
||||
| root_gb | 80 |
|
||||
| service | compute |
|
||||
| state | active |
|
||||
| tenant_id | 3334 |
|
||||
| timestamp | 2015-04-22 21:46:05.066171 |
|
||||
| user_id | 3848 |
|
||||
| vcpus | 2 |
|
||||
+--------------------+------------------------------------------+
|
||||
|
||||
```
|
||||
|
@ -13,6 +13,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import jsonutil
|
||||
|
||||
from docopt import docopt
|
||||
import prettytable
|
||||
import requests
|
||||
@ -32,26 +34,12 @@ def dump_response(keys, rows):
|
||||
print x
|
||||
|
||||
|
||||
def get(url, cmd, params):
|
||||
def get(url, cmd, params, debug=False):
|
||||
final = "%s/%s" % (url, cmd)
|
||||
if debug:
|
||||
print 'URL: %s' % final
|
||||
for item in params.items():
|
||||
print " : %s='%s'" % item
|
||||
ret = requests.get(final, params=params)
|
||||
ret.raise_for_status()
|
||||
return ret
|
||||
|
||||
|
||||
class Impl(object):
|
||||
def __init__(self, base_url, base_args, cmds, docs):
|
||||
self.base_url = base_url
|
||||
self.base_args = base_args
|
||||
self.cmds = cmds
|
||||
self.docs = docs
|
||||
|
||||
def dispatch(self, cmdline):
|
||||
arguments = docopt(self.docs, argv=cmdline, help=False,
|
||||
options_first=True)
|
||||
if self.base_args['--debug']:
|
||||
print arguments
|
||||
|
||||
for key in self.cmds.keys():
|
||||
if arguments.get(key):
|
||||
self.cmds[key].cmdline(self, cmdline)
|
||||
return ret.json(object_hook=jsonutil.object_hook)
|
||||
|
@ -13,57 +13,41 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Klugman - cmdline and client library for StackTach.v3
|
||||
|
||||
Usage:
|
||||
klugman.py [options] <command> [<args>...]
|
||||
klugman.py (-h | --help)
|
||||
klugman.py --version
|
||||
|
||||
Options:
|
||||
-h --help Show this help message
|
||||
--version Show klugman version
|
||||
--debug Debug mode
|
||||
-a, --api_version <api_version>
|
||||
Which API version to use [default: latest]
|
||||
--url <url> StackTach.v3 server url [default: http://localhost:8000]
|
||||
|
||||
For a list of possible StackTach commands, use:
|
||||
klugman help
|
||||
|
||||
"""
|
||||
|
||||
from docopt import docopt
|
||||
|
||||
import argparse
|
||||
|
||||
import v1
|
||||
import v2
|
||||
|
||||
versions = {1: v1.V1, 2: v2.V2}
|
||||
versions = {1: v1.V1}
|
||||
latest = 1
|
||||
|
||||
|
||||
def main():
|
||||
arguments = docopt(__doc__, options_first=True)
|
||||
if arguments['--debug']:
|
||||
print arguments
|
||||
def _get_base_parser():
|
||||
parser = argparse.ArgumentParser(description='Klugman cmdline tool')
|
||||
parser.add_argument('--version', metavar='version', type=int,
|
||||
default=latest, help='Which api version to use.')
|
||||
parser.add_argument('url', metavar='url',
|
||||
help='The API endpoint url')
|
||||
parser.add_argument('--debug', action='store_true',
|
||||
default=False, help='Enable debugging.')
|
||||
return parser
|
||||
|
||||
version = arguments["--api_version"]
|
||||
if version == "latest":
|
||||
version = latest
|
||||
else:
|
||||
version = int(version)
|
||||
|
||||
def main():
|
||||
parser = _get_base_parser()
|
||||
parser.add_argument('args', nargs=argparse.REMAINDER)
|
||||
arguments = parser.parse_args()
|
||||
|
||||
version = arguments.version
|
||||
impl = versions[version]
|
||||
|
||||
url = "%s/v%d" % (arguments["--url"], version)
|
||||
cmd = arguments['<command>']
|
||||
argv = [cmd] + arguments['<args>']
|
||||
url = "%s/v%d" % (arguments.url, version)
|
||||
|
||||
api = impl(url, arguments)
|
||||
if cmd == 'help':
|
||||
print api.__doc__
|
||||
else:
|
||||
api.dispatch(argv)
|
||||
# Ok, we got past the basics. Add the subparsers and try again ...
|
||||
parser = _get_base_parser()
|
||||
api = impl(url, parser)
|
||||
arguments = parser.parse_args()
|
||||
|
||||
api.dispatch(arguments)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
417
klugman/v1.py
417
klugman/v1.py
@ -14,76 +14,105 @@
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import base
|
||||
import json
|
||||
import jsonutil
|
||||
import argparse
|
||||
import prettytable
|
||||
import sys
|
||||
|
||||
from docopt import docopt
|
||||
|
||||
|
||||
def check_state(state):
|
||||
if state and state not in ["active", "firing", "expiring", "error",
|
||||
"expire_error", "completed",
|
||||
"retry_fire", "retry_expire"]:
|
||||
print "Invalid state. %s not one of 'active, firing, " \
|
||||
"expiring, error, expire_error, completed, " \
|
||||
"retry_fire or retry_expire" % state
|
||||
sys.exit(1)
|
||||
import base
|
||||
|
||||
|
||||
class Streams(object):
|
||||
"""usage:
|
||||
klugman.py streams [options]
|
||||
def __init__(self, url, subparser=None):
|
||||
self.url = url
|
||||
if subparser:
|
||||
parser = subparser.add_parser('streams')
|
||||
parser.add_argument('--name', metavar='trigger_name',
|
||||
help='Return streams of type trigger_name.')
|
||||
parser.add_argument('--from', metavar='datetime', dest='_from',
|
||||
help='Return streams last updated after datetime')
|
||||
parser.add_argument('--to', metavar='datetime',
|
||||
help='Return streams last updated before datetime')
|
||||
parser.add_argument('--traits', metavar='trait_list',
|
||||
help='Return streams with specific distinguishing traits.')
|
||||
parser.add_argument('--details', action='store_true',
|
||||
default=False, help='Return full event details.')
|
||||
parser.add_argument('--state', choices=['active', 'firing',
|
||||
'expiring', 'error', 'expire_error', 'completed',
|
||||
'retry_fire', 'retry_expire'],
|
||||
help='Only return streams in this state.')
|
||||
|
||||
options:
|
||||
--id <id>
|
||||
get stream with id
|
||||
--details
|
||||
return events with each stream
|
||||
--state <state>
|
||||
return streams in state
|
||||
--older_than <datetime>
|
||||
list streams where first_event < <datetime>
|
||||
--younger_than <datetime>
|
||||
list streams where last_event > <datetime>
|
||||
--trigger_name <name>
|
||||
list streams with given trigger definition
|
||||
--distinguishing_traits <dtraits>
|
||||
list stream with specific distinguishing traits
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument('--count', action='store_true',
|
||||
default=False,
|
||||
help='Return a count of streams matching filter criteria.')
|
||||
group.add_argument('--id', metavar='stream_id', dest='stream_id',
|
||||
help='Return a single specific stream by id.')
|
||||
|
||||
Stream states:
|
||||
collecting - collecting events
|
||||
ready - ready for processing
|
||||
triggered - being processed
|
||||
processed - processing completed
|
||||
error - pipeline processing failed
|
||||
commit_error - pipeline result commit failed
|
||||
def get_streams_count(self, from_datetime=None, to_datetime=None,
|
||||
traits=None, state=None, name=None, debug=False):
|
||||
if traits:
|
||||
traits = ",".join(["%s:%s" % item for item in traits.items()])
|
||||
cmd = "streams/count"
|
||||
params = base.remove_empty({'older_than': from_datetime,
|
||||
'younger_than': to_datetime,
|
||||
'name': name,
|
||||
'state': state,
|
||||
'distinguishing_traits': traits})
|
||||
|
||||
Distinguishing trait format:
|
||||
"trait:value;trait:value;..."
|
||||
"""
|
||||
return base.get(self.url, cmd, params, debug=debug)
|
||||
|
||||
def cmdline(self, version, cmdline):
|
||||
arguments = docopt(Streams.__doc__, argv=cmdline)
|
||||
debug = version.base_args['--debug']
|
||||
if debug:
|
||||
print arguments
|
||||
def get_streams(self, from_datetime=None, to_datetime=None,
|
||||
traits=None, name=None, stream_id=None, debug=False,
|
||||
state=None, details=None):
|
||||
if stream_id:
|
||||
params = base.remove_empty({'details': details})
|
||||
return base.get(self.url, "streams/%s" % stream_id, params,
|
||||
debug=debug)
|
||||
|
||||
response = self.do_streams(version, arguments)
|
||||
# Handle cmdline output here, not in do_foo()
|
||||
raw_rows = response.json(object_hook=jsonutil.object_hook)
|
||||
if traits:
|
||||
traits = ",".join(["%s:%s" % item for item in traits.items()])
|
||||
cmd = "streams"
|
||||
params = base.remove_empty({'older_than': from_datetime,
|
||||
'younger_than': to_datetime,
|
||||
'name': name,
|
||||
'details': details,
|
||||
'state': state,
|
||||
'distinguishing_traits': traits})
|
||||
|
||||
if debug:
|
||||
print json.dumps(raw_rows, indent=2)
|
||||
return base.get(self.url, cmd, params, debug=debug)
|
||||
|
||||
# TODO(sandy): This should come from the server-issued
|
||||
# schema at some point.
|
||||
def _cmdline(self, arguments):
|
||||
_from = arguments._from
|
||||
_to = arguments.to
|
||||
_name = arguments.name
|
||||
_traits = arguments.traits
|
||||
_debug = arguments.debug
|
||||
_state = arguments.state
|
||||
_details = arguments.details
|
||||
|
||||
trait_dict = None
|
||||
if _traits:
|
||||
trait_pairs = _traits.split(',')
|
||||
trait_dict = dict([tuple(item.split(':')) for item in trait_pairs])
|
||||
|
||||
if arguments.count:
|
||||
rows = self.get_streams_count(from_datetime=_from, to_datetime=_to,
|
||||
name=_name, traits=trait_dict,
|
||||
state=_state, debug=_debug)
|
||||
print rows
|
||||
keys = ['count']
|
||||
base.dump_response(keys, rows)
|
||||
return
|
||||
|
||||
_stream_id = arguments.stream_id
|
||||
rows = self.get_streams(from_datetime=_from, to_datetime=_to,
|
||||
name=_name, traits=trait_dict,
|
||||
details=_details, state=_state,
|
||||
stream_id=_stream_id, debug=_debug)
|
||||
|
||||
keys = ['id', 'state', 'name', 'first_event', 'last_event',
|
||||
'fire_timestamp', 'expire_timestamp']
|
||||
for row in raw_rows:
|
||||
for row in rows:
|
||||
x = prettytable.PrettyTable(["Section", "Property", "Value"])
|
||||
for key in keys:
|
||||
x.add_row(["Stream", key, row.get(key)])
|
||||
@ -105,209 +134,105 @@ class Streams(object):
|
||||
print x
|
||||
|
||||
|
||||
def do_streams(self, version, arguments):
|
||||
sid = arguments.get('--id')
|
||||
state = arguments.get('--state')
|
||||
older = arguments.get('--older_than')
|
||||
younger = arguments.get('--younger_than')
|
||||
trigger = arguments.get('--trigger_name')
|
||||
traits = arguments.get('--distinguishing_traits')
|
||||
details = arguments.get('--details')
|
||||
|
||||
check_state(state)
|
||||
cmd = "streams"
|
||||
if sid:
|
||||
cmd = "streams/%s" % sid
|
||||
return base.get(version.base_url, cmd, {'details': details})
|
||||
|
||||
params = base.remove_empty({'state': state,
|
||||
'older_than': older,
|
||||
'younger_than': younger,
|
||||
'trigger_name': trigger,
|
||||
'distinguishing_traits': traits,
|
||||
'details': details})
|
||||
|
||||
return base.get(version.base_url, cmd, params)
|
||||
|
||||
|
||||
class NumStreams(object):
|
||||
"""usage:
|
||||
klugman.py num-streams [options]
|
||||
|
||||
options:
|
||||
--state <state>
|
||||
return streams in state
|
||||
--older_than <datetime>
|
||||
list streams older than datetime
|
||||
--older_than <datetime>
|
||||
list streams where first_event < <datetime>
|
||||
--younger_than <datetime>
|
||||
list streams where last_event > <datetime>
|
||||
--distinguishing_traits <dtraits>
|
||||
list stream with specific distinguishing traits
|
||||
|
||||
Stream states:
|
||||
active = collecting events
|
||||
firing = about to process events
|
||||
expiring = about to expire stream
|
||||
error = pipeline processing failed
|
||||
expire_error = pipeline expiry failed
|
||||
completed = stream processing completed
|
||||
retry_fire = re-attempt pipeline firing
|
||||
retry_expire = re-attempt pipeline expiry
|
||||
|
||||
Distinguishing trait format:
|
||||
"trait:value;trait:value;..."
|
||||
"""
|
||||
|
||||
def cmdline(self, version, cmdline):
|
||||
arguments = docopt(NumStreams.__doc__, argv=cmdline)
|
||||
debug = version.base_args['--debug']
|
||||
if debug:
|
||||
print arguments
|
||||
|
||||
response = self.do_stream_count(version, arguments)
|
||||
raw_rows = response.json(object_hook=jsonutil.object_hook)
|
||||
|
||||
keys = ['count']
|
||||
base.dump_response(keys, raw_rows)
|
||||
|
||||
def do_stream_count(self, version, arguments):
|
||||
state = arguments.get('--state')
|
||||
older = arguments.get('--older_than')
|
||||
younger = arguments.get('--younger_than')
|
||||
trigger = arguments.get('--trigger_name')
|
||||
traits = arguments.get('--distinguishing_traits')
|
||||
|
||||
check_state(state)
|
||||
|
||||
cmd = "streams/count"
|
||||
params = base.remove_empty({'state': state,
|
||||
'older_than': older,
|
||||
'younger_than': younger,
|
||||
'trigger_name': trigger,
|
||||
'distinguishing_traits': traits})
|
||||
|
||||
return base.get(version.base_url, cmd, params)
|
||||
|
||||
|
||||
class Events(object):
|
||||
"""usage:
|
||||
klugman.py events [options]
|
||||
def __init__(self, url, subparser=None):
|
||||
self.url = url
|
||||
if subparser:
|
||||
parser = subparser.add_parser('events')
|
||||
parser.add_argument('--name', metavar='event_name',
|
||||
help='Return events of type event_name.')
|
||||
parser.add_argument('--from', metavar='datetime', dest='_from',
|
||||
help='Return events generated before datetime')
|
||||
parser.add_argument('--to', metavar='datetime',
|
||||
help='Return events generated after datetime')
|
||||
parser.add_argument('--traits', metavar='trait_list',
|
||||
help='Return events with specific traits.')
|
||||
|
||||
options:
|
||||
--debug
|
||||
--name <name>
|
||||
return events of type <name>
|
||||
--from <datetime>
|
||||
list events generated before datetime
|
||||
--to <datetime>
|
||||
list events generated after datetime
|
||||
--traits <traits>
|
||||
list events with specific traits
|
||||
--msg_id <message_id>
|
||||
get event with <message_id>
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument('--count', action='store_true',
|
||||
default=False,
|
||||
help='Return a count of events matching filter criteria.')
|
||||
group.add_argument('--msg_id', metavar='message_id',
|
||||
help='Return a single specific event by message id.')
|
||||
|
||||
Trait format:
|
||||
"trait:value;trait:value;..."
|
||||
"""
|
||||
|
||||
def cmdline(self, version, cmdline):
|
||||
arguments = docopt(Events.__doc__, argv=cmdline)
|
||||
debug = version.base_args['--debug']
|
||||
if debug:
|
||||
print arguments
|
||||
def get_events_count(self, from_datetime=None, to_datetime=None,
|
||||
traits=None, name=None, debug=False):
|
||||
if traits:
|
||||
traits = ",".join(["%s:%s" % item for item in traits.items()])
|
||||
cmd = "events/count"
|
||||
params = base.remove_empty({'from_datetime': from_datetime,
|
||||
'to_datetime': to_datetime,
|
||||
'event_name': name,
|
||||
'traits': traits})
|
||||
|
||||
response = self.do_event(version, arguments)
|
||||
raw_rows = response.json(object_hook=jsonutil.object_hook)
|
||||
return base.get(self.url, cmd, params, debug=debug)
|
||||
|
||||
if isinstance(raw_rows, dict):
|
||||
raw_rows = [raw_rows]
|
||||
def get_events(self, from_datetime=None, to_datetime=None,
|
||||
traits=None, name=None, msg_id=None, debug=False):
|
||||
if msg_id:
|
||||
return base.get(self.url, "events/%s" % msg_id, {}, debug=debug)
|
||||
|
||||
if traits:
|
||||
traits = ",".join(["%s:%s" % item for item in traits.items()])
|
||||
cmd = "events"
|
||||
params = base.remove_empty({'from_datetime': from_datetime,
|
||||
'to_datetime': to_datetime,
|
||||
'event_name': name,
|
||||
'traits': traits})
|
||||
|
||||
return base.get(self.url, cmd, params, debug=debug)
|
||||
|
||||
def _cmdline(self, arguments):
|
||||
_from = arguments._from
|
||||
_to = arguments.to
|
||||
_name = arguments.name
|
||||
_traits = arguments.traits
|
||||
_debug = arguments.debug
|
||||
|
||||
trait_dict = None
|
||||
if _traits:
|
||||
trait_pairs = _traits.split(',')
|
||||
trait_dict = dict([tuple(item.split(':')) for item in trait_pairs])
|
||||
|
||||
if arguments.count:
|
||||
rows = self.get_events_count(from_datetime=_from, to_datetime=_to,
|
||||
name=_name, traits=trait_dict,
|
||||
debug=_debug)
|
||||
keys = ['count']
|
||||
base.dump_response(keys, rows)
|
||||
return
|
||||
|
||||
_msg_id = arguments.msg_id
|
||||
rows = self.get_events(from_datetime=_from, to_datetime=_to,
|
||||
name=_name, traits=trait_dict,
|
||||
msg_id=_msg_id, debug=_debug)
|
||||
|
||||
if isinstance(rows, dict):
|
||||
rows = [rows]
|
||||
keys = set()
|
||||
for row in raw_rows:
|
||||
for row in rows:
|
||||
keys.update(row.keys())
|
||||
keys = sorted(list(keys))
|
||||
base.dump_response(keys, raw_rows)
|
||||
|
||||
def do_event(self, version, arguments):
|
||||
_from = arguments.get('--from')
|
||||
_to = arguments.get('--to')
|
||||
name = arguments.get('--name')
|
||||
traits = arguments.get('--traits')
|
||||
msg_id = arguments.get('--msg_id')
|
||||
|
||||
if msg_id:
|
||||
cmd = "events/%s" % msg_id
|
||||
return base.get(version.base_url, cmd, {})
|
||||
|
||||
cmd = "events"
|
||||
params = base.remove_empty({'from_datetime': _from,
|
||||
'to_datetime': _to,
|
||||
'event_name': name,
|
||||
'traits': traits})
|
||||
|
||||
return base.get(version.base_url, cmd, params)
|
||||
base.dump_response(keys, rows)
|
||||
|
||||
|
||||
class NumEvents(object):
|
||||
"""usage:
|
||||
klugman.py num-events [options]
|
||||
class V1(object):
|
||||
def __init__(self, url, parser):
|
||||
subparser = parser.add_subparsers(dest='command',
|
||||
help="V1 API commands")
|
||||
self.resources = {'events': Events(url, subparser),
|
||||
'streams': Streams(url, subparser)}
|
||||
|
||||
options:
|
||||
--debug
|
||||
--name <name>
|
||||
return events of type <name>
|
||||
--from <datetime>
|
||||
list events generated before datetime
|
||||
--to <datetime>
|
||||
list events generated after datetime
|
||||
--traits <traits>
|
||||
list events with specific traits
|
||||
def dispatch(self, arguments):
|
||||
# We could let argparse dispatch automatically, but I
|
||||
# want to make this work as a library as well as a
|
||||
# cmdline tool, so it goes to an object vs. a function.
|
||||
cmd = arguments.command
|
||||
|
||||
Trait format:
|
||||
"trait:value;trait:value;..."
|
||||
"""
|
||||
# This shouldn't be needed, but I'm being paranoid.
|
||||
if cmd not in self.resources:
|
||||
print "Unknown command: '%s'" % cmd
|
||||
return
|
||||
|
||||
def cmdline(self, version, cmdline):
|
||||
arguments = docopt(NumEvents.__doc__, argv=cmdline)
|
||||
debug = version.base_args['--debug']
|
||||
if debug:
|
||||
print arguments
|
||||
|
||||
response = self.do_event(version, arguments)
|
||||
raw_rows = response.json(object_hook=jsonutil.object_hook)
|
||||
|
||||
keys = ['count']
|
||||
base.dump_response(keys, raw_rows)
|
||||
|
||||
def do_event(self, version, arguments):
|
||||
_from = arguments.get('--from')
|
||||
_to = arguments.get('--to')
|
||||
name = arguments.get('--name')
|
||||
traits = arguments.get('--traits')
|
||||
|
||||
cmd = "events/count"
|
||||
params = base.remove_empty({'from_datetime': _from,
|
||||
'to_datetime': _to,
|
||||
'event_name': name,
|
||||
'traits': traits})
|
||||
|
||||
return base.get(version.base_url, cmd, params)
|
||||
|
||||
|
||||
class V1(base.Impl):
|
||||
"""usage:
|
||||
klugman.py streams [<args>...] [options]
|
||||
klugman.py num-streams [<args>...] [options]
|
||||
klugman.py events [<args>...] [options]
|
||||
klugman.py num-events [<args>...] [options]
|
||||
|
||||
-h, --help show command options
|
||||
"""
|
||||
|
||||
def __init__(self, base_url, base_args):
|
||||
cmds = {'streams': Streams(),
|
||||
'num-streams': NumStreams(),
|
||||
'events': Events(),
|
||||
'num-events': NumEvents()}
|
||||
super(V1, self).__init__(base_url, base_args, cmds, V1.__doc__)
|
||||
self.resources[cmd]._cmdline(arguments)
|
||||
|
@ -1,80 +0,0 @@
|
||||
# Copyright (c) 2014 Dark Secret Software Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import base
|
||||
import v1
|
||||
import jsonutil
|
||||
|
||||
from docopt import docopt
|
||||
import requests
|
||||
|
||||
|
||||
class Archives(object):
|
||||
"""usage:
|
||||
klugman.py archives <start_datetime> <end_datetime> [options]
|
||||
|
||||
options:
|
||||
-h, --help
|
||||
<start_datetime> starting datetime range
|
||||
<end_datetime> ending datetime range
|
||||
|
||||
"""
|
||||
|
||||
def cmdline(self, version, cmdline):
|
||||
arguments = docopt(Archives.__doc__, argv=cmdline)
|
||||
if version.base_args['--debug']:
|
||||
print arguments
|
||||
|
||||
response = self.do_archives(version, arguments)
|
||||
raw_rows = response.json(object_hook=jsonutil.object_hook)
|
||||
|
||||
keys = ['id', 'filename']
|
||||
base.dump_response(keys, raw_rows)
|
||||
|
||||
def do_archives(self, version, arguments):
|
||||
start = arguments.get('--start')
|
||||
end = arguments.get('--end')
|
||||
|
||||
cmd = "archives"
|
||||
params = base.remove_empty({'start_ts': start,
|
||||
'end_ts': end})
|
||||
|
||||
return base.get(version.base_url, cmd, params)
|
||||
|
||||
|
||||
class V2(base.Impl):
|
||||
|
||||
# Note the [<args>...] [options] approach
|
||||
# which basically says "anything is acceptable".
|
||||
# We will be more strict in the actual command handler.
|
||||
"""Klugman - StackTach.v3 client
|
||||
|
||||
Usage:
|
||||
klugman.py [options] streams [<args>...]
|
||||
klugman.py num-streams [<args>...] [options]
|
||||
klugman.py events [<args>...] [options]
|
||||
klugman.py [options] archives [<args>...]
|
||||
|
||||
Options:
|
||||
-h, --help show command options
|
||||
"""
|
||||
|
||||
def __init__(self, base_url, base_args):
|
||||
cmds = {'streams': v1.Streams(),
|
||||
'num-streams': v1.NumStreams(),
|
||||
'events': v1.Events(),
|
||||
'archives': Archives()}
|
||||
super(V2, self).__init__(base_url, base_args, cmds, V2.__doc__)
|
Loading…
Reference in New Issue
Block a user