Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added doc/cli_wrapper/images/architecture.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/architecture_1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/architecture_2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/compiler_stage.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/encode_format.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/generate_wrapper_file.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/source_tree.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/test_result_arm_1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/test_result_arm_2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/watchdog_flow.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/wrapper_disable.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/cli_wrapper/images/wrapper_enable.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
213 changes: 213 additions & 0 deletions doc/cli_wrapper/shd-cli_wrapper_hld.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
# CLI wrapper

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
**Table of Contents**

- [Revision](#revision)

- [1. High Level Design Document](#1-high-level-design-document)

- [1.1. About this Manual](#11-about-this-manual)

- [1.2. Architecture](#12-architecture)

- [1.3. Design](#13-design)

- [1.3.1. Generate wrapped files](#131-generate-wrapped-files)

- [1.3.2. Command execution flow](#132-command-execution-flow)

- [1.3.3. Watchdog execution flow](#133-watchdog-execution-flow)

- [1.3.4. Encoded command format](#134-encoded-command-format)

- [1.3.5. CLI wrapper service](#135-cli-wrapper-service)

- [1.3.6. Source tree](#136-source-tree)

- [2. Performance improvements](#2-performance-improvements)

- [3. Open questions](#3-open-questions)

- [4. Reference](#4-reference)

<!-- markdown-toc end -->

## Revision

| Rev | Date | Author | Change Description |
| :--: | :--------: | :-----------------------------------: | ------------------ |
| 0.1 | 08/12/2022 | Justin Lu | 1. Initial version |
| 0.2 | 09/03/2022 | Justin Lu | 1. Add watchdog design <br> 2. Modify architecture picture |
| 0.3 | 09/22/2022 | Antonio Ho | 1. Add enable/disable design |
| 0.4 | 01/16/2023 | Antonio Ho | 1. Add performance improvements |
| 0.5 | 05/03/2023 | Antonio Ho | 1. Modify performance improvements <br> 2. Add TODO list |

# 1. High Level Design Document

## 1.1 About this Manual

This document provides the high-level design for CLI_wrapper in SONiC

## 1.2 Architecture

SONiC uses click package as its CLI engine, although click package provides developers a convenient way to establish whole CLI architecture, it also has some disadvantage. The problem we want to address here is about the bad performance of CLI execution time.

Everytime user executes a command, CLI engine will load main source file (ex. config/main.py), then starts to execute the command. In this process, all libraries always have to be imported again. It costs about 80% execution time on this process, so CLI_wrapper is designed to reduce the time.

The figure below depicts the architecture of CLI_wrapper.

![Architecture](images/architecture_1.jpg)

* CLI_wrapper builder

In order to integrate CLI_wrapper with current CLI architecture, we develop CLI_wrapper builder to generate CLI_wrapper for command source file (ex. main.py). When sonic-utilities debian is packaged, it calls CLI_wrapper builder to generate wrapped files which contains only function interface and minimal libraries. It replaces function body with the calling of CLI_wrapper client to send a encoded command to CLI_wrapper server and acquires the result. Since the CLI_wrapper only contains minimal libraries, CLI engine doesn't need a lot of time to execute.

![Architecture](images/architecture_2.jpg)

* CLI_wrapper server

CLI_wrapper server is responsible for the execution of click command. It starts when system boots up, and loads all needed libraries to server. Then setup a socket to wait client's request. Once it accepts a request, it spawns a CLI_worker process to deal with this request.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the case of warmboot/fastboot while spawning CLI wrapper server. Are there any CLI commands that are executed during the warmboot/fastboot? If not I recommend delaying the CLI wrapper server until reconciliation is complete.


In order to avoid that some command may stuck in CLI worker and cause resource leakage, a watchdog thread is designed to watch the execution time of CLI worker, once the execution time exceeds maximum execution time, the CLI worker will be gracefully terminated. But if the CLI worker is still alive after one minute, a kill signal will be sent to CLI worker to tear down it.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are config/show commands that can go beyond 1 min, hope you have a configuration to increase the timeout if required.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the show output has more than 1 page, how are you handling the pagination? can we make sure the current behavior is not disturbed with this new design?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this needs to be rephrased. If I am not mistaken the watchdog will terminate only after 10 minutes and send kill at 11th minute if there is no resposne.


The local DB is used to store the record of spawned CLI worker, it records the steady timestamp and pid of the CLI worker.
Copy link
Collaborator

@venkatmahalingam venkatmahalingam May 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this local DB is some kind of a Q?

When there are more than client, how is server handling the requests from clients at a time? How's config/show errors are being responded back to the client?


* CLI_worker

Decode the request and execute this command. Return the execution result to client and finish this process.

Everytime cli_wapper server receives a request, it spawns a process to handle this request, so no single block point may happen in this design.

* CLI_wrapper client

It is a library that can be used to interact with CLI wrapper server.

---

## 1.3 Design

This section provides design details for CLI_wrapper.

### 1.3.1 Generate wrapped files

![Generate wrapper file](images/generate_wrapper_file.jpg)

* In the step 1 and step 2, builder copies the necessary libraries to wrapped file and discard other libraries to reduce loading time

* In the step 3, builder removes the content of command function body and replaces it with CLI_wrapper client

### 1.3.2 Command execution flow

![Command execution flow](images/command_execution_flow.jpg)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change the diagram to include more than one client, also, not sure how the context for the particular command is carried end to end, please clarify.


* System ctrl bring up CLI_wrapper server when system starts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep this feature disabled by default, if we're comfortable making it enabled some point in time in the future, we can have it enabled by default.

Copy link
Collaborator

@venkatmahalingam venkatmahalingam May 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have an option to use current click commands (without wrapper) even after this feature is enabled? I just want to make sure we're not blocked because of some bug in the wrapper routines?


* Click engine imports wrapped main.py and call CLI_wrapper client to send request

* CLI_wrapper client gets command parameter and environment setting from CLI context, then encodes those information to a command string and send to CLI_wrapper server.

* CLI_wrapper server launches a CLI worker to deal with this request and write timestamp and pid to local DB

* CLI worker decodes the command to get parameters and environment setting, then execute this command based on those settings. In the end, it sends return code and data back to CLI wrapper client

### 1.3.3 Watchdog execution flow

Copy link
Collaborator

@venkatmahalingam venkatmahalingam May 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to accept optional value for each command for execution time? sometimes, it's hard to predict the execution time of the command.

![Command execution flow](images/watchdog_flow.jpg)
* Default polling time is 60 seconds, watchdog check if the pid in local DB is still running, if not, update local DB.

* Default expired time is 600 seconds (To send terminate signal) and 660 seconds (To send kill signal), watchdog check if CLI worker execution time exceeds expired time, send terminate or kill signal to recycle it.

### 1.3.4 Encoded command format

In order to send all needed information in a request, some encode processes must be applied before sending it to server.
The following picture shows two examples for encoded requests.

![Encode format](images/encode_format.jpg)

* \__wrapper_calling_cmd__: used to indicate the start of a command

* \__wrapper_env__ : used to indicate the environment setting when executing this command, separate the value by ";", this is a optional field.

### 1.3.5 CLI wrapper service

In compile stage, CLI_wrapper builder put generated wrapped file and original main.py to a backup folder.

CLI wrapper service use these backup files to enable/disable CLI_wrapper feature.

![Encode format](images/compiler_stage.jpg)

* Enable CLI wrapper service

![Encode format](images/wrapper_enable.jpg)

1. Replace main.py with wrapped main.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we enable disable at run time through a CLI?


2. Start CLI wrapper daemon

* Disable CLI wrapper service

![Encode format](images/wrapper_disable.jpg)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this done? Does a user have to manually rename the file and stop the server? A global rules flag set to "n" should take care of these steps instead of manual intervention on every switch.


1. Replace main.py with main_impl.py

2. Stop CLI wrapper daemon

### 1.3.6 Source tree

Here lists the related source tree of CLI_wrapper

![Encode format](images/source_tree.jpg)

* CLI_wrapper builder : files/build_scripts/cli_wrapper
* CLI_wrapper client : src/sonic-utilities/cli_wrapper
* CLI_wrapper server : src/sonic-utilities/cli_wrapper
* Integrate CLI wrapper builder to sonic-utilities debian: rules/sonic-utilities.mk

# 2. Performance improvements

* The following test results are made in arm platform(dual-core A53 processor):

* Executing "show vlan brief" command 20 times

- The following results are compared with and without cli_wrapper.

![Encode format](images/test_result_arm_1.jpg)

* The following is an analysis of the execution time of the "show vlan brief" command

- The following results are compared with and without cli_wrapper.

![Encode format](images/test_result_arm_2.jpg)

* Conclusion

* Cli_wrapper can improve command execution time when Python code imports more global packages.

* For less powerful CPUs, cli_wrapper can significantly reduce execution time.

# 3. Open questions
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please clarify the design around the interactive commands (yes/no).


* TODO:

* Dynamically generating wrapped files
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How will this feature work with auto CLI generation feature? Please check https://github.com/sonic-net/SONiC/blob/master/doc/cli_auto_generation/cli_auto_generation.md


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also check the interoperability with GCU feature. Since GCU loads the yang models once for every command, can we think about loading the entire yang only once and then validating?

- Why I did

- Section 1.3.5 mentions that during the compilation stage, cli_wrapper builder generates wrapped files, backs up the original files, and then packages all files into Debian.

- However, this static method of generating wrapped files has the following drawbacks:

* It is inconvenient for developers as they need to consider whether the cli_wrapper function is enabled and which files have been modified.

* Moreover, while the cli_wrapper service is starting or stopping, there is a possibility of overwriting the contents that developers have modified.

- How I did

- When the cli_wrapper service is starting, the cli_wrapper builder will generate wrapped files.

- Conversely, when the cli_wrapper service is stopping, all wrapped files will be deleted and then the main.py file will be restored.

# 4. Reference

N/A