Merge "Ceph for standard: System Inventory CLI, API, DB"
This commit is contained in:
commit
13e11582ad
|
@ -439,7 +439,7 @@ class platform::ceph::rgw::keystone::auth(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class platform::ceph::controller::runtime {
|
class platform::ceph::runtime {
|
||||||
include ::platform::ceph::monitor
|
include ::platform::ceph::monitor
|
||||||
include ::platform::ceph
|
include ::platform::ceph
|
||||||
|
|
||||||
|
@ -452,7 +452,3 @@ class platform::ceph::controller::runtime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class platform::ceph::compute::runtime {
|
|
||||||
include ::platform::ceph
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,8 +10,7 @@
|
||||||
from cgtsclient.common import base
|
from cgtsclient.common import base
|
||||||
from cgtsclient import exc
|
from cgtsclient import exc
|
||||||
|
|
||||||
CREATION_ATTRIBUTES = ['ceph_mon_gib', 'ceph_mon_dev',
|
CREATION_ATTRIBUTES = ['ihost_uuid']
|
||||||
'ceph_mon_dev_ctrl0', 'ceph_mon_dev_ctrl1']
|
|
||||||
|
|
||||||
|
|
||||||
class CephMon(base.Resource):
|
class CephMon(base.Resource):
|
||||||
|
@ -36,8 +35,8 @@ class CephMonManager(base.Manager):
|
||||||
path = '/v1/ceph_mon'
|
path = '/v1/ceph_mon'
|
||||||
return self._list(path, "ceph_mon")
|
return self._list(path, "ceph_mon")
|
||||||
|
|
||||||
def get(self, ceph_mon_id):
|
def get(self, ceph_mon_uuid):
|
||||||
path = '/v1/ceph_mon/%s' % ceph_mon_id
|
path = '/v1/ceph_mon/%s' % ceph_mon_uuid
|
||||||
try:
|
try:
|
||||||
return self._list(path)[0]
|
return self._list(path)[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
@ -53,6 +52,10 @@ class CephMonManager(base.Manager):
|
||||||
raise exc.InvalidAttribute('%s' % key)
|
raise exc.InvalidAttribute('%s' % key)
|
||||||
return self._create(path, new)
|
return self._create(path, new)
|
||||||
|
|
||||||
|
def delete(self, host_uuid):
|
||||||
|
path = '/v1/ceph_mon/%s' % host_uuid
|
||||||
|
return self._delete(path)
|
||||||
|
|
||||||
def update(self, ceph_mon_id, patch):
|
def update(self, ceph_mon_id, patch):
|
||||||
path = '/v1/ceph_mon/%s' % ceph_mon_id
|
path = '/v1/ceph_mon/%s' % ceph_mon_id
|
||||||
return self._update(path, patch)
|
return self._update(path, patch)
|
||||||
|
@ -62,7 +65,7 @@ class CephMonManager(base.Manager):
|
||||||
return self._json_get(path, {})
|
return self._json_get(path, {})
|
||||||
|
|
||||||
|
|
||||||
def ceph_mon_add(cc, args):
|
def ceph_mon_add(cc, args, ihost_uuid):
|
||||||
data = dict()
|
data = dict()
|
||||||
|
|
||||||
if not vars(args).get('confirmed', None):
|
if not vars(args).get('confirmed', None):
|
||||||
|
@ -73,8 +76,13 @@ def ceph_mon_add(cc, args):
|
||||||
if ceph_mon_gib:
|
if ceph_mon_gib:
|
||||||
data['ceph_mon_gib'] = ceph_mon_gib
|
data['ceph_mon_gib'] = ceph_mon_gib
|
||||||
|
|
||||||
|
data['ihost_uuid'] = ihost_uuid
|
||||||
ceph_mon = cc.ceph_mon.create(**data)
|
ceph_mon = cc.ceph_mon.create(**data)
|
||||||
suuid = getattr(ceph_mon, 'uuid', '')
|
if ceph_mon and len(ceph_mon.ceph_mon):
|
||||||
|
suuid = ceph_mon.ceph_mon[0].get('uuid', '')
|
||||||
|
else:
|
||||||
|
raise exc.CommandError(
|
||||||
|
"Created ceph_mon has invalid data.")
|
||||||
try:
|
try:
|
||||||
ceph_mon = cc.ceph_mon.get(suuid)
|
ceph_mon = cc.ceph_mon.get(suuid)
|
||||||
except exc.HTTPNotFound:
|
except exc.HTTPNotFound:
|
||||||
|
|
|
@ -11,21 +11,24 @@
|
||||||
|
|
||||||
from cgtsclient.common import constants
|
from cgtsclient.common import constants
|
||||||
from cgtsclient.common import utils
|
from cgtsclient.common import utils
|
||||||
|
from cgtsclient import exc
|
||||||
from cgtsclient.v1 import ihost as ihost_utils
|
from cgtsclient.v1 import ihost as ihost_utils
|
||||||
|
|
||||||
|
|
||||||
def _print_ceph_mon_show(ceph_mon):
|
def _print_ceph_mon_show(ceph_mon):
|
||||||
|
|
||||||
fields = ['uuid', 'ceph_mon_gib',
|
fields = ['uuid', 'ceph_mon_gib',
|
||||||
'created_at', 'updated_at']
|
'created_at', 'updated_at',
|
||||||
|
'state', 'task']
|
||||||
data = [(f, getattr(ceph_mon, f)) for f in fields]
|
data = [(f, getattr(ceph_mon, f)) for f in fields]
|
||||||
utils.print_tuple_list(data)
|
utils.print_tuple_list(data)
|
||||||
|
|
||||||
|
|
||||||
def _print_ceph_mon_list(cc):
|
def _print_ceph_mon_list(cc):
|
||||||
field_labels = ['uuid', 'ceph_mon_gib',
|
field_labels = ['uuid', 'ceph_mon_gib',
|
||||||
'hostname']
|
'hostname', 'state', 'task']
|
||||||
fields = ['uuid', 'ceph_mon_gib', 'hostname']
|
fields = ['uuid', 'ceph_mon_gib', 'hostname',
|
||||||
|
'state', 'task']
|
||||||
ceph_mons = cc.ceph_mon.list()
|
ceph_mons = cc.ceph_mon.list()
|
||||||
utils.print_list(ceph_mons, fields, field_labels, sortby=0)
|
utils.print_list(ceph_mons, fields, field_labels, sortby=0)
|
||||||
|
|
||||||
|
@ -88,3 +91,44 @@ def do_ceph_mon_show(cc, args):
|
||||||
hostname = getattr(ceph_mon, 'hostname', '')
|
hostname = getattr(ceph_mon, 'hostname', '')
|
||||||
if hostname == ihost.hostname:
|
if hostname == ihost.hostname:
|
||||||
_print_ceph_mon_show(ceph_mon)
|
_print_ceph_mon_show(ceph_mon)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('hostnameorid',
|
||||||
|
metavar='<hostname or id>',
|
||||||
|
help='name or ID of host [REQUIRED]')
|
||||||
|
def do_ceph_mon_add(cc, args):
|
||||||
|
ihost = ihost_utils._find_ihost(cc, args.hostnameorid)
|
||||||
|
|
||||||
|
fields = {}
|
||||||
|
|
||||||
|
fields['ihost_uuid'] = ihost.uuid
|
||||||
|
try:
|
||||||
|
ceph_mon = cc.ceph_mon.create(**fields)
|
||||||
|
except exc.HTTPNotFound:
|
||||||
|
raise exc.CommandError(
|
||||||
|
"Ceph mon creation failed: "
|
||||||
|
"host %s: " % args.hostnameorid)
|
||||||
|
|
||||||
|
if ceph_mon and len(ceph_mon.ceph_mon):
|
||||||
|
suuid = ceph_mon.ceph_mon[0].get('uuid', '')
|
||||||
|
else:
|
||||||
|
raise exc.CommandError(
|
||||||
|
"Created ceph_mon has invalid data.")
|
||||||
|
try:
|
||||||
|
ceph_mon = cc.ceph_mon.get(suuid)
|
||||||
|
except exc.HTTPNotFound:
|
||||||
|
raise exc.CommandError("Created ceph monitor UUID not found: "
|
||||||
|
"%s" % suuid)
|
||||||
|
|
||||||
|
_print_ceph_mon_show(ceph_mon)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('hostnameorid',
|
||||||
|
help='hostname for compute')
|
||||||
|
def do_ceph_mon_delete(cc, args):
|
||||||
|
ihost = ihost_utils._find_ihost(cc, args.hostnameorid)
|
||||||
|
|
||||||
|
try:
|
||||||
|
cc.ceph_mon.delete(ihost.uuid)
|
||||||
|
except exc.HTTPNotFound:
|
||||||
|
raise exc.CommandError("failed to delete ceph_mon")
|
||||||
|
|
|
@ -12,6 +12,7 @@ from cgtsclient.common import constants
|
||||||
from cgtsclient.common import utils
|
from cgtsclient.common import utils
|
||||||
from cgtsclient import exc
|
from cgtsclient import exc
|
||||||
from cgtsclient.v1 import ceph_mon as ceph_mon_utils
|
from cgtsclient.v1 import ceph_mon as ceph_mon_utils
|
||||||
|
from cgtsclient.v1 import ihost as ihost_utils
|
||||||
from cgtsclient.v1 import storage_ceph # noqa
|
from cgtsclient.v1 import storage_ceph # noqa
|
||||||
from cgtsclient.v1 import storage_ceph_external # noqa
|
from cgtsclient.v1 import storage_ceph_external # noqa
|
||||||
from cgtsclient.v1 import storage_external # noqa
|
from cgtsclient.v1 import storage_external # noqa
|
||||||
|
@ -139,7 +140,20 @@ def backend_add(cc, backend, args):
|
||||||
|
|
||||||
# add ceph mons to controllers
|
# add ceph mons to controllers
|
||||||
if backend == constants.SB_TYPE_CEPH:
|
if backend == constants.SB_TYPE_CEPH:
|
||||||
ceph_mon_utils.ceph_mon_add(cc, args)
|
# Controllers should always have monitors.
|
||||||
|
# Not finding a controller means it's not yet configured,
|
||||||
|
# so move forward.
|
||||||
|
try:
|
||||||
|
ihost = ihost_utils._find_ihost(cc, constants.CONTROLLER_0_HOSTNAME)
|
||||||
|
ceph_mon_utils.ceph_mon_add(cc, args, ihost.uuid)
|
||||||
|
except exc.CommandError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
ihost = ihost_utils._find_ihost(cc, constants.CONTROLLER_1_HOSTNAME)
|
||||||
|
ceph_mon_utils.ceph_mon_add(cc, args, ihost.uuid)
|
||||||
|
except exc.CommandError:
|
||||||
|
pass
|
||||||
|
|
||||||
# allowed storage_backend fields
|
# allowed storage_backend fields
|
||||||
allowed_fields = ['name', 'services', 'confirmed', 'ceph_conf']
|
allowed_fields = ['name', 'services', 'confirmed', 'ceph_conf']
|
||||||
|
|
|
@ -16,10 +16,11 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2017 Wind River Systems, Inc.
|
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
|
|
||||||
import jsonpatch
|
import jsonpatch
|
||||||
|
import six
|
||||||
|
|
||||||
import pecan
|
import pecan
|
||||||
from pecan import rest
|
from pecan import rest
|
||||||
|
@ -75,6 +76,9 @@ class CephMon(base.APIBase):
|
||||||
forihostid = int
|
forihostid = int
|
||||||
"The id of the host the ceph mon belongs to."
|
"The id of the host the ceph mon belongs to."
|
||||||
|
|
||||||
|
ihost_uuid = types.uuid
|
||||||
|
"The UUID of the host this ceph mon belongs to"
|
||||||
|
|
||||||
hostname = wtypes.text
|
hostname = wtypes.text
|
||||||
"The name of host this ceph mon belongs to."
|
"The name of host this ceph mon belongs to."
|
||||||
|
|
||||||
|
@ -85,13 +89,11 @@ class CephMon(base.APIBase):
|
||||||
ceph_mon_gib = int
|
ceph_mon_gib = int
|
||||||
"The ceph-mon-lv size in GiB, for Ceph backend only."
|
"The ceph-mon-lv size in GiB, for Ceph backend only."
|
||||||
|
|
||||||
ceph_mon_dev_ctrl0 = wtypes.text
|
state = wtypes.text
|
||||||
"The disk device on controller-0 that cgts-vg will be extended " \
|
"The state of the monitor. It can be configured or configuring."
|
||||||
"to create ceph-mon-lv"
|
|
||||||
|
|
||||||
ceph_mon_dev_ctrl1 = wtypes.text
|
task = wtypes.text
|
||||||
"The disk device on controller-1 that cgts-vg will be extended " \
|
"Current task of the corresponding ceph monitor."
|
||||||
"to create ceph-mon-lv"
|
|
||||||
|
|
||||||
links = [link.Link]
|
links = [link.Link]
|
||||||
"A list containing a self link and associated ceph_mon links"
|
"A list containing a self link and associated ceph_mon links"
|
||||||
|
@ -100,28 +102,18 @@ class CephMon(base.APIBase):
|
||||||
updated_at = wtypes.datetime.datetime
|
updated_at = wtypes.datetime.datetime
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|
||||||
|
defaults = {'state': constants.SB_STATE_CONFIGURED,
|
||||||
|
'task': constants.SB_TASK_NONE}
|
||||||
|
|
||||||
self.fields = objects.ceph_mon.fields.keys()
|
self.fields = objects.ceph_mon.fields.keys()
|
||||||
|
|
||||||
for k in self.fields:
|
for k in self.fields:
|
||||||
setattr(self, k, kwargs.get(k))
|
setattr(self, k, kwargs.get(k, defaults.get(k)))
|
||||||
|
|
||||||
if not self.uuid:
|
if not self.uuid:
|
||||||
self.uuid = uuidutils.generate_uuid()
|
self.uuid = uuidutils.generate_uuid()
|
||||||
|
|
||||||
self.fields.append('ceph_mon_dev')
|
|
||||||
setattr(self, 'ceph_mon_dev', kwargs.get('ceph_mon_dev', None))
|
|
||||||
|
|
||||||
self.fields.append('ceph_mon_dev_ctrl0')
|
|
||||||
setattr(self, 'ceph_mon_dev_ctrl0',
|
|
||||||
kwargs.get('ceph_mon_dev_ctrl0', None))
|
|
||||||
|
|
||||||
self.fields.append('ceph_mon_dev_ctrl1')
|
|
||||||
setattr(self, 'ceph_mon_dev_ctrl1',
|
|
||||||
kwargs.get('ceph_mon_dev_ctrl1', None))
|
|
||||||
|
|
||||||
self.fields.append('device_node')
|
|
||||||
setattr(self, 'device_node', kwargs.get('device_node', None))
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def convert_with_links(cls, rpc_ceph_mon, expand=True):
|
def convert_with_links(cls, rpc_ceph_mon, expand=True):
|
||||||
|
|
||||||
|
@ -129,12 +121,15 @@ class CephMon(base.APIBase):
|
||||||
if not expand:
|
if not expand:
|
||||||
ceph_mon.unset_fields_except(['created_at',
|
ceph_mon.unset_fields_except(['created_at',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
|
'ihost_uuid',
|
||||||
'forihostid',
|
'forihostid',
|
||||||
'uuid',
|
'uuid',
|
||||||
'device_path',
|
'device_path',
|
||||||
'device_node',
|
'device_node',
|
||||||
'ceph_mon_dev',
|
'ceph_mon_dev',
|
||||||
'ceph_mon_gib',
|
'ceph_mon_gib',
|
||||||
|
'state',
|
||||||
|
'task',
|
||||||
'ceph_mon_dev_ctrl0',
|
'ceph_mon_dev_ctrl0',
|
||||||
'ceph_mon_dev_ctrl1',
|
'ceph_mon_dev_ctrl1',
|
||||||
'hostname'])
|
'hostname'])
|
||||||
|
@ -381,13 +376,21 @@ class CephMonController(rest.RestController):
|
||||||
return StorageBackendConfig.get_ceph_mon_ip_addresses(
|
return StorageBackendConfig.get_ceph_mon_ip_addresses(
|
||||||
pecan.request.dbapi)
|
pecan.request.dbapi)
|
||||||
|
|
||||||
|
@cutils.synchronized(LOCK_NAME)
|
||||||
|
@wsme_pecan.wsexpose(None, six.text_type, status_code=204)
|
||||||
|
def delete(self, host_uuid):
|
||||||
|
"""Delete a ceph_mon."""
|
||||||
|
|
||||||
|
_delete(host_uuid)
|
||||||
|
|
||||||
|
|
||||||
def _set_defaults(ceph_mon):
|
def _set_defaults(ceph_mon):
|
||||||
defaults = {
|
defaults = {
|
||||||
|
'uuid': None,
|
||||||
'ceph_mon_gib': constants.SB_CEPH_MON_GIB,
|
'ceph_mon_gib': constants.SB_CEPH_MON_GIB,
|
||||||
'ceph_mon_dev': None,
|
'ceph_mon_dev': None,
|
||||||
'ceph_mon_dev_ctrl0': None,
|
'state': constants.SB_STATE_CONFIGURED,
|
||||||
'ceph_mon_dev_ctrl1': None,
|
'task': constants.SB_TASK_NONE,
|
||||||
}
|
}
|
||||||
|
|
||||||
storage_ceph_merged = ceph_mon.copy()
|
storage_ceph_merged = ceph_mon.copy()
|
||||||
|
@ -407,30 +410,74 @@ def _create(ceph_mon):
|
||||||
|
|
||||||
_check_ceph_mon(ceph_mon)
|
_check_ceph_mon(ceph_mon)
|
||||||
|
|
||||||
|
chost = pecan.request.dbapi.ihost_get(ceph_mon['ihost_uuid'])
|
||||||
|
ceph_mon['forihostid'] = chost['id']
|
||||||
|
|
||||||
controller_fs_utils._check_controller_fs(
|
controller_fs_utils._check_controller_fs(
|
||||||
ceph_mon_gib_new=ceph_mon['ceph_mon_gib'])
|
ceph_mon_gib_new=ceph_mon['ceph_mon_gib'])
|
||||||
|
|
||||||
pecan.request.rpcapi.reserve_ip_for_first_storage_node(
|
pecan.request.rpcapi.reserve_ip_for_first_storage_node(
|
||||||
pecan.request.context)
|
pecan.request.context)
|
||||||
|
|
||||||
new_ceph_mons = list()
|
# Size of ceph-mon logical volume must be the same for all
|
||||||
chosts = pecan.request.dbapi.ihost_get_by_personality(constants.CONTROLLER)
|
# monitors so we get the size from any or use default.
|
||||||
for chost in chosts:
|
ceph_mons = pecan.request.dbapi.ceph_mon_get_list()
|
||||||
# Check if mon exists
|
if ceph_mons:
|
||||||
ceph_mons = pecan.request.dbapi.ceph_mon_get_by_ihost(chost.uuid)
|
ceph_mon['ceph_mon_gib'] = ceph_mons[0]['ceph_mon_gib']
|
||||||
if ceph_mons:
|
|
||||||
pecan.request.dbapi.ceph_mon_update(
|
|
||||||
ceph_mons[0].uuid, {'ceph_mon_gib': ceph_mon['ceph_mon_gib']}
|
|
||||||
)
|
|
||||||
new_ceph_mons.append(ceph_mons[0])
|
|
||||||
else:
|
|
||||||
ceph_mon_new = dict()
|
|
||||||
ceph_mon_new['uuid'] = None
|
|
||||||
ceph_mon_new['forihostid'] = chost.id
|
|
||||||
ceph_mon_new['ceph_mon_gib'] = ceph_mon['ceph_mon_gib']
|
|
||||||
|
|
||||||
LOG.info("creating ceph_mon_new for %s: %s" %
|
# In case we add the monitor on a worker node, the state
|
||||||
(chost.hostname, str(ceph_mon_new)))
|
# and task must be set properly.
|
||||||
new_ceph_mons.append(pecan.request.dbapi.ceph_mon_create(ceph_mon_new))
|
if chost.personality == constants.WORKER:
|
||||||
|
ceph_mon['state'] = constants.SB_STATE_CONFIGURING
|
||||||
|
ctrls = pecan.request.dbapi.ihost_get_by_personality(
|
||||||
|
constants.CONTROLLER)
|
||||||
|
valid_ctrls = [
|
||||||
|
ctrl for ctrl in ctrls if
|
||||||
|
(ctrl.administrative == constants.ADMIN_LOCKED and
|
||||||
|
ctrl.availability == constants.AVAILABILITY_ONLINE) or
|
||||||
|
(ctrl.administrative == constants.ADMIN_UNLOCKED and
|
||||||
|
ctrl.operational == constants.OPERATIONAL_ENABLED)]
|
||||||
|
|
||||||
return new_ceph_mons
|
tasks = {}
|
||||||
|
for ctrl in valid_ctrls:
|
||||||
|
tasks[ctrl.hostname] = constants.SB_STATE_CONFIGURING
|
||||||
|
|
||||||
|
ceph_mon['task'] = str(tasks)
|
||||||
|
|
||||||
|
LOG.info("Creating ceph-mon DB entry for host uuid %s: %s" %
|
||||||
|
(ceph_mon['ihost_uuid'], str(ceph_mon)))
|
||||||
|
new_ceph_mon = pecan.request.dbapi.ceph_mon_create(ceph_mon)
|
||||||
|
|
||||||
|
# We update the base config when adding a dynamic monitor.
|
||||||
|
# At this moment the only possibility to add a dynamic monitor
|
||||||
|
# is on a worker node, so we check for that.
|
||||||
|
if chost.personality == constants.WORKER:
|
||||||
|
# Storage nodes are not supported on a controller based
|
||||||
|
# storage model.
|
||||||
|
personalities = [constants.CONTROLLER, constants.WORKER]
|
||||||
|
pecan.request.rpcapi.update_ceph_base_config(
|
||||||
|
pecan.request.context,
|
||||||
|
personalities)
|
||||||
|
|
||||||
|
# The return value needs to be iterable, so make it a list.
|
||||||
|
return [new_ceph_mon]
|
||||||
|
|
||||||
|
|
||||||
|
def _delete(host_uuid):
|
||||||
|
ceph_mon = pecan.request.dbapi.ceph_mon_get_by_ihost(host_uuid)
|
||||||
|
if ceph_mon:
|
||||||
|
ceph_mon = ceph_mon[0]
|
||||||
|
else:
|
||||||
|
raise wsme.exc.ClientSideError(
|
||||||
|
_("No Ceph Monitor defined for host with uuid: %s" % host_uuid))
|
||||||
|
|
||||||
|
if ceph_mon.state == constants.SB_STATE_CONFIG_ERR:
|
||||||
|
try:
|
||||||
|
pecan.request.dbapi.ceph_mon_destroy(ceph_mon.uuid)
|
||||||
|
except exception.HTTPNotFound:
|
||||||
|
raise wsme.exc.ClientSideError("Deleting Ceph Monitor failed!")
|
||||||
|
else:
|
||||||
|
raise wsme.exc.ClientSideError(
|
||||||
|
_("Direct Ceph monitor delete only allowed for state '%s'. "
|
||||||
|
"Please lock and delete node to remove the configured Ceph Monitor."
|
||||||
|
% constants.SB_STATE_CONFIG_ERR))
|
||||||
|
|
|
@ -4452,8 +4452,8 @@ class HostController(rest.RestController):
|
||||||
LOG.info(
|
LOG.info(
|
||||||
'Apply new Ceph manifest to provisioned worker nodes.'
|
'Apply new Ceph manifest to provisioned worker nodes.'
|
||||||
)
|
)
|
||||||
pecan.request.rpcapi.config_worker_for_ceph(
|
pecan.request.rpcapi.update_ceph_base_config(
|
||||||
pecan.request.context
|
pecan.request.context, personalities=[constants.WORKER]
|
||||||
)
|
)
|
||||||
# mark all tasks completed after updating the manifests for
|
# mark all tasks completed after updating the manifests for
|
||||||
# all worker nodes.
|
# all worker nodes.
|
||||||
|
|
|
@ -1415,24 +1415,29 @@ class ConductorManager(service.PeriodicService):
|
||||||
ceph_mon_gib = ceph_mons[0].ceph_mon_gib
|
ceph_mon_gib = ceph_mons[0].ceph_mon_gib
|
||||||
values = {'forisystemid': system.id,
|
values = {'forisystemid': system.id,
|
||||||
'forihostid': host.id,
|
'forihostid': host.id,
|
||||||
'ceph_mon_gib': ceph_mon_gib}
|
'ceph_mon_gib': ceph_mon_gib,
|
||||||
|
'state': constants.SB_STATE_CONFIGURED,
|
||||||
|
'task': constants.SB_TASK_NONE}
|
||||||
LOG.info("creating ceph_mon for host %s with ceph_mon_gib=%s."
|
LOG.info("creating ceph_mon for host %s with ceph_mon_gib=%s."
|
||||||
% (host.hostname, ceph_mon_gib))
|
% (host.hostname, ceph_mon_gib))
|
||||||
self.dbapi.ceph_mon_create(values)
|
self.dbapi.ceph_mon_create(values)
|
||||||
|
|
||||||
def config_worker_for_ceph(self, context):
|
def _remove_ceph_mon(self, host):
|
||||||
"""
|
if not StorageBackendConfig.has_backend(
|
||||||
configure worker nodes for adding ceph
|
self.dbapi,
|
||||||
:param context:
|
constants.CINDER_BACKEND_CEPH
|
||||||
:return: none
|
):
|
||||||
"""
|
return
|
||||||
personalities = [constants.WORKER]
|
|
||||||
config_uuid = self._config_update_hosts(context, personalities)
|
mon = self.dbapi.ceph_mon_get_by_ihost(host.uuid)
|
||||||
config_dict = {
|
if mon:
|
||||||
"personalities": personalities,
|
LOG.info("Deleting ceph monitor for host %s"
|
||||||
"classes": ['platform::ceph::compute::runtime']
|
% str(host.hostname))
|
||||||
}
|
self.dbapi.ceph_mon_destroy(mon[0].uuid)
|
||||||
self._config_apply_runtime_manifest(context, config_uuid, config_dict)
|
else:
|
||||||
|
LOG.info("No ceph monitor present for host %s. "
|
||||||
|
"Skipping deleting ceph monitor."
|
||||||
|
% str(host.hostname))
|
||||||
|
|
||||||
def update_remotelogging_config(self, context):
|
def update_remotelogging_config(self, context):
|
||||||
"""Update the remotelogging configuration"""
|
"""Update the remotelogging configuration"""
|
||||||
|
@ -1529,6 +1534,8 @@ class ConductorManager(service.PeriodicService):
|
||||||
self._allocate_addresses_for_host(context, host)
|
self._allocate_addresses_for_host(context, host)
|
||||||
# Set up the PXE config file for this host so it can run the installer
|
# Set up the PXE config file for this host so it can run the installer
|
||||||
self._update_pxe_config(host)
|
self._update_pxe_config(host)
|
||||||
|
if host['hostname'] == constants.STORAGE_0_HOSTNAME:
|
||||||
|
self._ceph_mon_create(host)
|
||||||
|
|
||||||
# TODO(CephPoolsDecouple): remove
|
# TODO(CephPoolsDecouple): remove
|
||||||
def configure_osd_pools(self, context, ceph_backend=None, new_pool_size=None, new_pool_min_size=None):
|
def configure_osd_pools(self, context, ceph_backend=None, new_pool_size=None, new_pool_min_size=None):
|
||||||
|
@ -1590,6 +1597,7 @@ class ConductorManager(service.PeriodicService):
|
||||||
self._remove_addresses_for_host(host)
|
self._remove_addresses_for_host(host)
|
||||||
self._puppet.remove_host_config(host)
|
self._puppet.remove_host_config(host)
|
||||||
self._remove_pxe_config(host)
|
self._remove_pxe_config(host)
|
||||||
|
self._remove_ceph_mon(host)
|
||||||
|
|
||||||
def _unconfigure_storage_host(self, host):
|
def _unconfigure_storage_host(self, host):
|
||||||
"""Unconfigure a storage host.
|
"""Unconfigure a storage host.
|
||||||
|
@ -5649,7 +5657,7 @@ class ConductorManager(service.PeriodicService):
|
||||||
rpcapi.iconfig_update_install_uuid(context, host_uuid, install_uuid)
|
rpcapi.iconfig_update_install_uuid(context, host_uuid, install_uuid)
|
||||||
|
|
||||||
def update_ceph_config(self, context, sb_uuid, services):
|
def update_ceph_config(self, context, sb_uuid, services):
|
||||||
"""Update the manifests for Cinder Ceph backend"""
|
"""Update the manifests for Ceph backend and services"""
|
||||||
|
|
||||||
personalities = [constants.CONTROLLER]
|
personalities = [constants.CONTROLLER]
|
||||||
|
|
||||||
|
@ -5666,7 +5674,7 @@ class ConductorManager(service.PeriodicService):
|
||||||
'platform::haproxy::runtime',
|
'platform::haproxy::runtime',
|
||||||
'openstack::keystone::endpoint::runtime',
|
'openstack::keystone::endpoint::runtime',
|
||||||
'platform::filesystem::img_conversions::runtime',
|
'platform::filesystem::img_conversions::runtime',
|
||||||
'platform::ceph::controller::runtime',
|
'platform::ceph::runtime',
|
||||||
]
|
]
|
||||||
|
|
||||||
if utils.is_aio_duplex_system(self.dbapi):
|
if utils.is_aio_duplex_system(self.dbapi):
|
||||||
|
@ -5721,6 +5729,27 @@ class ConductorManager(service.PeriodicService):
|
||||||
'task': str(tasks)}
|
'task': str(tasks)}
|
||||||
self.dbapi.storage_ceph_update(sb_uuid, values)
|
self.dbapi.storage_ceph_update(sb_uuid, values)
|
||||||
|
|
||||||
|
def update_ceph_base_config(self, context, personalities):
|
||||||
|
""" Update Ceph configuration, monitors and ceph.conf only"""
|
||||||
|
config_uuid = self._config_update_hosts(context, personalities)
|
||||||
|
|
||||||
|
valid_nodes = []
|
||||||
|
for personality in personalities:
|
||||||
|
nodes = self.dbapi.ihost_get_by_personality(personality)
|
||||||
|
valid_nodes += [
|
||||||
|
node for node in nodes if
|
||||||
|
(node.administrative == constants.ADMIN_UNLOCKED and
|
||||||
|
node.operational == constants.OPERATIONAL_ENABLED)]
|
||||||
|
|
||||||
|
# TODO: check what other puppet class need to be called
|
||||||
|
config_dict = {
|
||||||
|
"personalities": personalities,
|
||||||
|
"host_uuids": [node.uuid for node in valid_nodes],
|
||||||
|
"classes": ['platform::ceph::runtime'],
|
||||||
|
puppet_common.REPORT_STATUS_CFG: puppet_common.REPORT_CEPH_MONITOR_CONFIG
|
||||||
|
}
|
||||||
|
self._config_apply_runtime_manifest(context, config_uuid, config_dict)
|
||||||
|
|
||||||
def config_update_nova_local_backed_hosts(self, context, instance_backing):
|
def config_update_nova_local_backed_hosts(self, context, instance_backing):
|
||||||
hosts_uuid = self.hosts_with_nova_local(instance_backing)
|
hosts_uuid = self.hosts_with_nova_local(instance_backing)
|
||||||
if hosts_uuid:
|
if hosts_uuid:
|
||||||
|
@ -6001,6 +6030,19 @@ class ConductorManager(service.PeriodicService):
|
||||||
LOG.error("No match for sysinv-agent manifest application reported! "
|
LOG.error("No match for sysinv-agent manifest application reported! "
|
||||||
"reported_cfg: %(cfg)s status: %(status)s "
|
"reported_cfg: %(cfg)s status: %(status)s "
|
||||||
"iconfig: %(iconfig)s" % args)
|
"iconfig: %(iconfig)s" % args)
|
||||||
|
elif reported_cfg == puppet_common.REPORT_CEPH_MONITOR_CONFIG:
|
||||||
|
host_uuid = iconfig['host_uuid']
|
||||||
|
if status == puppet_common.REPORT_SUCCESS:
|
||||||
|
# Configuration was successful
|
||||||
|
self.report_ceph_base_config_success(host_uuid)
|
||||||
|
elif status == puppet_common.REPORT_FAILURE:
|
||||||
|
# Configuration has failed
|
||||||
|
self.report_ceph_base_config_failure(host_uuid, error)
|
||||||
|
else:
|
||||||
|
args = {'cfg': reported_cfg, 'status': status, 'iconfig': iconfig}
|
||||||
|
LOG.error("No match for sysinv-agent manifest application reported! "
|
||||||
|
"reported_cfg: %(cfg)s status: %(status)s "
|
||||||
|
"iconfig: %(iconfig)s" % args)
|
||||||
else:
|
else:
|
||||||
LOG.error("Reported configuration '%(cfg)s' is not handled by"
|
LOG.error("Reported configuration '%(cfg)s' is not handled by"
|
||||||
" report_config_status! iconfig: %(iconfig)s" %
|
" report_config_status! iconfig: %(iconfig)s" %
|
||||||
|
@ -6495,6 +6537,89 @@ class ConductorManager(service.PeriodicService):
|
||||||
values = {'state': constants.SB_STATE_CONFIG_ERR, 'task': None}
|
values = {'state': constants.SB_STATE_CONFIG_ERR, 'task': None}
|
||||||
self.dbapi.storage_backend_update(backend.uuid, values)
|
self.dbapi.storage_backend_update(backend.uuid, values)
|
||||||
|
|
||||||
|
def report_ceph_base_config_success(self, host_uuid):
|
||||||
|
"""
|
||||||
|
Callback for Sysinv Agent
|
||||||
|
"""
|
||||||
|
|
||||||
|
LOG.info("Ceph monitor update succeeded on host: %s" % host_uuid)
|
||||||
|
|
||||||
|
# Get the monitor that is configuring
|
||||||
|
monitor_list = self.dbapi.ceph_mon_get_list()
|
||||||
|
monitor = None
|
||||||
|
for mon in monitor_list:
|
||||||
|
if mon.state == constants.SB_STATE_CONFIGURING:
|
||||||
|
monitor = mon
|
||||||
|
break
|
||||||
|
|
||||||
|
ctrls = self.dbapi.ihost_get_by_personality(constants.CONTROLLER)
|
||||||
|
# Note that even if nodes are degraded we still accept the answer.
|
||||||
|
valid_ctrls = [ctrl for ctrl in ctrls if
|
||||||
|
(ctrl.administrative == constants.ADMIN_LOCKED and
|
||||||
|
ctrl.availability == constants.AVAILABILITY_ONLINE) or
|
||||||
|
(ctrl.administrative == constants.ADMIN_UNLOCKED and
|
||||||
|
ctrl.operational == constants.OPERATIONAL_ENABLED)]
|
||||||
|
|
||||||
|
# Set state for current node
|
||||||
|
for host in valid_ctrls:
|
||||||
|
if host.uuid == host_uuid:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
LOG.error("Host %(host) is not in the required state!" % host_uuid)
|
||||||
|
host = self.dbapi.ihost_get(host_uuid)
|
||||||
|
if not host:
|
||||||
|
LOG.error("Host %s is invalid!" % host_uuid)
|
||||||
|
return
|
||||||
|
elif host.personality == constants.WORKER:
|
||||||
|
LOG.info("Ignoring report from worker hosts")
|
||||||
|
return
|
||||||
|
tasks = eval(monitor.get('task', '{}'))
|
||||||
|
if tasks:
|
||||||
|
tasks[host.hostname] = constants.SB_STATE_CONFIGURED
|
||||||
|
else:
|
||||||
|
tasks = {host.hostname: constants.SB_STATE_CONFIGURED}
|
||||||
|
|
||||||
|
# Check if all hosts configurations have applied correctly
|
||||||
|
# and mark config success
|
||||||
|
config_success = True
|
||||||
|
for host in valid_ctrls:
|
||||||
|
if tasks.get(host.hostname, '') != constants.SB_STATE_CONFIGURED:
|
||||||
|
config_success = False
|
||||||
|
|
||||||
|
values = None
|
||||||
|
if monitor.state != constants.SB_STATE_CONFIG_ERR:
|
||||||
|
if config_success:
|
||||||
|
# All hosts have completed configuration
|
||||||
|
values = {'state': constants.SB_STATE_CONFIGURED, 'task': None}
|
||||||
|
else:
|
||||||
|
# This host_uuid has completed configuration
|
||||||
|
values = {'task': str(tasks)}
|
||||||
|
if values:
|
||||||
|
self.dbapi.ceph_mon_update(monitor.uuid, values)
|
||||||
|
|
||||||
|
def report_ceph_base_config_failure(self, host_uuid, error):
|
||||||
|
"""
|
||||||
|
Callback for Sysinv Agent
|
||||||
|
"""
|
||||||
|
LOG.error("Ceph monitor update failed on host: %(host)s. Error: "
|
||||||
|
"%(error)s" % {'host': host_uuid, 'error': error})
|
||||||
|
|
||||||
|
host = self.dbapi.ihost_get(host_uuid)
|
||||||
|
if host and host.personality == constants.WORKER:
|
||||||
|
# Ignoring report from worker
|
||||||
|
return
|
||||||
|
|
||||||
|
monitor_list = self.dbapi.ceph_mon_get_list()
|
||||||
|
monitor = None
|
||||||
|
for mon in monitor_list:
|
||||||
|
if mon.state == constants.SB_STATE_CONFIGURING:
|
||||||
|
monitor = mon
|
||||||
|
break
|
||||||
|
|
||||||
|
# Set monitor to error state
|
||||||
|
values = {'state': constants.SB_STATE_CONFIG_ERR, 'task': None}
|
||||||
|
self.dbapi.ceph_mon_update(monitor.uuid, values)
|
||||||
|
|
||||||
def create_controller_filesystems(self, context, rootfs_device):
|
def create_controller_filesystems(self, context, rootfs_device):
|
||||||
""" Create the storage config based on disk size for
|
""" Create the storage config based on disk size for
|
||||||
database, image, backup, img-conversion
|
database, image, backup, img-conversion
|
||||||
|
|
|
@ -788,13 +788,19 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
|
||||||
"""
|
"""
|
||||||
return self.call(context, self.make_msg('update_lvm_config'))
|
return self.call(context, self.make_msg('update_lvm_config'))
|
||||||
|
|
||||||
def config_worker_for_ceph(self, context):
|
def update_ceph_base_config(self, context, personalities):
|
||||||
"""Synchronously, have the conductor update the worker configuration
|
"""Synchronously, have the conductor update the configuration
|
||||||
for adding ceph.
|
for monitors and ceph.conf.
|
||||||
|
|
||||||
:param context: request context.
|
:param context: request context.
|
||||||
|
:param personalities: list of host personalities.
|
||||||
"""
|
"""
|
||||||
return self.call(context, self.make_msg('config_worker_for_ceph'))
|
return self.call(
|
||||||
|
context, self.make_msg(
|
||||||
|
'update_ceph_base_config',
|
||||||
|
personalities=personalities
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def update_drbd_config(self, context):
|
def update_drbd_config(self, context):
|
||||||
"""Synchronously, have the conductor update the drbd configuration.
|
"""Synchronously, have the conductor update the drbd configuration.
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
from sqlalchemy import Column, MetaData, String, Table
|
||||||
|
|
||||||
|
ENGINE = 'InnoDB'
|
||||||
|
CHARSET = 'utf8'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
ceph_mon = Table('ceph_mon', meta, autoload=True)
|
||||||
|
ceph_mon.create_column(Column('state', String(255)))
|
||||||
|
ceph_mon.create_column(Column('task', String(255)))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migrate_engine):
|
||||||
|
# As per other openstack components, downgrade is
|
||||||
|
# unsupported in this release.
|
||||||
|
raise NotImplementedError('SysInv database downgrade is unsupported.')
|
|
@ -953,6 +953,8 @@ class CephMon(Base):
|
||||||
uuid = Column(String(36))
|
uuid = Column(String(36))
|
||||||
device_path = Column(String(255))
|
device_path = Column(String(255))
|
||||||
ceph_mon_gib = Column(Integer)
|
ceph_mon_gib = Column(Integer)
|
||||||
|
state = Column(String(255))
|
||||||
|
task = Column(String(255))
|
||||||
forihostid = Column(Integer, ForeignKey('i_host.id', ondelete='CASCADE'))
|
forihostid = Column(Integer, ForeignKey('i_host.id', ondelete='CASCADE'))
|
||||||
|
|
||||||
host = relationship("ihost", lazy="joined", join_depth=1)
|
host = relationship("ihost", lazy="joined", join_depth=1)
|
||||||
|
|
|
@ -23,13 +23,17 @@ class CephMon(base.SysinvObject):
|
||||||
|
|
||||||
'device_path': utils.str_or_none,
|
'device_path': utils.str_or_none,
|
||||||
'ceph_mon_gib': utils.int_or_none,
|
'ceph_mon_gib': utils.int_or_none,
|
||||||
|
'state': utils.str_or_none,
|
||||||
|
'task': utils.str_or_none,
|
||||||
|
|
||||||
'forihostid': utils.int_or_none,
|
'forihostid': utils.int_or_none,
|
||||||
|
'ihost_uuid': utils.str_or_none,
|
||||||
'hostname': utils.str_or_none,
|
'hostname': utils.str_or_none,
|
||||||
}
|
}
|
||||||
|
|
||||||
_foreign_fields = {
|
_foreign_fields = {
|
||||||
'hostname': 'host:hostname',
|
'hostname': 'host:hostname',
|
||||||
|
'ihost_uuid': 'host:uuid'
|
||||||
}
|
}
|
||||||
|
|
||||||
@base.remotable_classmethod
|
@base.remotable_classmethod
|
||||||
|
|
|
@ -33,6 +33,7 @@ REPORT_EXTERNAL_BACKEND_CONFIG = 'external_config'
|
||||||
REPORT_CEPH_BACKEND_CONFIG = 'ceph_config'
|
REPORT_CEPH_BACKEND_CONFIG = 'ceph_config'
|
||||||
REPORT_CEPH_EXTERNAL_BACKEND_CONFIG = 'ceph_external_config'
|
REPORT_CEPH_EXTERNAL_BACKEND_CONFIG = 'ceph_external_config'
|
||||||
REPORT_CEPH_SERVICES_CONFIG = 'ceph_services'
|
REPORT_CEPH_SERVICES_CONFIG = 'ceph_services'
|
||||||
|
REPORT_CEPH_MONITOR_CONFIG = 'ceph_monitor'
|
||||||
|
|
||||||
|
|
||||||
def puppet_apply_manifest(ip_address, personality,
|
def puppet_apply_manifest(ip_address, personality,
|
||||||
|
|
Loading…
Reference in New Issue