return cls(ctx, fsid, daemon_id,
fetch_configs(ctx), ctx.image)
+ def _get_tls_cert_key_mounts(
+ self, data_dir: str, files: Dict[str, str]
+ ) -> Dict[str, str]:
+ mounts = dict()
+ for fn in ['server_cert', 'server_key', 'client_cert', 'client_key']:
+ if fn in files:
+ mounts[
+ os.path.join(data_dir, fn)
+ ] = f'/{fn.replace("_", ".")}'
+ return mounts
+
@staticmethod
def get_container_mounts(data_dir: str, log_dir: str, mtls_dir: Optional[str] = None) -> Dict[str, str]:
mounts = dict()
mounts.update(CephNvmeof.get_container_mounts(data_dir, log_dir, mtls_dir=mtls_dir))
else:
mounts.update(CephNvmeof.get_container_mounts(data_dir, log_dir))
+ ceph_nvmeof = CephNvmeof.init(ctx, fsid, daemon_id)
+ mounts.update(ceph_nvmeof._get_tls_cert_key_mounts(data_dir, ceph_nvmeof.files))
if daemon_type == CephIscsi.daemon_type:
assert daemon_id
##################################
+@infer_config
+def command_sos(ctx: CephadmContext):
+ """
+ Execute the sos command
+ returns the pattern of the sos report part files generated
+ in the LOG_DIR folder
+
+ To avoid fill the disk, each execution deletes all previous sos report files
+
+ The original compressed file can be rebuild using:
+ # cat /var/log/ceph/<cluster_fsid>/sosreport* > /tmp/sosreport_case_<xx>.tar.xz
+ """
+ def remove_files(folder: str, pattern: str) -> None:
+ file_path = ""
+ try:
+ for file_path in filter(os.path.isfile, glob(os.path.join(folder, pattern))):
+ os.remove(file_path)
+ except Exception as ex:
+ logger.error(f'Error removing file {file_path}: {ex}')
+
+ result = 1 # error by default, will be changed if everything ok
+ try:
+ # get silently the cluster fsid
+ cp = read_config(ctx.config)
+ if cp.has_option('global', 'fsid'):
+ fsid = cp.get('global', 'fsid')
+ else:
+ raise Exception('Cannot infer Ceph cluster fsid .SOS report command'
+ ' aborted')
+
+ # sos report execution
+ cmd_sos = ['sos'] + ctx.parameters
+ out, err, code = call(ctx, cmd_sos, verbosity=CallVerbosity.DEBUG)
+ if (err or code):
+ if out:
+ # even with errors a sos file can be generated
+ # inform about the issue and continue trying to get the file
+ print(f'Issue executing <{cmd_sos}>: {code}:{err}')
+ else:
+ raise Exception(f'Error executing command <{cmd_sos}>:{code}-{err}')
+
+ file_path_pattern = r'Your sosreport has been generated and saved in:\s+(\S+)'
+ match = re.search(file_path_pattern, out)
+ if not match:
+ raise Exception(f'Cannot locate sos report file in sos command <{cmd_sos}> output: {out}')
+
+ sos_file = match.group(1)
+ sos_file_extension = os.path.splitext(sos_file)[1]
+ timestamp_sos_file = int(time.time() * 1000)
+ if '--case-id' in ctx.parameters:
+ case_id = ctx.parameters[ctx.parameters.index('--case-id') + 1]
+ else:
+ case_id = 'unknown_case_id'
+ prefix = f'sosreport_case_{case_id}_{timestamp_sos_file}_'
+ suffix = f'{sos_file_extension}_part'
+ sos_report_parts_folder = f'{LOG_DIR}/{fsid}'
+
+ # remove previous part files
+ remove_files(sos_report_parts_folder, 'sosreport*')
+
+ # split sos report file in <sos_files_number> parts (10 by default)
+ os.chdir(sos_report_parts_folder)
+ split_cmd = ['split', '-n', f'{ctx.sos_files_number}', sos_file, prefix, '--additional-suffix', suffix]
+ out, err, code = call(ctx, split_cmd, verbosity=CallVerbosity.DEBUG)
+ if err or code:
+ raise Exception(f'Error splitting sos report file: <{out}>')
+
+ # remove source sos report (because we already have the
+ # parts in the logs folder)
+ remove_files(os.path.dirname(sos_file), 'sosreport*')
+ # show the info needed to know what are the last sos files
+ print(f'New sos report files can be found in {LOG_DIR}/<fsid>/{prefix}*')
+
+ # If a target provided copy the sos report files to the
+ # destination host
+ if ctx.mgr_target:
+ scp_cmd = f'scp {sos_report_parts_folder}/{prefix}* {ctx.mgr_target}:{sos_report_parts_folder} > /dev/null 2>&1'
+ try:
+ os.system(scp_cmd)
+ except Exception as ex:
+ logger.error(f'Error copying sos files to target: {ex}')
+ return 1
+
+ # everything was ok
+ result = 0
+
+ except Exception as ex:
+ logger.error(f'Failed to execute sos command <{cmd_sos}>:\n {ex}')
+
+ return result
+
+##################################
+
def systemd_target_state(ctx: CephadmContext, target_name: str, subsystem: str = 'ceph') -> bool:
# TODO: UNITTEST
#: ``enable_auth`` enables user authentication on nvmeof gateway
self.enable_auth = enable_auth
#: ``server_key`` gateway server key
- self.server_key = server_key or './server.key'
+ self.server_key = server_key
#: ``server_cert`` gateway server certificate
- self.server_cert = server_cert or './server.crt'
+ self.server_cert = server_cert
#: ``client_key`` client key
- self.client_key = client_key or './client.key'
+ self.client_key = client_key
#: ``client_cert`` client certificate
- self.client_cert = client_cert or './client.crt'
+ self.client_cert = client_cert
#: ``spdk_path`` path to SPDK
self.spdk_path = spdk_path or '/usr/local/bin/nvmf_tgt'
#: ``tgt_path`` nvmeof target path
raise SpecValidationError('Cannot add NVMEOF: No Pool specified')
if self.enable_auth:
- if not any([self.server_key, self.server_cert, self.client_key, self.client_cert]):
+ if not all([self.server_key, self.server_cert, self.client_key, self.client_cert]):
raise SpecValidationError(
'enable_auth is true but client/server certificates are missing')