Skip to content

Commit

Permalink
bus: implement CR remarks
Browse files Browse the repository at this point in the history
  • Loading branch information
peterjan committed Nov 12, 2024
1 parent e0c5b04 commit ec6e402
Show file tree
Hide file tree
Showing 14 changed files with 103 additions and 125 deletions.
11 changes: 6 additions & 5 deletions api/bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,11 @@ type (
PriceTable rhpv3.HostPriceTable `json:"priceTable,omitempty"`
}

// UpdateAutopilotConfigRequest is the request type for the /autopilot/config endpoint.
UpdateAutopilotConfigRequest struct {
Enabled *bool `json:"enabled"`
Contracts *ContractsConfig `json:"contracts"`
Hosts *HostsConfig `json:"hosts"`
// UpdateAutopilotRequest is the request type for the /autopilot endpoint.
UpdateAutopilotRequest struct {
Enabled *bool `json:"enabled"`
Contracts *ContractsConfig `json:"contracts"`
CurrentPeriod *uint64 `json:"currentPeriod"`
Hosts *HostsConfig `json:"hosts"`
}
)
8 changes: 3 additions & 5 deletions bus/bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,7 @@ type (
AutopilotStore interface {
Autopilot(ctx context.Context) (api.Autopilot, error)
InitAutopilot(ctx context.Context) error
UpdateAutopilotConfig(ctx context.Context, cfg api.AutopilotConfig) error
UpdateCurrentPeriod(ctx context.Context, period uint64) error
UpdateAutopilot(ctx context.Context, ap api.Autopilot) error
}

// BackupStore is the interface of a store that can be backed up.
Expand Down Expand Up @@ -405,9 +404,8 @@ func (b *Bus) Handler() http.Handler {
"POST /alerts/dismiss": b.handlePOSTAlertsDismiss,
"POST /alerts/register": b.handlePOSTAlertsRegister,

"GET /autopilot": b.autopilotHandlerGET,
"PUT /autopilot/config": b.autopilotConfigHandlerPUT,
"PUT /autopilot/period": b.autopilotPeriodHandlerPUT,
"GET /autopilot": b.autopilotHandlerGET,
"PUT /autopilot": b.autopilotHandlerPUT,

"GET /buckets": b.bucketsHandlerGET,
"POST /buckets": b.bucketsHandlerPOST,
Expand Down
41 changes: 26 additions & 15 deletions bus/client/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,47 @@ import (
"go.sia.tech/renterd/api"
)

var (
enable = true
disable = false
)

// Autopilot returns the autopilot.
func (c *Client) Autopilot(ctx context.Context) (ap api.Autopilot, err error) {
err = c.c.WithContext(ctx).GET("/autopilot", &ap)
return
}

// EnableAutopilot allows the autopilot to be enabled or disabled.
func (c *Client) EnableAutopilot(ctx context.Context, enable bool) error {
return c.updateAutopilotConfig(ctx, nil, nil, &enable)
// DisableAutopilot disables the autopilot.
func (c *Client) DisableAutopilot(ctx context.Context) error {
return c.updateAutopilot(ctx, &disable, nil, nil, nil)
}

// EnableAutopilot enables the autopilot.
func (c *Client) EnableAutopilot(ctx context.Context) error {
return c.updateAutopilot(ctx, &enable, nil, nil, nil)
}

// UpdateCurrentPeriod updates the autopilot's current period in the bus.
func (c *Client) UpdateCurrentPeriod(ctx context.Context, currentPeriod uint64) error {
return c.updateAutopilot(ctx, nil, nil, nil, &currentPeriod)
}

// UpdateContractsConfig updates the autopilot's contract configuration in the bus.
func (c *Client) UpdateContractsConfig(ctx context.Context, cfg api.ContractsConfig) error {
return c.updateAutopilotConfig(ctx, &cfg, nil, nil)
return c.updateAutopilot(ctx, nil, &cfg, nil, nil)
}

// UpdateHostsConfig updates the autopilot's hosts configuration in the bus.
func (c *Client) UpdateHostsConfig(ctx context.Context, cfg api.HostsConfig) error {
return c.updateAutopilotConfig(ctx, nil, &cfg, nil)
}

// AutopilotPeriod returns the current period.
func (c *Client) UpdateCurrentPeriod(ctx context.Context, period uint64) error {
return c.c.WithContext(ctx).PUT("/autopilot/period", period)
return c.updateAutopilot(ctx, nil, nil, &cfg, nil)
}

func (c *Client) updateAutopilotConfig(ctx context.Context, contracts *api.ContractsConfig, hosts *api.HostsConfig, enabled *bool) error {
return c.c.WithContext(ctx).PUT("/autopilot/config", api.UpdateAutopilotConfigRequest{
Contracts: contracts,
Hosts: hosts,
Enabled: enabled,
func (c *Client) updateAutopilot(ctx context.Context, enabled *bool, contracts *api.ContractsConfig, hosts *api.HostsConfig, currentPeriod *uint64) error {
return c.c.WithContext(ctx).PUT("/autopilot", api.UpdateAutopilotRequest{
Enabled: enabled,
Contracts: contracts,
CurrentPeriod: currentPeriod,
Hosts: hosts,
})
}
51 changes: 20 additions & 31 deletions bus/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -1793,62 +1793,51 @@ func (b *Bus) autopilotHandlerGET(jc jape.Context) {
jc.Encode(ap)
}

func (b *Bus) autopilotConfigHandlerPUT(jc jape.Context) {
var req api.UpdateAutopilotConfigRequest
func (b *Bus) autopilotHandlerPUT(jc jape.Context) {
// decode request
var req api.UpdateAutopilotRequest
if jc.Decode(&req) != nil {
return
} else if req == (api.UpdateAutopilotConfigRequest{}) {
} else if req == (api.UpdateAutopilotRequest{}) {
jc.Error(errors.New("request body is empty"), http.StatusBadRequest)
return
}

// fetch the autopilot
ap, err := b.store.Autopilot(jc.Request.Context())
if jc.Check("failed to fetch autopilot", err) != nil {
return
}
cfg := ap.AutopilotConfig

if req.Enabled != nil {
cfg.Enabled = *req.Enabled
}

// update the contracts config
if req.Contracts != nil {
if err := req.Contracts.Validate(); err != nil && cfg.Enabled {
jc.Error(fmt.Errorf("failed to update autopilot config, contracts config is invalid: %w", err), http.StatusBadRequest)
if err := req.Contracts.Validate(); err != nil {
jc.Error(fmt.Errorf("failed to update autopilot, contracts config is invalid: %w", err), http.StatusBadRequest)
return
}
cfg.Contracts = *req.Contracts
ap.Contracts = *req.Contracts
}

// update the hosts config
if req.Hosts != nil {
if err := req.Hosts.Validate(); err != nil && cfg.Enabled {
jc.Error(fmt.Errorf("failed to update autopilot config, hosts config is invalid: %w", err), http.StatusBadRequest)
if err := req.Hosts.Validate(); err != nil {
jc.Error(fmt.Errorf("failed to update autopilot, hosts config is invalid: %w", err), http.StatusBadRequest)
return
}
cfg.Hosts = *req.Hosts
ap.Hosts = *req.Hosts
}

if cfg.Enabled {
if err := cfg.Contracts.Validate(); err != nil {
jc.Error(fmt.Errorf("failed to enable autopilot, contracts config is invalid: %w", err), http.StatusConflict)
return
}
if err := cfg.Hosts.Validate(); err != nil {
jc.Error(fmt.Errorf("failed to enable autopilot, hosts config is invalid: %w", err), http.StatusConflict)
return
}
// enable/disable the autopilot
if req.Enabled != nil {
ap.Enabled = *req.Enabled
}

jc.Check("failed to update autopilot config", b.store.UpdateAutopilotConfig(jc.Request.Context(), cfg))
}

func (b *Bus) autopilotPeriodHandlerPUT(jc jape.Context) {
var period uint64
if jc.Decode(&period) != nil {
return
// update the current period
if req.CurrentPeriod != nil {
ap.CurrentPeriod = *req.CurrentPeriod
}

jc.Check("failed to update autopilot period", b.store.UpdateCurrentPeriod(jc.Request.Context(), period))
jc.Check("failed to update autopilot", b.store.UpdateAutopilot(jc.Request.Context(), ap))
}

func (b *Bus) contractIDAncestorsHandler(jc jape.Context) {
Expand Down
32 changes: 16 additions & 16 deletions internal/test/e2e/autopilot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,37 @@ func TestAutopilot(t *testing.T) {
}

// assert hosts config is validated
hcfg := ap.Hosts
hcfg.MaxDowntimeHours = 99*365*24 + 1 // exceed by one
if err := b.UpdateHostsConfig(context.Background(), hcfg); !utils.IsErr(err, api.ErrMaxDowntimeHoursTooHigh) {
hosts := ap.Hosts
hosts.MaxDowntimeHours = 99*365*24 + 1 // exceed by one
if err := b.UpdateHostsConfig(context.Background(), hosts); !utils.IsErr(err, api.ErrMaxDowntimeHoursTooHigh) {
t.Fatal("unexpected", err)
}
hcfg.MaxDowntimeHours = 99 * 365 * 24 // allowed max
tt.OK(b.UpdateHostsConfig(context.Background(), hcfg))
hosts.MaxDowntimeHours = 99 * 365 * 24 // allowed max
tt.OK(b.UpdateHostsConfig(context.Background(), hosts))

hcfg.MinProtocolVersion = "not a version"
if err := b.UpdateHostsConfig(context.Background(), hcfg); !utils.IsErr(err, api.ErrInvalidReleaseVersion) {
hosts.MinProtocolVersion = "not a version"
if err := b.UpdateHostsConfig(context.Background(), hosts); !utils.IsErr(err, api.ErrInvalidReleaseVersion) {
t.Fatal("unexpected")
}

// assert contracts config is validated
ccfg := ap.Contracts
ccfg.Period = 0 // invalid period
if err := b.UpdateContractsConfig(context.Background(), ccfg); err == nil || !strings.Contains(err.Error(), "period must be greater than 0") {
contracts := ap.Contracts
contracts.Period = 0 // invalid period
if err := b.UpdateContractsConfig(context.Background(), contracts); err == nil || !strings.Contains(err.Error(), "period must be greater than 0") {
t.Fatal("unexpected", err)
}
ccfg.Period = 1 // valid period
ccfg.RenewWindow = 0 // invalid renew window
if err := b.UpdateContractsConfig(context.Background(), ccfg); err == nil || !strings.Contains(err.Error(), "renewWindow must be greater than 0") {
contracts.Period = 1 // valid period
contracts.RenewWindow = 0 // invalid renew window
if err := b.UpdateContractsConfig(context.Background(), contracts); err == nil || !strings.Contains(err.Error(), "renewWindow must be greater than 0") {
t.Fatal("unexpected", err)
}
ccfg.RenewWindow = 1 // valid renew window
if err := b.UpdateContractsConfig(context.Background(), ccfg); err != nil {
contracts.RenewWindow = 1 // valid renew window
if err := b.UpdateContractsConfig(context.Background(), contracts); err != nil {
t.Fatal(err)
}

// assert we can disable the autopilot
tt.OK(b.EnableAutopilot(context.Background(), false))
tt.OK(b.DisableAutopilot(context.Background()))
ap, err = b.Autopilot(context.Background())
tt.OK(err)
if ap.Enabled {
Expand Down
2 changes: 1 addition & 1 deletion internal/test/e2e/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ func newTestCluster(t *testing.T, opts testClusterOptions) *TestCluster {
tt.OKAll(
busClient.UpdateContractsConfig(ctx, apConfig.Contracts),
busClient.UpdateHostsConfig(ctx, apConfig.Hosts),
busClient.EnableAutopilot(ctx, true),
busClient.EnableAutopilot(ctx),
)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/test/e2e/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2256,7 +2256,7 @@ func TestWalletFormUnconfirmed(t *testing.T) {
tt.OKAll(
b.UpdateContractsConfig(context.Background(), test.AutopilotConfig.Contracts),
b.UpdateHostsConfig(context.Background(), test.AutopilotConfig.Hosts),
b.EnableAutopilot(context.Background(), true),
b.EnableAutopilot(context.Background()),
)

// wait for a contract to form
Expand Down
6 changes: 3 additions & 3 deletions internal/test/e2e/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ func TestFormContract(t *testing.T) {
// update autopilot config to allow for 1 contract, this won't form a
// contract but will ensure we don't skip contract maintenance, which should
// renew the contract we formed
cfg := ap.Contracts
cfg.Amount = 1
tt.OK(b.UpdateContractsConfig(context.Background(), cfg))
contracts := ap.Contracts
contracts.Amount = 1
tt.OK(b.UpdateContractsConfig(context.Background(), contracts))

// assert the contract gets renewed and thus maintained
var renewalID types.FileContractID
Expand Down
6 changes: 3 additions & 3 deletions internal/test/e2e/gouging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ func TestHostMinVersion(t *testing.T) {
tt := cluster.tt

// set min version to a high value
cfg := test.AutopilotConfig.Hosts
cfg.MinProtocolVersion = "99.99.99"
tt.OK(cluster.Bus.UpdateHostsConfig(context.Background(), cfg))
hosts := test.AutopilotConfig.Hosts
hosts.MinProtocolVersion = "99.99.99"
tt.OK(cluster.Bus.UpdateHostsConfig(context.Background(), hosts))

// contracts in set should drop to 0
tt.Retry(100, 100*time.Millisecond, func() error {
Expand Down
10 changes: 2 additions & 8 deletions stores/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,8 @@ func (s *SQLStore) InitAutopilot(ctx context.Context) error {
})
}

func (s *SQLStore) UpdateAutopilotConfig(ctx context.Context, cfg api.AutopilotConfig) error {
func (s *SQLStore) UpdateAutopilot(ctx context.Context, ap api.Autopilot) error {
return s.db.Transaction(ctx, func(tx sql.DatabaseTx) error {
return tx.UpdateAutopilotConfig(ctx, cfg)
})
}

func (s *SQLStore) UpdateCurrentPeriod(ctx context.Context, period uint64) error {
return s.db.Transaction(ctx, func(tx sql.DatabaseTx) error {
return tx.UpdateCurrentPeriod(ctx, period)
return tx.UpdateAutopilot(ctx, ap)
})
}
8 changes: 2 additions & 6 deletions stores/sql/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,8 @@ type (
// UnspentSiacoinElements returns all wallet outputs in the database.
UnspentSiacoinElements(ctx context.Context) ([]types.SiacoinElement, error)

// UpdateAutopilotConfig updates the autopilot configuration in the
// database.
UpdateAutopilotConfig(ctx context.Context, cfg api.AutopilotConfig) error
// UpdateAutopilot updates the autopilot in the database.
UpdateAutopilot(ctx context.Context, ap api.Autopilot) error

// UpdateBucketPolicy updates the policy of the bucket with the provided
// one, fully overwriting the existing policy.
Expand All @@ -346,9 +345,6 @@ type (
// it doesn't exist already.
UpdateContractSet(ctx context.Context, name string, toAdd, toRemove []types.FileContractID) error

// UpdateCurrentPeriod updates the current period in the database.
UpdateCurrentPeriod(ctx context.Context, period uint64) error

// UpdateHostAllowlistEntries updates the allowlist in the database
UpdateHostAllowlistEntries(ctx context.Context, add, remove []types.PublicKey, clear bool) error

Expand Down
35 changes: 16 additions & 19 deletions stores/sql/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2178,10 +2178,11 @@ WHERE fcid = ?`,
return nil
}

func UpdateAutopilotConfig(ctx context.Context, tx sql.Tx, cfg api.AutopilotConfig) error {
func UpdateAutopilot(ctx context.Context, tx sql.Tx, ap api.Autopilot) error {
_, err := tx.Exec(ctx, `
UPDATE autopilot
SET enabled = ?,
current_period = ?,
contracts_set = ?,
contracts_amount = ?,
contracts_period = ?,
Expand All @@ -2195,28 +2196,24 @@ SET enabled = ?,
hosts_min_protocol_version = ?,
hosts_max_consecutive_scan_failures = ?
WHERE id = ?`,
cfg.Enabled,
cfg.Contracts.Set,
cfg.Contracts.Amount,
cfg.Contracts.Period,
cfg.Contracts.RenewWindow,
cfg.Contracts.Download,
cfg.Contracts.Upload,
cfg.Contracts.Storage,
cfg.Contracts.Prune,
cfg.Hosts.AllowRedundantIPs,
cfg.Hosts.MaxDowntimeHours,
cfg.Hosts.MinProtocolVersion,
cfg.Hosts.MaxConsecutiveScanFailures,
ap.Enabled,
ap.CurrentPeriod,
ap.Contracts.Set,
ap.Contracts.Amount,
ap.Contracts.Period,
ap.Contracts.RenewWindow,
ap.Contracts.Download,
ap.Contracts.Upload,
ap.Contracts.Storage,
ap.Contracts.Prune,
ap.Hosts.AllowRedundantIPs,
ap.Hosts.MaxDowntimeHours,
ap.Hosts.MinProtocolVersion,
ap.Hosts.MaxConsecutiveScanFailures,
sql.AutopilotID)
return err
}

func UpdateCurrentPeriod(ctx context.Context, tx sql.Tx, period uint64) error {
_, err := tx.Exec(ctx, `UPDATE autopilot SET current_period = ? WHERE id = ?`, period, sql.AutopilotID)
return err
}

func UpdatePeerInfo(ctx context.Context, tx sql.Tx, addr string, fn func(*syncer.PeerInfo)) error {
info, err := PeerInfo(ctx, tx, addr)
if err != nil {
Expand Down
8 changes: 2 additions & 6 deletions stores/sql/mysql/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -998,12 +998,8 @@ func (tx *MainDatabaseTx) UnspentSiacoinElements(ctx context.Context) (elements
return ssql.UnspentSiacoinElements(ctx, tx.Tx)
}

func (tx *MainDatabaseTx) UpdateAutopilotConfig(ctx context.Context, cfg api.AutopilotConfig) error {
return ssql.UpdateAutopilotConfig(ctx, tx, cfg)
}

func (tx *MainDatabaseTx) UpdateCurrentPeriod(ctx context.Context, period uint64) error {
return ssql.UpdateCurrentPeriod(ctx, tx, period)
func (tx *MainDatabaseTx) UpdateAutopilot(ctx context.Context, ap api.Autopilot) error {
return ssql.UpdateAutopilot(ctx, tx, ap)
}

func (tx *MainDatabaseTx) UpdateBucketPolicy(ctx context.Context, bucket string, bp api.BucketPolicy) error {
Expand Down
Loading

0 comments on commit ec6e402

Please sign in to comment.