# New/Updated RPC Endpoint Checklist

Prefer adding a new message to changing any existing RPC messages.

## Code

* [ ] `Request` struct and `*RequestType` constant in
      `nomad/structs/structs.go`. Append the constant, old constant
      values must remain unchanged. Just add the request type to this file, all other resource definitions
      must be on their own separate file.

* [ ] In `nomad/fsm.go`, add a dispatch case to the switch statement in `(n *nomadFSM) Apply`
  * `*nomadFSM` method to decode the request and call the state method

* [ ] State method for modifying objects in a `Txn` in the `state` package, located in
      `nomad/state/`. Every new resource should have its own file and test file, named using the convention
      `nomad/state/state_store_[resource].go` and `nomad/state/state_store_[resource]_test.go`

* [ ] Handler for the request in `nomad/foo_endpoint.go`
  * RPCs are resolved by matching the method name for bound structs
	[net/rpc](https://golang.org/pkg/net/rpc/)
  * Register any new RPC structs in `nomad/server.go`
  * Authentication:
    * For RPCs that support HTTP APIs, call `Authenticate` before forwarding. Return any error after frowarding, and call `ResolveACL` to get an ACL to check.
    * For RPCs that support client-to-server RPCs _only_, use `AuthenticateClientOnly` before forwarding. Check the `AllowClientOp` ACL after forwarding.
    * For RPCs that support server-to-server RPCs _only_, use `AuthenticateServerOnly` before forwarding. Check the `AllowServerOp` ACL _before_ forwarding.
  * Authorization:
    * Use `ResolveACL` to turn the authenticated request into an ACL to check.
    * For Update/Get/Delete RPCs, check ACLs before hitting the state store.
    * For List RPCs, use ACLs as a filter on the query.
    * _Never_ check that the ACL object is `nil` to bypass authorization. The
      authorization methods in `acl/acl.go` should already handle `nil` ACL
      objects correctly (by rejecting them).

* [ ] Wrapper for the HTTP request in `command/agent/foo_endpoint.go`
  * Backwards compatibility requires a new endpoint, an upgraded
    client or server may be forwarding this request to an old server,
    without support for the new RPC
  * RPCs triggered by an internal process may not need support
  * Check ACLs as an optimization

* [ ] `nomad/core_sched.go` sends many RPCs
  * `ServersMeetMinimumVersion` asserts that the server cluster is
    upgraded, so use this to guard sending the new RPC, else send the old RPC
  * Version must match the actual release version!

* [ ] If implementing a Client RPC...
  * Use `QueryOptions` instead of `WriteRequest` in the Request struct as
    `WriteRequest` is only for *Raft* writes.
  * Set `QueryOptions.AllowStale = true` in the *Server* RPC forwarder to avoid
    an infinite loop between leaders and followers when a Client RPC is
    forwarded through a follower. See
    https://github.com/hashicorp/nomad/issues/16517

## Docs

* [ ] Changelog
* [ ] [Metrics](https://developer.hashicorp.com/nomad/docs/operations/metrics#server-metrics)
* [ ] [API docs](https://developer.hashicorp.com/nomad/api-docs) for RPCs with an HTTP endpoint, include ACLs, params, and example response body.
