`metadata.yaml`

List of files in the charm project > metadata.yaml

See also: About assumes

The only file that must be present in a charm is metadata.yaml, in the root directory. It must be a valid YAML dictionary.

The metadata.yaml file has three required fields: name, summary and description. Here’s a minimal valid metadata.yaml file:

name: mongodb
summary: A document database
description: A database that stores JSON-like data. 

All other fields are optional, but most charms will specify more than just the three required fields mentioned above. The full spec for a charm’s metadata (metadata.yaml) is as follows:

# (Required) The name of the charm. Determines URL in Charmhub and the name administrators
# will ultimately use to deploy the charm. E.g. `juju deploy <name>`
name: <name>

# (Required) A short, one-line description of the charm
summary: <summary>

# (Required) A full description of the configuration layer
description: |
    <description>

# (Optional) A list of maintainers in the format "First Last <email>"
maintainers:
    - <maintainer>

# (Optional) A string (or a list of strings) containing a link (or links) to project websites.
# In general this is likely to be the upstream project website, or the formal website for the
# charmed offering.
website: <url> | [<urls>]

# (Optional) A string (or a list of strings) containing a link (or links) to the charm source code.
source: <url> | [<urls>]

# (Optional) A string (or a list of strings) containing a link (or links) to the charm bug tracker.
issues: <url> | [<urls>]

# (Optional) A link to a documentation cover page on Discourse
# More details at https://juju.is/docs/sdk/charm-documentation
docs: <url>

# (Optional) A list of terms that any charm user must agree with
terms:
    - <term>

# (Optional) True if the charm is meant to be deployed as a subordinate to a 
# principal charm
subordinate: true | false

# (Optional) A map of containers to be created adjacent to the charm. This field
# is required when the charm is targeting Kubernetes, where each of the specified
# containers will be created as sidecars to the charm in the same pod.
containers:
    # Each key represents the name of the container
    <container name>:
        # Note: One of either resource or bases must be specified.
        
        # (Optional) Reference for an entry in the resources field. Specifies 
        # the oci-image resource used to create the container. Must not be 
        # present if a base/channel is specified
        resource: <resource name>

        # (Optional) A list of bases in descending order of preference for use 
        # in resolving a container image. Must not be present if resource is 
        # specified. These bases are listed as base (instead of name) and 
        # channel as in the Base definition, as an unnamed top-level object list
        bases:
            # Name of the OS. For example ubuntu/centos/windows/osx/opensuse
            - name: <base name>

              # Channel of the OS in format "track[/risk][/branch]" such as used by
              # Snaps. For example 20.04/stable or 18.04/stable/fips
              channel: <track[/risk][/branch]>

              # List of architectures that this particular charm can run on
              architectures: 
                  - <architecture>
        
        # (Optional) List of mounted storages for this container
        mounts:
            # (Required) Name of the storage to mount from the charm storage
            - storage: <storage name>
            
              # (Optional) In the case of filesystem storages, the location to
              # mount the storage. For multi-stores, the location acts as the
              # parent directory for each mounted store.
              location: <path>
    
# (Optional) Additional resources that accompany the charm
resources:
    # Each key represents the name of the resource
    <resource name>:

        # (Required) The type of the resource
        type: file | oci-image

        # (Optional) Description of the resource and its purpose
        description: <description>

        # (Required: when type:file) The filename of the resource as it should 
        # appear in the filesystem
        filename: <filename>

# (Optional) Map of relations provided by this charm
provides:
    # Each key represents the name of the relation as known by this charm
    <relation name>:

        # (Required) The interface schema that this relation conforms to
        interface: <interface name>

        # (Optional) Maximum number of supported connections to this relation
        # endpoint. This field is an integer
        limit: <n>

        # (Optional) Defines if the relation is required. Informational only.
        optional: true | false

        # (Optional) The scope of the relation. Defaults to "global"
        scope: global | container

# (Optional) Map of relations required by this charm
requires:
    # Each key represents the name of the relation as known by this charm
    <relation name>:

        # (Required) The interface schema that this relation conforms to
        interface: <interface name>

        # (Optional) Maximum number of supported connections to this relation
        # endpoint. This field is an integer
        limit: <n>

        # (Optional) Defines if the relation is required. Informational only.
        optional: true | false

        # (Optional) The scope of the relation. Defaults to "global"
        scope: global | container

# (Optional) Mutual relations between units/peers of this charm
peer:
    # Each key represents the name of the relation as known by this charm
    <relation name>:

        # (Required) The interface schema that this relation conforms to
        interface: <interface name>

        # (Optional) Maximum number of supported connections to this relation
        # endpoint. This field is an integer
        limit: <n>

        # (Optional) Defines if the relation is required. Informational only.
        optional: true | false

        # (Optional) The scope of the relation. Defaults to "global"
        scope: global | container

# (Optional) Storage requests for the charm
storage:
  # Each key represents the name of the storage
  <storage name>:

      # (Required) Type of the requested storage
      type: filesystem | block

      # (Optional) Description of the storage requested
      description: <description>

      # (Optional) The mount location for filesystem stores. For multi-stores
      # the location acts as the parent directory for each mounted store.
      location: <location>

      # (Optional) Indicates if all units of the application share the storage
      shared: true | false

      # (Optional) Indicates if the storage should be made read-only (where possible)
      read-only: true | false

      # (Optional) The number of storage instances to be requested
      multiple: <n> | <n>-<m> | <n>- | <n>+

      # (Optional) Minimum size of requested storage in forms G, GiB, GB. Size 
      # multipliers are M, G, T, P, E, Z or Y. With no multiplier supplied, M 
      # is implied.
      minimum-size: <n>| <n><multiplier>

      # (Optional) List of properties, only supported value is "transient"
      properties:
          - transient

# (Optional) Device requests for the charm, for example a GPU
devices:
    # Each key represents the name of the device
    <device name>:

        # (Required) The type of device requested
        type: gpu | nvidia.com/gpu | amd.com/gpu

        # (Optional) Description of the requested device
        description: <description>

        # (Optional) Minimum number of devices required
        countmin: <n>

        # (Optional) Maximum number of devices required
        countmax: <n>

# (Optional) Extra bindings for the charm. For example binding extra network
# interfaces. Key only map, value must be blank. Key represents the name
extra-bindings:
    # Key only map; key represents the name of the binding
    <binding name>:

# (Optional) A set of features that must be provided by the Juju model to ensure that the charm can be successfully deployed.
assumes:
    - <feature_name>
    - any-of:
        - <feature_name>
        - <feature_name>
    - all-of:
        - <feature_name>
        - <feature_name>

As can be seen at the end of the full spec above, charm metadata may include a section called “assumes”. This section allows charm authors to explicitly state in the metadata of a charm various features that a Juju model must be able to provide to ensure that the charm can be successfully deployed on it. When a charm comes preloaded with such requirements, this enables Juju to perform a pre-deployment check and to display user-friendly error messages if a feature requirement cannot be met by the model that the user is trying to deploy the charm to. The assumes feature is available since Juju 2.9.23. For more information about the assumes section and its syntax please take a look at Assumes.

In addition to the official fields and keywords mentioned above, a metadata.yaml file may also contain other arbitrary keywords. These can serve to keep track of other choices a charmer might make. In some cases these become semi-official, being adopted by many charmers and even incorporated into CI processes. An example is upstream-source.

Example metadata.yaml

Below is an example of a metadata.yaml file for a Kubernetes charm

name: super-k8s
summary: a really great charm
description: |
    This is a really great charm, whose metadata is suitably complete so as to
    demonstrate as many of the fields as possible.
maintainers:
    - Joe Bloggs <joe.bloggs@email.com>
docs: https://discourse.charmhub.io/t/9999

# The following three fields can be a single string, or a list of strings.
source: https://github.com/foo/super-k8s-operator
issues: https://github.com/foo/super-k8s-operator/issues/
website:
    - https://charmed-super.io/k8s
    - https://super-app.io

containers:
    super-app:
        resource: super-app-image
        mounts:
            - storage: logs
              location: /logs
    
    super-app-helper:
        bases:
            - name: ubuntu
              channel: ubuntu/20.04
              architectures:
                  - amd64
                  - arm64

resources:
    super-app-image:
        type: oci-image
        description: OCI image for the Super App (hub.docker.com/_/super-app)
    
    definitions:
        type: file
        description: A small SQLite3 database of definitions needed by super app
        filename: definitions.db

provides:
    super-worker:
        interface: super-worker

requires:
    ingress:
        interface: ingress
        optional: true
        limit: 1

peers:
    super-replicas:
        interface: super-replicas

storage:
    logs:
        type: filesystem
        location: /logs
        description: Storage mount for application logs
        shared: true

assumes:
    - juju >= 2.9.23 
    - k8s-api

Prior discussions/context around metadata

Relevant documents

I think we should have a description field for a relation, that would explain the intent behind the relation, e.g., “enabling scrape of the /metrics endpoint by technology like Prometheus that supports the OpenMetrics format”. This information would be extremely valuable for a contributor approaching a charm codebase, as well as CharmHub, when we start displaying with which other charms does this one interoperate.

2 Likes

According to https://github.com/canonical-web-and-design/charmhub.io/issues/1171#issuecomment-976579707, CharmHub uses the categories keyword in the metadata to enable the search filters on the search page.

Could someone update this document with this info and the supported categories, please?

Hi Heitor

I left that field out deliberately. Both the tags and categories fields are only really relevant to the older charm store, which will be going away in the not too distant future. These fields are basically a no-op, and probably aren’t of great use in metadata.

Updated the spec to fix the key in container mount which should have been storage not name

A follow up to the discussion on tags and categories is here

cc: @heitor :slight_smile:

Can we now use assumes instead of placeholder images? How?

That would be very helpful! The relations (provides, requires, and peer) and containers are the only fields that do not have a description field.

AFAIK, the assumes functionality is implemented, but currently behind a feature flag. There has been a short term fix though, which means that you can deploy “charm only” charms on Kubernetes by just not specifying a containers map.

@achilleasa will be able to confirm when the assumes stuff lands, and we should update this doc with the supported options when that happens.

Thanks, I’ll give it a try. My impression was that not specifying a container would need to be paired with assumes juju >= 2.9.18.

If you are using a recent 2.9 release you can enable support for enforcing assumes sections in charm metadata as follows: juju controller-config 'features=[charm-assumes]'.

If you enable the flag, juju show-model will also report the features that are supported on the currently active model.

To disable: juju controller-config 'features=[]'.

Juju will parse and store assumes blocks but will not actively enforce them unless the flag is set. We are currently working on a doc page for describing the supported set of features charms can assume and will be launching the feature once the docs have been completed.

To try this out, add an assumes section (see this example) to the charm metadata.yaml like:

assumes:
  - k8s-api

The above syntax is quite flexible (you can nest requirements in any-of/all-of blocks and also provide version constraints) and is described in detail here.

Just wanted to let you know that we have completed the doc-related tasks for the assumes feature and, unless something changes, it will be going live with Juju 2.9.23.

@niemeyer @jameinel this doesn’t seem like a bad idea to me. Adding a description field to the spec won’t require any work Juju/OF end, but could be used by Charmhub for displaying some context around the relations a given charm supports?

I definitely like the idea of having a description field for how this charm interacts with that relation.

For the record, the description field for the relation would be used to power the “Integration description” on the WIP CharmHub Integrations page.

There have been some recent discussions about making some additional metadata fields available for links associated with a given charm, as part of a wider discussion about improving charm documentation.

The main purpose of this, would be to provide simple way for charm authors to point to the upstream website, issue tracker and source code for the charm. Support for this is currently mixed: charm authors can use the publisher page to set a homepage and contact link, but not an issue tracker - and some older (imported) charms have bought their issue tracker along with them from the older charm store.

The snapcraft folks actually already tackled this problem (spec).

We already have the maintainers field, which is analogous to snapcraft’s contact field. My proposition is that we add the fields website, issues and source-code to this spec. This would then enable the store and charmhub folk to read this data and use it to display relevant links on the various charm pages on Charmhub consistently across all charms if it is present?

/cc @jameinel @roadmr @jkfran @gomboli @danieleprocida @hollyhall

3 Likes

The in-progress work for snaps will also benefit Charmhub, and the following URL fields will be available :

“donations” “contact” “issues” “website” “source”

I believe this covers the ones you proposed.

  • Daniel

Ah interesting - so if we stick with those names, the store will natively understand them from metadata.yaml?