Documentation
¶
Overview ¶
Package api is the HTTP interface every Wegweiser client speaks.
The web interface and the weg command line are both clients of it, and neither reaches the database any other way (architecture invariant 1). What the API accepts is described in openapi.yaml, which is the source of truth: the models, the server interface and the client in gen/ are all generated from it, so an endpoint that is not written down there does not exist.
Index ¶
- Constants
- Variables
- func EnsureBootstrapToken(ctx context.Context, s store.Store, now time.Time) (secret string, err error)
- func MintToken(name string, scopes []Scope, now time.Time) (secret string, tok store.Token, err error)
- type Config
- type Scope
- type Server
- func (s *Server) Close() error
- func (s *Server) CreateRecord(ctx context.Context, req gen.CreateRecordRequestObject) (gen.CreateRecordResponseObject, error)
- func (s *Server) CreateSession(ctx context.Context, req gen.CreateSessionRequestObject) (gen.CreateSessionResponseObject, error)
- func (s *Server) CreateToken(ctx context.Context, req gen.CreateTokenRequestObject) (gen.CreateTokenResponseObject, error)
- func (s *Server) CreateZone(ctx context.Context, req gen.CreateZoneRequestObject) (gen.CreateZoneResponseObject, error)
- func (s *Server) DeleteRecord(ctx context.Context, req gen.DeleteRecordRequestObject) (gen.DeleteRecordResponseObject, error)
- func (s *Server) DeleteSession(ctx context.Context, _ gen.DeleteSessionRequestObject) (gen.DeleteSessionResponseObject, error)
- func (s *Server) DeleteZone(ctx context.Context, req gen.DeleteZoneRequestObject) (gen.DeleteZoneResponseObject, error)
- func (s *Server) DetachRecord(ctx context.Context, req gen.DetachRecordRequestObject) (gen.DetachRecordResponseObject, error)
- func (s *Server) ExportZone(ctx context.Context, req gen.ExportZoneRequestObject) (gen.ExportZoneResponseObject, error)
- func (s *Server) GetCommit(ctx context.Context, req gen.GetCommitRequestObject) (gen.GetCommitResponseObject, error)
- func (s *Server) GetHealth(_ context.Context, _ gen.GetHealthRequestObject) (gen.GetHealthResponseObject, error)
- func (s *Server) GetMetrics(_ context.Context, _ gen.GetMetricsRequestObject) (gen.GetMetricsResponseObject, error)
- func (s *Server) GetRecord(ctx context.Context, req gen.GetRecordRequestObject) (gen.GetRecordResponseObject, error)
- func (s *Server) GetSession(ctx context.Context, _ gen.GetSessionRequestObject) (gen.GetSessionResponseObject, error)
- func (s *Server) GetSettings(ctx context.Context, _ gen.GetSettingsRequestObject) (gen.GetSettingsResponseObject, error)
- func (s *Server) GetZone(ctx context.Context, req gen.GetZoneRequestObject) (gen.GetZoneResponseObject, error)
- func (s *Server) ImportZone(ctx context.Context, req gen.ImportZoneRequestObject) (gen.ImportZoneResponseObject, error)
- func (s *Server) ListCommits(ctx context.Context, req gen.ListCommitsRequestObject) (gen.ListCommitsResponseObject, error)
- func (s *Server) ListRecords(ctx context.Context, req gen.ListRecordsRequestObject) (gen.ListRecordsResponseObject, error)
- func (s *Server) ListTokens(ctx context.Context, _ gen.ListTokensRequestObject) (gen.ListTokensResponseObject, error)
- func (s *Server) ListZones(ctx context.Context, req gen.ListZonesRequestObject) (gen.ListZonesResponseObject, error)
- func (s *Server) ReplaceRRsets(ctx context.Context, req gen.ReplaceRRsetsRequestObject) (gen.ReplaceRRsetsResponseObject, error)
- func (s *Server) RevokeToken(ctx context.Context, req gen.RevokeTokenRequestObject) (gen.RevokeTokenResponseObject, error)
- func (s *Server) RollbackZone(ctx context.Context, req gen.RollbackZoneRequestObject) (gen.RollbackZoneResponseObject, error)
- func (s *Server) StreamQueries(ctx context.Context, request gen.StreamQueriesRequestObject) (gen.StreamQueriesResponseObject, error)
- func (s *Server) UpdateRecord(ctx context.Context, req gen.UpdateRecordRequestObject) (gen.UpdateRecordResponseObject, error)
- func (s *Server) UpdateSettings(ctx context.Context, req gen.UpdateSettingsRequestObject) (gen.UpdateSettingsResponseObject, error)
- func (s *Server) UpdateZone(ctx context.Context, req gen.UpdateZoneRequestObject) (gen.UpdateZoneResponseObject, error)
- type Snapshots
Constants ¶
const BootstrapName = "bootstrap"
BootstrapName is the name the first token carries, so that an operator listing tokens can see which one came from the installer rather than from a person.
const TokenPrefix = "weg_"
TokenPrefix marks a secret as one of ours, so that a token pasted into the wrong field is recognisable in a log and a secret scanner has something to match on.
Variables ¶
var ErrTokenInvalid = errors.New("api: the token is not valid")
ErrTokenInvalid is what every failed authentication returns.
Unknown, revoked and expired are one error on purpose: three would let an attacker sort guesses into "wrong" and "used to be right" (D5).
Functions ¶
func EnsureBootstrapToken ¶
func EnsureBootstrapToken( ctx context.Context, s store.Store, now time.Time, ) (secret string, err error)
EnsureBootstrapToken creates the first admin token if the database has none, and returns the secret exactly once.
An empty secret means tokens already existed and nothing was created. There is no way to ask for the secret again: what is stored is a hash, so a lost bootstrap token is replaced rather than recovered (docs/decisions.md D5).
Types ¶
type Config ¶
type Config struct {
// Store is the source of truth. It is read directly and written only
// through the applier.
Store store.Store
// Applier is the write path. Every change goes through it, so that no
// write bypasses the journal (architecture invariant 4).
Applier *apply.Applier
// Snapshots is the data plane whose view is republished after every write.
// A nil one means the API is running without a query path, which is what a
// test does; writes then change the database and nothing else.
Snapshots Snapshots
// Metrics is what /metrics exports. It is required rather than optional:
// an endpoint that answers with an empty registry when the process forgot
// to build one would report a server that answers no queries, which is
// worse than no endpoint at all.
Metrics *metrics.Metrics
// Stream is what the live query stream subscribes to. Required for the
// same reason as Metrics: an endpoint that opens a stream nothing feeds
// looks like a server nobody is querying.
Stream *stream.Hub
// UI decides whether the embedded web interface is served alongside the
// API. False serves only the API and answers everything else with a
// problem document saying so (docs/decisions.md D16).
UI bool
// OnError is called for failures the client is not told the detail of, so
// that they reach an operator instead of nobody. It may be nil.
OnError func(error)
// Now supplies the current time. Nil picks [time.Now]; tests set it.
Now func() time.Time
}
Config is what a Server needs.
type Scope ¶
type Scope string
Scope is a permission a token carries.
The scopes a token may carry. They are ordered: admin allows everything write allows, and write allows everything read allows. Three levels rather than a permission per endpoint, because a permission model nobody can hold in their head is one that gets granted wholesale.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server implements the generated API.
func (*Server) Close ¶
Close stops the background work the server does and writes out what it was holding.
It is safe to call more than once, and a server that is closed still serves: the handler does not depend on any of this, so a request arriving during shutdown is answered rather than dropped.
func (*Server) CreateRecord ¶
func (s *Server) CreateRecord( ctx context.Context, req gen.CreateRecordRequestObject, ) (gen.CreateRecordResponseObject, error)
CreateRecord adds a record to a zone.
What adding it caused comes back with it. An address record may generate a PTR, may find that the address already answers with another name, or may find no reverse zone to put anything in, and the last two are not errors. They are decisions for a person, so they travel as data (docs/decisions.md D3 and D6).
func (*Server) CreateSession ¶
func (s *Server) CreateSession( ctx context.Context, req gen.CreateSessionRequestObject, ) (gen.CreateSessionResponseObject, error)
CreateSession exchanges a token for a browser session.
func (*Server) CreateToken ¶
func (s *Server) CreateToken( ctx context.Context, req gen.CreateTokenRequestObject, ) (gen.CreateTokenResponseObject, error)
CreateToken mints a token and shows its secret for the only time.
func (*Server) CreateZone ¶
func (s *Server) CreateZone( ctx context.Context, req gen.CreateZoneRequestObject, ) (gen.CreateZoneResponseObject, error)
CreateZone brings a zone into existence.
func (*Server) DeleteRecord ¶
func (s *Server) DeleteRecord( ctx context.Context, req gen.DeleteRecordRequestObject, ) (gen.DeleteRecordResponseObject, error)
DeleteRecord removes a record, and whatever was generated from it.
func (*Server) DeleteSession ¶
func (s *Server) DeleteSession( ctx context.Context, _ gen.DeleteSessionRequestObject, ) (gen.DeleteSessionResponseObject, error)
DeleteSession ends the session, if the request came with one.
func (*Server) DeleteZone ¶
func (s *Server) DeleteZone( ctx context.Context, req gen.DeleteZoneRequestObject, ) (gen.DeleteZoneResponseObject, error)
DeleteZone removes a zone and everything in it.
func (*Server) DetachRecord ¶
func (s *Server) DetachRecord( ctx context.Context, req gen.DetachRecordRequestObject, ) (gen.DetachRecordResponseObject, error)
DetachRecord turns a generated record into an authored one.
This is the way out of "a generated record cannot be edited" (D4). A record that is already authored comes back unchanged rather than as an error, which makes calling this twice harmless.
func (*Server) ExportZone ¶
func (s *Server) ExportZone( ctx context.Context, req gen.ExportZoneRequestObject, ) (gen.ExportZoneResponseObject, error)
ExportZone writes a zone out in the format every other authoritative server reads.
func (*Server) GetCommit ¶
func (s *Server) GetCommit( ctx context.Context, req gen.GetCommitRequestObject, ) (gen.GetCommitResponseObject, error)
GetCommit returns one commit with everything it changed.
func (*Server) GetHealth ¶
func (s *Server) GetHealth(_ context.Context, _ gen.GetHealthRequestObject) (gen.GetHealthResponseObject, error)
GetHealth reports whether the server is fit to answer queries.
func (*Server) GetMetrics ¶
func (s *Server) GetMetrics( _ context.Context, _ gen.GetMetricsRequestObject, ) (gen.GetMetricsResponseObject, error)
GetMetrics writes the current values in the Prometheus text exposition format.
func (*Server) GetRecord ¶
func (s *Server) GetRecord( ctx context.Context, req gen.GetRecordRequestObject, ) (gen.GetRecordResponseObject, error)
GetRecord returns one record.
func (*Server) GetSession ¶
func (s *Server) GetSession( ctx context.Context, _ gen.GetSessionRequestObject, ) (gen.GetSessionResponseObject, error)
GetSession reports who the request is authenticated as.
func (*Server) GetSettings ¶
func (s *Server) GetSettings( ctx context.Context, _ gen.GetSettingsRequestObject, ) (gen.GetSettingsResponseObject, error)
GetSettings reports the defaults a zone that says nothing inherits.
func (*Server) GetZone ¶
func (s *Server) GetZone( ctx context.Context, req gen.GetZoneRequestObject, ) (gen.GetZoneResponseObject, error)
GetZone returns one zone.
func (*Server) ImportZone ¶
func (s *Server) ImportZone( ctx context.Context, req gen.ImportZoneRequestObject, ) (gen.ImportZoneResponseObject, error)
ImportZone brings a whole zone in from a file in the format of RFC 1035 §5.
func (*Server) ListCommits ¶
func (s *Server) ListCommits( ctx context.Context, req gen.ListCommitsRequestObject, ) (gen.ListCommitsResponseObject, error)
ListCommits returns one page of history, newest first.
func (*Server) ListRecords ¶
func (s *Server) ListRecords( ctx context.Context, req gen.ListRecordsRequestObject, ) (gen.ListRecordsResponseObject, error)
ListRecords returns one page of a zone's records.
func (*Server) ListTokens ¶
func (s *Server) ListTokens( ctx context.Context, _ gen.ListTokensRequestObject, ) (gen.ListTokensResponseObject, error)
ListTokens returns every token, revoked and expired ones included.
func (*Server) ListZones ¶
func (s *Server) ListZones( ctx context.Context, req gen.ListZonesRequestObject, ) (gen.ListZonesResponseObject, error)
ListZones returns one page of zones.
func (*Server) ReplaceRRsets ¶
func (s *Server) ReplaceRRsets( ctx context.Context, req gen.ReplaceRRsetsRequestObject, ) (gen.ReplaceRRsetsResponseObject, error)
ReplaceRRsets makes the named RRsets exactly what the client sent.
func (*Server) RevokeToken ¶
func (s *Server) RevokeToken( ctx context.Context, req gen.RevokeTokenRequestObject, ) (gen.RevokeTokenResponseObject, error)
RevokeToken withdraws a token.
func (*Server) RollbackZone ¶
func (s *Server) RollbackZone( ctx context.Context, req gen.RollbackZoneRequestObject, ) (gen.RollbackZoneResponseObject, error)
RollbackZone restores a zone to the state it had at a serial.
func (*Server) StreamQueries ¶
func (s *Server) StreamQueries( ctx context.Context, request gen.StreamQueriesRequestObject, ) (gen.StreamQueriesResponseObject, error)
StreamQueries carries a live tail of the exchanges matching the filter, as Server-Sent Events.
func (*Server) UpdateRecord ¶
func (s *Server) UpdateRecord( ctx context.Context, req gen.UpdateRecordRequestObject, ) (gen.UpdateRecordResponseObject, error)
UpdateRecord changes a record, keeping its identity.
func (*Server) UpdateSettings ¶
func (s *Server) UpdateSettings( ctx context.Context, req gen.UpdateSettingsRequestObject, ) (gen.UpdateSettingsResponseObject, error)
UpdateSettings changes them. A field the request leaves out is left alone, so a client may send only what it means to change.
func (*Server) UpdateZone ¶
func (s *Server) UpdateZone( ctx context.Context, req gen.UpdateZoneRequestObject, ) (gen.UpdateZoneResponseObject, error)
UpdateZone changes a zone's own settings, leaving its records alone.
type Snapshots ¶
Snapshots is the data plane, as far as the API needs to know about it: it reports what is being answered from, and it takes what should be answered from next. A *dns.Server is one.
It is an interface so that the API can be tested without a socket, and so that the coupling stays the one pointer architecture invariant 2 allows.