2026-04-06 15:48:37 +05:30
|
|
|
// Copyright IBM Corp. 2020, 2026
|
2023-02-02 17:15:17 -08:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2022-06-20 18:20:17 -07:00
|
|
|
package server
|
2022-05-23 09:07:30 -07:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2025-03-26 14:54:02 -05:00
|
|
|
"database/sql"
|
2022-05-23 09:07:30 -07:00
|
|
|
"fmt"
|
|
|
|
|
|
2026-10-12 10:33:41 -07:00
|
|
|
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/db"
|
|
|
|
|
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/errors"
|
2022-05-23 09:07:30 -07:00
|
|
|
)
|
|
|
|
|
|
2025-03-18 12:30:38 -05:00
|
|
|
func (r *Repository) ListControllers(ctx context.Context, opt ...Option) ([]*Controller, error) {
|
2022-05-23 09:07:30 -07:00
|
|
|
return r.listControllersWithReader(ctx, r.reader, opt...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// listControllersWithReader will return a listing of resources and honor the
|
|
|
|
|
// WithLimit option or the repo defaultLimit. It accepts a reader, allowing it
|
|
|
|
|
// to be used within a transaction or without.
|
2025-03-18 12:30:38 -05:00
|
|
|
func (r *Repository) listControllersWithReader(ctx context.Context, reader db.Reader, opt ...Option) ([]*Controller, error) {
|
2022-09-02 14:32:41 -04:00
|
|
|
opts := GetOpts(opt...)
|
2022-05-23 09:07:30 -07:00
|
|
|
liveness := opts.withLiveness
|
|
|
|
|
if liveness == 0 {
|
|
|
|
|
liveness = DefaultLiveness
|
|
|
|
|
}
|
|
|
|
|
var where string
|
|
|
|
|
if liveness > 0 {
|
|
|
|
|
where = fmt.Sprintf("update_time > now() - interval '%d seconds'", uint32(liveness.Seconds()))
|
|
|
|
|
}
|
2025-03-18 12:30:38 -05:00
|
|
|
var controllers []*Controller
|
2022-05-23 09:07:30 -07:00
|
|
|
if err := reader.SearchWhere(
|
|
|
|
|
ctx,
|
|
|
|
|
&controllers,
|
|
|
|
|
where,
|
2022-10-25 18:29:38 -05:00
|
|
|
[]any{},
|
2022-05-23 09:07:30 -07:00
|
|
|
db.WithLimit(-1),
|
|
|
|
|
); err != nil {
|
|
|
|
|
return nil, errors.Wrap(ctx, err, "workers.listControllersWithReader")
|
|
|
|
|
}
|
|
|
|
|
return controllers, nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-18 12:30:38 -05:00
|
|
|
func (r *Repository) UpsertController(ctx context.Context, controller *Controller) (int, error) {
|
2024-10-23 08:42:36 -04:00
|
|
|
const op = "server.(Repository).UpsertController"
|
2022-05-23 09:07:30 -07:00
|
|
|
if controller == nil {
|
|
|
|
|
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "controller is nil")
|
|
|
|
|
}
|
|
|
|
|
var rowsUpdated int64
|
|
|
|
|
_, err := r.writer.DoTx(
|
|
|
|
|
ctx,
|
|
|
|
|
db.StdRetryCnt,
|
|
|
|
|
db.ExpBackoff{},
|
|
|
|
|
func(read db.Reader, w db.Writer) error {
|
|
|
|
|
var err error
|
|
|
|
|
onConflict := &db.OnConflict{
|
|
|
|
|
Target: db.Columns{"private_id"},
|
2022-10-25 18:29:38 -05:00
|
|
|
Action: append(db.SetColumns([]string{"description", "address"}), db.SetColumnValues(map[string]any{"update_time": "now()"})...),
|
2022-05-23 09:07:30 -07:00
|
|
|
}
|
|
|
|
|
err = w.Create(ctx, controller, db.WithOnConflict(onConflict), db.WithReturnRowsAffected(&rowsUpdated))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(ctx, err, op+":Upsert")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return db.NoRowsAffected, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return int(rowsUpdated), nil
|
|
|
|
|
}
|
2025-03-26 14:54:02 -05:00
|
|
|
|
|
|
|
|
// UpdateControllerStatus updates the controller's status in the repository.
|
|
|
|
|
// This includes updating the address or description of the controller as well
|
|
|
|
|
// as updating the update_time attribute, which is required for liveness checks
|
|
|
|
|
// as part of a controller's status ticking.
|
|
|
|
|
func (r *Repository) UpdateControllerStatus(ctx context.Context, controller *Controller) (int, error) {
|
|
|
|
|
const op = "server.(Repository).UpdateControllerStatus"
|
|
|
|
|
|
|
|
|
|
if controller == nil {
|
|
|
|
|
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "controller is nil")
|
|
|
|
|
}
|
|
|
|
|
if controller.PrivateId == "" {
|
|
|
|
|
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "controller private_id is empty")
|
|
|
|
|
}
|
|
|
|
|
if controller.Address == "" {
|
|
|
|
|
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "controller address is empty")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rowsUpdated int
|
|
|
|
|
_, err := r.writer.DoTx(
|
|
|
|
|
ctx,
|
|
|
|
|
db.StdRetryCnt,
|
|
|
|
|
db.ExpBackoff{},
|
|
|
|
|
func(reader db.Reader, w db.Writer) error {
|
|
|
|
|
var err error
|
2025-07-02 13:45:26 -05:00
|
|
|
params := []any{
|
|
|
|
|
sql.Named("controller_private_id", controller.PrivateId),
|
|
|
|
|
sql.Named("controller_address", controller.Address),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if controller.Description != "" {
|
|
|
|
|
params = append(params, sql.Named("controller_description", controller.Description))
|
|
|
|
|
} else {
|
|
|
|
|
params = append(params, sql.Named("controller_description", nil))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rowsUpdated, err = w.Exec(ctx, updateController, params)
|
2025-03-26 14:54:02 -05:00
|
|
|
switch {
|
|
|
|
|
case err != nil:
|
|
|
|
|
return errors.Wrap(ctx, err, op+":Update")
|
|
|
|
|
case rowsUpdated > 1:
|
|
|
|
|
return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been updated")
|
|
|
|
|
case rowsUpdated == 0:
|
|
|
|
|
return errors.New(ctx, errors.RecordNotFound, op, "no resources would have been updated")
|
|
|
|
|
default:
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return db.NoRowsAffected, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rowsUpdated, nil
|
|
|
|
|
}
|