Skip to content

panasheMuriro/juju_charms_pizza

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

Here is a simple, hands-on Juju project using the modern Ops Framework called The Pizzeria Deployment.

We will build two charms:

  1. pizza-shop (The frontend/order manager)
  2. pizza-oven (The backend baker)

This project will teach you how to handle events, read configs (like setting the daily special), and connect services using juju relations (sending pizza orders to the oven).


🍕 Project Overview

   [ pizza-shop ]  <--- (Config: daily-special="Pepperoni")
         |
         |  Relation: pizza-order
         v
   [ pizza-oven ]  <--- (Fires event: order-received)

We will create a relation interface called pizza-order. The pizza-shop will send the requested pizza type across the relation, and the pizza-oven will log that it is baking it.


🏢 Part 1: The pizza-shop Charm

This charm will take a configuration option for the "daily special" and pass that order to any connected oven.

1. charmcraft.yaml (Metadata & Config)

type: charm
name: pizza-shop
summary: Manages customer pizza orders.
description: A learning charm to simulate a pizza shop front.
bases:
  - build-on:
      - name: ubuntu
        channel: "22.04"
    run-on:
      - name: ubuntu
        channel: "22.04"

# 1. Defining the Configuration
config:
  options:
    daily-special:
      type: string
      default: "Margherita"
      description: "The pizza flavor of the day."

# 2. Defining the Relation
provides:
  pizza-order:
    interface: pizza-delivery

2. src/charm.py (The Logic)

#!/usr/bin/env python3
import logging
from ops.charm import CharmBase
from ops.main import main
from ops.model import ActiveStatus

logger = logging.getLogger(__name__)

class PizzaShopCharm(CharmBase):
    def __init__(self, *args):
        super().__init__(*args)
        
        # Observe events
        self.framework.observe(self.on.install, self._on_install)
        self.framework.observe(self.on.config_changed, self._on_config_changed)
        self.framework.observe(self.on.pizza_order_relation_joined, self._on_pizza_order_relation_joined)

    def _on_install(self, event):
        self.unit.status = ActiveStatus("Shop opened!")

    def _on_config_changed(self, event):
        # Read config value
        special = self.config.get("daily-special")
        logger.info(f"Daily special updated to: {special}")
        
        # If we are already related to an oven, update the order dynamically
        if self.model.relations['pizza-order']:
            for relation in self.model.relations['pizza-order']:
                relation.data[self.unit]["requested-pizza"] = special
        
        self.unit.status = ActiveStatus(f"Serving {special}")

    def _on_pizza_order_relation_joined(self, event):
        # Grab the current config and send it across the relation bucket
        special = self.config.get("daily-special")
        event.relation.data[self.unit]["requested-pizza"] = special
        logger.info(f"Sent order for {special} to the oven!")

if __name__ == "__main__":
    main(PizzaShopCharm)

🔥 Part 2: The pizza-oven Charm

This charm listens for incoming relations from a shop and processes the data sent over the wire.

1. charmcraft.yaml

type: charm
name: pizza-oven
summary: Bakes the pizzas sent from the shop.
description: A learning charm simulating a backend baking service.
bases:
  - build-on:
      - name: ubuntu
        channel: "22.04"
    run-on:
      - name: ubuntu
        channel: "22.04"

# Consumes the relation provided by the shop
requires:
  pizza-order:
    interface: pizza-delivery

2. src/charm.py

#!/usr/bin/env python3
import logging
from ops.charm import CharmBase
from ops.main import main
from ops.model import ActiveStatus, WaitingStatus

logger = logging.getLogger(__name__)

class PizzaOvenCharm(CharmBase):
    def __init__(self, *args):
        super().__init__(*args)
        
        self.framework.observe(self.on.install, self._on_install)
        # Observe the relation-changed event to know when data updates
        self.framework.observe(self.on.pizza_order_relation_changed, self._on_pizza_order_changed)

    def _on_install(self, event):
        self.unit.status = WaitingStatus("Oven is cold. Waiting for orders...")

    def _on_pizza_order_changed(self, event):
        # Read data provided by the remote unit (the shop)
        remote_unit = event.unit
        pizza_type = event.relation.data[remote_unit].get("requested-pizza")

        if pizza_type:
            logger.info(f"🔥 [OVEN] Baking a delicious {pizza_type} pizza! 🔥")
            self.unit.status = ActiveStatus(f"Baking {pizza_type}")
        else:
            self.unit.status = WaitingStatus("Connected to shop, but no pizza requested yet.")

if __name__ == "__main__":
    main(PizzaOvenCharm)

🛠️ Key Concepts Learned Here

  • Ops Framework Events: Every method we registered via self.framework.observe(self.on.<event>, self.<method>) is a Juju lifecycle hook.
  • Configs: self.config.get("key") pulls user-defined runtime values directly into your charm execution loop.
  • Relations (relation-joined vs relation-changed): * When the shop joins, it triggers relation-joined and drops data into its local relation data bucket (relation.data[self.unit]).
  • When that data bucket is populated, it triggers relation-changed on the oven's side, allowing the oven to read the data using event.relation.data[remote_unit].

🚀 How to Test it Locally

If you want to pack and test this locally in a microk8s or LXD controller environment:

  1. Pack both charms: Run charmcraft pack inside both project directories to generate the .charm files.
  2. Deploy them:
juju deploy ./pizza-shop_ubuntu-22.04-amd64.charm
juju deploy ./pizza-oven_ubuntu-22.04-amd64.charm
  1. Relate them:
juju relate pizza-shop:pizza-order pizza-oven:pizza-order
  1. Watch the logs & change config: Open a separate terminal and run juju debug-log. Then dynamically change the order:
juju config pizza-shop daily-special="Pepperoni"

You will instantly see the config_changed event fire on the shop, which updates the relation data, triggering relation_changed on the oven to start baking Pepperoni!

Would you like to expand this by adding a custom Juju Action (e.g., a clear-oven or serve-order command)?

About

To learn about juju charms

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages