Sync with alternatives charmhelpers, installed ceph.conf as alternative for charm co-existence
This commit is contained in:
parent
f7a4e786ed
commit
2b75b70758
|
@ -1,7 +1,8 @@
|
||||||
branch: lp:charm-helpers
|
branch: lp:~openstack-charmers/charm-helpers/os-alternatives
|
||||||
destination: hooks/charmhelpers
|
destination: hooks/charmhelpers
|
||||||
include:
|
include:
|
||||||
- core
|
- core
|
||||||
- fetch
|
- fetch
|
||||||
- contrib.storage.linux:
|
- contrib.storage.linux:
|
||||||
- utils
|
- utils
|
||||||
|
- contrib.openstack.alternatives
|
||||||
|
|
|
@ -143,6 +143,11 @@ def remote_unit():
|
||||||
return os.environ['JUJU_REMOTE_UNIT']
|
return os.environ['JUJU_REMOTE_UNIT']
|
||||||
|
|
||||||
|
|
||||||
|
def service_name():
|
||||||
|
"The name service group this unit belongs to"
|
||||||
|
return local_unit().split('/')[0]
|
||||||
|
|
||||||
|
|
||||||
@cached
|
@cached
|
||||||
def config(scope=None):
|
def config(scope=None):
|
||||||
"Juju charm configuration"
|
"Juju charm configuration"
|
||||||
|
@ -192,7 +197,7 @@ def relation_ids(reltype=None):
|
||||||
relid_cmd_line = ['relation-ids', '--format=json']
|
relid_cmd_line = ['relation-ids', '--format=json']
|
||||||
if reltype is not None:
|
if reltype is not None:
|
||||||
relid_cmd_line.append(reltype)
|
relid_cmd_line.append(reltype)
|
||||||
return json.loads(subprocess.check_output(relid_cmd_line))
|
return json.loads(subprocess.check_output(relid_cmd_line)) or []
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
@ -203,7 +208,7 @@ def related_units(relid=None):
|
||||||
units_cmd_line = ['relation-list', '--format=json']
|
units_cmd_line = ['relation-list', '--format=json']
|
||||||
if relid is not None:
|
if relid is not None:
|
||||||
units_cmd_line.extend(('-r', relid))
|
units_cmd_line.extend(('-r', relid))
|
||||||
return json.loads(subprocess.check_output(units_cmd_line))
|
return json.loads(subprocess.check_output(units_cmd_line)) or []
|
||||||
|
|
||||||
|
|
||||||
@cached
|
@cached
|
||||||
|
@ -330,5 +335,6 @@ class Hooks(object):
|
||||||
return decorated
|
return decorated
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def charm_dir():
|
def charm_dir():
|
||||||
return os.environ.get('CHARM_DIR')
|
return os.environ.get('CHARM_DIR')
|
||||||
|
|
|
@ -5,33 +5,36 @@
|
||||||
# Nick Moffitt <nick.moffitt@canonical.com>
|
# Nick Moffitt <nick.moffitt@canonical.com>
|
||||||
# Matthew Wedgwood <matthew.wedgwood@canonical.com>
|
# Matthew Wedgwood <matthew.wedgwood@canonical.com>
|
||||||
|
|
||||||
import apt_pkg
|
|
||||||
import os
|
import os
|
||||||
import pwd
|
import pwd
|
||||||
import grp
|
import grp
|
||||||
|
import random
|
||||||
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from hookenv import log, execution_environment
|
from hookenv import log
|
||||||
|
|
||||||
|
|
||||||
def service_start(service_name):
|
def service_start(service_name):
|
||||||
service('start', service_name)
|
return service('start', service_name)
|
||||||
|
|
||||||
|
|
||||||
def service_stop(service_name):
|
def service_stop(service_name):
|
||||||
service('stop', service_name)
|
return service('stop', service_name)
|
||||||
|
|
||||||
|
|
||||||
def service_restart(service_name):
|
def service_restart(service_name):
|
||||||
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):
|
||||||
if not service('reload', service_name) and restart_on_failure:
|
service_result = service('reload', service_name)
|
||||||
service('restart', service_name)
|
if not service_result and restart_on_failure:
|
||||||
|
service_result = service('restart', service_name)
|
||||||
|
return service_result
|
||||||
|
|
||||||
|
|
||||||
def service(action, service_name):
|
def service(action, service_name):
|
||||||
|
@ -39,6 +42,18 @@ def service(action, service_name):
|
||||||
return subprocess.call(cmd) == 0
|
return subprocess.call(cmd) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def service_running(service):
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(['service', service, 'status'])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if ("start/running" in output or "is running" in output):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
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"""
|
||||||
try:
|
try:
|
||||||
|
@ -74,36 +89,33 @@ def add_user_to_group(username, group):
|
||||||
|
|
||||||
def rsync(from_path, to_path, flags='-r', options=None):
|
def rsync(from_path, to_path, flags='-r', options=None):
|
||||||
"""Replicate the contents of a path"""
|
"""Replicate the contents of a path"""
|
||||||
context = execution_environment()
|
|
||||||
options = options or ['--delete', '--executability']
|
options = options or ['--delete', '--executability']
|
||||||
cmd = ['/usr/bin/rsync', flags]
|
cmd = ['/usr/bin/rsync', flags]
|
||||||
cmd.extend(options)
|
cmd.extend(options)
|
||||||
cmd.append(from_path.format(**context))
|
cmd.append(from_path)
|
||||||
cmd.append(to_path.format(**context))
|
cmd.append(to_path)
|
||||||
log(" ".join(cmd))
|
log(" ".join(cmd))
|
||||||
return subprocess.check_output(cmd).strip()
|
return subprocess.check_output(cmd).strip()
|
||||||
|
|
||||||
|
|
||||||
def symlink(source, destination):
|
def symlink(source, destination):
|
||||||
"""Create a symbolic link"""
|
"""Create a symbolic link"""
|
||||||
context = execution_environment()
|
|
||||||
log("Symlinking {} as {}".format(source, destination))
|
log("Symlinking {} as {}".format(source, destination))
|
||||||
cmd = [
|
cmd = [
|
||||||
'ln',
|
'ln',
|
||||||
'-sf',
|
'-sf',
|
||||||
source.format(**context),
|
source,
|
||||||
destination.format(**context)
|
destination,
|
||||||
]
|
]
|
||||||
subprocess.check_call(cmd)
|
subprocess.check_call(cmd)
|
||||||
|
|
||||||
|
|
||||||
def mkdir(path, owner='root', group='root', perms=0555, force=False):
|
def mkdir(path, owner='root', group='root', perms=0555, force=False):
|
||||||
"""Create a directory"""
|
"""Create a directory"""
|
||||||
context = execution_environment()
|
|
||||||
log("Making dir {} {}:{} {:o}".format(path, owner, group,
|
log("Making dir {} {}:{} {:o}".format(path, owner, group,
|
||||||
perms))
|
perms))
|
||||||
uid = pwd.getpwnam(owner.format(**context)).pw_uid
|
uid = pwd.getpwnam(owner).pw_uid
|
||||||
gid = grp.getgrnam(group.format(**context)).gr_gid
|
gid = grp.getgrnam(group).gr_gid
|
||||||
realpath = os.path.abspath(path)
|
realpath = os.path.abspath(path)
|
||||||
if os.path.exists(realpath):
|
if os.path.exists(realpath):
|
||||||
if force and not os.path.isdir(realpath):
|
if force and not os.path.isdir(realpath):
|
||||||
|
@ -114,71 +126,15 @@ def mkdir(path, owner='root', group='root', perms=0555, force=False):
|
||||||
os.chown(realpath, uid, gid)
|
os.chown(realpath, uid, gid)
|
||||||
|
|
||||||
|
|
||||||
def write_file(path, fmtstr, owner='root', group='root', perms=0444, **kwargs):
|
def write_file(path, content, owner='root', group='root', perms=0444):
|
||||||
"""Create or overwrite a file with the contents of a string"""
|
"""Create or overwrite a file with the contents of a string"""
|
||||||
context = execution_environment()
|
log("Writing file {} {}:{} {:o}".format(path, owner, group, perms))
|
||||||
context.update(kwargs)
|
uid = pwd.getpwnam(owner).pw_uid
|
||||||
log("Writing file {} {}:{} {:o}".format(path, owner, group,
|
gid = grp.getgrnam(group).gr_gid
|
||||||
perms))
|
with open(path, 'w') as target:
|
||||||
uid = pwd.getpwnam(owner.format(**context)).pw_uid
|
|
||||||
gid = grp.getgrnam(group.format(**context)).gr_gid
|
|
||||||
with open(path.format(**context), 'w') as target:
|
|
||||||
os.fchown(target.fileno(), uid, gid)
|
os.fchown(target.fileno(), uid, gid)
|
||||||
os.fchmod(target.fileno(), perms)
|
os.fchmod(target.fileno(), perms)
|
||||||
target.write(fmtstr.format(**context))
|
target.write(content)
|
||||||
|
|
||||||
|
|
||||||
def render_template_file(source, destination, **kwargs):
|
|
||||||
"""Create or overwrite a file using a template"""
|
|
||||||
log("Rendering template {} for {}".format(source,
|
|
||||||
destination))
|
|
||||||
context = execution_environment()
|
|
||||||
with open(source.format(**context), 'r') as template:
|
|
||||||
write_file(destination.format(**context), template.read(),
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def filter_installed_packages(packages):
|
|
||||||
"""Returns a list of packages that require installation"""
|
|
||||||
apt_pkg.init()
|
|
||||||
cache = apt_pkg.Cache()
|
|
||||||
_pkgs = []
|
|
||||||
for package in packages:
|
|
||||||
try:
|
|
||||||
p = cache[package]
|
|
||||||
p.current_ver or _pkgs.append(package)
|
|
||||||
except KeyError:
|
|
||||||
log('Package {} has no installation candidate.'.format(package),
|
|
||||||
level='WARNING')
|
|
||||||
_pkgs.append(package)
|
|
||||||
return _pkgs
|
|
||||||
|
|
||||||
|
|
||||||
def apt_install(packages, options=None, fatal=False):
|
|
||||||
"""Install one or more packages"""
|
|
||||||
options = options or []
|
|
||||||
cmd = ['apt-get', '-y']
|
|
||||||
cmd.extend(options)
|
|
||||||
cmd.append('install')
|
|
||||||
if isinstance(packages, basestring):
|
|
||||||
cmd.append(packages)
|
|
||||||
else:
|
|
||||||
cmd.extend(packages)
|
|
||||||
log("Installing {} with options: {}".format(packages,
|
|
||||||
options))
|
|
||||||
if fatal:
|
|
||||||
subprocess.check_call(cmd)
|
|
||||||
else:
|
|
||||||
subprocess.call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def apt_update(fatal=False):
|
|
||||||
"""Update local apt cache"""
|
|
||||||
cmd = ['apt-get', 'update']
|
|
||||||
if fatal:
|
|
||||||
subprocess.check_call(cmd)
|
|
||||||
else:
|
|
||||||
subprocess.call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def mount(device, mountpoint, options=None, persist=False):
|
def mount(device, mountpoint, options=None, persist=False):
|
||||||
|
@ -271,3 +227,15 @@ def lsb_release():
|
||||||
k, v = l.split('=')
|
k, v = l.split('=')
|
||||||
d[k.strip()] = v.strip()
|
d[k.strip()] = v.strip()
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def pwgen(length=None):
|
||||||
|
'''Generate a random pasword.'''
|
||||||
|
if length is None:
|
||||||
|
length = random.choice(range(35, 45))
|
||||||
|
alphanumeric_chars = [
|
||||||
|
l for l in (string.letters + string.digits)
|
||||||
|
if l not in 'l0QD1vAEIOUaeiou']
|
||||||
|
random_chars = [
|
||||||
|
random.choice(alphanumeric_chars) for _ in range(length)]
|
||||||
|
return(''.join(random_chars))
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
import importlib
|
import importlib
|
||||||
from yaml import safe_load
|
from yaml import safe_load
|
||||||
from charmhelpers.core.host import (
|
from charmhelpers.core.host import (
|
||||||
apt_install,
|
|
||||||
apt_update,
|
|
||||||
filter_installed_packages,
|
|
||||||
lsb_release
|
lsb_release
|
||||||
)
|
)
|
||||||
from urlparse import (
|
from urlparse import (
|
||||||
|
@ -15,6 +12,7 @@ from charmhelpers.core.hookenv import (
|
||||||
config,
|
config,
|
||||||
log,
|
log,
|
||||||
)
|
)
|
||||||
|
import apt_pkg
|
||||||
|
|
||||||
CLOUD_ARCHIVE = """# Ubuntu Cloud Archive
|
CLOUD_ARCHIVE = """# Ubuntu Cloud Archive
|
||||||
deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
|
deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
|
||||||
|
@ -24,10 +22,67 @@ deb http://archive.ubuntu.com/ubuntu {}-proposed main universe multiverse restri
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def filter_installed_packages(packages):
|
||||||
|
"""Returns a list of packages that require installation"""
|
||||||
|
apt_pkg.init()
|
||||||
|
cache = apt_pkg.Cache()
|
||||||
|
_pkgs = []
|
||||||
|
for package in packages:
|
||||||
|
try:
|
||||||
|
p = cache[package]
|
||||||
|
p.current_ver or _pkgs.append(package)
|
||||||
|
except KeyError:
|
||||||
|
log('Package {} has no installation candidate.'.format(package),
|
||||||
|
level='WARNING')
|
||||||
|
_pkgs.append(package)
|
||||||
|
return _pkgs
|
||||||
|
|
||||||
|
|
||||||
|
def apt_install(packages, options=None, fatal=False):
|
||||||
|
"""Install one or more packages"""
|
||||||
|
options = options or []
|
||||||
|
cmd = ['apt-get', '-y']
|
||||||
|
cmd.extend(options)
|
||||||
|
cmd.append('install')
|
||||||
|
if isinstance(packages, basestring):
|
||||||
|
cmd.append(packages)
|
||||||
|
else:
|
||||||
|
cmd.extend(packages)
|
||||||
|
log("Installing {} with options: {}".format(packages,
|
||||||
|
options))
|
||||||
|
if fatal:
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
else:
|
||||||
|
subprocess.call(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def apt_update(fatal=False):
|
||||||
|
"""Update local apt cache"""
|
||||||
|
cmd = ['apt-get', 'update']
|
||||||
|
if fatal:
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
else:
|
||||||
|
subprocess.call(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def apt_purge(packages, fatal=False):
|
||||||
|
"""Purge one or more packages"""
|
||||||
|
cmd = ['apt-get', '-y', 'purge']
|
||||||
|
if isinstance(packages, basestring):
|
||||||
|
cmd.append(packages)
|
||||||
|
else:
|
||||||
|
cmd.extend(packages)
|
||||||
|
log("Purging {}".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:'))):
|
||||||
subprocess.check_call(['add-apt-repository', 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']),
|
||||||
fatal=True)
|
fatal=True)
|
||||||
|
@ -79,6 +134,7 @@ def configure_sources(update=False,
|
||||||
# least- to most-specific URL matching.
|
# least- to most-specific URL matching.
|
||||||
FETCH_HANDLERS = (
|
FETCH_HANDLERS = (
|
||||||
'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler',
|
'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler',
|
||||||
|
'charmhelpers.fetch.bzrurl.BzrUrlFetchHandler',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,6 +154,7 @@ def install_remote(source):
|
||||||
# We ONLY check for True here because can_handle may return a string
|
# We ONLY check for True here because can_handle may return a string
|
||||||
# explaining why it can't handle a given source.
|
# explaining why it can't handle a given source.
|
||||||
handlers = [h for h in plugins() if h.can_handle(source) is True]
|
handlers = [h for h in plugins() if h.can_handle(source) is True]
|
||||||
|
installed_to = None
|
||||||
for handler in handlers:
|
for handler in handlers:
|
||||||
try:
|
try:
|
||||||
installed_to = handler.install(source)
|
installed_to = handler.install(source)
|
||||||
|
|
|
@ -8,6 +8,7 @@ from charmhelpers.payload.archive import (
|
||||||
get_archive_handler,
|
get_archive_handler,
|
||||||
extract,
|
extract,
|
||||||
)
|
)
|
||||||
|
from charmhelpers.core.host import mkdir
|
||||||
|
|
||||||
|
|
||||||
class ArchiveUrlFetchHandler(BaseFetchHandler):
|
class ArchiveUrlFetchHandler(BaseFetchHandler):
|
||||||
|
@ -24,20 +25,24 @@ class ArchiveUrlFetchHandler(BaseFetchHandler):
|
||||||
# propogate all exceptions
|
# propogate all exceptions
|
||||||
# URLError, OSError, etc
|
# URLError, OSError, etc
|
||||||
response = urllib2.urlopen(source)
|
response = urllib2.urlopen(source)
|
||||||
with open(dest, 'w') as dest_file:
|
try:
|
||||||
dest_file.write(response.read())
|
with open(dest, 'w') as dest_file:
|
||||||
|
dest_file.write(response.read())
|
||||||
|
except Exception as e:
|
||||||
|
if os.path.isfile(dest):
|
||||||
|
os.unlink(dest)
|
||||||
|
raise e
|
||||||
|
|
||||||
def install(self, source):
|
def install(self, source):
|
||||||
url_parts = self.parse_url(source)
|
url_parts = self.parse_url(source)
|
||||||
dest_dir = os.path.join(os.environ.get('CHARM_DIR'), 'fetched')
|
dest_dir = os.path.join(os.environ.get('CHARM_DIR'), 'fetched')
|
||||||
|
if not os.path.exists(dest_dir):
|
||||||
|
mkdir(dest_dir, perms=0755)
|
||||||
dld_file = os.path.join(dest_dir, os.path.basename(url_parts.path))
|
dld_file = os.path.join(dest_dir, os.path.basename(url_parts.path))
|
||||||
try:
|
try:
|
||||||
self.download(source, dld_file)
|
self.download(source, dld_file)
|
||||||
except urllib2.URLError as e:
|
except urllib2.URLError as e:
|
||||||
return UnhandledSource(e.reason)
|
raise UnhandledSource(e.reason)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
return UnhandledSource(e.strerror)
|
raise UnhandledSource(e.strerror)
|
||||||
finally:
|
|
||||||
if os.path.isfile(dld_file):
|
|
||||||
os.unlink(dld_file)
|
|
||||||
return extract(dld_file)
|
return extract(dld_file)
|
||||||
|
|
|
@ -21,21 +21,27 @@ from charmhelpers.core.hookenv import (
|
||||||
related_units,
|
related_units,
|
||||||
relation_get,
|
relation_get,
|
||||||
Hooks,
|
Hooks,
|
||||||
UnregisteredHookError
|
UnregisteredHookError,
|
||||||
|
service_name
|
||||||
)
|
)
|
||||||
from charmhelpers.core.host import (
|
from charmhelpers.core.host import (
|
||||||
|
umount,
|
||||||
|
mkdir
|
||||||
|
)
|
||||||
|
from charmhelpers.fetch import (
|
||||||
|
add_source,
|
||||||
apt_install,
|
apt_install,
|
||||||
apt_update,
|
apt_update,
|
||||||
filter_installed_packages,
|
filter_installed_packages,
|
||||||
umount
|
|
||||||
)
|
)
|
||||||
from charmhelpers.fetch import add_source
|
|
||||||
|
|
||||||
from utils import (
|
from utils import (
|
||||||
render_template,
|
render_template,
|
||||||
get_host_ip,
|
get_host_ip,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from charmhelpers.contrib.openstack.alternatives import install_alternative
|
||||||
|
|
||||||
hooks = Hooks()
|
hooks = Hooks()
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,9 +72,14 @@ def emit_cephconf():
|
||||||
'fsid': get_fsid(),
|
'fsid': get_fsid(),
|
||||||
'version': ceph.get_ceph_version()
|
'version': ceph.get_ceph_version()
|
||||||
}
|
}
|
||||||
|
# Install ceph.conf as an alternative to support
|
||||||
with open('/etc/ceph/ceph.conf', 'w') as cephconf:
|
# co-existence with other charms that write this file
|
||||||
|
charm_ceph_conf = "/var/lib/charm/{}/ceph.conf".format(service_name())
|
||||||
|
mkdir(os.path.dirname(charm_ceph_conf))
|
||||||
|
with open(charm_ceph_conf, 'w') as cephconf:
|
||||||
cephconf.write(render_template('ceph.conf', cephcontext))
|
cephconf.write(render_template('ceph.conf', cephcontext))
|
||||||
|
install_alternative('ceph.conf', '/etc/ceph/ceph.conf',
|
||||||
|
charm_ceph_conf, 90)
|
||||||
|
|
||||||
JOURNAL_ZAPPED = '/var/lib/ceph/journal_zapped'
|
JOURNAL_ZAPPED = '/var/lib/ceph/journal_zapped'
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ from charmhelpers.core.hookenv import (
|
||||||
unit_get,
|
unit_get,
|
||||||
cached
|
cached
|
||||||
)
|
)
|
||||||
from charmhelpers.core.host import (
|
from charmhelpers.fetch import (
|
||||||
apt_install,
|
apt_install,
|
||||||
filter_installed_packages
|
filter_installed_packages
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue