2
from charmhelpers.core.hookenv import (
13
from charmhelpers.fetch import (
17
filter_installed_packages
19
from charmhelpers.core.host import (
25
from charmhelpers.contrib.network.ip import (
28
from tempfile import NamedTemporaryFile
29
from stat import S_ISBLK
37
registry_port_rpc = 7861
38
metadata_port_rpc = 7862
42
registry_port_http = 7871
45
# -- shell-commands -----------------------------
48
def call(cmd, level=DEBUG):
50
result = subprocess.check_output(cmd)
53
log('command not found: {}'.format(e1), ERROR)
55
except subprocess.CalledProcessError as e2:
56
# cmd was not successful
57
return False, '{} {}'.format(e2, e2.output)
59
for line in result.split('\n'):
64
def echo_pipe(text, cmd):
65
""" wrapper for echo $text | $cmd """
67
subprocess.check_call('echo '+text+' | '+cmd, shell=True)
69
log('Error: "echo {} | {}" failed:.\n{}'.format(text, cmd, e), ERROR)
73
# -- file-system --------------------------------
77
return os.listdir(folder) in [[], ['lost+found']]
80
def is_block_device(filename):
82
mode = os.lstat(filename).st_mode
89
def is_mounted(device):
90
# mounts yields [['/mount/point','/dev/path'],[...]]
91
return device in map(lambda x, _: x[1], mounts(), [])
94
def is_quobyte(mount_point):
95
return -1 < max([x.upper().find('QUOBYTE_DEV_SETUP') for x in os.listdir(mount_point)])
98
def create_filesystem(device, filesystem):
99
if filesystem in ['ext4']:
100
log('Create filesystem {} on {}'.format(filesystem, device))
101
success, mkfs_log = call(['mkfs.%s' % filesystem, '-F', '-m0', device])
103
log('{} filesystem created on {}'.format(filesystem, device))
109
log('Given parameter filesystem={} is not supported.'.format(filesystem), ERROR)
113
def mount_device(device, mount_point, overwrite=True, filesystem="ext4"):
114
if os.path.exists(mount_point):
115
if os.path.isdir(mount_point):
116
mount(device, mount_point, persist=True, filesystem=filesystem)
120
os.unlink(mount_point)
121
mount(device, mount_point, persist=True, filesystem=filesystem)
124
# error ~ mount_point is a file
128
mount(device, mount_point, persist=True)
132
# -- package-system -----------------------------
135
def fetch_key_from_repository():
138
release = lsb_release()['DISTRIB_RELEASE']
139
repo_id = config('repo_id')
140
if release in ['12.04', '12.10', '13.10', '14.04', '14.10', '15.04']:
141
url_key = 'https://support.quobyte.com/repo/2/{}/xUbuntu_{}/Release.key'.format(repo_id, release)
143
msg = 'Ubuntu Release {} is not supported'.format(release)
145
status_set('blocked', msg)
148
cmd_fetch = ['wget', '-q', '-O', '-', url_key]
150
key = subprocess.check_output(cmd_fetch)
151
except subprocess.CalledProcessError as error:
152
msg = 'Unable to fetch key: {}'.format(error)
154
status_set('blocked', msg)
156
cmd_extract = ['gpg', '--dry-run', '--list-packets']
157
p2 = subprocess.Popen(cmd_extract, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
158
p2.stdin.writelines(key)
160
key_info = p2.stdout.readlines()
161
for line in key_info:
162
if line.strip().startswith('keyid'):
163
keyid = line.split(':')[1].strip()
168
def update_config_file(key, new_value, filename):
169
""" Look for 'key=some_value' in a a given file and replaces some_value with new_value
170
:param key: key to lookup
171
:param new_value: new value
172
:param filename: file to manipulate
173
:return: 0 if successful, > 0 otherwise
176
out_file_name = tempfile.mkdtemp()
177
out_file_name = os.path.join(out_file_name, os.path.basename(filename))
178
out_file = open(out_file_name, 'w')
180
log('Cannot open a temp. file: %r' % e, ERROR)
185
with open(filename, 'r') as in_file:
187
token = line.strip().split('=')
188
if token[0].strip() == key:
190
new_line = key+'='+new_value
191
if len(token[1].split('#')):
192
# preserve given comments
193
new_line += ' '+''.join(token[1].split('#')[1:])
197
out_file.write(new_line)
199
new_line = '{}={}'.format(key, new_value)
200
out_file.write(new_line)
202
log('Cannot read from file %r: %r' % (filename, e), ERROR)
208
shutil.move(out_file_name, filename)
212
def is_installed(packages=None):
214
packages = ['quobyte-client', 'quobyte-server',
215
'oracle-java8-installer', 'ntp']
216
return len(filter_installed_packages(packages)) is 0
219
def install_quobyte():
222
log('install_quobyte called, but nothing to do', DEBUG)
225
repo_id = config('repo_id')
226
oracle_java_license_accepted = config('oracle-java-license-accepted')
227
quobyte_license_accepted = config('quobyte-license-accepted')
228
if repo_id is None or len(repo_id) == 0:
229
status_set('blocked', 'please provide customer repository id using Juju config')
231
if not oracle_java_license_accepted:
232
status_set('blocked', 'please accept Oracle Java License using Juju config')
234
if not quobyte_license_accepted:
235
status_set('blocked', 'please accept Quobyte License using Juju config')
238
release = lsb_release()['DISTRIB_RELEASE']
239
if release in ['12.04', '14.04', '15.04', '15.10']:
240
qb_deb = 'deb https://support.quobyte.com/repo/2/{}/xUbuntu_{} ./'.format(repo_id, release)
241
if release in ['12.04']:
242
add_source('ppa:ubuntu-toolchain-r/test')
243
apt_update(fatal=True)
244
apt_install(packages=['python-software-properties'])
246
msg = 'Ubuntu Release {} is not supported'.format(release)
248
status_set('blocked', msg)
251
log('Installing Quobyte-Data')
252
status_set('maintenance', 'Installing software')
255
status_set('maintenance', 'Fetching Java')
256
add_source('ppa:webupd8team/java')
257
# accept Oracle Jave License
258
if oracle_java_license_accepted:
259
echo_pipe('oracle-java8-installer shared/accepted-oracle-license-v1-1 select true',
260
'debconf-set-selections')
265
status_set('maintenance', 'Fetching Quobyte')
266
key, keyid = fetch_key_from_repository()
267
log('add key with keyid "%s" to apt' % keyid)
268
add_source(qb_deb, key)
271
status_set('maintenance', 'Installing Software')
272
apt_update(fatal=True)
273
apt_install(['oracle-java8-installer'])
274
apt_install(packages=['quobyte-client', 'quobyte-server', 'ntp'])
276
update_config_file('constants.automation.manage_registry_replicas', 'true', r'/etc/quobyte/host.cfg')
278
if not is_installed():
279
status_set('blocked', 'Installing failed')
282
status_set('maintenance', 'Software is installed')
285
# -- Juju-Relations -----------------------------
288
def get_relation_hosts(relation):
290
address = unit_get('private-address')
292
hosts.append('{}'.format(format_ipv6_addr(address) or address))
293
log('Hosts (local): {}'.format(hosts), DEBUG)
295
for rel_id in relation_ids(relation):
296
for unit in related_units(rel_id):
297
address = relation_get('host', unit, rel_id)
298
if address is not None:
299
hosts.append('{}'.format(
300
format_ipv6_addr(address) or address))
303
log('Hosts (all-known)(relation): {} ({})'.format(hosts, relation), DEBUG)
307
def do_update_replica_hosts(hosts):
308
with_ports = ['{}:{}'.format(host, registry_port_rpc) for host in hosts]
309
hosts = ','.join(with_ports)
310
success = 0 is update_config_file('registry', hosts, r'/etc/quobyte/host.cfg')
311
return success, hosts
314
# -- quobyte-system -----------------------------
317
def update_volume_config(key, new_value, configuration_name='BASE'):
318
current_file = NamedTemporaryFile()
319
new_file = NamedTemporaryFile()
320
success, output = call(['qmgmt', 'volume', 'config', 'export', configuration_name, current_file.name])
322
log('Error:\n{}'.format(output), ERROR)
323
for line in current_file:
324
if line.find(':') >= 0:
325
current_key, value = line.split(':')
326
if key == current_key.strip():
327
new_file.write('{}: {}\n'.format(key, new_value))
334
success, output = call(['qmgmt', 'volume', 'config', 'import', configuration_name, new_file.name])
336
log('Error:\n{}'.format(output), ERROR)
340
def fetch_registry_replica_devices(ip_api_service):
341
registered_devices = []
342
# cmd = ['qmgmt', '--force', '-u',
343
cmd = ['qmgmt', '-u',
344
'http://{}:{}'.format(ip_api_service, api_port_rpc),
346
success, result = call(cmd)
349
if line.strip().isdigit():
350
registered_devices.append(line.strip())
351
return True, registered_devices
357
def add_registry_replica(device_id, ip_api_service):
358
# cmd = ['qmgmt', '--force', '-u',
359
cmd = ['qmgmt', '-u',
360
'http://{}:{}'.format(ip_api_service, api_port_rpc),
361
'registry', 'add', '{}'.format(device_id)]
362
success, result = call(cmd)
370
def fetch_devices(ip_api_service, service_type=None):
372
# cmd = ['qmgmt', '--force', '-u',
373
cmd = ['qmgmt', '-u',
374
'http://{}:{}'.format(ip_api_service, api_port_rpc),
376
success, result = call(cmd)
380
if (token[0].isdigit() and
381
(service_type is token[-1] or service_type is None)):
382
devices.append(token[0])
389
def get_device_id(mount_point):
391
with open(os.path.join(mount_point, 'QUOBYTE_DEV_ID'), 'r') as fd:
393
if line.strip().startswith('device.id'):
394
return line.split('=')[-1].strip()
396
log('failed to get quobyte device id from {}: {}'.format(mount_point, e))