Skip to content

Commit

Permalink
Merge pull request #134 from canonical/kf-3664-dynamic-sidebar-featur…
Browse files Browse the repository at this point in the history
…e-branch
  • Loading branch information
ca-scribner authored Jul 13, 2023
2 parents 633aafa + 821f584 commit a4ea068
Show file tree
Hide file tree
Showing 20 changed files with 2,098 additions and 249 deletions.
26 changes: 6 additions & 20 deletions .github/workflows/integrate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ on:
jobs:
lib-check:
name: Check libraries
uses: canonical/charmed-kubeflow-workflows/.github/workflows/_quality-checks.yaml@main
# TODO: Pin this to a version once charmed-kubeflow-workflows has versioned release
uses: canonical/charmed-kubeflow-workflows/.github/workflows/_quality-checks.yaml@f0e79034881a1b33a0742fa9a034c96a14652df2
secrets: inherit
with:
charm-path: "."
Expand Down Expand Up @@ -77,29 +78,14 @@ jobs:
run: |
sg microk8s -c "tox -e integration -- --model kubeflow"
- name: Get all
run: kubectl get all -A
if: failure()

- name: Get configmaps
run: kubectl get cm -A
if: failure()

- name: Get juju status
run: juju status
if: failure()

- name: Get kubeflow-profiles workload logs
run: kubectl logs --tail 100 -nkubeflow -ljuju-app=kubeflow-dashboard
if: failure()

- name: Get kubeflow-kfam workload logs
run: kubectl logs --tail 100 -nkubeflow -ljuju-app=kubeflow-dashboard
if: failure()

- name: Get operator logs
run: kubectl logs --tail 100 -nkubeflow -loperator.juju.is/name
if: failure()
- uses: canonical/kubeflow-ci/actions/dump-charm-debug-artifacts@main
# always() if you want this to run on every run, regardless of failure.
# more details: https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions
if: always()

- name: Upload selenium screenshots
uses: actions/upload-artifact@v3
Expand Down
56 changes: 52 additions & 4 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,63 @@
# See LICENSE file for licensing details.

options:
additional-menu-links:
type: string
default: ''
description: >
YAML or JSON formatted input defining additional menu links.
For usage details, see https://github.com/canonical/kubeflow-dashboard-operator.
additional-external-links:
type: string
default: ''
description: >
YAML or JSON formatted input defining additional external links.
For usage details, see https://github.com/canonical/kubeflow-dashboard-operator.
additional-quick-links:
type: string
default: '[]'
description: >
YAML or JSON formatted input defining additional quick links.
For usage details, see https://github.com/canonical/kubeflow-dashboard-operator.
additional-documentation-links:
type: string
default: '[{"text":"Getting started with Charmed Kubeflow","desc":"Learn how to get started with Kubeflow","link":"https://charmed-kubeflow.io/docs/get-started-with-charmed-kubeflow#heading--part-ii-get-started-with-charmed-kubeflow"},{"text":"Microk8s for Kubeflow","desc":"Quickly get Kubeflow running locally on native hypervisors","link":"https://charmed-kubeflow.io/docs/get-started-with-charmed-kubeflow#heading--install-and-prepare-microk8s-"},{"text":"Requirements for Kubeflow","desc":"Get more detailed information about using Kubeflow and its components","link":"https://www.kubeflow.org/docs/started/requirements/"}]'
description: >
YAML or JSON formatted input defining additional documentation links.
For usage details, see https://github.com/canonical/kubeflow-dashboard-operator.
dashboard-configmap:
type: string
default: centraldashboard-config
description: Name of the Kubeflow Dashboard configmap to be created
port:
type: int
default: 8082
description: HTTP port
dashboard-configmap:
type: string
default: centraldashboard-config
description: Kubeflow Profile to create
registration-flow:
type: boolean
default: true
description: Whether to enable the registration flow on sign-in
menu-link-order:
type: string
default: '["Notebooks", "Experiments (AutoML)", "Experiments (KFP)", "Pipelines", "Runs", "Recurring Runs", "Volumes", "Tensorboards"]'
description: >
YAML or JSON formatted list of strings defining the order of the menu links in the dashboard sidebar.
For usage details, see https://github.com/canonical/kubeflow-dashboard-operator.
external-link-order:
type: string
default: '["MLflow"]'
description: >
YAML or JSON formatted list of strings defining the order of the external links in the dashboard sidebar.
For usage details, see https://github.com/canonical/kubeflow-dashboard-operator.
quick-link-order:
type: string
default: '["Upload a pipeline","View all pipeline runs","Create a new Notebook server","View Katib Experiments"]'
description: >
YAML or JSON formatted list of strings defining the order of the quick links in the dashboard sidebar.
For usage details, see https://github.com/canonical/kubeflow-dashboard-operator.
documentation-link-order:
type: string
default: '["Getting started with Charmed Kubeflow","Microk8s for Kubeflow","Requirements for Kubeflow"]'
description: >
YAML or JSON formatted list of strings defining the order of the documentation links in the dashboard sidebar.
For usage details, see https://github.com/canonical/kubeflow-dashboard-operator.
86 changes: 86 additions & 0 deletions lib/charms/harness_extensions/v0/capture_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'''This is a library providing a utility for unittesting events fired on a
Harness-ed Charm.
Example usage:
>>> from charms.harness_extensions.v0.capture_events import capture
>>> with capture(RelationEvent) as captured:
>>> harness.add_relation('foo', 'remote')
>>> assert captured.event.unit.name == 'remote'
'''

# The unique Charmhub library identifier, never change it
LIBID = "9fcdab70e26d4eee9797c0e542ab397a"

# Increment this major API version when introducing breaking changes
LIBAPI = 0

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 3

# Copyright 2022 Canonical Ltd.
# See LICENSE file for licensing details.

from contextlib import contextmanager
from typing import Generic, Iterator, Optional, Type, TypeVar

from ops.charm import CharmBase
from ops.framework import EventBase

_T = TypeVar("_T", bound=EventBase)


@contextmanager
def capture_events(charm: CharmBase, *types: Type[EventBase]):
"""Capture all events of type `*types` (using instance checks)."""
allowed_types = types or (EventBase,)

captured = []
_real_emit = charm.framework._emit

def _wrapped_emit(evt):
if isinstance(evt, allowed_types):
captured.append(evt)
return _real_emit(evt)

charm.framework._emit = _wrapped_emit # type: ignore # noqa # ugly

yield captured

charm.framework._emit = _real_emit # type: ignore # noqa # ugly


class Captured(Generic[_T]):
"""Object to type and expose return value of capture()."""

_event = None

@property
def event(self) -> Optional[_T]:
"""Return the captured event."""
return self._event

@event.setter
def event(self, val: _T):
self._event = val


@contextmanager
def capture(charm: CharmBase, typ_: Type[_T] = EventBase) -> Iterator[Captured[_T]]:
"""Capture exactly 1 event of type `typ_`.
Will raise if more/less events have been fired, or if the returned event
does not pass an instance check.
"""
result = Captured()
with capture_events(charm, typ_) as captured:
if not captured:
yield result

assert len(captured) <= 1, f"too many events captured: {captured}"
assert len(captured) >= 1, f"no event of type {typ_} emitted."
event = captured[0]
assert isinstance(event, typ_), f"expected {typ_}, not {type(event)}"
result.event = event

Loading

0 comments on commit a4ea068

Please sign in to comment.