1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
package client
import (
"fmt"
"reflect"
"github.com/google/uuid"
"github.com/ovn-kubernetes/libovsdb/model"
"github.com/ovn-kubernetes/libovsdb/ovsdb"
)
const emptyUUID = "00000000-0000-0000-0000-000000000000"
// Monitor represents a monitor
type Monitor struct {
Method string
Tables []TableMonitor
Errors []error
LastTransactionID string
}
// newMonitor creates a new *Monitor with default values
func newMonitor() *Monitor {
return &Monitor{
Method: ovsdb.ConditionalMonitorSinceRPC,
Errors: make([]error, 0),
LastTransactionID: emptyUUID,
}
}
// NewMonitor creates a new Monitor with the provided options
func (o *ovsdbClient) NewMonitor(opts ...MonitorOption) *Monitor {
m := newMonitor()
for _, opt := range opts {
err := opt(o, m)
if err != nil {
m.Errors = append(m.Errors, err)
}
}
return m
}
// MonitorOption adds Tables to a Monitor
type MonitorOption func(o *ovsdbClient, m *Monitor) error
// MonitorCookie is the struct we pass to correlate from updates back to their
// originating Monitor request.
type MonitorCookie struct {
DatabaseName string `json:"databaseName"`
ID string `json:"id"`
}
func newMonitorCookie(dbName string) MonitorCookie {
return MonitorCookie{
DatabaseName: dbName,
ID: uuid.NewString(),
}
}
// TableMonitor is a table to be monitored
type TableMonitor struct {
// Table is the table to be monitored
Table string
// Conditions are the conditions under which the table should be monitored
Conditions []ovsdb.Condition
// Fields are the fields in the model to monitor
// If none are supplied, all fields will be used
Fields []string
}
func newTableMonitor(o *ovsdbClient, m model.Model, conditions []model.Condition, fields []any) (*TableMonitor, error) {
dbModel := o.primaryDB().model
tableName := dbModel.FindTable(reflect.TypeOf(m))
if tableName == "" {
return nil, fmt.Errorf("object of type %s is not part of the ClientDBModel", reflect.TypeOf(m))
}
var columns []string
var ovsdbConds []ovsdb.Condition
if len(fields) == 0 && len(conditions) == 0 {
return &TableMonitor{
Table: tableName,
Conditions: ovsdbConds,
Fields: columns,
}, nil
}
data, err := dbModel.NewModelInfo(m)
if err != nil {
return nil, fmt.Errorf("unable to obtain info from model %v: %v", m, err)
}
for _, f := range fields {
column, err := data.ColumnByPtr(f)
if err != nil {
return nil, fmt.Errorf("unable to obtain column from model %v: %v", data, err)
}
columns = append(columns, column)
}
db := o.databases[o.primaryDBName]
mmapper := db.model.Mapper
for _, modelCond := range conditions {
ovsdbCond, err := mmapper.NewCondition(data, modelCond.Field, modelCond.Function, modelCond.Value)
if err != nil {
return nil, fmt.Errorf("unable to convert condition %v: %v", modelCond, err)
}
ovsdbConds = append(ovsdbConds, *ovsdbCond)
}
return &TableMonitor{
Table: tableName,
Conditions: ovsdbConds,
Fields: columns,
}, nil
}
func WithTable(m model.Model, fields ...any) MonitorOption {
return func(o *ovsdbClient, monitor *Monitor) error {
tableMonitor, err := newTableMonitor(o, m, []model.Condition{}, fields)
if err != nil {
return err
}
monitor.Tables = append(monitor.Tables, *tableMonitor)
return nil
}
}
func WithConditionalTable(m model.Model, conditions []model.Condition, fields ...any) MonitorOption {
return func(o *ovsdbClient, monitor *Monitor) error {
tableMonitor, err := newTableMonitor(o, m, conditions, fields)
if err != nil {
return err
}
monitor.Tables = append(monitor.Tables, *tableMonitor)
return nil
}
}
|