Documentation ¶
Index ¶
- Constants
- Variables
- func GetClassStatus(existing *k8sv1.GatewayClassStatus, gen int64) k8sv1.GatewayClassStatus
- func IsManaged(gw *k8s.GatewaySpec) bool
- func ManagedGatewayControllerVersion(gw gateway.Gateway) (existing string, takeOver bool, manage bool)
- func NewUntypedWrapper[T controllers.ComparableObject](c kclient.Client[T]) getter
- type AllowedReferences
- type ClassController
- type ConfigError
- type ConfigErrorReason
- type Controller
- func (c *Controller) Create(config config.Config) (revision string, err error)
- func (c *Controller) Delete(typ config.GroupVersionKind, name, namespace string, _ *string) error
- func (c *Controller) Get(typ config.GroupVersionKind, name, namespace string) *config.Config
- func (c *Controller) HasSynced() bool
- func (c *Controller) List(typ config.GroupVersionKind, namespace string) []config.Config
- func (c *Controller) Patch(orig config.Config, patchFn config.PatchFunc) (string, error)
- func (c *Controller) QueueStatusUpdates(r GatewayResources)
- func (c *Controller) Reconcile(ps *model.PushContext) error
- func (c *Controller) RegisterEventHandler(typ config.GroupVersionKind, handler model.EventHandler)
- func (c *Controller) Run(stop <-chan struct{})
- func (c *Controller) Schemas() collection.Schemas
- func (c *Controller) SecretAllowed(resourceName string, namespace string) bool
- func (c *Controller) SetStatusWrite(enabled bool, statusManager *status.Manager)
- func (c *Controller) Update(config config.Config) (newRevision string, err error)
- func (c *Controller) UpdateStatus(config config.Config) (newRevision string, err error)
- type DeploymentController
- type GatewayContext
- type GatewayResources
- type Grants
- type IstioResources
- type ParentError
- type ParentErrorReason
- type Reference
- type RouteParentResult
- type TemplateInput
- type UntypedWrapper
Constants ¶
const ( ParentErrorNotAccepted = ParentErrorReason(k8s.RouteReasonNoMatchingParent) ParentErrorNotAllowed = ParentErrorReason(k8s.RouteReasonNotAllowedByListeners) ParentErrorNoHostname = ParentErrorReason(k8s.RouteReasonNoMatchingListenerHostname) ParentErrorParentRefConflict = ParentErrorReason("ParentRefConflict") ParentNoError = ParentErrorReason("") )
const ( // ControllerVersionAnnotation is an annotation added to the Gateway by the controller specifying // the "controller version". The original intent of this was to work around // https://github.com/istio/istio/issues/44164, where we needed to transition from a global owner // to a per-revision owner. The newer version number allows forcing ownership, even if the other // version was otherwise expected to control the Gateway. // The version number has no meaning other than "larger numbers win". // Numbers are used to future-proof in case we need to do another migration in the future. ControllerVersionAnnotation = "gateway.istio.io/controller-version" // ControllerVersion is the current version of our controller logic. Known versions are: // // * 1.17 and older: version 1 OR no version at all, depending on patch release // * 1.18+: version 5 // // 2, 3, and 4 were intentionally skipped to allow for the (unlikely) event we need to insert // another version between these ControllerVersion = 5 )
const NamespaceNameLabel = "kubernetes.io/metadata.name"
NamespaceNameLabel represents that label added automatically to namespaces is newer Kubernetes clusters
Variables ¶
var SupportedFeatures = features.AllFeatures
Functions ¶
func GetClassStatus ¶
func GetClassStatus(existing *k8sv1.GatewayClassStatus, gen int64) k8sv1.GatewayClassStatus
func IsManaged ¶
func IsManaged(gw *k8s.GatewaySpec) bool
IsManaged checks if a Gateway is managed (ie we create the Deployment and Service) or unmanaged. This is based on the address field of the spec. If address is set with a Hostname type, it should point to an existing Service that handles the gateway traffic. If it is not set, or refers to only a single IP, we will consider it managed and provision the Service. If there is an IP, we will set the `loadBalancerIP` type. While there is no defined standard for this in the API yet, it is tracked in https://github.com/kubernetes-sigs/gateway-api/issues/892. So far, this mirrors how out of clusters work (address set means to use existing IP, unset means to provision one), and there has been growing consensus on this model for in cluster deployments.
Currently, the supported options are: * 1 Hostname value. This can be short Service name ingress, or FQDN ingress.ns.svc.cluster.local, example.com. If its a non-k8s FQDN it is a ServiceEntry. * 1 IP address. This is managed, with IP explicit * Nothing. This is managed, with IP auto assigned
Not supported: Multiple hostname/IP - It is feasible but preference is to create multiple Gateways. This would also break the 1:1 mapping of GW:Service Mixed hostname and IP - doesn't make sense; user should define the IP in service NamedAddress - Service has no concept of named address. For cloud's that have named addresses they can be configured by annotations,
which users can add to the Gateway.
func ManagedGatewayControllerVersion ¶
func ManagedGatewayControllerVersion(gw gateway.Gateway) (existing string, takeOver bool, manage bool)
ManagedGatewayControllerVersion determines the version of the controller managing this Gateway, and if we should manage this. See ControllerVersionAnnotation for motivations.
func NewUntypedWrapper ¶
func NewUntypedWrapper[T controllers.ComparableObject](c kclient.Client[T]) getter
Types ¶
type AllowedReferences ¶
func (AllowedReferences) BackendAllowed ¶
func (refs AllowedReferences) BackendAllowed( k config.GroupVersionKind, backendName k8s.ObjectName, backendNamespace k8s.Namespace, routeNamespace string, ) bool
func (AllowedReferences) SecretAllowed ¶
func (refs AllowedReferences) SecretAllowed(resourceName string, namespace string) bool
type ClassController ¶
type ClassController struct {
// contains filtered or unexported fields
}
ClassController is a controller that creates the default Istio GatewayClass(s). This will not continually reconcile the full state of the GatewayClass object, and instead only create the class if it doesn't exist. This allows users to manage it through other means or modify it as they wish. If it is deleted, however, it will be added back. This controller intentionally does not do leader election for simplicity. Because we only create and not update there is no need; the first controller to create the GatewayClass wins.
func NewClassController ¶
func NewClassController(kc kube.Client) *ClassController
func (*ClassController) Reconcile ¶
func (c *ClassController) Reconcile(types.NamespacedName) error
func (*ClassController) Run ¶
func (c *ClassController) Run(stop <-chan struct{})
type ConfigError ¶
type ConfigError struct { Reason ConfigErrorReason Message string }
ConfigError represents an invalid configuration that will be reported back to the user.
type ConfigErrorReason ¶
type ConfigErrorReason = string
const ( // InvalidRefNotPermitted indicates a route was not permitted InvalidRefNotPermitted ConfigErrorReason = ConfigErrorReason(k8s.RouteReasonRefNotPermitted) // InvalidDestination indicates an issue with the destination InvalidDestination ConfigErrorReason = "InvalidDestination" InvalidAddress ConfigErrorReason = ConfigErrorReason(k8s.GatewayReasonUnsupportedAddress) // InvalidDestinationPermit indicates a destination was not permitted InvalidDestinationPermit ConfigErrorReason = ConfigErrorReason(k8s.RouteReasonRefNotPermitted) // InvalidDestinationKind indicates an issue with the destination kind InvalidDestinationKind ConfigErrorReason = ConfigErrorReason(k8s.RouteReasonInvalidKind) // InvalidDestinationNotFound indicates a destination does not exist InvalidDestinationNotFound ConfigErrorReason = ConfigErrorReason(k8s.RouteReasonBackendNotFound) // InvalidParentRef indicates we could not refer to the parent we request InvalidParentRef ConfigErrorReason = "InvalidParentReference" // InvalidFilter indicates an issue with the filters InvalidFilter ConfigErrorReason = "InvalidFilter" // InvalidTLS indicates an issue with TLS settings InvalidTLS ConfigErrorReason = ConfigErrorReason(k8s.ListenerReasonInvalidCertificateRef) // InvalidListenerRefNotPermitted indicates a listener reference was not permitted InvalidListenerRefNotPermitted ConfigErrorReason = ConfigErrorReason(k8s.ListenerReasonRefNotPermitted) // InvalidConfiguration indicates a generic error for all other invalid configurations InvalidConfiguration ConfigErrorReason = "InvalidConfiguration" InvalidResources ConfigErrorReason = ConfigErrorReason(k8s.GatewayReasonNoResources) DeprecateFieldUsage = "DeprecatedField" )
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller defines the controller for the gateway-api. The controller acts a bit different from most. Rather than watching the CRs directly, we depend on the existing model.ConfigStoreController which already watches all CRs. When there are updates, a new PushContext will be computed, which will eventually call Controller.Reconcile(). Once this happens, we will inspect the current state of the world, and transform gateway-api types into Istio types (Gateway/VirtualService). Future calls to Get/List will return these Istio types. These are not stored in the cluster at all, and are purely internal; they can be seen on /debug/configz. During Reconcile(), the status on all gateway-api types is also tracked. Once completed, if the status has changed at all, it is queued to asynchronously update the status of the object in Kubernetes.
func NewController ¶
func NewController( kc kube.Client, c model.ConfigStoreController, waitForCRD func(class schema.GroupVersionResource, stop <-chan struct{}) bool, credsController credentials.MulticlusterController, options controller.Options, ) *Controller
func (*Controller) Create ¶
func (c *Controller) Create(config config.Config) (revision string, err error)
func (*Controller) Delete ¶
func (c *Controller) Delete(typ config.GroupVersionKind, name, namespace string, _ *string) error
func (*Controller) Get ¶
func (c *Controller) Get(typ config.GroupVersionKind, name, namespace string) *config.Config
func (*Controller) HasSynced ¶
func (c *Controller) HasSynced() bool
func (*Controller) List ¶
func (c *Controller) List(typ config.GroupVersionKind, namespace string) []config.Config
func (*Controller) QueueStatusUpdates ¶
func (c *Controller) QueueStatusUpdates(r GatewayResources)
func (*Controller) Reconcile ¶
func (c *Controller) Reconcile(ps *model.PushContext) error
Reconcile takes in a current snapshot of the gateway-api configs, and regenerates our internal state. Any status updates required will be enqueued as well.
func (*Controller) RegisterEventHandler ¶
func (c *Controller) RegisterEventHandler(typ config.GroupVersionKind, handler model.EventHandler)
func (*Controller) Run ¶
func (c *Controller) Run(stop <-chan struct{})
func (*Controller) Schemas ¶
func (c *Controller) Schemas() collection.Schemas
func (*Controller) SecretAllowed ¶
func (c *Controller) SecretAllowed(resourceName string, namespace string) bool
func (*Controller) SetStatusWrite ¶
func (c *Controller) SetStatusWrite(enabled bool, statusManager *status.Manager)
func (*Controller) Update ¶
func (c *Controller) Update(config config.Config) (newRevision string, err error)
func (*Controller) UpdateStatus ¶
func (c *Controller) UpdateStatus(config config.Config) (newRevision string, err error)
type DeploymentController ¶
type DeploymentController struct {
// contains filtered or unexported fields
}
DeploymentController implements a controller that materializes a Gateway into an in cluster gateway proxy to serve requests from. This is implemented with a Deployment and Service today. The implementation makes a few non-obvious choices - namely using Server Side Apply from go templates and not using controller-runtime.
controller-runtime has a number of constraints that make it inappropriate for usage here, despite this seeming to be the bread and butter of the library: * It is not readily possible to bring existing Informers, which would require extra watches (#1668) * Goroutine leaks (#1655) * Excessive API-server calls at startup which have no benefit to us (#1603) * Hard to use with SSA (#1669) While these can be worked around, at some point it isn't worth the effort.
Server Side Apply with go templates is an odd choice (no one likes YAML templating...) but is one of the few remaining options after all others are ruled out.
- Merge patch/Update cannot be used. If we always enforce that our object is *exactly* the same as the in-cluster object we will get in endless loops due to other controllers that like to add annotations, etc. If we chose to allow any unknown fields, then we would never be able to remove fields we added, as we cannot tell if we created it or someone else did. SSA fixes these issues
- SSA using client-go Apply libraries is almost a good choice, but most third-party clients (Istio, MCS, and gateway-api) do not provide these libraries.
- SSA using standard API types doesn't work well either: https://github.com/kubernetes-sigs/controller-runtime/issues/1669
- This leaves YAML templates, converted to unstructured types and Applied with the dynamic client.
func NewDeploymentController ¶
func NewDeploymentController(client kube.Client, clusterID cluster.ID, env *model.Environment, webhookConfig func() inject.WebhookConfig, injectionHandler func(fn func()), tw revisions.TagWatcher, revision string, ) *DeploymentController
NewDeploymentController constructs a DeploymentController and registers required informers. The controller will not start until Run() is called.
func (*DeploymentController) HandleTagChange ¶
func (d *DeploymentController) HandleTagChange(newTags sets.String)
func (*DeploymentController) Reconcile ¶
func (d *DeploymentController) Reconcile(req types.NamespacedName) error
Reconcile takes in the name of a Gateway and ensures the cluster is in the desired state
func (*DeploymentController) Run ¶
func (d *DeploymentController) Run(stop <-chan struct{})
type GatewayContext ¶
type GatewayContext struct {
// contains filtered or unexported fields
}
GatewayContext contains a minimal subset of push context functionality to be exposed to GatewayAPIControllers
func NewGatewayContext ¶
func NewGatewayContext(ps *model.PushContext, cluster cluster.ID) GatewayContext
func (GatewayContext) GetService ¶
func (gc GatewayContext) GetService(hostname, namespace string) *model.Service
func (GatewayContext) ResolveGatewayInstances ¶
func (gc GatewayContext) ResolveGatewayInstances( namespace string, gwsvcs []string, servers []*networking.Server, ) (internal, internalIP, external, pending, warns []string, allUsable bool)
ResolveGatewayInstances attempts to resolve all instances that a gateway will be exposed on. Note: this function considers *all* instances of the service; its possible those instances will not actually be properly functioning gateways, so this is not 100% accurate, but sufficient to expose intent to users. The actual configuration generation is done on a per-workload basis and will get the exact set of matched instances for that workload. Four sets are exposed: * Internal addresses (eg istio-ingressgateway.istio-system.svc.cluster.local:80). * Internal IP addresses (eg 1.2.3.4). This comes from ClusterIP. * External addresses (eg 1.2.3.4), this comes from LoadBalancer services. There may be multiple in some cases (especially multi cluster). * Pending addresses (eg istio-ingressgateway.istio-system.svc), are LoadBalancer-type services with pending external addresses. * Warnings for references that could not be resolved. These are intended to be user facing.
type GatewayResources ¶
type GatewayResources struct { GatewayClass []config.Config Gateway []config.Config HTTPRoute []config.Config GRPCRoute []config.Config TCPRoute []config.Config TLSRoute []config.Config ReferenceGrant []config.Config ServiceEntry []config.Config // Namespaces stores all namespace in the cluster, keyed by name Namespaces map[string]*corev1.Namespace // Credentials stores all credentials in the cluster Credentials credentials.Controller // Domain for the cluster. Typically, cluster.local Domain string Context GatewayContext }
GatewayResources stores all gateway resources used for our conversion.
func (GatewayResources) FuzzValidate ¶
func (kr GatewayResources) FuzzValidate() bool
type IstioResources ¶
type IstioResources struct { Gateway []config.Config VirtualService []config.Config // AllowedReferences stores all allowed references, from Reference -> to Reference(s) AllowedReferences AllowedReferences // ReferencedNamespaceKeys stores the label key of all namespace selections. This allows us to quickly // determine if a namespace update could have impacted any Gateways. See namespaceEvent. ReferencedNamespaceKeys sets.String // ResourceReferences stores all resources referenced by gateway-api resources. This allows us to quickly // determine if a resource update could have impacted any Gateways. // key: referenced resources(e.g. secrets), value: gateway-api resources(e.g. gateways) ResourceReferences map[model.ConfigKey][]model.ConfigKey }
IstioResources stores all outputs of our conversion
type ParentError ¶
type ParentError struct { Reason ParentErrorReason Message string }
ParentError represents that a parent could not be referenced
type ParentErrorReason ¶
type ParentErrorReason string
type Reference ¶
type Reference struct { Kind config.GroupVersionKind Namespace k8s.Namespace }
Reference stores a reference to a namespaced GVK, as used by ReferencePolicy
type RouteParentResult ¶
type RouteParentResult struct { // OriginalReference contains the original reference OriginalReference k8s.ParentReference // DeniedReason, if present, indicates why the reference was not valid DeniedReason *ParentError // RouteError, if present, indicates why the reference was not valid RouteError *ConfigError }
RouteParentResult holds the result of a route for a specific parent
type TemplateInput ¶
type TemplateInput struct { *gateway.Gateway DeploymentName string ServiceAccount string Ports []corev1.ServicePort ServiceType corev1.ServiceType ClusterID string KubeVersion int Revision string ProxyUID int64 ProxyGID int64 CompliancePolicy string InfrastructureLabels map[string]string InfrastructureAnnotations map[string]string GatewayNameLabel string }
type UntypedWrapper ¶
type UntypedWrapper[T controllers.ComparableObject] struct { // contains filtered or unexported fields }
UntypedWrapper wraps a typed reader to an untyped one, since Go cannot do it automatically.
func (UntypedWrapper[T]) Get ¶
func (u UntypedWrapper[T]) Get(name, namespace string) controllers.Object