Cross-model relations

Cross-model Relations (CMR) allow applications in different models to be related. Models may be hosted on the same controller, different controllers, and different clouds.

What is a relation?: If you are unsure what the terms model and relation mean in the context of Juju, then you should read the Models and Managing relations pages for introductions.


In this section command syntax may be simplified to keep complexity to a minimum

Intended use cases

CMR addresses the case where one may wish to centralise a service. This allows your models to become more targeted and can reduce the cloud resources they may require. A common use case is to deploy prometheus monitoring in a single, central model, and relate it to various data sources in other models hosting various workloads.

Some services that can benefit from central administration:

  • Certificate Authorities, such as the easyrsa charm
  • secret management, such as Vault
  • logging and monitoring
  • block storage management
  • databases

Another use case would be when you are simply using different cloud types and wish to integrate the management of services across those different clouds.


An offer is an application that an administrator makes available to applications residing in other models. The model in which the offer resides is known as the offering model.

The application (and model) that utilizes the offer is called the consuming application (and consuming model).

Like traditional Juju applications,

  • an offer has one or more endpoints that denote the features available for that offer.

  • a fully-qualified offer endpoint includes the associated offer name:

    <offer name>:<offer endpoint>

  • a reference to an offer endpoint will often omit the ‘offer name’ if the context presupposes it.

  • an endpoint has an interface that satisfies a particular protocol.


Central monitoring of model workloads

Assume that we have a number of models for which we want to collect performance metrics using a common prometheus deployment.

We’ll deploy prometheus to one model and offer it.

juju switch bigbrother:voyeur
juju deploy prometheus2
juju expose prometheus2
juju offer prometheus2:target offerprom

In a different model, we’ll deploy a workload.

juju switch monitorme
juju deploy ubuntu
juju deploy telegraf
juju relate ubuntu:juju-info telegraf

Now we’ll consume the prometheus offer and relate our workload to it.

juju consume bigbrother:admin/voyeur.offerprom promed
juju relate telegraf:prometheus2-client promed:target


How to create an offer

An offer stems from an application endpoint. This is how an offer is created:

juju offer <application>:<application endpoint>

By default, an offer is named after its underlying application but you may also choose to give it a different name:

juju offer <application>:<application endpoint> <offer name>


juju deploy mysql
juju offer mysql:db hosted_mysql

To offer both the db and db-admin endpoints:

juju deploy mysql
juju offer mysql:db,db-admin hosted_mysql

Although an offer may have multiple (offer) endpoints it is always expressed as a single URL:


If the above mysql offer were made in the prod model by user admin, the URL would be:


If the ‘controller’ portion is omitted the current controller is assumed.

How to remove an offer

An offer can be removed providing a relation has not been made to it. To override this behaviour the --force option is required, in which case the relation is also removed. This is how an offer is removed:

juju remove-offer [--force] <offer-url>

Note that if the offer resides in the current model then the shorter offer name can be used instead of the longer URL.

Similarly, if an application is being offered it cannot be deleted until all its offers are removed.

How do I control access to an offer?

Offers can have one of three access levels:

  • read (a user can see the offer when searching)
  • consume (a user can relate an application to the offer)
  • admin (a user can manage the offer)

These are applied similarly to how standard model access is applied, via the juju grant and juju revoke commands:

juju grant <user> <access-level> <offer-url>
juju revoke <user> <access level> <offer-url>

Revoking a user’s consume access will result in all relations for that user to that offer to be suspended. If the consume access is granted anew, each relation will need to be individually resumed. Suspending and resuming relations are explained in more detail later.

To grant bob consume access to an offer:

juju grant bob consume admin/prod.hosted_mysql

To revoke bob’s consume access (he will be left with read access):

juju revoke bob consume admin/prod.hosted_mysql

To revoke all of bob’s access:

juju revoke bob read admin/prod.hosted_mysql

Relating to offers

If a user has consume access to an offer, they can deploy an application in their model and establish a relation to the offer by way of its URL. The controller part of the URL is optional if the other model resides in the same controller.

juju add-relation <application>[:<application endpoint>] <offer-url>[:<offer endpoint>]

Specifying the endpoint for the application and the offer is analogous to normal relations. They can be added but are often unnecessary:

juju add-relation <application> <offer-url>

When an offer is related to, a proxy application is made in the consuming model, named after the offer.


juju deploy mediawiki
juju relate mediawiki:db admin/prod.hosted_mysql

An offer can be consumed without relating to it. This workflow sets up the proxy application in the consuming model and creates a user-defined alias for the offer. This latter is what’s used to subsequently relate to. Having an offer alias can avoid a namespace conflict with a pre-existing application.

juju consume <offer-url> <offer-alias>
juju add-relation <application> <offer alias>


juju consume admin/prod.hosted_mysql mysql-alias
juju relate mediawiki:db mysql-alias

Offers which have been consumed show up in juju status in the SAAS section.

The relations block in status shows any relevant status information about the relation to the offer in the Message field. This includes any error information due to rejected ingress, or if the relation is suspended etc.

$ juju status --relations
Model  Controller  Cloud/Region  Version  SLA
test   foo         lxd           2.9.0    unsupported

SAAS          Status  Store  URL
hosted_mysql  active  acme   admin/prod.hosted_mysql

App        Version  Status  Scale  Charm      Store     Rev  OS      Notes
mediawiki  1.19.14  active      1  mediawiki  charmhub  19   ubuntu  

Unit          Workload  Agent  Machine  Public address  Ports   Message
mediawiki/0*  active    idle   0  80/tcp  Ready

Machine  State    DNS             Inst id        Series  AZ  Message
0        started  juju-16fc34-0  trusty      Running

Relation provider  Requirer      Interface  Type     Message
hosted_mysql:db    mediawiki:db  mysql      regular 

To remove a consumed offer:

juju remove-saas <offer alias>

Viewing Offer Details

The `show-offer` command gives details about a given offer.
juju show-offer <offer name>


juju show-offer default.mysql
Store   URL                     Access  Description                                    Endpoint  Interface  Role
myctrl  admin/prod.hostedmysql  admin   MySQL is a fast, stable and true multi-user,   db        mysql      provider
                                        multi-threaded SQL database server. SQL                             
                                        (Structured Query Language) is the most                             
                                        popular database query language in the world.                       
                                        The ma...                                                           

For more details, including which users can access the offer, the the yaml format.


juju show-offer default.mysql --format yaml
  description: |
    MySQL is a fast, stable and true multi-user, multi-threaded SQL database
    server. SQL (Structured Query Language) is the most popular database query
    language in the world. The main goals of MySQL are speed, robustness and
    ease of use.
  access: admin
      interface: mysql
      role: provider
      display-name: admin
      access: admin
      access: read

A non-admin user with read/consume access can also view an offer’s details, but they won’t see the information for users with access.

Inspecting Relations to an Offer

The offers command is used to see all connections to one more offers.

juju offers [--format (tabular|summary|yaml|json)] [<offer name>]

If offer name is not provided, all offers are included in the result.

The default tabular output shows each user connected (relating to) the offer, the relation id of the relation, and ingress subnets in use with that connection. The summary output shows one row per offer, with a count of active/total relations. Use the yaml output to see extra detail such as the UUID of the consuming model.

The output can be filtered by:

  • interface: the interface name of the endpoint
  • application: the name of the offered application
  • connected user: the name of a user who has a relation to the offer
  • allowed consumer: the name of a user allowed to consume the offer
  • active only: only show offers which are in use (are related to)

See juju help offers for more detail.


juju offers mysql
Offer  User   Relation id  Status  Endpoint  Interface  Role      Ingress subnets
mysql  admin  2            joined  db        mysql      provider

juju offers --format summary
Offer         Application  Charm        Connected  Store   URL                      Endpoint  Interface  Role
hosted_mysql  mysql        ch:mysql-57  1/1        myctrl  admin/prod.hosted_mysql  db        mysql      provider

All offers for a given application: juju offers --application mysql

All offers for a given interface: juju offers --interface mysql

All offers for a given user who has related to the offer: juju offers --connected-user fred

All offers for a given user who can consume the offer: juju offers --format summary --allowed-consumer mary

The above command is best run with --format summary as the intent is to see, for a given user, what offers they might relate to, regardless of whether there are existing relations (which is what the tabular view shows).

Relations and firewalls

When the consuming model is behind a NAT firewall its traffic will typically exit (egress) that firewall with a modified address/network. In this case, the --via option can be used with the juju relate command to request the firewall on the offering side to allow this traffic. This option specifies the NATed address (or network) in CIDR notation:

juju add-relation <application> <offer url> --via <cidr subnet(s)>

Example: juju relate mediawiki:db ian:admin/default.mysql --via

The --via value is a comma separated list of subnets in CIDR notation. This includes the /32 case where a single NATed IP address is used for egress.

It’s also possible to set up egress subnets as a model config value so that all cross model relations use those subnets without needing to use the --via option.

juju model-config egress-subnets=<cidr subnet>

Example: juju model-config egress-subnets=

To be clear, the above command is applied to the consuming model.

To allow control over what ingress can be applied to the offering model, an administrator can set up allowed ingress subnets by creating a firewall rule.

juju set-firewall-rule juju-application-offer --whitelist <cidr subnet>

Where ‘juju-application-offer’ is a well-known string that denotes the firewall rule to apply to any offer in the current model. If a consumer attempts to create a relation with requested ingress outside the bounds of the whitelist subnets, the relation will fail and be marked as in error.

The above command is applied to the offering model.

Example: juju set-firewall-rule juju-application-offer --whitelist

The juju set-firewall-rule command only affects subsequently created relations, not existing ones. Only new relations will be rejected if the changed firewall rules preclude the requested ingress.

To see what firewall rules have currently been defined, use the list firewall-rules command.


juju firewall-rules
Service                 Whitelist subnets

Beyond a certain number of firewall rules, which have been dynamically created to allow access from individual relations, Juju will revert to using the whitelist subnets as the access rules. The number of rules at which this cutover applies is cloud specific.

Suspending and resuming relations

Individual relations (connections) to an offer may be temporarily suspended. Suspended relations will run the relation departed / broken hooks on either end, and any firewall ingress will be closed.

Before you can suspend or resume a relation, you need to know the relation id.

Given two related apps (app1: endpoint, app2), the relation id can be found as follows:

juju exec --unit $UNIT_FOR_APP1 -- relation-ids endpoint

The output, <ENDPOINT>:<REL_ID>, gives you the relation id.

Once you have the relation id, suspending and resuming a relation is very easy.

To suspend a relation, do:

juju suspend-relation <id1>

More than one relation id can be specified, separated by spaces.

And, to resume a relation, do:

juju resume-relation <id1>


juju suspend-relation 2 --message "reason for suspension"
juju suspend-relation 3 4 5 --message "reason for suspension"
juju resume-relation 2

Removing relations

To remove a relation entirely:

juju remove-relation <id1>

Removing a relation on the offering side will trigger a removal on the consuming side. A relation can also be removed from the consuming side, as well as the application proxy, resulting in all relations being removed.

Finding offers to use

Offers can be searched based on various criteria:
  • URL (or part thereof)
  • offer name
  • model name
  • interface

The results will show information about the offer, including the level of access the user making the query has on each offer.

To find all offers on a specified controller:

$ juju find-offers foo:
Store  URL                         Access  Interfaces
foo    admin/default.hosted-mysql  admin   mysql:db
foo    admin/default.mysql-admin   admin   mysql-root:db-admin, mysql:db
foo    admin/default.postgresql    admin   pgsql:db

As with the list-offers command, the yaml output will show extra information, including users who can access the offer (if an admin makes the query).

juju find-offers --offer hosted-mysql --format yaml
  access: admin
      interface: mysql
      role: provider
      display-name: admin
      access: admin
      access: read

To find offers in a specified model:

juju find-offers admin/prod
juju find-offers foo:admin/prod

To find offers with a specified interface on the current controller:

juju find-offers --interface mysql

To find offers with a specified interface on a specific controller:

juju find-offers --interface mysql foo:

To find offers with “sql” in the name:

$ juju find-offers --offer sql foo:

Example scenarios

The following CMR scenarios will be examined:

  • Scenario #1 A MediaWiki deployment, based within the same controller, used by the admin user, but consumed by multiple models.
  • Scenario #2 A MediaWiki deployment, based within multiple controllers, used by a non-admin user, and consumed by a single model.

Commands used with Cross-model Relations

The commands related specifically to this subject are:

consume : Accepts an offer to a model but does not relate to it.

find-offers : Finds URLs and endpoints of available offers.

list-firewall-rules : Lists the firewall rules.

offer : Creates an offer.

offers : Lists connected (related to) offers.

remove-offer : Removes an offer.

remove-saas : Removes a SAAS object created with the juju consume command.

resume-relation : Resumes a suspended relation to an offer.

set-firewall-rule : Sets a firewall rule.

show-offer : Shows details for a connected (related to) offer.

suspend-relation : Suspends a relation to an offer.

Last updated 2 months ago.