From 0d8483391dd7aa19304e3f1e2b6ea3bee040a279 Mon Sep 17 00:00:00 2001 From: Huan Xie Date: Tue, 12 Jul 2016 22:48:01 -0700 Subject: [PATCH] XenAPI: add support for conntrack with XenServer With XenServer as hypervisor, the commands neutron-ovs-agent in compute node run are actually executed in Dom0. But current Dom0 plugin doesn't allow conntrack command, this patch is to add such support. Also, the exitcode the commands returned in Dom0 will pass through Dom0 to neutron to make sure the plugin is only aimed executing commands, it doesn't deal with business scenario. Closes-Bug: #1603400 Change-Id: I304788240bcd590ec211bca052fe64594a4e6eca --- bin/neutron-rootwrap-xen-dom0 | 24 ++++++++++++------- .../agent/xenapi/etc/xapi.d/plugins/netwrap | 17 +++++++++---- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/bin/neutron-rootwrap-xen-dom0 b/bin/neutron-rootwrap-xen-dom0 index 829b9c1564b..a73068a8fd5 100755 --- a/bin/neutron-rootwrap-xen-dom0 +++ b/bin/neutron-rootwrap-xen-dom0 @@ -29,7 +29,6 @@ from oslo_serialization import jsonutils as json import os import select import sys -import traceback import XenAPI @@ -45,7 +44,7 @@ def parse_args(): exec_name = sys.argv.pop(0) # argv[0] required; path to conf file if len(sys.argv) < 2: - print("%s: No command specified" % exec_name) + sys.stderr.write("%s: No command specified" % exec_name) sys.exit(RC_NOCOMMAND) config_file = sys.argv.pop(0) @@ -59,7 +58,7 @@ def _xenapi_section_name(config): if len(sections) == 1: return sections[0] - print("Multiple [xenapi] sections or no [xenapi] section found!") + sys.stderr.write("Multiple [xenapi] sections or no [xenapi] section found!") sys.exit(RC_BADCONFIG) @@ -74,13 +73,14 @@ def load_configuration(exec_name, config_file): username = config.get(section, "xenapi_connection_username") password = config.get(section, "xenapi_connection_password") except ConfigParser.Error: - print("%s: Incorrect configuration file: %s" % (exec_name, config_file)) + sys.stderr.write("%s: Incorrect configuration file: %s" % + (exec_name, config_file)) sys.exit(RC_BADCONFIG) if not url or not password: msg = ("%s: Must specify xenapi_connection_url, " "xenapi_connection_username (optionally), and " "xenapi_connection_password in %s") % (exec_name, config_file) - print(msg) + sys.stderr.write(msg) sys.exit(RC_BADCONFIG) return dict( filters_path=filters_path, @@ -105,7 +105,7 @@ def filter_command(exec_name, filters_path, user_args, exec_dirs): filter_match = wrapper.match_filter( filters, user_args, exec_dirs=exec_dirs) if not filter_match: - print("Unauthorized command: %s" % ' '.join(user_args)) + sys.stderr.write("Unauthorized command: %s" % ' '.join(user_args)) sys.exit(RC_UNAUTHORIZED) @@ -118,11 +118,17 @@ def run_command(url, username, password, user_args, cmd_input): result = session.xenapi.host.call_plugin( host, 'netwrap', 'run_command', {'cmd': json.dumps(user_args), 'cmd_input': json.dumps(cmd_input)}) - return json.loads(result) + result_dict = json.loads(result) + returncode = result_dict.get('returncode') + captured_stdout = result_dict.get('out') + captured_stderr = result_dict.get('err') + sys.stdout.write(captured_stdout) + sys.stderr.write(captured_stderr) + sys.exit(returncode) finally: session.xenapi.session.logout() except Exception as e: - traceback.print_exc() + sys.stderr.write("Failed to execute command in Dom0, %s" % e) sys.exit(RC_XENAPI_ERROR) @@ -142,4 +148,4 @@ def main(): if __name__ == '__main__': - print(main()) + main() diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/xenapi/etc/xapi.d/plugins/netwrap b/neutron/plugins/ml2/drivers/openvswitch/agent/xenapi/etc/xapi.d/plugins/netwrap index ca5d1c24467..33204cf2f2a 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/xenapi/etc/xapi.d/plugins/netwrap +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/xenapi/etc/xapi.d/plugins/netwrap @@ -44,6 +44,7 @@ ALLOWED_CMDS = [ 'ovs-ofctl', 'ovs-vsctl', 'ovsdb-client', + 'conntrack', ] @@ -61,10 +62,7 @@ def _run_command(cmd, cmd_input): proc = subprocess.Popen(cmd, shell=False, stdin=pipe, stdout=pipe, stderr=pipe, close_fds=True) (out, err) = proc.communicate(cmd_input) - - if proc.returncode != 0: - raise PluginError(err) - return out + return proc.returncode, out, err def run_command(session, args): @@ -72,7 +70,16 @@ def run_command(session, args): if cmd and cmd[0] not in ALLOWED_CMDS: msg = _("Dom0 execution of '%s' is not permitted") % cmd[0] raise PluginError(msg) - result = _run_command(cmd, json.loads(args.get('cmd_input', 'null'))) + returncode, out, err = _run_command( + cmd, json.loads(args.get('cmd_input', 'null'))) + if not err: + err = "" + if not out: + out = "" + # This runs in Dom0, will return to neutron-ovs-agent in compute node + result = {'returncode': returncode, + 'out': out, + 'err': err} return json.dumps(result)