Use json for response sent through service out fd

Now we use very simple format using ':' as a separator return
task status and a message related to the task operation, but
that protocol makes it difficult to add more informations into
the response.

This patch changes its format to json, so that we can include
more information keys/values into the response easily.

Change-Id: If2d609fb2ba2187e121e9cadd281017af46a6661
This commit is contained in:
Takashi Kajinami 2017-01-24 11:03:37 +09:00 committed by Takashi Kajinami
parent 905956ff81
commit e04818f234
8 changed files with 58 additions and 42 deletions
src/java/SDaemon/src/main/org/openstack/storlet/daemon
storlets
agent/common
sbus/client
tests/unit
agent/common
sbus/client

@ -14,9 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openstack.storlet.daemon;
import java.io.IOException;
import java.io.OutputStream;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
/*----------------------------------------------------------------------------
@ -32,4 +36,20 @@ public class SAbstractTask {
this.logger = logger;
}
protected boolean respond(OutputStream ostream, boolean status, String message) {
JSONObject obj = new JSONObject();
obj.put("status", status);
obj.put("message", message);
boolean bStatus = true;
try {
ostream.write(obj.toJSONString().getBytes());
ostream.flush();
ostream.close();
} catch (IOException e) {
e.printStackTrace();
bStatus = false;
}
return bStatus;
}
}

@ -54,15 +54,7 @@ public class SCancelTask extends SAbstractTask {
* run
* */
public boolean run() {
boolean bStatus = true;
try {
this.sOut_.write((new String("True: OK")).getBytes());
this.sOut_.close();
} catch (IOException e) {
e.printStackTrace();
bStatus = false;
}
return bStatus;
return respond(this.sOut_, true, new String("OK"));
}
}
/* ============================== END OF FILE =============================== */

@ -45,15 +45,7 @@ public class SHaltTask extends SAbstractTask {
* The actual response on "ping" command.
* */
public boolean run() {
boolean bStatus = true;
try {
this.sOut_.write((new String("True: OK")).getBytes());
this.sOut_.close();
} catch (IOException e) {
e.printStackTrace();
bStatus = false;
}
return bStatus;
return respond(this.sOut_, true, new String("OK"));
}
}
/* ============================== END OF FILE =============================== */

@ -45,15 +45,7 @@ public class SPingTask extends SAbstractTask {
* The actual response on "ping" command.
* */
public boolean run() {
boolean bStatus = true;
try {
this.sOut_.write((new String("True: OK")).getBytes());
this.sOut_.close();
} catch (IOException e) {
e.printStackTrace();
bStatus = false;
}
return bStatus;
return respond(this.sOut_, true, new String("OK"));
}
}
/* ============================== END OF FILE =============================== */

@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from functools import partial
import json
import os
from storlets.sbus import SBus
@ -44,7 +45,7 @@ class CommandResponse(Exception):
@property
def report_message(self):
return '%s: %s' % (str(self.status), self.message)
return json.dumps({'status': self.status, 'message': self.message})
CommandSuccess = partial(CommandResponse, True)

@ -12,6 +12,7 @@
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
from storlets.sbus import SBus
from storlets.sbus.command import SBUS_CMD_CANCEL, SBUS_CMD_DAEMON_STATUS, \
@ -47,11 +48,12 @@ class SBusClient(object):
:param str_response: response string
:returns: SBusResponse instance
"""
two_tokens = str_response.split(':', 1)
if len(two_tokens) != 2:
try:
resp = json.loads(str_response)
status = resp['status']
message = resp['message']
except (ValueError, KeyError):
raise SBusClientMalformedResponse('Got malformed response')
status = (two_tokens[0].lower() == 'true')
message = two_tokens[1]
return SBusResponse(status, message)
def _request(self, command, params=None, task_id=None):

@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import mock
import json
import unittest
from storlets.sbus import command as sbus_cmd
@ -37,7 +38,8 @@ class TestCommandResponse(unittest.TestCase):
def test_report_message(self):
resp = CommandResponse(True, 'msg', True)
self.assertEqual('True: msg', resp.report_message)
self.assertEqual({'status': True, 'message': 'msg'},
json.loads(resp.report_message))
class TestCommandSuccess(unittest.TestCase):

@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import mock
import os
import unittest
@ -76,20 +77,31 @@ class TestSBusClient(unittest.TestCase):
self.client = SBusClient(self.pipe_path, 4)
def test_parse_response(self):
resp = self.client._parse_response('True:OK')
raw_resp = json.dumps({'status': True, 'message': 'OK'})
resp = self.client._parse_response(raw_resp)
self.assertTrue(resp.status)
self.assertEqual('OK', resp.message)
resp = self.client._parse_response('False:NG')
raw_resp = json.dumps({'status': False, 'message': 'ERROR'})
resp = self.client._parse_response(raw_resp)
self.assertFalse(resp.status)
self.assertEqual('NG', resp.message)
self.assertEqual('ERROR', resp.message)
resp = self.client._parse_response('True:Sample:Message')
raw_resp = json.dumps({'status': True, 'message': 'Sample:Message'})
resp = self.client._parse_response(raw_resp)
self.assertTrue(resp.status)
self.assertEqual('Sample:Message', resp.message)
with self.assertRaises(SBusClientMalformedResponse):
resp = self.client._parse_response('Foo')
self.client._parse_response('Foo')
raw_resp = json.dumps({'status': True})
with self.assertRaises(SBusClientMalformedResponse):
self.client._parse_response(raw_resp)
raw_resp = json.dumps({'message': 'foo'})
with self.assertRaises(SBusClientMalformedResponse):
self.client._parse_response(raw_resp)
def _check_all_pipes_closed(self, pipes):
# Make sure that pipes are not empty
@ -100,19 +112,22 @@ class TestSBusClient(unittest.TestCase):
self.assertTrue(_pipe[1].closed)
def _test_service_request(self, method, *args, **kwargs):
with _mock_os_pipe(['True:OK']) as pipes, _mock_sbus(0):
raw_resp = json.dumps({'status': True, 'message': 'OK'})
with _mock_os_pipe([raw_resp]) as pipes, _mock_sbus(0):
resp = method(*args, **kwargs)
self.assertTrue(resp.status)
self.assertEqual('OK', resp.message)
self._check_all_pipes_closed(pipes)
with _mock_os_pipe(['False:ERROR']) as pipes, _mock_sbus(0):
raw_resp = json.dumps({'status': False, 'message': 'ERROR'})
with _mock_os_pipe([raw_resp]) as pipes, _mock_sbus(0):
resp = method(*args, **kwargs)
self.assertFalse(resp.status)
self.assertEqual('ERROR', resp.message)
self._check_all_pipes_closed(pipes)
with _mock_os_pipe(['True:OK']) as pipes, _mock_sbus(-1):
raw_resp = json.dumps({'status': True, 'message': 'OK'})
with _mock_os_pipe([raw_resp]) as pipes, _mock_sbus(-1):
with self.assertRaises(SBusClientSendError):
method(*args, **kwargs)
self._check_all_pipes_closed(pipes)