Parse linuxbridge plugins using openstack.common.cfg

Implements the blueprint use-common-cfg

In order for the linuxbridge plugin to use the rpc code soon to be merged into
openstack-common, we need to parse our configuration using cfg. Here we
make the most simple, backwards compatible change in that direction.

The same is relevant for the openvswitch implementation

Fixes after comments.

Change-Id: I70fc1898a802cb4198f72741453283d114added2
This commit is contained in:
Gary Kotton 2012-05-29 08:19:45 -04:00
parent d2a21ec921
commit a86c31ba15
14 changed files with 1762 additions and 155 deletions

View File

@ -0,0 +1,25 @@
..
Copyright 2010-2011 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.
Open Stack Common
=================
A number of modules used are from the openstack-common project.
The imported files are in 'quantum/openstack-common.conf'.
More information can be found at `OpenStack Common`_.
.. _`OpenStack Common`: https://launchpad.net/openstack-common

View File

@ -45,6 +45,7 @@ Development Documents
:maxdepth: 1 :maxdepth: 1
devref/index devref/index
devref/common
Man Pages Man Pages
--------- ---------

View File

@ -11,22 +11,22 @@ reconnect_interval = 2
[OVS] [OVS]
# This enables the new OVSQuantumTunnelAgent which enables tunneling # This enables the new OVSQuantumTunnelAgent which enables tunneling
# between hybervisors. Leave it set to False or omit for legacy behavior. # between hybervisors. Leave it set to False or omit for legacy behavior.
enable-tunneling = False enable_tunneling = False
# Do not change this parameter unless you have a good reason to. # Do not change this parameter unless you have a good reason to.
# This is the name of the OVS integration bridge. There is one per hypervisor. # This is the name of the OVS integration bridge. There is one per hypervisor.
# The integration bridge acts as a virtual "patch port". All VM VIFs are # The integration bridge acts as a virtual "patch port". All VM VIFs are
# attached to this bridge and then "patched" according to their network # attached to this bridge and then "patched" according to their network
# connectivity. # connectivity.
integration-bridge = br-int integration_bridge = br-int
# Only used if enable-tunneling (above) is True. # Only used if enable-tunneling (above) is True.
# In most cases, the default value should be fine. # In most cases, the default value should be fine.
tunnel-bridge = br-tun tunnel_bridge = br-tun
# Uncomment this line if enable-tunneling is True above. # Uncomment this line if enable-tunneling is True above.
# Set local-ip to be the local IP address of this hypervisor. # Set local-ip to be the local IP address of this hypervisor.
# local-ip = 10.0.0.3 # local_ip = 10.0.0.3
[AGENT] [AGENT]
# Agent's polling interval in seconds # Agent's polling interval in seconds
@ -43,8 +43,8 @@ root_helper = sudo
# [DATABASE] # [DATABASE]
# sql_connection = mysql://root:nova@127.0.0.1:3306/ovs_quantum # sql_connection = mysql://root:nova@127.0.0.1:3306/ovs_quantum
# [OVS] # [OVS]
# enable-tunneling = False # enable_tunneling = False
# integration-bridge = br-int # integration_bridge = br-int
# [AGENT] # [AGENT]
# root_helper = sudo # root_helper = sudo
# #
@ -52,10 +52,10 @@ root_helper = sudo
# [DATABASE] # [DATABASE]
# sql_connection = mysql://root:nova@127.0.0.1:3306/ovs_quantum # sql_connection = mysql://root:nova@127.0.0.1:3306/ovs_quantum
# [OVS] # [OVS]
# enable-tunneling = True # enable_tunneling = True
# integration-bridge = br-int # integration_bridge = br-int
# tunnel-bridge = br-tun # tunnel_bridge = br-tun
# remote-ip-file = /opt/stack/remote-ips.txt # remote-ip-file = /opt/stack/remote-ips.txt
# local-ip = 10.0.0.3 # local_ip = 10.0.0.3
# [AGENT] # [AGENT]
# root_helper = sudo # root_helper = sudo

View File

@ -1,7 +1,7 @@
[DEFAULT] [DEFAULT]
# The list of modules to copy from openstack-common # The list of modules to copy from openstack-common
modules=setup modules=cfg,iniparser,setup
# The base module to hold the copy of openstack.common # The base module to hold the copy of openstack.common
base=quantum base=quantum

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,126 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 OpenStack LLC.
#
# 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.
class ParseError(Exception):
def __init__(self, message, lineno, line):
self.msg = message
self.line = line
self.lineno = lineno
def __str__(self):
return 'at line %d, %s: %r' % (self.lineno, self.msg, self.line)
class BaseParser(object):
lineno = 0
parse_exc = ParseError
def _assignment(self, key, value):
self.assignment(key, value)
return None, []
def _get_section(self, line):
if line[-1] != ']':
return self.error_no_section_end_bracket(line)
if len(line) <= 2:
return self.error_no_section_name(line)
return line[1:-1]
def _split_key_value(self, line):
colon = line.find(':')
equal = line.find('=')
if colon < 0 and equal < 0:
return self.error_invalid_assignment(line)
if colon < 0 or (equal >= 0 and equal < colon):
key, value = line[:equal], line[equal + 1:]
else:
key, value = line[:colon], line[colon + 1:]
return key.strip(), [value.strip()]
def parse(self, lineiter):
key = None
value = []
for line in lineiter:
self.lineno += 1
line = line.rstrip()
if not line:
# Blank line, ends multi-line values
if key:
key, value = self._assignment(key, value)
continue
elif line[0] in (' ', '\t'):
# Continuation of previous assignment
if key is None:
self.error_unexpected_continuation(line)
else:
value.append(line.lstrip())
continue
if key:
# Flush previous assignment, if any
key, value = self._assignment(key, value)
if line[0] == '[':
# Section start
section = self._get_section(line)
if section:
self.new_section(section)
elif line[0] in '#;':
self.comment(line[1:].lstrip())
else:
key, value = self._split_key_value(line)
if not key:
return self.error_empty_key(line)
if key:
# Flush previous assignment, if any
self._assignment(key, value)
def assignment(self, key, value):
"""Called when a full assignment is parsed"""
raise NotImplementedError()
def new_section(self, section):
"""Called when a new section is started"""
raise NotImplementedError()
def comment(self, comment):
"""Called when a comment is parsed"""
pass
def error_invalid_assignment(self, line):
raise self.parse_exc("No ':' or '=' found in assignment",
self.lineno, line)
def error_empty_key(self, line):
raise self.parse_exc('Key cannot be empty', self.lineno, line)
def error_unexpected_continuation(self, line):
raise self.parse_exc('Unexpected continuation line',
self.lineno, line)
def error_no_section_end_bracket(self, line):
raise self.parse_exc('Invalid section (must end with ])',
self.lineno, line)
def error_no_section_name(self, line):
raise self.parse_exc('Empty section name', self.lineno, line)

View File

@ -23,7 +23,6 @@ from quantum.db import api as db
from quantum.plugins.linuxbridge.common import constants as const from quantum.plugins.linuxbridge.common import constants as const
from quantum.plugins.linuxbridge.common import utils as cutil from quantum.plugins.linuxbridge.common import utils as cutil
from quantum.plugins.linuxbridge.db import l2network_db as cdb from quantum.plugins.linuxbridge.db import l2network_db as cdb
from quantum.plugins.linuxbridge import plugin_configuration as conf
from quantum.quantum_plugin_base import QuantumPluginBase from quantum.quantum_plugin_base import QuantumPluginBase

View File

@ -22,7 +22,6 @@
# Quantum OpenVSwitch Plugin. # Quantum OpenVSwitch Plugin.
# @author: Sumit Naiksatam, Cisco Systems, Inc. # @author: Sumit Naiksatam, Cisco Systems, Inc.
import ConfigParser
import logging import logging
from optparse import OptionParser from optparse import OptionParser
import os import os
@ -35,11 +34,12 @@ import time
from sqlalchemy.ext.sqlsoup import SqlSoup from sqlalchemy.ext.sqlsoup import SqlSoup
from quantum.common import exceptions as exception from quantum.common import exceptions as exception
from quantum.plugins.linuxbridge.common import config
logging.basicConfig() logging.basicConfig()
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
BRIDGE_NAME_PREFIX = "brq" BRIDGE_NAME_PREFIX = "brq"
GATEWAY_INTERFACE_PREFIX = "gw-" GATEWAY_INTERFACE_PREFIX = "gw-"
TAP_INTERFACE_PREFIX = "tap" TAP_INTERFACE_PREFIX = "tap"
@ -479,33 +479,15 @@ def main():
sys.exit(1) sys.exit(1)
config_file = args[0] config_file = args[0]
config = ConfigParser.ConfigParser() conf = config.parse(config_file)
try: br_name_prefix = BRIDGE_NAME_PREFIX
fh = open(config_file) physical_interface = conf.BRIDGE.physical_interface
fh.close() polling_interval = conf.AGENT.polling_interval
config.read(config_file) reconnect_interval = conf.DATABASE.reconnect_interval
br_name_prefix = BRIDGE_NAME_PREFIX root_helper = conf.AGENT.root_helper
physical_interface = config.get("LINUX_BRIDGE", "physical_interface") 'Establish database connection and load models'
if config.has_option("AGENT", "polling_interval"): db_connection_url = conf.DATABASE.sql_connection
polling_interval = config.getint("AGENT", "polling_interval") LOG.info("Connecting to %s" % (db_connection_url))
else:
polling_interval = DEFAULT_POLLING_INTERVAL
LOG.info("Polling interval not defined. Using default.")
if config.has_option("DATABASE", "reconnect_interval"):
reconnect_interval = config.getint("DATABASE",
"reconnect_interval")
else:
reconnect_interval = DEFAULT_RECONNECT_INTERVAL
LOG.info("Reconnect interval not defined. Using default.")
root_helper = config.get("AGENT", "root_helper")
'Establish database connection and load models'
db_connection_url = config.get("DATABASE", "sql_connection")
LOG.info("Connecting to %s" % (db_connection_url))
except Exception as e:
LOG.error("Unable to parse config file \"%s\": \nException %s" %
(config_file, str(e)))
sys.exit(1)
plugin = LinuxBridgeQuantumAgent(br_name_prefix, physical_interface, plugin = LinuxBridgeQuantumAgent(br_name_prefix, physical_interface,
polling_interval, reconnect_interval, polling_interval, reconnect_interval,

View File

@ -17,28 +17,34 @@
# @author: Sumit Naiksatam, Cisco Systems, Inc. # @author: Sumit Naiksatam, Cisco Systems, Inc.
# @author: Rohit Agarwalla, Cisco Systems, Inc. # @author: Rohit Agarwalla, Cisco Systems, Inc.
import os from quantum.openstack.common import cfg
from quantum.common.config import find_config_file
from quantum.plugins.linuxbridge.common import configparser as confp
CONF_FILE = find_config_file({'plugin': 'linuxbridge'}, None, vlan_opts = [
"linuxbridge_conf.ini") cfg.IntOpt('vlan_start', default=1000),
CONF_PARSER_OBJ = confp.ConfigParser(CONF_FILE) cfg.IntOpt('vlan_end', default=3000),
]
database_opts = [
cfg.StrOpt('sql_connection', default='sqlite://'),
cfg.IntOpt('reconnect_interval', default=2),
]
bridge_opts = [
cfg.StrOpt('physical_interface', default='eth1'),
]
agent_opts = [
cfg.IntOpt('polling_interval', default=2),
cfg.StrOpt('root_helper', default='sudo'),
]
""" def parse(config_file):
Reading the conf for the linuxbridge_plugin conf = cfg.ConfigOpts(default_config_files=[config_file])
""" conf(args=[])
SECTION_CONF = CONF_PARSER_OBJ['VLANS'] conf.register_opts(vlan_opts, "VLANS")
VLAN_START = SECTION_CONF['vlan_start'] conf.register_opts(database_opts, "DATABASE")
VLAN_END = SECTION_CONF['vlan_end'] conf.register_opts(bridge_opts, "BRIDGE")
conf.register_opts(agent_opts, "AGENT")
return conf
SECTION_CONF = CONF_PARSER_OBJ['DATABASE']
DB_SQL_CONNECTION = SECTION_CONF['sql_connection']
if 'reconnect_interval' in SECTION_CONF:
DB_RECONNECT_INTERVAL = int(SECTION_CONF['reconnect_interval'])
else:
DB_RECONNECT_INTERVAL = 2

View File

@ -21,18 +21,21 @@ from sqlalchemy import func
from sqlalchemy.orm import exc from sqlalchemy.orm import exc
from quantum.common import exceptions as q_exc from quantum.common import exceptions as q_exc
from quantum.common.config import find_config_file
import quantum.db.api as db import quantum.db.api as db
from quantum.plugins.linuxbridge.common import exceptions as c_exc from quantum.plugins.linuxbridge.common import exceptions as c_exc
from quantum.plugins.linuxbridge.db import l2network_models from quantum.plugins.linuxbridge.db import l2network_models
from quantum.plugins.linuxbridge import plugin_configuration as conf from quantum.plugins.linuxbridge.common import config
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
CONF_FILE = find_config_file({'plugin': 'linuxbridge'}, None,
"linuxbridge_conf.ini")
CONF = config.parse(CONF_FILE)
def initialize(): def initialize():
options = {"sql_connection": "%s" % conf.DB_SQL_CONNECTION} options = {"sql_connection": "%s" % CONF.DATABASE.sql_connection}
options.update({"reconnect_interval": conf.DB_RECONNECT_INTERVAL}) options.update({"reconnect_interval": CONF.DATABASE.reconnect_interval})
db.configure_db(options) db.configure_db(options)
create_vlanids() create_vlanids()
@ -41,8 +44,8 @@ def create_vlanids():
"""Prepopulates the vlan_bindings table""" """Prepopulates the vlan_bindings table"""
LOG.debug("create_vlanids() called") LOG.debug("create_vlanids() called")
session = db.get_session() session = db.get_session()
start = int(conf.VLAN_START) start = CONF.VLANS.vlan_start
end = int(conf.VLAN_END) end = CONF.VLANS.vlan_end
try: try:
vlanid = session.query(l2network_models.VlanID).\ vlanid = session.query(l2network_models.VlanID).\
one() one()

View File

@ -19,7 +19,6 @@
# @author: Dan Wendlandt, Nicira Networks, Inc. # @author: Dan Wendlandt, Nicira Networks, Inc.
# @author: Dave Lapsley, Nicira Networks, Inc. # @author: Dave Lapsley, Nicira Networks, Inc.
import ConfigParser
import logging import logging
from optparse import OptionParser from optparse import OptionParser
import shlex import shlex
@ -31,6 +30,9 @@ import time
import sqlalchemy import sqlalchemy
from sqlalchemy.ext import sqlsoup from sqlalchemy.ext import sqlsoup
from quantum.plugins.openvswitch.common import config
logging.basicConfig() logging.basicConfig()
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -688,67 +690,21 @@ def main():
sys.exit(1) sys.exit(1)
config_file = args[0] config_file = args[0]
config = ConfigParser.ConfigParser() conf = config.parse(config_file)
try:
config.read(config_file)
except Exception as e:
LOG.error("Unable to parse config file \"%s\": %s" %
(config_file, str(e)))
raise e
# Determine which agent type to use. # Determine which agent type to use.
enable_tunneling = False enable_tunneling = conf.OVS.enable_tunneling
try: integ_br = conf.OVS.integration_bridge
enable_tunneling = config.getboolean("OVS", "enable-tunneling") db_connection_url = conf.DATABASE.sql_connection
except Exception as e: polling_interval = conf.AGENT.polling_interval
pass reconnect_interval = conf.DATABASE.reconnect_interval
root_helper = conf.AGENT.root_helper
# Get common parameters.
try:
integ_br = config.get("OVS", "integration-bridge")
if not len(integ_br):
raise Exception('Empty integration-bridge in configuration file.')
db_connection_url = config.get("DATABASE", "sql_connection")
if not len(db_connection_url):
raise Exception('Empty db_connection_url in configuration file.')
if config.has_option("AGENT", "polling_interval"):
polling_interval = config.getint("AGENT", "polling_interval")
else:
polling_interval = DEFAULT_POLLING_INTERVAL
LOG.info("Polling interval not defined. Using default.")
if config.has_option("DATABASE", "reconnect_interval"):
reconnect_interval = config.getint("DATABASE",
"reconnect_interval")
else:
reconnect_interval = DEFAULT_RECONNECT_INTERVAL
LOG.info("Reconnect interval not defined. Using default.")
root_helper = config.get("AGENT", "root_helper")
except Exception as e:
LOG.error("Error parsing common params in config_file: '%s': %s" %
(config_file, str(e)))
sys.exit(1)
if enable_tunneling: if enable_tunneling:
# Get parameters for OVSQuantumTunnelAgent # Get parameters for OVSQuantumTunnelAgent
try: tun_br = conf.OVS.tunnel_bridge
# Mandatory parameter. # Mandatory parameter.
tun_br = config.get("OVS", "tunnel-bridge") local_ip = conf.OVS.local_ip
if not len(tun_br):
raise Exception('Empty tunnel-bridge in configuration file.')
# Mandatory parameter.
local_ip = config.get("OVS", "local-ip")
if not len(local_ip):
raise Exception('Empty local-ip in configuration file.')
except Exception as e:
LOG.error("Error parsing tunnel params in config_file: '%s': %s" %
(config_file, str(e)))
sys.exit(1)
plugin = OVSQuantumTunnelAgent(integ_br, tun_br, local_ip, root_helper, plugin = OVSQuantumTunnelAgent(integ_br, tun_br, local_ip, root_helper,
polling_interval, reconnect_interval) polling_interval, reconnect_interval)
else: else:

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4 # vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2012 Cisco Systems, Inc. All rights reserved. # Copyright 2012 Red Hat, Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # 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 # not use this file except in compliance with the License. You may obtain
@ -13,19 +13,3 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
#
# @author: Sumit Naiksatam, Cisco Systems, Inc.
from configobj import ConfigObj
class ConfigParser(ConfigObj):
"""Config Parser based on the ConfigObj module"""
def __init__(self, filename):
super(ConfigParser, self).__init__(filename, raise_errors=True,
file_error=True)
def dummy(self, section, key):
"""Dummy function to return the same key, used in walk"""
return section[key]

View File

@ -0,0 +1,44 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Red Hat, Inc.
#
# 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.
from quantum.openstack.common import cfg
database_opts = [
cfg.StrOpt('sql_connection', default='sqlite://'),
cfg.IntOpt('reconnect_interval', default=2),
]
ovs_opts = [
cfg.StrOpt('enable_tunneling', default='False'),
cfg.StrOpt('integration_bridge', default='br-int'),
cfg.StrOpt('tunnel_bridge', default='br-tun'),
cfg.StrOpt('local_ip', default='10.0.0.3'),
]
agent_opts = [
cfg.IntOpt('polling_interval', default=2),
cfg.StrOpt('root_helper', default='sudo'),
]
def parse(config_file):
conf = cfg.ConfigOpts(default_config_files=[config_file])
conf(args=[])
conf.register_opts(database_opts, "DATABASE")
conf.register_opts(ovs_opts, "OVS")
conf.register_opts(agent_opts, "AGENT")
return conf

View File

@ -18,7 +18,6 @@
# @author: Dan Wendlandt, Nicira Networks, Inc. # @author: Dan Wendlandt, Nicira Networks, Inc.
# @author: Dave Lapsley, Nicira Networks, Inc. # @author: Dave Lapsley, Nicira Networks, Inc.
import ConfigParser
import logging import logging
from optparse import OptionParser from optparse import OptionParser
import os import os
@ -29,9 +28,9 @@ from quantum.common import exceptions as q_exc
from quantum.common.config import find_config_file from quantum.common.config import find_config_file
import quantum.db.api as db import quantum.db.api as db
from quantum.plugins.openvswitch import ovs_db from quantum.plugins.openvswitch import ovs_db
from quantum.plugins.openvswitch.common import config
from quantum.quantum_plugin_base import QuantumPluginBase from quantum.quantum_plugin_base import QuantumPluginBase
LOG = logging.getLogger("ovs_quantum_plugin") LOG = logging.getLogger("ovs_quantum_plugin")
@ -89,7 +88,6 @@ class VlanMap(object):
class OVSQuantumPlugin(QuantumPluginBase): class OVSQuantumPlugin(QuantumPluginBase):
def __init__(self, configfile=None): def __init__(self, configfile=None):
config = ConfigParser.ConfigParser()
if configfile is None: if configfile is None:
if os.path.exists(CONF_FILE): if os.path.exists(CONF_FILE):
configfile = CONF_FILE configfile = CONF_FILE
@ -100,15 +98,9 @@ class OVSQuantumPlugin(QuantumPluginBase):
raise Exception("Configuration file \"%s\" doesn't exist" % raise Exception("Configuration file \"%s\" doesn't exist" %
(configfile)) (configfile))
LOG.debug("Using configuration file: %s" % configfile) LOG.debug("Using configuration file: %s" % configfile)
config.read(configfile) conf = config.parse(configfile)
LOG.debug("Config: %s" % config) options = {"sql_connection": conf.DATABASE.sql_connection}
reconnect_interval = conf.DATABASE.reconnect_interval
options = {"sql_connection": config.get("DATABASE", "sql_connection")}
if config.has_option("DATABASE", "reconnect_interval"):
reconnect_interval = config.getint("DATABASE",
"reconnect_interval")
else:
reconnect_interval = 2
options.update({"reconnect_interval": reconnect_interval}) options.update({"reconnect_interval": reconnect_interval})
db.configure_db(options) db.configure_db(options)