#!/usr/bin/env python # Copyright 2012 OpenStack Foundation # Copyright 2012 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # 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. # # XenAPI plugin for executing network commands (ovs, iptables, etc) on dom0 # import errno import gettext gettext.install('neutron', unicode=1) try: import json except ImportError: import simplejson as json import subprocess import XenAPIPlugin MSG_UNAUTHORIZED = "Unauthorized command" MSG_NOT_FOUND = "Executable not found" ALLOWED_CMDS = [ 'ip', 'ipset', 'iptables-save', 'iptables-restore', 'ip6tables-save', 'ip6tables-restore', 'sysctl', # NOTE(yamamoto): of_interface=native doesn't use ovs-ofctl 'ovs-ofctl', 'ovs-vsctl', 'ovsdb-client', 'conntrack', ] class PluginError(Exception): """Base Exception class for all plugin errors.""" def __init__(self, *args): Exception.__init__(self, *args) def _run_command(cmd, cmd_input): """Abstracts out the basics of issuing system commands. If the command returns anything in stderr, a PluginError is raised with that information. Otherwise, the output from stdout is returned. """ try: pipe = subprocess.PIPE proc = subprocess.Popen(cmd, shell=False, stdin=pipe, stdout=pipe, stderr=pipe, close_fds=True) except OSError, e: if e.errno == errno.ENOENT: raise PluginError(MSG_NOT_FOUND) (out, err) = proc.communicate(cmd_input) return proc.returncode, out, err def run_command(session, args): cmd = json.loads(args.get('cmd')) if cmd and cmd[0] not in ALLOWED_CMDS: raise PluginError(MSG_UNAUTHORIZED) 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) if __name__ == "__main__": XenAPIPlugin.dispatch({"run_command": run_command})