Move to Operator Framework
Move the charm to an Operator Framework Charm Signed-off-by: Billy Olsen <billy.olsen@gmail.com>
This commit is contained in:
parent
9f9a9dd6cb
commit
d8019ba12d
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,4 +13,5 @@ xenial/
|
|||||||
.stestr
|
.stestr
|
||||||
__pycache__
|
__pycache__
|
||||||
func-results.json
|
func-results.json
|
||||||
|
.idea
|
||||||
*.charm
|
*.charm
|
||||||
|
3
.jujuignore
Normal file
3
.jujuignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/venv
|
||||||
|
*.py[cod]
|
||||||
|
*.charm
|
18
README.md
Normal file
18
README.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Overview
|
||||||
|
|
||||||
|
This charm provides the Ironic Dashboard plugin for use with the OpenStack Dashboard.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
Example minimal deploy:
|
||||||
|
|
||||||
|
juju deploy openstack-dashboard --channel yoga/stable
|
||||||
|
juju deploy ironic-dashboard
|
||||||
|
juju add-relation \
|
||||||
|
openstack-dashboard:dashboard-plugin ironic-dashboard:dashboard
|
||||||
|
|
||||||
|
# Bugs
|
||||||
|
|
||||||
|
Please report bugs on [Launchpad](https://bugs.launchpad.net/charm-ironic-dashboard/+filebug).
|
||||||
|
|
||||||
|
For general questions please refer to the OpenStack [Charm Guide](https://docs.openstack.org/charm-guide/latest/).
|
@ -1,7 +0,0 @@
|
|||||||
# NOTES(lourot):
|
|
||||||
# * We don't install charmcraft via pip anymore because it anyway spins up a
|
|
||||||
# container and scp the system's charmcraft snap inside it. So the charmcraft
|
|
||||||
# snap is necessary on the system anyway.
|
|
||||||
# * `tox -e build` successfully validated with charmcraft 1.2.1
|
|
||||||
|
|
||||||
cffi==1.14.6; python_version < '3.6' # cffi 1.15.0 drops support for py35.
|
|
@ -1,30 +1,22 @@
|
|||||||
type: charm
|
type: "charm"
|
||||||
|
|
||||||
parts:
|
|
||||||
charm:
|
|
||||||
build-packages:
|
|
||||||
- tox
|
|
||||||
- git
|
|
||||||
- python3-dev
|
|
||||||
override-build: |
|
|
||||||
apt-get install ca-certificates -y
|
|
||||||
tox -e build-reactive
|
|
||||||
override-stage: |
|
|
||||||
echo "Copying charm to staging area: $CRAFT_STAGE"
|
|
||||||
NAME=$(ls $CRAFT_PART_BUILD/build/builds)
|
|
||||||
cp -r $CRAFT_PART_BUILD/build/builds/$NAME/* $CRAFT_STAGE/
|
|
||||||
override-prime: |
|
|
||||||
# For some reason, the normal priming chokes on the fact that there's a
|
|
||||||
# hooks directory.
|
|
||||||
cp -r $CRAFT_STAGE/* .
|
|
||||||
|
|
||||||
bases:
|
bases:
|
||||||
- build-on:
|
- build-on:
|
||||||
- name: ubuntu
|
- name: "ubuntu"
|
||||||
channel: "22.04"
|
channel: "20.04"
|
||||||
architectures:
|
architectures:
|
||||||
- amd64
|
- amd64
|
||||||
run-on:
|
run-on:
|
||||||
- name: ubuntu
|
- name: "ubuntu"
|
||||||
channel: "22.04"
|
channel: "20.04"
|
||||||
architectures: [amd64, s390x, ppc64el, arm64]
|
architectures: [amd64, s390x, ppc64el, arm64]
|
||||||
|
|
||||||
|
#bases:
|
||||||
|
# - build-on:
|
||||||
|
# - name: ubuntu
|
||||||
|
# channel: "22.04"
|
||||||
|
# architectures:
|
||||||
|
# - amd64
|
||||||
|
# run-on:
|
||||||
|
# - name: ubuntu
|
||||||
|
# channel: "22.04"
|
||||||
|
# architectures: [amd64, s390x, ppc64el, arm64]
|
||||||
|
291
lib/charms/openstack/v0/horizon_plugin.py
Normal file
291
lib/charms/openstack/v0/horizon_plugin.py
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
# Copyright 2022 Canonical Ltd.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""# Horizon Plugin library.
|
||||||
|
|
||||||
|
This library facilitates interactions with the 'classic' OpenStack Dashboard
|
||||||
|
Machine Charm. This library is used to provide configuration and dependent
|
||||||
|
package information for this plugin.
|
||||||
|
|
||||||
|
Horizon Plugin charms should be created as subordinate charms. These
|
||||||
|
subordinate charms will run inside the same machine or LXD container that the
|
||||||
|
horizon service is installed in. The plugin charm should avoid installing any
|
||||||
|
debian packages directly, as there are complications with upgrade ordering and
|
||||||
|
compatibility when the OpenStack Dashboard charm is upgraded via an
|
||||||
|
openstack-upgrade action.
|
||||||
|
|
||||||
|
Instead, to ensure consistency, the plugin charm will ask the parent to
|
||||||
|
install the dependent packages and provide any settings that need to be set
|
||||||
|
in the Horizon service's local_settings.py configuration file. The data
|
||||||
|
provided by the subordinate charm is passed verbatim to the local_settings.py.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
Charms seeking to provide a horizon plugin should import the `HorizonPlugin`
|
||||||
|
class from this library. The simplest scenario is to just instantiate the
|
||||||
|
`HorizonPlugin` object and provide the set of debian packages which should be
|
||||||
|
installed, as below:
|
||||||
|
|
||||||
|
from charms.openstack.v0.horizon_plugin import HorizonPlugin
|
||||||
|
|
||||||
|
class AwesomeHorizonPluginFoo(CharmBase):
|
||||||
|
def __init__(self, *args):
|
||||||
|
super().__init__(*args)
|
||||||
|
...
|
||||||
|
self.plugin = HorizonPlugin(self, install_packages=['plugin-foo'])
|
||||||
|
...
|
||||||
|
|
||||||
|
The first argument ('self') to `HorizonPlugin` is always a reference to the
|
||||||
|
horizon plugin charm.
|
||||||
|
|
||||||
|
The `HorizonPlugin` class provides the information from the OpenStack Horizon
|
||||||
|
Dashboard charm as well, in the event that they are needed within the plugin.
|
||||||
|
The plugin charm is provided information regarding the installed OpenStack
|
||||||
|
release, the bin directory path and the location that the dashboard is
|
||||||
|
installed to. The plugin charm can access these values as attributes on the
|
||||||
|
`HorizonPlugin` object.
|
||||||
|
|
||||||
|
...
|
||||||
|
logger.debug(f'Current release is {self.plugin.release}
|
||||||
|
...
|
||||||
|
|
||||||
|
Note, these values are only returned when the relation between plugin charm
|
||||||
|
and the principal charm exists and the joined events have occurred in the
|
||||||
|
principal charm.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
import ops.charm
|
||||||
|
from ops.framework import (
|
||||||
|
EventBase,
|
||||||
|
EventSource,
|
||||||
|
Object,
|
||||||
|
ObjectEvents,
|
||||||
|
)
|
||||||
|
from ops.model import Relation
|
||||||
|
|
||||||
|
# The unique Charmhub library identifier, never change it
|
||||||
|
LIBID = "TBD"
|
||||||
|
|
||||||
|
# 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 = 1
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class HorizonConnectedEvent(EventBase):
|
||||||
|
"""Raised when the OpenStack Horizon Dashboard is connected."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HorizonAvailableEvent(EventBase):
|
||||||
|
"""Raised when the OpenStack Horizon Dashboard is available."""
|
||||||
|
|
||||||
|
|
||||||
|
class HorizonGoneAwayEvent(EventBase):
|
||||||
|
"""Raised when the OpenStack Horizon Dashboard is no longer available."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class HorizonEvents(ObjectEvents):
|
||||||
|
"""ObjectEvents class used to provide the `on` for Dashboard events."""
|
||||||
|
|
||||||
|
connected = EventSource(HorizonConnectedEvent)
|
||||||
|
available = EventSource(HorizonAvailableEvent)
|
||||||
|
goneaway = EventSource(HorizonGoneAwayEvent)
|
||||||
|
|
||||||
|
|
||||||
|
class HorizonPlugin(Object):
|
||||||
|
"""The client-side API for the OpenStack dashboard interface.
|
||||||
|
|
||||||
|
The DashboardRequires object provides the client-side API for the dashboard
|
||||||
|
interface. Charms that require access to the OpenStack dashboard in order
|
||||||
|
to provide a plugin extension can use this library to indicate that new
|
||||||
|
plugins are available.
|
||||||
|
"""
|
||||||
|
|
||||||
|
on = HorizonEvents()
|
||||||
|
|
||||||
|
def __init__(self, charm: ops.charm.CharmBase,
|
||||||
|
relation_name: str = 'dashboard',
|
||||||
|
install_packages: List[str] = None,
|
||||||
|
conflicting_packages: Optional[List[str]] = None,
|
||||||
|
local_settings: str = "",
|
||||||
|
priority: str = None,):
|
||||||
|
super().__init__(charm, relation_name)
|
||||||
|
self.charm = charm
|
||||||
|
self.relation_name = relation_name
|
||||||
|
self.install_packages = install_packages
|
||||||
|
self.conflicting_packages = conflicting_packages
|
||||||
|
self.local_settings = local_settings
|
||||||
|
self.priority = priority
|
||||||
|
|
||||||
|
self.framework.observe(
|
||||||
|
self.charm.on[relation_name].relation_joined,
|
||||||
|
self._on_dashboard_relation_joined,
|
||||||
|
)
|
||||||
|
self.framework.observe(
|
||||||
|
self.charm.on[relation_name].relation_changed,
|
||||||
|
self._on_dashboard_relation_changed,
|
||||||
|
)
|
||||||
|
self.framework.observe(
|
||||||
|
self.charm.on[relation_name].relation_broken,
|
||||||
|
self._on_dashboard_relation_broken,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _on_dashboard_relation_joined(self, event: EventBase):
|
||||||
|
"""Handles relation joined events for the dashboard relation.
|
||||||
|
|
||||||
|
When the dashboard relation joins, the local plugin info will be
|
||||||
|
published to the openstack dashboard charm.
|
||||||
|
|
||||||
|
:param event: the event
|
||||||
|
:type event: EventBase
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
logging.debug(f'{self.relation_name} relation has joined')
|
||||||
|
self.publish_plugin_info(
|
||||||
|
self.local_settings,
|
||||||
|
self.priority,
|
||||||
|
self.install_packages,
|
||||||
|
self.conflicting_packages,
|
||||||
|
event.relation,
|
||||||
|
)
|
||||||
|
self.on.connected.emit()
|
||||||
|
|
||||||
|
def _on_dashboard_relation_changed(self, event: EventBase):
|
||||||
|
"""Handles relation changed events for the dashboard relation.
|
||||||
|
|
||||||
|
When the dashboard relation changes, it may be indicating that there's
|
||||||
|
a new OpenStack release or that some other element has changed.
|
||||||
|
"""
|
||||||
|
logging.debug(f'{self.relation_name} relation has changed')
|
||||||
|
self.on.available.emit()
|
||||||
|
|
||||||
|
def _on_dashboard_relation_broken(self, event: EventBase):
|
||||||
|
"""Handles relation departed events for the dashboard relation.
|
||||||
|
|
||||||
|
When the dashboard relation is departed it means the unit/application
|
||||||
|
is being removed.
|
||||||
|
|
||||||
|
:param event: the event
|
||||||
|
:type event: EventBase
|
||||||
|
return: None
|
||||||
|
"""
|
||||||
|
logging.debug(f'{self.relation_name} relation has departed')
|
||||||
|
self.on.goneaway.emit()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _relation(self) -> Relation:
|
||||||
|
"""The shared-db relation."""
|
||||||
|
return self.framework.model.get_relation(self.relation_name)
|
||||||
|
|
||||||
|
def publish_plugin_info(
|
||||||
|
self,
|
||||||
|
local_settings: str,
|
||||||
|
priority: str,
|
||||||
|
install_packages: Optional[List[str]] = None,
|
||||||
|
conflicting_packages: Optional[List[str]] = None,
|
||||||
|
relation: Optional[Relation] = None,
|
||||||
|
) -> None:
|
||||||
|
"""Publish information regarding the plugin to the provider.
|
||||||
|
|
||||||
|
Publishes the dashboard plugin information to the principle charm.
|
||||||
|
The principle charm does the installation and maintenance of the
|
||||||
|
packages so that it can also manage the upgrades of these packages.
|
||||||
|
|
||||||
|
:param local_settings: a string to be placed into the
|
||||||
|
local_settings.py. Note it is placed verbatim into the
|
||||||
|
local_settings.py configuration file
|
||||||
|
:type local_settings: str
|
||||||
|
:param priority: Value used by the principal charm to order the
|
||||||
|
configuration blobs when multiple plugin subordinates are present
|
||||||
|
:param install_packages: a list of packages that should be installed
|
||||||
|
for this plugin
|
||||||
|
:type install_packages: Optional[List[str]]
|
||||||
|
:param conflicting_packages: a list of packages that conflict with
|
||||||
|
this plugin
|
||||||
|
:type conflicting_packages: Optional[List[str]]
|
||||||
|
:param relation: the relation to set the data on
|
||||||
|
:type relation: Relation
|
||||||
|
:return: None
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
rel = relation or self._relation
|
||||||
|
# If this is called when there isn't a relation, then just return
|
||||||
|
if not rel:
|
||||||
|
return
|
||||||
|
|
||||||
|
data = rel.data[self.charm.unit]
|
||||||
|
data['local-settings'] = local_settings
|
||||||
|
if priority:
|
||||||
|
data['priority'] = priority
|
||||||
|
if install_packages:
|
||||||
|
data['install-packages'] = json.dumps(install_packages)
|
||||||
|
if conflicting_packages:
|
||||||
|
data['conflicting-packages'] = json.dumps(conflicting_packages)
|
||||||
|
|
||||||
|
rel.data[self.charm.unit].update(data)
|
||||||
|
|
||||||
|
def _get_remote_data(self, key: str) -> Optional[str]:
|
||||||
|
"""Returns the value for the given key from the relation data.
|
||||||
|
|
||||||
|
As long as *one* of the related units can provide the requested data,
|
||||||
|
then that data is returned.
|
||||||
|
|
||||||
|
:param key: the key of the value to retrieve from the relation.
|
||||||
|
:type key: str
|
||||||
|
:return: the value of the relation data
|
||||||
|
:rtype: Optional[str]
|
||||||
|
"""
|
||||||
|
relation = self._relation
|
||||||
|
if not relation:
|
||||||
|
return None
|
||||||
|
|
||||||
|
for unit in relation.units:
|
||||||
|
value = relation.data[unit].get(key)
|
||||||
|
if value:
|
||||||
|
return value
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def openstack_dir(self) -> Optional[str]:
|
||||||
|
"""Retrieves the openstack_dir property from the principal charm
|
||||||
|
|
||||||
|
:return: openstack_dir property from principal charm
|
||||||
|
:rtype: Optional[str]
|
||||||
|
"""
|
||||||
|
return self._get_remote_data('openstack_dir')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bin_path(self) -> Optional[str]:
|
||||||
|
"""Retrives the bin_path property from the principal charm
|
||||||
|
|
||||||
|
:return: bin_path property from the principal charm"""
|
||||||
|
return self._get_remote_data('bin_path')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def release(self) -> Optional[str]:
|
||||||
|
"""Retrives the release property from the principal charm
|
||||||
|
|
||||||
|
:return: release property from the principal charm"""
|
||||||
|
return self._get_remote_data('release')
|
@ -1 +0,0 @@
|
|||||||
src/metadata.yaml
|
|
26
metadata.yaml
Normal file
26
metadata.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Copyright 2022 Canonical Ltd.
|
||||||
|
# See LICENSE file for licensing details
|
||||||
|
|
||||||
|
name: ironic-dashboard
|
||||||
|
display-name: Ironic Dashboard
|
||||||
|
summary: Horizon plugin for Ironic Bare Metal services
|
||||||
|
maintainers:
|
||||||
|
- OpenStack Charmers <openstack-charmers@lists.ubuntu.com>
|
||||||
|
description: |
|
||||||
|
The Ironic Dashboard provides the plugin necessary to
|
||||||
|
manage bare metal instances from the Horizon Dashboard.
|
||||||
|
tags:
|
||||||
|
- openstack
|
||||||
|
|
||||||
|
series:
|
||||||
|
- focal
|
||||||
|
- jammy
|
||||||
|
|
||||||
|
# This charm is a machine charm which is intended to be inside
|
||||||
|
# the same container/machine as the openstack-dashboard.
|
||||||
|
subordinate: true
|
||||||
|
|
||||||
|
requires:
|
||||||
|
dashboard:
|
||||||
|
interface: dashboard-plugin
|
||||||
|
scope: container
|
@ -3,28 +3,5 @@
|
|||||||
# choices of *requirements.txt files for OpenStack Charms:
|
# choices of *requirements.txt files for OpenStack Charms:
|
||||||
# https://github.com/openstack-charmers/release-tools
|
# https://github.com/openstack-charmers/release-tools
|
||||||
#
|
#
|
||||||
# NOTE(lourot): This might look like a duplication of test-requirements.txt but
|
|
||||||
# some tox targets use only test-requirements.txt whereas charm-build uses only
|
|
||||||
# requirements.txt
|
|
||||||
setuptools<50.0.0 # https://github.com/pypa/setuptools/commit/04e3df22df840c6bb244e9b27bc56750c44b7c85
|
|
||||||
|
|
||||||
# NOTE: newer versions of cryptography require a Rust compiler to build,
|
ops
|
||||||
# see
|
|
||||||
# * https://github.com/openstack-charmers/zaza/issues/421
|
|
||||||
# * https://mail.python.org/pipermail/cryptography-dev/2021-January/001003.html
|
|
||||||
#
|
|
||||||
cryptography<3.4
|
|
||||||
|
|
||||||
# Build requirements
|
|
||||||
cffi==1.14.6; python_version < '3.6' # cffi 1.15.0 drops support for py35.
|
|
||||||
git+https://github.com/juju/charm-tools#egg=charm-tools
|
|
||||||
|
|
||||||
simplejson
|
|
||||||
|
|
||||||
# Newer versions use keywords that didn't exist in python 3.5 yet (e.g.
|
|
||||||
# "ModuleNotFoundError")
|
|
||||||
# NOTE(lourot): This might look like a duplication of test-requirements.txt but
|
|
||||||
# some tox targets use only test-requirements.txt whereas charm-build uses only
|
|
||||||
# requirements.txt
|
|
||||||
importlib-metadata<3.0.0; python_version < '3.6'
|
|
||||||
importlib-resources<3.0.0; python_version < '3.6'
|
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
# Overview
|
|
||||||
|
|
||||||
This subordinate charm provides the Ironic Dashboard plugin for use with the OpenStack Dashboard.
|
|
||||||
|
|
||||||
# Usage
|
|
||||||
|
|
||||||
Example minimal deploy:
|
|
||||||
|
|
||||||
juju deploy openstack-dashboard --channel yoga/stable
|
|
||||||
juju deploy ironic-dashboard
|
|
||||||
juju add-relation \
|
|
||||||
openstack-dashboard:dashboard-plugin ironic-dashboard:dashboard
|
|
||||||
|
|
||||||
# Bugs
|
|
||||||
|
|
||||||
Please report bugs on [Launchpad](https://bugs.launchpad.net/charm-ironic-dashboard/+filebug).
|
|
||||||
|
|
||||||
For general questions please refer to the OpenStack [Charm Guide](https://docs.openstack.org/charm-guide/latest/).
|
|
60
src/charm.py
Executable file
60
src/charm.py
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright 2022 Canonical Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""An Operator Charm for deploying the Ironic Dashboard in Charmed OpenStack.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from ops.charm import CharmBase
|
||||||
|
from ops.main import main
|
||||||
|
from ops.model import ActiveStatus
|
||||||
|
|
||||||
|
from charms.openstack.v0.horizon_plugin import (
|
||||||
|
HorizonPlugin,
|
||||||
|
HorizonAvailableEvent,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class IronicDashboardCharm(CharmBase):
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
super().__init__(*args)
|
||||||
|
self.dashboard = HorizonPlugin(
|
||||||
|
self, install_packages=['python3-ironic-ui'],
|
||||||
|
)
|
||||||
|
self.framework.observe(
|
||||||
|
self.dashboard.on.available, self._dashboard_available
|
||||||
|
)
|
||||||
|
|
||||||
|
def _dashboard_available(self, event: HorizonAvailableEvent):
|
||||||
|
"""Invoked when the dashboard is now available.
|
||||||
|
|
||||||
|
:param event: the DashboardAvailableEvent to indicate the dashboard
|
||||||
|
is now available.
|
||||||
|
:type event: HorizonAvailableEvent
|
||||||
|
"""
|
||||||
|
self.model.unit.status = ActiveStatus('ready')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(IronicDashboardCharm)
|
@ -1,17 +0,0 @@
|
|||||||
includes:
|
|
||||||
- layer:openstack
|
|
||||||
- interface:dashboard-plugin
|
|
||||||
options:
|
|
||||||
basic:
|
|
||||||
use_venv: True
|
|
||||||
include_system_packages: False
|
|
||||||
repo: https://github.com/openstack/charm-ironic-dashboard
|
|
||||||
config:
|
|
||||||
deletes:
|
|
||||||
- debug
|
|
||||||
- verbose
|
|
||||||
- use-internal-endpoints
|
|
||||||
- use-syslog
|
|
||||||
- ssl_ca
|
|
||||||
- ssl_cert
|
|
||||||
- ssl_key
|
|
@ -1,42 +0,0 @@
|
|||||||
# Copyright 2021 Canonical Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
|
|
||||||
import charms_openstack.adapters
|
|
||||||
import charms_openstack.charm
|
|
||||||
|
|
||||||
|
|
||||||
class IronicDashboardCharm(charms_openstack.charm.OpenStackCharm):
|
|
||||||
release = 'ussuri'
|
|
||||||
name = 'ironic-dashboard'
|
|
||||||
packages = ['python3-ironic-ui']
|
|
||||||
python_version = 3
|
|
||||||
adapters_class = charms_openstack.adapters.OpenStackRelationAdapters
|
|
||||||
required_relations = ['dashboard']
|
|
||||||
|
|
||||||
def enable_ui_plugin(self):
|
|
||||||
source = '/etc/openstack-dashboard/enabled'
|
|
||||||
destination = \
|
|
||||||
'/usr/lib/python3/dist-packages/openstack_dashboard/local/enabled'
|
|
||||||
plugin_files = glob.glob('{}/*_container_infra_*.py'.format(source))
|
|
||||||
for plugin_file in plugin_files:
|
|
||||||
dest_file = os.path.join(
|
|
||||||
destination, os.path.basename(plugin_file))
|
|
||||||
try:
|
|
||||||
os.symlink(plugin_file, dest_file)
|
|
||||||
except FileExistsError:
|
|
||||||
# plugin file is already enabled
|
|
||||||
continue
|
|
@ -1,15 +0,0 @@
|
|||||||
name: ironic-dashboard
|
|
||||||
summary: Openstack Ironic Dashboard
|
|
||||||
maintainer: OpenStack Charmers <openstack-charmers@lists.ubuntu.com>
|
|
||||||
description: |
|
|
||||||
This is the dashboard for the OpenStack Bare Metal service, Ironic.
|
|
||||||
tags:
|
|
||||||
- openstack
|
|
||||||
series:
|
|
||||||
- focal
|
|
||||||
- jammy
|
|
||||||
subordinate: true
|
|
||||||
requires:
|
|
||||||
dashboard:
|
|
||||||
interface: dashboard-plugin
|
|
||||||
scope: container
|
|
@ -1,41 +0,0 @@
|
|||||||
# Copyright 2018 Canonical Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
import charms.reactive as reactive
|
|
||||||
|
|
||||||
import charms_openstack.bus
|
|
||||||
import charms_openstack.charm as charm
|
|
||||||
|
|
||||||
charms_openstack.bus.discover()
|
|
||||||
|
|
||||||
# Use the charms.openstack defaults for common states and hooks
|
|
||||||
charm.use_defaults(
|
|
||||||
'charm.installed',
|
|
||||||
'config.changed',
|
|
||||||
'update-status',
|
|
||||||
'upgrade-charm')
|
|
||||||
|
|
||||||
|
|
||||||
@reactive.when('dashboard.available')
|
|
||||||
def dashboard_available():
|
|
||||||
"""Relation to OpenStack Dashboard principal charm complete.
|
|
||||||
"""
|
|
||||||
with charm.provide_charm_instance() as ironic_dashboard_charm:
|
|
||||||
dashboard_relation = reactive.endpoint_from_flag('dashboard.available')
|
|
||||||
dashboard_relation.publish_plugin_info(
|
|
||||||
"", None,
|
|
||||||
conflicting_packages=ironic_dashboard_charm.purge_packages,
|
|
||||||
install_packages=ironic_dashboard_charm.packages)
|
|
||||||
ironic_dashboard_charm.enable_ui_plugin()
|
|
||||||
ironic_dashboard_charm.assess_status()
|
|
@ -1,12 +0,0 @@
|
|||||||
# This file is managed centrally by release-tools and should not be modified
|
|
||||||
# within individual charm repos. See the 'global' dir contents for available
|
|
||||||
# choices of *requirements.txt files for OpenStack Charms:
|
|
||||||
# https://github.com/openstack-charmers/release-tools
|
|
||||||
#
|
|
||||||
|
|
||||||
# Need tox to be available from tox... inception yes, but its a workaround for now
|
|
||||||
tox
|
|
||||||
|
|
||||||
# Functional Test Requirements (let Zaza's dependencies solve all dependencies here!)
|
|
||||||
git+https://github.com/openstack-charmers/zaza.git#egg=zaza
|
|
||||||
git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack
|
|
61
src/tox.ini
61
src/tox.ini
@ -1,61 +0,0 @@
|
|||||||
# Source charm (with zaza): ./src/tox.ini
|
|
||||||
# This file is managed centrally by release-tools and should not be modified
|
|
||||||
# within individual charm repos. See the 'global' dir contents for available
|
|
||||||
# choices of tox.ini for OpenStack Charms:
|
|
||||||
# https://github.com/openstack-charmers/release-tools
|
|
||||||
|
|
||||||
[tox]
|
|
||||||
envlist = pep8
|
|
||||||
skipsdist = True
|
|
||||||
# NOTE: Avoid build/test env pollution by not enabling sitepackages.
|
|
||||||
sitepackages = False
|
|
||||||
# NOTE: Avoid false positives by not skipping missing interpreters.
|
|
||||||
skip_missing_interpreters = False
|
|
||||||
# NOTES:
|
|
||||||
# * We avoid the new dependency resolver by pinning pip < 20.3, see
|
|
||||||
# https://github.com/pypa/pip/issues/9187
|
|
||||||
# * Pinning dependencies requires tox >= 3.2.0, see
|
|
||||||
# https://tox.readthedocs.io/en/latest/config.html#conf-requires
|
|
||||||
# * It is also necessary to pin virtualenv as a newer virtualenv would still
|
|
||||||
# lead to fetching the latest pip in the func* tox targets, see
|
|
||||||
# https://stackoverflow.com/a/38133283
|
|
||||||
requires = pip < 20.3
|
|
||||||
virtualenv < 20.0
|
|
||||||
# NOTE: https://wiki.canonical.com/engineering/OpenStack/InstallLatestToxOnOsci
|
|
||||||
minversion = 3.18.0
|
|
||||||
|
|
||||||
[testenv]
|
|
||||||
setenv = VIRTUAL_ENV={envdir}
|
|
||||||
PYTHONHASHSEED=0
|
|
||||||
allowlist_externals = juju
|
|
||||||
passenv = HOME TERM CS_* OS_* TEST_*
|
|
||||||
deps = -r{toxinidir}/test-requirements.txt
|
|
||||||
install_command =
|
|
||||||
pip install {opts} {packages}
|
|
||||||
|
|
||||||
[testenv:pep8]
|
|
||||||
basepython = python3
|
|
||||||
commands = charm-proof
|
|
||||||
|
|
||||||
[testenv:func-noop]
|
|
||||||
basepython = python3
|
|
||||||
commands =
|
|
||||||
functest-run-suite --help
|
|
||||||
|
|
||||||
[testenv:func]
|
|
||||||
basepython = python3
|
|
||||||
commands =
|
|
||||||
functest-run-suite --keep-model
|
|
||||||
|
|
||||||
[testenv:func-smoke]
|
|
||||||
basepython = python3
|
|
||||||
commands =
|
|
||||||
functest-run-suite --keep-model --smoke
|
|
||||||
|
|
||||||
[testenv:func-target]
|
|
||||||
basepython = python3
|
|
||||||
commands =
|
|
||||||
functest-run-suite --keep-model --bundle {posargs}
|
|
||||||
|
|
||||||
[testenv:venv]
|
|
||||||
commands = {posargs}
|
|
@ -1,3 +0,0 @@
|
|||||||
git+https://github.com/openstack/charms.openstack.git#egg=charms.openstack
|
|
||||||
|
|
||||||
git+https://github.com/juju/charm-helpers.git#egg=charmhelpers
|
|
@ -3,52 +3,13 @@
|
|||||||
# choices of *requirements.txt files for OpenStack Charms:
|
# choices of *requirements.txt files for OpenStack Charms:
|
||||||
# https://github.com/openstack-charmers/release-tools
|
# https://github.com/openstack-charmers/release-tools
|
||||||
#
|
#
|
||||||
pyparsing<3.0.0 # aodhclient is pinned in zaza and needs pyparsing < 3.0.0, but cffi also needs it, so pin here.
|
|
||||||
cffi==1.14.6; python_version < '3.6' # cffi 1.15.0 drops support for py35.
|
|
||||||
setuptools<50.0.0 # https://github.com/pypa/setuptools/commit/04e3df22df840c6bb244e9b27bc56750c44b7c85
|
|
||||||
|
|
||||||
stestr>=2.2.0
|
-r requirements.txt
|
||||||
|
|
||||||
# Dependency of stestr. Workaround for
|
coverage
|
||||||
# https://github.com/mtreinish/stestr/issues/145
|
flake8
|
||||||
cliff<3.0.0
|
stestr
|
||||||
|
|
||||||
# Dependencies of stestr. Newer versions use keywords that didn't exist in
|
# Functional Test Requirements (let Zaza's dependencies solve all dependencies here!)
|
||||||
# python 3.5 yet (e.g. "ModuleNotFoundError")
|
git+https://github.com/openstack-charmers/zaza.git#egg=zaza
|
||||||
importlib-metadata<3.0.0; python_version < '3.6'
|
git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack
|
||||||
importlib-resources<3.0.0; python_version < '3.6'
|
|
||||||
|
|
||||||
# Some Zuul nodes sometimes pull newer versions of these dependencies which
|
|
||||||
# dropped support for python 3.5:
|
|
||||||
osprofiler<2.7.0;python_version<'3.6'
|
|
||||||
stevedore<1.31.0;python_version<'3.6'
|
|
||||||
debtcollector<1.22.0;python_version<'3.6'
|
|
||||||
oslo.utils<=3.41.0;python_version<'3.6'
|
|
||||||
|
|
||||||
requests>=2.18.4
|
|
||||||
charms.reactive
|
|
||||||
|
|
||||||
# Newer mock seems to have some syntax which is newer than python3.5 (e.g.
|
|
||||||
# f'{something}'
|
|
||||||
mock>=1.2,<4.0.0; python_version < '3.6'
|
|
||||||
mock>=1.2; python_version >= '3.6'
|
|
||||||
|
|
||||||
nose>=1.3.7
|
|
||||||
coverage>=3.6
|
|
||||||
git+https://github.com/openstack/charms.openstack.git#egg=charms.openstack
|
|
||||||
#
|
|
||||||
# Revisit for removal / mock improvement:
|
|
||||||
#
|
|
||||||
# NOTE(lourot): newer versions of cryptography require a Rust compiler to build,
|
|
||||||
# see
|
|
||||||
# * https://github.com/openstack-charmers/zaza/issues/421
|
|
||||||
# * https://mail.python.org/pipermail/cryptography-dev/2021-January/001003.html
|
|
||||||
#
|
|
||||||
netifaces # vault
|
|
||||||
psycopg2-binary # vault
|
|
||||||
tenacity # vault
|
|
||||||
pbr==5.6.0 # vault
|
|
||||||
cryptography<3.4 # vault, keystone-saml-mellon
|
|
||||||
lxml # keystone-saml-mellon
|
|
||||||
hvac # vault, barbican-vault
|
|
||||||
psutil # cinder-lvm
|
|
||||||
|
50
tox.ini
50
tox.ini
@ -6,35 +6,17 @@
|
|||||||
|
|
||||||
[tox]
|
[tox]
|
||||||
skipsdist = True
|
skipsdist = True
|
||||||
envlist = pep8,py3
|
envlist = pep8, py3
|
||||||
# NOTE: Avoid build/test env pollution by not enabling sitepackages.
|
# NOTE: Avoid build/test env pollution by not enabling sitepackages.
|
||||||
sitepackages = False
|
sitepackages = False
|
||||||
# NOTE: Avoid false positives by not skipping missing interpreters.
|
# NOTE: Avoid false positives by not skipping missing interpreters.
|
||||||
skip_missing_interpreters = False
|
skip_missing_interpreters = False
|
||||||
# NOTES:
|
|
||||||
# * We avoid the new dependency resolver by pinning pip < 20.3, see
|
|
||||||
# https://github.com/pypa/pip/issues/9187
|
|
||||||
# * Pinning dependencies requires tox >= 3.2.0, see
|
|
||||||
# https://tox.readthedocs.io/en/latest/config.html#conf-requires
|
|
||||||
# * It is also necessary to pin virtualenv as a newer virtualenv would still
|
|
||||||
# lead to fetching the latest pip in the func* tox targets, see
|
|
||||||
# https://stackoverflow.com/a/38133283
|
|
||||||
requires =
|
|
||||||
pip < 20.3
|
|
||||||
virtualenv < 20.0
|
|
||||||
setuptools<50.0.0
|
|
||||||
|
|
||||||
# NOTE: https://wiki.canonical.com/engineering/OpenStack/InstallLatestToxOnOsci
|
|
||||||
minversion = 3.18.0
|
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
setenv = VIRTUAL_ENV={envdir}
|
setenv = VIRTUAL_ENV={envdir}
|
||||||
PYTHONHASHSEED=0
|
PYTHONHASHSEED=0
|
||||||
TERM=linux
|
TERM=linux
|
||||||
LAYER_PATH={toxinidir}/layers
|
passenv = http_proxy https_proxy
|
||||||
INTERFACE_PATH={toxinidir}/interfaces
|
|
||||||
JUJU_REPOSITORY={toxinidir}/build
|
|
||||||
passenv = http_proxy https_proxy INTERFACE_PATH LAYER_PATH JUJU_REPOSITORY
|
|
||||||
install_command =
|
install_command =
|
||||||
{toxinidir}/pip.sh install {opts} {packages}
|
{toxinidir}/pip.sh install {opts} {packages}
|
||||||
allowlist_externals =
|
allowlist_externals =
|
||||||
@ -47,22 +29,12 @@ deps =
|
|||||||
|
|
||||||
[testenv:build]
|
[testenv:build]
|
||||||
basepython = python3
|
basepython = python3
|
||||||
deps = -r{toxinidir}/build-requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
commands =
|
commands =
|
||||||
charmcraft clean
|
charmcraft clean
|
||||||
charmcraft -v build
|
charmcraft -v pack
|
||||||
{toxinidir}/rename.sh
|
{toxinidir}/rename.sh
|
||||||
|
|
||||||
[testenv:build-reactive]
|
|
||||||
basepython = python3
|
|
||||||
commands =
|
|
||||||
charm-build --log-level DEBUG --use-lock-file-branches -o {toxinidir}/build/builds src {posargs}
|
|
||||||
|
|
||||||
[testenv:add-build-lock-file]
|
|
||||||
basepython = python3
|
|
||||||
commands =
|
|
||||||
charm-build --log-level DEBUG --write-lock-file -o {toxinidir}/build/builds src {posargs}
|
|
||||||
|
|
||||||
[testenv:py3]
|
[testenv:py3]
|
||||||
basepython = python3
|
basepython = python3
|
||||||
deps = -r{toxinidir}/test-requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
@ -91,27 +63,21 @@ commands = stestr run --slowest {posargs}
|
|||||||
[testenv:pep8]
|
[testenv:pep8]
|
||||||
basepython = python3
|
basepython = python3
|
||||||
deps = flake8==3.9.2
|
deps = flake8==3.9.2
|
||||||
charm-tools==2.8.3
|
|
||||||
commands = flake8 {posargs} src unit_tests
|
commands = flake8 {posargs} src unit_tests
|
||||||
|
|
||||||
[testenv:func-target]
|
[testenv:func-target]
|
||||||
# Hack to get functional tests working in the charmcraft
|
|
||||||
# world. We should fix this.
|
|
||||||
basepython = python3
|
basepython = python3
|
||||||
passenv = HOME TERM CS_* OS_* TEST_*
|
passenv = HOME TERM CS_* OS_* TEST_*
|
||||||
deps = -r{toxinidir}/src/test-requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
changedir = {toxinidir}/src
|
|
||||||
commands =
|
commands =
|
||||||
bash -c "if [ ! -f ../*.charm ]; then echo 'Charm does not exist. Run tox -e build'; exit 1; fi"
|
bash -c "if [ ! -f ../*.charm ]; then echo 'Charm does not exist. Run tox -e build'; exit 1; fi"
|
||||||
tox --version
|
functest-run-suite --keep-model --bundle {posargs}
|
||||||
tox -e func-target {posargs}
|
|
||||||
|
|
||||||
[testenv:cover]
|
[testenv:cover]
|
||||||
# Technique based heavily upon
|
# Technique based heavily upon
|
||||||
# https://github.com/openstack/nova/blob/master/tox.ini
|
# https://github.com/openstack/nova/blob/master/tox.ini
|
||||||
basepython = python3
|
basepython = python3
|
||||||
deps = -r{toxinidir}/requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
-r{toxinidir}/test-requirements.txt
|
|
||||||
setenv =
|
setenv =
|
||||||
{[testenv]setenv}
|
{[testenv]setenv}
|
||||||
PYTHON=coverage run
|
PYTHON=coverage run
|
||||||
@ -131,8 +97,8 @@ source =
|
|||||||
.
|
.
|
||||||
omit =
|
omit =
|
||||||
.tox/*
|
.tox/*
|
||||||
*/charmhelpers/*
|
|
||||||
unit_tests/*
|
unit_tests/*
|
||||||
|
lib/*
|
||||||
|
|
||||||
[testenv:venv]
|
[testenv:venv]
|
||||||
basepython = python3
|
basepython = python3
|
||||||
|
@ -12,11 +12,5 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import sys
|
import ops.testing
|
||||||
|
ops.testing.SIMULATE_CAN_CONNECT = False
|
||||||
sys.path.append('src')
|
|
||||||
sys.path.append('src/lib')
|
|
||||||
|
|
||||||
# Mock out charmhelpers so that we can test without it.
|
|
||||||
import charms_openstack.test_mocks # noqa
|
|
||||||
charms_openstack.test_mocks.mock_charmhelpers()
|
|
||||||
|
39
unit_tests/test_charm.py
Normal file
39
unit_tests/test_charm.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Copyright 2021 Canonical Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append('lib') # noqa
|
||||||
|
sys.path.append('src') # noqa
|
||||||
|
|
||||||
|
from charm import IronicDashboardCharm
|
||||||
|
from ops.model import ActiveStatus
|
||||||
|
from ops.testing import Harness
|
||||||
|
|
||||||
|
|
||||||
|
class TestCharm(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.harness = Harness(IronicDashboardCharm)
|
||||||
|
self.harness.begin()
|
||||||
|
self.addCleanup(self.harness.cleanup)
|
||||||
|
|
||||||
|
def test_add_relation(self):
|
||||||
|
rel_id = self.harness.add_relation('dashboard', 'openstack-dashboard')
|
||||||
|
self.harness.add_relation_unit(rel_id, "openstack-dashboard/0")
|
||||||
|
self.harness.update_relation_data(rel_id, 'openstack-dashboard', {
|
||||||
|
'release': 'testing'
|
||||||
|
})
|
||||||
|
assert isinstance(self.harness.charm.model.unit.status,
|
||||||
|
ActiveStatus)
|
@ -1,63 +0,0 @@
|
|||||||
# Copyright 2021 Canonical Ltd
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
import reactive.ironic_dashboard_handlers as handlers
|
|
||||||
|
|
||||||
import charms_openstack.test_utils as test_utils
|
|
||||||
|
|
||||||
|
|
||||||
class TestRegisteredHooks(test_utils.TestRegisteredHooks):
|
|
||||||
|
|
||||||
def test_hooks(self):
|
|
||||||
defaults = [
|
|
||||||
'charm.installed',
|
|
||||||
'config.changed',
|
|
||||||
'update-status',
|
|
||||||
'upgrade-charm']
|
|
||||||
hook_set = {
|
|
||||||
'when': {
|
|
||||||
'dashboard_available': (
|
|
||||||
'dashboard.available',),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
# test that the hooks were registered via the
|
|
||||||
# reactive.barbican_handlers
|
|
||||||
self.registered_hooks_test_helper(handlers, hook_set, defaults)
|
|
||||||
|
|
||||||
|
|
||||||
class TestIronicDashboardHandlers(test_utils.PatchHelper):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super().setUp()
|
|
||||||
self.ironic_dashboard_charm = mock.MagicMock()
|
|
||||||
self.patch_object(handlers.charm, 'provide_charm_instance',
|
|
||||||
new=mock.MagicMock())
|
|
||||||
self.provide_charm_instance().__enter__.return_value = \
|
|
||||||
self.ironic_dashboard_charm
|
|
||||||
self.provide_charm_instance().__exit__.return_value = None
|
|
||||||
self.patch('charms.reactive.endpoint_from_flag')
|
|
||||||
|
|
||||||
def test_dashboard_available(self):
|
|
||||||
mock_flag = mock.Mock()
|
|
||||||
self.endpoint_from_flag.return_value = mock_flag
|
|
||||||
self.ironic_dashboard_charm.purge_packages = ['n1']
|
|
||||||
self.ironic_dashboard_charm.packages = ['p1', 'p2']
|
|
||||||
handlers.dashboard_available()
|
|
||||||
self.ironic_dashboard_charm.enable_ui_plugin.assert_called_once_with()
|
|
||||||
self.ironic_dashboard_charm.assess_status.assert_called_once_with()
|
|
||||||
mock_flag.publish_plugin_info.assert_called_once_with(
|
|
||||||
"", None, conflicting_packages=['n1'],
|
|
||||||
install_packages=['p1', 'p2'])
|
|
Loading…
Reference in New Issue
Block a user