MicroOVN Charm

mj ponsonby Publisher

Platform:

Ubuntu
26.04 24.04
Channel Revision Published Runs on
latest/stable 160 09 Jul 2026
Ubuntu 24.04
latest/stable 159 09 Jul 2026
Ubuntu 24.04
latest/stable 158 09 Jul 2026
Ubuntu 24.04
latest/stable 157 09 Jul 2026
Ubuntu 24.04
latest/stable 156 09 Jul 2026
Ubuntu 24.04
latest/candidate 160 15 Jun 2026
Ubuntu 24.04
latest/candidate 159 15 Jun 2026
Ubuntu 24.04
latest/candidate 158 15 Jun 2026
Ubuntu 24.04
latest/candidate 157 15 Jun 2026
Ubuntu 24.04
latest/candidate 156 15 Jun 2026
Ubuntu 24.04
latest/edge 237 28 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 236 28 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 233 24 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 232 24 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 228 24 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 227 24 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 223 23 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 222 23 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 221 23 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
latest/edge 220 23 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 181 15 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 180 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 178 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 174 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 173 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 172 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 170 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 168 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 167 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/stable 166 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 181 15 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 180 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 178 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 174 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 173 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 172 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 170 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 168 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 167 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/candidate 166 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 248 30 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 247 29 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 244 29 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 239 29 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
24.03/edge 229 24 Jul 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 179 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 177 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 176 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 175 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 171 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 169 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 164 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 163 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 162 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/stable 161 13 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 179 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 177 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 176 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 175 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 171 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 169 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 164 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 163 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 162 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/candidate 161 09 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 250 31 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 249 31 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 246 29 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 245 29 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 243 29 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 242 29 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 241 29 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 240 29 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 231 24 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
26.03/edge 230 24 Jul 2026
Ubuntu 26.04 Ubuntu 24.04
25.03/stable 155 09 Jul 2026
Ubuntu 24.04
25.03/stable 153 15 Jun 2026
Ubuntu 24.04
25.03/stable 150 15 Jun 2026
Ubuntu 24.04
25.03/stable 149 15 Jun 2026
Ubuntu 24.04
25.03/stable 147 15 Jun 2026
Ubuntu 24.04
25.03/candidate 155 15 Jun 2026
Ubuntu 24.04
25.03/candidate 149 22 Apr 2026
Ubuntu 24.04
25.03/candidate 147 22 Apr 2026
Ubuntu 24.04
25.03/candidate 153 22 Apr 2026
Ubuntu 24.04
25.03/candidate 150 22 Apr 2026
Ubuntu 24.04
25.03/edge 155 22 Apr 2026
Ubuntu 24.04
25.03/edge 153 22 Apr 2026
Ubuntu 24.04
25.03/edge 150 22 Apr 2026
Ubuntu 24.04
25.03/edge 149 22 Apr 2026
Ubuntu 24.04
25.03/edge 147 22 Apr 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