- Table of Contents
- List of Tables
- Revision
- About this Manual
- Scope
- Definition/Abbreviation
- 1 Feature Overview
- 2 Functionality
- 3 Design
- 4 Flow Diagrams
- 5 Error Handling
- 6 Serviceability and Debug
- 7 Warm Boot Support
- 8 Scalability
- 9 Unit Tests
Rev | Date | Author | Change Description |
---|---|---|---|
0.1 | 03/01/2021 | Mohamed Ghoneim | Initial version |
This document provides a detailed description on the strategy to implement the SONiC configuration generic update and rollback feature.
This document describes the high level design of a SONiC configuration generic update and rollback feature. This document provides minor implementation details about the proposed solutions.
Term | Meaning |
---|---|
ConfigDB | Configuration Database |
JSON | JavaScript Object Notation |
Updating SONiC partial configurations systematically has been a challenge for a long time, as each part of the config has different requirements in terms of which files to push to the device, what commands to use, and if there are services that need manual restarting. For example updating ACLs
is very different from updating DHCP
configurations.
ACLs: Updating ACLs require the following steps:
- Pushing
acl.json
file to the device that contain the new ACL rules - Pushing
minigraph.xml
to the device that contains the new ACL interfaces - Execute
sudo acl-loader update full /etc/sonic/acl.json --table_name example_acl
DHCP: Updating DHCP config requires the following steps:
- Pushing
minigraph.xml
to the device that contains the new ACL interfaces - Generating
dhcp_servers
JSON configs from theminigraph.xml
, and saving it as a temporary file - Executing
sudo sonic-cfggen -j /tmp/dhcp.json --write-to-db
- Restart
dhcp_relay
service
We have explored SONiC CLI commands to make configuration changes. These CLI commands result in updates to the ConfigDB which are corresponding to the CLI command executed. For example, the config vlan add 10
will create a new row in the VLAN table of the ConfigDB. But relying on the CLI commands to do partial update is also not feasible as there is no standard way of showing the config after the update. Setting up a different update mechanism for each part of the config is very time consuming and inefficient.
The other challenge to updating a switch is recoverability via rollback. Rollback needs to be with minimum-disruption e.g. if reverting ACL updates DHCP should not be affected. Currently SONiC has a couple of operations that can be candidates for rollback config load
and config reload
.
config reload <config_db.json> : This command clears all the contents of the ConfigDB and loads the contents of config_db.json into the ConfigDB. After that all the Docker containers and Linux services are restarted to establish the user specified configuration state in the config_db.json file.
- Pro's
- Assured way of affecting a configuration state change
- Con's
- Brings the links down and resets the forwarding state. This operation is disruptive in nature
- Time consuming as it may take 2-3 minutes for all the services to come back online. The time taken may vary based on the switch CPU power.
- Verdict
- Cannot be used as a rollback mechanism
config load <config_db.json>: This command loads the contents of config_db.json into the ConfigDB. The updates made to the ConfigDB are additive in nature and thus the new configuration state is a combination of the current running state and the partial configuration state specified by the user in the config_db.json file
- Pro's
- Quick way to add new configuration changes
- It does not disrupt existing service whose configuration is not being modified. So it is non-disruptive in nature
- Con's
- Can't remove existing configuration and can only be used to add/modify the existing configuration
- Verdict
- Cannot be used as a rollback mechanism
Since both config load
and config reload
are not suitable for a minimum-disruption rollback, we have to look for other approaches.
In this design document, we will be exploring how to standardize the way to do partial updates, how to take checkpoints and finally how to rollback the configurations.
In summary, this is the flow of an update:
And the steps would be:
admin@sonic:~$ config checkpoint mycheckpoint
admin@sonic:~$ echo "config changes to apply to ConfigDb" > some-config-changes.json-patch
admin@sonic:~$ config apply-patch ./some-config-changes.json-patch
admin@sonic:~$ config rollback mycheckpoint # in case of failures
- A single, simple command to partially update SONiC configuration according to a patch of updates
- A single, simple command to take a checkpoint of the full current SONiC config
- A single, simple command to fully rollback current SONiC configs with to a checkpoint
- [low-priority] A single simple command to fully replace current SONiC configs with a full config provided by an external user.
- Other commands to list checkpoints, delete checkpoints
- The patch of updates should follow a standard notation. The JSON Patch (RFC6902) notation should be used
- Config rollback should be with minimum disruption to the device e.g. if reverting ACL updates DHCP should not be affected i.e. minimum-disruption rollback
- User should be able to preview the configuration difference before going ahead and committing the configuration changes
- In case of errors, the system should just report an error and the user should take care of it
- Only one session globally can update device config at a time i.e. no concurrent updates to configurations
- All commands argument to generated using Python-click to provide help menus and other out-of-the box features
- Only root user must be allowed to execute the commands
- Non-root users can execute commands with dry-run option
- Each command must provide the following sub options:
- "dry-run" Perform a dry-run of the command showing exactly what will be executed on the device, without executing it
- "verbose" Provide additional information on the steps executed
N/A
N/A
SONiC ConfigDB contents can be retrieved in a JSON file format. Modifying JSON file should follow some rules in order to make it straightforward for the users. Fortunately there is already a formal way of defining JSON config updates. It is called JsonPatch, and is formally defined in RFC 6902 JSON Patch.
On top of ConfigDBConnector we are going to implement RFC 6902 JSON Patch. This API we will call apply-patch
. On top of that API, we will implement the rollback
functionality. It will simply starts by getting the diff (patch) between the checkpoint and the current running config, then it will call the API apply-patch
to update that patch.
The JsonPatch python is an open source library that already implements the RFC 6902 JSON Patch. We can leverage this library to verify patch config, generate a diff between checkpoint and current running config, verify apply-patch and rollback work as expected by simulating the final output of the update and comparing with the observed output.
Example: Assume running-config to be:
{
"DEVICE_NEIGHBOR": {
"Ethernet8": {
"name": "Servers1",
"port": "eth0"
},
"Ethernet96": {
"name": "Servers23",
"port": "eth0"
},
},
"DHCP_SERVERS": {
"1.1.1.1": {},
"2.2.2.2": {},
"3.3.3.3": {}
}
}
and the ask to:
- replace port under Ethernet8 with eth1
- add 4.4.4.4 to DHCP_SERVERS
- remove 2.2.2.2 from DHCP_SERVERS
The steps would be:
- Take the content of config DB here and store it as a checkpoint
admin@sonic:~$ config checkpoint mycheckpoint
- Create a file on the device named
dhcp-changes.json-patch
, with the following content
[
{
"op": "replace",
"path": "/DEVICE_NEIGHBOR/Ethernet8/port",
"value": "eth1"
},
{
"op": "add",
"path": "/DHCP_SERVERS/4.4.4.4",
"value": {}
},
{
"op": "remove",
"path": "/DHCP_SERVERS/2.2.2.2"
}
]
- Apply patch using
apply-patch
command
admin@sonic:~$ config apply-patch ./dhcp-changes.json-patch
- In case of failure, rollback the config using
rollback
command
admin@sonic:~$ config rollback mycheckpoint --verbose # verbose to see generated patch
This will internally do a diff, and generate patch of the needed changes and apply using apply-patch
.
The patch will be:
[
{
"op": "replace",
"path": "/DEVICE_NEIGHBOR/Ethernet8/port",
"value": "eth0"
},
{
"op": "remove",
"path": "/DHCP_SERVERS/4.4.4.4,",
"value": {}
},
{
"op": "add",
"path": "/DHCP_SERVERS/2.2.2.2"
},
]
All the introduced commands will be part of the python-sonic-utilities package installed in Debian host O/S.
The apply-patch
method should help with automating partial config updates, as external systems can generate the update patch, and apply.
The checkpoint
and rollback
commands should help improve recoverability, can also be used by external systems to help revert failures during apply-patch
operation.
Human operators can also leverage the checkpoint
and rollback
functionalities while doing updates through the CLI using SONiC CLI commands.
The SONiC apply-patch
command can broadly classified into the following steps
Using YANG SONiC models, but the format of the JSON patch is not what YANG SONiC models is built to verify. We will verify using the following steps:
- Get current running config from ConfigDB as JSON
- Simulate the patch application on the current config JSON object
- Verify the the simulated output using YANG SONiC models
There are many ideas to ordering the patch, I will pick a simple and straight forward idea to better understand this problem. Let's assume the main granular element is Table
. Each table gets assigned an order index based on its semantic dependencies. Semantic dependencies mean tables referencing other tables, think of it as the result of doing a topological sorting of table dependencies. For example: PORT
lots of table depend on it, but it does not depend on other tables so it gets a low index. VLAN_MEMBER
depends on PORT
so its gets a higher index, and so on. This helps make sure low order table absorb the changes first before dependent tables are updated.
Let's assume the following order indices:
PORT = 1
VLAN_MEMBER = 2
ACL = 3
And the patch to update is the following:
[
{ "op": "add", "path": "/ACL_TABLE/NO-NSW-PACL-V4/ports/0", "value": "Ethernet2" }
{ "op": "add", "path": "/VLAN_MEMBER/Vlan100|Ethernet2", "value": { "tagging_mode": "untagged" } }
{ "op": "add", "path": "/PORT/Ethernet2", "value": { "lanes": "65", "speed": "10000"} }
]
Each operation belongs to a single table, the table name will be the first token in the path after the first /
. For example the table of the first operation is ACL_TABLE
. Let's add the table name to each operation.
[
{ "table": "ACL_TABLE", "op": "add", "path": "/ACL_TABLE/NO-NSW-PACL-V4/ports/0", "value": "Ethernet2" }
{ "table": "VLAN_MEMBER", "op": "add", "path": "/VLAN_MEMBER/Vlan100|Ethernet2", "value": { "tagging_mode": "untagged" } }
{ "table": "PORT", "op": "add", "path": "/PORT/Ethernet2", "value": { "lanes": "65", "speed": "10000"} }
]
Using the indices table above, let's assign an order index to each operation:
[
{ "order": 3, "table": "ACL_TABLE", "op": "add", "path": "/ACL_TABLE/NO-NSW-PACL-V4/ports/0", "value": "Ethernet2" }
{ "order": 2, "table": "VLAN_MEMBER", "op": "add", "path": "/VLAN_MEMBER/Vlan100|Ethernet2", "value": { "tagging_mode": "untagged" } }
{ "order": 1, "table": "PORT", "op": "add", "path": "/PORT/Ethernet2", "value": { "lanes": "65", "speed": "10000"} }
]
Now let's order the operations by "order":
[
{ "order": 1, "table": "PORT", "op": "add", "path": "/PORT/Ethernet2", "value": { "lanes": "65", "speed": "10000"} }
{ "order": 2, "table": "VLAN_MEMBER", "op": "add", "path": "/VLAN_MEMBER/Vlan100|Ethernet2", "value": { "tagging_mode": "untagged" } }
{ "order": 3, "table": "ACL_TABLE", "op": "add", "path": "/ACL_TABLE/NO-NSW-PACL-V4/ports/0", "value": "Ethernet2" }
]
This will be the final order of applying the changes.
Unfortunately this solution does not always work especially for the case of deletion from PORT, VLAN_MEMBER, ACL_TABLE. Where if following the same logic we will have:
[
{ "order": 1, "table": "PORT", "op": "remove", "path": "/PORT/Ethernet2" }
{ "order": 2, "table": "VLAN_MEMBER", "op": "remove", "path": "/VLAN_MEMBER/Vlan100|Ethernet2" }
{ "order": 3, "table": "ACL_TABLE", "op": "remove", "path": "/ACL_TABLE/NO-NSW-PACL-V4/ports/0" }
]
This will not work, as the PORT table will complain that the port Ethernet2
is still in use by a VLAN_MEMBER
.
Since this problem can be solved by many ways, and it needs to verified thoroughly, let's abstract it to a a contract which will be implemented later.
The contract would be:
list<JsonChange> order-patch(JsonPatch jsonPatch)
Here is a summary explaining the JsonChange
contract. Check 3.1.1.4.1 JsonChange for detailed description.
aspect | description |
---|---|
definition | JsonChange is a JsonPatch in terms of the final outcome of the update. Ordering of JsonChange updates will not follow the operations order within a JsonPatch, but will update the JSON file in any arbitrary order. |
Here is a summary explaining the order-patch
contract, Check 3.1.1.4 Patch Orderer for detailed description.
aspect | item | description |
---|---|---|
inputs | JsonPatch | It represents the changes that needs to applied to the device running config, described in JSON Patch (RFC6902). |
outputs | list<JsonChange> | The list will contain the steps to be followed to apply the input JsonPatch correctly. Each item in the list is assumed to be executed after the previous item, in the order given in the list. |
errors | malformedPatchError | Will be raised if the input JsonPatch is not valid according to JSON Patch (RFC6902). |
other errors | Check 3.1.1.4.2 Order-Patch for exact list of errors to expect. | |
side-effects | None | |
assumptions | running-config locked | The implementor of this contract might interact with ConfigDB to get the running-config, it is assumed the running-config is locked for changes for the lifespan of the operation. |
There are a few SONiC applications which store their configuration in the ConfigDB. These applications do not subscribe to the ConfigDB change events. So any changes to their corresponding table entries as part of the patch apply process in the ConfigDB are not processed by the application immediately. In order to apply the configuration changes, corresponding service needs to be restarted. Listed below are some example tables from SONiC config, and the corresponding services that need to be manually restarted.
NOTE: In the below table we have "Key": ["list-item1", ...]. Key in below example is the table name, corresponding list is the list of services that needs restarting post table update.
{
"SYSLOG_SERVER": ["rsyslog"],
"DHCP_SERVER": ["dhcp_relay"],
"NTP_SERVER": ["ntp-config.service", "ntp.service"]
"BGP_MONITORS": ["bgp"],
"BUFFER_PROFILE": ["swss"],
"RESTAPI": ["restapi"]
}
Although some other services do not need manual restarting, and absorb the configs silently, there is no good way to make sure there is no errors encountered while the services absorbed the changes. Some of these services might report an error to syslog, others might crash ...etc.
Currently there is no standard approach of updating ConfigDB that takes care of manual service restart and verifying services have absorbed change correctly.
So we are going to introduce a new contract overlaying ConfigDB changes, that will take care of making correct changes to ConfigDB as well as verifying that corresponding services have absorbed the changes correctly.
The contract would be:
void apply-change(JsonChange jsonChange)
Check 3.1.1.4.1 JsonChange for detailed description of JsonChange.
Here is a summary explaining the apply-change
contract, Check 3.1.1.4 Change Applier for detailed description.
aspect | item | description |
---|---|---|
inputs | JsonChange | It represents the changes that needs to applied to the device running config, described in 3.1.1.4.1 JsonChange. |
outputs | None | |
errors | malformedChangeError | Will be raised if the input JsonChange is not valid according to 3.1.1.4.1 JsonChange. |
other errors | Check 3.1.1.4.1 apply-change for exact list of errors to expect. | |
side-effects | updating running-config | This operation will cause changes to the running-config according to the input JsonChange. |
assumptions | running-config locked | The implementor of this contract will interact with ConfigDB to updating the running-config, it is assumed the running-config is locked for changes for the lifespan of the operation. |
The expectations after applying the JsonPatch is that it will adhere to RFC 6902.
The verification steps
- Get the state of ConfigDB JSON before the update as a JSON object
- Simulate the JsonPatch application over this JSON object
- Compare that JSON object with current ConfigDB JSON
- In case of mismatch, just report failure
If an error is encountered during the apply-patch
operation, an error is reported and the system DOES NOT take any automatic action. The user can take a checkpoint
before running apply-patch
and if the operation failed, the user can rollback
. Another idea is to introduce a config-session
where a user enters a config-session
mode does all the modifications, once they are happy with it, they commit
the changes to ConfigDB. config-session
can be built using checkpoint
and rollback
functionality, but this config-session
idea is beyond the scope of this document.
All the configuration update operations executed and the output displayed by the apply-patch
command are stored in the systemd journal. They are also forwarded to the syslog. By storing the commands in the systemd-journal, the user will be able to search and display them easily at a later point in time. The show apply-patch log
command reads the systemd-journal to display information about the apply-patch
command that was previously executed or currently in progress.
The SONiC checkpoint
command can broadly classified into the following steps
The ConfigDBConnector class is used to obtain the running configuration in JSON format
ConfigDB might be in invalid to begin with and later if used for rollback it will not work.
Save the checkpoint to a dedicated location on the SONiC box
The SONiC rollback
command can broadly classified into the following steps
The ConfigDBConnector class is used to obtain the running configuration in JSON format
Load the checkpoint from the SONiC box
The current ConfigDB JSON config is compared with the JSON config from the checkpoint. The comparison result should be in JsonPatch format.
Pass the generated JsonPatch to the apply-patch API
Compare the ConfigDB JSON after the update with the checkpoint JSON, there should be no differences.
If an error is encountered during the rollback
operation, an error is reported and the system DOES NOT take any automatic action. Rollback operation is itself an automated fail-safe action, if itself fails the caller should decide how to handle such failures e.g. generate an alert of high severity, or do config reload
.
All the configuration update operations executed and the output displayed by the rollback
command are stored in the systemd journal. They are also forwarded to the syslog. By storing the commands in the systemd-journal, the user will be able to search and display them easily at a later point in time. The show rollback log
command reads the systemd-journal to display information about the rollback
command that was previously executed or currently in progress.
The SONiC replace
command can broadly classified into the following steps
The external user to provide the full target ConfigDB config in JSON format.
The target config are unknown configs and need to be validating using YANG models
The ConfigDBConnector class is used to obtain the running configuration in JSON format
The current ConfigDB JSON config is compared with the target JSON config. The comparison result should be in JsonPatch format.
Pass the generated JsonPatch to the apply-patch API
Compare the ConfigDB JSON after the update with the target JSON, there should be no differences.
If an error is encountered during the replace
operation, an error is reported and the system DOES NOT take any automatic action. The user can take a checkpoint
before running replace
and if the operation failed, the user can rollback
.
All the configuration update operations executed and the output displayed by the replace
command are stored in the systemd journal. They are also forwarded to the syslog. By storing the commands in the systemd-journal, the user will be able to search and display them easily at a later point in time. The show replace log
command reads the systemd-journal to display information about the replace
command that was previously executed or currently in progress.
The user of the system, can simply be a human operator or a service that can talk to SONiC CLI. The user can only apply-patch if they have an admin permission. Users without admin permissions can only execute dry-run of the operations where they will be able to see the exact changes going to affect the device, without executing these changes.
These are the CLI of SONiC switch to which makes it easy for the users to interact with the system. The CLI commands we are interested in are config ...
and show ...
, check SONiC Command Line Interface Guide to learn more about SONiC CLI.
For further details on the CLI setup, Check 3.2.2 CLI
YANG is a data modeling language used to model configuration data, state data, Remote Procedure Calls, and notifications for network management protocols. For further details check The YANG 1.1 Data Modeling Language
SONiC is currently getting on-boarded to YANG data models to help verify and generate the configurations. We will leverage these YANG models to help verify the result of simulating the JsonPatch on ConfigDb, to make sure final outcome adheres to all the constrains defined in the YANG models. For further details check YANG SONiC models.
This component is going to solve the problems discussed in Stage-2 JSON Patch Ordering. This component is going to help provide an order of execution to the JsonPatch, in such a way when the config is updated in this order, there will be no errors generated on the device. The exact implementation details of this component will not be included in this design document, but we are going to explain in details the contract for any implementation.
The contract would be:
list<JsonChange> order-patch(JsonPatch jsonPatch)
aspect | description |
---|---|
definition | JsonChange is a JsonPatch in terms of the final outcome of the update. Ordering of JsonChange updates will not follow the operations order within a JsonPatch, but will update the JSON file in any arbitrary order. |
validation | JsonChange is considered valid if its corresponding JsonPatch is valid according to JSON Patch (RFC6902) |
Assume we have the following JsonPatch:
[
{ "op": "add", "path": "/ACL_TABLE/NO-NSW-PACL-V4/ports/0", "value": "Ethernet2" }
{ "op": "add", "path": "/VLAN_MEMBER/Vlan100|Ethernet2", "value": { "tagging_mode": "untagged" } }
{ "op": "add", "path": "/PORT/Ethernet2", "value": { "lanes": "65", "speed": "10000"} }
]
Operations specified in the JsonPatch will be executed in the order specified, but JsonChange can be applied in any arbitrary order as the implementation specify, for example:
[
{ "op": "add", "path": "/PORT/Ethernet2", "value": { "lanes": "65", "speed": "10000"} }
{ "op": "add", "path": "/VLAN_MEMBER/Vlan100|Ethernet2", "value": { "tagging_mode": "untagged" } }
{ "op": "add", "path": "/ACL_TABLE/NO-NSW-PACL-V4/ports/0", "value": "Ethernet2" }
]
or
[
{ "op": "add", "path": "/PORT/Ethernet2", "value": { "lanes": "65", "speed": "10000"} }
{ "op": "add", "path": "/VLAN_MEMBER/Vlan100|Ethernet2", "value": { "tagging_mode": "untagged" } }
{ "op": "add", "path": "/ACL_TABLE/NO-NSW-PACL-V4/ports/0", "value": "Ethernet2" }
]
The only condition of JsonChange is that the final outcome after applying the whole JsonPatch is the same.
aspect | item | description |
---|---|---|
inputs | JsonPatch | It represents the changes that needs to applied to the device running config, described in JSON Patch (RFC6902). |
outputs | list<JsonChange> | The list will contain the steps to be followed to apply the input JsonPatch correctly. Each item in the list is assumed to be executed after the previous item, in the order given in the list. |
errors | malformedPatchError | Will be raised if the input JsonPatch is not valid according to JSON Patch (RFC6902). |
unprocessableRequestError | Will be raised if the implementation of the order-patch is not able to provide a valid ordering according to its own ordering validations. |
|
resourceNotFoundError | Will be raised if running config failed to be read or in case any other external resource is not found nor available. | |
conflictingStateError | Will be raised if the patch cannot be applied to the current state of the running config e.g. trying to add an item to a non-existing json dictionary. | |
internalError | Will be raised if any other error is encountered that's different than the ones listed above. | |
side-effects | None | |
assumptions | running-config locked | The implementor of this contract might interact with ConfigDB to get the running-config, it is assumed the ConfigDB is locked for changes for the lifespan of the operation. |
If order-patch
has to force the update to follow very specific steps, it would have to provide multiple JsonChange objects in the return list of order-patch
.
order-patch
is returning a list of JsonChanges instead of a simple JsonPatch with multiple operations because a JsonChange can group together multiple JsonPatch operations that share no dependency and can be executed together. This can help the implementor of apply-change
to optimize the mechanism for applying JsonChange e.g. group changes under same parent together or reduce number of service restarts.
For example: Assume JsonPatch contains:
[
{ "op": "add", "path": "/DHCP_SERVERS/4.4.4.4", "value": {} },
{ "op": "replace", "path": "/DEVICE_NEIGHBOR/Ethernet8/port", "value": "eth1" },
{ "op": "add", "path": "/DHCP_SERVERS/2.2.2.2", "value": {} }
]
We have 2 operations updating DHCP servers, and another operation for DEVICE_NEIGHBOR. We can assume DHCP and DEVICE_NEIGHBOR tables to be independent meaning they can updated at the same time. order-patch
would return:
[
[
{ "op": "add", "path": "/DHCP_SERVERS/4.4.4.4", "value": {} },
{ "op": "replace", "path": "/DEVICE_NEIGHBOR/Ethernet8/port", "value": "eth1" },
{ "op": "add", "path": "/DHCP_SERVERS/2.2.2.2", "value": {} }
],
]
Updating DHCP_SERVERS requires restarting dhcp_relay
service, so if the above patch is to be executed in order, we will restart dhcp_relay
service twice.
But since the implementor of apply-change
can order the operations in any way they see fit since they are OK to update together. They can decide move the DHCP updates together, and DHCP table twice, but restart dhcp_relay
service only once.
Let's take a visual example, assume we have a JsonPatch with 8 operations, and here is the topological order of the operation. Arrow from op-x to op-y means op-y depends on op-x.
If we sort by on the operations we would have:
But if we organize the operations into groups of JsonChange, we will have:
This will allow the the implementor of apply-change
to have the freedom to optimize the operations in any order they see fit.
NOTE: Check Patch Orderer implementation design design details in Json_Patch_Ordering_using_YANG_Models_Design document.
This component is going to solve the problems discussed in Stage-3 Applying list of JsonChanges in order. This component is going to help provide a mechanism for updating a JsonChange taking into account manual service restarts, and update verification. The exact implementation details of this component will not be included in this design document, but we are going to explain in details the contract for any implementation.
The contract would be:
void apply-change(JsonChange jsonChange)
aspect | item | description |
---|---|---|
inputs | JsonChange | It represents the changes that needs to applied to the device running config, described in 3.1.1.4.1 JsonChange. |
outputs | None | |
errors | malformedChangeError | Will be raised if the input JsonChange is not valid according to 3.1.1.4.1 JsonChange. |
resourceNotFoundError | Will be raised if running config failed to be read or in case any other external resource is not found nor available. | |
unprocessableRequestError | Will be raised if the change is valid, all the resources are found but when applying the change it causes an error in the system. | |
internalError | Will be raised if any other error is encountered that's different than the ones listed above. | |
side-effects | updating running-config | This operation will cause changes to the running-config according to the input JsonChange. |
assumptions | running-config locked | The implementor of this contract will interact with ConfigDB to updating the running-config, it is assumed the ConfigDB is locked for changes for the lifespan of the operation. |
Since the order of executing the operation does not matter, the implementor of this component can work on optimizing the time to run the operation. For details check 3.1.1.4 Change Applier.
NOTE: Check Change Applier implementation design design details in Json_Change_Application_Design document.
SONiC is managing configuration in a single source of truth - a redisDB instance that we refer as ConfigDB. Applications subscribe to ConfigDB and generate their running configuration correspondingly.
For further details on the ConfigDB, check SONiC Configuration Database Manual.
The user of the system, can simply be a human operator or a service that can talk to SONiC CLI. The user can only apply-patch if they have an admin permission.
Same as 3.1.1.2 SONiC CLI
Same as 3.1.1.3 YANG models
same as 3.1.1.5 ConfigDB
This will the file system where SONiC os is setup. Some suggestions prefer the path /var/sonic/checkpoints
, but that is not decided yet. Will leave it to the implementor of this design document to decide.
Same as 3.1.2.1 User
Same as 3.1.1.2 SONiC CLI
Same as 3.1.2.5 File system
same as 3.1.1.5 ConfigDB
Same as 3.1.2.1 User
Same as 3.1.1.2 SONiC CLI
Same as 3.1.1.3 YANG models
Same as 3.1.2.5 File system
same as 3.1.1.5 ConfigDB
The JsonPatch consistes of a list operation, and each operation follows this format:
{ "op": "<Operation-Code>", "path": "<Path>", "value": "<Value>", "from": "<From-Path>" }
For detailed information about the JSON patch operations refer to the section 4(Operations) of RFC 6902.
Operation Code
- replace - Set ConfigDB entry described in Path to be equal to the data specified in Value
- add - Create a new ConfigDB entry described in Path and set it Value
- remove - Delete the ConfigDB entry described in Path
- copy - Copy the ConfigDB entry specified in the FromPath to create a ConfigDB entry specified in Path
- move - Copy the ConfigDB entry specified in the FromPath to create a ConfigDB entry specified in Path and then delete the ConfigDB entry in FromPath
Path
Describes the location of the ConfigDB entry which is being processed. The path string can be dissected into below elements.
- Table Name - The ConfigDB table corresponding to the entry
- Key - The Key string to identify the row data within the ConfigDB table
- Field - The column_key to identify the ConfigDB entry within the identified row data
e.g "/VLAN_MEMBER/Vlan10|Ethernet0/tagging_mode"
- Table: VLAN_MEMBER
- Key: Vlan10|Ethernet0
- Field: tagging_mode
FromPath
- Same as Path used in copy and move operations
Value
- Data that is used to patch the ConfigDB entry specified in path
apply-patch Command Format
config apply-patch <patch-filename> [--dry-run] [--verbose]
Command Option | Purpose |
---|---|
<patch-filename> | The file of the JsonPatch file to apply which follows JSON Patch (RFC6902) specifications |
dry-run | Displays the generates commands going to be executed without running them. |
verbose | Provide additional details about each step executed as part of the operation. |
Command Usage
Command | Purpose |
---|---|
config apply-patch filename | Applies the given JsonPatch file operations following the JSON Patch (RFC6902) specifications. |
config apply-patch filename --dry-run | Displays the generates commands going to be executed without running them. |
config apply-patch filename --verbose | Applies the given JsonPatch file operations following the JSON Patch (RFC6902) specifications. The CLI output will include additional details about each step executed as part of the operation. |
config apply-patch filename --dry-run --verbose | Displays the generates commands going to be executed without running them. The CLI output will include additional details about each step executed as part of the operation. |
checkpoint
Command Format
config checkpoint <checkpoint-name> [--dry-run] [--verbose]
Command Option | Purpose |
---|---|
<checkpoint-name> | The name of the checkpoint where ConfigDB JSON config will saved under. |
dry-run | Displays the generates commands going to be executed without running them. |
verbose | Provide additional details about each step executed as part of the operation. |
Command Usage
Command | Purpose |
---|---|
config checkpoint checkpoint-name | Will save ConfigDB JSON config as a checkpoint with the name checkpoint-name. |
config checkpoint filename --dry-run | Displays the generates commands going to be executed without running them. |
config checkpoint filename --verbose | Will save ConfigDB JSON config as a checkpoint with the name checkpoint-name. The CLI output will include additional details about each step executed as part of the operation. |
config checkpoint filename --dry-run --verbose | Displays the generates commands going to be executed without running them. The CLI output will include additional details about each step executed as part of the operation. |
checkpoint
Command Format
config rollback <checkpoint-name> [--dry-run] [--verbose]
Command Option | Purpose |
---|---|
<checkpoint-name> | The name of the checkpoint where ConfigDB JSON config will saved under |
dry-run | Displays the generates commands going to be executed without running them. |
verbose | Provide additional details about each step executed as part of the operation. |
Command Usage
Command | Purpose |
---|---|
config rollback checkpoint-name | Rolls back the ConfigDB JSON config to the config saved under checkpoint-name checkpoint. |
config rollback filename --dry-run | Displays the generates commands going to be executed without running them. |
config rollback filename --verbose | Rolls back the ConfigDB JSON config to the config saved under checkpoint-name checkpoint. The CLI output will include additional details about each step executed as part of the operation. |
config rollback filename --dry-run --verbose | Displays the generates commands going to be executed without running them. The CLI output will include additional details about each step executed as part of the operation. |
apply-patch Command Format
show apply-patch log [exec | verify | status]
Command | Purpose |
---|---|
show apply-patch log exec | Displays a log of all the ConfigDB operations executed including those that failed. In case of a failed operation, it displays an error message against the failed operation. |
show apply-patch log verify | Displays a log all the ConfigDB operations that failed, along with an error message. It does not display the operations that were successful. |
show apply-patch log status | Displays the status of last successful patch application operation since switch reboot. |
rollback Command Format
show rollback log [exec | verify | status]
Command | Purpose |
---|---|
show rollback log exec | Displays a log of all the ConfigDB operations executed including those that failed. In case of a failed operation, it displays an error message against the failed operation. |
show rollback log verify | Displays a log all the ConfigDB operations that failed, along with an error message. It does not display the operations that were successful. |
show rollback log status | Displays the status of last successful config rollback operation since switch reboot. |
Use the verbose option to view additional details while executing the different commands.
If an error is encountered during executing any of the commands, the error is reported to the user. The system does not do any recovery actions, and leaves it up to the user to decide.
All commands logs are stored in systemd-journal and syslog.
N/A
N/A
Test Case | Description |
---|---|
1 | Add a new table. |
2 | Remove an existing table. |
3 | Modify values of an existing table entry. |
4 | Modify value of an existing item an array value. |
5 | Add a new item to an array value. |
6 | Remove an item form an array value. |
7 | Add a new key to an existing table . |
8 | Remove a key from an existing table. |
9 | Remove 2 items that depends on each other but in different tables e.g. /PORT/Ethernet2 and /VLAN_MEMBER/Vlan101 |
10 | Add 2 items that depends on each other but in different tables e.g. /PORT/Ethernet2 and /VLAN_MEMBER/Vlan101 |
11 | Remove 2 items that depends on each other in the same table e.g. /INTERFACE/INTERFACE_LIST and /INTERFACE/INTERFACE_PREFIX_LIST. |
12 | Add 2 items that depends on each other in the same table e.g. /INTERFACE/INTERFACE_LIST and /INTERFACE/INTERFACE_PREFIX_LIST. |
13 | Replace a mandatory item e.g. type under ACL_TABLE. |
14 | Dynamic port breakout as described here. |
15 | Remove an item that has a default value. |
16 | Modifying items that rely depends on each other based on a must condition rather than direct connection such as leafref e.g. /CRM/acl_counter_high_threshold (check here). |
17 | Updating Syslog configs. |
18 | Updating AAA configs. |
19 | Updating DHCP configs. |
20 | Updating IPv6 configs. |
21 | Updating monitor configs (EverflowAlaysOn). |
22 | Updating BGP speaker configs. |
23 | Updating BGP listener configs. |
24 | Updating Bounce Back Routing configs. |
25 | Updating control-plane ACLs (NTP, SNMP, SSH) configs. |
26 | Updating Ethernet interfaces configs. |
27 | Updating VLAN interfaces configs. |
28 | Updating port-channel interfaces configs. |
29 | Updating loopback interfaces configs. |
30 | Updating BGP prefix hijack configs. |
Test Case | Description |
---|---|
1 | Invalid Configs according to YANG models should fail to be saved. |
2 | Saving ConfigDB successfully to a file. |
Test Case | Description |
---|---|
1 ..* | Rollback all unit-tests specified in 9.1 Unit Tests for Apply-Patch. |
Test Case | Description |
---|---|
1 ..* | Use replace instead of apply-patch for unit-tests specified in 9.1 Unit Tests for Apply-Patch. |