~niedbalski/charms/trusty/quantum-gateway/lp-1396607

« back to all changes in this revision

Viewing changes to hooks/quantum_utils.py

  • Committer: James Page
  • Date: 2013-07-19 09:46:25 UTC
  • mto: (33.1.23 python-redux)
  • mto: This revision was merged to the branch mainline in revision 34.
  • Revision ID: james.page@canonical.com-20130719094625-wqfy6lw11vzhs5ba
Redux to use agree structure and OS templating

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
import subprocess
2
1
import os
3
2
import uuid
4
 
import base64
5
 
import apt_pkg as apt
 
3
import socket
6
4
from charmhelpers.core.hookenv import (
7
5
    log,
8
 
    config
 
6
    config,
 
7
    unit_get,
 
8
    cached
9
9
)
10
10
from charmhelpers.core.host import (
11
 
    apt_install
12
 
)
13
 
from charmhelpers.contrib.openstack.openstack_utils import (
14
 
    configure_installation_source
15
 
)
 
11
    apt_install,
 
12
    apt_update
 
13
)
 
14
from charmhelpers.contrib.network.ovs import (
 
15
    add_bridge,
 
16
    add_bridge_port
 
17
)
 
18
from charmhelpers.contrib.openstack.utils import (
 
19
    configure_installation_source,
 
20
    get_os_codename_package,
 
21
    get_os_codename_install_source
 
22
)
 
23
import charmhelpers.contrib.openstack.context as context
 
24
import charmhelpers.contrib.openstack.templating as templating
 
25
import quantum_contexts
 
26
from collections import OrderedDict
16
27
 
17
28
OVS = "ovs"
18
29
NVP = "nvp"
26
37
    NVP: NVP_PLUGIN
27
38
}
28
39
 
 
40
 
 
41
def valid_plugin():
 
42
    return config('plugin') in CORE_PLUGIN
 
43
 
29
44
OVS_PLUGIN_CONF = \
30
45
    "/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini"
31
46
NVP_PLUGIN_CONF = \
51
66
    ]
52
67
}
53
68
 
54
 
GATEWAY_AGENTS = {
55
 
    OVS: [
56
 
        "quantum-plugin-openvswitch-agent",
57
 
        "quantum-l3-agent",
58
 
        "quantum-dhcp-agent",
59
 
        "nova-api-metadata"
60
 
    ],
61
 
    NVP: [
62
 
        "quantum-dhcp-agent",
63
 
        "nova-api-metadata"
64
 
    ],
 
69
EARLY_PACKAGES = {
 
70
    OVS: ['openvswitch-datapath-dkms']
65
71
}
66
72
 
 
73
 
 
74
def get_early_packages():
 
75
    '''Return a list of package for pre-install based on configured plugin'''
 
76
    if config('plugin') in EARLY_PACKAGES:
 
77
        return EARLY_PACKAGES[config('plugin')]
 
78
    else:
 
79
        return []
 
80
 
 
81
 
 
82
def get_packages():
 
83
    '''Return a list of packages for install based on the configured plugin'''
 
84
    return GATEWAY_PKGS[config('plugin')]
 
85
 
67
86
EXT_PORT_CONF = '/etc/init/ext-port.conf'
68
 
 
69
 
 
70
 
def get_os_version(package=None):
71
 
    apt.init()
72
 
    cache = apt.Cache()
73
 
    pkg = cache[package or 'quantum-common']
74
 
    if pkg.current_ver:
75
 
        return apt.upstream_version(pkg.current_ver.ver_str)
76
 
    else:
77
 
        return None
78
 
 
79
 
 
80
 
if get_os_version('quantum-common') >= "2013.1":
81
 
    for plugin in GATEWAY_AGENTS:
82
 
        GATEWAY_AGENTS[plugin].append("quantum-metadata-agent")
 
87
TEMPLATES = 'templates'
 
88
 
 
89
QUANTUM_CONF = "/etc/quantum/quantum.conf"
 
90
L3_AGENT_CONF = "/etc/quantum/l3_agent.ini"
 
91
DHCP_AGENT_CONF = "/etc/quantum/dhcp_agent.ini"
 
92
METADATA_AGENT_CONF = "/etc/quantum/metadata_agent.ini"
 
93
NOVA_CONF = "/etc/nova/nova.conf"
 
94
 
 
95
SHARED_CONFIG_FILES = {
 
96
    DHCP_AGENT_CONF: {
 
97
        'hook_contexts': [quantum_contexts.QuantumGatewayContext()],
 
98
        'services': ['quantum-dhcp-agent']
 
99
    },
 
100
    METADATA_AGENT_CONF: {
 
101
        'hook_contexts': [quantum_contexts.NetworkServiceContext()],
 
102
        'services': ['quantum-metadata-agent']
 
103
    },
 
104
    NOVA_CONF: {
 
105
        'hook_contexts': [context.AMQPContext(),
 
106
                          context.SharedDBContext(),
 
107
                          quantum_contexts.NetworkServiceContext(),
 
108
                          quantum_contexts.QuantumGatewayContext()],
 
109
        'services': ['nova-api-metadata']
 
110
    },
 
111
}
 
112
 
 
113
OVS_CONFIG_FILES = {
 
114
    QUANTUM_CONF: {
 
115
        'hook_contexts': [context.AMQPContext(),
 
116
                          quantum_contexts.QuantumGatewayContext()],
 
117
        'services': ['quantum-l3-agent',
 
118
                     'quantum-dhcp-agent',
 
119
                     'quantum-metadata-agent',
 
120
                     'quantum-plugin-openvswitch-agent']
 
121
    },
 
122
    L3_AGENT_CONF: {
 
123
        'hook_contexts': [quantum_contexts.NetworkServiceContext()],
 
124
        'services': ['quantum-l3-agent']
 
125
    },
 
126
    # TODO: Check to see if this is actually required
 
127
    OVS_PLUGIN_CONF: {
 
128
        'hook_contexts': [context.SharedDBContext(),
 
129
                          quantum_contexts.QuantumGatewayContext()],
 
130
        'services': ['quantum-plugin-openvswitch-agent']
 
131
    },
 
132
    EXT_PORT_CONF: {
 
133
        'hook_contexts': [quantum_contexts.ExternalPortContext()],
 
134
        'services': []
 
135
    }
 
136
}
 
137
 
 
138
NVP_CONFIG_FILES = {
 
139
    QUANTUM_CONF: {
 
140
        'hook_contexts': [context.AMQPContext()],
 
141
        'services': ['quantum-dhcp-agent', 'quantum-metadata-agent']
 
142
    },
 
143
}
 
144
 
 
145
CONFIG_FILES = {
 
146
    NVP: NVP_CONFIG_FILES.update(SHARED_CONFIG_FILES),
 
147
    OVS: OVS_CONFIG_FILES.update(SHARED_CONFIG_FILES),
 
148
}
 
149
 
 
150
 
 
151
def register_configs():
 
152
    ''' Register config files with their respective contexts. '''
 
153
    release = get_os_codename_package('quantum-common', fatal=False) or \
 
154
        'essex'
 
155
    configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
 
156
                                          openstack_release=release)
 
157
 
 
158
    plugin = config('plugin')
 
159
    for conf in CONFIG_FILES[plugin].keys():
 
160
        configs.register(conf, CONFIG_FILES[conf]['hook_contexts'])
 
161
 
 
162
    return configs
 
163
 
 
164
 
 
165
def restart_map():
 
166
    '''
 
167
    Determine the correct resource map to be passed to
 
168
    charmhelpers.core.restart_on_change() based on the services configured.
 
169
 
 
170
    :returns: dict: A dictionary mapping config file to lists of services
 
171
                    that should be restarted when file changes.
 
172
    '''
 
173
    _map = []
 
174
    for f, ctxt in CONFIG_FILES[config('plugin')].iteritems():
 
175
        svcs = []
 
176
        for svc in ctxt['services']:
 
177
            svcs.append(svc)
 
178
        if svcs:
 
179
            _map.append((f, svcs))
 
180
    return OrderedDict(_map)
 
181
 
83
182
 
84
183
DB_USER = "quantum"
85
184
QUANTUM_DB = "quantum"
87
186
NOVA_DB_USER = "nova"
88
187
NOVA_DB = "nova"
89
188
 
90
 
QUANTUM_CONF = "/etc/quantum/quantum.conf"
91
 
L3_AGENT_CONF = "/etc/quantum/l3_agent.ini"
92
 
DHCP_AGENT_CONF = "/etc/quantum/dhcp_agent.ini"
93
 
METADATA_AGENT_CONF = "/etc/quantum/metadata_agent.ini"
94
 
NOVA_CONF = "/etc/nova/nova.conf"
95
 
 
96
 
 
97
 
OVS_RESTART_MAP = {
98
 
    QUANTUM_CONF: [
99
 
        'quantum-l3-agent',
100
 
        'quantum-dhcp-agent',
101
 
        'quantum-metadata-agent',
102
 
        'quantum-plugin-openvswitch-agent'
103
 
    ],
104
 
    DHCP_AGENT_CONF: [
105
 
        'quantum-dhcp-agent'
106
 
    ],
107
 
    L3_AGENT_CONF: [
108
 
        'quantum-l3-agent'
109
 
    ],
110
 
    METADATA_AGENT_CONF: [
111
 
        'quantum-metadata-agent'
112
 
    ],
113
 
    OVS_PLUGIN_CONF: [
114
 
        'quantum-plugin-openvswitch-agent'
115
 
    ],
116
 
    NOVA_CONF: [
117
 
        'nova-api-metadata'
118
 
    ]
119
 
}
120
 
 
121
 
NVP_RESTART_MAP = {
122
 
    QUANTUM_CONF: [
123
 
        'quantum-dhcp-agent',
124
 
        'quantum-metadata-agent'
125
 
    ],
126
 
    DHCP_AGENT_CONF: [
127
 
        'quantum-dhcp-agent'
128
 
    ],
129
 
    METADATA_AGENT_CONF: [
130
 
        'quantum-metadata-agent'
131
 
    ],
132
 
    NOVA_CONF: [
133
 
        'nova-api-metadata'
134
 
    ]
135
 
}
136
 
 
137
 
 
138
 
RESTART_MAP = {
139
 
    OVS: OVS_RESTART_MAP,
140
 
    NVP: NVP_RESTART_MAP
141
 
}
142
 
 
143
 
 
144
189
RABBIT_USER = "nova"
145
190
RABBIT_VHOST = "nova"
146
191
 
161
206
            secret = secret_file.read().strip()
162
207
    return secret
163
208
 
164
 
 
165
 
def flush_local_configuration():
166
 
    if os.path.exists('/usr/bin/quantum-netns-cleanup'):
167
 
        cmd = [
168
 
            "quantum-netns-cleanup",
169
 
            "--config-file=/etc/quantum/quantum.conf"
170
 
        ]
171
 
        for agent_conf in ['l3_agent.ini', 'dhcp_agent.ini']:
172
 
            agent_cmd = list(cmd)
173
 
            agent_cmd.append('--config-file=/etc/quantum/{}'
174
 
                             .format(agent_conf))
175
 
            subprocess.call(agent_cmd)
176
 
 
177
 
 
178
 
def install_ca(ca_cert):
179
 
    with open('/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt',
180
 
              'w') as crt:
181
 
        crt.write(base64.b64decode(ca_cert))
182
 
    subprocess.check_call(['update-ca-certificates', '--fresh'])
183
 
 
184
209
DHCP_AGENT = "DHCP Agent"
185
210
L3_AGENT = "L3 Agent"
186
211
 
187
212
 
188
 
def reassign_agent_resources(env):
 
213
def reassign_agent_resources():
189
214
    ''' Use agent scheduler API to detect down agents and re-schedule '''
190
 
    from quantumclient.v2_0 import client
 
215
    env = quantum_contexts.NetworkServiceContext()()
 
216
    if not env:
 
217
        log('Unable to re-assign resources at this time')
 
218
        return
 
219
    try:
 
220
        from quantumclient.v2_0 import client
 
221
    except ImportError:
 
222
        ''' Try to import neutronclient instead for havana+ '''
 
223
        from neutronclient.v2_0 import client
 
224
 
191
225
    # TODO: Fixup for https keystone
192
226
    auth_url = 'http://%(keystone_host)s:%(auth_port)s/v2.0' % env
193
227
    quantum = client.Client(username=env['service_username'],
243
277
        index += 1
244
278
 
245
279
 
246
 
def do_openstack_upgrade():
247
 
    configure_installation_source(config('openstack-origin'))
248
 
    plugin = config('plugin')
249
 
    pkgs = []
250
 
    if plugin in GATEWAY_PKGS.keys():
251
 
        pkgs.extend(GATEWAY_PKGS[plugin])
252
 
        if plugin in [OVS, NVP]:
253
 
            pkgs.append('openvswitch-datapath-dkms')
 
280
def do_openstack_upgrade(configs):
 
281
    """
 
282
    Perform an upgrade.  Takes care of upgrading packages, rewriting
 
283
    configs, database migrations and potentially any other post-upgrade
 
284
    actions.
 
285
 
 
286
    :param configs: The charms main OSConfigRenderer object.
 
287
    """
 
288
    new_src = config('openstack-origin')
 
289
    new_os_rel = get_os_codename_install_source(new_src)
 
290
 
 
291
    log('Performing OpenStack upgrade to %s.' % (new_os_rel))
 
292
 
 
293
    configure_installation_source(new_src)
254
294
    dpkg_opts = [
255
 
        '--option', 'Dpkg::Options::=--force-confold',
256
 
        '--option', 'Dpkg::Options::=--force-confdef'
 
295
        '--option', 'Dpkg::Options::=--force-confnew',
 
296
        '--option', 'Dpkg::Options::=--force-confdef',
257
297
    ]
258
 
    apt_install(pkgs, options=dpkg_opts, fatal=True)
 
298
    apt_update(fatal=True)
 
299
    apt_install(packages=GATEWAY_PKGS[config('plugin')], options=dpkg_opts,
 
300
                fatal=True)
 
301
 
 
302
    # set CONFIGS to load templates from new release
 
303
    configs.set_release(openstack_release=new_os_rel)
 
304
 
 
305
 
 
306
@cached
 
307
def get_host_ip(hostname=None):
 
308
    try:
 
309
        import dns.resolver
 
310
    except ImportError:
 
311
        apt_install('python-dnspython', fatal=True)
 
312
        import dns.resolver
 
313
    hostname = hostname or unit_get('private-address')
 
314
    try:
 
315
        # Test to see if already an IPv4 address
 
316
        socket.inet_aton(hostname)
 
317
        return hostname
 
318
    except socket.error:
 
319
        answers = dns.resolver.query(hostname, 'A')
 
320
        if answers:
 
321
            return answers[0].address
 
322
 
 
323
 
 
324
def configure_ovs():
 
325
    if config('plugin') == OVS:
 
326
        add_bridge(INT_BRIDGE)
 
327
        add_bridge(EXT_BRIDGE)
 
328
        ext_port = config('ext-port')
 
329
        if ext_port:
 
330
            add_bridge_port(EXT_BRIDGE, ext_port)
 
331
    if config('plugin') == NVP:
 
332
        add_bridge(INT_BRIDGE)