Commit cd223971 authored by Jérome Perrin's avatar Jérome Perrin

cli/request: support passing instance parameters from a file

Support a syntax like:

     slapos request --node=computer_guid=local --parameters=_=@~/request.json ERP5 https://lab.nexedi.com/nexedi/slapos/raw/1.0.145/software/erp5/software.cfg

to request an instance with a parameter named _ whose value is the content of
~/request.json file.

This also adds missing tests for slapos request command
parent 34d7fb60
...@@ -28,13 +28,13 @@ ...@@ -28,13 +28,13 @@
############################################################################## ##############################################################################
import pprint import pprint
import os.path
from slapos.cli.config import ClientConfigCommand from slapos.cli.config import ClientConfigCommand
from slapos.client import init, ClientConfig, _getSoftwareReleaseFromSoftwareString from slapos.client import init, ClientConfig, _getSoftwareReleaseFromSoftwareString
from slapos.slap import ResourceNotReady from slapos.slap import ResourceNotReady
def parse_option_dict(options): def parse_option_dict(options):
""" """
Parse a list of option strings like foo=bar baz=qux and return a dictionary. Parse a list of option strings like foo=bar baz=qux and return a dictionary.
...@@ -45,6 +45,11 @@ def parse_option_dict(options): ...@@ -45,6 +45,11 @@ def parse_option_dict(options):
key, value = option_pair.split('=', 1) key, value = option_pair.split('=', 1)
if key in ret: if key in ret:
raise ValueError("Multiple values provided for the same key '%s'" % key) raise ValueError("Multiple values provided for the same key '%s'" % key)
if value.startswith('@'):
file_path = os.path.expanduser(value[1:])
if os.path.exists(file_path):
with open(file_path, "r") as f:
value = f.read()
ret[key] = value ret[key] = value
return ret return ret
...@@ -80,7 +85,8 @@ class RequestCommand(ClientConfigCommand): ...@@ -80,7 +85,8 @@ class RequestCommand(ClientConfigCommand):
ap.add_argument('--parameters', ap.add_argument('--parameters',
nargs='+', nargs='+',
help="Give your configuration 'option1=value1 option2=value2'") help="Instance parameters, in the form 'option1=value1 option2=value2'.\n"
"The content of a file can also be passed as option=@filename")
return ap return ap
......
...@@ -49,10 +49,12 @@ import slapos.cli.computer_info ...@@ -49,10 +49,12 @@ import slapos.cli.computer_info
import slapos.cli.computer_list import slapos.cli.computer_list
import slapos.cli.computer_token import slapos.cli.computer_token
import slapos.cli.supervisorctl import slapos.cli.supervisorctl
import slapos.cli.request
from slapos.cli.proxy_show import do_show, StringIO from slapos.cli.proxy_show import do_show, StringIO
from slapos.cli.cache import do_lookup as cache_do_lookup from slapos.cli.cache import do_lookup as cache_do_lookup
from slapos.cli.cache_source import do_lookup as cache_source_do_lookup from slapos.cli.cache_source import do_lookup as cache_source_do_lookup
from slapos.client import ClientConfig from slapos.client import ClientConfig
from slapos.slap import SoftwareProductCollection
import slapos.grid.svcbackend import slapos.grid.svcbackend
import slapos.proxy import slapos.proxy
import slapos.slap import slapos.slap
...@@ -65,8 +67,8 @@ def raiseNotFoundError(*args, **kwargs): ...@@ -65,8 +67,8 @@ def raiseNotFoundError(*args, **kwargs):
class CliMixin(unittest.TestCase): class CliMixin(unittest.TestCase):
def setUp(self): def setUp(self):
slap = slapos.slap.slap() slap = slapos.slap.slap()
self.local = {'slap': slap}
self.logger = create_autospec(logging.Logger) self.logger = create_autospec(logging.Logger)
self.local = {'slap': slap, 'product': SoftwareProductCollection(self.logger, slap)}
self.conf = create_autospec(ClientConfig) self.conf = create_autospec(ClientConfig)
class TestCliCache(CliMixin): class TestCliCache(CliMixin):
...@@ -567,3 +569,50 @@ print(request('software_release', 'instance').getInstanceParameterDict()['parame ...@@ -567,3 +569,50 @@ print(request('software_release', 'instance').getInstanceParameterDict()['parame
script.write(self.script) script.write(self.script)
script.flush() script.flush()
app.run(('console', '--cfg', config_file, script.name)) app.run(('console', '--cfg', config_file, script.name))
@patch.object(slapos.slap.slap, 'registerOpenOrder', return_value=mock.create_autospec(slapos.slap.OpenOrder))
class TestCliRequest(CliMixin):
def test_parse_option_dict(self, _):
parse_option_dict = slapos.cli.request.parse_option_dict
self.assertEqual({'foo': 'bar', 'a': 'b'}, parse_option_dict(['foo=bar', 'a=b']))
# malformed option = assignment
self.assertRaises(ValueError, parse_option_dict, ['a'])
# duplicated key
self.assertRaises(ValueError, parse_option_dict, ['a=b', 'a=c'])
# @file syntax
with tempfile.NamedTemporaryFile(mode='w') as f:
f.write("file content")
f.flush()
self.assertEqual({'_': 'file content'}, parse_option_dict(['_=@' + f.name]))
# corner cases
self.assertEqual({'a': 'a=b'}, parse_option_dict(['a=a=b']))
self.assertEqual({}, parse_option_dict([]))
self.assertEqual({'_': '@file'}, parse_option_dict(['_=@file']))
def test_request(self, _):
self.conf.reference = 'instance reference'
self.conf.software_url = 'software URL'
self.conf.parameters = {'key': 'value'}
self.conf.node = {'computer_guid': 'COMP-1234'}
self.conf.type = None
self.conf.state = None
self.conf.slave = False
slapos.cli.request.do_request(self.logger, self.conf, self.local)
self.logger.info.assert_any_call(
'Requesting %s as instance of %s...',
'instance reference',
'software URL',
)
self.local['slap'].registerOpenOrder().request.assert_called_once_with(
software_release='software URL',
partition_reference='instance reference',
partition_parameter_kw={'key': 'value'},
software_type=None,
filter_kw={'computer_guid': 'COMP-1234'},
state=None,
shared=False,
)
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment