11"""Call arbitrary API endpoints."""
2- import json
3-
42import click
53
64from SoftLayer .CLI import environment
75from SoftLayer .CLI import formatting
6+ from SoftLayer .CLI import helpers
7+ from SoftLayer import utils
8+
9+
10+ def _build_filters (_filters ):
11+ """Builds filters using the filter options passed into the CLI.
12+
13+ This only supports the equals keyword at the moment.
14+ """
15+ root = utils .NestedDict ({})
16+ for _filter in _filters :
17+ # split "some.key=value" into ["some.key", "value"]
18+ key , value = _filter .split ('=' , 1 )
19+
20+ current = root
21+ # split "some.key" into ["some", "key"]
22+ parts = [part .strip () for part in key .split ('.' )]
823
9- # pylint: disable=unused-argument
24+ # Actually drill down and add the filter
25+ for part in parts [:- 1 ]:
26+ current = current [part ]
27+ current [parts [- 1 ]] = utils .query_filter (value .strip ())
1028
29+ return root .to_dict ()
1130
12- def validate_filter (ctx , param , value ):
13- """Try to parse the given filter as a JSON string."""
14- try :
15- if value :
16- return json .loads (value )
17- except ValueError :
18- raise click .BadParameter ('filters need to be in JSON format' )
31+
32+ def _build_python_example (args , kwargs ):
33+ sorted_kwargs = sorted (kwargs .items ())
34+
35+ call_str = 'import SoftLayer\n \n '
36+ call_str += 'client = SoftLayer.create_client_from_env()\n '
37+ call_str += 'result = client.call('
38+ arg_list = [repr (arg ) for arg in args ]
39+ arg_list += [key + '=' + repr (value )
40+ for key , value in sorted_kwargs if value ]
41+ call_str += ',\n ' .join (arg_list )
42+ call_str += ')'
43+
44+ return call_str
1945
2046
2147@click .command ('call' , short_help = "Call arbitrary API endpoints." )
2248@click .argument ('service' )
2349@click .argument ('method' )
2450@click .argument ('parameters' , nargs = - 1 )
2551@click .option ('--id' , '_id' , help = "Init parameter" )
26- @click .option ('--filter' , '_filter' ,
27- callback = validate_filter ,
28- help = "Object filter in a JSON string" )
52+ @helpers .multi_option ('--filter' , '-f' , '_filters' ,
53+ help = "Object filters. This should be of the form: "
54+ "'property=value' or 'nested.property=value'. Complex "
55+ "filters like betweenDate are not currently supported." )
2956@click .option ('--mask' , help = "String-based object mask" )
3057@click .option ('--limit' , type = click .INT , help = "Result limit" )
3158@click .option ('--offset' , type = click .INT , help = "Result offset" )
59+ @click .option ('--output-python / --no-output-python' ,
60+ help = "Show python example code instead of executing the call" )
3261@environment .pass_env
33- def cli (env , service , method , parameters , _id , _filter , mask , limit , offset ):
62+ def cli (env , service , method , parameters , _id , _filters , mask , limit , offset ,
63+ output_python = False ):
3464 """Call arbitrary API endpoints with the given SERVICE and METHOD.
3565
3666 \b
@@ -40,11 +70,23 @@ def cli(env, service, method, parameters, _id, _filter, mask, limit, offset):
4070 slcli call-api Virtual_Guest getObject --id=12345
4171 slcli call-api Metric_Tracking_Object getBandwidthData --id=1234 \\
4272 "2015-01-01 00:00:00" "2015-01-1 12:00:00" public
73+ slcli call-api Account getVirtualGuests \\
74+ -f 'virtualGuests.datacenter.name=dal05' \\
75+ -f 'virtualGuests.maxCpu=4' \\
76+ --mask=id,hostname,datacenter.name,maxCpu
4377 """
44- result = env .client .call (service , method , * parameters ,
45- id = _id ,
46- filter = _filter ,
47- mask = mask ,
48- limit = limit ,
49- offset = offset )
50- env .fout (formatting .iter_to_table (result ))
78+
79+ args = [service , method ] + list (parameters )
80+ kwargs = {
81+ 'id' : _id ,
82+ 'filter' : _build_filters (_filters ),
83+ 'mask' : mask ,
84+ 'limit' : limit ,
85+ 'offset' : offset ,
86+ }
87+
88+ if output_python :
89+ env .out (_build_python_example (args , kwargs ))
90+ else :
91+ result = env .client .call (* args , ** kwargs )
92+ env .fout (formatting .iter_to_table (result ))
0 commit comments