# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""nvflare deploy subcommands."""
import argparse
import sys
from typing import Optional
from nvflare.tool.cli_output import output_usage_error
from nvflare.tool.cli_schema import handle_schema_flag
_deploy_root_parser: Optional[argparse.ArgumentParser] = None
_deploy_prepare_parser: Optional[argparse.ArgumentParser] = None
_deploy_k8_parser: Optional[argparse.ArgumentParser] = None
_deploy_k8_stage_parser: Optional[argparse.ArgumentParser] = None
_DEPLOY_PREPARE_EXAMPLES = [
"nvflare deploy prepare ./site-1",
"nvflare deploy prepare ./site-1 --output ./site-1-docker --config docker.yaml",
"nvflare deploy prepare ./site-1 --output ./site-1-k8s --config k8s.yaml",
]
_DEPLOY_K8_STAGE_EXAMPLES = [
"nvflare deploy k8 stage ./site-1-k8s --namespace nvflare",
"nvflare deploy k8 stage ./server-k8s --namespace nvflare --local-configmap server-local",
"nvflare deploy k8 stage ./site-1-k8s --startup-secret site-1-startup",
]
_DEPLOY_K8_STAGE_KUBECTL_CHOICES = ("kubectl", "oc")
[docs]
def def_deploy_cli_parser(sub_cmd) -> dict:
"""Register 'nvflare deploy' with the top-level sub_cmd parser."""
global _deploy_root_parser, _deploy_prepare_parser, _deploy_k8_parser, _deploy_k8_stage_parser
cmd = "deploy"
parser = sub_cmd.add_parser(cmd, help="prepare startup kits for deployment runtimes")
_deploy_root_parser = parser
deploy_subparser = parser.add_subparsers(title="deploy subcommands", metavar="", dest="deploy_sub_cmd")
prepare_parser = deploy_subparser.add_parser(
"prepare",
description="Prepare an existing server/client startup kit for Docker or Kubernetes.",
help="prepare a startup kit for Docker or Kubernetes",
)
prepare_parser.add_argument("kit", nargs="?", help="Existing input startup kit directory.")
prepare_parser.add_argument("--kit", dest="kit_flag", help="Existing input startup kit directory.")
prepare_parser.add_argument(
"--output",
help="Directory to write the prepared startup kit copy. Defaults to <kit>/prepared/<runtime>.",
)
prepare_parser.add_argument(
"--config",
help="YAML runtime config file with top-level runtime: docker or runtime: k8s. Defaults to <kit>/config.yaml.",
)
prepare_parser.add_argument("--schema", action="store_true", help="print command schema as JSON and exit")
_deploy_prepare_parser = prepare_parser
k8_parser = deploy_subparser.add_parser(
"k8",
aliases=["k8s"],
description="Kubernetes deployment helper commands.",
help="Kubernetes deployment helpers",
)
_deploy_k8_parser = k8_parser
k8_subparser = k8_parser.add_subparsers(title="k8 subcommands", metavar="", dest="deploy_k8_sub_cmd")
stage_parser = k8_subparser.add_parser(
"stage",
description=(
"Create Kubernetes ConfigMap/Secret resources for a prepared kit's local/startup folders "
"and patch the generated Helm chart to mount them."
),
help="stage local/startup as Kubernetes ConfigMap/Secret",
)
stage_parser.add_argument("kit", nargs="?", help="Prepared Kubernetes startup kit directory.")
stage_parser.add_argument("--kit", dest="kit_flag", help="Prepared Kubernetes startup kit directory.")
stage_parser.add_argument(
"--namespace",
help="Kubernetes namespace for the ConfigMap and Secret. Defaults to the prepared launcher namespace.",
)
stage_parser.add_argument(
"--local-configmap",
help="ConfigMap name for the prepared local/ folder. Defaults to nvflare-local-<site>.",
)
stage_parser.add_argument(
"--startup-secret",
help="Secret name for the prepared startup/ folder. Defaults to nvflare-startup-<site>.",
)
stage_parser.add_argument(
"--kubectl",
choices=_DEPLOY_K8_STAGE_KUBECTL_CHOICES,
help="Kubernetes CLI command used for apply. Defaults to the KUBECTL environment variable or kubectl.",
)
stage_parser.add_argument("--schema", action="store_true", help="print command schema as JSON and exit")
_deploy_k8_stage_parser = stage_parser
return {cmd: parser}
[docs]
def handle_deploy_cmd(args):
sub_cmd = getattr(args, "deploy_sub_cmd", None)
if sub_cmd == "prepare":
handle_schema_flag(_deploy_prepare_parser, "nvflare deploy prepare", _DEPLOY_PREPARE_EXAMPLES, sys.argv[1:])
from nvflare.tool.deploy.deploy_commands import prepare_deployment
prepare_deployment(args)
return
if sub_cmd in {"k8", "k8s"}:
if getattr(args, "deploy_k8_sub_cmd", None) == "stage":
handle_schema_flag(
_deploy_k8_stage_parser,
"nvflare deploy k8 stage",
_DEPLOY_K8_STAGE_EXAMPLES,
sys.argv[1:],
)
from nvflare.tool.deploy.deploy_commands import stage_k8_deployment
stage_k8_deployment(args)
return
output_usage_error(_deploy_k8_parser, "deploy k8 subcommand required", exit_code=4)
raise SystemExit(4)
output_usage_error(_deploy_root_parser, "deploy subcommand required", exit_code=4)
raise SystemExit(4)