11"""Call arbitrary API endpoints."""
2+ import json
3+
24import click
35
46from SoftLayer .CLI import environment
@@ -27,8 +29,7 @@ def _build_filters(_filters):
2729 if len (top_parts ) == 2 :
2830 break
2931 else :
30- raise exceptions .CLIAbort ('Failed to find valid operation for: %s'
31- % _filter )
32+ raise exceptions .CLIAbort ('Failed to find valid operation for: %s' % _filter )
3233
3334 key , value = top_parts
3435 current = root
@@ -68,25 +69,60 @@ def _build_python_example(args, kwargs):
6869 return call_str
6970
7071
72+ def _validate_filter (ctx , param , value ): # pylint: disable=unused-argument
73+ """Validates a JSON style object filter"""
74+ _filter = None
75+ if value :
76+ try :
77+ _filter = json .loads (value )
78+ if not isinstance (_filter , dict ):
79+ raise exceptions .CLIAbort ("\" {}\" should be a JSON object, but is a {} instead." .
80+ format (_filter , type (_filter )))
81+ except json .JSONDecodeError as error :
82+ raise exceptions .CLIAbort ("\" {}\" is not valid JSON. {}" .format (value , error ))
83+
84+ return _filter
85+
86+
87+ def _validate_parameters (ctx , param , value ): # pylint: disable=unused-argument
88+ """Checks if value is a JSON string, and converts it to a datastructure if that is true"""
89+
90+ validated_values = []
91+ for parameter in value :
92+ if isinstance (parameter , str ):
93+ # looks like a JSON string...
94+ if '{' in parameter or '[' in parameter :
95+ try :
96+ parameter = json .loads (parameter )
97+ except json .JSONDecodeError as error :
98+ click .secho ("{} looked like json, but was invalid, passing to API as is. {}" .
99+ format (parameter , error ), fg = 'red' )
100+ validated_values .append (parameter )
101+ return validated_values
102+
103+
71104@click .command ('call' , short_help = "Call arbitrary API endpoints." )
72105@click .argument ('service' )
73106@click .argument ('method' )
74- @click .argument ('parameters' , nargs = - 1 )
107+ @click .argument ('parameters' , nargs = - 1 , callback = _validate_parameters )
75108@click .option ('--id' , '_id' , help = "Init parameter" )
76109@helpers .multi_option ('--filter' , '-f' , '_filters' ,
77- help = "Object filters. This should be of the form: "
78- "'property=value' or 'nested.property=value'. Complex "
79- "filters like betweenDate are not currently supported." )
110+ help = "Object filters. This should be of the form: 'property=value' or 'nested.property=value'."
111+ "Complex filters should use --json-filter." )
80112@click .option ('--mask' , help = "String-based object mask" )
81113@click .option ('--limit' , type = click .INT , help = "Result limit" )
82114@click .option ('--offset' , type = click .INT , help = "Result offset" )
83115@click .option ('--output-python / --no-output-python' ,
84116 help = "Show python example code instead of executing the call" )
117+ @click .option ('--json-filter' , callback = _validate_filter ,
118+ help = "A JSON string to be passed in as the object filter to the API call."
119+ "Remember to use double quotes (\" ) for variable names. Can NOT be used with --filter." )
85120@environment .pass_env
86121def cli (env , service , method , parameters , _id , _filters , mask , limit , offset ,
87- output_python = False ):
122+ output_python = False , json_filter = None ):
88123 """Call arbitrary API endpoints with the given SERVICE and METHOD.
89124
125+ For parameters that require a datatype, use a JSON string for that parameter.
90126 Example::
91127
92128 slcli call-api Account getObject
@@ -100,12 +136,23 @@ def cli(env, service, method, parameters, _id, _filters, mask, limit, offset,
100136 --mask=id,hostname,datacenter.name,maxCpu
101137 slcli call-api Account getVirtualGuests \\
102138 -f 'virtualGuests.datacenter.name IN dal05,sng01'
139+ slcli call-api Account getVirtualGuests \\
140+ --json-filter '{"virtualGuests":{"hostname": {"operation": "^= test"}}}' --limit=10
141+ slcli -v call-api SoftLayer_User_Customer addBulkPortalPermission --id=1234567 \\
142+ '[{"keyName": "NETWORK_MESSAGE_DELIVERY_MANAGE"}]'
103143 """
104144
145+ if _filters and json_filter :
146+ raise exceptions .CLIAbort ("--filter and --json-filter cannot be used together." )
147+
148+ object_filter = _build_filters (_filters )
149+ if json_filter :
150+ object_filter .update (json_filter )
151+
105152 args = [service , method ] + list (parameters )
106153 kwargs = {
107154 'id' : _id ,
108- 'filter' : _build_filters ( _filters ) ,
155+ 'filter' : object_filter ,
109156 'mask' : mask ,
110157 'limit' : limit ,
111158 'offset' : offset ,
0 commit comments