Documentation
¶
Index ¶
- Constants
- Variables
- func WriteKubeconfig(cfg *rest.Config, rootPath string) (string, error)
- type BaseSuite
- func (b *BaseSuite) BackendFromManifest(manifestPath, manifestName string) *models.Backend
- func (b *BaseSuite) CheckEntryInMapFile(mapFileRelativePath, key, value string) bool
- func (b *BaseSuite) CleanupFixtures(fixturePath string, manifestNames []string)
- func (b *BaseSuite) CleanupFixturesCheckMapFiles(fixturePath string, manifestNames []string, mapFileRelativePaths []string)
- func (b *BaseSuite) CleanupFixturesInNamespace(fixturePath, namespace string, manifestNames []string)
- func (b *BaseSuite) ConsistentlyNoReload(oldPid string, duration time.Duration)
- func (b *BaseSuite) CreateFixtures(fixturePath string, manifestNames []string)
- func (b *BaseSuite) CreateFixturesInNamespace(fixturePath, namespace string, manifestNames []string)
- func (b *BaseSuite) ExpectAttachedListenerSets(ctx context.Context, namespace, gwName string, expected int)
- func (b *BaseSuite) ExpectAttachedRoute(ctx context.Context, namespace, gwName, listenerName string, ...)
- func (b *BaseSuite) ExpectBackends(ctx context.Context, expectationPath string, expectedBackends []string)
- func (b *BaseSuite) ExpectBackendsDoNotExist(ctx context.Context, backendThatShouldNotExist string)
- func (b *BaseSuite) ExpectCertificates(ctx context.Context, expectedCerts []*models.SslCertificate)
- func (b *BaseSuite) ExpectCrtLists(ctx context.Context, expectedCrtLists map[futils.FilePath][]string)
- func (b *BaseSuite) ExpectCrtListsIdenticalModuloNaming(templateA, templateB string, differences ...NamingDifference)
- func (b *BaseSuite) ExpectFrontends(ctx context.Context, expectationPath string, expectedFrontends []string)
- func (b *BaseSuite) ExpectFrontendsIdenticalModuloNaming(templateA, templateB string, differences ...NamingDifference)
- func (*BaseSuite) ExpectListenerRouteMapContents(_ string)
- func (b *BaseSuite) ExpectListenerSetConditions(ctx context.Context, namespace, name string, expected []metav1.Condition)
- func (b *BaseSuite) ExpectListenerSetDeleted(ctx context.Context, namespace, name string)
- func (b *BaseSuite) ExpectListenerSetEntries(ctx context.Context, namespace, lsetName string, expected []string)
- func (b *BaseSuite) ExpectListenerSetEntryAttachedRoutes(ctx context.Context, namespace, lsetName, entryName string, expected int32)
- func (b *BaseSuite) ExpectListenerSetEntryConditions(ctx context.Context, namespace, lsetName, entryName string, ...)
- func (b *BaseSuite) ExpectListenerSetEntryHasCondition(ctx context.Context, namespace, lsetName, entryName string, ...)
- func (b *BaseSuite) ExpectListenerSetReportsNothing(ctx context.Context, namespace, name string)
- func (b *BaseSuite) ExpectMapContents(mapFilePath, expectedMapPath string)
- func (b *BaseSuite) ExpectMapEntryMentions(mapFileRelativePath, key string, mustMention, mustNotMention []string)
- func (b *BaseSuite) ExpectMapsIdenticalModuloNaming(templateA, templateB string, differences ...NamingDifference)
- func (b *BaseSuite) ExpectNoMapEntry(mapFileRelativePath, value string)
- func (b *BaseSuite) ExpectRouteConditionsUpdated(ctx context.Context, namespace, name string, ...)
- func (b *BaseSuite) ExpectRouteHasNoParent(ctx context.Context, namespace, routeName string, ...)
- func (b *BaseSuite) ExpectRouteParentHasCondition(ctx context.Context, namespace, routeName string, ...)
- func (b *BaseSuite) ExpectServers(backend string, expectedServers []string)
- func (b *BaseSuite) FrontendFromManifest(manifestPath, manifestName string) *models.Frontend
- func (b *BaseSuite) GetMapFileFrom(mapFileRelativePath string) ([]string, error)
- func (b *BaseSuite) IntTest() IntTest
- func (b *BaseSuite) SetupSuite(crdRelativePath string, levelsUp int, opts ...func(*IntTest))
- func (b *BaseSuite) TearDownSuite()
- func (b *BaseSuite) WaitForNoReloadsAnyMore(overAllDuration time.Duration, ...) string
- func (b *BaseSuite) YamlToConditions(yamlPath string) conditions.Conditions
- func (b *BaseSuite) YamlToListenerStatuses(yamlPath string) []gatewayv1.ListenerStatus
- func (b *BaseSuite) YamlToRouteConditions(yamlPath string) rc.RouteConditions
- type IntTest
- type NamingDifference
Constants ¶
const TestControllerName = "gate.haproxy.org/hug"
const (
TestMapThroughRuntime = true
)
Variables ¶
var RuntimeMaps = []string{
"domain_wildcard_sni.map",
"tcp_route.map",
"listener_exact_match.map",
"listener_route_exact_match.map",
"listener_route_wildcard_match.map",
"listener_wildcard_match.map",
"path_exact.map",
"path_prefix.map",
"path_regex.map",
"sni.map",
}
RuntimeMaps is the subset of StandardMaps that HAProxy loads via map() directives and are therefore accessible through the runtime socket. The three path maps are pre-loaded by no-op ACLs in haproxy.cfg so lua.find_route can reach them via core.get_patref.
var StandardMaps = []string{
"domain_wildcard_sni.map",
"listener_exact_match.map",
"listener_route_exact_match.map",
"listener_route_wildcard_match.map",
"listener_wildcard_match.map",
"path_exact.map",
"path_prefix.map",
"path_regex.map",
"sni.map",
"tcp_route.map",
}
Functions ¶
Types ¶
type BaseSuite ¶
func (*BaseSuite) BackendFromManifest ¶
func (*BaseSuite) CheckEntryInMapFile ¶ added in v0.8.0
func (*BaseSuite) CleanupFixtures ¶
func (*BaseSuite) CleanupFixturesCheckMapFiles ¶ added in v0.9.0
func (b *BaseSuite) CleanupFixturesCheckMapFiles(fixturePath string, manifestNames []string, mapFileRelativePaths []string)
CleanupFixturesCheckMapFiles is similar to CleanupFixtures, but it takes an additional argument mapFileRelativePath, which is the path to the map file that should be cleaned up. This is useful for tests that create a map file and then need to clean it up after the test has finished.
Note that CleanupFixturesCheckMapFiles will wait until the map file is empty before returning. This is to ensure that the test does not finish before the cleanup has finished.
func (*BaseSuite) CleanupFixturesInNamespace ¶
func (*BaseSuite) ConsistentlyNoReload ¶ added in v0.9.0
ConsistentlyNoReload executes a check repeatedly for a duration. It t.Fatalf() if the condition ever returns false.
func (*BaseSuite) CreateFixtures ¶
CreateFixtures will create all the objects from manifests that are in the fixturePath directory They are created in the test namespace To create in a specific namespace use CreateFixturesInNamespace If manifestNames is empty, it will create all objects that are in the directory If manifestNames, it will create only the objects in manifestNames (a sublist of the files in fixturePath)
func (*BaseSuite) CreateFixturesInNamespace ¶
func (*BaseSuite) ExpectAttachedListenerSets ¶ added in v1.1.0
func (b *BaseSuite) ExpectAttachedListenerSets(ctx context.Context, namespace, gwName string, expected int)
ExpectAttachedListenerSets waits for the number of ListenerSets a Gateway reports as attached, that is Gateway.status.attachedListenerSets. The field is optional and a pointer, so an absent one is read as zero: a Gateway that attaches none is not required to publish it at all.
func (*BaseSuite) ExpectAttachedRoute ¶ added in v0.9.0
func (*BaseSuite) ExpectBackends ¶
func (*BaseSuite) ExpectBackendsDoNotExist ¶
func (*BaseSuite) ExpectCertificates ¶
func (b *BaseSuite) ExpectCertificates(ctx context.Context, expectedCerts []*models.SslCertificate)
For now: only checks the following certificate fields: - StorageName - Subject (for CN) Check is performed using the RUNTIME command on haproxy
func (*BaseSuite) ExpectCrtLists ¶
func (b *BaseSuite) ExpectCrtLists(ctx context.Context, expectedCrtLists map[futils.FilePath][]string)
ExpectCrtLists checks that the crt-list are the expectedCrtLists For now, there is no CN method to get the content of the crt-list : "show ssl crt-list <filename>" The only existing method in CN is "show ssl crt-list" that gives the list of crt-lists So, for now, we check the content of the crt-list from the crt-list file, not from the RUNTIME.
func (*BaseSuite) ExpectCrtListsIdenticalModuloNaming ¶ added in v1.1.0
func (b *BaseSuite) ExpectCrtListsIdenticalModuloNaming(templateA, templateB string, differences ...NamingDifference)
ExpectCrtListsIdenticalModuloNaming fails unless the two frontends serve the same certificates, once the ports and the declared naming differences are canonicalised.
The crt-list is where termination is configured: for a case whose two sides terminate with a secret each, comparing the two lists is comparing what a TLS handshake on either port will offer. The paths they hold carry the secret's own namespace and name, so the two sides differ there by construction -- two Secrets cannot share a name in one namespace -- and the caller declares that pair like any other naming.
Both lists are required to be non-empty first: two frontends that serve nothing must not pass by being equally empty.
func (*BaseSuite) ExpectFrontends ¶
func (*BaseSuite) ExpectFrontendsIdenticalModuloNaming ¶ added in v1.1.0
func (b *BaseSuite) ExpectFrontendsIdenticalModuloNaming(templateA, templateB string, differences ...NamingDifference)
ExpectFrontendsIdenticalModuloNaming fails unless the two frontends the template names designate hold the same configuration, once the ports and the declared naming differences are canonicalised.
func (*BaseSuite) ExpectListenerRouteMapContents ¶ added in v1.0.3
ExpectListenerRouteMapContents is a no-op: listener maps are now per-frontend and are verified by ExpectMapContents for each frontend directory.
func (*BaseSuite) ExpectListenerSetConditions ¶ added in v1.1.0
func (b *BaseSuite) ExpectListenerSetConditions(ctx context.Context, namespace, name string, expected []metav1.Condition)
ExpectListenerSetConditions waits for the ListenerSet's own status.conditions.
func (*BaseSuite) ExpectListenerSetDeleted ¶ added in v1.1.0
ExpectListenerSetDeleted waits for the ListenerSet to be gone. What the deletion leaves behind -- the frontend that survives, the map entries that do not -- is asserted separately, by the map and frontend expectations.
func (*BaseSuite) ExpectListenerSetEntries ¶ added in v1.1.0
func (b *BaseSuite) ExpectListenerSetEntries(ctx context.Context, namespace, lsetName string, expected []string)
ExpectListenerSetEntries waits for the exact set of entry names a ListenerSet reports, which is how a case asserts that an entry reported as invalid is still reported -- the API asks for an entry per listener, not per valid listener.
func (*BaseSuite) ExpectListenerSetEntryAttachedRoutes ¶ added in v1.1.0
func (b *BaseSuite) ExpectListenerSetEntryAttachedRoutes(ctx context.Context, namespace, lsetName, entryName string, expected int32)
ExpectListenerSetEntryAttachedRoutes waits for the attachedRoutes an entry reports.
func (*BaseSuite) ExpectListenerSetEntryConditions ¶ added in v1.1.0
func (b *BaseSuite) ExpectListenerSetEntryConditions(ctx context.Context, namespace, lsetName, entryName string, expected []metav1.Condition)
ExpectListenerSetEntryConditions waits for the conditions of one entry of a ListenerSet, that is status.listeners[].conditions, addressed by entry name. The set is compared exactly.
func (*BaseSuite) ExpectListenerSetEntryHasCondition ¶ added in v1.1.0
func (b *BaseSuite) ExpectListenerSetEntryHasCondition(ctx context.Context, namespace, lsetName, entryName string, expected metav1.Condition)
ExpectListenerSetEntryHasCondition waits for one condition of an entry to be present, whatever the entry's other conditions are.
func (*BaseSuite) ExpectListenerSetReportsNothing ¶ added in v1.1.0
ExpectListenerSetReportsNothing waits for a ListenerSet to carry nothing but the conditions the API itself seeded, and no entry at all.
"Nothing published" cannot be asserted as an absence of conditions: the ListenerSet CRD declares a default status of Accepted and Programmed, both Unknown with the reason Pending and the message "Waiting for controller", so a freshly created ListenerSet already carries them and a controller that stays silent leaves them exactly as they are. Silence is therefore observable as those placeholders surviving untouched, which is also a sharper assertion than an absence: any write of ours moves observedGeneration to the object's generation and replaces the reason.
As with any assertion of silence, the case has to establish that the object was processed: pair it with a second ListenerSet whose status is published, and wait for that one first.
func (*BaseSuite) ExpectMapContents ¶ added in v0.9.0
func (*BaseSuite) ExpectMapEntryMentions ¶ added in v1.1.0
func (b *BaseSuite) ExpectMapEntryMentions(mapFileRelativePath, key string, mustMention, mustNotMention []string)
ExpectMapEntryMentions waits for the line of a map file whose key is `key` to mention every value of mustMention and none of mustNotMention.
What it asserts is attribution, which is what a value carries when several resources share a port: the frontends are keyed on the port, so a listener that moves from one Gateway to another keeps its line in the same map -- under the new Gateway's key. Asserting the entry's absence there would be asserting the frontend had gone, which is a different question.
func (*BaseSuite) ExpectMapsIdenticalModuloNaming ¶ added in v1.1.0
func (b *BaseSuite) ExpectMapsIdenticalModuloNaming(templateA, templateB string, differences ...NamingDifference)
ExpectMapsIdenticalModuloNaming fails unless every standard map of the two frontends holds the same entries, once the ports and the declared naming differences are canonicalised.
The maps are where the routing lives: the hostname-to-listener table, the listener/route table and the SNI table are what a request is resolved through, and comparing them is comparing what the two listeners actually serve.
The listener maps are required to be non-empty on both sides first, so that two frontends which programmed nothing cannot pass by being equally empty.
func (*BaseSuite) ExpectNoMapEntry ¶ added in v1.1.0
ExpectNoMapEntry waits for no line of a map file to mention the given value.
This is what a purge is asserted with, on a frontend that survives: reading the file tells the entries a deleted object had filled apart from a frontend that was simply destroyed with its maps.
func (*BaseSuite) ExpectRouteConditionsUpdated ¶ added in v0.9.0
func (*BaseSuite) ExpectRouteHasNoParent ¶ added in v1.1.0
func (b *BaseSuite) ExpectRouteHasNoParent(ctx context.Context, namespace, routeName string, parent gatewayv1.ParentReference)
ExpectRouteHasNoParent waits for a route to publish no status for a given parent.
It is the mirror of ExpectRouteParentHasCondition and has the same blind spot in reverse: "no entry" is true before the controller has looked at the route, so a case that asserts it must first wait for another parent of the same route to be published. The pair is what makes the absence a statement about the controller rather than about the test's timing.
func (*BaseSuite) ExpectRouteParentHasCondition ¶ added in v1.1.0
func (b *BaseSuite) ExpectRouteParentHasCondition(ctx context.Context, namespace, routeName string, parent gatewayv1.ParentReference, expected metav1.Condition)
ExpectRouteParentHasCondition waits for one route to carry a condition on a given parent, and asserts it by presence rather than by set.
The exact set a route publishes for a parent is assembled by two passes -- the parentRef check, then the resolution of its rules' references -- so which conditions accompany the one asserted here is not something a caller should have to know. The parent is identified by kind, name and sectionName, which is also what says *which* parent the route blamed: a refusal that names a ListenerSet is a different claim from one that names its Gateway.
func (*BaseSuite) ExpectServers ¶ added in v0.9.0
func (*BaseSuite) FrontendFromManifest ¶
func (*BaseSuite) GetMapFileFrom ¶ added in v0.8.0
func (*BaseSuite) SetupSuite ¶
func (*BaseSuite) TearDownSuite ¶
func (b *BaseSuite) TearDownSuite()
func (*BaseSuite) WaitForNoReloadsAnyMore ¶ added in v0.9.0
func (b *BaseSuite) WaitForNoReloadsAnyMore( overAllDuration time.Duration, consistentlyDurationWithoutReloads time.Duration, ) string
WaitForNoReloadsAnyMore checks during an overall overAllDuration That we reach a stable state without reloads for at least consistentlyDurationWithoutReloads We set a timer stabilityTimer and if at any point during the stability window a reload occurs, we reset this timer. If we reach the overAllDuration without a stable window without reload we issue a t.Fatalf()
func (*BaseSuite) YamlToConditions ¶
func (b *BaseSuite) YamlToConditions(yamlPath string) conditions.Conditions
func (*BaseSuite) YamlToListenerStatuses ¶
func (b *BaseSuite) YamlToListenerStatuses(yamlPath string) []gatewayv1.ListenerStatus
func (*BaseSuite) YamlToRouteConditions ¶
func (b *BaseSuite) YamlToRouteConditions(yamlPath string) rc.RouteConditions
type IntTest ¶
type IntTest struct {
Ctx context.Context
Client ctrlruntimeclient.Client
RuntimeClient runtime.Runtime
HaproxyClient hapapi.HAProxyClient
TestEnv *envtest.Environment
PortMap map[int]int // template port → unique ephemeral port for this test run
Namespace string
HaproxyCfgDir string
RuntimeSocketPath string
PIDFilePath string
// EnableIngress opts the controller under test into Kubernetes Ingress
// support. Off by default so suites that don't exercise Ingress do not get
// the synthetic gateway's extra frontends.
EnableIngress bool
// GWAPICompat switches backendless-rule responses from the legacy 404
// to the spec-mandated 500.
GWAPICompat bool
// contains filtered or unexported fields
}
func NewIntTest ¶
func (*IntTest) StartTestEnv ¶
func (*IntTest) StopHaproxy ¶ added in v0.9.1
func (*IntTest) StopTestEnv ¶
type NamingDifference ¶ added in v1.1.0
type NamingDifference [2]string
NamingDifference is one difference a parity comparison tolerates: two names that denote the same thing on either side -- the resource each frontend belongs to, or the route that feeds each of them when they are distinct objects. Every member is rewritten to the same placeholder before comparing.
The first pair a caller passes is the pair of declaring resources, and both members must be present in their own document: a frontend that lost the origin it was programmed for is a defect of its own, and it must not pass by having nothing left to compare.