{% set rfcid = “RFC-0242” %} {% include “docs/contribute/governance/rfcs/_common/_rfc_header.md” %}
{# Fuchsia RFCs use templates to display various fields from _rfcs.yaml. View the #} {# fully rendered RFCs at https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs #}
Outline the use of configuration capabilities in the component framework and the syntax that will be added to CML files to support them.
It should be noted that this document supercedes parts of the earlier Structured Configuration RFCs, which are mentioned in the prior arts section.
Components in Fuchsia use structured configuration to get configuration values. Today configuration values are mostly loaded out of a component's package. It is possible for a parent component to imperatively set configuration values when launching a dynamic component, but most components in Fuchsia are static.
There are multiple motivations for adding this feature:
The first customer for Configuration Capabilities is system assembly, as this feature will make it possible to remove technical debt. The technical debt exists because there is currently no way to provide configuration to a static component besides editing that component's package. System assembly currently opens fuchsia packages, edits their configuration value files, and then re-packages them. This is technical debt as it changes the hash value of the package and the config value file is technically a “private” API of the component that is not easily evolvable.
For out of tree packages that cannot be rebuilt, configuration capabilities provides a way for those components to be configured. There is currently no way to edit those component's configurations within a static topology.
This feature will likely be useful in many future configuration use cases.
Facilitator: neelsa@google.com
Reviewers:
Socialization: This issue has been discussed with the Component Framework team before writing the RFC.
Configuration Capabilities allows CML authors to set the configuration values of static components. They allow for the routing of configuration values through the topology so that multiple components can use the same value. Routing values through the topology allows indirect ancestors to specify values, where the existing feature only allows direct parents to specify values.
Configuration Capabilities should follow existing Component Framework features when possible to be consistent with the rest of the system.
The bulk of the design is CML syntax for declaring and routing a configuration capability. A configuration capability has both its type and value defined in CML. A configuration capability is routed to a component that wishes to use it. The component using the configuration capability will be able to see the value when the component is started by using the existing structured configuration libraries.
Below is an example for defining a configuration capability:
// Configuration capabilities can be defined in any component. // When a configuration capability is defined, a value must be set for it. capabilities: [ { // Define the name of the capability. config: "fuchsia.netstack.UseNetstack3", // Define the type of the configuration. type: "bool", // When defining a configuration capability, there *must* be a value. // If the route for the configuration capability ends at this definition, the // value of the capability will always be this value. value: "true" }, // The below shows a string config. { config: "fuchsia.config.MyString", type: "string", max_size: 100, value: "test", }, // The below shows a vector config. { config: "fuchsia.config.MyUint8Vector", type: "vector", element: { type: "uint8" }, max_count: 100, value: [1, 2, 3 ], }, ]
The type
, element
, max_count
, max_size
fields on the config
capability have identical meanings to their use in the config
stanza. All values that are supported in the config
stanza are supported in the capabilities
block.
The type
field supports the following:
The using block supports the same type
, element
, max_count
, and max_size
fields as the capabilities block.
Below is example syntax for using a configuration capability:
// Using a configuration capability means that this configuration will show // up in the component's structured config at runtime with the specified `key` // name. // NOTE: Using a configuration capability will override the value in the Config // Value File (CVF) and the value obtained from the "mutability" setting. use: [ { config: "fuchsia.netstack.LaunchProcess", // This is the name that the component will see in its Structured Config // struct. If the `use` is optional this must match a name in the "config" // block of the component's manifest. key: "can_launch_process", // The using field needs the type information so that the component's // Config Value File format can be created. type: "bool", // From is identical to other capabilities. from: "parent", }, // The below shows a vector config. { config: "fuchsia.netstack.MyUint8Vector", key: "my_vector", type: "vector", element: { type: "uint8" }, max_count: 100, from: "parent", }, // The below shows a string config. { config: "fuchsia.netstack.MyString", key: "my_string", type: "string", max_size: 256, from: "parent", }, ]
Below is example syntax for routing a configuration capability:
// Expose and Offer behave the same as any other capability. expose: [ { config: "fuchsia.netstack.UseNetstack3", as: "fuchsia.mycomponent.UseVersion3", from: "self", }, ] offer: [ { config: "fuchsia.config.MyString", as: "fuchsia.mycomponent.ProcessName", from: "self", to: "#mychild", }, ]
If a component is using a configuration capability with the availability set to optional
, and that capability is being routed from void
, then the component will receive the value from the Configuration Value File (CVF). This feature exists to support soft migrations for updating configurations.
Before configuration capabilities, the config fields were declared in the config
stanza in the CML. This information is now being replaced by the information in the use
stanza. This means that the Structured Configuration schema that is generated for a component will be a union of the field declarations in the use
block and the config
stanza.
Once all structured config clients have been migrated to configuration capabilities, support for the config block in CML will be removed.
Before configuration capabilities, a config value could be declared as mutability: parent
, which would allow the parent of that component to change the value.
Users of this feature will be migrated to use
a configuration capability from their parent. Once all users have been migrated, this feature will be removed.
The implementation of these CML features is relatively straight forward and can be done in tree in a few CLs. Clients can migrate to using configuration capabilities at any time as this does not affect existing structured configuration features.
We will need to ensure Scrutiny understands the configuration capabilities and can verify that a specific product has a given configuration.
Starting a component may become slightly slower due to Component Framework needing to perform routing on the configuration capabilities a component uses. This could be significant if the capabilities are coming from a component that is unresolved and needs to downloaded. This should be negligible for resolved components.
The ergonomics for this new CML capability are identical to existing capabilities. It is a bit verbose to add and route a configuration capability, but the syntax was chosen to match existing capability syntax as much as possible. Where possible, the syntax was also chosen to match the existing config
block syntax. When the two syntax's conflicted, the existing capability syntax was preferred. Matching existing syntax reduces cognitive effort by users familiar with the component framework.
The CF team may decide to keep the config
block as syntactic sugar for declaring a configuration capability, or add additional syntactic sugar if we need better ergonomics.
This is a new feature. It is backwards compatible with existing structured configuration features.
It is worth noting that routing a configuration capability to a component will always take precedence over the value in the CVF file. If a component has an optional configuration capability route and the route is not present, then the value in the CVF file will be used.
This feature should not impact security. Scrutiny and other tools to investigate CML will work on this new capability type.
It could be argued that setting capabilities in this way will be more visible than the existing strategy of editing values within a component's package.
If a component is using a required configuration capability and one is not routed to it, the component will be unable to start. This should not be a security problem because the parent of a component is trusted, and these routes can be statically verified to be correct.
This proposal should have no impact on privacy.
This feature will need unit and integration tests. The general testing areas are:
The feature will need the following tests added to Scrutiny:
None of these tests require new test infrastructure.
Fuchsia.dev will need to be updated to have documentation on configuration capabilities. The existing capability docs will be used as a template for this new documentation.
The original Structured Configuration RFC proposed that structured config is directly sourced from a component's package. The RFC specifically calls out that it is not attempting to address “configuration data that is set by other components (except parent components and admin components)”. One alternative is to continue to not support a capability based configuration scheme.
One of the drawbacks to Configuration Capabilities instead of the override service is that Configuration Capabilities is more verbose and more complicated. Implementing something globally is always going to be simpler initially. However, Fuchsia has found that capability based systems end up being more composable and understandable in the long run. It is very helpful to be able to say that a specific configuration is only used by a subset of the component topology, or to use two different values within two different components. Configuration Capabilities make this easier to express and embodies the capability based system used elsewhere in Fuchsia. Using the existing CML syntax for configuration allows the feature to be understood more easily by fuchsia developers, and it composes well with component framework's existing tools.
Keeping the type information in the use
block adds 6 additional fields which are only valid for configuration capabilities.
It would be possible to combine these 6 fields into one field with subfields, but adding the fields was preferable as it kept the syntax close to the existing config
block syntax.
One drawback to putting the configuration schema in the use
declaratio is that the use
block defines the type information and also defines routing. Some components may wish to define their configuration without specifying routing, and then route their configuration differently in different scenarios. This is simpler if the type information is in a different place than the Use block.
Component authors that want to change how their types are defined must modify their use
blocks instead of only modifying their config
blocks.
If the combination of configuration definition and routing becomes a persistent pain point for developers, then Component Framework team may revisit this decision.
config
blockOne alternative is to not have a “type” field in the use
declaration, and to instead rely on the type information in the existing “config” block. This was the case in the earlier versions of this RFC. This alternative addresses the current drawback of conflating type information and routing. It makes it easier for clients to define configuration in one place and to route it in another place (possibly including different CML shards to route differently based on different configurations).
In the current Structured Configuration-based implementation in which Component Manager “pushes” configuration to the component when launching it, Component Manager needs to ensure that the routed capability's type matches that of the target Structured Configuration field. It was decided that the type information would be placed on the use
declaration because this is symmetric with the Capability Declaration. When Component Manager performs routing it needs to ensure that the type information lines up, which means that logically the information should be contained at both ends (Capability and Use) of the route.
Another reason for keeping the type information on the use
declaration is that it becomes possible to keep all of the information in the use
declaration and not require a matching “config” block entry. This keeps the information in a single location in the CML file, which makes it easier to audit.
as
field in use
declarationWith the Structured Configuration field name and type information encapsulated within the config
block, as
could be used to specify the field to which the capability is being provided. This would be consistent with how most non-path
“renaming” is done in CML.
The key
term was used instead because the field operates differently than other as
fields. as
is normally optional, but key
is required. key
must also match an existing key in the config
block if the capability is optional.
There are a number of ways that the existing Structured Configuration is inconsistent with how other Capabilities work.
One inconsistency is that the program is deeply dependent on the format of the Structured Configuration that is defined in the component manifest. Normally it is the manifest that depends on the program, and Structured Configuration makes this relationship circular. This is visible in the fact that the Structured Configuration build rules require adding an extra layer between the component, component manifest, and the program. This circular inconsistency will not be addressed by Configuration Capabilities, but it should hopefully be addressed in a followup RFC.
Another inconsistency is that Structured Configuration is “pushed” to the component when it is started, where other capabilities are “pulled” as the component accesses them. This inconsistency is also not addressed in this RFC. The purpose of this RFC is to add routing and capability support within Component Manifests. This RFC does not change the interface between a program and Structured Configuration, so that the number of migrations needed is limited.
Fuchsia will be in a better place to address these inconsistencies after implementing Configuration Capabilities and seeing how they are used. More client data will help us address pain points and implement followup changes.
Prior structured configuration rfcs: