added input validation, updated sdk and fixed bug
This commit is contained in:
Родитель
fa4bb4de0f
Коммит
bbb4ae0398
|
@ -17,18 +17,13 @@
|
|||
"cpu_cores": 0.1,
|
||||
"memory_gb": 0.5,
|
||||
"delete_service_after_test": false,
|
||||
"no_code_deployment_enabled": false,
|
||||
"tags": {"<your-webservice-tag-key>": "<your-webservice-tag-value>"},
|
||||
"properties": {"<your-webservice-property-key>": "<your-webservice-property-value>"},
|
||||
"description": "<your-webservice-description>",
|
||||
"location": "<your-aci-location>",
|
||||
"gpu_cores": 0,
|
||||
"ssl_enabled": true,
|
||||
"ssl_cert_pem_file": "<your-aci-ssl-cert-pem-file>",
|
||||
"ssl_key_pem_file": "<your-aci-ssl-key-pem-file>",
|
||||
"ssl_cname": "<your-aci-ssl-cname>",
|
||||
"dns_name_label": "<your-aci-dns-name-label>",
|
||||
"cmk_vault_base_url": "<your-aci-cmk-vault-base-url>",
|
||||
"cmk_key_name": "<your-aci-cmk-key-name>",
|
||||
"cmk_key_version": "<your-aci-cmk-key-version>"
|
||||
"dns_name_label": "<your-aci-dns-name-label>"
|
||||
}
|
|
@ -17,8 +17,8 @@
|
|||
"custom_base_image": "<your-custom-docker-base-image>",
|
||||
"cpu_cores": 0.1,
|
||||
"memory_gb": 0.5,
|
||||
"gpu_cores": 0,
|
||||
"delete_service_after_test": false,
|
||||
"no_code_deployment_enabled": false,
|
||||
"tags": {"<your-webservice-tag-key>": "<your-webservice-tag-value>"},
|
||||
"properties": {"<your-webservice-property-key>": "<your-webservice-property-value>"},
|
||||
"description": "<your-webservice-description>",
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
"deployment_compute_target": "<your-deployment-compute-target-name>", // do not specify deployment compute target name for deployment on Azure Container Registry
|
||||
"inference_source_directory": "<your-inference-source-directory>",
|
||||
"inference_entry_script": "<your-inference-entry-script>",
|
||||
"conda_file": "<your-conda-environment-file-path>",
|
||||
"extra_docker_file_steps": "<your-extra-docker-steps-file-path>",
|
||||
"test_enabled": true,
|
||||
"test_file_path": "<your-test-file-path>",
|
||||
"test_file_function_name": "<your-test-file-function-name>",
|
||||
"conda_file": "<your-conda-environment-file-path>",
|
||||
"extra_docker_file_steps": "<your-extra-docker-steps-file-path>",
|
||||
"enable_gpu": false,
|
||||
"cuda_version": "<your-cuda-version>",
|
||||
"model_data_collection_enabled": true,
|
||||
|
@ -18,24 +18,20 @@
|
|||
"cpu_cores": 0.1,
|
||||
"memory_gb": 0.5,
|
||||
"delete_service_after_test": false,
|
||||
"no_code_deployment_enabled": false,
|
||||
"tags": {"<your-webservice-tag-key>": "<your-webservice-tag-value>"},
|
||||
"properties": {"<your-webservice-property-key>": "<your-webservice-property-value>"},
|
||||
"description": "<your-webservice-description>",
|
||||
|
||||
// aci specific parameters
|
||||
"location": "<your-aci-location>",
|
||||
"gpu_cores": 0,
|
||||
"ssl_enabled": true,
|
||||
"ssl_cert_pem_file": "<your-aci-ssl-cert-pem-file>",
|
||||
"ssl_key_pem_file": "<your-aci-ssl-key-pem-file>",
|
||||
"ssl_cname": "<your-aci-ssl-cname>",
|
||||
"dns_name_label": "<your-aci-dns-name-label>",
|
||||
"cmk_vault_base_url": "<your-aci-cmk-vault-base-url>",
|
||||
"cmk_key_name": "<your-aci-cmk-key-name>",
|
||||
"cmk_key_version": "<your-aci-cmk-key-version>",
|
||||
|
||||
// aks specific parameters
|
||||
"gpu_cores": 0,
|
||||
"autoscale_enabled": true,
|
||||
"autoscale_min_replicas": 1,
|
||||
"autoscale_max_replicas": 10,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
name: Lint
|
||||
name: Lint and Test
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
name: Lint and Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Python 3.7
|
||||
|
@ -19,5 +19,11 @@ jobs:
|
|||
id: python_linting
|
||||
run: |
|
||||
pip install flake8
|
||||
flake8 --ignore E501 code/main.py
|
||||
flake8 --ignore E501 code/utils.py
|
||||
flake8 code/ --count --ignore=E501 --show-source --statistics
|
||||
flake8 tests/ --count --ignore=E501,E402 --show-source --statistics
|
||||
|
||||
- name: Test
|
||||
id: python_test
|
||||
run: |
|
||||
pip install pytest jsonschema azureml-sdk
|
||||
pytest
|
||||
|
|
|
@ -1,5 +1,131 @@
|
|||
################################################################################
|
||||
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
|
||||
################################################################################
|
||||
# Byte-compiled / optimized / DLL files
|
||||
.vs/
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
/.vs
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
.vs/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
FROM marvinbuss/aml-docker:1.1.5
|
||||
FROM marvinbuss/aml-docker:1.4.0
|
||||
|
||||
LABEL maintainer="azure/gh_aml"
|
||||
|
||||
|
|
16
README.md
16
README.md
|
@ -111,13 +111,13 @@ A sample file can be found in this repository in the folder `.cloud/.azure`. The
|
|||
| inference_entry_script | | str | `"score.py"` | The path to a local file in your repository that contains the code to run for the image and score the data. This path is relative to the specified source directory. The python script has to define an `init` and a `run` function. A sample can be found in the template repositories. |
|
||||
| conda_file | | str | `"environment.yml"` | The path to a local file in your repository containing a conda environment definition to use for the image. This path is relative to the specified source directory. |
|
||||
| extra_docker_file_steps | | str | null | The path to a local file in your repository containing additional Docker steps to run when setting up image. This path is relative to the specified source directory. |
|
||||
| enable_gpu | | str | false | Indicates whether to enable GPU support in the image. The GPU image must be used on Microsoft Azure Services such as Azure Container Instances, Azure Machine Learning Compute, Azure Virtual Machines, and Azure Kubernetes Service. |
|
||||
| enable_gpu | | bool | false | Indicates whether to enable GPU support in the image. The GPU image must be used on Microsoft Azure Services such as Azure Container Instances, Azure Machine Learning Compute, Azure Virtual Machines, and Azure Kubernetes Service. |
|
||||
| cuda_version | | str | `"9.1"` if `enable_gpu` is set to true | The Version of CUDA to install for images that need GPU support. The GPU image must be used on Microsoft Azure Services such as Azure Container Instances, Azure Machine Learning Compute, Azure Virtual Machines, and Azure Kubernetes Service. Supported versions are 9.0, 9.1, and 10.0. |
|
||||
| runtime | | str: `"python"` or `"spark-py"` | `"python"` | The runtime to use for the image. |
|
||||
| custom_base_image | | str | null | A custom Docker image to be used as base image. If no base image is given then the base image will be used based off of given runtime parameter. |
|
||||
| model_data_collection_enabled | | bool | false | Whether or not to enable model data collection for this Webservice. |
|
||||
| authentication_enabled | | bool | false for ACI, true for AKS | Whether or not to enable key auth for this Webservice. |
|
||||
| app_insights_enabled | | bool | false | Whether or not to enable Application Insights logging for this Webservice. |
|
||||
| app_insights_enabled | | bool | false | Whether or not to enable Application Insights logging for this Webservice. |
|
||||
| cpu_cores | | float | 0.1 | The number of CPU cores to allocate for this Webservice. Can be a decimal. |
|
||||
| memory_gb | | float | 0.5 | The amount of memory (in GB) to allocate for this Webservice. Can be a decimal. |
|
||||
| delete_service_after_deployment | | bool | false | Indicates whether the service gets deleted after the deployment completed successfully. |
|
||||
|
@ -139,7 +139,7 @@ ACI is the default deployment resource. A sample file for an aci deployment can
|
|||
| location | | str: [supported region](https://azure.microsoft.com/en-us/global-infrastructure/services/?products=container-instances) | workspace location | The Azure region to deploy this Webservice to. |
|
||||
| ssl_enabled | | bool | false | Whether or not to enable SSL for this Webservice. |
|
||||
| ssl_cert_pem_file | | str | null | A file path to a file containing cert information for SSL validation. Must provide all three CName, cert file, and key file to enable SSL validation. |
|
||||
| ssl_key_pem_file | | st | null | A file path to a file containing key information for SSL validation. Must provide all three CName, cert file, and key file to enable SSL validation. |
|
||||
| ssl_key_pem_file | | str | null | A file path to a file containing key information for SSL validation. Must provide all three CName, cert file, and key file to enable SSL validation. |
|
||||
| ssl_cname | | str | null | A CName to use if enabling SSL validation on the cluster. Must provide all three CName, cert file, and key file to enable SSL validation. |
|
||||
| dns_name_label | | str | null | The DNS name label for the scoring endpoint. If not specified a unique DNS name label will be generated for the scoring endpoint. |
|
||||
|
||||
|
@ -151,14 +151,14 @@ For the deployment of the model to AKS, you must configure an AKS resource and s
|
|||
|
||||
| Parameter | Required | Allowed Values | Default | Description |
|
||||
| ----------------------- | -------- | -------------- | ---------- | ----------- |
|
||||
| gpu_cores | | float | 1 | The number of GPU cores to allocate for this Webservice. |
|
||||
| autoscale_enabled | | bool | true if `num_replicas` is null | Whether or not to enable autoscaling for this Webservice. |
|
||||
| gpu_cores | | int | 1 | The number of GPU cores to allocate for this Webservice. |
|
||||
| autoscale_enabled | | bool | true if `num_replicas` is null | Whether to enable autoscale for this Webservice. |
|
||||
| autoscale_min_replicas | | int | 1 | The minimum number of containers to use when autoscaling this Webservice. |
|
||||
| autoscale_max_replicas | | int | 10 | The maximum number of containers to use when autoscaling this Webservice. |
|
||||
| autoscale_refresh_seconds | | int | 1 | How often the autoscaler should attempt to scale this Webservice. |
|
||||
| autoscale_refresh_seconds | | int | 1 | How often the autoscaler should attempt to scale this Webservice (in seconds). |
|
||||
| autoscale_target_utilization| | int | 70 | The target utilization (in percent out of 100) the autoscaler should attempt to maintain for this Webservice. |
|
||||
| scoring_timeout_ms | | int | 60000 | A timeout in ms to enforce for scoring calls to this Webservice. |
|
||||
| replica_max_concurrent_requests| | float | 1 | The number of maximum concurrent requests per replica to allow for this Webservice. **Do not change this setting from the default value of 1 unless instructed by Microsoft Technical Support or a member of Azure Machine Learning team.** |
|
||||
| replica_max_concurrent_requests| | int | 1 | The number of maximum concurrent requests per replica to allow for this Webservice. **Do not change this setting from the default value of 1 unless instructed by Microsoft Technical Support or a member of Azure Machine Learning team.** |
|
||||
| max_request_wait_time | | int | 500 | The maximum amount of time a request will stay in the queue (in milliseconds) before returning a 503 error. |
|
||||
| num_replicas | | int | null | The number of containers to allocate for this Webservice. **No default, if this parameter is not set then the autoscaler is enabled by default.** |
|
||||
| period_seconds | | int: [1, inf[ | 10 | How often (in seconds) to perform the liveness probe. |
|
||||
|
@ -167,7 +167,7 @@ For the deployment of the model to AKS, you must configure an AKS resource and s
|
|||
| success_threshold | | int: [1, inf[ | 1 | The minimum consecutive successes for the liveness probe to be considered successful after having failed. |
|
||||
| failure_threshold | | int: [1, inf[ | 3 | When a Pod starts and the liveness probe fails, Kubernetes will try failureThreshold times before giving up. |
|
||||
| namespace | | str | null | The Kubernetes namespace in which to deploy this Webservice: up to 63 lowercase alphanumeric ('a'-'z', '0'-'9') and hyphen ('-') characters. The first and last characters cannot be hyphens. |
|
||||
| token_auth_enabled | | bool | false | Whether or not to enable Token auth for this Webservice. If this is enabled, users can access this Webservice by fetching an access token using their Azure Active Directory credentials. |
|
||||
| token_auth_enabled | | bool | false | Whether to enable Token authentication for this Webservice. If this is enabled, users can access this Webservice by fetching an access token using their Azure Active Directory credentials. |
|
||||
|
||||
Please visit [this website](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.webservice.aks.akswebservice?view=azure-ml-py#deploy-configuration-autoscale-enabled-none--autoscale-min-replicas-none--autoscale-max-replicas-none--autoscale-refresh-seconds-none--autoscale-target-utilization-none--collect-model-data-none--auth-enabled-none--cpu-cores-none--memory-gb-none--enable-app-insights-none--scoring-timeout-ms-none--replica-max-concurrent-requests-none--max-request-wait-time-none--num-replicas-none--primary-key-none--secondary-key-none--tags-none--properties-none--description-none--gpu-cores-none--period-seconds-none--initial-delay-seconds-none--timeout-seconds-none--success-threshold-none--failure-threshold-none--namespace-none--token-auth-enabled-none--compute-target-name-none-) for more details. More Information on autoscaling parameters can be found [here](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.webservice.aks.autoscaler?view=azure-ml-py) and for liveness probe [here](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.webservice.aks.livenessproberequirements?view=azure-ml-py).
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
set -e
|
||||
|
||||
ls -la
|
||||
ls -la code
|
||||
python /code/main.py
|
36
code/main.py
36
code/main.py
|
@ -12,24 +12,18 @@ from azureml.core.authentication import ServicePrincipalAuthentication
|
|||
from adal.adal_error import AdalError
|
||||
from msrest.exceptions import AuthenticationError
|
||||
from json import JSONDecodeError
|
||||
from utils import AMLConfigurationException, AMLDeploymentException, required_parameters_provided, get_resource_config, mask_parameter
|
||||
from utils import AMLConfigurationException, AMLDeploymentException, get_resource_config, mask_parameter, validate_json
|
||||
from schemas import azure_credentials_schema, parameters_schema
|
||||
|
||||
|
||||
def main():
|
||||
# Loading input values
|
||||
print("::debug::Loading input values")
|
||||
parameters_file = os.environ.get("INPUT_PARAMETERS_FILE", default="deploy.json")
|
||||
azure_credentials = os.environ.get("INPUT_AZURE_CREDENTIALS", default="{}")
|
||||
model_name = os.environ.get("INPUT_MODEL_NAME", default=None)
|
||||
model_version = os.environ.get("INPUT_MODEL_VERSION", default=None)
|
||||
|
||||
# Casting input values
|
||||
print("::debug::Casting input values")
|
||||
try:
|
||||
azure_credentials = json.loads(azure_credentials)
|
||||
except JSONDecodeError:
|
||||
print("::error::Please paste output of `az ad sp create-for-rbac --name <your-sp-name> --role contributor --scopes /subscriptions/<your-subscriptionId>/resourceGroups/<your-rg> --sdk-auth` as value of secret variable: AZURE_CREDENTIALS")
|
||||
raise AMLConfigurationException(f"Incorrect or poorly formed output from azure credentials saved in AZURE_CREDENTIALS secret. See setup in https://github.com/Azure/aml-compute/blob/master/README.md")
|
||||
try:
|
||||
model_version = int(model_version)
|
||||
except TypeError as exception:
|
||||
|
@ -39,12 +33,21 @@ def main():
|
|||
print(f"::debug::Could not cast model version to int: {exception}")
|
||||
model_version = None
|
||||
|
||||
# Loading azure credentials
|
||||
print("::debug::Loading azure credentials")
|
||||
azure_credentials = os.environ.get("INPUT_AZURE_CREDENTIALS", default="{}")
|
||||
try:
|
||||
azure_credentials = json.loads(azure_credentials)
|
||||
except JSONDecodeError:
|
||||
print("::error::Please paste output of `az ad sp create-for-rbac --name <your-sp-name> --role contributor --scopes /subscriptions/<your-subscriptionId>/resourceGroups/<your-rg> --sdk-auth` as value of secret variable: AZURE_CREDENTIALS")
|
||||
raise AMLConfigurationException(f"Incorrect or poorly formed output from azure credentials saved in AZURE_CREDENTIALS secret. See setup in https://github.com/Azure/aml-compute/blob/master/README.md")
|
||||
|
||||
# Checking provided parameters
|
||||
print("::debug::Checking provided parameters")
|
||||
required_parameters_provided(
|
||||
parameters=azure_credentials,
|
||||
keys=["tenantId", "clientId", "clientSecret"],
|
||||
message="Required parameter(s) not found in your azure credentials saved in AZURE_CREDENTIALS secret for logging in to the workspace. Please provide a value for the following key(s): "
|
||||
validate_json(
|
||||
data=azure_credentials,
|
||||
schema=azure_credentials_schema,
|
||||
input_name="AZURE_CREDENTIALS"
|
||||
)
|
||||
|
||||
# Mask values
|
||||
|
@ -56,6 +59,7 @@ def main():
|
|||
|
||||
# Loading parameters file
|
||||
print("::debug::Loading parameters file")
|
||||
parameters_file = os.environ.get("INPUT_PARAMETERS_FILE", default="deploy.json")
|
||||
parameters_file_path = os.path.join(".cloud", ".azure", parameters_file)
|
||||
try:
|
||||
with open(parameters_file_path) as f:
|
||||
|
@ -63,6 +67,14 @@ def main():
|
|||
except FileNotFoundError:
|
||||
print(f"::debug::Could not find parameter file in {parameters_file_path}. Please provide a parameter file in your repository if you do not want to use default settings (e.g. .cloud/.azure/deploy.json).")
|
||||
parameters = {}
|
||||
|
||||
# Checking provided parameters
|
||||
print("::debug::Checking provided parameters")
|
||||
validate_json(
|
||||
data=parameters,
|
||||
schema=parameters_schema,
|
||||
input_name="PARAMETERS_FILE"
|
||||
)
|
||||
|
||||
# Loading Workspace
|
||||
print("::debug::Loading AML Workspace")
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
azure_credentials_schema = {
|
||||
"$id": "http://azure-ml.com/schemas/azure_credentials.json",
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"title": "azure_credentials",
|
||||
"description": "JSON specification for your azure credentials",
|
||||
"type": "object",
|
||||
"required": ["clientId", "clientSecret", "subscriptionId", "tenantId"],
|
||||
"properties": {
|
||||
"clientId": {
|
||||
"type": "string",
|
||||
"description": "The client ID of the service principal."
|
||||
},
|
||||
"clientSecret": {
|
||||
"type": "string",
|
||||
"description": "The client secret of the service principal."
|
||||
},
|
||||
"subscriptionId": {
|
||||
"type": "string",
|
||||
"description": "The subscription ID that should be used."
|
||||
},
|
||||
"tenantId": {
|
||||
"type": "string",
|
||||
"description": "The tenant ID of the service principal."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameters_schema = {
|
||||
"$id": "http://azure-ml.com/schemas/deploy.json",
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"title": "aml-registermodel",
|
||||
"description": "JSON specification for your deploy details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name to give the deployed service.",
|
||||
"minLength": 3,
|
||||
"maxLength": 32
|
||||
},
|
||||
"deployment_compute_target": {
|
||||
"type": "string",
|
||||
"description": "Name of the compute target to deploy the webservice to."
|
||||
},
|
||||
"inference_source_directory": {
|
||||
"type": "string",
|
||||
"description": "The path to the folder that contains all files to create the image."
|
||||
},
|
||||
"inference_entry_script": {
|
||||
"type": "string",
|
||||
"description": "The path to a local file in your repository that contains the code to run for the image and score the data."
|
||||
},
|
||||
"test_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to run tests for this model deployment and the created real-time endpoint."
|
||||
},
|
||||
"test_file_path": {
|
||||
"type": "string",
|
||||
"description": "Path to the python script in your repository in which you define your own tests that you want to run against the webservice endpoint."
|
||||
},
|
||||
"test_file_function_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the function in your python script in your repository in which you define your own tests that you want to run against the webservice endpoint."
|
||||
},
|
||||
"conda_file": {
|
||||
"type": "string",
|
||||
"description": "The path to a local file in your repository containing a conda environment definition to use for the image."
|
||||
},
|
||||
"extra_docker_file_steps": {
|
||||
"type": "string",
|
||||
"description": "The path to a local file in your repository containing additional Docker steps to run when setting up image."
|
||||
},
|
||||
"enable_gpu": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates whether to enable GPU support in the image."
|
||||
},
|
||||
"cuda_version": {
|
||||
"type": "string",
|
||||
"description": "The Version of CUDA to install for images that need GPU support."
|
||||
},
|
||||
"model_data_collection_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not to enable model data collection for this Webservice."
|
||||
},
|
||||
"authentication_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not to enable key auth for this Webservice."
|
||||
},
|
||||
"app_insights_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not to enable Application Insights logging for this Webservice."
|
||||
},
|
||||
"runtime": {
|
||||
"type": "string",
|
||||
"description": "The runtime to use for the image.",
|
||||
"pattern": "python|spark-py"
|
||||
},
|
||||
"custom_base_image": {
|
||||
"type": "string",
|
||||
"description": "A custom Docker image to be used as base image."
|
||||
},
|
||||
"cpu_cores": {
|
||||
"type": "number",
|
||||
"description": "The number of CPU cores to allocate for this Webservice."
|
||||
},
|
||||
"memory_gb": {
|
||||
"type": "number",
|
||||
"description": "The amount of memory (in GB) to allocate for this Webservice."
|
||||
},
|
||||
"delete_service_after_test": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates whether the service gets deleted after the deployment completed successfully."
|
||||
},
|
||||
"tags": {
|
||||
"type": "object",
|
||||
"description": "Dictionary of key value tags to give this Webservice."
|
||||
},
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"description": "Dictionary of key value properties to give this Webservice."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "A description to give this Webservice and image."
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "The Azure region to deploy this Webservice to."
|
||||
},
|
||||
"ssl_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not to enable SSL for this Webservice."
|
||||
},
|
||||
"ssl_cert_pem_file": {
|
||||
"type": "string",
|
||||
"description": "A file path to a file containing cert information for SSL validation."
|
||||
},
|
||||
"ssl_key_pem_file": {
|
||||
"type": "string",
|
||||
"description": "A file path to a file containing key information for SSL validation."
|
||||
},
|
||||
"ssl_cname": {
|
||||
"type": "string",
|
||||
"description": "A CName to use if enabling SSL validation on the cluster."
|
||||
},
|
||||
"dns_name_label": {
|
||||
"type": "string",
|
||||
"description": "The DNS name label for the scoring endpoint."
|
||||
},
|
||||
"gpu_cores": {
|
||||
"type": "integer",
|
||||
"description": "The number of GPU cores to allocate for this Webservice."
|
||||
},
|
||||
"autoscale_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable autoscale for this Webservice."
|
||||
},
|
||||
"autoscale_min_replicas": {
|
||||
"type": "integer",
|
||||
"description": "The minimum number of containers to use when autoscaling this Webservice.",
|
||||
"minimum": 1
|
||||
},
|
||||
"autoscale_max_replicas": {
|
||||
"type": "integer",
|
||||
"description": "The maximum number of containers to use when autoscaling this Webservice.",
|
||||
"minimum": 1
|
||||
},
|
||||
"autoscale_refresh_seconds": {
|
||||
"type": "integer",
|
||||
"description": "How often the autoscaler should attempt to scale this Webservice (in seconds).",
|
||||
"minimum": 1
|
||||
},
|
||||
"autoscale_target_utilization": {
|
||||
"type": "integer",
|
||||
"description": "The target utilization (in percent out of 100) the autoscaler should attempt to maintain for this Webservice.",
|
||||
"minimum": 1,
|
||||
"maximum": 100
|
||||
},
|
||||
"scoring_timeout_ms": {
|
||||
"type": "integer",
|
||||
"description": "A timeout in ms to enforce for scoring calls to this Webservice.",
|
||||
"minimum": 1
|
||||
},
|
||||
"replica_max_concurrent_requests": {
|
||||
"type": "integer",
|
||||
"description": "The number of maximum concurrent requests per replica to allow for this Webservice.",
|
||||
"minimum": 1
|
||||
},
|
||||
"max_request_wait_time": {
|
||||
"type": "integer",
|
||||
"description": "The maximum amount of time a request will stay in the queue (in milliseconds) before returning a 503 error."
|
||||
},
|
||||
"num_replicas": {
|
||||
"type": "integer",
|
||||
"description": "The number of containers to allocate for this Webservice."
|
||||
},
|
||||
"period_seconds": {
|
||||
"type": "integer",
|
||||
"description": "How often (in seconds) to perform the liveness probe.",
|
||||
"minimum": 1
|
||||
},
|
||||
"initial_delay_seconds": {
|
||||
"type": "integer",
|
||||
"description": "The number of seconds after the container has started before liveness probes are initiated.",
|
||||
"minimum": 1
|
||||
},
|
||||
"timeout_seconds": {
|
||||
"type": "integer",
|
||||
"description": "The number of seconds after which the liveness probe times out.",
|
||||
"minimum": 1
|
||||
},
|
||||
"success_threshold": {
|
||||
"type": "integer",
|
||||
"description": "The minimum consecutive successes for the liveness probe to be considered successful after having failed.",
|
||||
"minimum": 1
|
||||
},
|
||||
"failure_threshold": {
|
||||
"type": "integer",
|
||||
"description": "When a Pod starts and the liveness probe fails, Kubernetes will try failureThreshold times before giving up.",
|
||||
"minimum": 1
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"description": "The Kubernetes namespace in which to deploy this Webservice.",
|
||||
"maxLength": 63,
|
||||
"pattern": "([a-z0-9\-])+"
|
||||
},
|
||||
"token_auth_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable Token authentication for this Webservice."
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
import jsonschema
|
||||
|
||||
|
||||
class AMLConfigurationException(Exception):
|
||||
pass
|
||||
|
||||
|
@ -6,15 +9,15 @@ class AMLDeploymentException(Exception):
|
|||
pass
|
||||
|
||||
|
||||
def required_parameters_provided(parameters, keys, message="Required parameter(s) not found in your parameters file. Please provide a value for the following key(s): "):
|
||||
missing_keys = []
|
||||
for key in keys:
|
||||
if key not in parameters:
|
||||
err_msg = f"{message} {key}"
|
||||
print(f"::error::{err_msg}")
|
||||
missing_keys.append(key)
|
||||
if len(missing_keys) > 0:
|
||||
raise AMLConfigurationException(f"{message} {missing_keys}")
|
||||
def validate_json(data, schema, input_name):
|
||||
validator = jsonschema.Draft7Validator(schema)
|
||||
errors = validator.iter_errors(data)
|
||||
if len(list(errors)) > 0:
|
||||
for error in errors:
|
||||
print(f"::error::JSON validation error: {error}")
|
||||
raise AMLConfigurationException(f"JSON validation error for '{input_name}'. Provided object does not match schema. Please check the output for more details.")
|
||||
else:
|
||||
print(f"::debug::JSON validation passed for '{input_name}'. Provided object does match schema.")
|
||||
|
||||
|
||||
def get_resource_config(config, resource_config, config_name):
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
myPath = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.join(myPath, "..", "code"))
|
||||
|
||||
from main import main
|
||||
from utils import AMLConfigurationException
|
||||
|
||||
|
||||
def test_main_no_input():
|
||||
"""
|
||||
Unit test to check the main function with no inputs
|
||||
"""
|
||||
with pytest.raises(AMLConfigurationException):
|
||||
assert main()
|
||||
|
||||
|
||||
def test_main_invalid_azure_credentials():
|
||||
os.environ["INPUT_AZURE_CREDENTIALS"] = ""
|
||||
with pytest.raises(AMLConfigurationException):
|
||||
assert main()
|
||||
|
||||
|
||||
def test_main_invalid_parameters_file():
|
||||
os.environ["INPUT_AZURE_CREDENTIALS"] = """{
|
||||
'clientId': 'test',
|
||||
'clientSecret': 'test',
|
||||
'subscriptionId': 'test',
|
||||
'tenantId': 'test'
|
||||
}"""
|
||||
os.environ["INPUT_PARAMETERS_FILE"] = "wrongfile.json"
|
||||
with pytest.raises(AMLConfigurationException):
|
||||
assert main()
|
|
@ -0,0 +1,59 @@
|
|||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
myPath = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.join(myPath, "..", "code"))
|
||||
|
||||
from utils import validate_json, AMLConfigurationException
|
||||
from schemas import azure_credentials_schema
|
||||
|
||||
|
||||
def test_validate_json_valid_inputs():
|
||||
"""
|
||||
Unit test to check the validate_json function with valid inputs
|
||||
"""
|
||||
json_object = {
|
||||
"clientId": "",
|
||||
"clientSecret": "",
|
||||
"subscriptionId": "",
|
||||
"tenantId": ""
|
||||
}
|
||||
schema_object = azure_credentials_schema
|
||||
validate_json(
|
||||
data=json_object,
|
||||
schema=schema_object,
|
||||
input_name="PARAMETERS_FILE"
|
||||
)
|
||||
|
||||
|
||||
def test_validate_json_invalid_json():
|
||||
"""
|
||||
Unit test to check the validate_json function with invalid json_object inputs
|
||||
"""
|
||||
json_object = {
|
||||
"clientId": "",
|
||||
"clientSecret": "",
|
||||
"subscriptionId": ""
|
||||
}
|
||||
schema_object = azure_credentials_schema
|
||||
with pytest.raises(AMLConfigurationException):
|
||||
assert validate_json(
|
||||
data=json_object,
|
||||
schema=schema_object,
|
||||
input_name="PARAMETERS_FILE"
|
||||
)
|
||||
|
||||
|
||||
def test_validate_json_invalid_schema():
|
||||
"""
|
||||
Unit test to check the validate_json function with invalid schema inputs
|
||||
"""
|
||||
json_object = {}
|
||||
schema_object = {}
|
||||
with pytest.raises(Exception):
|
||||
assert validate_json(
|
||||
data=json_object,
|
||||
schema=schema_object,
|
||||
input_name="PARAMETERS_FILE"
|
||||
)
|
Загрузка…
Ссылка в новой задаче