Esempio n. 1
0
def test_get_volume_containing_path_runtime_error(os, list_volumes, path):
    """Test get_volume_containing_path() with no backing volume."""
    os.path.isabs.return_value = True
    os.path.exists.return_value = True
    list_volumes.return_value = _list_volumes_return_value
    with pytest.raises(RuntimeError):
        podutils.get_volume_containing_path(path)
Esempio n. 2
0
File: nb.py Progetto: ydataai/kale
def get_volume_containing_path(request, path):
    """Get the closest volume mount point to the input absolute path."""
    vol = podutils.get_volume_containing_path(path)
    return {"name": vol[1].name, "mount_point": vol[0]}
Esempio n. 3
0
def test_get_volume_containing_path(os, list_volumes, path, ret):
    """Test successful execution of get_volume_containing_path()."""
    os.path.exists.return_value = True
    list_volumes.return_value = _list_volumes_return_value
    assert podutils.get_volume_containing_path(path) == ret
Esempio n. 4
0
def test_get_volume_containing_path_value_error(path):
    """Test get_volume_containing_path() with bad input."""
    with pytest.raises(ValueError):
        podutils.get_volume_containing_path(path)
Esempio n. 5
0
def serve(model: Any,
          name: str = None,
          wait: bool = True,
          predictor: str = None,
          preprocessing_fn: Callable = None,
          preprocessing_assets: Dict = None) -> KFServer:
    """Main API used to serve models from a notebook or a pipeline step.

    This function procedurally deploys a KFServing InferenceService, starting
    from a model object. A summary list of actions follows:

    * Autogenerate an InferenceService name, if not provided
    * Process transformer function (and related assets)
    * Dump the model, to a path under a mounted PVC
    * Snapshot the PVC
    * Hydrate a new PVC from the new snapshot
    * Submit an InferenceService CR
    * Monitor the CR until it becomes ready

    FIXME: Improve documentation. Provide some examples in the docstring and
      explain how the preprocessing function parsing works.

    Args:
        model: Model object to be used as a predictor
        name (optional): Name of the predictor. Will be autogenerated if not
            provided
        wait (optional): Wait for the InferenceService to become ready.
            Default: True
        predictor (optional): Predictor type to be used for the
            InferenceService. If not provided it will be inferred using
            the the matching marshalling backends.
        preprocessing_fn (optional): A processing function that will be
            deployed as a KFServing Transformer
        preprocessing_assets (optional): A dictionary with object required by
            the preprocessing function. This is needed in case the
            preprocessing function references global objects.

    Returns: A KFServer instance
    """
    log.info("Starting serve procedure for model '%s'", model)
    if not name:
        name = "%s-%s" % (podutils.get_pod_name(), utils.random_string(5))

    # Validate and process transformer
    if preprocessing_fn:
        _prepare_transformer_assets(preprocessing_fn, preprocessing_assets)

    # Detect predictor type
    predictor_type = marshal.get_backend(model).predictor_type
    if predictor and predictor != predictor_type:
        raise RuntimeError("Trying to create an InferenceService with"
                           " predictor of type '%s' but the model is of type"
                           " '%s'" % (predictor, predictor_type))
    if not predictor_type:
        log.error(
            "Kale does not yet support serving objects with '%s'"
            " backend.\n\nPlease help us improve Kale by opening a new"
            " issue at:\n"
            "https://github.com/kubeflow-kale/kale/issues",
            marshal.get_backend(model).display_name)
        utils.graceful_exit(-1)
    predictor = predictor_type  # in case `predictor` is None

    volume = podutils.get_volume_containing_path(PVC_ROOT)
    volume_name = volume[1].persistent_volume_claim.claim_name
    log.info("Model is contained in volume '%s'", volume_name)

    # Dump the model
    marshal.set_data_dir(PREDICTOR_MODEL_DIR)
    model_filepath = marshal.save(model, "model")
    log.info("Model saved successfully at '%s'", model_filepath)

    # Take snapshot
    task_info = rokutils.snapshot_pvc(volume_name,
                                      bucket=rokutils.SERVING_BUCKET,
                                      wait=True)
    task = rokutils.get_task(task_info["task"]["id"],
                             bucket=rokutils.SERVING_BUCKET)
    new_pvc_name = "%s-pvc-%s" % (name, utils.random_string(5))
    rokutils.hydrate_pvc_from_snapshot(task["result"]["event"]["object"],
                                       task["result"]["event"]["version"],
                                       new_pvc_name,
                                       bucket=rokutils.SERVING_BUCKET)

    # Cleanup: remove dumped model and transformer assets from the current PVC
    utils.rm_r(
        os.path.join(PREDICTOR_MODEL_DIR, os.path.basename(model_filepath)))
    utils.rm_r(TRANSFORMER_ASSETS_DIR, silent=True)

    # Need an absolute path from the *root* of the PVC. Add '/' if not exists.
    pvc_model_path = "/" + PREDICTOR_MODEL_DIR.lstrip(PVC_ROOT)
    # Tensorflow saves the model's files into a directory by itself
    if predictor == "tensorflow":
        pvc_model_path += "/" + os.path.basename(model_filepath).lstrip("/")

    kfserver = create_inference_service(name=name,
                                        predictor=predictor,
                                        pvc_name=new_pvc_name,
                                        model_path=pvc_model_path,
                                        transformer=preprocessing_fn
                                        is not None)

    if wait:
        monitor_inference_service(kfserver.name)
    return kfserver