In the previous chapter, Feature Control, we explored how to enable or disable specific features for devices based on their context and predefined rules. Now, we will delve into Database Operations, a critical abstraction that enables the xconfwebconfig application to interact with its database for storing, retrieving, and managing data such as metrics, status tracking, and precook data.
The Database Operations abstraction provides the foundation for managing data persistence and retrieval in xconfwebconfig. It ensures that critical data, such as penetration metrics, configuration data, and process statuses, are stored reliably in the database and can be queried efficiently. The abstraction simplifies complex database interactions into reusable methods, allowing other components of the application to focus on their core logic instead of worrying about database-related concerns.
Consider a scenario where you need to store penetration metrics for a device. These metrics include information such as the device's MAC address, model, firmware version, and the time the firmware was applied. For example:
- A penetration metric must be stored in the database whenever a device updates its firmware.
- The stored metrics can later be retrieved for analysis or troubleshooting.
The Database Operations abstraction provides methods to handle such use cases, including:
- Writing data to the database (e.g., penetration metrics, configuration data).
- Reading data from the database (e.g., retrieving metrics for a specific device).
- Managing status tracking for long-running processes.
The Cassandra Client is the core component responsible for interacting with the Cassandra database. It provides methods to:
- Initialize a connection to the database.
- Execute queries for reading and writing data.
- Manage concurrent database operations through a query queue.
client := db.CassandraClient{
DeviceKeyspace: "odp",
TestOnly: false,
}In this example:
DeviceKeyspace: Specifies the keyspace (logical database) to be used.TestOnly: Indicates whether the client is running in test mode.
Penetration Metrics are records that store detailed information about a device's firmware status and related data. These metrics include:
- EstbMac: The device's MAC address.
- FwVersion: The firmware version applied.
- FwAppliedRule: The rule that determined the firmware update.
- FwTs: The timestamp of the firmware update.
{
"EstbMac": "AA:BB:CC:DD:EE:FF",
"FwVersion": "2.0.1",
"FwAppliedRule": "FirmwareRule123",
"FwTs": 1696528200000
}Precook Data refers to precomputed data that is stored in the database for efficient retrieval. This data is typically used by other components of the application to avoid recomputation.
Recooking Status tracks the progress of long-running processes, such as data recooking. It includes:
- Partition ID: The ID of the data partition being processed.
- State: The current state of the process (e.g.,
Initialized,Pending,Complete). - Updated Time: The last time the status was updated.
{
"PartitionId": "Partition001",
"State": 2,
"UpdatedTime": 1696528200000
}To interact with the database, initialize the Cassandra Client.
client := db.CassandraClient{
DeviceKeyspace: "odp",
TestOnly: false,
}- DeviceKeyspace: Specifies the keyspace for device data.
- TestOnly: Indicates whether the client should use test keyspaces.
Use the SetPenetrationMetrics method to store penetration metrics for a device.
metrics := &db.PenetrationMetrics{
EstbMac: "AA:BB:CC:DD:EE:FF",
FwVersion: "2.0.1",
FwAppliedRule: "FirmwareRule123",
FwTs: time.Now(),
}
err := client.SetPenetrationMetrics(metrics)
if err != nil {
log.Fatalf("Failed to store penetration metrics: %v", err)
}- Input: A
PenetrationMetricsobject containing the metrics to be stored. - Action: The metrics are written to the database.
Use the GetPenetrationMetrics method to retrieve penetration metrics for a specific device.
metrics, err := client.GetPenetrationMetrics("AA:BB:CC:DD:EE:FF")
if err != nil {
log.Fatalf("Failed to retrieve penetration metrics: %v", err)
}
fmt.Printf("Firmware Version: %s\n", metrics["FwVersion"])- Input: The MAC address of the device.
- Output: A map containing the penetration metrics.
To update the recooking status, use the SetRecookingStatus method.
err := client.SetRecookingStatus("ModuleA", "Partition001", 1)
if err != nil {
log.Fatalf("Failed to update recooking status: %v", err)
}- Input: The module name, partition ID, and state.
- Action: Updates the recooking status in the database.
The following sequence diagram illustrates the process of storing penetration metrics:
sequenceDiagram
participant App as Application
participant Client as CassandraClient
participant DB as Cassandra Database
App->>Client: SetPenetrationMetrics()
Client->>DB: Insert metrics into table
DB-->>Client: Acknowledge insert
Client-->>App: Return success
The SetPenetrationMetrics method inserts penetration metrics into the database.
File: db/cassandra_client.go
func (c *CassandraClient) SetPenetrationMetrics(pMetrics *PenetrationMetrics) error {
stmt := `INSERT INTO PenetrationMetrics (estb_mac, fw_version, fw_applied_rule, fw_ts) VALUES (?, ?, ?, ?)`
err := c.Query(stmt, pMetrics.EstbMac, pMetrics.FwVersion, pMetrics.FwAppliedRule, pMetrics.FwTs).Exec()
return err
}- Query: Constructs an
INSERTquery to store the metrics. - Exec: Executes the query.
The GetPenetrationMetrics method retrieves metrics for a specific device.
File: db/cassandra_client.go
func (c *CassandraClient) GetPenetrationMetrics(estbMac string) (map[string]interface{}, error) {
dict := make(map[string]interface{})
stmt := `SELECT * FROM PenetrationMetrics WHERE estb_mac = ?`
err := c.Query(stmt, estbMac).MapScan(dict)
return dict, err
}- Query: Constructs a
SELECTquery to retrieve the metrics. - MapScan: Maps the result to a dictionary.
The SetRecookingStatus method updates the status of a recooking process.
File: db/recooking_status_client.go
func (c *CassandraClient) SetRecookingStatus(moduleName string, partitionId string, state int) error {
stmt := `INSERT INTO RecookingStatus (module, partition_id, state, updated_time) VALUES (?, ?, ?, ?)`
updatedTime := time.Now()
return c.Query(stmt, moduleName, partitionId, state, updatedTime).Exec()
}- Query: Constructs an
INSERTquery to update the recooking status. - Exec: Executes the query.
- Use Keyspaces Appropriately: Ensure that data is stored in the correct keyspace to avoid cross-environment conflicts.
- Handle Errors Gracefully: Always check for errors when interacting with the database.
- Optimize Queries: Use efficient queries to minimize database load.
In this chapter, we explored Database Operations, the abstraction responsible for managing database interactions in xconfwebconfig. We learned how to use the Cassandra Client to store and retrieve data such as penetration metrics and recooking statuses. Additionally, we examined the internal implementation of these operations to understand how they work under the hood.
In the next chapter, Cassandra Database Schema Management, we will explore how the database schema is designed and maintained for xconfwebconfig.
Generated by AI Codebase Knowledge Builder