You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/server/repository_controller.go

128 lines
3.9 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package server
import (
"context"
"database/sql"
"fmt"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
)
func (r *Repository) ListControllers(ctx context.Context, opt ...Option) ([]*Controller, error) {
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.
func (r *Repository) listControllersWithReader(ctx context.Context, reader db.Reader, opt ...Option) ([]*Controller, error) {
opts := GetOpts(opt...)
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()))
}
var controllers []*Controller
if err := reader.SearchWhere(
ctx,
&controllers,
where,
[]any{},
db.WithLimit(-1),
); err != nil {
return nil, errors.Wrap(ctx, err, "workers.listControllersWithReader")
}
return controllers, nil
}
func (r *Repository) UpsertController(ctx context.Context, controller *Controller) (int, error) {
const op = "server.(Repository).UpsertController"
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"},
Action: append(db.SetColumns([]string{"description", "address"}), db.SetColumnValues(map[string]any{"update_time": "now()"})...),
}
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
}
// 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
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)
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
}