Enable support for beast frontend

Introduce support for the beast web frontend for the Ceph
RADOS Gateway which brings improvements to speed and scalability.

Default behaviour is changed in that for Octopus and later
(aside from some unsupported architectures) beast is enabled by
default; for older releases civetweb is still used.

This may be overridden using the 'http-frontend' configuration
option which accepts either 'beast' or 'civetweb' as valid
values.  'beast' is only supported with Ceph Mimic or later.

Closes-Bug: 1865396
Change-Id: Ib73e58e21219eca611cd4293da69bf80040f5803
This commit is contained in:
James Page 2021-05-05 13:56:57 +01:00 committed by Aurelien Lourot
parent eccbd7e772
commit c634aba6fd
5 changed files with 148 additions and 4 deletions

View File

@ -509,3 +509,10 @@ options:
NOTE: X-Versions-Location is the only versioning-related header that
radosgw interprets. X-History-Location, supported by native OpenStack
Swift, is currently not supported by radosgw.
http-frontend:
type: string
default:
description: |
Frontend HTTP engine to use for the Ceph RADOS Gateway; For Octopus and
later this defaults to 'beast' and for older releases (and on architectures
where beast is not supported) 'civetweb'.

View File

@ -23,10 +23,14 @@ from charmhelpers.contrib.hahelpers.cluster import (
determine_api_port,
determine_apache_port,
)
from charmhelpers.core.host import cmp_pkgrevno
from charmhelpers.core.host import (
cmp_pkgrevno,
arch,
)
from charmhelpers.core.hookenv import (
DEBUG,
WARNING,
ERROR,
config,
log,
related_units,
@ -44,6 +48,12 @@ from charmhelpers.contrib.storage.linux.ceph import CephConfContext
import utils
BEAST_FRONTEND = 'beast'
CIVETWEB_FRONTEND = 'civetweb'
SUPPORTED_FRONTENDS = (BEAST_FRONTEND, CIVETWEB_FRONTEND)
UNSUPPORTED_BEAST_ARCHS = ('s390x', 'riscv64')
class ApacheSSLContext(context.ApacheSSLContext):
interfaces = ['https']
service_namespace = 'ceph-radosgw'
@ -142,6 +152,55 @@ def ensure_host_resolvable_v6(hostname):
shutil.rmtree(dtmp)
def resolve_http_frontend():
"""Automatically determine the HTTP frontend configuration
Determines the best HTTP frontend configuration based
on the Ceph release in use and the architecture of the
machine being used.
:returns http frontend configuration to use.
:rtype: str
"""
octopus_or_later = cmp_pkgrevno('radosgw', '15.2.0') >= 0
pacific_or_later = cmp_pkgrevno('radosgw', '16.2.0') >= 0
if octopus_or_later:
# Pacific or later supports beast on all architectures
# but octopus does not support s390x or riscv64
if not pacific_or_later and arch() in UNSUPPORTED_BEAST_ARCHS:
return CIVETWEB_FRONTEND
else:
return BEAST_FRONTEND
return CIVETWEB_FRONTEND
def validate_http_frontend(frontend_config):
"""Validate HTTP frontend configuration
:param frontend_config: user provided config value
:type: str
:raises: ValueError if the provided config is not valid
"""
mimic_or_later = cmp_pkgrevno('radosgw', '13.2.0') >= 0
pacific_or_later = cmp_pkgrevno('radosgw', '16.2.0') >= 0
if frontend_config not in SUPPORTED_FRONTENDS:
e = ('Please provide either civetweb or beast for '
'http-frontend configuration')
log(e, level=ERROR)
raise ValueError(e)
if frontend_config == BEAST_FRONTEND:
if not mimic_or_later:
e = ('Use of the beast HTTP frontend requires Ceph '
'mimic or later.')
log(e, level=ERROR)
raise ValueError(e)
if not pacific_or_later and arch() in UNSUPPORTED_BEAST_ARCHS:
e = ('Use of the beast HTTP frontend on {} requires Ceph '
'pacific or later.'.format(arch()))
log(e, level=ERROR)
raise ValueError(e)
class MonContext(context.CephContext):
interfaces = ['mon']
@ -191,6 +250,12 @@ class MonContext(context.CephContext):
if config('prefer-ipv6'):
port = "[::]:%s" % (port)
http_frontend = config('http-frontend')
if not http_frontend:
http_frontend = resolve_http_frontend()
else:
validate_http_frontend(http_frontend)
mon_hosts.sort()
ctxt = {
'auth_supported': auth,
@ -210,6 +275,7 @@ class MonContext(context.CephContext):
'unit_public_ip': unit_public_ip(),
'fsid': fsid,
'rgw_swift_versioning': config('rgw-swift-versioning-enabled'),
'frontend': http_frontend,
}
# NOTE(dosaboy): these sections must correspond to what is supported in

View File

@ -42,6 +42,7 @@ from charmhelpers.core.hookenv import (
is_leader,
leader_set,
leader_get,
WORKLOAD_STATES,
)
from charmhelpers.fetch import (
apt_update,
@ -747,4 +748,8 @@ if __name__ == '__main__':
hooks.execute(sys.argv)
except UnregisteredHookError as e:
log('Unknown hook {} - skipping.'.format(e))
assess_status(CONFIGS)
except ValueError as e:
# Handle any invalid configuration values
status_set(WORKLOAD_STATES.BLOCKED, str(e))
else:
assess_status(CONFIGS)

View File

@ -39,7 +39,7 @@ rgw_zone = {{ rgw_zone }}
{% endif %}
rgw init timeout = 1200
rgw frontends = civetweb port={{ port }}
rgw frontends = {{ frontend }} port={{ port }}
{% if auth_type == 'keystone' %}
rgw keystone url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/
rgw keystone admin user = {{ admin_user }}

View File

@ -17,6 +17,7 @@ from mock import patch
import ceph_radosgw_context as context
import charmhelpers
import charmhelpers.contrib.storage.linux.ceph as ceph
import charmhelpers.fetch as fetch
from test_utils import CharmTestCase
@ -27,6 +28,7 @@ TO_PATCH = [
'relation_ids',
'related_units',
'cmp_pkgrevno',
'arch',
'socket',
'unit_public_ip',
'determine_api_port',
@ -42,6 +44,7 @@ class HAProxyContextTests(CharmTestCase):
self.relation_get.side_effect = self.test_relation.get
self.config.side_effect = self.test_config.get
self.cmp_pkgrevno.return_value = 1
self.arch.return_value = 'amd64'
@patch('charmhelpers.contrib.openstack.context.get_relation_ip')
@patch('charmhelpers.contrib.openstack.context.mkdir')
@ -356,7 +359,8 @@ class MonContextTest(CharmTestCase):
super(MonContextTest, self).setUp(context, TO_PATCH)
self.config.side_effect = self.test_config.get
self.unit_public_ip.return_value = '10.255.255.255'
self.cmp_pkgrevno.return_value = 1
self.cmp_pkgrevno.side_effect = lambda *args: 1
self.arch.return_value = 'amd64'
@patch.object(ceph, 'config', lambda *args:
'{"client.radosgw.gateway": {"rgw init timeout": 60}}')
@ -395,6 +399,7 @@ class MonContextTest(CharmTestCase):
'rgw_zone': 'default',
'fsid': 'testfsid',
'rgw_swift_versioning': False,
'frontend': 'beast',
}
self.assertEqual(expect, mon_ctxt())
self.assertFalse(mock_ensure_rsv_v6.called)
@ -444,6 +449,7 @@ class MonContextTest(CharmTestCase):
'rgw_zone': 'default',
'fsid': 'testfsid',
'rgw_swift_versioning': False,
'frontend': 'beast',
}
self.assertEqual(expect, mon_ctxt())
self.assertFalse(mock_ensure_rsv_v6.called)
@ -502,6 +508,7 @@ class MonContextTest(CharmTestCase):
'rgw_zone': 'default',
'fsid': 'testfsid',
'rgw_swift_versioning': False,
'frontend': 'beast',
}
self.assertEqual(expect, mon_ctxt())
@ -542,9 +549,68 @@ class MonContextTest(CharmTestCase):
'rgw_zone': 'default',
'fsid': 'testfsid',
'rgw_swift_versioning': False,
'frontend': 'beast',
}
self.assertEqual(expect, mon_ctxt())
def test_resolve_http_frontend(self):
_test_version = '12.2.0'
def _compare_version(package, version):
return fetch.apt_pkg.version_compare(
_test_version, version
)
# Older releases, default and invalid configuration
self.cmp_pkgrevno.side_effect = _compare_version
self.assertEqual('civetweb', context.resolve_http_frontend())
# Default for Octopus but not Pacific
_test_version = '15.2.0'
self.assertEqual('beast', context.resolve_http_frontend())
self.arch.return_value = 's390x'
self.assertEqual('civetweb', context.resolve_http_frontend())
# Default for Pacific and later
_test_version = '16.2.0'
self.assertEqual('beast', context.resolve_http_frontend())
self.arch.return_value = 'amd64'
self.assertEqual('beast', context.resolve_http_frontend())
def test_validate_http_frontend(self):
_test_version = '12.2.0'
def _compare_version(package, version):
return fetch.apt_pkg.version_compare(
_test_version, version
)
self.cmp_pkgrevno.side_effect = _compare_version
# Invalid configuration option
with self.assertRaises(ValueError):
context.validate_http_frontend('foobar')
# beast config but ceph pre mimic
with self.assertRaises(ValueError):
context.validate_http_frontend('beast')
# Mimic with valid configuration
_test_version = '13.2.0'
context.validate_http_frontend('beast')
context.validate_http_frontend('civetweb')
# beast config on unsupported s390x/octopus
_test_version = '15.2.0'
self.arch.return_value = 's390x'
with self.assertRaises(ValueError):
context.validate_http_frontend('beast')
# beast config on s390x/pacific
_test_version = '16.2.0'
context.validate_http_frontend('beast')
class ApacheContextTest(CharmTestCase):