3fe148891b
* Stub Config Entries for Consul Native API Gateway (#15644) * Add empty InlineCertificate struct and protobuf * apigateway stubs * new files * Stub HTTPRoute in api pkg * checkpoint * Stub HTTPRoute in structs pkg * Simplify api.APIGatewayConfigEntry to be consistent w/ other entries * Update makeConfigEntry switch, add docstring for HTTPRouteConfigEntry * Add TCPRoute to MakeConfigEntry, return unique Kind * proto generated files * Stub BoundAPIGatewayConfigEntry in agent Since this type is only written by a controller and read by xDS, it doesn't need to be defined in the `api` pkg * Add RaftIndex to APIGatewayConfigEntry stub * Add new config entry kinds to validation allow-list * Add RaftIndex to other added config entry stubs * fix panic * Update usage metrics assertions to include new cfg entries * Regenerate proto w/ Go 1.19 * Run buf formatter on config_entry.proto * Add Meta and acl.EnterpriseMeta to all new ConfigEntry types * Remove optional interface method Warnings() for now Will restore later if we wind up needing it * Remove unnecessary Services field from added config entry types * Implement GetMeta(), GetEnterpriseMeta() for added config entry types * Add meta field to proto, name consistently w/ existing config entries * Format config_entry.proto * Add initial implementation of CanRead + CanWrite for new config entry types * Add unit tests for decoding of new config entry types * Add unit tests for parsing of new config entry types * Add unit tests for API Gateway config entry ACLs * Return typed PermissionDeniedError on BoundAPIGateway CanWrite * Add unit tests for added config entry ACLs * Add BoundAPIGateway type to AllConfigEntryKinds * Return proper kind from BoundAPIGateway * Add docstrings for new config entry types * Add missing config entry kinds to proto def * Update usagemetrics_oss_test.go * Use utility func for returning PermissionDeniedError * Add BoundAPIGateway to proto def Co-authored-by: Sarah Alsmiller <sarah.alsmiller@hashicorp.com> Co-authored-by: Nathan Coleman <nathan.coleman@hashicorp.com> * Add APIGateway validation * Fix comment * Add additional validations * Add cert ref validation * Add protobuf definitions * Tabs to spaces * Fix up field types * Add API structs * Move struct fields around a bit * EventPublisher subscriptions for Consul Native API Gateway (#15757) * Create new event topics in subscribe proto * Add tests for PBSubscribe func * Make configs singular, add all configs to PBToStreamSubscribeRequest * Add snapshot methods * Add config_entry_events tests * Add config entry kind to topic for new configs * Add unit tests for snapshot methods * Start adding integration test * Test using the new controller code * Update agent/consul/state/config_entry_events.go Co-authored-by: Nathan Coleman <nathan.coleman@hashicorp.com> * Check value of error Co-authored-by: Nathan Coleman <nathan.coleman@hashicorp.com> * Add controller stubs for API Gateway (#15837) * update initial stub implementation * move files, clean up mutex references * Remove embed, use idiomatic names for constructors * Remove stray file introduced in merge Co-authored-by: Nathan Coleman <nathan.coleman@hashicorp.com> * Initial server-side and proto defs * drop trailing whitespace * Add APIGateway validation (#15847) * Add APIGateway validation * Fix comment * Add additional validations * Add cert ref validation * Add protobuf definitions * Tabs to spaces * Fix up field types * Add API structs * Move struct fields around a bit * APIGateway InlineCertificate validation (#15856) * Add APIGateway validation * Add additional validations * Add protobuf definitions * Tabs to spaces * Add API structs * Move struct fields around a bit * Add validation for InlineCertificate * Fix ACL test * APIGateway BoundAPIGateway validation (#15858) * Add APIGateway validation * Fix comment * Add additional validations * Add cert ref validation * Add protobuf definitions * Tabs to spaces * Fix up field types * Add API structs * Move struct fields around a bit * Add validation for BoundAPIGateway * drop trailing whitespace * APIGateway TCPRoute validation (#15855) * Add APIGateway validation * Fix comment * Add additional validations * Add cert ref validation * Add protobuf definitions * Tabs to spaces * Fix up field types * Add API structs * Move struct fields around a bit * Add TCPRoute normalization and validation * Address PR feedback * Add forgotten Status * Add some more field docs in api package * Fix test * Fix bad merge * Remove duplicate helpers * Fix up proto defs * Fix up stray changes * remove extra newline --------- Co-authored-by: Thomas Eckert <teckert@hashicorp.com> Co-authored-by: Sarah Alsmiller <sarah.alsmiller@hashicorp.com> Co-authored-by: Nathan Coleman <nathan.coleman@hashicorp.com> Co-authored-by: sarahalsmiller <100602640+sarahalsmiller@users.noreply.github.com>
371 lines
9.8 KiB
Go
371 lines
9.8 KiB
Go
package structs
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/consul/acl"
|
|
)
|
|
|
|
// BoundRoute indicates a route that has parent gateways which
|
|
// can be accessed by calling the GetParents associated function.
|
|
type BoundRoute interface {
|
|
ConfigEntry
|
|
GetParents() []ResourceReference
|
|
GetProtocol() APIGatewayListenerProtocol
|
|
}
|
|
|
|
// HTTPRouteConfigEntry manages the configuration for a HTTP route
|
|
// with the given name.
|
|
type HTTPRouteConfigEntry struct {
|
|
// Kind of the config entry. This will be set to structs.HTTPRoute.
|
|
Kind string
|
|
|
|
// Name is used to match the config entry with its associated set
|
|
// of resources, which may include routers, splitters, filters, etc.
|
|
Name string
|
|
|
|
// Parents is a list of gateways that this route should be bound to
|
|
Parents []ResourceReference
|
|
// Rules are a list of HTTP-based routing rules that this route should
|
|
// use for constructing a routing table.
|
|
Rules []HTTPRouteRule
|
|
// Hostnames are the hostnames for which this HTTPRoute should respond to requests.
|
|
Hostnames []string
|
|
|
|
Meta map[string]string `json:",omitempty"`
|
|
// Status is the asynchronous reconciliation status which an HTTPRoute propagates to the user.
|
|
Status Status
|
|
acl.EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
|
|
RaftIndex
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) GetKind() string {
|
|
return HTTPRoute
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) GetName() string {
|
|
if e == nil {
|
|
return ""
|
|
}
|
|
return e.Name
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) GetParents() []ResourceReference {
|
|
if e == nil {
|
|
return []ResourceReference{}
|
|
}
|
|
// TODO HTTP Route should have "parents". Andrew will implement this in his work.
|
|
return []ResourceReference{}
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) GetProtocol() APIGatewayListenerProtocol {
|
|
return ListenerProtocolHTTP
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) Normalize() error {
|
|
return nil
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) Validate() error {
|
|
return nil
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) CanRead(authz acl.Authorizer) error {
|
|
var authzContext acl.AuthorizerContext
|
|
e.FillAuthzContext(&authzContext)
|
|
return authz.ToAllowAuthorizer().MeshReadAllowed(&authzContext)
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) CanWrite(authz acl.Authorizer) error {
|
|
var authzContext acl.AuthorizerContext
|
|
e.FillAuthzContext(&authzContext)
|
|
return authz.ToAllowAuthorizer().MeshWriteAllowed(&authzContext)
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) GetMeta() map[string]string {
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
return e.Meta
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) GetEnterpriseMeta() *acl.EnterpriseMeta {
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
return &e.EnterpriseMeta
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) GetRaftIndex() *RaftIndex {
|
|
if e == nil {
|
|
return &RaftIndex{}
|
|
}
|
|
return &e.RaftIndex
|
|
}
|
|
|
|
// HTTPMatch specifies the criteria that should be
|
|
// used in determining whether or not a request should
|
|
// be routed to a given set of services.
|
|
type HTTPMatch struct {
|
|
Headers []HTTPHeaderMatch
|
|
Method HTTPMatchMethod
|
|
Path HTTPPathMatch
|
|
Query []HTTPQueryMatch
|
|
}
|
|
|
|
// HTTPMatchMethod specifies which type of HTTP verb should
|
|
// be used for matching a given request.
|
|
type HTTPMatchMethod string
|
|
|
|
const (
|
|
HTTPMatchMethodAll HTTPMatchMethod = ""
|
|
HTTPMatchMethodConnect HTTPMatchMethod = "CONNECT"
|
|
HTTPMatchMethodDelete HTTPMatchMethod = "DELETE"
|
|
HTTPMatchMethodGet HTTPMatchMethod = "GET"
|
|
HTTPMatchMethodHead HTTPMatchMethod = "HEAD"
|
|
HTTPMatchMethodOptions HTTPMatchMethod = "OPTIONS"
|
|
HTTPMatchMethodPatch HTTPMatchMethod = "PATCH"
|
|
HTTPMatchMethodPost HTTPMatchMethod = "POST"
|
|
HTTPMatchMethodPut HTTPMatchMethod = "PUT"
|
|
HTTPMatchMethodTrace HTTPMatchMethod = "TRACE"
|
|
)
|
|
|
|
// HTTPHeaderMatchType specifies how header matching criteria
|
|
// should be applied to a request.
|
|
type HTTPHeaderMatchType string
|
|
|
|
const (
|
|
HTTPHeaderMatchExact HTTPHeaderMatchType = "exact"
|
|
HTTPHeaderMatchPrefix HTTPHeaderMatchType = "prefix"
|
|
HTTPHeaderMatchPresent HTTPHeaderMatchType = "present"
|
|
HTTPHeaderMatchRegularExpression HTTPHeaderMatchType = "regex"
|
|
HTTPHeaderMatchSuffix HTTPHeaderMatchType = "suffix"
|
|
)
|
|
|
|
// HTTPHeaderMatch specifies how a match should be done
|
|
// on a request's headers.
|
|
type HTTPHeaderMatch struct {
|
|
Match HTTPHeaderMatchType
|
|
Name string
|
|
Value string
|
|
}
|
|
|
|
// HTTPPathMatchType specifies how path matching criteria
|
|
// should be applied to a request.
|
|
type HTTPPathMatchType string
|
|
|
|
const (
|
|
HTTPPathMatchExact HTTPPathMatchType = "exact"
|
|
HTTPPathMatchPrefix HTTPPathMatchType = "prefix"
|
|
HTTPPathMatchRegularExpression HTTPPathMatchType = "regex"
|
|
)
|
|
|
|
// HTTPPathMatch specifies how a match should be done
|
|
// on a request's path.
|
|
type HTTPPathMatch struct {
|
|
Match HTTPPathMatchType
|
|
Value string
|
|
}
|
|
|
|
// HTTPQueryMatchType specifies how querys matching criteria
|
|
// should be applied to a request.
|
|
type HTTPQueryMatchType string
|
|
|
|
const (
|
|
HTTPQueryMatchExact HTTPQueryMatchType = "exact"
|
|
HTTPQueryMatchPresent HTTPQueryMatchType = "present"
|
|
HTTPQueryMatchRegularExpression HTTPQueryMatchType = "regex"
|
|
)
|
|
|
|
// HTTPQueryMatch specifies how a match should be done
|
|
// on a request's query parameters.
|
|
type HTTPQueryMatch struct {
|
|
Match HTTPQueryMatchType
|
|
Name string
|
|
Value string
|
|
}
|
|
|
|
// HTTPFilters specifies a list of filters used to modify a request
|
|
// before it is routed to an upstream.
|
|
type HTTPFilters struct {
|
|
Headers []HTTPHeaderFilter
|
|
}
|
|
|
|
// HTTPHeaderFilter specifies how HTTP headers should be modified.
|
|
type HTTPHeaderFilter struct {
|
|
Add map[string]string
|
|
Remove []string
|
|
Set map[string]string
|
|
}
|
|
|
|
// HTTPRouteRule specifies the routing rules used to determine what upstream
|
|
// service an HTTP request is routed to.
|
|
type HTTPRouteRule struct {
|
|
// Filters is a list of HTTP-based filters used to modify a request prior
|
|
// to routing it to the upstream service
|
|
Filters HTTPFilters
|
|
// Matches specified the matching criteria used in the routing table. If a
|
|
// request matches the given HTTPMatch configuration, then traffic is routed
|
|
// to services specified in the Services field.
|
|
Matches []HTTPMatch
|
|
// Services is a list of HTTP-based services to route to if the request matches
|
|
// the rules specified in the Matches field.
|
|
Services []HTTPService
|
|
}
|
|
|
|
// HTTPService is a service reference for HTTP-based routing rules
|
|
type HTTPService struct {
|
|
Name string
|
|
// Weight is an arbitrary integer used in calculating how much
|
|
// traffic should be sent to the given service.
|
|
Weight int
|
|
// Filters is a list of HTTP-based filters used to modify a request prior
|
|
// to routing it to the upstream service
|
|
Filters HTTPFilters
|
|
|
|
acl.EnterpriseMeta
|
|
}
|
|
|
|
var _ ControlledConfigEntry = (*HTTPRouteConfigEntry)(nil)
|
|
|
|
func (e *HTTPRouteConfigEntry) GetStatus() Status {
|
|
return e.Status
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) SetStatus(status Status) {
|
|
e.Status = status
|
|
}
|
|
|
|
func (e *HTTPRouteConfigEntry) DefaultStatus() Status {
|
|
return Status{}
|
|
}
|
|
|
|
// TCPRouteConfigEntry manages the configuration for a TCP route
|
|
// with the given name.
|
|
type TCPRouteConfigEntry struct {
|
|
// Kind of the config entry. This will be set to structs.TCPRoute.
|
|
Kind string
|
|
|
|
// Name is used to match the config entry with its associated set
|
|
// of resources.
|
|
Name string
|
|
|
|
// Parents is a list of gateways that this route should be bound to
|
|
Parents []ResourceReference
|
|
|
|
// Services is a list of TCP-based services that this should route to.
|
|
// Currently, this must specify at maximum one service.
|
|
Services []TCPService
|
|
|
|
Meta map[string]string `json:",omitempty"`
|
|
// Status is the asynchronous reconciliation status which a TCPRoute propagates to the user.
|
|
Status Status
|
|
acl.EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
|
|
RaftIndex
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) GetKind() string {
|
|
return TCPRoute
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) GetName() string {
|
|
if e == nil {
|
|
return ""
|
|
}
|
|
return e.Name
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) GetParents() []ResourceReference {
|
|
if e == nil {
|
|
return []ResourceReference{}
|
|
}
|
|
return e.Parents
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) GetProtocol() APIGatewayListenerProtocol {
|
|
return ListenerProtocolTCP
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) GetMeta() map[string]string {
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
return e.Meta
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) Normalize() error {
|
|
for i, parent := range e.Parents {
|
|
if parent.Kind == "" {
|
|
parent.Kind = APIGateway
|
|
e.Parents[i] = parent
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) Validate() error {
|
|
validParentKinds := map[string]bool{
|
|
APIGateway: true,
|
|
}
|
|
|
|
if len(e.Services) > 1 {
|
|
return fmt.Errorf("tcp-route currently only supports one service")
|
|
}
|
|
for _, parent := range e.Parents {
|
|
if !validParentKinds[parent.Kind] {
|
|
return fmt.Errorf("unsupported parent kind: %q, must be 'api-gateway'", parent.Kind)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) CanRead(authz acl.Authorizer) error {
|
|
var authzContext acl.AuthorizerContext
|
|
e.FillAuthzContext(&authzContext)
|
|
return authz.ToAllowAuthorizer().MeshReadAllowed(&authzContext)
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) CanWrite(authz acl.Authorizer) error {
|
|
var authzContext acl.AuthorizerContext
|
|
e.FillAuthzContext(&authzContext)
|
|
return authz.ToAllowAuthorizer().MeshWriteAllowed(&authzContext)
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) GetRaftIndex() *RaftIndex {
|
|
if e == nil {
|
|
return &RaftIndex{}
|
|
}
|
|
return &e.RaftIndex
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) GetEnterpriseMeta() *acl.EnterpriseMeta {
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
return &e.EnterpriseMeta
|
|
}
|
|
|
|
var _ ControlledConfigEntry = (*TCPRouteConfigEntry)(nil)
|
|
|
|
func (e *TCPRouteConfigEntry) GetStatus() Status {
|
|
return e.Status
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) SetStatus(status Status) {
|
|
e.Status = status
|
|
}
|
|
|
|
func (e *TCPRouteConfigEntry) DefaultStatus() Status {
|
|
return Status{}
|
|
}
|
|
|
|
// TCPService is a service reference for a TCPRoute
|
|
type TCPService struct {
|
|
Name string
|
|
// Weight specifies the proportion of requests forwarded to the referenced service.
|
|
// This is computed as weight/(sum of all weights in the list of services).
|
|
Weight int
|
|
|
|
acl.EnterpriseMeta
|
|
}
|