Repository: NVIDIA/NVFlare

Issue:
[BUG] Preflight check - server attempts to bind to DNS name instead of localhost
**Describe the bug**
When running the preflight_check on a provisioned server startup kit downloaded from the dashboard, the server attempts (and files) to bind its grpc and admin ports to the server DNS name rather than binding to localhost.

This happens when the DNS name configured for the server is to a load balancer rather than the server machine directly (have not tested whether it happens without a load balancer).

A workaround is to modify the /etc/hosts file on this machine to map 0.0.0.0 to the server DNS name.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to dashboard
2. Log in or register as an Org Admin
3. Enter project configuration and application configuration
4. Go to Server Configuration
5. Enter the Server DNS name as the load balancer DNS name
6. Enable HA and enter an Overseer DNS name
7. Go to Project Home and Freeze the project
8. Go to Downloads and download the overseer and server startup kits
9. Launch the overseer kit using `./overseer/startup/start.sh`
10. Run the preflight_check on the server using `nvflare preflight_check -p server/`
11. Observe the errors in "check grpc port binding" and "check admin port binding": `Can't bind to address (address:8003): [Errno 99] Cannot assign requested address`
12. Launch the server startup kit using `./server/startup/start.sh`
13. Observe the server runs successfully
14. (Optional) Modify the server/startup/fed_server.json and replace the hostname occurrences under `servers[0].service.target` and `server[0].admin_host` with "0.0.0.0" or "localhost" -- the preflight check will now pass but the dry run/actual execution of the startup kit will understandably complain that the fed_server.json file has been modified
15. Edit the /etc/hosts file to add a mapping of the DNS name to localhost using `echo '0.0.0.0 server.hostname' >> /etc/hosts`
16. Observe the preflight_check now passes

**Expected behavior**
The preflight check should pass on a freshly downloaded server startup kit without needing to manually modify the fed_server.json or /etc/hosts file.

**Screenshots**
```
Checking Package: server
-------------------------------------------------------------------------------------------------------------------------------------------------------
| Checks                          | Problems                                                                         | How to fix                     |
|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| Check overseer running          | PASSED                                                                           | N/A                            |
|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| Check grpc port binding         | Can't bind to address                                                            | Please check the DNS and port. |
|                                 | (server.hostname:8003): [Errno 99] Cannot assign requested address               |                                |
|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| Check admin port binding        | Can't bind to address                                                            | Please check the DNS and port. |
|                                 | (server.hostname:8003): [Errno 99] Cannot assign requested address               |                                |
|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| Check snapshot storage writable | PASSED                                                                           | N/A                            |
|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| Check job storage writable      | PASSED                                                                           | N/A                            |
-------------------------------------------------------------------------------------------------------------------------------------------------------
```

**Desktop (please complete the following information):**
 - OS: 20.04
 - Python Version: 3.8.12
 - NVFlare Version: 2.2.1

**Additional context**
- Using startup kits downloaded from the dashboard on the latest nvflare/nvflare image, launched with `nvflare dashboard -p 8008 --start`
- The DNS name we're using is for a load balancer in front of the server rather than for the server machine itself



Discussion:
@parkeraddison  thanks for reporting, we will take a look. @YuanTingHsieh, can you check this ? 
Thanks for the good report. 
The suggestion makes sense to me.
I will work on this.
Fixed in #1234 

Resolving patch:
diff --git a/nvflare/tool/package_checker/package_checker.py b/nvflare/tool/package_checker/package_checker.py
--- a/nvflare/tool/package_checker/package_checker.py
+++ b/nvflare/tool/package_checker/package_checker.py
@@ -39,7 +39,7 @@ def init_rules(self, package_path: str):
     def init(self, package_path: str):
         if not os.path.exists(package_path):
             raise RuntimeError(f"Package path: {package_path} does not exist.")
-        self.package_path = package_path
+        self.package_path = os.path.abspath(package_path)
         self.init_rules(package_path)
 
     @abstractmethod
@@ -54,8 +54,8 @@ def get_dry_run_command(self) -> str:
     def stop_dry_run(self, force: bool = True):
         # todo: add gracefully shutdown command, currently
         print("killing dry run process")
-
-        cmd = f"pkill -9 -f '{self.package_path}'"
+        command = self.get_dry_run_command()
+        cmd = f"pkill -9 -f '{command}'"
         process = run_command_in_subprocess(cmd)
         process.wait()
 
diff --git a/nvflare/tool/package_checker/server_package_checker.py b/nvflare/tool/package_checker/server_package_checker.py
--- a/nvflare/tool/package_checker/server_package_checker.py
+++ b/nvflare/tool/package_checker/server_package_checker.py
@@ -54,19 +54,19 @@ def _get_job_storage_root(package_path: str) -> str:
     return job_storage_root
 
 
-def _get_grpc_host_and_port(package_path: str):
+def _get_grpc_host_and_port(package_path: str) -> (str, int):
     fed_config = _get_server_fed_config(package_path)
     server_conf = fed_config["servers"][0]
     grpc_service_config = server_conf["service"]
     grpc_target_address = grpc_service_config["target"]
-    host, port = grpc_target_address.split(":")
-    return host, int(port)
+    _, port = grpc_target_address.split(":")
+    return "localhost", int(port)
 
 
-def _get_admin_host_and_port(package_path: str):
+def _get_admin_host_and_port(package_path: str) -> (str, int):
     fed_config = _get_server_fed_config(package_path)
     server_conf = fed_config["servers"][0]
-    return server_conf["admin_host"], int(server_conf["admin_port"])
+    return "localhost", int(server_conf["admin_port"])
 
 
 class ServerPackageChecker(PackageChecker):
@@ -103,8 +103,8 @@ def get_dry_run_command(self) -> str:
         self.job_storage_root = _get_job_storage_root(self.package_path)
         return command
 
-    def stop_dry_run(self):
-        super().stop_dry_run()
+    def stop_dry_run(self, force=True):
+        super().stop_dry_run(force=force)
         if os.path.exists(self.snapshot_storage_root):
             shutil.rmtree(self.snapshot_storage_root)
         if os.path.exists(self.job_storage_root):


Test patch: