diff options
-rwxr-xr-x | qa/workunits/cephadm/test_cephadm.sh | 32 | ||||
-rw-r--r-- | src/cephadm/CMakeLists.txt | 8 | ||||
-rwxr-xr-x | src/cephadm/build.py | 41 | ||||
-rwxr-xr-x | src/cephadm/cephadm.py | 44 |
4 files changed, 103 insertions, 22 deletions
diff --git a/qa/workunits/cephadm/test_cephadm.sh b/qa/workunits/cephadm/test_cephadm.sh index cca9cbc7bbc..fcb4aa1c60f 100755 --- a/qa/workunits/cephadm/test_cephadm.sh +++ b/qa/workunits/cephadm/test_cephadm.sh @@ -29,9 +29,16 @@ CEPHADM_SAMPLES_DIR=${CEPHADM_SRC_DIR}/samples [ -z "$SUDO" ] && SUDO=sudo +# If cephadm is already installed on the system, use that one, avoid building +# # one if we can. +if [ -z "$CEPHADM" ] && command -v cephadm >/dev/null ; then + CEPHADM="$(command -v cephadm)" +fi + if [ -z "$CEPHADM" ]; then CEPHADM=`mktemp -p $TMPDIR tmp.cephadm.XXXXXX` ${CEPHADM_SRC_DIR}/build.sh "$CEPHADM" + NO_BUILD_INFO=1 fi # at this point, we need $CEPHADM set @@ -162,17 +169,20 @@ $SUDO $CEPHADM check-host ## run a gather-facts (output to stdout) $SUDO $CEPHADM gather-facts -## version + --image -$SUDO CEPHADM_IMAGE=$IMAGE_PACIFIC $CEPHADM_BIN version -$SUDO CEPHADM_IMAGE=$IMAGE_PACIFIC $CEPHADM_BIN version \ - | grep 'ceph version 16' -#$SUDO CEPHADM_IMAGE=$IMAGE_OCTOPUS $CEPHADM_BIN version -#$SUDO CEPHADM_IMAGE=$IMAGE_OCTOPUS $CEPHADM_BIN version \ -# | grep 'ceph version 15' -$SUDO $CEPHADM_BIN --image $IMAGE_MAIN version | grep 'ceph version' - -# try force docker; this won't work if docker isn't installed -systemctl status docker > /dev/null && ( $CEPHADM --docker version | grep 'ceph version' ) || echo "docker not installed" +## NOTE: cephadm version is, as of around May 2023, no longer basing the +## output for `cephadm version` on the version of the containers. The version +## reported is that of the "binary" and is determined during the ceph build. +## `cephadm version` should NOT require sudo/root. +$CEPHADM_BIN version +$CEPHADM_BIN version | grep 'cephadm version' +# Typically cmake should be running the cephadm build script with CLI arguments +# that embed version info into the "binary". If not using a cephadm build via +# cmake you can set `NO_BUILD_INFO` to skip this check. +if [ -z "$NO_BUILD_INFO" ]; then + $CEPHADM_BIN version | grep -v 'UNSET' + $CEPHADM_BIN version | grep -v 'UNKNOWN' +fi + ## test shell before bootstrap, when crash dir isn't (yet) present on this host $CEPHADM shell --fsid $FSID -- ceph -v | grep 'ceph version' diff --git a/src/cephadm/CMakeLists.txt b/src/cephadm/CMakeLists.txt index fdb7c9881fa..8b969bc33e7 100644 --- a/src/cephadm/CMakeLists.txt +++ b/src/cephadm/CMakeLists.txt @@ -11,7 +11,13 @@ add_custom_command( ${CMAKE_CURRENT_SOURCE_DIR}/cephadm.py ${CMAKE_CURRENT_SOURCE_DIR}/build.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND ${Python3_EXECUTABLE} build.py ${bin_target_file} + COMMAND ${Python3_EXECUTABLE} build.py + --set-version-var=CEPH_GIT_VER=${CEPH_GIT_VER} + --set-version-var=CEPH_GIT_NICE_VER=${CEPH_GIT_NICE_VER} + --set-version-var=CEPH_RELEASE=${CEPH_RELEASE} + --set-version-var=CEPH_RELEASE_NAME=${CEPH_RELEASE_NAME} + --set-version-var=CEPH_RELEASE_TYPE=${CEPH_RELEASE_TYPE} + ${bin_target_file} ) add_custom_target(cephadm ALL diff --git a/src/cephadm/build.py b/src/cephadm/build.py index 39c93ce3b30..4264b814f1e 100755 --- a/src/cephadm/build.py +++ b/src/cephadm/build.py @@ -27,6 +27,15 @@ except ImportError: log = logging.getLogger(__name__) +_VALID_VERS_VARS = [ + "CEPH_GIT_VER", + "CEPH_GIT_NICE_VER", + "CEPH_RELEASE", + "CEPH_RELEASE_NAME", + "CEPH_RELEASE_TYPE", +] + + def _reexec(python): """Switch to the selected version of python by exec'ing into the desired python path. @@ -45,7 +54,7 @@ def _did_rexec(): return bool(os.environ.get("_BUILD_PYTHON_SET", "")) -def _build(dest, src): +def _build(dest, src, versioning_vars=None): """Build the binary.""" os.chdir(src) tempdir = pathlib.Path(tempfile.mkdtemp(suffix=".cephadm.build")) @@ -61,6 +70,8 @@ def _build(dest, src): # dir to be zipped. For now we just have a simple call to copy # (and rename) the one file we care about. shutil.copy("cephadm.py", tempdir / "__main__.py") + if versioning_vars: + generate_version_file(versioning_vars, tempdir / "_version.py") _compile(dest, tempdir) finally: shutil.rmtree(tempdir) @@ -115,6 +126,24 @@ def _install_deps(tempdir): ) +def generate_version_file(versioning_vars, dest): + log.info("Generating version file") + log.debug("versioning_vars=%r", versioning_vars) + with open(dest, "w") as fh: + print("# GENERATED FILE -- do not edit", file=fh) + for key, value in versioning_vars: + print(f"{key} = {value!r}", file=fh) + + +def version_kv_pair(value): + if "=" not in value: + raise argparse.ArgumentTypeError(f"not a key=value pair: {value!r}") + key, value = value.split("=", 1) + if key not in _VALID_VERS_VARS: + raise argparse.ArgumentTypeError(f"Unexpected key: {key!r}") + return key, value + + def main(): handler = logging.StreamHandler(sys.stdout) handler.setFormatter(logging.Formatter("cephadm/build.py: %(message)s")) @@ -132,6 +161,14 @@ def main(): parser.add_argument( "--python", help="The path to the desired version of python" ) + parser.add_argument( + "--set-version-var", + "-S", + type=version_kv_pair, + dest="version_vars", + action="append", + help="Set a key=value pair in the generated version info file", + ) args = parser.parse_args() if not _did_rexec() and args.python: @@ -160,7 +197,7 @@ def main(): dest = pathlib.Path(args.dest).absolute() log.info("Source Dir: %s", source) log.info("Destination Path: %s", dest) - _build(dest, source) + _build(dest, source, versioning_vars=args.version_vars) if __name__ == "__main__": diff --git a/src/cephadm/cephadm.py b/src/cephadm/cephadm.py index 3500f8b5e39..15fb31377e3 100755 --- a/src/cephadm/cephadm.py +++ b/src/cephadm/cephadm.py @@ -2296,6 +2296,16 @@ def default_image(func: FuncT) -> FuncT: return cast(FuncT, _default_image) +def executes_early(func: FuncT) -> FuncT: + """Decorator that indicates the command function is meant to have no + dependencies and no environmental requirements and can therefore be + executed as non-root and with no logging, etc. Commands that have this + decorator applied must be simple and self-contained. + """ + cast(Any, func)._execute_early = True + return func + + def get_container_info(ctx: CephadmContext, daemon_filter: str, by_name: bool) -> Optional[ContainerInfo]: """ :param ctx: Cephadm context @@ -4850,15 +4860,24 @@ def command_agent(ctx: CephadmContext) -> None: ################################## - -@infer_image +@executes_early def command_version(ctx): # type: (CephadmContext) -> int - c = CephContainer(ctx, ctx.image, 'ceph', ['--version']) - out, err, ret = call(ctx, c.run_cmd(), desc=c.entrypoint) - if not ret: - print(out.strip()) - return ret + import importlib + + try: + vmod = importlib.import_module('_version') + except ImportError: + print('cephadm version UNKNOWN') + return 1 + _unset = '<UNSET>' + print('cephadm version {0} ({1}) {2} ({3})'.format( + getattr(vmod, 'CEPH_GIT_NICE_VER', _unset), + getattr(vmod, 'CEPH_GIT_VER', _unset), + getattr(vmod, 'CEPH_RELEASE_NAME', _unset), + getattr(vmod, 'CEPH_RELEASE_TYPE', _unset), + )) + return 0 ################################## @@ -9427,7 +9446,7 @@ def _get_parser(): subparsers = parser.add_subparsers(help='sub-command') parser_version = subparsers.add_parser( - 'version', help='get ceph version from container') + 'version', help='get cephadm version') parser_version.set_defaults(func=command_version) parser_pull = subparsers.add_parser( @@ -10106,6 +10125,15 @@ def main() -> None: sys.stderr.write('No command specified; pass -h or --help for usage\n') sys.exit(1) + if ctx.has_function() and getattr(ctx.func, '_execute_early', False): + try: + sys.exit(ctx.func(ctx)) + except Error as e: + if ctx.verbose: + raise + logger.error('ERROR: %s' % e) + sys.exit(1) + cephadm_require_root() cephadm_init_logging(ctx, av) try: |