MicroOVN Charm

mj ponsonby Publisher

Platform:

Ubuntu
26.04 24.04
Channel Revision Published Runs on
latest/stable 297 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/stable 296 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/stable 295 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/stable 294 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/stable 293 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/stable 292 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/stable 291 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/stable 290 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/stable 289 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/stable 288 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 312 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 310 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 308 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 306 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 301 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 300 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 299 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 297 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 296 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
latest/candidate 289 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 312 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 310 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 308 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 306 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 301 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 300 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 299 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 297 23 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 296 23 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 289 22 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 287 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 282 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 279 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 278 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 277 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 197 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 195 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 192 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 191 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 180 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 287 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 282 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 279 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 278 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 277 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 197 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 195 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 192 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 191 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 180 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 287 16 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 282 15 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 279 15 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 278 15 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 277 15 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 197 21 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 195 21 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 192 21 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 191 21 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 180 30 Jun 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 285 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 284 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 275 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 274 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 273 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 272 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 271 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 245 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 241 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 240 28 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 313 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 311 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 309 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 307 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 305 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 304 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 303 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 302 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 298 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 284 18 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 313 15 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 311 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 309 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 307 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 305 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 304 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 303 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 302 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 298 14 Oct 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 284 16 Sep 2026
Ubuntu 26.04 Ubuntu 24.04
25.03/stable 286 28 Sep 2026
Ubuntu 24.04
25.03/stable 283 28 Sep 2026
Ubuntu 24.04
25.03/stable 281 28 Sep 2026
Ubuntu 24.04
25.03/stable 280 28 Sep 2026
Ubuntu 24.04
25.03/stable 276 28 Sep 2026
Ubuntu 24.04
25.03/candidate 286 18 Sep 2026
Ubuntu 24.04
25.03/candidate 283 18 Sep 2026
Ubuntu 24.04
25.03/candidate 281 18 Sep 2026
Ubuntu 24.04
25.03/candidate 280 18 Sep 2026
Ubuntu 24.04
25.03/candidate 276 18 Sep 2026
Ubuntu 24.04
25.03/edge 286 16 Sep 2026
Ubuntu 24.04
25.03/edge 283 15 Sep 2026
Ubuntu 24.04
25.03/edge 280 15 Sep 2026
Ubuntu 24.04
25.03/edge 281 15 Sep 2026
Ubuntu 24.04
25.03/edge 276 15 Sep 2026
Ubuntu 24.04
juju deploy microovn --channel 24.03/stable

"""
This is a charm library for the ovsdb interface. This contains two classes to
ease development of charms using this interface, one for provides and one for
requires.

The provides part of this takes the ovsdb connection strings from the microovn
environment file.

The requires part communicates with the relation data and gets these strings to
be easily returned and used for interaction with the ovsdb databases.
"""

# The unique Charmhub library identifier, never change it
LIBID = "599e7729d8cf403db3f6afb6d7c64c92"

# 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

ENV_FILE = "/var/snap/microovn/common/data/env/ovn.env"
CONNECT_ENV_NAME = "OVN_{0}_CONNECT"
CONNECT_STR_KEY = "db_{0}_connection_str"

from dataclasses import dataclass
import logging

from ops import CharmBase, StoredState, EventBase
from ops.framework import Object
from ops.model import (
    Application,
    ModelError,
    Relation,
    SecretNotFoundError,
    Unit,
)

logger = logging.getLogger(__name__)

@dataclass
class OVSDBConnectionString:
    """Class for storing the northbound and southbound connection strings"""
    nb: str
    sb: str


class OVSDBRequires(Object):
    _stored = StoredState()

    def __init__(
        self,
        charm: CharmBase,
        relation_name: str,
    ):
        super().__init__(charm, relation_name)
        self.charm = charm
        self.relation_name = relation_name

    """
    get_connection_strings takes the northbound and southbound connection strings
    from the relation data.

    it returns None on failure, and it returns a instance of
    OVSDBConnectionString containing both northbound and southbound strings
    """
    def get_connection_strings(self) -> OVSDBConnectionString:
        if not (relation := self.charm.model.get_relation(self.relation_name)):
            return None

        ovsdb_app_data = relation.data[relation.app]
        nb_connect = ovsdb_app_data.get(CONNECT_STR_KEY.format("nb"))
        sb_connect = ovsdb_app_data.get(CONNECT_STR_KEY.format("sb"))
        if nb_connect and sb_connect:
            return OVSDBConnectionString(nb=nb_connect, sb=sb_connect)
        else:
            return None

class OVSDBProvides(Object):
    _stored = StoredState()

    def __init__(
        self,
        charm: CharmBase,
        relation_name: str,
    ):
        super().__init__(charm, relation_name)
        self.charm = charm
        self.relation_name = relation_name
        self.framework.observe(
            self.charm.on[relation_name].relation_changed,
            self._on_ovsdb_relation_changed,
        )
        self.framework.observe(
            self.charm.on[relation_name].relation_created,
            self._on_ovsdb_relation_changed,
        )

    def _on_ovsdb_relation_changed(self, _: EventBase):
        self.update_relation_data()

    def update_relation_data(self):
        if not (self.charm.unit.is_leader() and self.charm._stored.in_cluster):
            return

        if not (relation := self.charm.model.get_relation(self.relation_name)):
            return

        connect_str = self.get_connection_strings()
        if connect_str:
            relation.data[self.charm.app][CONNECT_STR_KEY.format("nb")] = \
                connect_str.nb
            relation.data[self.charm.app][CONNECT_STR_KEY.format("sb")] = \
                connect_str.sb
            logger.info("connection strings updated")

    """
    get_connection_strings takes the northbound and southbound connection strings
    from the relation data.

    it returns None on failure, and it returns a instance of
    OVSDBConnectionString containing both northbound and southbound strings
    """
    def get_connection_strings(self) -> OVSDBConnectionString:
        nb_connect = None
        sb_connect = None
        try:
            with open(ENV_FILE, "r") as f:
                for line in f:
                    line = line.strip()
                    if line.startswith(CONNECT_ENV_NAME.format("NB")):
                        nb_connect = line.split("=", 1)[1].strip('"')
                    if line.startswith(CONNECT_ENV_NAME.format("SB")):
                        sb_connect = line.split("=", 1)[1].strip('"')
        except FileNotFoundError:
            logger.error(
                "OVN env file not found, is this unit in the microovn cluster?")
            raise FileNotFoundError("{0} not found".format(ENV_FILE))

        if nb_connect and sb_connect:
            return OVSDBConnectionString(nb=nb_connect, sb=sb_connect)
        else:
            return None