The UBS Engine Go API is a UBS Engine management interface developed based on the Go language. It is used to schedule and manage resources and perform key service operations.

This document aims to help developers quickly master the core functions, application scenarios, and development skills of the UBS Engine Go API, provide sample code that can be directly executed, and avoid common issues.

1. Prerequisites

To use the UBS Engine Go API for development, prepare the UBS Engine development environment and install the development package by following the steps below.

1.1 Environment Requirements

  • OS: Linux
  • Go version: Go 1.21 or later
  • GCC compiler: supports CGO compilation.

1.2 Development Package Installation

# Install the development package (for integrated development).
sudo dnf install -y ubs-engine-client-libs ubs-engine-client-devel

1.3 Installation Result

File/Directory Other Information
/usr/include/ubse Permission on the header file (*.h) in the directory: 644
/usr/lib64/libubse-client.so Soft link, pointing to /usr/lib64/libubse-client.so.1
/usr/lib64/libubse-client.so.1 Soft link, pointing to libubse-client.so.xx.xx.xx
/usr/lib64/libubse-client.so.xx.xx.xx Binary dynamic library
/usr/lib64/libubse-client.a Binary static library

1.4 Go Module Dependencies

In a Go project, you need to import the following modules:

import (
    "atomgit.com/openeuler/ubs-engine.git/src/sdk/go/engine"
    "atomgit.com/openeuler/ubs-engine.git/src/sdk/go/log"
    "atomgit.com/openeuler/ubs-engine.git/src/sdk/go/mem"
    "atomgit.com/openeuler/ubs-engine.git/src/sdk/go/topo"
)

2. Using the UBS Engine Go API: Topology Query as an Example

Topology query is a common scenario of the UBS Engine service. Cluster resources can be scheduled and managed by querying node and connection information.

2.1 Implementation Logic Overview

The implementation of topology query can be divided into the following four main steps:

  • Initialize the client: Use engine.UbsEngineClientInitialize to initialize the client connection.

  • Register log callback: Use log.UbsEngineLogCallbackRegister to register the log callback function for debugging and monitoring.

  • Query topology information: Use topo.UbsTopoNodeList to query information about all nodes, topo.UbsTopoNodeLocalGet to query information about the local node, and topo.UbsTopoLinkList to query information about all connections.

  • Clear resources: Use engine.UbsEngineClientFinalize to clear client resources after fter the operation is complete.

2.2 Implementation Code

The example.go file provides the implementation code for topology query. You can refer to this code to implement the topology query process.

2.3 Expected Output

Initialize result: 0
====== Start to query all node information. ======
[log_example][INFO][ubse_uds_client.cpp:Connect:90] Connection successful
[log_example][INFO][ubse_ipc_client.cpp:ubse_invoke_call:98] Sending request, module_code=3, op_code=1
[log_example][INFO][ubse_uds_client.cpp:Send:178] Starting Send operation with timeout: 1800000ms
[log_example][INFO][ubse_uds_client.cpp:Send:212] Waiting for response...
[log_example][INFO][ubse_uds_client.cpp:Receive:271] Starting Receive operation with remaining time: 1800000ms
[log_example][INFO][ubse_uds_client.cpp:Receive:321] Receive operation completed successfully
[log_example][INFO][ubse_ipc_client.cpp:ubse_invoke_call:105] Sending request successfully, module_code=3, op_code=1
Information about two nodes is obtained.

=== Node information [0] ===
Slot ID (SlotId): 2
Host name (HostName): node01
Socket ID: Socket[0]=36 Socket[1]=236
NUMA IDs:
Socket[0]: NUMA[0]=0 NUMA[1]=4294967295 NUMA[2]=4294967295 NUMA[3]=4294967295
Socket[1]: NUMA[0]=1 NUMA[1]=4294967295 NUMA[2]=4294967295 NUMA[3]=4294967295
IP address list (three IP addresses):
IP[0]: 192.168.122.1
IP[1]: 192.168.1.11
IP[2]: 192.168.100.101

=== Node information [1] ===
Slot ID (SlotId): 1
Host name (HostName): controller
Socket ID: Socket[0]=236 Socket[1]=36
NUMA IDs:
Socket[0]: NUMA[0]=1 NUMA[1]=4294967295 NUMA[2]=4294967295 NUMA[3]=4294967295
Socket[1]: NUMA[0]=0 NUMA[1]=4294967295 NUMA[2]=4294967295 NUMA[3]=4294967295
IP address list (three IP addresses):
IP[0]: 192.168.122.1
IP[1]: 192.168.1.10
IP[2]: 192.168.100.100

====== Full node information query is complete. ======

====== Start to query local node information. ======
[log_example][INFO][ubse_uds_client.cpp:Connect:90] Connection successful
[log_example][INFO][ubse_ipc_client.cpp:ubse_invoke_call:98] Sending request, module_code=3, op_code=4
[log_example][INFO][ubse_uds_client.cpp:Send:178] Starting Send operation with timeout: 1800000ms
[log_example][INFO][ubse_uds_client.cpp:Send:212] Waiting for response...
[log_example][INFO][ubse_uds_client.cpp:Receive:271] Starting Receive operation with remaining time: 1800000ms
[log_example][INFO][ubse_uds_client.cpp:Receive:321] Receive operation completed successfully
[log_example][INFO][ubse_ipc_client.cpp:ubse_invoke_call:105] Sending request successfully, module_code=3, op_code=4
Information about the local node is obtained.
=== Node information [0] ===
Slot ID (SlotId): 1
Host name (HostName): controller
Socket ID: Socket[0]=236 Socket[1]=36
NUMA IDs:
Socket[0]: NUMA[0]=1 NUMA[1]=4294967295 NUMA[2]=4294967295 NUMA[3]=4294967295
Socket[1]: NUMA[0]=0 NUMA[1]=4294967295 NUMA[2]=4294967295 NUMA[3]=4294967295
IP address list (three IP addresses):
IP[0]: 192.168.122.1
IP[1]: 192.168.1.10
IP[2]: 192.168.100.100

====== Local node information query is complete. ======

====== Start to query all connection information. ======
[log_example][INFO][ubse_uds_client.cpp:Connect:90] Connection successful
[log_example][INFO][ubse_ipc_client.cpp:ubse_invoke_call:98] Sending request, module_code=3, op_code=2
[log_example][INFO][ubse_uds_client.cpp:Send:178] Starting Send operation with timeout: 1800000ms
[log_example][INFO][ubse_uds_client.cpp:Send:212] Waiting for response...
[log_example][INFO][ubse_uds_client.cpp:Receive:271] Starting Receive operation with remaining time: 1800000ms
[log_example][INFO][ubse_uds_client.cpp:Receive:321] Receive operation completed successfully
[log_example][INFO][ubse_ipc_client.cpp:ubse_invoke_call:105] Sending request successfully, module_code=3, op_code=2
Link: 0
SlotId=1, SocketId=36, PortId=1
PeerSlotId=2, PeerSocketId=36, PeerPortId=1
Link: 1
SlotId=1, SocketId=236, PortId=1
PeerSlotId=2, PeerSocketId=236, PeerPortId=1
====== Full connection information query is complete. ======

3. Using the UBS Engine Go API: NUMA Memory Query as an Example

NUMA memory query is another common scenario of the UBS Engine service. Memory resources can be managed by querying the remote memory information in NUMA topology.

3.1 Implementation Logic Overview

The implementation of NUMA memory query can be divided into the following four main steps:

  • Initialize the client: Use engine.UbsEngineClientInitialize to initialize the client connection.

  • Query NUMA memory: Use mem.UbsMemNumaList to query all remote NUMA memory on the local node.

  • Process the query result: Parse the returned memory description, including the borrow identifier, NUMA ID, borrow size, and lending/borrowing node information.

  • Clear resources: Use engine.UbsEngineClientFinalize to clear client resources after fter the operation is complete.

3.2 Implementation Code

The example.go file provides the implementation code for NUMA memory query. You can refer to this code to implement the memory query process.

3.3 Expected Output

# Example of the expected output
====== Start to query all NUMA memory information.======
[log_example][INFO][ubse_uds_client.cpp:Connect:90] Connection successful
[log_example][INFO][ubse_ipc_client.cpp:ubse_invoke_call:98] Sending request, module_code=1, op_code=20
[log_example][INFO][ubse_uds_client.cpp:Send:178] Starting Send operation with timeout: 1800000ms
[log_example][INFO][ubse_uds_client.cpp:Send:212] Waiting for response...
[log_example][INFO][ubse_uds_client.cpp:Receive:271] Starting Receive operation with remaining time: 1800000ms
[log_example][INFO][ubse_uds_client.cpp:Receive:321] Receive operation completed successfully
[log_example][INFO][ubse_ipc_client.cpp:ubse_invoke_call:105] Sending request successfully, module_code=1, op_code=20
No NUMA memory description is obtained.
====== Full NUMA memory information query is complete. ======
Client finalized successfully

4. Running Example

4.1 Preparing the Service Environment

Environment requirements

  • OS: openEuler 24.03 LTS or later
  • CPU architecture: AArch64
  • Memory: ≥ 64 GB
  • Disk: SSD, throughput 500 MB/s (IOPS)
  • Chip interconnection: UB
  • NIC: optional dependency (TCP can be used to assist UB in link establishment. By default, UB bootstrap is used for link establishment.)
  • User permission: The root permission is required for installation and management.

For more requirements, see Deployment Description.

Install the RPM package. (The ubs-engine main package must be installed on all cluster nodes.)

# Install the main program package.
sudo dnf install -y ubs-engine

# Install the client runtime library (mandatory for third-party integration).
sudo dnf install -y ubs-engine-client-libs

Start the UBS Engine service on each node.

By default, secure communication is enabled for UBS Engine. Ensure that the certificate is successfully imported. Otherwise, the cluster status may be abnormal. For details about how to import the certificate, see ubsectl_cert. Alternatively, you can modify the /etc/ubse/ubse.conf configuration file and set cert.use to false to disable secure communication.

sudo systemctl start ubse
# Check the service process status.
$ ps -ef | grep ubse
--------------------------------------------------------------------------
ubse       64120       1 99 15:14 ?        00:18:18 /usr/bin/ubse
root     2182344 2181443  0 15:52 pts/3    00:00:00 grep --color=auto ubse

Wait for about 1 minute and check whether the nodes are started and active and standby clusters are successfully selected.

sudo ubsectl display cluster
# Expected output example (two-node environment)
-------------------------------------------------------------------------------------------------------------
  node            role      bonding-eid                               guid
-------------------------------------------------------------------------------------------------------------
  controller(1)   master    4245:4944:0000:0000:0000:0000:0100:0000   CC08-A000-0-0-000000-0000000800010000
                                                                     
  node01(2)       standby   4245:4944:0000:0000:0000:0000:0200:0000   CC08-A000-0-0-000000-0000000801000000
-------------------------------------------------------------------------------------------------------------

4.2 Building a Sample Program

Ensure that your Go version is 1.21 or later and CGO is enabled.

Build the sample program in the example/go directory.

cd example/go
go mod tidy
go build -o example example.go

After the compilation is complete, the executable file example is generated in the current directory. You need to manually transfer the executable file to the service runtime environment and modify the file permission based on service requirements.

4.3 Running the Sample Program

4.3.1 Configuring the Client Program

For details about the UBSE authentication mechanism, see UBSE Role-based Access Control Design. The user who delivers the configuration must have the root permission. Assume that the user who uses the UBSE API is test_user.

  1. Add test_user to the UBSE user group.

    sudo usermod -aG ubse test_user
    
  2. Create a custom permission configuration file for the client.

    sudo touch /etc/ubse/auth_test_api.conf
    
  3. Edit the custom permission configuration file for the client.

    sudo vi /etc/ubse/auth_test_api.conf
    

    Press the i key to enter insert mode and copy the following content into the file:

    # Authentication configuration file
    # Defines base user-role and role-permission mappings with priority flags.
    
    [auth.user]
    # Section for user-to-role mappings.
    test_user=test
    
    [auth.role]
    # Section for role-to-permission mappings.
    test=mem.numa,mem.shm,topo
    

    Press Esc to exit insert mode, type :wq, and press Enter to save and exit the editor.

  4. Restart the UBSE service for the configuration to take effect.

sudo systemctl restart ubse

4.3.2 Running the Client Program

# Run the sample program.
./example

4.4 Precautions

  • Required permissions

    • User permissions: The ubsectl command can be used only by the root user and the UBSE user automatically created during installation. The API can be used only by the root user, the UBSE user automatically created during installation, and custom users added to the UBSE group. If the API is used by a custom user added to the UBSE group, a custom permission configuration file for the client needs to be configured.
  • Startup exception analysis

    • Node query error: If the error message is ERROR: Failed to obtain cluster information, the current node has not been started or the startup is abnormal. You can query the service process status. If the process exists, the node is still being started. Try again later.

    • Incomplete active/standby node information: If the queried node is the active node and the standby node status is empty, the current node has not been added to the cluster. You are advised to check whether the communication between nodes is normal.

  • CGO dependencies

    • The UBS Engine Go API uses CGO to call the C library. Ensure that the GCC compiler and related C development libraries have been installed in the system.
  • Resource management

    • You must call engine.UbsEngineClientFinalize() to clean up resources before the program exits. You are advised to use the defer statement to ensure that resources are released.