2
# Copyright 2012 Canonical Ltd.
5
# James Page <james.page@ubuntu.com>
6
# Paul Collins <paul.collins@canonical.com>
8
from lib.openstack_common import *
10
ceilometer_conf = "/etc/ceilometer/ceilometer.conf"
12
def execute(cmd, die=False, echo=False):
13
""" Executes a command
15
if die=True, script will exit(1) if command does not return 0
16
if echo=True, output of command will be printed to stdout
18
returns a tuple: (stdout, stderr, return code)
20
p = subprocess.Popen(cmd.split(" "),
21
stdout=subprocess.PIPE,
22
stdin=subprocess.PIPE,
23
stderr=subprocess.PIPE)
32
for l in iter(p.stdout.readline, ''):
35
for l in iter(p.stderr.readline, ''):
43
error_out("ERROR: command %s return non-zero.\n" % cmd)
44
return (stdout, stderr, rc)
48
""" Obtain the units config via 'config-get'
49
Returns a dict representing current config.
50
private-address and IP of the unit is also tacked on for
53
output = execute("config-get --format json")[0]
55
config = json.loads(output)
56
# make sure no config element is blank after config-get
57
for c in config.keys():
59
error_out("ERROR: Config option has no paramter: %s" % c)
60
# tack on our private address and ip
61
hostname = execute("unit-get private-address")[0].strip()
62
config["hostname"] = execute("unit-get private-address")[0].strip()
17
hook = os.path.basename(sys.argv[0])
20
hook_func = hooks[hook]
23
"This charm doesn't know how to handle '{}'.".format(hook))
67
def relation_ids(relation_name=None):
68
j = execute('relation-ids --format=json %s' % relation_name)[0]
71
def relation_list(relation_id=None):
72
cmd = 'relation-list --format=json'
74
cmd += ' -r %s' % relation_id
78
def relation_set(relation_data):
79
""" calls relation-set for all key=values in dict """
80
for k in relation_data:
81
execute("relation-set %s=%s" % (k, relation_data[k]), die=True)
83
def relation_get(relation_data):
84
""" Obtain all current relation data
85
relation_data is a list of options to query from the relation
86
Returns a k,v dict of the results.
87
Leave empty responses out of the results as they haven't yet been
89
Caller can then "len(results.keys()) == len(relation_data)" to find out if
90
all relation values have been set on the other side
93
for r in relation_data:
94
result = execute("relation-get %s" % r, die=True)[0].strip('\n')
99
def relation_get_dict(relation_id=None, remote_unit=None):
100
"""Obtain all relation data as dict by way of JSON"""
101
cmd = 'relation-get --format=json'
103
cmd += ' -r %s' % relation_id
105
remote_unit_orig = os.getenv('JUJU_REMOTE_UNIT', None)
106
os.environ['JUJU_REMOTE_UNIT'] = remote_unit
107
j = execute(cmd, die=True)[0]
108
if remote_unit and remote_unit_orig:
109
os.environ['JUJU_REMOTE_UNIT'] = remote_unit_orig
112
# convert unicode to strings
113
for k, v in d.iteritems():
114
settings[str(k)] = str(v)
117
def update_config_block(block, **kwargs):
118
""" Updates ceilometer.conf blocks given kwargs.
119
Can be used to update driver settings for a particular backend,
120
setting the sql connection, etc.
122
Parses block heading as '[block]'
124
If block does not exist, a new block will be created at end of file with
127
f = open(ceilometer_conf, "r+")
131
heading = "[%s]\n" % block
136
def update_block(block):
137
for k, v in kwargs.iteritems():
139
if l.strip().split(" ")[0] == k:
140
block[block.index(l)] = "%s = %s\n" % (k, v)
142
block.append('%s = %s\n' % (k, v))
148
if orig[ln] != heading:
155
while orig[ln].strip() != '':
156
block.append(orig[ln])
163
if new[(len(new) - 1)].strip() != '':
165
new.append('%s' % heading)
166
for k, v in kwargs.iteritems():
167
new.append('%s = %s\n' % (k, v))
170
error_out('Error while attempting to update config block. '\
171
'Refusing to overwite existing config.')
36
subprocess.check_call(cmd)
38
TEMPLATES_DIR = 'templates'
43
install('python-jinja2')
46
def render_template(template_name, context, template_dir=TEMPLATES_DIR):
47
templates = jinja2.Environment(
48
loader=jinja2.FileSystemLoader(template_dir)
50
template = templates.get_template(template_name)
51
return template.render(context)
54
""" # Ubuntu Cloud Archive
55
deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
58
CLOUD_ARCHIVE_POCKETS = {
59
'precise-folsom': 'precise-updates/folsom',
60
'precise-folsom/updates': 'precise-updates/folsom',
61
'precise-folsom/proposed': 'precise-proposed/folsom',
62
'precise-grizzly': 'precise-updates/grizzly',
63
'precise-grizzly/updates': 'precise-updates/grizzly',
64
'precise-grizzly/proposed': 'precise-proposed/grizzly'
67
def configure_source():
68
source = str(config_get('openstack-origin'))
175
# backup original config
176
backup = open(ceilometer_conf + '.juju-back', 'w+')
188
def ceilometer_conf_update(opt, val):
189
""" Updates ceilometer.conf values
190
If option exists, it is reset to new value
191
If it does not, it added to the top of the config file after the [DEFAULT]
192
heading to keep it out of the paste deploy config
194
f = open(ceilometer_conf, "r+")
199
if l.split(' ')[0] == opt:
200
juju_log("Updating %s, setting %s = %s" % (keystone_conf, opt, val))
201
new += "%s = %s\n" % (opt, val)
71
if source.startswith('ppa:'):
76
subprocess.check_call(cmd)
77
if source.startswith('cloud:'):
78
install('ubuntu-cloud-keyring')
79
pocket = source.split(':')[1]
80
with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as apt:
81
apt.write(CLOUD_ARCHIVE.format(CLOUD_ARCHIVE_POCKETS[pocket]))
82
if source.startswith('deb'):
83
l = len(source.split('|'))
85
(apt_line, key) = source.split('|')
88
'adv', '--keyserver keyserver.ubuntu.com',
91
subprocess.check_call(cmd)
95
with open('/etc/apt/sources.list.d/ceilometer.list', 'w') as apt:
96
apt.write(apt_line + "\n")
101
subprocess.check_call(cmd)
108
def expose(port, protocol='TCP'):
111
'{}/{}'.format(port, protocol)
113
subprocess.check_call(cmd)
116
def juju_log(severity, message):
119
'--log-level', severity,
122
subprocess.check_call(cmd)
125
def relation_ids(relation):
130
return subprocess.check_output(cmd).split() # IGNORE:E1103
133
def relation_list(rid):
138
return subprocess.check_output(cmd).split() # IGNORE:E1103
141
def relation_get(attribute, unit=None, rid=None):
148
cmd.append(attribute)
151
value = subprocess.check_output(cmd).strip() # IGNORE:E1103
158
def relation_set(**kwargs):
163
for k, v in kwargs.items():
205
new = new.split('\n')
206
# insert a new value at the top of the file, after the 'DEFAULT' header so
207
# as not to muck up paste deploy configuration later in the file
209
juju_log("Adding new config option %s = %s" % (opt, val))
210
header = new.index("[DEFAULT]")
211
new.insert((header+1), "%s = %s" % (opt, val))
168
args.append('{}={}'.format(k, v))
170
subprocess.check_call(cmd)
173
def unit_get(attribute):
178
value = subprocess.check_output(cmd).strip() # IGNORE:E1103
185
def config_get(attribute):
190
value = subprocess.check_output(cmd).strip() # IGNORE:E1103
197
def get_unit_hostname():
198
return socket.gethostname()
201
def get_host_ip(hostname=unit_get('private-address')):
203
# Test to see if already an IPv4 address
204
socket.inet_aton(hostname)
209
answers = dns.resolver.query(hostname, 'A')
211
return answers[0].address
212
except dns.resolver.NXDOMAIN:
217
CLUSTER_RESOURCES = {
218
'quantum-dhcp-agent': 'res_quantum_dhcp_agent',
219
'quantum-l3-agent': 'res_quantum_l3_agent'
222
HAMARKER = '/var/lib/juju/haconfigured'
225
def _service_ctl(service, action):
226
if (os.path.exists(HAMARKER) and
227
os.path.exists(os.path.join('/etc/init/',
228
'{}.override'.format(service))) and
229
service in CLUSTER_RESOURCES):
230
hostname = str(subprocess.check_output(['hostname'])).strip()
232
subprocess.check_output(['crm', 'resource', 'show',
233
CLUSTER_RESOURCES[service]])
234
# Only restart if we are the node that owns the service
235
if hostname in service_status:
236
subprocess.check_call(['crm', 'resource', action,
237
CLUSTER_RESOURCES[service]])
239
subprocess.check_call(['service', service, action])
242
def restart(*services):
243
for service in services:
244
_service_ctl(service, 'restart')
248
for service in services:
249
_service_ctl(service, 'stop')
252
def start(*services):
253
for service in services:
254
_service_ctl(service, 'start')
257
def get_os_version(package=None):
260
pkg = cache[package or 'quantum-common']
262
return apt.upstream_version(pkg.current_ver.ver_str)