Merge NVP support.
This commit is contained in:
commit
028ff2ed69
2
.project
2
.project
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
29
config.yaml
29
config.yaml
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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')
|
||||||
|
@ -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 = [
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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',
|
||||||
|
@ -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
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 |
@ -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 }}
|
||||||
|
6
templates/folsom/quantum-server
Normal file
6
templates/folsom/quantum-server
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# quantum
|
||||||
|
###############################################################################
|
||||||
|
# [ WARNING ]
|
||||||
|
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||||
|
###############################################################################
|
||||||
|
QUANTUM_PLUGIN_CONFIG="{{ config }}"
|
6
templates/havana/neutron-server
Normal file
6
templates/havana/neutron-server
Normal 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
11
templates/havana/nvp.ini
Normal 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 }}
|
@ -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'],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user