diff --git a/doc/source/python/python_server.md b/doc/source/python/python_server.md index 445cdea231..6fd5a3224f 100644 --- a/doc/source/python/python_server.md +++ b/doc/source/python/python_server.md @@ -187,6 +187,7 @@ Python Server can be configured using environmental variables or command line fl | `--threads` | `GUNICORN_THREADS` | `10` | Number of threads to run per Gunicorn worker. | | `--max-requests` | `GUNICORN_MAX_REQUESTS` | `0` | Maximum number of requests gunicorn worker will process before restarting. | | `--max-requests-jitter` | `GUNICORN_MAX_REQUESTS_JITTER` | `0` | Maximum random jitter to add to max-requests. | +| `--pidfile` | N/A | None | A file path to use for the Gunicorn PID file. | | `--single-threaded` | `FLASK_SINGLE_THREADED` | `0` | Force the Flask app to run single-threaded. Also applies to Gunicorn. Can be `0` or `1`. | | N/A | `FILTER_METRICS_ACCESS_LOGS` | `not debug` | Filter out logs related to Prometheus accessing the metrics port. By default enabled in production and disabled in debug mode. | | N/A | `PREDICTIVE_UNIT_METRICS_ENDPOINT` | `/metrics` | Endpoint name for Prometheus metrics. In k8s deployment default is `/prometheus`. | diff --git a/operator/hack/create_graph_openapi_schema.py b/operator/hack/create_graph_openapi_schema.py index cc67c43765..3e3cb52a41 100644 --- a/operator/hack/create_graph_openapi_schema.py +++ b/operator/hack/create_graph_openapi_schema.py @@ -3,14 +3,20 @@ import sys import copy + def getOpts(cmd_line_args): - parser = argparse.ArgumentParser(description="Create graph OpenAPI schema patch. Takes an input template and output Kustomize path for given number of levels") + parser = argparse.ArgumentParser( + description="Create graph OpenAPI schema patch. Takes an input template and output Kustomize path for given number of levels" + ) parser.add_argument("template", help="the yaml template for 1 level of the graph") parser.add_argument("path", help="the output path to save result") - parser.add_argument("--levels", help="the number of levels to create", type=int, default=10) + parser.add_argument( + "--levels", help="the number of levels to create", type=int, default=10 + ) opts = parser.parse_args(cmd_line_args) return opts + def expand_tmpl(filename, levels): with open(filename, "r") as stream: y = yaml.safe_load(stream) @@ -19,15 +25,20 @@ def expand_tmpl(filename, levels): child = copy.deepcopy(tmpl) tmpl["properties"]["children"]["items"] = child tmpl = child - if i == levels-1: + if i == levels - 1: del tmpl["properties"]["children"] # add replace for second and third schema version y.append(copy.deepcopy(y[0])) - y[1]["path"] = "/spec/versions/1/schema/openAPIV3Schema/properties/spec/properties/predictors/items/properties/graph" + y[1][ + "path" + ] = "/spec/versions/1/schema/openAPIV3Schema/properties/spec/properties/predictors/items/properties/graph" y.append(copy.deepcopy(y[0])) - y[2]["path"] = "/spec/versions/2/schema/openAPIV3Schema/properties/spec/properties/predictors/items/properties/graph" + y[2][ + "path" + ] = "/spec/versions/2/schema/openAPIV3Schema/properties/spec/properties/predictors/items/properties/graph" return y + def main(argv): opts = getOpts(argv[1:]) print(opts) @@ -36,5 +47,6 @@ def main(argv): with open(opts.path, "w") as outfile: outfile.write(fdata) + if __name__ == "__main__": - main(sys.argv) \ No newline at end of file + main(sys.argv) diff --git a/operator/hack/csv_hack.py b/operator/hack/csv_hack.py index 5581931872..a548b3c99a 100644 --- a/operator/hack/csv_hack.py +++ b/operator/hack/csv_hack.py @@ -2,12 +2,14 @@ import argparse import sys + def getOpts(cmd_line_args): parser = argparse.ArgumentParser(description="remove csv CRD versions") parser.add_argument("path", help="the output path to save result") opts = parser.parse_args(cmd_line_args) return opts + def remove_versions(filename): with open(filename, "r") as stream: y = yaml.safe_load(stream) @@ -15,10 +17,11 @@ def remove_versions(filename): del y["spec"]["customresourcedefinitions"]["owned"][1] return y + def str_presenter(dumper, data): - if len(data.splitlines()) > 1: # check for multiline string - return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') - return dumper.represent_scalar('tag:yaml.org,2002:str', data) + if len(data.splitlines()) > 1: # check for multiline string + return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|") + return dumper.represent_scalar("tag:yaml.org,2002:str", data) def main(argv): @@ -32,4 +35,4 @@ def main(argv): if __name__ == "__main__": yaml.add_representer(str, str_presenter) - main(sys.argv) \ No newline at end of file + main(sys.argv) diff --git a/operator/helm/split_resources.py b/operator/helm/split_resources.py index 34111f1187..2e9c8744f8 100644 --- a/operator/helm/split_resources.py +++ b/operator/helm/split_resources.py @@ -20,7 +20,7 @@ HELM_CERTMANAGER_IF_START = "{{- if .Values.certManager.enabled -}}\n" HELM_NOT_CERTMANAGER_IF_START = "{{- if not .Values.certManager.enabled -}}\n" HELM_VERSION_IF_START = ( -'{{- if semverCompare ">=1.15.0" .Capabilities.KubeVersion.GitVersion }}\n' + '{{- if semverCompare ">=1.15.0" .Capabilities.KubeVersion.GitVersion }}\n' ) HELM_KUBEFLOW_IF_START = "{{- if .Values.kubeflow }}\n" HELM_KUBEFLOW_IF_NOT_START = "{{- if not .Values.kubeflow }}\n" @@ -95,10 +95,21 @@ def helm_release(value: str): filename = args.folder + "/" + (kind + "_" + name).lower() + ".yaml" print(filename) print(version) - if filename == (args.folder + "/" + "customresourcedefinition_seldondeployments.machinelearning.seldon.io.yaml") \ - and version == "apiextensions.k8s.io/v1": + if ( + filename + == ( + args.folder + + "/" + + "customresourcedefinition_seldondeployments.machinelearning.seldon.io.yaml" + ) + and version == "apiextensions.k8s.io/v1" + ): print("MATCH") - filename = args.folder + "/" + "customresourcedefinition_v1_seldondeployments.machinelearning.seldon.io.yaml" + filename = ( + args.folder + + "/" + + "customresourcedefinition_v1_seldondeployments.machinelearning.seldon.io.yaml" + ) print("Processing ", file) # Update common labels @@ -368,16 +379,28 @@ def helm_release(value: str): fdata = HELM_CERTMANAGER_IF_START + fdata + HELM_IF_END elif name == "seldon-webhook-server-cert" and kind == "secret": fdata = HELM_NOT_CERTMANAGER_IF_START + fdata + HELM_IF_END - elif name == "seldondeployments.machinelearning.seldon.io" and \ - version == "apiextensions.k8s.io/v1beta1": - fdata = HELM_CRD_IF_START + \ - HELM_K8S_V1BETA1_CRD_IF_START + fdata + \ - HELM_IF_END + HELM_IF_END - elif name == "seldondeployments.machinelearning.seldon.io" and \ - version == "apiextensions.k8s.io/v1": - fdata = HELM_CRD_IF_START + \ - HELM_K8S_V1_CRD_IF_START + fdata + \ - HELM_IF_END + HELM_IF_END + elif ( + name == "seldondeployments.machinelearning.seldon.io" + and version == "apiextensions.k8s.io/v1beta1" + ): + fdata = ( + HELM_CRD_IF_START + + HELM_K8S_V1BETA1_CRD_IF_START + + fdata + + HELM_IF_END + + HELM_IF_END + ) + elif ( + name == "seldondeployments.machinelearning.seldon.io" + and version == "apiextensions.k8s.io/v1" + ): + fdata = ( + HELM_CRD_IF_START + + HELM_K8S_V1_CRD_IF_START + + fdata + + HELM_IF_END + + HELM_IF_END + ) elif kind == "service" and name == "seldon-webhook-service": fdata = HELM_CREATERESOURCES_IF_START + fdata + HELM_IF_END elif kind == "configmap" and name == "seldon-config": @@ -468,7 +491,7 @@ def helm_release(value: str): ) webhookData = webhookData + "\n" + HELM_IF_END - print("Webhook data len",len(webhookData)) + print("Webhook data len", len(webhookData)) filename = args.folder + "/" + "webhook.yaml" with open(filename, "w") as outfile: diff --git a/python/Makefile b/python/Makefile index 96728a0642..75b2106c6f 100644 --- a/python/Makefile +++ b/python/Makefile @@ -99,7 +99,7 @@ setup_linter: fmt: black \ - ./ ../testing ../operator/helm ../operator/seldon-operator/hack \ + ./ ../testing ../operator/helm ../operator/hack \ --exclude "(testing/scripts/proto|seldon_core/proto/|.eggs|.tox)" lint: licenses diff --git a/python/licenses/license.txt b/python/licenses/license.txt index 93e82abecf..715bb7e65e 100644 --- a/python/licenses/license.txt +++ b/python/licenses/license.txt @@ -147,7 +147,7 @@ SOFTWARE. Markdown -3.3 +3.3.1 BSD License Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later) Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) diff --git a/python/licenses/license_info.csv b/python/licenses/license_info.csv index f36a63183c..2656061395 100644 --- a/python/licenses/license_info.csv +++ b/python/licenses/license_info.csv @@ -4,7 +4,7 @@ "Flask-OpenTracing","1.1.0","BSD License" "Jinja2","2.11.2","BSD License" "Keras-Preprocessing","1.1.2","MIT License" -"Markdown","3.3","BSD License" +"Markdown","3.3.1","BSD License" "MarkupSafe","1.1.1","BSD License" "PyYAML","5.3.1","MIT License" "Werkzeug","1.0.1","BSD License" diff --git a/python/seldon_core/microservice.py b/python/seldon_core/microservice.py index 4149b95c44..3a53554bd3 100644 --- a/python/seldon_core/microservice.py +++ b/python/seldon_core/microservice.py @@ -313,6 +313,10 @@ def main(): help="Set metrics port of seldon service", ) + parser.add_argument( + "--pidfile", type=str, default=None, help="A file path to use for the PID file", + ) + args = parser.parse_args() parameters = parse_parameters(json.loads(args.parameters)) @@ -399,6 +403,8 @@ def rest_prediction_server(): "max_requests_jitter": args.max_requests_jitter, "post_worker_init": post_worker_init, } + if args.pidfile is not None: + options["pidfile"] = args.pidfile app = seldon_microservice.get_rest_microservice( user_object, seldon_metrics ) @@ -461,6 +467,8 @@ def rest_metrics_server(): "max_requests_jitter": args.max_requests_jitter, "post_worker_init": post_worker_init, } + if args.pidfile is not None: + options["pidfile"] = args.pidfile StandaloneApplication(app, options=options).run() logger.info("REST metrics microservice running on port %i", metrics_port)