Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add APIs to wait for isvc ready and check status #610

Merged
merged 1 commit into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion python/kfserving/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ Class | Method | Description
[KFServingClient](docs/KFServingClient.md) | [rollout_canary](docs/KFServingClient.md#rollout_canary) | Rollout the traffic on `canary` version for specified InferenceService|
[KFServingClient](docs/KFServingClient.md) | [promote](docs/KFServingClient.md#promote) | Promote the `canary` version of the InferenceService to `default`|
[KFServingClient](docs/KFServingClient.md) | [delete](docs/KFServingClient.md#delete) | Delete the specified InferenceService |

[KFServingClient](docs/KFServingClient.md) | [wait_isvc_ready](docs/KFServingClient.md#wait_isvc_ready) | Wait for the InferenceService to be ready |
[KFServingClient](docs/KFServingClient.md) | [is_isvc_ready](docs/KFServingClient.md#is_isvc_ready) | Check if the InferenceService is ready |

## Documentation For Models

Expand Down
53 changes: 53 additions & 0 deletions python/kfserving/docs/KFServingClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ KFServingClient | [replace](#replace) | Replace the specified InferenceService|
KFServingClient | [rollout_canary](#rollout_canary) | Rollout the traffic on `canary` version for specified InferenceService|
KFServingClient | [promote](#promote) | Promote the `canary` version of the InferenceService to `default`|
KFServingClient | [delete](#delete) | Delete the specified InferenceService |
KFServingClient | [wait_isvc_ready](#wait_isvc_ready) | Wait for the InferenceService to be ready |
KFServingClient | [is_isvc_ready](#is_isvc_read) | Check if the InferenceService is ready |
jinchihe marked this conversation as resolved.
Show resolved Hide resolved

## set_credentials
> set_credentials(storage_type, namespace=None, credentials_file=None, service_account='kfserving-service-credentials', **kwargs):
Expand Down Expand Up @@ -370,3 +372,54 @@ namespace | str | The inferenceservice's namespace. Defaults to current or defau

### Return type
object


## wait_isvc_ready
> wait_isvc_ready(name, namespace=None, watch=False, timeout_seconds=600, polling_interval=10):

Wait for the InferenceService to be ready.

### Example

```python
from kfserving import KFServingClient

KFServing = KFServingClient()
KFServing.wait_isvc_ready('flower-sample', namespace='kubeflow')
```

### Parameters
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
name | str | The InferenceService name.| |
namespace | str | The InferenceService namespace. Defaults to current or default namespace. | Optional|
watch | bool | Watch the specified InferenceService if `True`. | Optional |
timeout_seconds | int | How long to wait for the InferenceService, default wait for 600 seconds. | Optional|
polling_interval | int | How often to poll for the status of the InferenceService.| Optional|

### Return type
object


## is_isvc_ready
> is_isvc_ready(name, namespace=None)

Returns True if the InferenceService is ready; false otherwise.

### Example

```python
from kfserving import KFServingClient

KFServing = KFServingClient()
KFServing.is_isvc_ready('flower-sample', namespace='kubeflow')
```

### Parameters
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
name | str | The InferenceService name.| |
namespace | str | The InferenceService namespace. Defaults to current or default namespace.| Optional |

### Return type
Bool
46 changes: 46 additions & 0 deletions python/kfserving/kfserving/api/kf_serving_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,49 @@ def delete(self, name, namespace=None):
raise RuntimeError(
"Exception when calling CustomObjectsApi->delete_namespaced_custom_object:\
%s\n" % e)


def is_isvc_ready(self, name, namespace=None): #pylint:disable=inconsistent-return-statements
"""
Check if the inference service is ready.
:param name: inference service name
:param namespace: defaults to current or default namespace
:return:
"""
kfsvc_status = self.get(name, namespace=namespace)
status = 'Unknown'
for condition in kfsvc_status['status'].get('conditions', {}):
if condition.get('type', '') == 'Ready':
status = condition.get('status', 'Unknown')
return status.lower() == "true"
return False


def wait_isvc_ready(self, name, namespace=None, #pylint:disable=too-many-arguments
watch=False,
timeout_seconds=600,
polling_interval=10):
"""
Waiting for inference service ready, print out the inference service if timeout.
:param name: inference service name
:param namespace: defaults to current or default namespace
:param watch: True to watch the service until timeout elapsed or status is ready
:param timeout_seconds: timeout seconds for waiting, default to 600s.
Print out the InferenceService if timeout.
:param polling_interval: The time interval to poll status
:return:
"""
if watch:
isvc_watch(
name=name,
namespace=namespace,
timeout_seconds=timeout_seconds)
else:
for _ in range(round(timeout_seconds/polling_interval)):
time.sleep(polling_interval)
if self.is_isvc_ready(name, namespace=namespace):
return

current_isvc = self.get(name, namespace=namespace)
raise RuntimeError("Timeout to start the InferenceService {}. \
The InferenceService is as following: {}".format(name, current_isvc))
8 changes: 4 additions & 4 deletions python/kfserving/kfserving/constants/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
import os

# KFServing K8S constants
KFSERVING_GROUP = "serving.kubeflow.org"
KFSERVING_KIND = "InferenceService"
KFSERVING_PLURAL = "inferenceservices"
KFSERVING_VERSION = "v1alpha2"
KFSERVING_GROUP = 'serving.kubeflow.org'
KFSERVING_KIND = 'InferenceService'
KFSERVING_PLURAL = 'inferenceservices'
KFSERVING_VERSION = os.environ.get('KFSERVING_VERSION', 'v1alpha2')

KFSERVING_LOGLEVEL = os.environ.get('KFSERVING_LOGLEVEL', 'INFO').upper()

Expand Down
36 changes: 0 additions & 36 deletions test/e2e/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,42 +26,6 @@
KFSERVING_TEST_NAMESPACE = "kfserving-ci-e2e-test"


def wait_for_isvc_ready(name, namespace=KFSERVING_TEST_NAMESPACE,
timeout_seconds=600, debug=True):
for _ in range(round(timeout_seconds/10)):
time.sleep(10)
kfsvc_status = KFServing.get(name, namespace=namespace)
status = 'Unknown'
for condition in kfsvc_status['status'].get('conditions', {}):
if condition.get('type', '') == 'Ready':
status = condition.get('status', 'Unknown')
if status == 'True':
return
if debug is True:
logging.warning("Timeout to start the InferenceService %s.", name)
logging.info("Getting the detailed InferenceService ...")
logging.info(KFServing.get(name, namespace=namespace))
get_pod_log(pod='kfserving-controller-manager-0',
namespace=KFSERVING_NAMESPACE,
container='manager')
raise RuntimeError("Timeout to start the InferenceService %s. See above log for details.", name)


def get_pod_log(pod, namespace=KFSERVING_NAMESPACE, container=''):
"""
Note the arg container must be '' here, instead of None.
Otherwise API read_namespaced_pod_log will fail if no specified container.
"""
logging.info("Getting logs of Pod %s ... ", pod)
try:
config.load_kube_config()
core_api = client.CoreV1Api()
pod_logs = core_api.read_namespaced_pod_log(pod, namespace, container=container)
logging.info("The logs of Pod %s log:\n %s", pod, pod_logs)
except client.rest.ApiException as e:
logging.info("Exception when calling CoreV1Api->read_namespaced_pod_log: %s\n", e)


def predict(service_name, input_json):
isvc = KFServing.get(service_name, namespace=KFSERVING_TEST_NAMESPACE)
api_instance = client.CoreV1Api(client.ApiClient())
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/predictor/test_sklearn.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from kfserving import V1alpha2InferenceService
from kubernetes.client import V1ResourceRequirements

from ..common.utils import wait_for_isvc_ready, predict
from ..common.utils import predict
from ..common.utils import KFSERVING_TEST_NAMESPACE

api_version = constants.KFSERVING_GROUP + '/' + constants.KFSERVING_VERSION
Expand All @@ -48,7 +48,7 @@ def test_sklearn_kfserving():
spec=V1alpha2InferenceServiceSpec(default=default_endpoint_spec))

KFServing.create(isvc)
wait_for_isvc_ready(service_name)
KFServing.wait_isvc_ready(service_name, namespace=KFSERVING_TEST_NAMESPACE)
probs = predict(service_name, './data/iris_input.json')
assert(probs == [1, 1])
KFServing.delete(service_name, KFSERVING_TEST_NAMESPACE)
5 changes: 2 additions & 3 deletions test/e2e/predictor/test_tensorflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from kfserving import V1alpha2InferenceService
from kubernetes.client import V1ResourceRequirements

from ..common.utils import wait_for_isvc_ready, predict
from ..common.utils import predict
from ..common.utils import KFSERVING_TEST_NAMESPACE

api_version = constants.KFSERVING_GROUP + '/' + constants.KFSERVING_VERSION
Expand All @@ -49,5 +49,4 @@ def test_tensorflow_kfserving():
spec=V1alpha2InferenceServiceSpec(default=default_endpoint_spec))

KFServing.create(isvc)
wait_for_isvc_ready(service_name)

KFServing.wait_isvc_ready(service_name, namespace=KFSERVING_TEST_NAMESPACE)
4 changes: 2 additions & 2 deletions test/e2e/predictor/test_xgboost.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from kfserving import V1alpha2InferenceService
from kubernetes.client import V1ResourceRequirements

from ..common.utils import wait_for_isvc_ready, predict
from ..common.utils import predict
from ..common.utils import KFSERVING_TEST_NAMESPACE

api_version = constants.KFSERVING_GROUP + '/' + constants.KFSERVING_VERSION
Expand All @@ -48,7 +48,7 @@ def test_sklearn_kfserving():
spec=V1alpha2InferenceServiceSpec(default=default_endpoint_spec))

KFServing.create(isvc)
wait_for_isvc_ready(service_name)
KFServing.wait_isvc_ready(service_name, namespace=KFSERVING_TEST_NAMESPACE)
probs = predict(service_name, './data/iris_input.json')
assert(probs == [1, 1])
KFServing.delete(service_name, KFSERVING_TEST_NAMESPACE)
4 changes: 2 additions & 2 deletions test/e2e/transformer/test_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from kfserving import V1alpha2InferenceService
from kubernetes.client import V1ResourceRequirements
from kubernetes.client import V1Container
from ..common.utils import wait_for_isvc_ready, predict
from ..common.utils import predict
from ..common.utils import KFSERVING_TEST_NAMESPACE

api_version = constants.KFSERVING_GROUP + '/' + constants.KFSERVING_VERSION
Expand Down Expand Up @@ -61,7 +61,7 @@ def test_transformer():
spec=V1alpha2InferenceServiceSpec(default=default_endpoint_spec))

KFServing.create(isvc)
wait_for_isvc_ready(service_name)
KFServing.wait_isvc_ready(service_name, namespace=KFSERVING_TEST_NAMESPACE)
probs = predict(service_name, './data/transformer.json')
assert(np.argmax(probs) == 3)
KFServing.delete(service_name, KFSERVING_TEST_NAMESPACE)
Expand Down