Fix alphanumeric comparisons for openstack and ubuntu releases
- sync charmhelpers with fix-alpha helpers - fix up code where the alpha comparisons are done Change-Id: I10e3e689aba490118b84b6b9e58df1ba5632d07d Related-Bug: #1659575
This commit is contained in:
parent
8a3d1ad2d0
commit
72060b6ee7
@ -4,3 +4,4 @@ include:
|
||||
- contrib.amulet
|
||||
- contrib.openstack.amulet
|
||||
- core
|
||||
- osplatform
|
||||
|
@ -15,19 +15,23 @@ import sys
|
||||
from charmhelpers.contrib.storage.linux.utils import (
|
||||
is_block_device,
|
||||
zap_disk,
|
||||
is_device_mounted)
|
||||
is_device_mounted,
|
||||
)
|
||||
from charmhelpers.core.host import (
|
||||
mkdir,
|
||||
chownr,
|
||||
service_restart,
|
||||
lsb_release,
|
||||
cmp_pkgrevno)
|
||||
cmp_pkgrevno,
|
||||
CompareHostReleases,
|
||||
)
|
||||
from charmhelpers.core.hookenv import (
|
||||
log,
|
||||
ERROR,
|
||||
cached,
|
||||
status_set,
|
||||
WARNING)
|
||||
WARNING,
|
||||
)
|
||||
from charmhelpers.fetch import (
|
||||
apt_cache
|
||||
)
|
||||
@ -403,7 +407,7 @@ def upgrade_key_caps(key, caps):
|
||||
|
||||
@cached
|
||||
def systemd():
|
||||
return (lsb_release()['DISTRIB_CODENAME'] >= 'vivid')
|
||||
return CompareHostReleases(lsb_release()['DISTRIB_CODENAME']) >= 'vivid'
|
||||
|
||||
|
||||
def bootstrap_monitor_cluster(secret):
|
||||
|
@ -26,6 +26,7 @@ from charmhelpers.contrib.hardening.audits.file import (
|
||||
DirectoryPermissionAudit,
|
||||
NoReadWriteForOther,
|
||||
TemplatedFile,
|
||||
DeletedFile
|
||||
)
|
||||
from charmhelpers.contrib.hardening.audits.apache import DisabledModuleAudit
|
||||
from charmhelpers.contrib.hardening.apache import TEMPLATES_DIR
|
||||
@ -52,13 +53,13 @@ def get_audits():
|
||||
'mods-available/alias.conf'),
|
||||
context,
|
||||
TEMPLATES_DIR,
|
||||
mode=0o0755,
|
||||
mode=0o0640,
|
||||
user='root',
|
||||
service_actions=[{'service': 'apache2',
|
||||
'actions': ['restart']}]),
|
||||
|
||||
TemplatedFile(os.path.join(settings['common']['apache_dir'],
|
||||
'conf-enabled/hardening.conf'),
|
||||
'conf-enabled/99-hardening.conf'),
|
||||
context,
|
||||
TEMPLATES_DIR,
|
||||
mode=0o0640,
|
||||
@ -69,11 +70,13 @@ def get_audits():
|
||||
DirectoryPermissionAudit(settings['common']['apache_dir'],
|
||||
user='root',
|
||||
group='root',
|
||||
mode=0o640),
|
||||
mode=0o0750),
|
||||
|
||||
DisabledModuleAudit(settings['hardening']['modules_to_disable']),
|
||||
|
||||
NoReadWriteForOther(settings['common']['apache_dir']),
|
||||
|
||||
DeletedFile(['/var/www/html/index.html'])
|
||||
]
|
||||
|
||||
return audits
|
||||
@ -94,5 +97,4 @@ class ApacheConfContext(object):
|
||||
ctxt['apache_version'] = re.search(r'.+version: Apache/(.+?)\s.+',
|
||||
out).group(1)
|
||||
ctxt['apache_icondir'] = '/usr/share/apache2/icons/'
|
||||
ctxt['traceenable'] = settings['hardening']['traceenable']
|
||||
return ctxt
|
||||
|
@ -4,15 +4,29 @@
|
||||
###############################################################################
|
||||
|
||||
<Location / >
|
||||
<LimitExcept {{ allowed_http_methods }} >
|
||||
<LimitExcept {{ allowed_http_methods }} >
|
||||
# http://httpd.apache.org/docs/2.4/upgrading.html
|
||||
{% if apache_version > '2.2' -%}
|
||||
Require all granted
|
||||
{% else -%}
|
||||
Order Allow,Deny
|
||||
Deny from all
|
||||
Order Allow,Deny
|
||||
Deny from all
|
||||
{% endif %}
|
||||
</LimitExcept>
|
||||
</Location>
|
||||
|
||||
<Directory />
|
||||
Options -Indexes -FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
|
||||
<Directory /var/www/>
|
||||
Options -Indexes -FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
|
||||
TraceEnable {{ traceenable }}
|
||||
ServerTokens {{ servertokens }}
|
||||
|
||||
SSLHonorCipherOrder {{ honor_cipher_order }}
|
||||
SSLCipherSuite {{ cipher_suite }}
|
@ -49,13 +49,6 @@ class BaseAudit(object): # NO-QA
|
||||
|
||||
# Invoke the callback if there is one.
|
||||
if hasattr(self.unless, '__call__'):
|
||||
results = self.unless()
|
||||
if results:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
return not self.unless()
|
||||
|
||||
if self.unless:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
return not self.unless
|
||||
|
@ -10,4 +10,7 @@ common:
|
||||
hardening:
|
||||
traceenable: 'off'
|
||||
allowed_http_methods: "GET POST"
|
||||
modules_to_disable: [ cgi, cgid ]
|
||||
modules_to_disable: [ cgi, cgid ]
|
||||
servertokens: 'Prod'
|
||||
honor_cipher_order: 'on'
|
||||
cipher_suite: 'ALL:+MEDIUM:+HIGH:!LOW:!MD5:!RC4:!eNULL:!aNULL:!3DES'
|
||||
|
@ -7,3 +7,6 @@ common:
|
||||
hardening:
|
||||
allowed_http_methods:
|
||||
modules_to_disable:
|
||||
servertokens:
|
||||
honor_cipher_order:
|
||||
cipher_suite:
|
||||
|
@ -58,6 +58,7 @@ security:
|
||||
rsync
|
||||
kernel_enable_module_loading: True # (type:boolean)
|
||||
kernel_enable_core_dump: False # (type:boolean)
|
||||
ssh_tmout: 300
|
||||
|
||||
sysctl:
|
||||
kernel_secure_sysrq: 244 # 4 + 16 + 32 + 64 + 128
|
||||
|
@ -34,6 +34,7 @@ security:
|
||||
packages_list:
|
||||
kernel_enable_module_loading:
|
||||
kernel_enable_core_dump:
|
||||
ssh_tmout:
|
||||
sysctl:
|
||||
kernel_secure_sysrq:
|
||||
kernel_enable_sysrq:
|
||||
|
@ -25,7 +25,6 @@ def get_audits():
|
||||
audits = []
|
||||
|
||||
settings = utils.get_settings('os')
|
||||
|
||||
# If core dumps are not enabled, then don't allow core dumps to be
|
||||
# created as they may contain sensitive information.
|
||||
if not settings['security']['kernel_enable_core_dump']:
|
||||
@ -33,11 +32,18 @@ def get_audits():
|
||||
ProfileContext(),
|
||||
template_dir=TEMPLATES_DIR,
|
||||
mode=0o0755, user='root', group='root'))
|
||||
if settings['security']['ssh_tmout']:
|
||||
audits.append(TemplatedFile('/etc/profile.d/99-hardening.sh',
|
||||
ProfileContext(),
|
||||
template_dir=TEMPLATES_DIR,
|
||||
mode=0o0644, user='root', group='root'))
|
||||
return audits
|
||||
|
||||
|
||||
class ProfileContext(object):
|
||||
|
||||
def __call__(self):
|
||||
ctxt = {}
|
||||
settings = utils.get_settings('os')
|
||||
ctxt = {'ssh_tmout':
|
||||
settings['security']['ssh_tmout']}
|
||||
return ctxt
|
||||
|
@ -0,0 +1,5 @@
|
||||
TMOUT={{ tmout }}
|
||||
readonly TMOUT
|
||||
export TMOUT
|
||||
|
||||
readonly HISTFILE
|
@ -27,7 +27,10 @@ from charmhelpers.fetch import (
|
||||
apt_install,
|
||||
apt_update,
|
||||
)
|
||||
from charmhelpers.core.host import lsb_release
|
||||
from charmhelpers.core.host import (
|
||||
lsb_release,
|
||||
CompareHostReleases,
|
||||
)
|
||||
from charmhelpers.contrib.hardening.audits.file import (
|
||||
TemplatedFile,
|
||||
FileContentAudit,
|
||||
@ -68,7 +71,8 @@ class SSHConfigContext(object):
|
||||
'weak': default + ',hmac-sha1'}
|
||||
|
||||
# Use newer ciphers on Ubuntu Trusty and above
|
||||
if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
|
||||
_release = lsb_release()['DISTRIB_CODENAME'].lower()
|
||||
if CompareHostReleases(_release) >= 'trusty':
|
||||
log("Detected Ubuntu 14.04 or newer, using new macs", level=DEBUG)
|
||||
macs = macs_66
|
||||
|
||||
@ -96,7 +100,8 @@ class SSHConfigContext(object):
|
||||
'weak': weak}
|
||||
|
||||
# Use newer kex on Ubuntu Trusty and above
|
||||
if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
|
||||
_release = lsb_release()['DISTRIB_CODENAME'].lower()
|
||||
if CompareHostReleases(_release) >= 'trusty':
|
||||
log('Detected Ubuntu 14.04 or newer, using new key exchange '
|
||||
'algorithms', level=DEBUG)
|
||||
kex = kex_66
|
||||
@ -119,7 +124,8 @@ class SSHConfigContext(object):
|
||||
'weak': default + ',aes256-cbc,aes192-cbc,aes128-cbc'}
|
||||
|
||||
# Use newer ciphers on ubuntu Trusty and above
|
||||
if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
|
||||
_release = lsb_release()['DISTRIB_CODENAME'].lower()
|
||||
if CompareHostReleases(_release) >= 'trusty':
|
||||
log('Detected Ubuntu 14.04 or newer, using new ciphers',
|
||||
level=DEBUG)
|
||||
cipher = ciphers_66
|
||||
@ -291,7 +297,8 @@ class SSHConfigFileContentAudit(FileContentAudit):
|
||||
self.fail_cases = []
|
||||
settings = utils.get_settings('ssh')
|
||||
|
||||
if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
|
||||
_release = lsb_release()['DISTRIB_CODENAME'].lower()
|
||||
if CompareHostReleases(_release) >= 'trusty':
|
||||
if not settings['server']['weak_hmac']:
|
||||
self.pass_cases.append(r'^MACs.+,hmac-ripemd160$')
|
||||
else:
|
||||
@ -364,7 +371,8 @@ class SSHDConfigFileContentAudit(FileContentAudit):
|
||||
self.fail_cases = []
|
||||
settings = utils.get_settings('ssh')
|
||||
|
||||
if lsb_release()['DISTRIB_CODENAME'].lower() >= 'trusty':
|
||||
_release = lsb_release()['DISTRIB_CODENAME'].lower()
|
||||
if CompareHostReleases(_release) >= 'trusty':
|
||||
if not settings['server']['weak_hmac']:
|
||||
self.pass_cases.append(r'^MACs.+,hmac-ripemd160$')
|
||||
else:
|
||||
|
@ -31,6 +31,7 @@ from charmhelpers.core.hookenv import (
|
||||
|
||||
from charmhelpers.core.host import (
|
||||
lsb_release,
|
||||
CompareHostReleases,
|
||||
)
|
||||
|
||||
try:
|
||||
@ -67,6 +68,24 @@ def no_ip_found_error_out(network):
|
||||
raise ValueError(errmsg)
|
||||
|
||||
|
||||
def _get_ipv6_network_from_address(address):
|
||||
"""Get an netaddr.IPNetwork for the given IPv6 address
|
||||
:param address: a dict as returned by netifaces.ifaddresses
|
||||
:returns netaddr.IPNetwork: None if the address is a link local or loopback
|
||||
address
|
||||
"""
|
||||
if address['addr'].startswith('fe80') or address['addr'] == "::1":
|
||||
return None
|
||||
|
||||
prefix = address['netmask'].split("/")
|
||||
if len(prefix) > 1:
|
||||
netmask = prefix[1]
|
||||
else:
|
||||
netmask = address['netmask']
|
||||
return netaddr.IPNetwork("%s/%s" % (address['addr'],
|
||||
netmask))
|
||||
|
||||
|
||||
def get_address_in_network(network, fallback=None, fatal=False):
|
||||
"""Get an IPv4 or IPv6 address within the network from the host.
|
||||
|
||||
@ -100,11 +119,9 @@ def get_address_in_network(network, fallback=None, fatal=False):
|
||||
|
||||
if network.version == 6 and netifaces.AF_INET6 in addresses:
|
||||
for addr in addresses[netifaces.AF_INET6]:
|
||||
if not addr['addr'].startswith('fe80'):
|
||||
cidr = netaddr.IPNetwork("%s/%s" % (addr['addr'],
|
||||
addr['netmask']))
|
||||
if cidr in network:
|
||||
return str(cidr.ip)
|
||||
cidr = _get_ipv6_network_from_address(addr)
|
||||
if cidr and cidr in network:
|
||||
return str(cidr.ip)
|
||||
|
||||
if fallback is not None:
|
||||
return fallback
|
||||
@ -180,18 +197,18 @@ def _get_for_address(address, key):
|
||||
|
||||
if address.version == 6 and netifaces.AF_INET6 in addresses:
|
||||
for addr in addresses[netifaces.AF_INET6]:
|
||||
if not addr['addr'].startswith('fe80'):
|
||||
network = netaddr.IPNetwork("%s/%s" % (addr['addr'],
|
||||
addr['netmask']))
|
||||
cidr = network.cidr
|
||||
if address in cidr:
|
||||
if key == 'iface':
|
||||
return iface
|
||||
elif key == 'netmask' and cidr:
|
||||
return str(cidr).split('/')[1]
|
||||
else:
|
||||
return addr[key]
|
||||
network = _get_ipv6_network_from_address(addr)
|
||||
if not network:
|
||||
continue
|
||||
|
||||
cidr = network.cidr
|
||||
if address in cidr:
|
||||
if key == 'iface':
|
||||
return iface
|
||||
elif key == 'netmask' and cidr:
|
||||
return str(cidr).split('/')[1]
|
||||
else:
|
||||
return addr[key]
|
||||
return None
|
||||
|
||||
|
||||
@ -521,7 +538,8 @@ def port_has_listener(address, port):
|
||||
|
||||
def assert_charm_supports_ipv6():
|
||||
"""Check whether we are able to support charms ipv6."""
|
||||
if lsb_release()['DISTRIB_CODENAME'].lower() < "trusty":
|
||||
release = lsb_release()['DISTRIB_CODENAME'].lower()
|
||||
if CompareHostReleases(release) < "trusty":
|
||||
raise Exception("IPv6 is not supported in the charms for Ubuntu "
|
||||
"versions less than Trusty 14.04")
|
||||
|
||||
|
@ -33,9 +33,7 @@ import yaml
|
||||
|
||||
from charmhelpers.contrib.network import ip
|
||||
|
||||
from charmhelpers.core import (
|
||||
unitdata,
|
||||
)
|
||||
from charmhelpers.core import unitdata
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
action_fail,
|
||||
@ -55,6 +53,8 @@ from charmhelpers.core.hookenv import (
|
||||
application_version_set,
|
||||
)
|
||||
|
||||
from charmhelpers.core.strutils import BasicStringComparator
|
||||
|
||||
from charmhelpers.contrib.storage.linux.lvm import (
|
||||
deactivate_lvm_volume_group,
|
||||
is_lvm_physical_volume,
|
||||
@ -97,6 +97,22 @@ CLOUD_ARCHIVE_KEY_ID = '5EDB1B62EC4926EA'
|
||||
DISTRO_PROPOSED = ('deb http://archive.ubuntu.com/ubuntu/ %s-proposed '
|
||||
'restricted main multiverse universe')
|
||||
|
||||
OPENSTACK_RELEASES = (
|
||||
'diablo',
|
||||
'essex',
|
||||
'folsom',
|
||||
'grizzly',
|
||||
'havana',
|
||||
'icehouse',
|
||||
'juno',
|
||||
'kilo',
|
||||
'liberty',
|
||||
'mitaka',
|
||||
'newton',
|
||||
'ocata',
|
||||
'pike',
|
||||
)
|
||||
|
||||
UBUNTU_OPENSTACK_RELEASE = OrderedDict([
|
||||
('oneiric', 'diablo'),
|
||||
('precise', 'essex'),
|
||||
@ -238,6 +254,17 @@ GIT_DEFAULT_BRANCHES = {
|
||||
DEFAULT_LOOPBACK_SIZE = '5G'
|
||||
|
||||
|
||||
class CompareOpenStackReleases(BasicStringComparator):
|
||||
"""Provide comparisons of OpenStack releases.
|
||||
|
||||
Use in the form of
|
||||
|
||||
if CompareOpenStackReleases(release) > 'mitaka':
|
||||
# do something with mitaka
|
||||
"""
|
||||
_list = OPENSTACK_RELEASES
|
||||
|
||||
|
||||
def error_out(msg):
|
||||
juju_log("FATAL ERROR: %s" % msg, level='ERROR')
|
||||
sys.exit(1)
|
||||
@ -1066,7 +1093,8 @@ def git_generate_systemd_init_files(templates_dir):
|
||||
|
||||
shutil.copyfile(init_in_source, init_source)
|
||||
with open(init_source, 'a') as outfile:
|
||||
template = '/usr/share/openstack-pkg-tools/init-script-template'
|
||||
template = ('/usr/share/openstack-pkg-tools/'
|
||||
'init-script-template')
|
||||
with open(template) as infile:
|
||||
outfile.write('\n\n{}'.format(infile.read()))
|
||||
|
||||
@ -1971,9 +1999,7 @@ def enable_memcache(source=None, release=None, package=None):
|
||||
if not _release:
|
||||
_release = get_os_codename_install_source(source)
|
||||
|
||||
# TODO: this should be changed to a numeric comparison using a known list
|
||||
# of releases and comparing by index.
|
||||
return _release >= 'mitaka'
|
||||
return CompareOpenStackReleases(_release) >= 'mitaka'
|
||||
|
||||
|
||||
def token_cache_pkgs(source=None, release=None):
|
||||
|
@ -987,18 +987,20 @@ def ensure_ceph_storage(service, pool, rbd_img, sizemb, mount_point,
|
||||
service_start(svc)
|
||||
|
||||
|
||||
def ensure_ceph_keyring(service, user=None, group=None, relation='ceph'):
|
||||
def ensure_ceph_keyring(service, user=None, group=None,
|
||||
relation='ceph', key=None):
|
||||
"""Ensures a ceph keyring is created for a named service and optionally
|
||||
ensures user and group ownership.
|
||||
|
||||
Returns False if no ceph key is available in relation state.
|
||||
@returns boolean: Flag to indicate whether a key was successfully written
|
||||
to disk based on either relation data or a supplied key
|
||||
"""
|
||||
key = None
|
||||
for rid in relation_ids(relation):
|
||||
for unit in related_units(rid):
|
||||
key = relation_get('key', rid=rid, unit=unit)
|
||||
if key:
|
||||
break
|
||||
if not key:
|
||||
for rid in relation_ids(relation):
|
||||
for unit in related_units(rid):
|
||||
key = relation_get('key', rid=rid, unit=unit)
|
||||
if key:
|
||||
break
|
||||
|
||||
if not key:
|
||||
return False
|
||||
|
@ -45,6 +45,7 @@ if __platform__ == "ubuntu":
|
||||
add_new_group,
|
||||
lsb_release,
|
||||
cmp_pkgrevno,
|
||||
CompareHostReleases,
|
||||
) # flake8: noqa -- ignore F401 for this import
|
||||
elif __platform__ == "centos":
|
||||
from charmhelpers.core.host_factory.centos import (
|
||||
@ -52,6 +53,7 @@ elif __platform__ == "centos":
|
||||
add_new_group,
|
||||
lsb_release,
|
||||
cmp_pkgrevno,
|
||||
CompareHostReleases,
|
||||
) # flake8: noqa -- ignore F401 for this import
|
||||
|
||||
UPDATEDB_PATH = '/etc/updatedb.conf'
|
||||
|
@ -2,6 +2,22 @@ import subprocess
|
||||
import yum
|
||||
import os
|
||||
|
||||
from charmhelpers.core.strutils import BasicStringComparator
|
||||
|
||||
|
||||
class CompareHostReleases(BasicStringComparator):
|
||||
"""Provide comparisons of Host releases.
|
||||
|
||||
Use in the form of
|
||||
|
||||
if CompareHostReleases(release) > 'trusty':
|
||||
# do something with mitaka
|
||||
"""
|
||||
|
||||
def __init__(self, item):
|
||||
raise NotImplementedError(
|
||||
"CompareHostReleases() is not implemented for CentOS")
|
||||
|
||||
|
||||
def service_available(service_name):
|
||||
# """Determine whether a system service is available."""
|
||||
|
@ -1,5 +1,37 @@
|
||||
import subprocess
|
||||
|
||||
from charmhelpers.core.strutils import BasicStringComparator
|
||||
|
||||
|
||||
UBUNTU_RELEASES = (
|
||||
'lucid',
|
||||
'maverick',
|
||||
'natty',
|
||||
'oneiric',
|
||||
'precise',
|
||||
'quantal',
|
||||
'raring',
|
||||
'saucy',
|
||||
'trusty',
|
||||
'utopic',
|
||||
'vivid',
|
||||
'wily',
|
||||
'xenial',
|
||||
'yakkety',
|
||||
'zesty',
|
||||
)
|
||||
|
||||
|
||||
class CompareHostReleases(BasicStringComparator):
|
||||
"""Provide comparisons of Ubuntu releases.
|
||||
|
||||
Use in the form of
|
||||
|
||||
if CompareHostReleases(release) > 'trusty':
|
||||
# do something with mitaka
|
||||
"""
|
||||
_list = UBUNTU_RELEASES
|
||||
|
||||
|
||||
def service_available(service_name):
|
||||
"""Determine whether a system service is available"""
|
||||
|
@ -68,3 +68,56 @@ def bytes_from_string(value):
|
||||
msg = "Unable to interpret string value '%s' as bytes" % (value)
|
||||
raise ValueError(msg)
|
||||
return int(matches.group(1)) * (1024 ** BYTE_POWER[matches.group(2)])
|
||||
|
||||
|
||||
class BasicStringComparator(object):
|
||||
"""Provides a class that will compare strings from an iterator type object.
|
||||
Used to provide > and < comparisons on strings that may not necessarily be
|
||||
alphanumerically ordered. e.g. OpenStack or Ubuntu releases AFTER the
|
||||
z-wrap.
|
||||
"""
|
||||
|
||||
_list = None
|
||||
|
||||
def __init__(self, item):
|
||||
if self._list is None:
|
||||
raise Exception("Must define the _list in the class definition!")
|
||||
try:
|
||||
self.index = self._list.index(item)
|
||||
except Exception:
|
||||
raise KeyError("Item '{}' is not in list '{}'"
|
||||
.format(item, self._list))
|
||||
|
||||
def __eq__(self, other):
|
||||
assert isinstance(other, str) or isinstance(other, self.__class__)
|
||||
return self.index == self._list.index(other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __lt__(self, other):
|
||||
assert isinstance(other, str) or isinstance(other, self.__class__)
|
||||
return self.index < self._list.index(other)
|
||||
|
||||
def __ge__(self, other):
|
||||
return not self.__lt__(other)
|
||||
|
||||
def __gt__(self, other):
|
||||
assert isinstance(other, str) or isinstance(other, self.__class__)
|
||||
return self.index > self._list.index(other)
|
||||
|
||||
def __le__(self, other):
|
||||
return not self.__gt__(other)
|
||||
|
||||
def __str__(self):
|
||||
"""Always give back the item at the index so it can be used in
|
||||
comparisons like:
|
||||
|
||||
s_mitaka = CompareOpenStack('mitaka')
|
||||
s_newton = CompareOpenstack('newton')
|
||||
|
||||
assert s_newton > s_mitaka
|
||||
|
||||
@returns: <string>
|
||||
"""
|
||||
return self._list[self.index]
|
||||
|
@ -15,20 +15,22 @@ from charmhelpers.core.hookenv import (
|
||||
config,
|
||||
status_set,
|
||||
network_get_primary_address,
|
||||
log, DEBUG,
|
||||
log,
|
||||
DEBUG,
|
||||
)
|
||||
from charmhelpers.fetch import (
|
||||
apt_install,
|
||||
filter_installed_packages
|
||||
filter_installed_packages,
|
||||
)
|
||||
|
||||
from charmhelpers.core.host import (
|
||||
lsb_release
|
||||
lsb_release,
|
||||
CompareHostReleases,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.network.ip import (
|
||||
get_address_in_network,
|
||||
get_ipv6_addr
|
||||
get_ipv6_addr,
|
||||
)
|
||||
|
||||
try:
|
||||
@ -141,6 +143,7 @@ def get_network_addrs(config_opt):
|
||||
|
||||
def assert_charm_supports_ipv6():
|
||||
"""Check whether we are able to support charms ipv6."""
|
||||
if lsb_release()['DISTRIB_CODENAME'].lower() < "trusty":
|
||||
_release = lsb_release()['DISTRIB_CODENAME'].lower()
|
||||
if CompareHostReleases(_release) < "trusty":
|
||||
raise Exception("IPv6 is not supported in the charms for Ubuntu "
|
||||
"versions less than Trusty 14.04")
|
||||
|
@ -40,6 +40,7 @@ from charmhelpers.contrib.amulet.utils import (
|
||||
AmuletUtils
|
||||
)
|
||||
from charmhelpers.core.decorators import retry_on_exception
|
||||
from charmhelpers.core.host import CompareHostReleases
|
||||
|
||||
DEBUG = logging.DEBUG
|
||||
ERROR = logging.ERROR
|
||||
@ -1255,7 +1256,7 @@ class OpenStackAmuletUtils(AmuletUtils):
|
||||
contents = self.file_contents_safe(sentry_unit, '/etc/memcached.conf',
|
||||
fatal=True)
|
||||
ubuntu_release, _ = self.run_cmd_unit(sentry_unit, 'lsb_release -cs')
|
||||
if ubuntu_release <= 'trusty':
|
||||
if CompareHostReleases(ubuntu_release) <= 'trusty':
|
||||
memcache_listen_addr = 'ip6-localhost'
|
||||
else:
|
||||
memcache_listen_addr = '::1'
|
||||
|
@ -45,6 +45,7 @@ if __platform__ == "ubuntu":
|
||||
add_new_group,
|
||||
lsb_release,
|
||||
cmp_pkgrevno,
|
||||
CompareHostReleases,
|
||||
) # flake8: noqa -- ignore F401 for this import
|
||||
elif __platform__ == "centos":
|
||||
from charmhelpers.core.host_factory.centos import (
|
||||
@ -52,6 +53,7 @@ elif __platform__ == "centos":
|
||||
add_new_group,
|
||||
lsb_release,
|
||||
cmp_pkgrevno,
|
||||
CompareHostReleases,
|
||||
) # flake8: noqa -- ignore F401 for this import
|
||||
|
||||
UPDATEDB_PATH = '/etc/updatedb.conf'
|
||||
|
@ -2,6 +2,22 @@ import subprocess
|
||||
import yum
|
||||
import os
|
||||
|
||||
from charmhelpers.core.strutils import BasicStringComparator
|
||||
|
||||
|
||||
class CompareHostReleases(BasicStringComparator):
|
||||
"""Provide comparisons of Host releases.
|
||||
|
||||
Use in the form of
|
||||
|
||||
if CompareHostReleases(release) > 'trusty':
|
||||
# do something with mitaka
|
||||
"""
|
||||
|
||||
def __init__(self, item):
|
||||
raise NotImplementedError(
|
||||
"CompareHostReleases() is not implemented for CentOS")
|
||||
|
||||
|
||||
def service_available(service_name):
|
||||
# """Determine whether a system service is available."""
|
||||
|
@ -1,5 +1,37 @@
|
||||
import subprocess
|
||||
|
||||
from charmhelpers.core.strutils import BasicStringComparator
|
||||
|
||||
|
||||
UBUNTU_RELEASES = (
|
||||
'lucid',
|
||||
'maverick',
|
||||
'natty',
|
||||
'oneiric',
|
||||
'precise',
|
||||
'quantal',
|
||||
'raring',
|
||||
'saucy',
|
||||
'trusty',
|
||||
'utopic',
|
||||
'vivid',
|
||||
'wily',
|
||||
'xenial',
|
||||
'yakkety',
|
||||
'zesty',
|
||||
)
|
||||
|
||||
|
||||
class CompareHostReleases(BasicStringComparator):
|
||||
"""Provide comparisons of Ubuntu releases.
|
||||
|
||||
Use in the form of
|
||||
|
||||
if CompareHostReleases(release) > 'trusty':
|
||||
# do something with mitaka
|
||||
"""
|
||||
_list = UBUNTU_RELEASES
|
||||
|
||||
|
||||
def service_available(service_name):
|
||||
"""Determine whether a system service is available"""
|
||||
|
@ -68,3 +68,56 @@ def bytes_from_string(value):
|
||||
msg = "Unable to interpret string value '%s' as bytes" % (value)
|
||||
raise ValueError(msg)
|
||||
return int(matches.group(1)) * (1024 ** BYTE_POWER[matches.group(2)])
|
||||
|
||||
|
||||
class BasicStringComparator(object):
|
||||
"""Provides a class that will compare strings from an iterator type object.
|
||||
Used to provide > and < comparisons on strings that may not necessarily be
|
||||
alphanumerically ordered. e.g. OpenStack or Ubuntu releases AFTER the
|
||||
z-wrap.
|
||||
"""
|
||||
|
||||
_list = None
|
||||
|
||||
def __init__(self, item):
|
||||
if self._list is None:
|
||||
raise Exception("Must define the _list in the class definition!")
|
||||
try:
|
||||
self.index = self._list.index(item)
|
||||
except Exception:
|
||||
raise KeyError("Item '{}' is not in list '{}'"
|
||||
.format(item, self._list))
|
||||
|
||||
def __eq__(self, other):
|
||||
assert isinstance(other, str) or isinstance(other, self.__class__)
|
||||
return self.index == self._list.index(other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __lt__(self, other):
|
||||
assert isinstance(other, str) or isinstance(other, self.__class__)
|
||||
return self.index < self._list.index(other)
|
||||
|
||||
def __ge__(self, other):
|
||||
return not self.__lt__(other)
|
||||
|
||||
def __gt__(self, other):
|
||||
assert isinstance(other, str) or isinstance(other, self.__class__)
|
||||
return self.index > self._list.index(other)
|
||||
|
||||
def __le__(self, other):
|
||||
return not self.__gt__(other)
|
||||
|
||||
def __str__(self):
|
||||
"""Always give back the item at the index so it can be used in
|
||||
comparisons like:
|
||||
|
||||
s_mitaka = CompareOpenStack('mitaka')
|
||||
s_newton = CompareOpenstack('newton')
|
||||
|
||||
assert s_newton > s_mitaka
|
||||
|
||||
@returns: <string>
|
||||
"""
|
||||
return self._list[self.index]
|
||||
|
25
tests/charmhelpers/osplatform.py
Normal file
25
tests/charmhelpers/osplatform.py
Normal file
@ -0,0 +1,25 @@
|
||||
import platform
|
||||
|
||||
|
||||
def get_platform():
|
||||
"""Return the current OS platform.
|
||||
|
||||
For example: if current os platform is Ubuntu then a string "ubuntu"
|
||||
will be returned (which is the name of the module).
|
||||
This string is used to decide which platform module should be imported.
|
||||
"""
|
||||
# linux_distribution is deprecated and will be removed in Python 3.7
|
||||
# Warings *not* disabled, as we certainly need to fix this.
|
||||
tuple_platform = platform.linux_distribution()
|
||||
current_platform = tuple_platform[0]
|
||||
if "Ubuntu" in current_platform:
|
||||
return "ubuntu"
|
||||
elif "CentOS" in current_platform:
|
||||
return "centos"
|
||||
elif "debian" in current_platform:
|
||||
# Stock Python does not detect Ubuntu and instead returns debian.
|
||||
# Or at least it does in some build environments like Travis CI
|
||||
return "ubuntu"
|
||||
else:
|
||||
raise RuntimeError("This module is not supported on {}."
|
||||
.format(current_platform))
|
Loading…
x
Reference in New Issue
Block a user