Skip to content

Commit

Permalink
add APIs to wait for isvc ready and check status (kserve#610)
Browse files Browse the repository at this point in the history
  • Loading branch information
jinchihe authored and k8s-ci-robot committed Jan 10, 2020
1 parent e6c13a1 commit 1ac1908
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 50 deletions.
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 |

## 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

0 comments on commit 1ac1908

Please sign in to comment.