Charm Metadata v2

The current oci-image resource type takes the ‘docker url’ to the image. Which can include tags, etc. So it is still allowing a tag, but also allows you to point to a different docker hub registry.

1 Like

I’m assuming that you could use focal/stable or just focal to reference a series or are we telling people to use the version number exclusively?

Also I’m assuming that the order still has the same order as the now deprecated series in metadata.yaml - it will pick the first one and correctly use that? I would expect that we should explain that ordering of given arrays/slices matter.

I’ve updated for congruence with the specification document.

In particular:

  • systems is replaced with bases, which can no longer include a resource name.
  • architectures is removed from metadata.yaml.
  • containers can include a single resource name or a list of bases.

@hpidcock - This spec is being referenced by the updated Charmed SDK documentation. Is it up to date and accurate?

1 Like

Thinking about representing this in the SDK docs in the same format as the snapcraft.yaml spec, and the pebble layer spec.

I think this will make it a little easier to digest for new charmers, along with an example of a more full featured metadata.yaml

First draft below, keen for review before publishing with the SDK docs. Perhaps @manadart and/or @jameinel

Spec:

# (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 list of terms that any charm user must agree with
terms:
    - <term>

# (Optional) A list of capabilities that must be present in order for the charm
# to function as expected
assumes:
    - <capability>

# (Optional) A short list of tags to annotate the charm with
tags:
    - <tag>

# (Optional) A list of categories to classify the charm under
categories:
    - <category>

# (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 targetting 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
            - name: <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) Indicate 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>:

Example:

name: super-charm
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>

categories:
    - web-applications
tags:
    - nodejs
    - express
    - awesome
terms:
    - https://supercorp.com/terms-and-conditions

containers:
    super-app:
        resource: super-app-image
        mounts:
            - name: 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

peer:
    super-replicas:
        interface: super-replicas

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

devices:
    gpu:
      type: nvidia-gpu
      description: CUDA-capable GPU used by super-app

One thing I’ve not seen is a concrete example of extra-bindings being used. Would appreciate some input on how best to demonstrate or explain this better :slight_smile:

2 Likes

extra-bindings is meant for the case where you want to represent the concept of something that needs network binding/routing information, but doesn’t represent a relation. It is a bit of a wart, and something we’d rather people avoid if possible. Openstack charms use it because of a need to have multiple possible networks for internal vs public vs administrative aspects of their applications, and the fact that relations are more about sharing configuration data than defining connectivity.

Here’s a json schema that captures the above:
https://github.com/juju/charm/pull/370

Bit more context on extra-bindings: as John says, they are a bit of a janky solution for a legitimate need.

In Frankfurt (circa March 2020 if I recall) the specification for an alternative was refined within the Juju team and in meetings with Gustavo.

We’d still like to implement it, but it hasn’t yet made it onto the list of things we can’t afford not to have on a cycle backlog.

1 Like

Given that the end goal is to have universal charms, I would like to propose splitting the assumes section into an all_of and a any_of block (the individual sections can be omitted if not used) where each block references a list of feature names.

In order for Juju to deploy the charm, every feature in the all_of block must be supported by the controller whereas at least one of the features in the any_of block must be supported.

Here is an example of how this could look:

assumes:
  all_of:
  - granular_port_access_rules
  any_of:
  - machines
  - containers

In the above example, the charm authors can:

  • signal that a charm can work both as a containerized workload and as a regular workload deployed to a physical/virtual machine (juju or the op framework will figure out the suitable binary/image to deploy based on the substrate).
  • request a particular set of (pebble and/or Juju) features to be available regardless of the deployment target.

Thoughts?

(I have also added the proposal as a comment in the relevant spec doc)

I think display-name is missing from the metadata.yaml list?

1 Like

min-juju-version is proposed for deprecation - what’s proposed to replace it?

The functionality of min-juju-version should be replaced with assumes, which is in the process of being specced out.

It’s currently not supported in Juju, if this is a publisher-only field, we still should add it to the Juju metadata to ensure that we capture it and can utilize it as well.

So juju itself never utilized display-name, it was there for consumption by the Charm Store to be able to diverge the title-on-the-page from the title that you deploy. (eg, ‘MySQL’ vs ‘mysql’ at the very least).

I believe that Charmhub has actually been moving in a different direction, where store-only data is not read from the charm metadata.yaml but instead is editable on the website. (go to https://charmhub.io/<your-charm>/listing and you can see the attributes that you can edit.)
This is also the expected route to go for things like charm categories, and other such properties that only really apply to the store, rather than the charm itself.
It also is a cleaner model when you start thinking about multiple channels for a charm. Once you have 4 different binary .charm files published, which one of them is the canonical ‘display-name’, and which one has the right categories, etc.

Hello! What is this field for? Where it will be used? Is it ok to put the original author here?

I’m asking this questions because there is a request for Charmcraft to automatic populate this field when a charm is initiated, but we’re not sure if that is fine, in which format this should happen (as we don’t know how this is planned to use), etc.

Thanks!!

We have been using this in our charms:

maintainers:
    - John Doe <john@doe.com>
    - Jane Doe <jane@doe.com>

Similar to one of the examples above. But, should it also support adding a team to the list?

What is the difference between tags and categories in the charm metadata.yaml? Which one should we use to make our charms easily searched in CharmHub?

I’ve taken the YAML-style spec from my previous post and made it into a docs page, let’s please use that as the source of documentation for the metadata spec going forward, as it’s a little more discoverable and easy for developers to re-use: Juju | Charm Metadata Reference

1 Like

Further discussion can be had on the discourse post for the relevant doc Charm Metadata Reference