We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[BUG]  'env_activate_cmd' referenced before assignment when using mlflow models build-docker --env-manager=local
### Willingness to contribute

Yes. I can contribute a fix for this bug independently.

### MLflow version

1.26.1

### System information

- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: Archlinux
- **Python version**: 3.9.9




### Describe the problem

I have a very tiny mlflow pyfunc model which I can build into a docker using
```bash
mlflow models build-docker --model-uri 'models:/predict_service/latest' --enable-mlserver --name predict_service
```
When using `--env-manager=local`, I get a Python error saying:

```bash
  2022/06/10 10:00:47 INFO mlflow.models.container: creating and activating custom environment
  Traceback (most recent call last):
    File "<string>", line 1, in <module>
    File "/usr/local/lib/python3.7/dist-packages/mlflow/models/container/__init__.py", line 124, in _install_pyfunc_deps
      activate_cmd = [env_activate_cmd] if has_env else []
  UnboundLocalError: local variable 'env_activate_cmd' referenced before assignment
```
Which refers to https://github.com/mlflow/mlflow/blob/master/mlflow/models/container/__init__.py#L124 where indeed the variable is reference before assignment.


### Tracking information

_No response_

### Code to reproduce issue

mlflow models build-docker --model-uri 'models:/predict_service/latest' --enable-mlserver --name predict_service --env-manager=local

### Other info / logs

_No response_

### What component(s) does this bug affect?

- [ ] `area/artifacts`: Artifact stores and artifact logging
- [X] `area/build`: Build and test infrastructure for MLflow
- [ ] `area/docs`: MLflow documentation pages
- [ ] `area/examples`: Example code
- [ ] `area/model-registry`: Model Registry service, APIs, and the fluent client calls for Model Registry
- [ ] `area/models`: MLmodel format, model serialization/deserialization, flavors
- [ ] `area/projects`: MLproject format, project running backends
- [ ] `area/scoring`: MLflow Model server, model deployment tools, Spark UDFs
- [ ] `area/server-infra`: MLflow Tracking server backend
- [ ] `area/tracking`: Tracking Service, tracking client APIs, autologging

### What interface(s) does this bug affect?

- [ ] `area/uiux`: Front-end, user experience, plotting, JavaScript, JavaScript dev server
- [ ] `area/docker`: Docker use across MLflow's components, such as MLflow Projects and MLflow Models
- [ ] `area/sqlalchemy`: Use of SQLAlchemy in the Tracking Service or Model Registry
- [ ] `area/windows`: Windows support

### What language(s) does this bug affect?

- [ ] `language/r`: R APIs and clients
- [ ] `language/java`: Java APIs and clients
- [ ] `language/new`: Proposals for new client languages

### What integration(s) does this bug affect?

- [ ] `integrations/azure`: Azure and Azure ML integrations
- [ ] `integrations/sagemaker`: SageMaker integrations
- [ ] `integrations/databricks`: Databricks integrations

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mlflow/models/container/__init__.py`
Content:
```
1 """
2 Initialize the environment and start model serving in a Docker container.
3 
4 To be executed only during the model deployment.
5 
6 """
7 import multiprocessing
8 import os
9 import signal
10 import shutil
11 from subprocess import check_call, Popen
12 import sys
13 import logging
14 
15 from pkg_resources import resource_filename
16 
17 import mlflow
18 import mlflow.version
19 
20 from mlflow import pyfunc, mleap
21 from mlflow.models import Model
22 from mlflow.models.model import MLMODEL_FILE_NAME
23 from mlflow.models.docker_utils import DISABLE_ENV_CREATION
24 from mlflow.pyfunc import scoring_server, mlserver
25 from mlflow.version import VERSION as MLFLOW_VERSION
26 from mlflow.utils import env_manager as em
27 from mlflow.utils.virtualenv import _get_or_create_virtualenv
28 
29 MODEL_PATH = "/opt/ml/model"
30 
31 
32 DEPLOYMENT_CONFIG_KEY_FLAVOR_NAME = "MLFLOW_DEPLOYMENT_FLAVOR_NAME"
33 
34 DEFAULT_SAGEMAKER_SERVER_PORT = 8080
35 DEFAULT_INFERENCE_SERVER_PORT = 8000
36 DEFAULT_NGINX_SERVER_PORT = 8080
37 DEFAULT_MLSERVER_PORT = 8080
38 
39 SUPPORTED_FLAVORS = [pyfunc.FLAVOR_NAME, mleap.FLAVOR_NAME]
40 
41 DISABLE_NGINX = "DISABLE_NGINX"
42 ENABLE_MLSERVER = "ENABLE_MLSERVER"
43 
44 SERVING_ENVIRONMENT = "SERVING_ENVIRONMENT"
45 
46 
47 _logger = logging.getLogger(__name__)
48 
49 
50 def _init(cmd, env_manager):
51     """
52     Initialize the container and execute command.
53 
54     :param cmd: Command param passed by Sagemaker. Can be  "serve" or "train" (unimplemented).
55     """
56     if cmd == "serve":
57         _serve(env_manager)
58     elif cmd == "train":
59         _train()
60     else:
61         raise Exception(
62             "Unrecognized command {cmd}, full args = {args}".format(cmd=cmd, args=str(sys.argv))
63         )
64 
65 
66 def _serve(env_manager):
67     """
68     Serve the model.
69 
70     Read the MLmodel config, initialize the Conda environment if needed and start python server.
71     """
72     model_config_path = os.path.join(MODEL_PATH, MLMODEL_FILE_NAME)
73     m = Model.load(model_config_path)
74 
75     if DEPLOYMENT_CONFIG_KEY_FLAVOR_NAME in os.environ:
76         serving_flavor = os.environ[DEPLOYMENT_CONFIG_KEY_FLAVOR_NAME]
77     else:
78         # Older versions of mlflow may not specify a deployment configuration
79         serving_flavor = pyfunc.FLAVOR_NAME
80 
81     if serving_flavor == mleap.FLAVOR_NAME:
82         _serve_mleap()
83     elif pyfunc.FLAVOR_NAME in m.flavors:
84         _serve_pyfunc(m, env_manager)
85     else:
86         raise Exception("This container only supports models with the MLeap or PyFunc flavors.")
87 
88 
89 def _install_pyfunc_deps(
90     model_path=None, install_mlflow=False, enable_mlserver=False, env_manager=em.CONDA
91 ):
92     """
93     Creates a conda env for serving the model at the specified path and installs almost all serving
94     dependencies into the environment - MLflow is not installed as it's not available via conda.
95     """
96     # If model is a pyfunc model, create its conda env (even if it also has mleap flavor)
97     has_env = False
98     if model_path:
99         model_config_path = os.path.join(model_path, MLMODEL_FILE_NAME)
100         model = Model.load(model_config_path)
101         # NOTE: this differs from _serve cause we always activate the env even if you're serving
102         # an mleap model
103         if pyfunc.FLAVOR_NAME not in model.flavors:
104             return
105         conf = model.flavors[pyfunc.FLAVOR_NAME]
106         if pyfunc.ENV in conf:
107             _logger.info("creating and activating custom environment")
108             env = conf[pyfunc.ENV]
109             env_path_dst = os.path.join("/opt/mlflow/", env)
110             env_path_dst_dir = os.path.dirname(env_path_dst)
111             if not os.path.exists(env_path_dst_dir):
112                 os.makedirs(env_path_dst_dir)
113             shutil.copyfile(os.path.join(MODEL_PATH, env), env_path_dst)
114             if env_manager == em.CONDA:
115                 conda_create_model_env = "conda env create -n custom_env -f {}".format(env_path_dst)
116                 if Popen(["bash", "-c", conda_create_model_env]).wait() != 0:
117                     raise Exception("Failed to create model environment.")
118                 env_activate_cmd = "source /miniconda/bin/activate custom_env"
119             elif env_manager == em.VIRTUALENV:
120                 env_activate_cmd = _get_or_create_virtualenv(model_path)
121                 path = env_activate_cmd.split(" ")[-1]
122                 os.symlink(path, "/opt/activate")
123             has_env = True
124     activate_cmd = [env_activate_cmd] if has_env else []
125     # NB: install gunicorn[gevent] from pip rather than from conda because gunicorn is already
126     # dependency of mlflow on pip and we expect mlflow to be part of the environment.
127     server_deps = ["gunicorn[gevent]"]
128     if enable_mlserver:
129         server_deps = ["mlserver", "mlserver-mlflow"]
130 
131     install_server_deps = [f"pip install {' '.join(server_deps)}"]
132     if Popen(["bash", "-c", " && ".join(activate_cmd + install_server_deps)]).wait() != 0:
133         raise Exception("Failed to install serving dependencies into the model environment.")
134 
135     if has_env and install_mlflow:
136         install_mlflow_cmd = [
137             "pip install /opt/mlflow/."
138             if _container_includes_mlflow_source()
139             else "pip install mlflow=={}".format(MLFLOW_VERSION)
140         ]
141         if Popen(["bash", "-c", " && ".join(activate_cmd + install_mlflow_cmd)]).wait() != 0:
142             raise Exception("Failed to install mlflow into the model environment.")
143     return activate_cmd
144 
145 
146 def _serve_pyfunc(model, env_manager):
147     # option to disable manually nginx. The default behavior is to enable nginx.
148     disable_nginx = os.getenv(DISABLE_NGINX, "false").lower() == "true"
149     enable_mlserver = os.getenv(ENABLE_MLSERVER, "false").lower() == "true"
150     disable_env_creation = os.environ.get(DISABLE_ENV_CREATION) == "true"
151 
152     conf = model.flavors[pyfunc.FLAVOR_NAME]
153     bash_cmds = []
154     if pyfunc.ENV in conf:
155         if not disable_env_creation:
156             _install_pyfunc_deps(
157                 MODEL_PATH,
158                 install_mlflow=True,
159                 enable_mlserver=enable_mlserver,
160                 env_manager=env_manager,
161             )
162         bash_cmds += (
163             ["source /miniconda/bin/activate custom_env"]
164             if env_manager == em.CONDA
165             else ["source /opt/activate"]
166         )
167 
168     procs = []
169 
170     start_nginx = True
171     if disable_nginx or enable_mlserver:
172         start_nginx = False
173 
174     if start_nginx:
175         nginx_conf = resource_filename(
176             mlflow.models.__name__, "container/scoring_server/nginx.conf"
177         )
178 
179         nginx = Popen(["nginx", "-c", nginx_conf]) if start_nginx else None
180 
181         # link the log streams to stdout/err so they will be logged to the container logs.
182         # Default behavior is to do the redirection unless explicitly specified
183         # by environment variable.
184         check_call(["ln", "-sf", "/dev/stdout", "/var/log/nginx/access.log"])
185         check_call(["ln", "-sf", "/dev/stderr", "/var/log/nginx/error.log"])
186 
187         procs.append(nginx)
188 
189     cpu_count = multiprocessing.cpu_count()
190     os.system("pip -V")
191     os.system("python -V")
192     os.system('python -c"from mlflow.version import VERSION as V; print(V)"')
193 
194     inference_server = mlserver if enable_mlserver else scoring_server
195     # Since MLServer will run without NGINX, expose the server in the `8080`
196     # port, which is the assumed "public" port.
197     port = DEFAULT_MLSERVER_PORT if enable_mlserver else DEFAULT_INFERENCE_SERVER_PORT
198     cmd, cmd_env = inference_server.get_cmd(model_uri=MODEL_PATH, nworkers=cpu_count, port=port)
199 
200     bash_cmds.append(cmd)
201     inference_server_process = Popen(["/bin/bash", "-c", " && ".join(bash_cmds)], env=cmd_env)
202     procs.append(inference_server_process)
203 
204     signal.signal(signal.SIGTERM, lambda a, b: _sigterm_handler(pids=[p.pid for p in procs]))
205     # If either subprocess exits, so do we.
206     awaited_pids = _await_subprocess_exit_any(procs=procs)
207     _sigterm_handler(awaited_pids)
208 
209 
210 def _serve_mleap():
211     serve_cmd = [
212         "java",
213         "-cp",
214         '"/opt/java/jars/*"',
215         "org.mlflow.sagemaker.ScoringServer",
216         MODEL_PATH,
217         str(DEFAULT_SAGEMAKER_SERVER_PORT),
218     ]
219     # Invoke `Popen` with a single string command in the shell to support wildcard usage
220     # with the mlflow jar version.
221     serve_cmd = " ".join(serve_cmd)
222     mleap = Popen(serve_cmd, shell=True)
223     signal.signal(signal.SIGTERM, lambda a, b: _sigterm_handler(pids=[mleap.pid]))
224     awaited_pids = _await_subprocess_exit_any(procs=[mleap])
225     _sigterm_handler(awaited_pids)
226 
227 
228 def _container_includes_mlflow_source():
229     return os.path.exists("/opt/mlflow/setup.py")
230 
231 
232 def _train():
233     raise Exception("Train is not implemented.")
234 
235 
236 def _await_subprocess_exit_any(procs):
237     pids = [proc.pid for proc in procs]
238     while True:
239         pid, _ = os.wait()
240         if pid in pids:
241             break
242     return pids
243 
244 
245 def _sigterm_handler(pids):
246     """
247     Cleanup when terminating.
248 
249     Attempt to kill all launched processes and exit.
250 
251     """
252     _logger.info("Got sigterm signal, exiting.")
253     for pid in pids:
254         try:
255             os.kill(pid, signal.SIGTERM)
256         except OSError:
257             pass
258 
259     sys.exit(0)
260
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mlflow/models/container/__init__.py b/mlflow/models/container/__init__.py
--- a/mlflow/models/container/__init__.py
+++ b/mlflow/models/container/__init__.py
@@ -94,7 +94,7 @@
     dependencies into the environment - MLflow is not installed as it's not available via conda.
     """
     # If model is a pyfunc model, create its conda env (even if it also has mleap flavor)
-    has_env = False
+    activate_cmd = []
     if model_path:
         model_config_path = os.path.join(model_path, MLMODEL_FILE_NAME)
         model = Model.load(model_config_path)
@@ -115,13 +115,13 @@
                 conda_create_model_env = "conda env create -n custom_env -f {}".format(env_path_dst)
                 if Popen(["bash", "-c", conda_create_model_env]).wait() != 0:
                     raise Exception("Failed to create model environment.")
-                env_activate_cmd = "source /miniconda/bin/activate custom_env"
+                activate_cmd = ["source /miniconda/bin/activate custom_env"]
             elif env_manager == em.VIRTUALENV:
                 env_activate_cmd = _get_or_create_virtualenv(model_path)
                 path = env_activate_cmd.split(" ")[-1]
                 os.symlink(path, "/opt/activate")
-            has_env = True
-    activate_cmd = [env_activate_cmd] if has_env else []
+                activate_cmd = [env_activate_cmd]
+    
     # NB: install gunicorn[gevent] from pip rather than from conda because gunicorn is already
     # dependency of mlflow on pip and we expect mlflow to be part of the environment.
     server_deps = ["gunicorn[gevent]"]
@@ -132,7 +132,7 @@
     if Popen(["bash", "-c", " && ".join(activate_cmd + install_server_deps)]).wait() != 0:
         raise Exception("Failed to install serving dependencies into the model environment.")
 
-    if has_env and install_mlflow:
+    if len(activate_cmd) and install_mlflow:
         install_mlflow_cmd = [
             "pip install /opt/mlflow/."
             if _container_includes_mlflow_source()

{"golden_diff": "diff --git a/mlflow/models/container/__init__.py b/mlflow/models/container/__init__.py\n--- a/mlflow/models/container/__init__.py\n+++ b/mlflow/models/container/__init__.py\n@@ -94,7 +94,7 @@\n     dependencies into the environment - MLflow is not installed as it's not available via conda.\n     \"\"\"\n     # If model is a pyfunc model, create its conda env (even if it also has mleap flavor)\n-    has_env = False\n+    activate_cmd = []\n     if model_path:\n         model_config_path = os.path.join(model_path, MLMODEL_FILE_NAME)\n         model = Model.load(model_config_path)\n@@ -115,13 +115,13 @@\n                 conda_create_model_env = \"conda env create -n custom_env -f {}\".format(env_path_dst)\n                 if Popen([\"bash\", \"-c\", conda_create_model_env]).wait() != 0:\n                     raise Exception(\"Failed to create model environment.\")\n-                env_activate_cmd = \"source /miniconda/bin/activate custom_env\"\n+                activate_cmd = [\"source /miniconda/bin/activate custom_env\"]\n             elif env_manager == em.VIRTUALENV:\n                 env_activate_cmd = _get_or_create_virtualenv(model_path)\n                 path = env_activate_cmd.split(\" \")[-1]\n                 os.symlink(path, \"/opt/activate\")\n-            has_env = True\n-    activate_cmd = [env_activate_cmd] if has_env else []\n+                activate_cmd = [env_activate_cmd]\n+    \n     # NB: install gunicorn[gevent] from pip rather than from conda because gunicorn is already\n     # dependency of mlflow on pip and we expect mlflow to be part of the environment.\n     server_deps = [\"gunicorn[gevent]\"]\n@@ -132,7 +132,7 @@\n     if Popen([\"bash\", \"-c\", \" && \".join(activate_cmd + install_server_deps)]).wait() != 0:\n         raise Exception(\"Failed to install serving dependencies into the model environment.\")\n \n-    if has_env and install_mlflow:\n+    if len(activate_cmd) and install_mlflow:\n         install_mlflow_cmd = [\n             \"pip install /opt/mlflow/.\"\n             if _container_includes_mlflow_source()\n", "issue": "[BUG]  'env_activate_cmd' referenced before assignment when using mlflow models build-docker --env-manager=local\n### Willingness to contribute\n\nYes. I can contribute a fix for this bug independently.\n\n### MLflow version\n\n1.26.1\n\n### System information\n\n- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: Archlinux\r\n- **Python version**: 3.9.9\r\n\r\n\r\n\n\n### Describe the problem\n\nI have a very tiny mlflow pyfunc model which I can build into a docker using\r\n```bash\r\nmlflow models build-docker --model-uri 'models:/predict_service/latest' --enable-mlserver --name predict_service\r\n```\r\nWhen using `--env-manager=local`, I get a Python error saying:\r\n\r\n```bash\r\n  2022/06/10 10:00:47 INFO mlflow.models.container: creating and activating custom environment\r\n  Traceback (most recent call last):\r\n    File \"<string>\", line 1, in <module>\r\n    File \"/usr/local/lib/python3.7/dist-packages/mlflow/models/container/__init__.py\", line 124, in _install_pyfunc_deps\r\n      activate_cmd = [env_activate_cmd] if has_env else []\r\n  UnboundLocalError: local variable 'env_activate_cmd' referenced before assignment\r\n```\r\nWhich refers to https://github.com/mlflow/mlflow/blob/master/mlflow/models/container/__init__.py#L124 where indeed the variable is reference before assignment.\r\n\n\n### Tracking information\n\n_No response_\n\n### Code to reproduce issue\n\nmlflow models build-docker --model-uri 'models:/predict_service/latest' --enable-mlserver --name predict_service --env-manager=local\n\n### Other info / logs\n\n_No response_\n\n### What component(s) does this bug affect?\n\n- [ ] `area/artifacts`: Artifact stores and artifact logging\n- [X] `area/build`: Build and test infrastructure for MLflow\n- [ ] `area/docs`: MLflow documentation pages\n- [ ] `area/examples`: Example code\n- [ ] `area/model-registry`: Model Registry service, APIs, and the fluent client calls for Model Registry\n- [ ] `area/models`: MLmodel format, model serialization/deserialization, flavors\n- [ ] `area/projects`: MLproject format, project running backends\n- [ ] `area/scoring`: MLflow Model server, model deployment tools, Spark UDFs\n- [ ] `area/server-infra`: MLflow Tracking server backend\n- [ ] `area/tracking`: Tracking Service, tracking client APIs, autologging\n\n### What interface(s) does this bug affect?\n\n- [ ] `area/uiux`: Front-end, user experience, plotting, JavaScript, JavaScript dev server\n- [ ] `area/docker`: Docker use across MLflow's components, such as MLflow Projects and MLflow Models\n- [ ] `area/sqlalchemy`: Use of SQLAlchemy in the Tracking Service or Model Registry\n- [ ] `area/windows`: Windows support\n\n### What language(s) does this bug affect?\n\n- [ ] `language/r`: R APIs and clients\n- [ ] `language/java`: Java APIs and clients\n- [ ] `language/new`: Proposals for new client languages\n\n### What integration(s) does this bug affect?\n\n- [ ] `integrations/azure`: Azure and Azure ML integrations\n- [ ] `integrations/sagemaker`: SageMaker integrations\n- [ ] `integrations/databricks`: Databricks integrations\n", "before_files": [{"content": "\"\"\"\nInitialize the environment and start model serving in a Docker container.\n\nTo be executed only during the model deployment.\n\n\"\"\"\nimport multiprocessing\nimport os\nimport signal\nimport shutil\nfrom subprocess import check_call, Popen\nimport sys\nimport logging\n\nfrom pkg_resources import resource_filename\n\nimport mlflow\nimport mlflow.version\n\nfrom mlflow import pyfunc, mleap\nfrom mlflow.models import Model\nfrom mlflow.models.model import MLMODEL_FILE_NAME\nfrom mlflow.models.docker_utils import DISABLE_ENV_CREATION\nfrom mlflow.pyfunc import scoring_server, mlserver\nfrom mlflow.version import VERSION as MLFLOW_VERSION\nfrom mlflow.utils import env_manager as em\nfrom mlflow.utils.virtualenv import _get_or_create_virtualenv\n\nMODEL_PATH = \"/opt/ml/model\"\n\n\nDEPLOYMENT_CONFIG_KEY_FLAVOR_NAME = \"MLFLOW_DEPLOYMENT_FLAVOR_NAME\"\n\nDEFAULT_SAGEMAKER_SERVER_PORT = 8080\nDEFAULT_INFERENCE_SERVER_PORT = 8000\nDEFAULT_NGINX_SERVER_PORT = 8080\nDEFAULT_MLSERVER_PORT = 8080\n\nSUPPORTED_FLAVORS = [pyfunc.FLAVOR_NAME, mleap.FLAVOR_NAME]\n\nDISABLE_NGINX = \"DISABLE_NGINX\"\nENABLE_MLSERVER = \"ENABLE_MLSERVER\"\n\nSERVING_ENVIRONMENT = \"SERVING_ENVIRONMENT\"\n\n\n_logger = logging.getLogger(__name__)\n\n\ndef _init(cmd, env_manager):\n    \"\"\"\n    Initialize the container and execute command.\n\n    :param cmd: Command param passed by Sagemaker. Can be  \"serve\" or \"train\" (unimplemented).\n    \"\"\"\n    if cmd == \"serve\":\n        _serve(env_manager)\n    elif cmd == \"train\":\n        _train()\n    else:\n        raise Exception(\n            \"Unrecognized command {cmd}, full args = {args}\".format(cmd=cmd, args=str(sys.argv))\n        )\n\n\ndef _serve(env_manager):\n    \"\"\"\n    Serve the model.\n\n    Read the MLmodel config, initialize the Conda environment if needed and start python server.\n    \"\"\"\n    model_config_path = os.path.join(MODEL_PATH, MLMODEL_FILE_NAME)\n    m = Model.load(model_config_path)\n\n    if DEPLOYMENT_CONFIG_KEY_FLAVOR_NAME in os.environ:\n        serving_flavor = os.environ[DEPLOYMENT_CONFIG_KEY_FLAVOR_NAME]\n    else:\n        # Older versions of mlflow may not specify a deployment configuration\n        serving_flavor = pyfunc.FLAVOR_NAME\n\n    if serving_flavor == mleap.FLAVOR_NAME:\n        _serve_mleap()\n    elif pyfunc.FLAVOR_NAME in m.flavors:\n        _serve_pyfunc(m, env_manager)\n    else:\n        raise Exception(\"This container only supports models with the MLeap or PyFunc flavors.\")\n\n\ndef _install_pyfunc_deps(\n    model_path=None, install_mlflow=False, enable_mlserver=False, env_manager=em.CONDA\n):\n    \"\"\"\n    Creates a conda env for serving the model at the specified path and installs almost all serving\n    dependencies into the environment - MLflow is not installed as it's not available via conda.\n    \"\"\"\n    # If model is a pyfunc model, create its conda env (even if it also has mleap flavor)\n    has_env = False\n    if model_path:\n        model_config_path = os.path.join(model_path, MLMODEL_FILE_NAME)\n        model = Model.load(model_config_path)\n        # NOTE: this differs from _serve cause we always activate the env even if you're serving\n        # an mleap model\n        if pyfunc.FLAVOR_NAME not in model.flavors:\n            return\n        conf = model.flavors[pyfunc.FLAVOR_NAME]\n        if pyfunc.ENV in conf:\n            _logger.info(\"creating and activating custom environment\")\n            env = conf[pyfunc.ENV]\n            env_path_dst = os.path.join(\"/opt/mlflow/\", env)\n            env_path_dst_dir = os.path.dirname(env_path_dst)\n            if not os.path.exists(env_path_dst_dir):\n                os.makedirs(env_path_dst_dir)\n            shutil.copyfile(os.path.join(MODEL_PATH, env), env_path_dst)\n            if env_manager == em.CONDA:\n                conda_create_model_env = \"conda env create -n custom_env -f {}\".format(env_path_dst)\n                if Popen([\"bash\", \"-c\", conda_create_model_env]).wait() != 0:\n                    raise Exception(\"Failed to create model environment.\")\n                env_activate_cmd = \"source /miniconda/bin/activate custom_env\"\n            elif env_manager == em.VIRTUALENV:\n                env_activate_cmd = _get_or_create_virtualenv(model_path)\n                path = env_activate_cmd.split(\" \")[-1]\n                os.symlink(path, \"/opt/activate\")\n            has_env = True\n    activate_cmd = [env_activate_cmd] if has_env else []\n    # NB: install gunicorn[gevent] from pip rather than from conda because gunicorn is already\n    # dependency of mlflow on pip and we expect mlflow to be part of the environment.\n    server_deps = [\"gunicorn[gevent]\"]\n    if enable_mlserver:\n        server_deps = [\"mlserver\", \"mlserver-mlflow\"]\n\n    install_server_deps = [f\"pip install {' '.join(server_deps)}\"]\n    if Popen([\"bash\", \"-c\", \" && \".join(activate_cmd + install_server_deps)]).wait() != 0:\n        raise Exception(\"Failed to install serving dependencies into the model environment.\")\n\n    if has_env and install_mlflow:\n        install_mlflow_cmd = [\n            \"pip install /opt/mlflow/.\"\n            if _container_includes_mlflow_source()\n            else \"pip install mlflow=={}\".format(MLFLOW_VERSION)\n        ]\n        if Popen([\"bash\", \"-c\", \" && \".join(activate_cmd + install_mlflow_cmd)]).wait() != 0:\n            raise Exception(\"Failed to install mlflow into the model environment.\")\n    return activate_cmd\n\n\ndef _serve_pyfunc(model, env_manager):\n    # option to disable manually nginx. The default behavior is to enable nginx.\n    disable_nginx = os.getenv(DISABLE_NGINX, \"false\").lower() == \"true\"\n    enable_mlserver = os.getenv(ENABLE_MLSERVER, \"false\").lower() == \"true\"\n    disable_env_creation = os.environ.get(DISABLE_ENV_CREATION) == \"true\"\n\n    conf = model.flavors[pyfunc.FLAVOR_NAME]\n    bash_cmds = []\n    if pyfunc.ENV in conf:\n        if not disable_env_creation:\n            _install_pyfunc_deps(\n                MODEL_PATH,\n                install_mlflow=True,\n                enable_mlserver=enable_mlserver,\n                env_manager=env_manager,\n            )\n        bash_cmds += (\n            [\"source /miniconda/bin/activate custom_env\"]\n            if env_manager == em.CONDA\n            else [\"source /opt/activate\"]\n        )\n\n    procs = []\n\n    start_nginx = True\n    if disable_nginx or enable_mlserver:\n        start_nginx = False\n\n    if start_nginx:\n        nginx_conf = resource_filename(\n            mlflow.models.__name__, \"container/scoring_server/nginx.conf\"\n        )\n\n        nginx = Popen([\"nginx\", \"-c\", nginx_conf]) if start_nginx else None\n\n        # link the log streams to stdout/err so they will be logged to the container logs.\n        # Default behavior is to do the redirection unless explicitly specified\n        # by environment variable.\n        check_call([\"ln\", \"-sf\", \"/dev/stdout\", \"/var/log/nginx/access.log\"])\n        check_call([\"ln\", \"-sf\", \"/dev/stderr\", \"/var/log/nginx/error.log\"])\n\n        procs.append(nginx)\n\n    cpu_count = multiprocessing.cpu_count()\n    os.system(\"pip -V\")\n    os.system(\"python -V\")\n    os.system('python -c\"from mlflow.version import VERSION as V; print(V)\"')\n\n    inference_server = mlserver if enable_mlserver else scoring_server\n    # Since MLServer will run without NGINX, expose the server in the `8080`\n    # port, which is the assumed \"public\" port.\n    port = DEFAULT_MLSERVER_PORT if enable_mlserver else DEFAULT_INFERENCE_SERVER_PORT\n    cmd, cmd_env = inference_server.get_cmd(model_uri=MODEL_PATH, nworkers=cpu_count, port=port)\n\n    bash_cmds.append(cmd)\n    inference_server_process = Popen([\"/bin/bash\", \"-c\", \" && \".join(bash_cmds)], env=cmd_env)\n    procs.append(inference_server_process)\n\n    signal.signal(signal.SIGTERM, lambda a, b: _sigterm_handler(pids=[p.pid for p in procs]))\n    # If either subprocess exits, so do we.\n    awaited_pids = _await_subprocess_exit_any(procs=procs)\n    _sigterm_handler(awaited_pids)\n\n\ndef _serve_mleap():\n    serve_cmd = [\n        \"java\",\n        \"-cp\",\n        '\"/opt/java/jars/*\"',\n        \"org.mlflow.sagemaker.ScoringServer\",\n        MODEL_PATH,\n        str(DEFAULT_SAGEMAKER_SERVER_PORT),\n    ]\n    # Invoke `Popen` with a single string command in the shell to support wildcard usage\n    # with the mlflow jar version.\n    serve_cmd = \" \".join(serve_cmd)\n    mleap = Popen(serve_cmd, shell=True)\n    signal.signal(signal.SIGTERM, lambda a, b: _sigterm_handler(pids=[mleap.pid]))\n    awaited_pids = _await_subprocess_exit_any(procs=[mleap])\n    _sigterm_handler(awaited_pids)\n\n\ndef _container_includes_mlflow_source():\n    return os.path.exists(\"/opt/mlflow/setup.py\")\n\n\ndef _train():\n    raise Exception(\"Train is not implemented.\")\n\n\ndef _await_subprocess_exit_any(procs):\n    pids = [proc.pid for proc in procs]\n    while True:\n        pid, _ = os.wait()\n        if pid in pids:\n            break\n    return pids\n\n\ndef _sigterm_handler(pids):\n    \"\"\"\n    Cleanup when terminating.\n\n    Attempt to kill all launched processes and exit.\n\n    \"\"\"\n    _logger.info(\"Got sigterm signal, exiting.\")\n    for pid in pids:\n        try:\n            os.kill(pid, signal.SIGTERM)\n        except OSError:\n            pass\n\n    sys.exit(0)\n", "path": "mlflow/models/container/__init__.py"}], "after_files": [{"content": "\"\"\"\nInitialize the environment and start model serving in a Docker container.\n\nTo be executed only during the model deployment.\n\n\"\"\"\nimport multiprocessing\nimport os\nimport signal\nimport shutil\nfrom subprocess import check_call, Popen\nimport sys\nimport logging\n\nfrom pkg_resources import resource_filename\n\nimport mlflow\nimport mlflow.version\n\nfrom mlflow import pyfunc, mleap\nfrom mlflow.models import Model\nfrom mlflow.models.model import MLMODEL_FILE_NAME\nfrom mlflow.models.docker_utils import DISABLE_ENV_CREATION\nfrom mlflow.pyfunc import scoring_server, mlserver\nfrom mlflow.version import VERSION as MLFLOW_VERSION\nfrom mlflow.utils import env_manager as em\nfrom mlflow.utils.virtualenv import _get_or_create_virtualenv\n\nMODEL_PATH = \"/opt/ml/model\"\n\n\nDEPLOYMENT_CONFIG_KEY_FLAVOR_NAME = \"MLFLOW_DEPLOYMENT_FLAVOR_NAME\"\n\nDEFAULT_SAGEMAKER_SERVER_PORT = 8080\nDEFAULT_INFERENCE_SERVER_PORT = 8000\nDEFAULT_NGINX_SERVER_PORT = 8080\nDEFAULT_MLSERVER_PORT = 8080\n\nSUPPORTED_FLAVORS = [pyfunc.FLAVOR_NAME, mleap.FLAVOR_NAME]\n\nDISABLE_NGINX = \"DISABLE_NGINX\"\nENABLE_MLSERVER = \"ENABLE_MLSERVER\"\n\nSERVING_ENVIRONMENT = \"SERVING_ENVIRONMENT\"\n\n\n_logger = logging.getLogger(__name__)\n\n\ndef _init(cmd, env_manager):\n    \"\"\"\n    Initialize the container and execute command.\n\n    :param cmd: Command param passed by Sagemaker. Can be  \"serve\" or \"train\" (unimplemented).\n    \"\"\"\n    if cmd == \"serve\":\n        _serve(env_manager)\n    elif cmd == \"train\":\n        _train()\n    else:\n        raise Exception(\n            \"Unrecognized command {cmd}, full args = {args}\".format(cmd=cmd, args=str(sys.argv))\n        )\n\n\ndef _serve(env_manager):\n    \"\"\"\n    Serve the model.\n\n    Read the MLmodel config, initialize the Conda environment if needed and start python server.\n    \"\"\"\n    model_config_path = os.path.join(MODEL_PATH, MLMODEL_FILE_NAME)\n    m = Model.load(model_config_path)\n\n    if DEPLOYMENT_CONFIG_KEY_FLAVOR_NAME in os.environ:\n        serving_flavor = os.environ[DEPLOYMENT_CONFIG_KEY_FLAVOR_NAME]\n    else:\n        # Older versions of mlflow may not specify a deployment configuration\n        serving_flavor = pyfunc.FLAVOR_NAME\n\n    if serving_flavor == mleap.FLAVOR_NAME:\n        _serve_mleap()\n    elif pyfunc.FLAVOR_NAME in m.flavors:\n        _serve_pyfunc(m, env_manager)\n    else:\n        raise Exception(\"This container only supports models with the MLeap or PyFunc flavors.\")\n\n\ndef _install_pyfunc_deps(\n    model_path=None, install_mlflow=False, enable_mlserver=False, env_manager=em.CONDA\n):\n    \"\"\"\n    Creates a conda env for serving the model at the specified path and installs almost all serving\n    dependencies into the environment - MLflow is not installed as it's not available via conda.\n    \"\"\"\n    # If model is a pyfunc model, create its conda env (even if it also has mleap flavor)\n    activate_cmd = []\n    if model_path:\n        model_config_path = os.path.join(model_path, MLMODEL_FILE_NAME)\n        model = Model.load(model_config_path)\n        # NOTE: this differs from _serve cause we always activate the env even if you're serving\n        # an mleap model\n        if pyfunc.FLAVOR_NAME not in model.flavors:\n            return\n        conf = model.flavors[pyfunc.FLAVOR_NAME]\n        if pyfunc.ENV in conf:\n            _logger.info(\"creating and activating custom environment\")\n            env = conf[pyfunc.ENV]\n            env_path_dst = os.path.join(\"/opt/mlflow/\", env)\n            env_path_dst_dir = os.path.dirname(env_path_dst)\n            if not os.path.exists(env_path_dst_dir):\n                os.makedirs(env_path_dst_dir)\n            shutil.copyfile(os.path.join(MODEL_PATH, env), env_path_dst)\n            if env_manager == em.CONDA:\n                conda_create_model_env = \"conda env create -n custom_env -f {}\".format(env_path_dst)\n                if Popen([\"bash\", \"-c\", conda_create_model_env]).wait() != 0:\n                    raise Exception(\"Failed to create model environment.\")\n                activate_cmd = [\"source /miniconda/bin/activate custom_env\"]\n            elif env_manager == em.VIRTUALENV:\n                env_activate_cmd = _get_or_create_virtualenv(model_path)\n                path = env_activate_cmd.split(\" \")[-1]\n                os.symlink(path, \"/opt/activate\")\n                activate_cmd = [env_activate_cmd]\n    \n    # NB: install gunicorn[gevent] from pip rather than from conda because gunicorn is already\n    # dependency of mlflow on pip and we expect mlflow to be part of the environment.\n    server_deps = [\"gunicorn[gevent]\"]\n    if enable_mlserver:\n        server_deps = [\"mlserver\", \"mlserver-mlflow\"]\n\n    install_server_deps = [f\"pip install {' '.join(server_deps)}\"]\n    if Popen([\"bash\", \"-c\", \" && \".join(activate_cmd + install_server_deps)]).wait() != 0:\n        raise Exception(\"Failed to install serving dependencies into the model environment.\")\n\n    if len(activate_cmd) and install_mlflow:\n        install_mlflow_cmd = [\n            \"pip install /opt/mlflow/.\"\n            if _container_includes_mlflow_source()\n            else \"pip install mlflow=={}\".format(MLFLOW_VERSION)\n        ]\n        if Popen([\"bash\", \"-c\", \" && \".join(activate_cmd + install_mlflow_cmd)]).wait() != 0:\n            raise Exception(\"Failed to install mlflow into the model environment.\")\n    return activate_cmd\n\n\ndef _serve_pyfunc(model, env_manager):\n    # option to disable manually nginx. The default behavior is to enable nginx.\n    disable_nginx = os.getenv(DISABLE_NGINX, \"false\").lower() == \"true\"\n    enable_mlserver = os.getenv(ENABLE_MLSERVER, \"false\").lower() == \"true\"\n    disable_env_creation = os.environ.get(DISABLE_ENV_CREATION) == \"true\"\n\n    conf = model.flavors[pyfunc.FLAVOR_NAME]\n    bash_cmds = []\n    if pyfunc.ENV in conf:\n        if not disable_env_creation:\n            _install_pyfunc_deps(\n                MODEL_PATH,\n                install_mlflow=True,\n                enable_mlserver=enable_mlserver,\n                env_manager=env_manager,\n            )\n        bash_cmds += (\n            [\"source /miniconda/bin/activate custom_env\"]\n            if env_manager == em.CONDA\n            else [\"source /opt/activate\"]\n        )\n\n    procs = []\n\n    start_nginx = True\n    if disable_nginx or enable_mlserver:\n        start_nginx = False\n\n    if start_nginx:\n        nginx_conf = resource_filename(\n            mlflow.models.__name__, \"container/scoring_server/nginx.conf\"\n        )\n\n        nginx = Popen([\"nginx\", \"-c\", nginx_conf]) if start_nginx else None\n\n        # link the log streams to stdout/err so they will be logged to the container logs.\n        # Default behavior is to do the redirection unless explicitly specified\n        # by environment variable.\n        check_call([\"ln\", \"-sf\", \"/dev/stdout\", \"/var/log/nginx/access.log\"])\n        check_call([\"ln\", \"-sf\", \"/dev/stderr\", \"/var/log/nginx/error.log\"])\n\n        procs.append(nginx)\n\n    cpu_count = multiprocessing.cpu_count()\n    os.system(\"pip -V\")\n    os.system(\"python -V\")\n    os.system('python -c\"from mlflow.version import VERSION as V; print(V)\"')\n\n    inference_server = mlserver if enable_mlserver else scoring_server\n    # Since MLServer will run without NGINX, expose the server in the `8080`\n    # port, which is the assumed \"public\" port.\n    port = DEFAULT_MLSERVER_PORT if enable_mlserver else DEFAULT_INFERENCE_SERVER_PORT\n    cmd, cmd_env = inference_server.get_cmd(model_uri=MODEL_PATH, nworkers=cpu_count, port=port)\n\n    bash_cmds.append(cmd)\n    inference_server_process = Popen([\"/bin/bash\", \"-c\", \" && \".join(bash_cmds)], env=cmd_env)\n    procs.append(inference_server_process)\n\n    signal.signal(signal.SIGTERM, lambda a, b: _sigterm_handler(pids=[p.pid for p in procs]))\n    # If either subprocess exits, so do we.\n    awaited_pids = _await_subprocess_exit_any(procs=procs)\n    _sigterm_handler(awaited_pids)\n\n\ndef _serve_mleap():\n    serve_cmd = [\n        \"java\",\n        \"-cp\",\n        '\"/opt/java/jars/*\"',\n        \"org.mlflow.sagemaker.ScoringServer\",\n        MODEL_PATH,\n        str(DEFAULT_SAGEMAKER_SERVER_PORT),\n    ]\n    # Invoke `Popen` with a single string command in the shell to support wildcard usage\n    # with the mlflow jar version.\n    serve_cmd = \" \".join(serve_cmd)\n    mleap = Popen(serve_cmd, shell=True)\n    signal.signal(signal.SIGTERM, lambda a, b: _sigterm_handler(pids=[mleap.pid]))\n    awaited_pids = _await_subprocess_exit_any(procs=[mleap])\n    _sigterm_handler(awaited_pids)\n\n\ndef _container_includes_mlflow_source():\n    return os.path.exists(\"/opt/mlflow/setup.py\")\n\n\ndef _train():\n    raise Exception(\"Train is not implemented.\")\n\n\ndef _await_subprocess_exit_any(procs):\n    pids = [proc.pid for proc in procs]\n    while True:\n        pid, _ = os.wait()\n        if pid in pids:\n            break\n    return pids\n\n\ndef _sigterm_handler(pids):\n    \"\"\"\n    Cleanup when terminating.\n\n    Attempt to kill all launched processes and exit.\n\n    \"\"\"\n    _logger.info(\"Got sigterm signal, exiting.\")\n    for pid in pids:\n        try:\n            os.kill(pid, signal.SIGTERM)\n        except OSError:\n            pass\n\n    sys.exit(0)\n", "path": "mlflow/models/container/__init__.py"}]}