Update charm-helpers-hooks.yaml and sync ch
Using the new version of the sync tool which removes the charmhelpers directory before syncing, run charm helpers sync to find any unexpected missing dependencies. Change-Id: I8feaef641fc9c22ed47529ce91b011db5694a6f7
This commit is contained in:
@@ -7,10 +7,10 @@ include:
|
|||||||
- fetch
|
- fetch
|
||||||
- contrib.openstack|inc=*
|
- contrib.openstack|inc=*
|
||||||
- contrib.hahelpers
|
- contrib.hahelpers
|
||||||
- contrib.storage.linux.ceph
|
- contrib.storage.linux
|
||||||
- payload
|
- payload
|
||||||
- contrib.network.ip
|
- contrib.network.ip
|
||||||
- contrib.python.packages
|
- contrib.python
|
||||||
- contrib.charmsupport
|
- contrib.charmsupport
|
||||||
- core.kernel
|
- core.kernel
|
||||||
- contrib.hardening|inc=*
|
- contrib.hardening|inc=*
|
||||||
|
@@ -88,14 +88,14 @@ class OpenStackAmuletUtils(AmuletUtils):
|
|||||||
validation_function = self.validate_v2_endpoint_data
|
validation_function = self.validate_v2_endpoint_data
|
||||||
xenial_queens = OPENSTACK_RELEASES_PAIRS.index('xenial_queens')
|
xenial_queens = OPENSTACK_RELEASES_PAIRS.index('xenial_queens')
|
||||||
if openstack_release and openstack_release >= xenial_queens:
|
if openstack_release and openstack_release >= xenial_queens:
|
||||||
validation_function = self.validate_v3_endpoint_data
|
validation_function = self.validate_v3_endpoint_data
|
||||||
expected = {
|
expected = {
|
||||||
'id': expected['id'],
|
'id': expected['id'],
|
||||||
'region': expected['region'],
|
'region': expected['region'],
|
||||||
'region_id': 'RegionOne',
|
'region_id': 'RegionOne',
|
||||||
'url': self.valid_url,
|
'url': self.valid_url,
|
||||||
'interface': self.not_null,
|
'interface': self.not_null,
|
||||||
'service_id': expected['service_id']}
|
'service_id': expected['service_id']}
|
||||||
return validation_function(endpoints, admin_port, internal_port,
|
return validation_function(endpoints, admin_port, internal_port,
|
||||||
public_port, expected)
|
public_port, expected)
|
||||||
|
|
||||||
|
@@ -1427,11 +1427,11 @@ class ZeroMQContext(OSContextGenerator):
|
|||||||
ctxt = {}
|
ctxt = {}
|
||||||
if is_relation_made('zeromq-configuration', 'host'):
|
if is_relation_made('zeromq-configuration', 'host'):
|
||||||
for rid in relation_ids('zeromq-configuration'):
|
for rid in relation_ids('zeromq-configuration'):
|
||||||
for unit in related_units(rid):
|
for unit in related_units(rid):
|
||||||
ctxt['zmq_nonce'] = relation_get('nonce', unit, rid)
|
ctxt['zmq_nonce'] = relation_get('nonce', unit, rid)
|
||||||
ctxt['zmq_host'] = relation_get('host', unit, rid)
|
ctxt['zmq_host'] = relation_get('host', unit, rid)
|
||||||
ctxt['zmq_redis_address'] = relation_get(
|
ctxt['zmq_redis_address'] = relation_get(
|
||||||
'zmq_redis_address', unit, rid)
|
'zmq_redis_address', unit, rid)
|
||||||
|
|
||||||
return ctxt
|
return ctxt
|
||||||
|
|
||||||
|
@@ -183,7 +183,7 @@ class OSConfigRenderer(object):
|
|||||||
/tmp/templates/grizzly/api-paste.ini
|
/tmp/templates/grizzly/api-paste.ini
|
||||||
/tmp/templates/havana/api-paste.ini
|
/tmp/templates/havana/api-paste.ini
|
||||||
|
|
||||||
Since it was registered with the grizzly release, it first seraches
|
Since it was registered with the grizzly release, it first searches
|
||||||
the grizzly directory for nova.conf, then the templates dir.
|
the grizzly directory for nova.conf, then the templates dir.
|
||||||
|
|
||||||
When writing api-paste.ini, it will find the template in the grizzly
|
When writing api-paste.ini, it will find the template in the grizzly
|
||||||
|
@@ -83,7 +83,8 @@ from charmhelpers.fetch import (
|
|||||||
add_source as fetch_add_source,
|
add_source as fetch_add_source,
|
||||||
SourceConfigError,
|
SourceConfigError,
|
||||||
GPGKeyError,
|
GPGKeyError,
|
||||||
get_upstream_version
|
get_upstream_version,
|
||||||
|
filter_missing_packages
|
||||||
)
|
)
|
||||||
|
|
||||||
from charmhelpers.fetch.snap import (
|
from charmhelpers.fetch.snap import (
|
||||||
@@ -309,6 +310,15 @@ def error_out(msg):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_installed_semantic_versioned_packages():
|
||||||
|
'''Get a list of installed packages which have OpenStack semantic versioning
|
||||||
|
|
||||||
|
:returns List of installed packages
|
||||||
|
:rtype: [pkg1, pkg2, ...]
|
||||||
|
'''
|
||||||
|
return filter_missing_packages(PACKAGE_CODENAMES.keys())
|
||||||
|
|
||||||
|
|
||||||
def get_os_codename_install_source(src):
|
def get_os_codename_install_source(src):
|
||||||
'''Derive OpenStack release codename from a given installation source.'''
|
'''Derive OpenStack release codename from a given installation source.'''
|
||||||
ubuntu_rel = lsb_release()['DISTRIB_CODENAME']
|
ubuntu_rel = lsb_release()['DISTRIB_CODENAME']
|
||||||
@@ -972,7 +982,9 @@ def _ows_check_charm_func(state, message, charm_func_with_configs):
|
|||||||
"""
|
"""
|
||||||
if charm_func_with_configs:
|
if charm_func_with_configs:
|
||||||
charm_state, charm_message = charm_func_with_configs()
|
charm_state, charm_message = charm_func_with_configs()
|
||||||
if charm_state != 'active' and charm_state != 'unknown':
|
if (charm_state != 'active' and
|
||||||
|
charm_state != 'unknown' and
|
||||||
|
charm_state is not None):
|
||||||
state = workload_state_compare(state, charm_state)
|
state = workload_state_compare(state, charm_state)
|
||||||
if message:
|
if message:
|
||||||
charm_message = charm_message.replace("Incomplete relations: ",
|
charm_message = charm_message.replace("Incomplete relations: ",
|
||||||
@@ -1241,7 +1253,7 @@ def remote_restart(rel_name, remote_service=None):
|
|||||||
|
|
||||||
|
|
||||||
def check_actually_paused(services=None, ports=None):
|
def check_actually_paused(services=None, ports=None):
|
||||||
"""Check that services listed in the services object and and ports
|
"""Check that services listed in the services object and ports
|
||||||
are actually closed (not listened to), to verify that the unit is
|
are actually closed (not listened to), to verify that the unit is
|
||||||
properly paused.
|
properly paused.
|
||||||
|
|
||||||
|
21
charmhelpers/contrib/python.py
Normal file
21
charmhelpers/contrib/python.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Copyright 2014-2019 Canonical Limited.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# deprecated aliases for backwards compatibility
|
||||||
|
from charmhelpers.fetch.python import debug # noqa
|
||||||
|
from charmhelpers.fetch.python import packages # noqa
|
||||||
|
from charmhelpers.fetch.python import rpdb # noqa
|
||||||
|
from charmhelpers.fetch.python import version # noqa
|
74
charmhelpers/contrib/storage/linux/bcache.py
Normal file
74
charmhelpers/contrib/storage/linux/bcache.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# Copyright 2017 Canonical Limited.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
|
from charmhelpers.core.hookenv import log
|
||||||
|
|
||||||
|
stats_intervals = ['stats_day', 'stats_five_minute',
|
||||||
|
'stats_hour', 'stats_total']
|
||||||
|
|
||||||
|
SYSFS = '/sys'
|
||||||
|
|
||||||
|
|
||||||
|
class Bcache(object):
|
||||||
|
"""Bcache behaviour
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, cachepath):
|
||||||
|
self.cachepath = cachepath
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fromdevice(cls, devname):
|
||||||
|
return cls('{}/block/{}/bcache'.format(SYSFS, devname))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.cachepath
|
||||||
|
|
||||||
|
def get_stats(self, interval):
|
||||||
|
"""Get cache stats
|
||||||
|
"""
|
||||||
|
intervaldir = 'stats_{}'.format(interval)
|
||||||
|
path = "{}/{}".format(self.cachepath, intervaldir)
|
||||||
|
out = dict()
|
||||||
|
for elem in os.listdir(path):
|
||||||
|
out[elem] = open('{}/{}'.format(path, elem)).read().strip()
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def get_bcache_fs():
|
||||||
|
"""Return all cache sets
|
||||||
|
"""
|
||||||
|
cachesetroot = "{}/fs/bcache".format(SYSFS)
|
||||||
|
try:
|
||||||
|
dirs = os.listdir(cachesetroot)
|
||||||
|
except OSError:
|
||||||
|
log("No bcache fs found")
|
||||||
|
return []
|
||||||
|
cacheset = set([Bcache('{}/{}'.format(cachesetroot, d)) for d in dirs if not d.startswith('register')])
|
||||||
|
return cacheset
|
||||||
|
|
||||||
|
|
||||||
|
def get_stats_action(cachespec, interval):
|
||||||
|
"""Action for getting bcache statistics for a given cachespec.
|
||||||
|
Cachespec can either be a device name, eg. 'sdb', which will retrieve
|
||||||
|
cache stats for the given device, or 'global', which will retrieve stats
|
||||||
|
for all cachesets
|
||||||
|
"""
|
||||||
|
if cachespec == 'global':
|
||||||
|
caches = get_bcache_fs()
|
||||||
|
else:
|
||||||
|
caches = [Bcache.fromdevice(cachespec)]
|
||||||
|
res = dict((c.cachepath, c.get_stats(interval)) for c in caches)
|
||||||
|
return json.dumps(res, indent=4, separators=(',', ': '))
|
@@ -1,12 +1,26 @@
|
|||||||
|
# Copyright 2014-2015 Canonical Limited.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from subprocess import (
|
from subprocess import (
|
||||||
check_call,
|
check_call,
|
||||||
check_output,
|
check_output,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
# loopback device helpers.
|
# loopback device helpers.
|
||||||
@@ -22,10 +36,12 @@ def loopback_devices():
|
|||||||
'''
|
'''
|
||||||
loopbacks = {}
|
loopbacks = {}
|
||||||
cmd = ['losetup', '-a']
|
cmd = ['losetup', '-a']
|
||||||
devs = [d.strip().split(' ') for d in
|
output = check_output(cmd)
|
||||||
check_output(cmd).splitlines() if d != '']
|
if six.PY3:
|
||||||
|
output = output.decode('utf-8')
|
||||||
|
devs = [d.strip().split(' ') for d in output.splitlines() if d != '']
|
||||||
for dev, _, f in devs:
|
for dev, _, f in devs:
|
||||||
loopbacks[dev.replace(':', '')] = re.search('\((\S+)\)', f).groups()[0]
|
loopbacks[dev.replace(':', '')] = re.search(r'\((\S+)\)', f).groups()[0]
|
||||||
return loopbacks
|
return loopbacks
|
||||||
|
|
||||||
|
|
||||||
@@ -37,7 +53,7 @@ def create_loopback(file_path):
|
|||||||
'''
|
'''
|
||||||
file_path = os.path.abspath(file_path)
|
file_path = os.path.abspath(file_path)
|
||||||
check_call(['losetup', '--find', file_path])
|
check_call(['losetup', '--find', file_path])
|
||||||
for d, f in loopback_devices().iteritems():
|
for d, f in six.iteritems(loopback_devices()):
|
||||||
if f == file_path:
|
if f == file_path:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@@ -51,7 +67,7 @@ def ensure_loopback_device(path, size):
|
|||||||
|
|
||||||
:returns: str: Full path to the ensured loopback device (eg, /dev/loop0)
|
:returns: str: Full path to the ensured loopback device (eg, /dev/loop0)
|
||||||
'''
|
'''
|
||||||
for d, f in loopback_devices().iteritems():
|
for d, f in six.iteritems(loopback_devices()):
|
||||||
if f == path:
|
if f == path:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@@ -60,3 +76,13 @@ def ensure_loopback_device(path, size):
|
|||||||
check_call(cmd)
|
check_call(cmd)
|
||||||
|
|
||||||
return create_loopback(path)
|
return create_loopback(path)
|
||||||
|
|
||||||
|
|
||||||
|
def is_mapped_loopback_device(device):
|
||||||
|
"""
|
||||||
|
Checks if a given device name is an existing/mapped loopback device.
|
||||||
|
:param device: str: Full path to the device (eg, /dev/loop1).
|
||||||
|
:returns: str: Path to the backing file if is a loopback device
|
||||||
|
empty string otherwise
|
||||||
|
"""
|
||||||
|
return loopback_devices().get(device, "")
|
||||||
|
@@ -1,3 +1,18 @@
|
|||||||
|
# Copyright 2014-2015 Canonical Limited.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import functools
|
||||||
from subprocess import (
|
from subprocess import (
|
||||||
CalledProcessError,
|
CalledProcessError,
|
||||||
check_call,
|
check_call,
|
||||||
@@ -12,7 +27,7 @@ from subprocess import (
|
|||||||
##################################################
|
##################################################
|
||||||
def deactivate_lvm_volume_group(block_device):
|
def deactivate_lvm_volume_group(block_device):
|
||||||
'''
|
'''
|
||||||
Deactivate any volume group associated with an LVM physical volume.
|
Deactivate any volume gruop associated with an LVM physical volume.
|
||||||
|
|
||||||
:param block_device: str: Full path to LVM physical volume
|
:param block_device: str: Full path to LVM physical volume
|
||||||
'''
|
'''
|
||||||
@@ -60,9 +75,10 @@ def list_lvm_volume_group(block_device):
|
|||||||
'''
|
'''
|
||||||
vg = None
|
vg = None
|
||||||
pvd = check_output(['pvdisplay', block_device]).splitlines()
|
pvd = check_output(['pvdisplay', block_device]).splitlines()
|
||||||
for l in pvd:
|
for lvm in pvd:
|
||||||
if l.strip().startswith('VG Name'):
|
lvm = lvm.decode('UTF-8')
|
||||||
vg = ' '.join(l.split()).split(' ').pop()
|
if lvm.strip().startswith('VG Name'):
|
||||||
|
vg = ' '.join(lvm.strip().split()[2:])
|
||||||
return vg
|
return vg
|
||||||
|
|
||||||
|
|
||||||
@@ -86,3 +102,81 @@ def create_lvm_volume_group(volume_group, block_device):
|
|||||||
:block_device: str: Full path of PV-initialized block device.
|
:block_device: str: Full path of PV-initialized block device.
|
||||||
'''
|
'''
|
||||||
check_call(['vgcreate', volume_group, block_device])
|
check_call(['vgcreate', volume_group, block_device])
|
||||||
|
|
||||||
|
|
||||||
|
def list_logical_volumes(select_criteria=None, path_mode=False):
|
||||||
|
'''
|
||||||
|
List logical volumes
|
||||||
|
|
||||||
|
:param select_criteria: str: Limit list to those volumes matching this
|
||||||
|
criteria (see 'lvs -S help' for more details)
|
||||||
|
:param path_mode: bool: return logical volume name in 'vg/lv' format, this
|
||||||
|
format is required for some commands like lvextend
|
||||||
|
:returns: [str]: List of logical volumes
|
||||||
|
'''
|
||||||
|
lv_diplay_attr = 'lv_name'
|
||||||
|
if path_mode:
|
||||||
|
# Parsing output logic relies on the column order
|
||||||
|
lv_diplay_attr = 'vg_name,' + lv_diplay_attr
|
||||||
|
cmd = ['lvs', '--options', lv_diplay_attr, '--noheadings']
|
||||||
|
if select_criteria:
|
||||||
|
cmd.extend(['--select', select_criteria])
|
||||||
|
lvs = []
|
||||||
|
for lv in check_output(cmd).decode('UTF-8').splitlines():
|
||||||
|
if not lv:
|
||||||
|
continue
|
||||||
|
if path_mode:
|
||||||
|
lvs.append('/'.join(lv.strip().split()))
|
||||||
|
else:
|
||||||
|
lvs.append(lv.strip())
|
||||||
|
return lvs
|
||||||
|
|
||||||
|
|
||||||
|
list_thin_logical_volume_pools = functools.partial(
|
||||||
|
list_logical_volumes,
|
||||||
|
select_criteria='lv_attr =~ ^t')
|
||||||
|
|
||||||
|
list_thin_logical_volumes = functools.partial(
|
||||||
|
list_logical_volumes,
|
||||||
|
select_criteria='lv_attr =~ ^V')
|
||||||
|
|
||||||
|
|
||||||
|
def extend_logical_volume_by_device(lv_name, block_device):
|
||||||
|
'''
|
||||||
|
Extends the size of logical volume lv_name by the amount of free space on
|
||||||
|
physical volume block_device.
|
||||||
|
|
||||||
|
:param lv_name: str: name of logical volume to be extended (vg/lv format)
|
||||||
|
:param block_device: str: name of block_device to be allocated to lv_name
|
||||||
|
'''
|
||||||
|
cmd = ['lvextend', lv_name, block_device]
|
||||||
|
check_call(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def create_logical_volume(lv_name, volume_group, size=None):
|
||||||
|
'''
|
||||||
|
Create a new logical volume in an existing volume group
|
||||||
|
|
||||||
|
:param lv_name: str: name of logical volume to be created.
|
||||||
|
:param volume_group: str: Name of volume group to use for the new volume.
|
||||||
|
:param size: str: Size of logical volume to create (100% if not supplied)
|
||||||
|
:raises subprocess.CalledProcessError: in the event that the lvcreate fails.
|
||||||
|
'''
|
||||||
|
if size:
|
||||||
|
check_call([
|
||||||
|
'lvcreate',
|
||||||
|
'--yes',
|
||||||
|
'-L',
|
||||||
|
'{}'.format(size),
|
||||||
|
'-n', lv_name, volume_group
|
||||||
|
])
|
||||||
|
# create the lv with all the space available, this is needed because the
|
||||||
|
# system call is different for LVM
|
||||||
|
else:
|
||||||
|
check_call([
|
||||||
|
'lvcreate',
|
||||||
|
'--yes',
|
||||||
|
'-l',
|
||||||
|
'100%FREE',
|
||||||
|
'-n', lv_name, volume_group
|
||||||
|
])
|
||||||
|
@@ -1,8 +1,25 @@
|
|||||||
from os import stat
|
# Copyright 2014-2015 Canonical Limited.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
from stat import S_ISBLK
|
from stat import S_ISBLK
|
||||||
|
|
||||||
from subprocess import (
|
from subprocess import (
|
||||||
check_call
|
check_call,
|
||||||
|
check_output,
|
||||||
|
call
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -12,7 +29,9 @@ def is_block_device(path):
|
|||||||
|
|
||||||
:returns: boolean: True if path is a block device, False if not.
|
:returns: boolean: True if path is a block device, False if not.
|
||||||
'''
|
'''
|
||||||
return S_ISBLK(stat(path).st_mode)
|
if not os.path.exists(path):
|
||||||
|
return False
|
||||||
|
return S_ISBLK(os.stat(path).st_mode)
|
||||||
|
|
||||||
|
|
||||||
def zap_disk(block_device):
|
def zap_disk(block_device):
|
||||||
@@ -22,4 +41,45 @@ def zap_disk(block_device):
|
|||||||
|
|
||||||
:param block_device: str: Full path of block device to clean.
|
:param block_device: str: Full path of block device to clean.
|
||||||
'''
|
'''
|
||||||
check_call(['sgdisk', '--zap-all', block_device])
|
# https://github.com/ceph/ceph/commit/fdd7f8d83afa25c4e09aaedd90ab93f3b64a677b
|
||||||
|
# sometimes sgdisk exits non-zero; this is OK, dd will clean up
|
||||||
|
call(['sgdisk', '--zap-all', '--', block_device])
|
||||||
|
call(['sgdisk', '--clear', '--mbrtogpt', '--', block_device])
|
||||||
|
dev_end = check_output(['blockdev', '--getsz',
|
||||||
|
block_device]).decode('UTF-8')
|
||||||
|
gpt_end = int(dev_end.split()[0]) - 100
|
||||||
|
check_call(['dd', 'if=/dev/zero', 'of=%s' % (block_device),
|
||||||
|
'bs=1M', 'count=1'])
|
||||||
|
check_call(['dd', 'if=/dev/zero', 'of=%s' % (block_device),
|
||||||
|
'bs=512', 'count=100', 'seek=%s' % (gpt_end)])
|
||||||
|
|
||||||
|
|
||||||
|
def is_device_mounted(device):
|
||||||
|
'''Given a device path, return True if that device is mounted, and False
|
||||||
|
if it isn't.
|
||||||
|
|
||||||
|
:param device: str: Full path of the device to check.
|
||||||
|
:returns: boolean: True if the path represents a mounted device, False if
|
||||||
|
it doesn't.
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
out = check_output(['lsblk', '-P', device]).decode('UTF-8')
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return bool(re.search(r'MOUNTPOINT=".+"', out))
|
||||||
|
|
||||||
|
|
||||||
|
def mkfs_xfs(device, force=False):
|
||||||
|
"""Format device with XFS filesystem.
|
||||||
|
|
||||||
|
By default this should fail if the device already has a filesystem on it.
|
||||||
|
:param device: Full path to device to format
|
||||||
|
:ptype device: tr
|
||||||
|
:param force: Force operation
|
||||||
|
:ptype: force: boolean"""
|
||||||
|
cmd = ['mkfs.xfs']
|
||||||
|
if force:
|
||||||
|
cmd.append("-f")
|
||||||
|
|
||||||
|
cmd += ['-i', 'size=1024', device]
|
||||||
|
check_call(cmd)
|
||||||
|
@@ -46,6 +46,7 @@ if __platform__ == "ubuntu":
|
|||||||
lsb_release,
|
lsb_release,
|
||||||
cmp_pkgrevno,
|
cmp_pkgrevno,
|
||||||
CompareHostReleases,
|
CompareHostReleases,
|
||||||
|
get_distrib_codename,
|
||||||
) # flake8: noqa -- ignore F401 for this import
|
) # flake8: noqa -- ignore F401 for this import
|
||||||
elif __platform__ == "centos":
|
elif __platform__ == "centos":
|
||||||
from charmhelpers.core.host_factory.centos import ( # NOQA:F401
|
from charmhelpers.core.host_factory.centos import ( # NOQA:F401
|
||||||
|
@@ -72,6 +72,14 @@ def lsb_release():
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def get_distrib_codename():
|
||||||
|
"""Return the codename of the distribution
|
||||||
|
:returns: The codename
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
return lsb_release()['DISTRIB_CODENAME'].lower()
|
||||||
|
|
||||||
|
|
||||||
def cmp_pkgrevno(package, revno, pkgcache=None):
|
def cmp_pkgrevno(package, revno, pkgcache=None):
|
||||||
"""Compare supplied revno with the revno of the installed package.
|
"""Compare supplied revno with the revno of the installed package.
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2014-2015 Canonical Limited.
|
# Copyright 2014-2019 Canonical Limited.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
54
charmhelpers/fetch/python/debug.py
Normal file
54
charmhelpers/fetch/python/debug.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# Copyright 2014-2015 Canonical Limited.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import atexit
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from charmhelpers.fetch.python.rpdb import Rpdb
|
||||||
|
from charmhelpers.core.hookenv import (
|
||||||
|
open_port,
|
||||||
|
close_port,
|
||||||
|
ERROR,
|
||||||
|
log
|
||||||
|
)
|
||||||
|
|
||||||
|
__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
|
||||||
|
|
||||||
|
DEFAULT_ADDR = "0.0.0.0"
|
||||||
|
DEFAULT_PORT = 4444
|
||||||
|
|
||||||
|
|
||||||
|
def _error(message):
|
||||||
|
log(message, level=ERROR)
|
||||||
|
|
||||||
|
|
||||||
|
def set_trace(addr=DEFAULT_ADDR, port=DEFAULT_PORT):
|
||||||
|
"""
|
||||||
|
Set a trace point using the remote debugger
|
||||||
|
"""
|
||||||
|
atexit.register(close_port, port)
|
||||||
|
try:
|
||||||
|
log("Starting a remote python debugger session on %s:%s" % (addr,
|
||||||
|
port))
|
||||||
|
open_port(port)
|
||||||
|
debugger = Rpdb(addr=addr, port=port)
|
||||||
|
debugger.set_trace(sys._getframe().f_back)
|
||||||
|
except Exception:
|
||||||
|
_error("Cannot start a remote debug session on %s:%s" % (addr,
|
||||||
|
port))
|
56
charmhelpers/fetch/python/rpdb.py
Normal file
56
charmhelpers/fetch/python/rpdb.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Copyright 2014-2015 Canonical Limited.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""Remote Python Debugger (pdb wrapper)."""
|
||||||
|
|
||||||
|
import pdb
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
|
||||||
|
__author__ = "Bertrand Janin <b@janin.com>"
|
||||||
|
__version__ = "0.1.3"
|
||||||
|
|
||||||
|
|
||||||
|
class Rpdb(pdb.Pdb):
|
||||||
|
|
||||||
|
def __init__(self, addr="127.0.0.1", port=4444):
|
||||||
|
"""Initialize the socket and initialize pdb."""
|
||||||
|
|
||||||
|
# Backup stdin and stdout before replacing them by the socket handle
|
||||||
|
self.old_stdout = sys.stdout
|
||||||
|
self.old_stdin = sys.stdin
|
||||||
|
|
||||||
|
# Open a 'reusable' socket to let the webapp reload on the same port
|
||||||
|
self.skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
|
||||||
|
self.skt.bind((addr, port))
|
||||||
|
self.skt.listen(1)
|
||||||
|
(clientsocket, address) = self.skt.accept()
|
||||||
|
handle = clientsocket.makefile('rw')
|
||||||
|
pdb.Pdb.__init__(self, completekey='tab', stdin=handle, stdout=handle)
|
||||||
|
sys.stdout = sys.stdin = handle
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
"""Revert stdin and stdout, close the socket."""
|
||||||
|
sys.stdout = self.old_stdout
|
||||||
|
sys.stdin = self.old_stdin
|
||||||
|
self.skt.close()
|
||||||
|
self.set_continue()
|
||||||
|
|
||||||
|
def do_continue(self, arg):
|
||||||
|
"""Stop all operation on ``continue``."""
|
||||||
|
self.shutdown()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
do_EOF = do_quit = do_exit = do_c = do_cont = do_continue
|
32
charmhelpers/fetch/python/version.py
Normal file
32
charmhelpers/fetch/python/version.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# Copyright 2014-2015 Canonical Limited.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
|
||||||
|
|
||||||
|
|
||||||
|
def current_version():
|
||||||
|
"""Current system python version"""
|
||||||
|
return sys.version_info
|
||||||
|
|
||||||
|
|
||||||
|
def current_version_string():
|
||||||
|
"""Current system python version as string major.minor.micro"""
|
||||||
|
return "{0}.{1}.{2}".format(sys.version_info.major,
|
||||||
|
sys.version_info.minor,
|
||||||
|
sys.version_info.micro)
|
Reference in New Issue
Block a user