--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Openstack, LLC.
+# 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.
+
+"""
+
+import ConfigParser
+import json
+import os
+import sys
+import traceback
+
+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:
+ print "%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]
+
+ print "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:
+ print "%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.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 neutron.openstack.common.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:
+ print "Unauthorized command: %s" % ' '.join(user_args)
+ sys.exit(RC_UNAUTHORIZED)
+
+
+def run_command(url, username, password, user_args):
+ try:
+ session = XenAPI.Session(url)
+ session.login_with_password(username, password)
+ host = session.xenapi.session.get_this_host(session.handle)
+ result = session.xenapi.host.call_plugin(
+ host, 'netwrap', 'run_command', {'cmd': json.dumps(user_args)})
+ return json.loads(result)
+ except Exception as e:
+ traceback.print_exc()
+ 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'])
+ return run_command(config['url'], config['username'], config['password'],
+ user_args)
+
+
+if __name__ == '__main__':
+ print main()