The MySQL Shell 8.0.17 introduces a novel way of extending its base functionality through plugins, which are JavaScript or Python scripts that allow the user to:
- Register reports that can be used in monitoring tasks through the \show and \watch Shell Commands.
- Create and register new global objects with custom functionality defined by the user.
The Plugin Structure
At its simplest form, a plugin is just a folder containing a plugin registration file which will be executed by the Shell when it starts.
The plugin registration file is a file named init.js for JavaScript plugins and init.py for Python plugins (Will call it the init file for the rest of this blog post).
The plugins are automatically loaded when the Shell starts, for this, the plugin folder must be located at the plugins folder of the user configuration path:
- Windows: %appdata%/MySQL/mysqlsh/plugins
- Others: ~/.mysqlsh/plugins
When the Shell starts, it will traverse the content of the plugins directory identifying all the folders that contain an init file. Such init files are the plugins that will be loaded. Once all the plugins are identified, it will start loading them by executing the init files in the corresponding language context.
Extending the Shell with Plugins
The shell global object contains the following functions that can be used to extend the shell functionality by registering user-defined reports or extension objects:
- shell.registerReport(name, type, report[, description]): registers a user-defined report.
- shell.createExtensionObject(): creates an extension object (that later can be registered as a global object).
- shell.addExtensionObjectMember(object, name, member[,definition]): adds a new member into an extension object.
- shell.registerGlobal(name, object[, definition]): registers an extension object as a shell global object.
When the init files are executed, some of the Shell global objects are available out of the box, this is, they can be used right away on the init file. These objects include:
- The shell object.
- The dba object.
- The mysql module.
- The mysqlx module.
By using the functions of the shell object listed above is how the init file can extend the Shell functionality.
Adding a report using a Shell plugin
The reporting feature is available since 8.0.16. On this section, we will create a simple report to monitor the status of an InnoDB cluster.
The .mysqlsh/plugins/monitor/init.js file contains the following:
A backend function that will return the cluster object associated to a given session:
1
2
3
4
5
6
7
8
9
10
11
|
function get_cluster(session, context) { if (session) { try { return dba.getCluster(); } catch (err) { throw "A session to a cluster instance is required: " + err.message } } else { throw "A session must be established to execute this " + context } } |
The report backend function in native JavaScript which produces the cluster status report when the global session is established to a cluster member:
1
2
3
4
5
6
7
8
9
10
11
12
|
// The report backend function in native JavaScript which will be // used to generate the cluster status report. function cluster_status(session, argv, options) { // Gets the cluster using the backend function above var cluster = get_cluster(session, "report") // Prints the Cluster status println(cluster.status()) // A report must return a list always return {report:[]} } |
The registration of the function above as a report, to make it usable with the \show and \watch Shell commands:
1
2
|
shell.registerReport("idc_status", "print", cluster_status, {brief: "Monitors the status of the cluster where the global session is connected"}) |
When the Shell is started, the plugin will be loaded and the new status report will be available for execution with the \show and \watch commands:
Adding a new global object using a Shell plugin
Extending the Shell base functionality becomes easy through the Shell extension objects. In general, the process of extending the shell includes:
- Creating the extension object.
- Adding functionality to the extension object.
- Registering the extension object.
When working with InnoDB Cluster we have the cluster object which already provides lots of features, examples of these features include the describe() and satus() functions. Lets say we want to addres a specific use case and we need a function that retrieves the list of members of the InnoDB Cluster.
Let’s define a new object called idc which will work with the InnoDB cluster associated to the global session and will have a function getMembers which will return the list of the cluster members without any additional information.
Let’s update our existing plugin by adding the code needed to achieve our objective.
This is the backend function that will provide the functionality we want.
1
2
3
4
5
6
7
8
9
10
11
|
// Backend function to get the list of cluster members function get_members() { var cluster = get_cluster(shell.getSession(), "function"); var data = cluster.describe(); var topology = data.defaultReplicaSet.topology; var members = []; for (index in topology) { members.push(topology[index].address); } return members; } |
Now we create the extension object, add the function into it and register it as a global:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// Creates the extension object var idc = shell.createExtensionObject() // Adds the desired functionality into it shell.addExtensionObjectMember(idc, "getMembers", get_members, { brief: "Retrieves the list of members of the active cluster.", details: [ "This function will return a list containing the addresses of each cluster member.", "The information is retrieved from the cluster topology."]}); // Register the extension object as a global object shell.registerGlobal("idc", idc, { brief:"Utility functions for InnoDB Cluster."}) |
When the Shell is started, the plugin will be loaded and the new idc global object will be available and with it, the functionality that has been added into it:
Help Integration
Even the main aspect of the shell extensions is about allowing the user to integrate additional functionality into the Shell, it is important to provide documentation about it. For that reason, the three functions used to register new functionality allow defining help through the following options:
- brief: Should be a short description of the report/object/function being registered.
- details: it’s an array of strings with detailed information about the report/function/object being registered. Each string on this array will be a separate paragraph on the displayed help.
Stay Tuned!
Additional blog post will be published about this subject, including:
- MySQL Shell Plugins – Data Validation: which guides you through the different data validation options when registering functions into an extension object.
- MySQL Shell Plugins – Plugin Groups: which explains how to organize your plugins in a way that they are contained in a single global object.
- MySQL Shell Plugins – A Python Approach: which explains how to combine python modules with the MySQL Shell Plugins to create complex plugins.
Resources
For details about the MySQL Shell Plugins please take a look at the MySQL Shell User Guide.
Don’t forget to download it and give it a try, your feedback is very welcome!
You can reach us at #shell channel in https://mysqlcommunity.slack.com/