Integration (relation)

See first: Juju | Integration

See also: How to add an integration to a charm

Before juju v.3.0, ‘integrations’ were called ‘relations’. Remnants of this persist in the names, options, and output of certain commands, and in integration event names.

In Juju, an integration is a connection between applications, or between different units of the same application (the latter are also known as ‘peer relations’).

The definitions of relations are handled through interfaces, which are “loosely typed”, meaning there is no de-facto specification for:

  • What information a relation must send/receive
  • What actions are to be taken with data sent/received over the wire

While there is no formal specification, it is important to carefully consider the interface you present. Integrations are formed based on interface name only. For integrations to work effectively, the same data format needs to be set/observed on either side of the integration.

Contents:

Types of integration

Provide and require integration

Provide and require integration are the typical form of integration for the case when you want to connect an application with another.

Implicit integration

Implicit integrations are a special form of provide or require integration that allow for simple integrations to be formed without requiring any modifications to target charms. Implicit integrations exist in the reserved namespace. There is currently only one such integration provided to all deployed applications: juju-info.

The juju-info integration captures very select data from the remote unit:

  • private-address
  • public-address

A common use for this type of integration is when authoring a subordinate charm that can be integrated with any other charm – in this case the juju-info implicit integration can be used.

Peer integration

Charms can contain peer integrations, which causes each unit of an application to respond to the other units deployed in the same application.

Integration data

The primary means for applications to communicate over an integration is using integration data. This is exposed to the charm as a property of the event passed to the relevant callbacks. All integration events inherit from the RelationEvent class, which encapsulates the relevant integration at .relation. The integration includes a data parameter of type RelationData which is a mapping containing all integration data stored by participating applications and units.

Integration data comprises a number of “databags” (or “data buckets”). Each application and each unit has its own databag, which is a Python str:str mapping. There are some rules about accessing integration data:

  • Units can read and write their own unit databags (e.g. event.relation.data[self.unit])
  • Units can read from any other unit databags (e.g. event.relation.data[event.unit])
  • Application leaders can read and write their application databags (e.g. event.relation.data[self.app])
  • Non-leaders can read from other application databags (e.g. event.relation.data[event.app])

Integration data is persisted to the controller database, and therefore persists across invocations of the charm code and through the various event handlers that may access it.

The framework also provides a mechanism for a charm author to fetch an integration from the model by name or ID. This can be useful in cases where methods (that are not integration event callbacks) need to access integration data. An example of this might be updating application data on a peer integration in the leader-elected event callback. Details of this method are documented in the API docs, and it is used in context in the examples provided. Where there are multiple integrations present for a single integration name, the get_integration method takes an id of the integration to fetch. In these cases it may be easier to iterate over the integrations property of the model, which returns a Mapping of all integrations.

Contributors: @florezal

This may be inferred from code examples and implicit in associated text, however I wonder if would be worth making it explicit that relation data persists across multiple executions of charm code, and event handlers.

1 Like

Done, thanks! :slight_smile:

In the peer relation example code snippet, is there a specific reason to update the leader-ip in the _on_replicas_relation_joined callback?
I would have expected that this would only be modified within the _on_leader_elected event callback.
Perhaps this is just given as an example, but I want to make sure I’m not missing something important.

In the table about the metadata, we see Subordinate charms are only valid if they have at least one requires relation with container scope.

Is this correct? I thought a subordinate charm would need to have a provides relation with container scope.

I think it would be valuable to mention juju show-unit in the context of this document. Here is a sample output, which could be very useful for debugging relation data without “printf debugging”

> $ juju show-unit av/0
av/0:
  opened-ports: []
  charm: local:focal/avalanche-k8s-0
  leader: true
  relation-info:
  - endpoint: replicas
    related-endpoint: replicas
    application-data: {}
    local-unit:
      in-scope: true
      data:
        egress-subnets: 10.152.183.129/32
        ingress-address: 10.152.183.129
        private-address: 10.152.183.129
    related-units:
      av/1:
        in-scope: true
        data:
          egress-subnets: 10.152.183.129/32
          ingress-address: 10.152.183.129
          private-address: 10.152.183.129
  provider-id: av-0
  address: 10.1.179.84

Hi, Please see this github issue. In view of the discussion perhaps it may be a good idea to make explicit the behavior of peer relations and peer relation data. Specifically the following things

  • The relation created event will execute before leader elected. This needs to be emphasized because AFAIU it is not true for any other type of relation created event except the peer relation created event.

  • However when peer relation created executes a leader will never the less exist despite what is mentioned above . This again is very different from the context of most other event handlers. AFAIU in most other event handlers the charm code can assume at least one unit will exist that is a leader because all these events (except perhaps pebble ready ?) occur after the first leader elected event.

  • Peer application data will persist even if the application unit count is scaled down to zero and then scaled back again. This may or may not be a pleasant surprise to a charm writer. This I expect is not true for unit relation data and I presume (?) relation data between charms.

  • Since this is the reference documentation section it may be useful to have a complete elaboration on “states of persistence for relation data”. For example in a RelationBrokenEvent is it guaranteed that application relation data for that relation will still be accessible ? Or for that matter in a RelationDepartedEvent will unit relation data for that unit still be accessible ? etc.

  • It may also be useful to clarify if during a RelationDepartedEvent where the departing unit is the leader unit, and the unit receiving this event is also the leader unit, is the unit still the leader.

  • When a unit gets a RelationDepartedEvent is it possible to determine if the unit itself self.model.unit is the departing unit or the other unit event.unit is the departing unit ? It will be useful to have this explicitly specified in this reference documentation.

1 Like

I was taking inspiration from this page on integration when working on a relation and found a minor error: I got an ImportIssue when trying to import RelationDataContents and after some digging I found, in the source code, that the class in fact is called RelationDataContent, without the trailing “s”. Perhaps it could be updated!

I got some feedback today about this page from a new charmer, and now that I see there is a separate page for “Integration” for “sdk” and “non-sdk” (“juju”) content, I was wondering if it would be suitable to:

  1. Separate more strictly between juju and operator framework. The current diagram as-is seems like ops docs to me.
  2. Add diagrams with different views. UML-wise, the current diagram is similar to an object diagram. It would be handy to have a deployment or package diagram too.
  3. Present the read/write permissions also in the form of a table. Or create a reference-level page for relations to link to.
  4. Give a better juju internals understanding of where data buckets are actually stored.
  5. Mention juju show-unit and hook tools, and how both could be used for troubleshooting.
  6. Mention relation ids, that they are unique per model, that relations are between apps (not between units), and how tricky it can be with subordinates.
  7. Link to docs about cross-model relations.
  8. Mention that peer relations are auto created on startup.

@tmihoc

@sed-i Planning a bigger intervention in the relation/integration docs for the next two weeks. Will follow up with you and others about this.

2 Likes