Skip to content

Commit

Permalink
Merge pull request #156 from kubeflow/main
Browse files Browse the repository at this point in the history
[pull] main from kubeflow:main
  • Loading branch information
openshift-merge-bot[bot] authored Dec 17, 2024
2 parents 682853d + f56a131 commit 1bf4ea6
Show file tree
Hide file tree
Showing 59 changed files with 2,244 additions and 1,028 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-image-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
IMG_VERSION: ${{ steps.tags.outputs.tag }}
run: make image/build
- name: Start Kind Cluster
uses: helm/kind-action@v1.10.0
uses: helm/kind-action@v1.11.0
with:
node_image: "kindest/node:v1.27.11"
- name: Load Local Registry Test Image
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/csi-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
run: make image/build

- name: Start KinD cluster
uses: helm/kind-action@v1.10.0
uses: helm/kind-action@v1.11.0
with:
node_image: "kindest/node:v1.27.11"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ jobs:
IMG_VERSION: ${{ steps.tags.outputs.tag }}
run: make image/build
- name: Start Kind Cluster
uses: helm/kind-action@v1.10.0
uses: helm/kind-action@v1.11.0
with:
node_image: "kindest/node:v1.27.11"
cluster_name: chart-testing-py-${{ matrix.python }}
Expand Down
52 changes: 26 additions & 26 deletions clients/python/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion clients/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ coverage = { extras = ["toml"], version = "^7.3.2" }
pytest-cov = ">=4.1,<7.0"
ruff = ">=0.5.2,<0.9.0"
mypy = "^1.7.0"
pytest-asyncio = ">=0.23.7,<0.25.0"
pytest-asyncio = ">=0.23.7,<0.26.0"
requests = "^2.32.2"
black = "^24.4.2"
types-python-dateutil = "^2.9.0.20240906"
Expand Down
34 changes: 29 additions & 5 deletions clients/ui/api/openapi/mod-arch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ paths:
operationId: healthcheck
summary: HealthCheck
description: HealthCheck endpoint.
/api/v1/config:
summary: Path used to manage Configuration information regarding the UI.
/api/v1/user:
summary: Path used to Retrieve a user based on the header.
description: >-
The REST endpoint/path used pass all the config information needed for the UI.
get:
tags:
- K8SOperation
parameters:
- $ref: "#/components/parameters/kubeflowUserId"
responses:
"200":
$ref: "#/components/responses/ConfigResponse"
Expand All @@ -49,6 +51,8 @@ paths:
get:
tags:
- K8SOperation
parameters:
- $ref: "#/components/parameters/kubeflowUserId"
responses:
"200":
$ref: "#/components/responses/ModelRegistryRespone"
Expand All @@ -68,6 +72,7 @@ paths:
- ModelRegistryService
parameters:
- $ref: "#/components/parameters/modelRegistryName"
- $ref: "#/components/parameters/kubeflowUserId"
responses:
"200":
$ref: "#/components/responses/ModelVersionResponse"
Expand Down Expand Up @@ -112,6 +117,7 @@ paths:
description: Updates an existing `ModelVersion`.
parameters:
- $ref: "#/components/parameters/modelRegistryName"
- $ref: "#/components/parameters/kubeflowUserId"
- name: modelversionId
description: A unique identifier for a `ModelVersion`.
schema:
Expand All @@ -131,6 +137,7 @@ paths:
- $ref: "#/components/parameters/orderBy"
- $ref: "#/components/parameters/sortOrder"
- $ref: "#/components/parameters/nextPageToken"
- $ref: "#/components/parameters/kubeflowUserId"
responses:
"200":
$ref: "#/components/responses/RegisteredModelListResponse"
Expand Down Expand Up @@ -159,6 +166,7 @@ paths:
- ModelRegistryService
parameters:
- $ref: "#/components/parameters/modelRegistryName"
- $ref: "#/components/parameters/kubeflowUserId"
responses:
"201":
$ref: "#/components/responses/RegisteredModelResponse"
Expand All @@ -180,6 +188,7 @@ paths:
- ModelRegistryService
parameters:
- $ref: "#/components/parameters/modelRegistryName"
- $ref: "#/components/parameters/kubeflowUserId"
responses:
"200":
$ref: "#/components/responses/RegisteredModelResponse"
Expand Down Expand Up @@ -224,6 +233,7 @@ paths:
description: Updates an existing `RegisteredModel`.
parameters:
- $ref: "#/components/parameters/modelRegistryName"
- $ref: "#/components/parameters/kubeflowUserId"
- name: registeredmodelId
description: A unique identifier for a `RegisteredModel`.
schema:
Expand All @@ -245,6 +255,7 @@ paths:
- $ref: "#/components/parameters/orderBy"
- $ref: "#/components/parameters/sortOrder"
- $ref: "#/components/parameters/nextPageToken"
- $ref: "#/components/parameters/kubeflowUserId"
responses:
"200":
$ref: "#/components/responses/ArtifactListResponse"
Expand Down Expand Up @@ -274,6 +285,7 @@ paths:
- ModelRegistryService
parameters:
- $ref: "#/components/parameters/modelRegistryName"
- $ref: "#/components/parameters/kubeflowUserId"
responses:
"200":
$ref: "#/components/responses/ArtifactResponse"
Expand Down Expand Up @@ -311,6 +323,7 @@ paths:
- $ref: "#/components/parameters/orderBy"
- $ref: "#/components/parameters/sortOrder"
- $ref: "#/components/parameters/nextPageToken"
- $ref: "#/components/parameters/kubeflowUserId"
responses:
"200":
$ref: "#/components/responses/ModelVersionListResponse"
Expand Down Expand Up @@ -355,6 +368,7 @@ paths:
description: Creates a new instance of a `ModelVersion`.
parameters:
- $ref: "#/components/parameters/modelRegistryName"
- $ref: "#/components/parameters/kubeflowUserId"
- name: registeredmodelId
description: A unique identifier for a `RegisteredModel`.
schema:
Expand All @@ -365,12 +379,16 @@ components:
schemas:
Config:
required:
- username
- userId
- clusterAdmin
type: object
properties:
username:
userId:
type: string
example: username-1
example: user@example.com
clusterAdmin:
type: boolean
example: true
ModelRegistry:
required:
- name
Expand Down Expand Up @@ -1193,6 +1211,12 @@ components:
$ref: "#/components/schemas/ServeModel"
description: A response containing a `ServeModel` entity.
parameters:
kubeflowUserId:
in: header
name: kubeflow-userid
schema:
type: string
required: true
modelRegistryName:
name: modelRegistryName
description: Name of the Model Registry selected.
Expand Down
40 changes: 40 additions & 0 deletions clients/ui/bff/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ make docker-build
| URL Pattern | Handler | Action |
|----------------------------------------------------------------------------------------------|----------------------------------------------|-------------------------------------------------------------|
| GET /v1/healthcheck | HealthcheckHandler | Show application information. |
| GET /v1/user | UserHandler | Show "kubeflow-user-id" from header information. |
| GET /v1/model_registry | ModelRegistryHandler | Get all model registries, |
| GET /v1/model_registry/{model_registry_id}/registered_models | GetAllRegisteredModelsHandler | Gets a list of all RegisteredModel entities. |
| POST /v1/model_registry/{model_registry_id}/registered_models | CreateRegisteredModelHandler | Create a RegisteredModel entity. |
Expand All @@ -78,6 +79,10 @@ You will need to inject your requests with a kubeflow-userid header for authoriz
curl -i -H "kubeflow-userid: user@example.com" localhost:4000/api/v1/healthcheck
```
```
# GET /v1/user
curl -i -H "kubeflow-userid: user@example.com" localhost:4000/api/v1/user
```
```
# GET /v1/model_registry
curl -i -H "kubeflow-userid: user@example.com" localhost:4000/api/v1/model_registry
```
Expand Down Expand Up @@ -211,3 +216,38 @@ curl -i -H "kubeflow-userid: user@example.com" "http://localhost:4000/api/v1/mod
# Get with a page size of 5, order by last update time in descending order.
curl -i -H "kubeflow-userid: user@example.com" "http://localhost:4000/api/v1/model_registry/model-registry/registered_models?pageSize=5&orderBy=LAST_UPDATE_TIME&sortOrder=DESC"
```


### FAQ

#### 1. How do we filter model registry services from other Kubernetes services?

We filter Model Registry services by using the Kubernetes label `component: model-registry. This label helps distinguish Model Registry services from other services in the cluster.

For example, in our service manifest, the `component label is defined as follows:
```yaml
# ...
labels:
# ...
component: model-registry
#...
```
You can view the complete Model Registry service manifest [here](https://github.com/kubeflow/model-registry/blob/main/manifests/kustomize/base/model-registry-service.yaml#L10).

#### 2. What is the structure of the mock Kubernetes environment?

The mock Kubernetes environment is activated when the environment variable `MOCK_K8S_CLIENT` is set to `true`. It is based on `env-test` and is designed to simulate a realistic Kubernetes setup for testing. The mock has the following characteristics:

- **Namespaces**:
- `kubeflow`
- `dora-namespace`

- **Users**:
- `user@example.com` (has `cluster-admin` privileges)
- `doraNonAdmin@example.com` (restricted to the `dora-namespace`)

- **Services (Model Registries)**:
- `model-registry`: resides in the `kubeflow` namespace with the label `component: model-registry`.
- `model-registry-dora`: resides in the `dora-namespace` namespace with the label `component: model-registry`.
- `model-registry-bella`: resides in the `kubeflow` namespace with the label `component: model-registry`.
- `non-model-registry`: resides in the `kubeflow` namespace *without* the label `component: model-registry`.
2 changes: 1 addition & 1 deletion clients/ui/bff/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/onsi/gomega v1.35.1
github.com/stretchr/testify v1.9.0
k8s.io/api v0.31.2
k8s.io/apimachinery v0.31.3
k8s.io/apimachinery v0.31.4
k8s.io/client-go v0.31.2
sigs.k8s.io/controller-runtime v0.19.1
)
Expand Down
4 changes: 2 additions & 2 deletions clients/ui/bff/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0=
k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk=
k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk=
k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk=
k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4=
k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/apimachinery v0.31.4 h1:8xjE2C4CzhYVm9DGf60yohpNUh5AEBnPxCryPBECmlM=
k8s.io/apimachinery v0.31.4/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc=
k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
Expand Down
2 changes: 2 additions & 0 deletions clients/ui/bff/internal/api/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
ModelVersionId = "model_version_id"
ModelArtifactId = "model_artifact_id"
HealthCheckPath = PathPrefix + "/healthcheck"
UserPath = PathPrefix + "/user"
ModelRegistryListPath = PathPrefix + "/model_registry"
ModelRegistryPath = ModelRegistryListPath + "/:" + ModelRegistryId
RegisteredModelListPath = ModelRegistryPath + "/registered_models"
Expand Down Expand Up @@ -103,6 +104,7 @@ func (app *App) Routes() http.Handler {
router.POST(ModelVersionArtifactListPath, app.AttachRESTClient(app.CreateModelArtifactByModelVersionHandler))

// Kubernetes client routes
router.GET(UserPath, app.UserHandler)
router.GET(ModelRegistryListPath, app.ModelRegistryHandler)
router.PATCH(ModelRegistryPath, app.AttachRESTClient(app.UpdateModelVersionHandler))

Expand Down
6 changes: 6 additions & 0 deletions clients/ui/bff/internal/api/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ func (app *App) RequireAccessControl(next http.Handler) http.Handler {
return
}

// Skip SAR for user info
if r.URL.Path == UserPath {
next.ServeHTTP(w, r)
return
}

user := r.Header.Get(kubeflowUserId)
if user == "" {
app.forbiddenResponse(w, r, "missing kubeflow-userid header")
Expand Down
Loading

0 comments on commit 1bf4ea6

Please sign in to comment.