RGWFSAL,
RawBlock,
CephBlock,
+ LogBlock,
format_block)
from .exception import NFSException, NFSInvalidOperation, FSNotFound, NFSObjectNotFound
from .utils import (
return self.status
class GaneshaExport:
- # currently, EXPORT and CEPH block.
+ # EXPORT, CEPH and LOG block.
def __init__(self,
export: Export,
- ceph_block: Optional[CephBlock] = None) -> None:
+ ceph_block: Optional[CephBlock] = None,
+ log_block: Optional[LogBlock] = None) -> None:
self.export = export
self.ceph_block = ceph_block
+ self.log_block = log_block
# frequently uesd properties so that much of the code that now
# has moved to using this class can still continue to acess via
def to_dict(self, full=False) -> Dict[str, Any]:
export_dict = self.export.to_dict()
- if not full or not self.ceph_block:
+ if not full or (not self.ceph_block and not self.log_block):
return export_dict
- ge_dict = {
- 'export': export_dict,
- 'ceph': self.ceph_block.to_dict()
- }
+ ge_dict = {'export': export_dict}
+ if self.ceph_block:
+ ge_dict['ceph'] = self.ceph_block.to_dict()
+ if self.log_block:
+ ge_dict['log'] = self.log_block.to_dict()
return ge_dict
def to_export_block(self):
block_str = format_block(self.export.to_export_block())
if self.ceph_block:
block_str += format_block(self.ceph_block.to_ceph_block())
+ if self.log_block:
+ block_str += format_block(self.log_block.to_log_block())
return block_str
def __eq__(self, other: Any) -> bool:
break
return nid
- def _has_ceph_block(raw_config_parsed: List) -> bool:
- return len(raw_config_parsed) > 1
+ def _has_ceph_block(raw_config_parsed: Dict) -> bool:
+ return 'CEPH' in raw_config_parsed.keys()
+ def _has_log_block(raw_config_parsed: Dict) -> bool:
+ return 'LOG' in raw_config_parsed.keys()
def _read_raw_config(self, rados_namespace: str) -> None:
with self.mgr.rados.open_ioctx(self.rados_pool) as ioctx:
log.debug(f'raw_config: {raw_config}')
raw_config_parsed = GaneshaConfParser(raw_config).parse()
log.debug(f'raw_config_parsed: {raw_config_parsed}')
- export_block = raw_config_parsed[0]
- # do we have a ceph block?
+ # mandatory export block
+ export_block = raw_config_parsed['EXPORT']
+ # do we have a ceph/log block? (optional)
+ ceph_block = None
+ log_block = None
if _has_ceph_block(raw_config_parsed):
- ceph_block = raw_config_parsed[1]
- self.export_conf_objs.append(
+ ceph_block = raw_config_parsed['CEPH']
+ if _has_log_block(raw_config_parsed):
+ log_block = raw_config_parsed['LOG']
+ self.export_conf_objs.append(
GaneshaExport(Export.from_export_block(export_block, rados_namespace),
- CephBlock.from_ceph_block(ceph_block)))
- else:
- self.export_conf_objs.append(
- GaneshaExport(Export.from_export_block(export_block, rados_namespace)))
+ CephBlock.from_ceph_block(ceph_block),
+ LogBlock.from_log_block(log_block)))
def _save_export(self, cluster_id: str, ganesha_export: GaneshaExport) -> None:
log.debug('in _save_export')
log.debug(f'raw_config: {raw_config}')
raw_config_parsed = GaneshaConfParser(raw_config).parse()
log.debug(f'raw_config_parsed: {raw_config_parsed}')
- export_block = raw_config_parsed[0]
- # do we have a ceph block?
+ export_block = raw_config_parsed['EXPORT']
+ # do we have a ceph/log block? (optional)
+ ceph_block = None
+ log_block = None
if _has_ceph_block(raw_config_parsed):
- ceph_block = raw_config_parsed[1]
- export = GaneshaExport(Export.from_export_block(export_block, cluster_id),
- CephBlock.from_ceph_block(ceph_block))
- else:
- export = GaneshaExport(Export.from_export_block(export_block, cluster_id))
+ ceph_block = raw_config_parsed['CEPH']
+ if _has_log_block(raw_config_parsed):
+ log_block = raw_config_parsed['LOG']
+ self.export_conf_objs.append(
+ GaneshaExport(Export.from_export_block(export_block, rados_namespace),
+ CephBlock.from_ceph_block(ceph_block),
+ LogBlock.from_log_block(log_block)))
log.debug(f'export: {export}')
return export
except ObjectNotFound:
def _change_export(self, cluster_id: str, export: Dict,
earmark_resolver: Optional[CephFSEarmarkResolver] = None) -> Dict[str, Any]:
- # if the export json has a ceph section (key), extract it from the export
+ # if the export json has a ceph/log section (key), extract it from the export
# json to preserver backward compatability.
ceph_dict = {}
+ log_dict = {}
if "ceph" in export.keys():
ceph_dict = export.pop("ceph")
- if not "export" in export.keys():
- raise Exception('\'export\' key missing in export json')
+ if "log" in export.keys():
+ log_dict = export.pop("log")
+ if "export" in export.keys():
export = export.pop("export")
msg = f'export_dict: {export}'
log.exception(msg)
msg = f'ceph_dict: {ceph_dict}'
log.exception(msg)
+ msg = f'log_dict: {log_dict}'
+ log.exception(msg)
try:
- return self._apply_export(cluster_id, export, earmark_resolver, ceph_dict)
+ return self._apply_export(cluster_id, export, earmark_resolver, ceph_dict, log_dict)
except NotImplementedError as e:
# in theory, the NotImplementedError here may be raised by a hook back to
# an orchestration module. If the orchestration module supports it the NFS
cluster_id: str,
new_export_dict: Dict,
earmark_resolver: Optional[CephFSEarmarkResolver] = None,
- ceph_dict: Optional[Dict] = {}) -> Dict[str, str]:
+ ceph_dict: Optional[Dict] = {},
+ log_dict: Optional[Dict] = {}) -> Dict[str, str]:
for k in ['path', 'pseudo']:
if k not in new_export_dict:
raise NFSInvalidOperation(f'Export missing required field {k}')
log.debug(f'ceph_dict: {ceph_dict}')
if ceph_dict:
ceph_block = CephBlock.from_dict(ceph_dict)
+ log_block = None
+ log.debug(f'log_dict: {log_dict}')
+ if log_dict:
+ log_block = LogBlock.from_dict(log_dict)
# use @ganesha_export in place of @new_export here onwards
- ganesha_export = GaneshaExport(new_export, ceph_block)
+ ganesha_export = GaneshaExport(new_export, ceph_block, log_block)
if not old_export:
if new_export.fsal.name == NFS_GANESHA_SUPPORTED_FSALS[1]: # only for RGW
and old_fsal.fs_name == new_fsal.fs_name
and old_export.path == new_export.path
and old_export.pseudo == new_export.pseudo
- and old_export.ceph_block == ganesha_export.ceph_block)
+ and old_export.ceph_block == ganesha_export.ceph_block
+ and old_export.log_block == ganesha_export.log_block)
if old_export.fsal.name == NFS_GANESHA_SUPPORTED_FSALS[1]:
old_rgw_fsal = cast(RGWFSAL, old_export.fsal)
value = self.stream()[:idx]
self.pos += idx + 1
block_dict = RawBlock('%url', values={'value': value})
- return block_dict
+ return ('%url', block_dict)
- block_dict = RawBlock(self.parse_block_name().upper())
+ block_name = self.parse_block_name().upper()
+ block_dict = RawBlock(block_name)
self.parse_block_body(block_dict)
if self.stream()[0] != '}':
raise Exception("No closing bracket '}' found at the end of block")
self.pos += 1
- return block_dict
+ return (block_name, block_dict)
def parse_parameter_value(self, raw_value: str) -> Any:
if raw_value.find(',') != -1:
self.parse_stanza(block_dict)
elif is_lbracket and ((is_semicolon and not is_semicolon_lt_lbracket)
or (not is_semicolon)):
- block_dict.blocks.append(self.parse_block_or_section())
+ block_dict.blocks.append(self.parse_block_or_section()[1])
else:
raise Exception("Malformed stanza: no semicolon found.")
raise Exception("Infinite loop while parsing block content")
def parse(self) -> List[RawBlock]:
- blocks = []
+ blocks = {}
while self.stream():
- blocks.append(self.parse_block_or_section())
+ (block_name, block) = self.parse_block_or_section()
+ blocks[block_name] = block
return blocks
return result
@classmethod
- def from_dict(cls, ex_dict: Dict[str, Any]) -> 'Export':
+ def from_dict(cls, ex_dict: Dict[str, Any]) -> 'CephBlock':
return cls(ex_dict.get('async', False),
ex_dict.get('zerocopy', False))
return False
return self.to_dict() == other.to_dict()
+class Facility:
+ def __init(self,
+ name: str,
+ destination: str,
+ enable: str):
+ self.name = name
+ self.destination = destination
+ self.enable = enable
+
+ @classmethod
+ def from_facility_block(cls, facility: RawBlock) -> 'Facility':
+ return cls(facility.values['name'],
+ facility.values['destination'], facility.values['enable'])
+
+ def to_facility_block(self) -> RawBlock:
+ result = RawBlock("FACILITY", values={'name': self.name,
+ 'destination': self.destination,
+ 'enable': self.enable})
+ return result
+
+ @classmethod
+ def from_dict(cls, ex_dict: Dict[str, Any]) -> 'Facility':
+ return cls(ex_dict['name'], ex_dict['destination'], ex_dict['enable'])
+
+ def to_dict(self) -> Dict[str, Any]:
+ values = {
+ 'name': self.name,
+ 'destination': self.destination,
+ 'enable': self.enable
+ }
+ return values
+
+ def __eq__(self, other: Any) -> bool:
+ if not isinstance(other, Facility):
+ return False
+ return self.to_dict() == other.to_dict()
+
+class Components:
+ def __init(self,
+ fsal: str,
+ nfsv4: str):
+ self.fsal = fsal
+ self.nfsv4 = nfsv4
+
+ @classmethod
+ def from_components_block(cls, components: RawBlock) -> 'Components':
+ return cls(components.values['fsal'], components.values['nfsv4'])
+
+ def to_components_block(self) -> RawBlock:
+ result = RawBlock("COMPONENTS", values={'fsal': self.fsal, 'nfsv4': self.nfsv4})
+ return result
+
+ @classmethod
+ def from_dict(cls, ex_dict: Dict[str, Any]) -> 'Components':
+ return cls(ex_dict['fsal'], ex_dict['nfsv4'])
+
+ def to_dict(self) -> Dict[str, Any]:
+ values = {
+ 'fsal': self.fsal,
+ 'nfsv4': self.nfsv4
+ }
+ return values
+
+ def __eq__(self, other: Any) -> bool:
+ if not isinstance(other, Components):
+ return False
+ return self.to_dict() == other.to_dict()
+
+class LogBlock:
+ def __init__(self,
+ default_log_level: str,
+ components: Components,
+ facility: Facility):
+ self.default_log_level = default_log_level
+ self.components = components
+ self.facility = facility
+
+ @classmethod
+ def from_log_block(cls, log_block: RawBlock) -> 'LogBlock':
+ return cls(log_block.values.get('default_log_level', None),
+ Components.from_components_block(self.components),
+ Facility.from_facility_block(self.facility))
+
+ def to_log_block(self) -> RawBlock:
+ result = RawBlock("LOG", values={'default_log_level': self.default_log_level})
+ result.blocks = [
+ self.components.to_components_block()
+ ] + [
+ self.facility.to_facility_block()
+ ]
+ return result
+
+ @classmethod
+ def from_dict(cls, ex_dict: Dict[str, Any]) -> 'LogBlock':
+ return cls(ex_dict['default_log_level'],
+ Components.from_dict(ex_dict['components']),
+ Facility.fron_dict(ex_dict['facility']))
+
+ def to_dict(self) -> Dict[str, Any]:
+ values = {
+ 'default_log_level': self.default_log_level,
+ 'components': self.components.to_dict(),
+ 'facility': self.facility.to_dict()
+ }
+ return values
+
+ def __eq__(self, other: Any) -> bool:
+ if not isinstance(other, LogBlock):
+ return False
+ return self.to_dict() == other.to_dict()
+
class Export:
def __init__(
self,