PaaS App Charmer

In Juju, the PaaS App charmer is a charm SDK supplement specialised in applications written using various specific frameworks (e.g., Flask or Django).

For each framework, the PaaS App Charmer provides a coordinated, framework-specific suite consisting of:

  • a Rockcraft profile + matching extension and
  • a matching Charmcraft profile + matching extension

designed to help you build a functional rock and charm in just a couple of steps.


tl;dr: Rock-n'-charm a Flask application using the PaaS App Charmer's 'flask-framework' suite

Rock:

  1. Initialise the rock: rockcraft init --profile flask-framework, which will generate all the basic structure and content you’ll need for the rock, including a rockcraft.yaml with extensions: ["flask-framework"].
  2. Pack the rock: rockcraft pack, which will pack the rock into an artifact you can upload to a container image registry.

Charm:

  1. Initialise the charm: charmcraft init --profile flask-framework. This will generate all the basic structure content you’ll need for the charm, including a charmcraft.yaml pre-loaded with extensions: ["flask-framework"] and a src/charm.py pre-loaded with paas_app_charmer.flask.
  2. (optional) Edit the charmcraft.yaml file to declare a configuration or an integration, from the list supported by the PaaS App Charmer for the Flask framework.
  3. Pack the charm: charmcraft pack, which will pack the charm into an artifact you can (optionally, publish on Charmhub and) deploy and manage with Juju.

The PaaS App Charmer thus makes it easy and fast to integrate certain classes of applications into the charm ecosystem.

The PaaS App Charmer is especially suitable for Juju users who find themselves in the position where they have to fill the gap between

  • applications that are general purpose and already have a public charm and
  • applications that are specific to their business and thus lack a charm and may never have a public charm. :point_left: the PaaS App Charmer (at least, for 12-factor / web apps)

Contents:

List of PaaS App Charmer suites

This section documents all of the PaaS App Charmer suites – their names and the specific charm they produce, especially the knobs they expose that you can use to customise the charm further in the various supported ways.

Pro tip:

All of these knobs are related in one way or another to the rockcraft.yaml or charmcraft.yaml file.

To learn about these files and their generic keys in general see Rockcraft | File rockcraft.yaml and, respectively, Charmcraft | File charmcraft.yaml.

To find out about more about these files in the form generated by the PaaS App Charmer, examine these files and their contents in your rock/charm directory, either in the default, abbreviated form or by expanding the content contributed by the extension in use by running rockcraft expand-extension / charmcraft expand-extension. See more: Manage extensions > View details about an extension in use.

The documentation below will focus on the latter, highlighting especially the bits that you can customise to take full advantage of the capabilities supported out-of-the-box by the PaaS App Charmer.

flask-framework

The flask-framework suite (resulting in a Rockcraft profile, a Rockcraft extension, a Charmcraft profile, and a Charmcraft extension of the same name) supports Flask applications. Most of the functionality is already built in, but the suite also exposes certain knobs that you can customise. These are as below.

rockcraft.yaml > parts > flask-framework/dependencies: > stage-packages

You can use this key to specify any dependencies required for your Flask application. For example, below we use it to specify libpq-dev:

parts:
    flask-framework/dependencies:
      stage-packages:
        # list required packages or slices for your flask application below.
        - libpq-dev

rockcraft.yaml > parts > flask-framework/install-app: > prime

You can use this key to specify the files to be included in your rock upon rockcraft pack, in flask/app/<filename> notation. For example:

parts:
  flask-framework/install-app:
    prime:
       - flask/app/.env
       - flask/app/app.py
       - flask/app/webapp
       - flask/app/templates
       - flask/app/static

Some files, if they exist, are included by default. These include: app, app.py, migrate, migrate.sh, migrate.py, static, templates.

Regarding the migrate.sh file:

If your app depends on a database it is common to run a database migration script before app startup which, for example, creates or modifies tables. This can be done by including the migrate.sh script in the root of your project. It will be executed with the same environment variables and context as the Flask application.

If the migration script fails, the app won’t be started and the app charm will go into blocked state. The migration script will be run on every unit and it is assumed that it is idempotent (can be run multiple times) and that it can be run on multiple units at the same time without causing issues. This can be achieved by, for example, locking any tables during the migration.

charmcraft.yaml > config > options

You can use the predefined options (run charmcraft expand-extension for details) or add some of your own. In the latter case, any option you define will be used to generate environment variables, on the template config option nameFLASK_CONFIG_OPTION_NAME. In either case, a user of your charm will be able to set it in the usual way by running juju config <application> <option>=<value>.

For example, if you define an option called token, as below, this will generate a FLASK_TOKEN environment variable, and a user of your charm can set it by running juju config <application> token=<token>.

config:
  options:
    token:
      description: The token for the service.
      type: string
      required: true

charmcraft.yaml > peers, provides, requires

Your charm already has some peers, provides, and requires endpoints


Expand to view pre-loaded endpoints
peers:
  secret-storage:
    interface: secret-storage
provides:
  metrics-endpoint:
    interface: prometheus_scrape
  grafana-dashboard:
    interface: grafana_dashboard
requires:
  logging:
    interface: loki_push_api
  ingress:
    interface: ingress
    limit: 1

In addition to that you may also add one or more of the following additional endpoint definitions, as needed.

requires:
  # Enable integration with the mysql and the mysql-k8s charm:
  mysql:
    interface: mysql_client
    limit: 1
  # Enable integration with the postgresql and the postgresql-k8s charm:
  postgresql:
    interface: postgresql_client
    limit: 1
  # Enable integration with the mongodb charm:
  mongodb:
    interface: mongodb_client
    limit: 1
  # Enable integration with the redis charm:
  redis:
    interface: redis
    limit: 1

Your charm’s code is already set up to interpret them and enable integration with any charms that support the same endpoint interface but have the opposite role simply by running juju integrate app1 app2.

After the integration has been established, the connection string (required to be able to connect to the database) will be available as one of the following environment variables:

  • MYSQL_DB_CONNECT_STRING
  • POSTGRESQL_DB_CONNECT_STRING
  • MONGODB_DB_CONNECT_STRING
  • REDIS_DB_CONNECT_STRING.