Add action to list unmounted disks

This action is fairly simple in that it returns
a list of unmounted disks

This also includes a git-sync to pull in charms.ceph
changes.

Change-Id: I0daa514958799cf5899375335e8e9e684df27704
Closes-Bug: 1645481
This commit is contained in:
Chris MacNaughton 2016-11-09 08:29:37 -05:00 committed by chris
parent d045424c54
commit 2dfbb5fe47
9 changed files with 1523 additions and 13 deletions

View File

@ -35,4 +35,5 @@ replace-osd:
description: The replacement device to use. Example /dev/sdb.
required: [osd-number, replacement-device]
additionalProperties: false
list-disks:
description: List the unmounted disk on the specified unit

1
actions/list-disks Symbolic link
View File

@ -0,0 +1 @@
list_disks.py

35
actions/list_disks.py Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/python
#
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
List unmounted devices.
This script will get all block devices known by udev and check if they
are mounted so that we can give unmounted devices to the administrator.
"""
import sys
sys.path.append('hooks/')
sys.path.append('lib/')
from charmhelpers.core.hookenv import action_set
from ceph import unmounted_disks
if __name__ == '__main__':
action_set({
'disks': unmounted_disks()})

View File

@ -2,7 +2,7 @@
# Wrapper to deal with newer Ubuntu versions that don't have py2 installed
# by default.
declare -a DEPS=('apt' 'netaddr' 'netifaces' 'pip' 'yaml' 'dnspython')
declare -a DEPS=('apt' 'netaddr' 'netifaces' 'pip' 'yaml')
check_and_install() {
pkg="${1}-${2}"
@ -17,4 +17,5 @@ for dep in ${DEPS[@]}; do
check_and_install ${PYTHON} ${dep}
done
./hooks/install_deps
exec ./hooks/install.real

18
hooks/install_deps Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
# Wrapper to ensure that python dependencies are installed before we get into
# the python part of the hook execution
declare -a DEPS=('dnspython' 'pyudev')
check_and_install() {
pkg="${1}-${2}"
if ! dpkg -s ${pkg} 2>&1 > /dev/null; then
apt-get -y install ${pkg}
fi
}
PYTHON="python"
for dep in ${DEPS[@]}; do
check_and_install ${PYTHON} ${dep}
done

View File

@ -2,5 +2,5 @@
# Wrapper to ensure that old python bytecode isn't hanging around
# after we upgrade the charm with newer libraries
rm -rf **/*.pyc
./hooks/install_deps
exec ./hooks/upgrade-charm.real

View File

@ -23,6 +23,7 @@ import re
import sys
import errno
import shutil
import pyudev
from charmhelpers.core import hookenv
from charmhelpers.core.host import (
@ -50,13 +51,15 @@ from charmhelpers.contrib.storage.linux.utils import (
is_block_device,
zap_disk,
is_device_mounted)
from charmhelpers.contrib.openstack.utils import (
get_os_codename_install_source)
LEADER = 'leader'
PEON = 'peon'
QUORUM = [LEADER, PEON]
PACKAGES = ['ceph', 'gdisk', 'ntp', 'btrfs-tools', 'python-ceph',
'radosgw', 'xfsprogs']
'radosgw', 'xfsprogs', 'python-pyudev']
LinkSpeed = {
"BASE_10": 10,
@ -100,6 +103,23 @@ NETWORK_ADAPTER_SYSCTLS = {
}
def unmounted_disks():
"""List of unmounted block devices on the current host."""
disks = []
context = pyudev.Context()
for device in context.list_devices(DEVTYPE='disk'):
if device['SUBSYSTEM'] == 'block':
matched = False
for block_type in [u'dm', u'loop', u'ram', u'nbd']:
if block_type in device.device_node:
matched = True
if matched:
continue
disks.append(device.device_node)
log("Found disks: {}".format(disks))
return [disk for disk in disks if not is_device_mounted(disk)]
def save_sysctls(sysctl_dict, save_location):
"""
Persist the sysctls to the hard drive.
@ -949,7 +969,7 @@ def get_mds_bootstrap_key():
_default_caps = collections.OrderedDict([
('mon', ['allow rw']),
('mon', ['allow r']),
('osd', ['allow rwx']),
])
@ -1344,7 +1364,7 @@ def roll_monitor_cluster(new_version, upgrade_key):
version=new_version)
else:
# Check if the previous node has finished
status_set('blocked',
status_set('waiting',
'Waiting on {} to finish upgrading'.format(
mon_sorted_list[position - 1]))
wait_on_previous_node(upgrade_key=upgrade_key,
@ -1361,11 +1381,10 @@ def roll_monitor_cluster(new_version, upgrade_key):
status_set('blocked', 'failed to upgrade monitor')
def upgrade_monitor():
def upgrade_monitor(new_version):
current_version = get_version()
status_set("maintenance", "Upgrading monitor")
log("Current ceph version is {}".format(current_version))
new_version = config('release-version')
log("Upgrading to: {}".format(new_version))
try:
@ -1393,7 +1412,6 @@ def upgrade_monitor():
service_start('ceph-mon@{}'.format(mon_id))
else:
service_start('ceph-mon-all')
status_set("active", "")
except subprocess.CalledProcessError as err:
log("Stopping ceph and upgrading packages failed "
"with message: {}".format(err.message))
@ -1415,9 +1433,9 @@ def lock_and_roll(upgrade_key, service, my_name, version):
# This should be quick
if service == 'osd':
upgrade_osd()
upgrade_osd(version)
elif service == 'mon':
upgrade_monitor()
upgrade_monitor(version)
else:
log("Unknown service {}. Unable to upgrade".format(service),
level=ERROR)
@ -1541,11 +1559,10 @@ def roll_osd_cluster(new_version, upgrade_key):
status_set('blocked', 'failed to upgrade osd')
def upgrade_osd():
def upgrade_osd(new_version):
current_version = get_version()
status_set("maintenance", "Upgrading osd")
log("Current ceph version is {}".format(current_version))
new_version = config('release-version')
log("Upgrading to: {}".format(new_version))
try:
@ -1578,3 +1595,58 @@ def upgrade_osd():
"with message: {}".format(err.message))
status_set("blocked", "Upgrade to {} failed".format(new_version))
sys.exit(1)
def list_pools(service):
"""
This will list the current pools that Ceph has
:param service: String service id to run under
:return: list. Returns a list of the ceph pools. Raises CalledProcessError
if the subprocess fails to run.
"""
try:
pool_list = []
pools = subprocess.check_output(['rados', '--id', service, 'lspools'])
for pool in pools.splitlines():
pool_list.append(pool)
return pool_list
except subprocess.CalledProcessError as err:
log("rados lspools failed with error: {}".format(err.output))
raise
# A dict of valid ceph upgrade paths. Mapping is old -> new
UPGRADE_PATHS = {
'firefly': 'hammer',
'hammer': 'jewel',
}
# Map UCA codenames to ceph codenames
UCA_CODENAME_MAP = {
'icehouse': 'firefly',
'juno': 'firefly',
'kilo': 'hammer',
'liberty': 'hammer',
'mitaka': 'jewel',
}
def pretty_print_upgrade_paths():
'''Pretty print supported upgrade paths for ceph'''
lines = []
for key, value in UPGRADE_PATHS.iteritems():
lines.append("{} -> {}".format(key, value))
return lines
def resolve_ceph_version(source):
'''
Resolves a version of ceph based on source configuration
based on Ubuntu Cloud Archive pockets.
@param: source: source configuration option of charm
@returns: ceph release codename or None if not resolvable
'''
os_release = get_os_codename_install_source(source)
return UCA_CODENAME_MAP.get(os_release)

1381
lib/ceph/ceph_helpers.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,3 +10,4 @@ Jinja2>=2.6 # BSD License (3 clause)
six>=1.9.0
dnspython>=1.12.0
psutil>=1.1.1,<2.0.0
pyudev