neutron/bin/neutron-rootwrap-xen-dom0
Huan Xie 0d8483391d 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
2016-09-23 02:34:25 +00:00

152 lines
5.1 KiB
Python
Executable File

#!/usr/bin/env python
# Copyright (c) 2012 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Neutron root wrapper for dom0.
Executes networking commands in dom0. The XenAPI plugin is
responsible determining whether a command is safe to execute.
"""
from __future__ import print_function
from six.moves import configparser as ConfigParser
from oslo_serialization import jsonutils as json
import os
import select
import sys
import XenAPI
RC_UNAUTHORIZED = 99
RC_NOCOMMAND = 98
RC_BADCONFIG = 97
RC_XENAPI_ERROR = 96
def parse_args():
# Split arguments, require at least a command
exec_name = sys.argv.pop(0)
# argv[0] required; path to conf file
if len(sys.argv) < 2:
sys.stderr.write("%s: No command specified" % exec_name)
sys.exit(RC_NOCOMMAND)
config_file = sys.argv.pop(0)
user_args = sys.argv[:]
return exec_name, config_file, user_args
def _xenapi_section_name(config):
sections = [sect for sect in config.sections() if sect.lower() == "xenapi"]
if len(sections) == 1:
return sections[0]
sys.stderr.write("Multiple [xenapi] sections or no [xenapi] section found!")
sys.exit(RC_BADCONFIG)
def load_configuration(exec_name, config_file):
config = ConfigParser.RawConfigParser()
config.read(config_file)
try:
exec_dirs = config.get("DEFAULT", "exec_dirs").split(",")
filters_path = config.get("DEFAULT", "filters_path").split(",")
section = _xenapi_section_name(config)
url = config.get(section, "xenapi_connection_url")
username = config.get(section, "xenapi_connection_username")
password = config.get(section, "xenapi_connection_password")
except ConfigParser.Error:
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)
sys.stderr.write(msg)
sys.exit(RC_BADCONFIG)
return dict(
filters_path=filters_path,
url=url,
username=username,
password=password,
exec_dirs=exec_dirs,
)
def filter_command(exec_name, filters_path, user_args, exec_dirs):
# Add ../ to sys.path to allow running from branch
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(exec_name),
os.pardir, os.pardir))
if os.path.exists(os.path.join(possible_topdir, "neutron", "__init__.py")):
sys.path.insert(0, possible_topdir)
from oslo_rootwrap import wrapper
# Execute command if it matches any of the loaded filters
filters = wrapper.load_filters(filters_path)
filter_match = wrapper.match_filter(
filters, user_args, exec_dirs=exec_dirs)
if not filter_match:
sys.stderr.write("Unauthorized command: %s" % ' '.join(user_args))
sys.exit(RC_UNAUTHORIZED)
def run_command(url, username, password, user_args, cmd_input):
try:
session = XenAPI.Session(url)
session.login_with_password(username, password)
try:
host = session.xenapi.session.get_this_host(session.handle)
result = session.xenapi.host.call_plugin(
host, 'netwrap', 'run_command',
{'cmd': json.dumps(user_args), 'cmd_input': json.dumps(cmd_input)})
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:
sys.stderr.write("Failed to execute command in Dom0, %s" % e)
sys.exit(RC_XENAPI_ERROR)
def main():
exec_name, config_file, user_args = parse_args()
config = load_configuration(exec_name, config_file)
filter_command(exec_name, config['filters_path'], user_args, config['exec_dirs'])
# If data is available on the standard input, we need to pass it to the
# command executed in dom0
cmd_input = None
if select.select([sys.stdin,],[],[],0.0)[0]:
cmd_input = "".join(sys.stdin)
return run_command(config['url'], config['username'], config['password'],
user_args, cmd_input)
if __name__ == '__main__':
main()