Merge NVP support.

This commit is contained in:
Adam Gandelman 2013-10-28 12:03:14 -07:00
commit 028ff2ed69
19 changed files with 825 additions and 724 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>nova-cloud-controller</name> <name>nvp-nova-cloud-controller</name>
<comment></comment> <comment></comment>
<projects> <projects>
</projects> </projects>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?><pydev_project> <?eclipse-pydev version="1.0"?><pydev_project>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/nova-cloud-controller/hooks</path> <path>/nvp-nova-cloud-controller/hooks</path>
<path>/nova-cloud-controller/unit_tests</path> <path>/nvp-nova-cloud-controller/unit_tests</path>
</pydev_pathproperty> </pydev_pathproperty>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property> <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> <pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>

View File

@ -1,4 +1,4 @@
branch: lp:charm-helpers branch: lp:~james-page/charm-helpers/nvp-updates
destination: hooks/charmhelpers destination: hooks/charmhelpers
include: include:
- core - core
@ -7,5 +7,4 @@ include:
- contrib.storage - contrib.storage
- contrib.hahelpers: - contrib.hahelpers:
- apache - apache
- ceph
- payload.execd - payload.execd

View File

@ -69,6 +69,7 @@ options:
Quantum plugin to use for network management; supports Quantum plugin to use for network management; supports
. .
ovs - OpenvSwitch Plugin ovs - OpenvSwitch Plugin
nvp - Nicira Network Virtualization Platform
. .
This configuration only has context when used with This configuration only has context when used with
network-manager Quantum. network-manager Quantum.
@ -125,3 +126,31 @@ options:
ssl_key: ssl_key:
type: string type: string
description: SSL key to use with certificate specified as ssl_cert. description: SSL key to use with certificate specified as ssl_cert.
# Neutron NVP Plugin configuration
nvp-controllers:
type: string
description: Space delimited addresses of NVP controllers
nvp-username:
type: string
default: admin
description: Username to connect to NVP controllers with
nvp-password:
type: string
default: admin
description: Password to connect to NVP controllers with
nvp-cluster-name:
type: string
default: example
description: Name of the NVP cluster configuration to create (grizzly only)
nvp-tz-uuid:
type: string
description: |
This is uuid of the default NVP Transport zone that will be used for
creating tunneled isolated Quantum networks. It needs to be created
in NVP before starting Quantum with the nvp plugin.
nvp-l3-uuid:
type: string
description: |
This is uuid of the default NVP L3 Gateway Service.
# end of NVP configuration

View File

@ -385,16 +385,33 @@ class NeutronContext(object):
def ovs_ctxt(self): def ovs_ctxt(self):
driver = neutron_plugin_attribute(self.plugin, 'driver', driver = neutron_plugin_attribute(self.plugin, 'driver',
self.network_manager) self.network_manager)
config = neutron_plugin_attribute(self.plugin, 'config',
self.network_manager)
ovs_ctxt = { ovs_ctxt = {
'core_plugin': driver, 'core_plugin': driver,
'neutron_plugin': 'ovs', 'neutron_plugin': 'ovs',
'neutron_security_groups': self.neutron_security_groups, 'neutron_security_groups': self.neutron_security_groups,
'local_ip': unit_private_ip(), 'local_ip': unit_private_ip(),
'config': config
} }
return ovs_ctxt return ovs_ctxt
def nvp_ctxt(self):
driver = neutron_plugin_attribute(self.plugin, 'driver',
self.network_manager)
config = neutron_plugin_attribute(self.plugin, 'config',
self.network_manager)
nvp_ctxt = {
'core_plugin': driver,
'neutron_plugin': 'nvp',
'neutron_security_groups': self.neutron_security_groups,
'local_ip': unit_private_ip(),
'config': config
}
return nvp_ctxt
def __call__(self): def __call__(self):
self._ensure_packages() self._ensure_packages()
@ -408,6 +425,8 @@ class NeutronContext(object):
if self.plugin == 'ovs': if self.plugin == 'ovs':
ctxt.update(self.ovs_ctxt()) ctxt.update(self.ovs_ctxt())
elif self.plugin == 'nvp':
ctxt.update(self.nvp_ctxt())
self._save_flag_file() self._save_flag_file()
return ctxt return ctxt

View File

@ -34,13 +34,23 @@ def quantum_plugins():
'services': ['quantum-plugin-openvswitch-agent'], 'services': ['quantum-plugin-openvswitch-agent'],
'packages': [[headers_package(), 'openvswitch-datapath-dkms'], 'packages': [[headers_package(), 'openvswitch-datapath-dkms'],
['quantum-plugin-openvswitch-agent']], ['quantum-plugin-openvswitch-agent']],
'server_packages': ['quantum-server',
'quantum-plugin-openvswitch'],
'server_services': ['quantum-server']
}, },
'nvp': { 'nvp': {
'config': '/etc/quantum/plugins/nicira/nvp.ini', 'config': '/etc/quantum/plugins/nicira/nvp.ini',
'driver': 'quantum.plugins.nicira.nicira_nvp_plugin.' 'driver': 'quantum.plugins.nicira.nicira_nvp_plugin.'
'QuantumPlugin.NvpPluginV2', 'QuantumPlugin.NvpPluginV2',
'contexts': [
context.SharedDBContext(user=config('neutron-database-user'),
database=config('neutron-database'),
relation_prefix='neutron')],
'services': [], 'services': [],
'packages': [], 'packages': [],
'server_packages': ['quantum-server',
'quantum-plugin-nicira'],
'server_services': ['quantum-server']
} }
} }
@ -60,13 +70,23 @@ def neutron_plugins():
'services': ['neutron-plugin-openvswitch-agent'], 'services': ['neutron-plugin-openvswitch-agent'],
'packages': [[headers_package(), 'openvswitch-datapath-dkms'], 'packages': [[headers_package(), 'openvswitch-datapath-dkms'],
['quantum-plugin-openvswitch-agent']], ['quantum-plugin-openvswitch-agent']],
'server_packages': ['neutron-server',
'neutron-plugin-openvswitch'],
'server_services': ['neutron-server']
}, },
'nvp': { 'nvp': {
'config': '/etc/neutron/plugins/nicira/nvp.ini', 'config': '/etc/neutron/plugins/nicira/nvp.ini',
'driver': 'neutron.plugins.nicira.nicira_nvp_plugin.' 'driver': 'neutron.plugins.nicira.nicira_nvp_plugin.'
'NeutronPlugin.NvpPluginV2', 'NeutronPlugin.NvpPluginV2',
'contexts': [
context.SharedDBContext(user=config('neutron-database-user'),
database=config('neutron-database'),
relation_prefix='neutron')],
'services': [], 'services': [],
'packages': [], 'packages': [],
'server_packages': ['neutron-server',
'neutron-plugin-nicira'],
'server_services': ['neutron-server']
} }
} }

View File

@ -9,6 +9,7 @@ import json
import yaml import yaml
import subprocess import subprocess
import UserDict import UserDict
from subprocess import CalledProcessError
CRITICAL = "CRITICAL" CRITICAL = "CRITICAL"
ERROR = "ERROR" ERROR = "ERROR"
@ -21,7 +22,7 @@ cache = {}
def cached(func): def cached(func):
''' Cache return values for multiple executions of func + args """Cache return values for multiple executions of func + args
For example: For example:
@ -32,7 +33,7 @@ def cached(func):
unit_get('test') unit_get('test')
will cache the result of unit_get + 'test' for future calls. will cache the result of unit_get + 'test' for future calls.
''' """
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
global cache global cache
key = str((func, args, kwargs)) key = str((func, args, kwargs))
@ -46,8 +47,8 @@ def cached(func):
def flush(key): def flush(key):
''' Flushes any entries from function cache where the """Flushes any entries from function cache where the
key is found in the function+args ''' key is found in the function+args """
flush_list = [] flush_list = []
for item in cache: for item in cache:
if key in item: if key in item:
@ -57,7 +58,7 @@ def flush(key):
def log(message, level=None): def log(message, level=None):
"Write a message to the juju log" """Write a message to the juju log"""
command = ['juju-log'] command = ['juju-log']
if level: if level:
command += ['-l', level] command += ['-l', level]
@ -66,7 +67,7 @@ def log(message, level=None):
class Serializable(UserDict.IterableUserDict): class Serializable(UserDict.IterableUserDict):
"Wrapper, an object that can be serialized to yaml or json" """Wrapper, an object that can be serialized to yaml or json"""
def __init__(self, obj): def __init__(self, obj):
# wrap the object # wrap the object
@ -96,11 +97,11 @@ class Serializable(UserDict.IterableUserDict):
self.data = state self.data = state
def json(self): def json(self):
"Serialize the object to json" """Serialize the object to json"""
return json.dumps(self.data) return json.dumps(self.data)
def yaml(self): def yaml(self):
"Serialize the object to yaml" """Serialize the object to yaml"""
return yaml.dump(self.data) return yaml.dump(self.data)
@ -119,38 +120,38 @@ def execution_environment():
def in_relation_hook(): def in_relation_hook():
"Determine whether we're running in a relation hook" """Determine whether we're running in a relation hook"""
return 'JUJU_RELATION' in os.environ return 'JUJU_RELATION' in os.environ
def relation_type(): def relation_type():
"The scope for the current relation hook" """The scope for the current relation hook"""
return os.environ.get('JUJU_RELATION', None) return os.environ.get('JUJU_RELATION', None)
def relation_id(): def relation_id():
"The relation ID for the current relation hook" """The relation ID for the current relation hook"""
return os.environ.get('JUJU_RELATION_ID', None) return os.environ.get('JUJU_RELATION_ID', None)
def local_unit(): def local_unit():
"Local unit ID" """Local unit ID"""
return os.environ['JUJU_UNIT_NAME'] return os.environ['JUJU_UNIT_NAME']
def remote_unit(): def remote_unit():
"The remote unit for the current relation hook" """The remote unit for the current relation hook"""
return os.environ['JUJU_REMOTE_UNIT'] return os.environ['JUJU_REMOTE_UNIT']
def service_name(): def service_name():
"The name service group this unit belongs to" """The name service group this unit belongs to"""
return local_unit().split('/')[0] return local_unit().split('/')[0]
@cached @cached
def config(scope=None): def config(scope=None):
"Juju charm configuration" """Juju charm configuration"""
config_cmd_line = ['config-get'] config_cmd_line = ['config-get']
if scope is not None: if scope is not None:
config_cmd_line.append(scope) config_cmd_line.append(scope)
@ -163,6 +164,7 @@ def config(scope=None):
@cached @cached
def relation_get(attribute=None, unit=None, rid=None): def relation_get(attribute=None, unit=None, rid=None):
"""Get relation information"""
_args = ['relation-get', '--format=json'] _args = ['relation-get', '--format=json']
if rid: if rid:
_args.append('-r') _args.append('-r')
@ -174,9 +176,14 @@ def relation_get(attribute=None, unit=None, rid=None):
return json.loads(subprocess.check_output(_args)) return json.loads(subprocess.check_output(_args))
except ValueError: except ValueError:
return None return None
except CalledProcessError, e:
if e.returncode == 2:
return None
raise
def relation_set(relation_id=None, relation_settings={}, **kwargs): def relation_set(relation_id=None, relation_settings={}, **kwargs):
"""Set relation information for the current unit"""
relation_cmd_line = ['relation-set'] relation_cmd_line = ['relation-set']
if relation_id is not None: if relation_id is not None:
relation_cmd_line.extend(('-r', relation_id)) relation_cmd_line.extend(('-r', relation_id))
@ -192,7 +199,7 @@ def relation_set(relation_id=None, relation_settings={}, **kwargs):
@cached @cached
def relation_ids(reltype=None): def relation_ids(reltype=None):
"A list of relation_ids" """A list of relation_ids"""
reltype = reltype or relation_type() reltype = reltype or relation_type()
relid_cmd_line = ['relation-ids', '--format=json'] relid_cmd_line = ['relation-ids', '--format=json']
if reltype is not None: if reltype is not None:
@ -203,7 +210,7 @@ def relation_ids(reltype=None):
@cached @cached
def related_units(relid=None): def related_units(relid=None):
"A list of related units" """A list of related units"""
relid = relid or relation_id() relid = relid or relation_id()
units_cmd_line = ['relation-list', '--format=json'] units_cmd_line = ['relation-list', '--format=json']
if relid is not None: if relid is not None:
@ -213,7 +220,7 @@ def related_units(relid=None):
@cached @cached
def relation_for_unit(unit=None, rid=None): def relation_for_unit(unit=None, rid=None):
"Get the json represenation of a unit's relation" """Get the json represenation of a unit's relation"""
unit = unit or remote_unit() unit = unit or remote_unit()
relation = relation_get(unit=unit, rid=rid) relation = relation_get(unit=unit, rid=rid)
for key in relation: for key in relation:
@ -225,7 +232,7 @@ def relation_for_unit(unit=None, rid=None):
@cached @cached
def relations_for_id(relid=None): def relations_for_id(relid=None):
"Get relations of a specific relation ID" """Get relations of a specific relation ID"""
relation_data = [] relation_data = []
relid = relid or relation_ids() relid = relid or relation_ids()
for unit in related_units(relid): for unit in related_units(relid):
@ -237,7 +244,7 @@ def relations_for_id(relid=None):
@cached @cached
def relations_of_type(reltype=None): def relations_of_type(reltype=None):
"Get relations of a specific type" """Get relations of a specific type"""
relation_data = [] relation_data = []
reltype = reltype or relation_type() reltype = reltype or relation_type()
for relid in relation_ids(reltype): for relid in relation_ids(reltype):
@ -249,7 +256,7 @@ def relations_of_type(reltype=None):
@cached @cached
def relation_types(): def relation_types():
"Get a list of relation types supported by this charm" """Get a list of relation types supported by this charm"""
charmdir = os.environ.get('CHARM_DIR', '') charmdir = os.environ.get('CHARM_DIR', '')
mdf = open(os.path.join(charmdir, 'metadata.yaml')) mdf = open(os.path.join(charmdir, 'metadata.yaml'))
md = yaml.safe_load(mdf) md = yaml.safe_load(mdf)
@ -264,6 +271,7 @@ def relation_types():
@cached @cached
def relations(): def relations():
"""Get a nested dictionary of relation data for all related units"""
rels = {} rels = {}
for reltype in relation_types(): for reltype in relation_types():
relids = {} relids = {}
@ -278,14 +286,14 @@ def relations():
def open_port(port, protocol="TCP"): def open_port(port, protocol="TCP"):
"Open a service network port" """Open a service network port"""
_args = ['open-port'] _args = ['open-port']
_args.append('{}/{}'.format(port, protocol)) _args.append('{}/{}'.format(port, protocol))
subprocess.check_call(_args) subprocess.check_call(_args)
def close_port(port, protocol="TCP"): def close_port(port, protocol="TCP"):
"Close a service network port" """Close a service network port"""
_args = ['close-port'] _args = ['close-port']
_args.append('{}/{}'.format(port, protocol)) _args.append('{}/{}'.format(port, protocol))
subprocess.check_call(_args) subprocess.check_call(_args)
@ -293,6 +301,7 @@ def close_port(port, protocol="TCP"):
@cached @cached
def unit_get(attribute): def unit_get(attribute):
"""Get the unit ID for the remote unit"""
_args = ['unit-get', '--format=json', attribute] _args = ['unit-get', '--format=json', attribute]
try: try:
return json.loads(subprocess.check_output(_args)) return json.loads(subprocess.check_output(_args))
@ -301,22 +310,46 @@ def unit_get(attribute):
def unit_private_ip(): def unit_private_ip():
"""Get this unit's private IP address"""
return unit_get('private-address') return unit_get('private-address')
class UnregisteredHookError(Exception): class UnregisteredHookError(Exception):
"""Raised when an undefined hook is called"""
pass pass
class Hooks(object): class Hooks(object):
"""A convenient handler for hook functions.
Example:
hooks = Hooks()
# register a hook, taking its name from the function name
@hooks.hook()
def install():
...
# register a hook, providing a custom hook name
@hooks.hook("config-changed")
def config_changed():
...
if __name__ == "__main__":
# execute a hook based on the name the program is called by
hooks.execute(sys.argv)
"""
def __init__(self): def __init__(self):
super(Hooks, self).__init__() super(Hooks, self).__init__()
self._hooks = {} self._hooks = {}
def register(self, name, function): def register(self, name, function):
"""Register a hook"""
self._hooks[name] = function self._hooks[name] = function
def execute(self, args): def execute(self, args):
"""Execute a registered hook based on args[0]"""
hook_name = os.path.basename(args[0]) hook_name = os.path.basename(args[0])
if hook_name in self._hooks: if hook_name in self._hooks:
self._hooks[hook_name]() self._hooks[hook_name]()
@ -324,6 +357,7 @@ class Hooks(object):
raise UnregisteredHookError(hook_name) raise UnregisteredHookError(hook_name)
def hook(self, *hook_names): def hook(self, *hook_names):
"""Decorator, registering them as hooks"""
def wrapper(decorated): def wrapper(decorated):
for hook_name in hook_names: for hook_name in hook_names:
self.register(hook_name, decorated) self.register(hook_name, decorated)
@ -337,4 +371,5 @@ class Hooks(object):
def charm_dir(): def charm_dir():
"""Return the root directory of the current charm"""
return os.environ.get('CHARM_DIR') return os.environ.get('CHARM_DIR')

View File

@ -19,18 +19,22 @@ from hookenv import log
def service_start(service_name): def service_start(service_name):
"""Start a system service"""
return service('start', service_name) return service('start', service_name)
def service_stop(service_name): def service_stop(service_name):
"""Stop a system service"""
return service('stop', service_name) return service('stop', service_name)
def service_restart(service_name): def service_restart(service_name):
"""Restart a system service"""
return service('restart', service_name) return service('restart', service_name)
def service_reload(service_name, restart_on_failure=False): def service_reload(service_name, restart_on_failure=False):
"""Reload a system service, optionally falling back to restart if reload fails"""
service_result = service('reload', service_name) service_result = service('reload', service_name)
if not service_result and restart_on_failure: if not service_result and restart_on_failure:
service_result = service('restart', service_name) service_result = service('restart', service_name)
@ -38,11 +42,13 @@ def service_reload(service_name, restart_on_failure=False):
def service(action, service_name): def service(action, service_name):
"""Control a system service"""
cmd = ['service', service_name, action] cmd = ['service', service_name, action]
return subprocess.call(cmd) == 0 return subprocess.call(cmd) == 0
def service_running(service): def service_running(service):
"""Determine whether a system service is running"""
try: try:
output = subprocess.check_output(['service', service, 'status']) output = subprocess.check_output(['service', service, 'status'])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
@ -55,7 +61,7 @@ def service_running(service):
def adduser(username, password=None, shell='/bin/bash', system_user=False): def adduser(username, password=None, shell='/bin/bash', system_user=False):
"""Add a user""" """Add a user to the system"""
try: try:
user_info = pwd.getpwnam(username) user_info = pwd.getpwnam(username)
log('user {0} already exists!'.format(username)) log('user {0} already exists!'.format(username))
@ -138,7 +144,7 @@ def write_file(path, content, owner='root', group='root', perms=0444):
def mount(device, mountpoint, options=None, persist=False): def mount(device, mountpoint, options=None, persist=False):
'''Mount a filesystem''' """Mount a filesystem at a particular mountpoint"""
cmd_args = ['mount'] cmd_args = ['mount']
if options is not None: if options is not None:
cmd_args.extend(['-o', options]) cmd_args.extend(['-o', options])
@ -155,7 +161,7 @@ def mount(device, mountpoint, options=None, persist=False):
def umount(mountpoint, persist=False): def umount(mountpoint, persist=False):
'''Unmount a filesystem''' """Unmount a filesystem"""
cmd_args = ['umount', mountpoint] cmd_args = ['umount', mountpoint]
try: try:
subprocess.check_output(cmd_args) subprocess.check_output(cmd_args)
@ -169,7 +175,7 @@ def umount(mountpoint, persist=False):
def mounts(): def mounts():
'''List of all mounted volumes as [[mountpoint,device],[...]]''' """Get a list of all mounted volumes as [[mountpoint,device],[...]]"""
with open('/proc/mounts') as f: with open('/proc/mounts') as f:
# [['/mount/point','/dev/path'],[...]] # [['/mount/point','/dev/path'],[...]]
system_mounts = [m[1::-1] for m in [l.strip().split() system_mounts = [m[1::-1] for m in [l.strip().split()
@ -178,7 +184,7 @@ def mounts():
def file_hash(path): def file_hash(path):
''' Generate a md5 hash of the contents of 'path' or None if not found ''' """Generate a md5 hash of the contents of 'path' or None if not found """
if os.path.exists(path): if os.path.exists(path):
h = hashlib.md5() h = hashlib.md5()
with open(path, 'r') as source: with open(path, 'r') as source:
@ -189,7 +195,7 @@ def file_hash(path):
def restart_on_change(restart_map): def restart_on_change(restart_map):
''' Restart services based on configuration files changing """Restart services based on configuration files changing
This function is used a decorator, for example This function is used a decorator, for example
@ -202,7 +208,7 @@ def restart_on_change(restart_map):
In this example, the cinder-api and cinder-volume services In this example, the cinder-api and cinder-volume services
would be restarted if /etc/ceph/ceph.conf is changed by the would be restarted if /etc/ceph/ceph.conf is changed by the
ceph_client_changed function. ceph_client_changed function.
''' """
def wrap(f): def wrap(f):
def wrapped_f(*args): def wrapped_f(*args):
checksums = {} checksums = {}
@ -220,7 +226,7 @@ def restart_on_change(restart_map):
def lsb_release(): def lsb_release():
'''Return /etc/lsb-release in a dict''' """Return /etc/lsb-release in a dict"""
d = {} d = {}
with open('/etc/lsb-release', 'r') as lsb: with open('/etc/lsb-release', 'r') as lsb:
for l in lsb: for l in lsb:
@ -230,7 +236,7 @@ def lsb_release():
def pwgen(length=None): def pwgen(length=None):
'''Generate a random pasword.''' """Generate a random pasword."""
if length is None: if length is None:
length = random.choice(range(35, 45)) length = random.choice(range(35, 45))
alphanumeric_chars = [ alphanumeric_chars = [

View File

@ -79,9 +79,24 @@ def apt_purge(packages, fatal=False):
subprocess.call(cmd) subprocess.call(cmd)
def apt_hold(packages, fatal=False):
"""Hold one or more packages"""
cmd = ['apt-mark', 'hold']
if isinstance(packages, basestring):
cmd.append(packages)
else:
cmd.extend(packages)
log("Holding {}".format(packages))
if fatal:
subprocess.check_call(cmd)
else:
subprocess.call(cmd)
def add_source(source, key=None): def add_source(source, key=None):
if ((source.startswith('ppa:') or if (source.startswith('ppa:') or
source.startswith('http:'))): source.startswith('http:') or
source.startswith('deb ')):
subprocess.check_call(['add-apt-repository', '--yes', source]) subprocess.check_call(['add-apt-repository', '--yes', source])
elif source.startswith('cloud:'): elif source.startswith('cloud:'):
apt_install(filter_installed_packages(['ubuntu-cloud-keyring']), apt_install(filter_installed_packages(['ubuntu-cloud-keyring']),
@ -118,8 +133,11 @@ def configure_sources(update=False,
Note that 'null' (a.k.a. None) should not be quoted. Note that 'null' (a.k.a. None) should not be quoted.
""" """
sources = safe_load(config(sources_var)) sources = safe_load(config(sources_var))
keys = safe_load(config(keys_var)) keys = config(keys_var)
if isinstance(sources, basestring) and isinstance(keys, basestring): if keys is not None:
keys = safe_load(keys)
if isinstance(sources, basestring) and (
keys is None or isinstance(keys, basestring)):
add_source(sources, keys) add_source(sources, keys)
else: else:
if not len(sources) == len(keys): if not len(sources) == len(keys):

View File

@ -139,6 +139,16 @@ class NeutronCCContext(context.NeutronContext):
def __call__(self): def __call__(self):
ctxt = super(NeutronCCContext, self).__call__() ctxt = super(NeutronCCContext, self).__call__()
ctxt['external_network'] = config('neutron-external-network') ctxt['external_network'] = config('neutron-external-network')
if 'nvp' in [config('quantum-plugin'), config('neutron-plugin')]:
_config = config()
for k, v in _config.iteritems():
if k.startswith('nvp'):
ctxt[k.replace('-', '_')] = v
if 'nvp-controllers' in _config:
ctxt['nvp_controllers'] = \
','.join(_config['nvp-controllers'].split())
ctxt['nvp_controllers_list'] = \
_config['nvp-controllers'].split()
return ctxt return ctxt

View File

@ -286,15 +286,6 @@ def quantum_joined(rid=None):
if not eligible_leader(CLUSTER_RES): if not eligible_leader(CLUSTER_RES):
return return
if network_manager() == 'quantum':
pkg = 'quantum-server'
else:
pkg = 'neutron-server'
required_pkg = filter_installed_packages([pkg])
if required_pkg:
apt_install(required_pkg)
url = canonical_url(CONFIGS) + ':9696' url = canonical_url(CONFIGS) + ':9696'
# XXX: Can we rename to neutron_*? # XXX: Can we rename to neutron_*?
rel_settings = { rel_settings = {
@ -314,7 +305,7 @@ def quantum_joined(rid=None):
if ks_auth_config and ks_ca: if ks_auth_config and ks_ca:
rel_settings['ca_cert'] = ks_ca rel_settings['ca_cert'] = ks_ca
relation_set(rid=rid, **rel_settings) relation_set(relation_id=rid, **rel_settings)
@hooks.hook('cluster-relation-changed', @hooks.hook('cluster-relation-changed',

View File

@ -76,6 +76,8 @@ NEUTRON_CONF = '/etc/neutron/neutron.conf'
HAPROXY_CONF = '/etc/haproxy/haproxy.cfg' HAPROXY_CONF = '/etc/haproxy/haproxy.cfg'
APACHE_CONF = '/etc/apache2/sites-available/openstack_https_frontend' APACHE_CONF = '/etc/apache2/sites-available/openstack_https_frontend'
APACHE_24_CONF = '/etc/apache2/sites-available/openstack_https_frontend.conf' APACHE_24_CONF = '/etc/apache2/sites-available/openstack_https_frontend.conf'
NEUTRON_DEFAULT = '/etc/default/neutron-server'
QUANTUM_DEFAULT = '/etc/default/quantum-server'
BASE_RESOURCE_MAP = OrderedDict([ BASE_RESOURCE_MAP = OrderedDict([
(NOVA_CONF, { (NOVA_CONF, {
@ -105,6 +107,10 @@ BASE_RESOURCE_MAP = OrderedDict([
nova_cc_context.IdentityServiceContext(), nova_cc_context.IdentityServiceContext(),
nova_cc_context.NeutronCCContext()], nova_cc_context.NeutronCCContext()],
}), }),
(QUANTUM_DEFAULT, {
'services': ['quantum-server'],
'contexts': [nova_cc_context.NeutronCCContext()],
}),
(QUANTUM_API_PASTE, { (QUANTUM_API_PASTE, {
'services': ['quantum-server'], 'services': ['quantum-server'],
'contexts': [nova_cc_context.IdentityServiceContext()], 'contexts': [nova_cc_context.IdentityServiceContext()],
@ -116,6 +122,10 @@ BASE_RESOURCE_MAP = OrderedDict([
nova_cc_context.NeutronCCContext(), nova_cc_context.NeutronCCContext(),
nova_cc_context.HAProxyContext()], nova_cc_context.HAProxyContext()],
}), }),
(NEUTRON_DEFAULT, {
'services': ['neutron-server'],
'contexts': [nova_cc_context.NeutronCCContext()],
}),
(HAPROXY_CONF, { (HAPROXY_CONF, {
'contexts': [context.HAProxyContext(), 'contexts': [context.HAProxyContext(),
nova_cc_context.HAProxyContext()], nova_cc_context.HAProxyContext()],
@ -171,11 +181,12 @@ def resource_map():
plugin = neutron_plugin() plugin = neutron_plugin()
if plugin: if plugin:
conf = neutron_plugin_attribute(plugin, 'config', net_manager) conf = neutron_plugin_attribute(plugin, 'config', net_manager)
service = '%s-server' % net_manager
ctxts = (neutron_plugin_attribute(plugin, 'contexts', net_manager) ctxts = (neutron_plugin_attribute(plugin, 'contexts', net_manager)
or []) or [])
services = neutron_plugin_attribute(plugin, 'server_services',
net_manager)
resource_map[conf] = {} resource_map[conf] = {}
resource_map[conf]['services'] = [service] resource_map[conf]['services'] = services
resource_map[conf]['contexts'] = ctxts resource_map[conf]['contexts'] = ctxts
resource_map[conf]['contexts'].append( resource_map[conf]['contexts'].append(
nova_cc_context.NeutronCCContext()) nova_cc_context.NeutronCCContext())
@ -232,6 +243,10 @@ def determine_packages():
packages = [] + BASE_PACKAGES packages = [] + BASE_PACKAGES
for k, v in resource_map().iteritems(): for k, v in resource_map().iteritems():
packages.extend(v['services']) packages.extend(v['services'])
if network_manager() in ['neutron', 'quantum']:
pkgs = neutron_plugin_attribute(neutron_plugin(), 'server_packages',
network_manager())
packages.extend(pkgs)
return list(set(packages)) return list(set(packages))

1257
icon.svg

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1 +1 @@
307 308

View File

@ -57,6 +57,14 @@ default_floating_pool = {{ external_network }}
{% endif -%} {% endif -%}
{% endif -%} {% endif -%}
{% if neutron_plugin and neutron_plugin == 'nvp' -%}
security_group_api = neutron
nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
{% if external_network -%}
default_floating_pool = {{ external_network }}
{% endif -%}
{% endif -%}
{% if network_manager_config -%} {% if network_manager_config -%}
{% for key, value in network_manager_config.iteritems() -%} {% for key, value in network_manager_config.iteritems() -%}
{{ key }} = {{ value }} {{ key }} = {{ value }}

View File

@ -0,0 +1,6 @@
# quantum
###############################################################################
# [ WARNING ]
# Configuration file maintained by Juju. Local changes may be overwritten.
###############################################################################
QUANTUM_PLUGIN_CONFIG="{{ config }}"

View File

@ -0,0 +1,6 @@
# havana
###############################################################################
# [ WARNING ]
# Configuration file maintained by Juju. Local changes may be overwritten.
###############################################################################
NEUTRON_PLUGIN_CONFIG="{{ config }}"

11
templates/havana/nvp.ini Normal file
View File

@ -0,0 +1,11 @@
# havana
###############################################################################
# [ WARNING ]
# Configuration file maintained by Juju. Local changes may be overwritten.
###############################################################################
[DEFAULT]
nvp_user = {{ nvp_username }}
nvp_password = {{ nvp_password }}
nvp_controllers = {{ nvp_controllers }}
default_tz_uuid = {{ nvp_tz_uuid }}
default_l3_gw_service_uuid = {{ nvp_l3_uuid }}

View File

@ -70,10 +70,11 @@ RESTART_MAP = OrderedDict([
'nova-api-ec2', 'nova-api-os-compute' 'nova-api-ec2', 'nova-api-os-compute'
]), ]),
('/etc/neutron/neutron.conf', ['neutron-server']), ('/etc/neutron/neutron.conf', ['neutron-server']),
('/etc/default/neutron-server', ['neutron-server']),
('/etc/haproxy/haproxy.cfg', ['haproxy']), ('/etc/haproxy/haproxy.cfg', ['haproxy']),
('/etc/apache2/sites-available/openstack_https_frontend', ['apache2']), ('/etc/apache2/sites-available/openstack_https_frontend', ['apache2']),
('/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini', ('/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini',
['neutron-server']) ['quantum-server'])
]) ])
@ -87,13 +88,17 @@ PLUGIN_ATTRIBUTES = {
'services': ['quantum-plugin-openvswitch-agent'], 'services': ['quantum-plugin-openvswitch-agent'],
'packages': ['quantum-plugin-openvswitch-agent', 'packages': ['quantum-plugin-openvswitch-agent',
'openvswitch-datapath-dkms'], 'openvswitch-datapath-dkms'],
'server_packages': ['quantum-server', 'quantum-plugin-openvswitch'],
'server_services': ['quantum-server'],
}, },
'nvp': { 'nvp': {
'config': '/etc/quantum/plugins/nicira/nvp.ini', 'config': '/etc/quantum/plugins/nicira/nvp.ini',
'driver': 'quantum.plugins.nicira.nicira_nvp_plugin.' 'driver': 'quantum.plugins.nicira.nicira_nvp_plugin.'
'QuantumPlugin.NvpPluginV2', 'QuantumPlugin.NvpPluginV2',
'services': [], 'services': [],
'packages': ['quantum-plugin-nicira'], 'packages': [],
'server_packages': ['quantum-server', 'quantum-plugin-nicria'],
'server_services': ['quantum-server'],
} }
} }