├── .aspell.yml
├── .check-commit.yml
├── .dockerignore
├── .github
├── stale.yml
└── workflows
│ ├── .goreleaser.yml
│ ├── actions.yml
│ ├── docker_auto_release.yml
│ ├── docker_description.yml
│ ├── docker_manual_release.yml
│ └── docker_nightly.yml
├── .gitignore
├── .gitlab-ci.yml
├── .gitlab
└── kind-config.yaml
├── .golangci.yml
├── .goreleaser.yml
├── LICENSE
├── Makefile
├── Makefile.ci
├── README.md
├── assets
├── images
│ └── haproxy-weblogo-210x49.png
└── license-header.txt
├── bin
├── check-commit.sh
└── lint-check.sh
├── build
├── Dockerfile
├── Dockerfile.dev
└── Dockerfile.pebble
├── cmd
└── linters
│ └── main.go
├── crs
├── README.md
├── api
│ └── ingress
│ │ ├── v1
│ │ ├── backend.go
│ │ ├── defaults.go
│ │ ├── doc.go
│ │ ├── global.go
│ │ ├── tcp.go
│ │ ├── zz_generated.deepcopy.go
│ │ └── zz_generated.register.go
│ │ └── v3
│ │ ├── backend.go
│ │ ├── defaults.go
│ │ ├── doc.go
│ │ ├── global.go
│ │ ├── tcp.go
│ │ ├── zz_generated.deepcopy.go
│ │ └── zz_generated.register.go
├── code-generator.sh
├── controller-gen
│ └── version_check_test.go
├── converters
│ ├── backend-spec.go
│ ├── defaults-spec.go
│ ├── global-spec.go
│ ├── tcp-spec.go
│ └── v1v3
│ │ └── convert.go
├── definition
│ ├── embed.go
│ ├── ingress.v1.haproxy.org_backends.yaml
│ ├── ingress.v1.haproxy.org_defaults.yaml
│ ├── ingress.v1.haproxy.org_globals.yaml
│ ├── ingress.v1.haproxy.org_tcps.yaml
│ ├── ingress.v3.haproxy.org_backends.yaml
│ ├── ingress.v3.haproxy.org_defaults.yaml
│ ├── ingress.v3.haproxy.org_globals.yaml
│ └── ingress.v3.haproxy.org_tcps.yaml
├── generated
│ └── api
│ │ └── ingress
│ │ ├── v1
│ │ ├── clientset
│ │ │ └── versioned
│ │ │ │ ├── clientset.go
│ │ │ │ ├── fake
│ │ │ │ ├── clientset_generated.go
│ │ │ │ ├── doc.go
│ │ │ │ └── register.go
│ │ │ │ ├── scheme
│ │ │ │ ├── doc.go
│ │ │ │ └── register.go
│ │ │ │ └── typed
│ │ │ │ └── ingress
│ │ │ │ └── v1
│ │ │ │ ├── backend.go
│ │ │ │ ├── defaults.go
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake_backend.go
│ │ │ │ ├── fake_defaults.go
│ │ │ │ ├── fake_global.go
│ │ │ │ ├── fake_ingress_client.go
│ │ │ │ └── fake_tcp.go
│ │ │ │ ├── generated_expansion.go
│ │ │ │ ├── global.go
│ │ │ │ ├── ingress_client.go
│ │ │ │ └── tcp.go
│ │ ├── informers
│ │ │ └── externalversions
│ │ │ │ ├── factory.go
│ │ │ │ ├── generic.go
│ │ │ │ ├── ingress
│ │ │ │ ├── interface.go
│ │ │ │ └── v1
│ │ │ │ │ ├── backend.go
│ │ │ │ │ ├── defaults.go
│ │ │ │ │ ├── global.go
│ │ │ │ │ ├── interface.go
│ │ │ │ │ └── tcp.go
│ │ │ │ └── internalinterfaces
│ │ │ │ └── factory_interfaces.go
│ │ └── listers
│ │ │ └── ingress
│ │ │ ├── v1
│ │ │ ├── backend.go
│ │ │ ├── defaults.go
│ │ │ ├── expansion_generated.go
│ │ │ ├── global.go
│ │ │ └── tcp.go
│ │ │ └── v3
│ │ │ ├── backend.go
│ │ │ ├── defaults.go
│ │ │ ├── expansion_generated.go
│ │ │ ├── global.go
│ │ │ └── tcp.go
│ │ └── v3
│ │ ├── clientset
│ │ └── versioned
│ │ │ ├── clientset.go
│ │ │ ├── fake
│ │ │ ├── clientset_generated.go
│ │ │ ├── doc.go
│ │ │ └── register.go
│ │ │ ├── scheme
│ │ │ ├── doc.go
│ │ │ └── register.go
│ │ │ └── typed
│ │ │ └── ingress
│ │ │ └── v3
│ │ │ ├── backend.go
│ │ │ ├── defaults.go
│ │ │ ├── doc.go
│ │ │ ├── fake
│ │ │ ├── doc.go
│ │ │ ├── fake_backend.go
│ │ │ ├── fake_defaults.go
│ │ │ ├── fake_global.go
│ │ │ ├── fake_ingress_client.go
│ │ │ └── fake_tcp.go
│ │ │ ├── generated_expansion.go
│ │ │ ├── global.go
│ │ │ ├── ingress_client.go
│ │ │ └── tcp.go
│ │ ├── informers
│ │ └── externalversions
│ │ │ ├── factory.go
│ │ │ ├── generic.go
│ │ │ ├── ingress
│ │ │ ├── interface.go
│ │ │ └── v3
│ │ │ │ ├── backend.go
│ │ │ │ ├── defaults.go
│ │ │ │ ├── global.go
│ │ │ │ ├── interface.go
│ │ │ │ └── tcp.go
│ │ │ └── internalinterfaces
│ │ │ └── factory_interfaces.go
│ │ └── listers
│ │ └── ingress
│ │ ├── v1
│ │ ├── backend.go
│ │ ├── defaults.go
│ │ ├── expansion_generated.go
│ │ ├── global.go
│ │ └── tcp.go
│ │ └── v3
│ │ ├── backend.go
│ │ ├── defaults.go
│ │ ├── expansion_generated.go
│ │ ├── global.go
│ │ └── tcp.go
└── remove-fields-from-crds.sh
├── deploy
├── haproxy-ingress-daemonset.yaml
├── haproxy-ingress.yaml
├── kustomization.yaml
└── tests
│ ├── README.md
│ ├── config
│ ├── 0.namespace.yaml
│ ├── 1.rbac.yaml
│ ├── 2.2.ingressclass.yaml
│ ├── 2.configmap.yaml
│ ├── 3.ingress-controller.yaml
│ ├── crd
│ │ ├── job-crd.yaml
│ │ └── rbac.yaml
│ ├── echo-app.yaml
│ └── experimental
│ │ ├── gwapi-echo-app.yaml
│ │ ├── gwapi-rbac.yaml
│ │ ├── gwapi-resources.yaml
│ │ └── gwapi.experimental.yaml
│ ├── create.sh
│ ├── delete.sh
│ ├── e2e
│ ├── access-control
│ │ ├── access_control_test.go
│ │ ├── config
│ │ │ ├── deploy.yaml.tmpl
│ │ │ ├── patternfile-a.yml
│ │ │ └── patternfile-empty.yml
│ │ └── suite_test.go
│ ├── admin-port
│ │ ├── pprof_test.go
│ │ └── suite_test.go
│ ├── basic-auth
│ │ ├── basic_auth_test.go
│ │ ├── config
│ │ │ └── deploy.yaml.tmpl
│ │ └── suite_test.go
│ ├── canary-deployment
│ │ ├── config
│ │ │ └── deploy.yaml.tmpl
│ │ ├── percentage_test.go
│ │ └── suite_test.go
│ ├── client.go
│ ├── config-snippet
│ │ ├── backend_cfg_snippet_test.go
│ │ ├── config
│ │ │ ├── backend-cfg-snippet.yaml
│ │ │ ├── configmap.yaml
│ │ │ └── deploy.yaml.tmpl
│ │ ├── frontend_cfg_snippet_test.go
│ │ └── suite_test.go
│ ├── cookie-persistence
│ │ ├── config
│ │ │ └── deploy.yml.tmpl
│ │ ├── cookie-persistence_test.go
│ │ └── suite_test.go
│ ├── cors
│ │ ├── config
│ │ │ ├── configmap.yaml.tmpl
│ │ │ └── deploy.yaml.tmpl
│ │ ├── cors_test.go
│ │ └── suite_test.go
│ ├── crd-tcp
│ │ ├── config
│ │ │ ├── crd-v1
│ │ │ │ ├── backend-cr.yaml
│ │ │ │ ├── tcp-cr-add-services.yaml
│ │ │ │ ├── tcp-cr-backend-switching-rule-acls.yaml
│ │ │ │ ├── tcp-cr-backend-switching-rule.yaml
│ │ │ │ ├── tcp-cr-full.yaml
│ │ │ │ ├── tcp-cr-no-ingress-class.yaml
│ │ │ │ ├── tcp-cr-ssl.yaml
│ │ │ │ └── tcp-cr.yaml
│ │ │ ├── crd-v3
│ │ │ │ ├── backend-cr.yaml
│ │ │ │ ├── tcp-cr-add-services.yaml
│ │ │ │ ├── tcp-cr-backend-switching-rule-acls.yaml
│ │ │ │ ├── tcp-cr-backend-switching-rule.yaml
│ │ │ │ ├── tcp-cr-full.yaml
│ │ │ │ ├── tcp-cr-no-ingress-class.yaml
│ │ │ │ ├── tcp-cr-ssl.yaml
│ │ │ │ └── tcp-cr.yaml
│ │ │ ├── deploy-index.yaml.tmpl
│ │ │ ├── deploy.yaml.tmpl
│ │ │ └── tcp-secret.yaml
│ │ ├── cr_tcp_additional_services_test.go
│ │ ├── cr_tcp_backend_switching_rule_test.go
│ │ ├── cr_tcp_full_test.go
│ │ ├── cr_tcp_no_ingress_class_test.go
│ │ ├── cr_tcp_test.go
│ │ └── suite_test.go
│ ├── crd
│ │ ├── config
│ │ │ ├── backend.yaml.tmpl
│ │ │ ├── crd-v1
│ │ │ │ └── global-full.yaml
│ │ │ ├── crd-v3
│ │ │ │ └── global-full.yaml
│ │ │ ├── defaults.yaml.tmpl
│ │ │ ├── deploy.yaml
│ │ │ ├── global.yaml.tmpl
│ │ │ └── ingress.yaml.tmpl
│ │ ├── cr_deploy_validation_test.go
│ │ ├── cr_global_test.go
│ │ └── suite_test.go
│ ├── dump.go
│ ├── endpoints
│ │ ├── config
│ │ │ ├── endpoints.yaml.tmpl
│ │ │ └── tcp.yaml
│ │ ├── http_test.go
│ │ ├── not_ready_test.go
│ │ ├── suite_test.go
│ │ └── tcp_test.go
│ ├── global-config
│ │ ├── config
│ │ │ ├── configmap-maxconn.yaml
│ │ │ ├── configmap-pp-1.yaml
│ │ │ └── configmap-pp-2.yaml
│ │ ├── maxconn_test.go
│ │ ├── proxy_protocol_test.go
│ │ └── suite_test.go
│ ├── haproxy-files
│ │ ├── config
│ │ │ ├── deploy.yaml.tmpl
│ │ │ ├── errorfiles.yaml
│ │ │ ├── patternfiles-1.yaml
│ │ │ └── patternfiles-2.yaml
│ │ ├── errorfiles_test.go
│ │ ├── patternfiles_test.go
│ │ └── suite_test.go
│ ├── https-runtime
│ │ ├── config
│ │ │ ├── crd-v1
│ │ │ │ └── backend-crd.yaml
│ │ │ ├── crd-v3
│ │ │ │ └── backend-crd.yaml
│ │ │ ├── echo-app-offload-backend-crd.yaml
│ │ │ ├── echo-app-offload-default.yaml
│ │ │ ├── echo-app-offload.yaml
│ │ │ ├── secret-default.yaml
│ │ │ ├── secret-offload-1.yaml
│ │ │ ├── secret-offload-2.yaml
│ │ │ ├── secret-offload-3.yaml
│ │ │ ├── secret-offload-4.yaml
│ │ │ ├── secret-offload-with-4-content.yaml
│ │ │ └── secret-offload.yaml
│ │ ├── offload_runtime_test.go
│ │ └── suite_test.go
│ ├── https
│ │ ├── config
│ │ │ ├── deploy.yaml
│ │ │ └── ingress.yaml.tmpl
│ │ ├── offload_test.go
│ │ ├── passthrough_test.go
│ │ ├── redirect_test.go
│ │ └── suite_test.go
│ ├── ingress-match
│ │ ├── config
│ │ │ ├── deploy.yaml.tmpl
│ │ │ └── ingress.yaml.tmpl
│ │ ├── ingress_match_path_test.go
│ │ └── suite_test.go
│ ├── ingressclass
│ │ ├── config
│ │ │ ├── deploy.yaml
│ │ │ ├── ingress.yaml.tmpl
│ │ │ └── ingressclass.yaml
│ │ ├── ingressClass_test.go
│ │ └── suite_test.go
│ ├── map-updates
│ │ ├── config
│ │ │ ├── deploy.yaml
│ │ │ └── ingress.yaml.tmpl
│ │ ├── suite_test.go
│ │ └── update_test.go
│ ├── rate-limiting
│ │ ├── config
│ │ │ ├── deploy.yaml
│ │ │ └── ingress.yaml.tmpl
│ │ ├── http_rate_limiting_test.go
│ │ └── suite_test.go
│ ├── send-proxy-protocol
│ │ ├── config
│ │ │ └── deploy.yaml.tmpl
│ │ └── suite_test.go
│ ├── service-discovery
│ │ ├── config
│ │ │ ├── deploy.yaml
│ │ │ └── ingress.yaml.tmpl
│ │ ├── port_discovery_test.go
│ │ └── suite_test.go
│ ├── set-header
│ │ ├── config
│ │ │ ├── deploy.yaml
│ │ │ └── ingress.yaml.tmpl
│ │ ├── set_header_test.go
│ │ ├── set_host_test.go
│ │ └── suite_test.go
│ ├── source-ip
│ │ ├── config
│ │ │ └── deploy.yaml.tmpl
│ │ ├── source_ip_test.go
│ │ └── suite_test.go
│ ├── tls-auth
│ │ ├── client-certs
│ │ │ ├── valid.crt
│ │ │ ├── valid.key
│ │ │ ├── wrong.crt
│ │ │ └── wrong.key
│ │ ├── client_auth_test.go
│ │ ├── config
│ │ │ ├── client-auth.yaml
│ │ │ └── secrets
│ │ │ │ ├── client-ca.yaml
│ │ │ │ └── default-cert.yaml
│ │ └── suite_test.go
│ └── utils.go
│ ├── images
│ ├── http-echo
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── generate-cert.sh
│ │ ├── go.mod
│ │ ├── handlers.go
│ │ └── main.go
│ └── proxy-protocol
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── integration
│ ├── base-suite.go
│ ├── config-snippet
│ │ ├── disable_configsnippet_test.go
│ │ └── suite_test.go
│ ├── customresources
│ │ ├── customresource_test.go
│ │ └── suite_test.go
│ ├── pod-maxconn
│ │ ├── pod-maxconn_test.go
│ │ └── suite_test.go
│ └── timeout-server
│ │ ├── suite_test.go
│ │ └── timeoutserver_test.go
│ ├── kind-config.yaml
│ ├── rebuild.sh
│ ├── tnr
│ └── routeacl
│ │ ├── suite_test.go
│ │ └── usebackend_test.go
│ └── ut
│ ├── acls
│ ├── acls_test.go
│ └── suite_test.go
│ └── httprequests
│ ├── httprequests_test.go
│ └── suite_test.go
├── documentation
├── README.md
├── annotations.md
├── canary-deployment.md
├── controller.md
├── custom-resource-tcp.md
├── custom-resources.md
├── doc.yaml
├── gateway-api.md
├── gen
│ ├── README.md
│ ├── annotations.go
│ ├── controller.go
│ ├── go.mod
│ ├── go.sum
│ ├── lifecycle.go
│ ├── main.go
│ ├── readme.go
│ ├── types.go
│ └── version.go
├── ingressclass.md
├── lifecycle.md
├── lifecycle.yaml
├── pebble.md
├── prometheus.md
├── secondary-config.md
└── tcp-cr-full-example
│ ├── echo-0.yaml
│ ├── echo-1.yaml
│ ├── echo.yaml
│ ├── haproxy.cfg
│ └── tcp-cr-full.yaml
├── examples
└── test-informers
│ └── replay-delete.sh
├── fs
├── etc
│ └── s6-overlay
│ │ ├── s6-rc.d
│ │ ├── aux-cfg
│ │ │ ├── type
│ │ │ └── up
│ │ ├── haproxy
│ │ │ ├── dependencies.d
│ │ │ │ ├── aux-cfg
│ │ │ │ ├── base
│ │ │ │ └── sigusr1
│ │ │ ├── run
│ │ │ └── type
│ │ ├── ingress-controller
│ │ │ ├── dependencies.d
│ │ │ │ ├── aux-cfg
│ │ │ │ ├── base
│ │ │ │ ├── haproxy
│ │ │ │ └── sigusr1
│ │ │ ├── finish
│ │ │ ├── run
│ │ │ └── type
│ │ ├── sigusr1
│ │ │ ├── type
│ │ │ └── up
│ │ └── user
│ │ │ └── contents.d
│ │ │ ├── haproxy
│ │ │ └── ingress-controller
│ │ └── scripts
│ │ ├── 00-sigusr1
│ │ └── 01-aux-cfg
├── start-pebble.sh
├── start.sh
├── usr
│ └── local
│ │ └── etc
│ │ └── haproxy
│ │ └── haproxy.cfg
└── var
│ └── lib
│ └── pebble
│ └── default
│ ├── layers
│ └── 001-haproxy.yaml
│ ├── run-controller
│ └── run-haproxy
├── go.mod
├── go.sum
├── main.go
├── pkg
├── annotations
│ ├── annotations.go
│ ├── cfgSnippet.go
│ ├── cfgSnippetHandler.go
│ ├── common
│ │ └── main.go
│ ├── global
│ │ ├── connectionMode.go
│ │ ├── hardStopAfter.go
│ │ ├── logFormat.go
│ │ ├── maxconn.go
│ │ ├── nbthread.go
│ │ ├── option.go
│ │ ├── syslogServer.go
│ │ └── timeout.go
│ ├── ingress
│ │ ├── accessControl.go
│ │ ├── basicAuth.go
│ │ ├── hostRedirect.go
│ │ ├── httpsRedirect.go
│ │ ├── reqCapture.go
│ │ ├── reqPathRewrite.go
│ │ ├── reqRateLimit.go
│ │ ├── reqSetHdr.go
│ │ ├── reqSetHost.go
│ │ ├── resSetCORS.go
│ │ └── srcIPHdr.go
│ ├── models.go
│ └── service
│ │ ├── abortOnClose.go
│ │ ├── backendForwardedFor.go
│ │ ├── ca.go
│ │ ├── check.go
│ │ ├── checkHTTP.go
│ │ ├── checkInter.go
│ │ ├── cookie.go
│ │ ├── crt.go
│ │ ├── loadbalance.go
│ │ ├── maxconn.go
│ │ ├── proto.go
│ │ ├── sendProxy.go
│ │ ├── ssl.go
│ │ ├── timeoutCheck.go
│ │ └── timeoutServer.go
├── controller
│ ├── builder.go
│ ├── constants
│ │ └── const.go
│ ├── controller.go
│ ├── global.go
│ ├── handler.go
│ └── monitor.go
├── fs
│ ├── fs-delayed.go
│ ├── fs.go
│ └── fs_test.go
├── gateways
│ ├── gateways.go
│ ├── status.go
│ └── updates.go
├── handler
│ ├── errorfiles.go
│ ├── globalcfg.go
│ ├── handler.go
│ ├── http-bind.go
│ ├── https.go
│ ├── pattern-files.go
│ ├── pprof.go
│ ├── prometheus.go
│ ├── proxy-protocol.go
│ ├── quic.go
│ ├── refresh.go
│ ├── tcp-cr.go
│ └── tcp-services.go
├── haproxy
│ ├── api
│ │ ├── acl.go
│ │ ├── api.go
│ │ ├── backend.go
│ │ ├── backend_switching_rule.go
│ │ ├── capture.go
│ │ ├── filters.go
│ │ ├── frontend.go
│ │ ├── global.go
│ │ ├── httprequest.go
│ │ ├── log_target.go
│ │ ├── runtime.go
│ │ ├── tcp_request_rule.go
│ │ └── userlist.go
│ ├── certs
│ │ └── main.go
│ ├── env
│ │ ├── defaults.go
│ │ └── main.go
│ ├── instance
│ │ └── configuration.go
│ ├── main.go
│ ├── maps
│ │ └── main.go
│ ├── process
│ │ ├── direct-control.go
│ │ ├── interface.go
│ │ ├── pebble.go
│ │ └── s6-overlay.go
│ └── rules
│ │ ├── main.go
│ │ ├── reqAcceptContent.go
│ │ ├── reqBasicAuth.go
│ │ ├── reqCapture.go
│ │ ├── reqDeny.go
│ │ ├── reqInspectDelay.go
│ │ ├── reqPathRewrite.go
│ │ ├── reqProxyProtocol.go
│ │ ├── reqRatelimit.go
│ │ ├── reqRequestRedirect.go
│ │ ├── reqRequestRedirectQuic.go
│ │ ├── reqReturnStatus.go
│ │ ├── reqSetSrc.go
│ │ ├── reqSetVar.go
│ │ ├── reqTrack.go
│ │ ├── setHdr.go
│ │ └── types.go
├── ingress
│ ├── ingress.go
│ ├── status.go
│ └── types.go
├── job
│ └── crd-check.go
├── k8s
│ ├── cr-backend.go
│ ├── cr-defaults.go
│ ├── cr-global.go
│ ├── cr-tcp.go
│ ├── crs-deprecated-v1.go
│ ├── crs-monitor.go
│ ├── informer-utils.go
│ ├── informers.go
│ ├── logging.go
│ ├── main.go
│ ├── meta
│ │ ├── meta.go
│ │ └── store.go
│ ├── sync
│ │ └── sync.go
│ ├── transform
│ │ ├── transform-backend.go
│ │ ├── transform-common.go
│ │ ├── transform-configmap.go
│ │ ├── transform-endpoints.go
│ │ ├── transform-ingress.go
│ │ ├── transform-ingressclass.go
│ │ ├── transform-namespace.go
│ │ ├── transform-secret.go
│ │ └── transform-service.go
│ └── types.go
├── metrics
│ └── prometheus.go
├── reference-counter
│ └── reference-counter.go
├── route
│ └── route.go
├── rules
│ ├── acls
│ │ └── acls.go
│ ├── backend_switching_rules
│ │ └── backend_switching_rules.go
│ ├── binds
│ │ └── binds.go
│ ├── captures
│ │ └── captures.go
│ ├── constant.go
│ ├── filters
│ │ └── filters.go
│ ├── httprequests
│ │ └── httprequests.go
│ ├── log_targets
│ │ └── log_targets.go
│ └── tcp_request_rules
│ │ └── tcp_request_rules.go
├── secret
│ └── secret.go
├── service
│ ├── endpoints.go
│ └── service.go
├── status
│ └── updatestatus.go
├── store
│ ├── convert.go
│ ├── events-cr-backend.go
│ ├── events-cr-defaults.go
│ ├── events-cr-global.go
│ ├── events-cr-tcp.go
│ ├── events-gateway.go
│ ├── events.go
│ ├── status.go
│ ├── store.go
│ ├── stringw.go
│ ├── types-configmap.go
│ ├── types-endpoints.go
│ ├── types-equal.go
│ ├── types-equal_test.go
│ ├── types-ingress.go
│ ├── types-ingressclass.go
│ ├── types-namespace.go
│ ├── types-pod.go
│ ├── types-secret.go
│ ├── types-service.go
│ ├── types-tcp-cr.go
│ ├── types-utils.go
│ └── types.go
├── utils
│ ├── errors.go
│ ├── flags-experimental.go
│ ├── flags.go
│ ├── logging.go
│ ├── orderedset.go
│ ├── types-equal.go
│ └── utils.go
└── version
│ ├── runtime.go
│ └── version.go
└── test
├── annotations
├── cfgSnippet_test.go
└── loadbalance_test.go
├── crs
├── v1-deep-copy
│ ├── backend_test.go
│ ├── defaults_test.go
│ └── global_test.go
└── v3-deep-copy
│ ├── backend_test.go
│ ├── defaults_test.go
│ ├── global_test.go
│ └── tcp_test.go
├── tcp-cr
├── expectations
│ ├── check-collisions
│ │ ├── 2-collisions.yaml
│ │ ├── coll-address-port-2.yaml
│ │ ├── coll-address-port.yaml
│ │ └── coll-fe-name.yaml
│ ├── has-collisions
│ │ ├── coll-address-port-2.yaml
│ │ ├── coll-address-port-3.yaml
│ │ ├── coll-address-port.yaml
│ │ └── coll-fe-name.yaml
│ ├── no-collision.yaml
│ └── ordered.yaml
├── manifests
│ ├── tcp1-coll-address-port-2.yaml
│ ├── tcp1-coll-address-port.yaml
│ ├── tcp1-coll-fe-name.yaml
│ ├── tcp1.yaml
│ ├── tcp2-coll-address-port.yaml
│ ├── tcp2.yaml
│ ├── tcp3.yaml
│ ├── tcp4.yaml
│ └── unordered.yaml
└── types-tcp-cr_test.go
└── transform
├── data
├── ingress
│ ├── dupl-1.yaml
│ ├── expectation
│ │ └── no-duplicate.yaml
│ └── no-duplicate.yaml
├── rule
│ ├── dupl-1.yaml
│ ├── expectation
│ │ └── no-duplicate.yaml
│ ├── no-dupl-1.yaml
│ ├── no-dupl-2.yaml
│ └── no-duplicate.yaml
└── tls
│ ├── dupl-both.yaml
│ ├── dupl-hosts.yaml
│ ├── dupl-tls-2.yaml
│ ├── dupl-tls.yaml
│ ├── expectation
│ ├── dupl-tls-2.yaml
│ └── no-duplicate.yaml
│ └── no-duplicate.yaml
└── transform-ingress_test.go
/.aspell.yml:
--------------------------------------------------------------------------------
1 | mode: commit
2 | min_length: 3
3 | allowed:
4 | - aspell
5 | - repo
6 | - yaml
7 | - config
8 | - Github
9 | - Gitlab
10 | - env
11 | - failsafe
12 | - golang
13 | - mkdir
14 | - WORKDIR
15 | - apk
16 | - ENTRYPOINT
17 | - ubuntu
18 | - golangci
19 | - sudo
20 | - releaser
21 | - backend
22 | - backends
23 | - frontend
24 | - frontends
25 | - tcp
26 | - crd
27 | - linter
28 | - linters
29 | - tls
30 | - lifecycle
31 | - passthrough
32 | - ssl
33 | - unix
34 | - parallelize
35 | - maxconn
36 | - kubebuilder
37 | - cfg
38 | - optim
39 | - prometheus
40 | - configmaps
41 | - namespace
42 | - namespaces
43 | - http
44 | - CORS
45 |
--------------------------------------------------------------------------------
/.check-commit.yml:
--------------------------------------------------------------------------------
1 | HelpText: "Please refer to https://github.com/haproxy/haproxy/blob/master/CONTRIBUTING#L632"
2 | PatchScopes:
3 | HAProxy Standard Scope:
4 | - MINOR
5 | - MEDIUM
6 | - MAJOR
7 | - CRITICAL
8 | PatchTypes:
9 | HAProxy Standard Patch:
10 | Values:
11 | - BUG
12 | - BUILD
13 | - CLEANUP
14 | - DOC
15 | - LICENSE
16 | - OPTIM
17 | - RELEASE
18 | - REORG
19 | - TEST
20 | - REVERT
21 | Scope: HAProxy Standard Scope
22 | HAProxy Standard Feature Commit:
23 | Values:
24 | - MINOR
25 | - MEDIUM
26 | - MAJOR
27 | - CRITICAL
28 | Custom Resource patch:
29 | Values:
30 | - CR
31 | Continuous Integration patch:
32 | Values:
33 | - CI
34 | TagOrder:
35 | - PatchTypes:
36 | - HAProxy Standard Patch
37 | - HAProxy Standard Feature Commit
38 | - PatchTypes:
39 | - Custom Resource patch
40 | Optional: true
41 | - PatchTypes:
42 | - Continuous Integration patch
43 | Optional: true
44 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .github
2 | .gitlab
3 | .dockerignore
4 | build
5 | assets
6 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 30
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 14
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - enhancement
8 | - bug
9 | - documentation
10 | # Label to use when marking an issue as stale
11 | staleLabel: stale
12 | # Comment to post when marking an issue as stale. Set to `false` to disable
13 | markComment: >
14 | This issue has been automatically marked as stale because it has not had
15 | recent activity. It will be closed if no further activity occurs. Thank you
16 | for your contributions.
17 | # Comment to post when closing a stale issue. Set to `false` to disable
18 | closeComment: false
19 |
--------------------------------------------------------------------------------
/.github/workflows/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | name: goreleaser
2 | on:
3 | push:
4 | tags:
5 | - "*"
6 | jobs:
7 | goreleaser:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@v4
12 | with:
13 | # we have to fetch all history to be able to generate the release note. c.f. https://goreleaser.com/ci/actions/.
14 | fetch-depth: 0
15 | - name: Set up Go
16 | uses: actions/setup-go@v5
17 | with:
18 | go-version-file: "go.mod"
19 | check-latest: true
20 | - name: Run GoReleaser
21 | uses: goreleaser/goreleaser-action@v4
22 | with:
23 | distribution: goreleaser
24 | version: 1.17.1
25 | args: release --clean
26 | env:
27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28 |
--------------------------------------------------------------------------------
/.github/workflows/docker_description.yml:
--------------------------------------------------------------------------------
1 | name: Update Docker Hub description
2 | on:
3 | push:
4 | branches:
5 | - main
6 | paths:
7 | - README.md
8 | workflow_dispatch:
9 | jobs:
10 | main:
11 | runs-on: ubuntu-latest
12 | env:
13 | DOCKER_IMAGE: haproxytech/kubernetes-ingress
14 | steps:
15 | - name: Check out repo
16 | id: checkout
17 | uses: actions/checkout@v4
18 |
19 | - name: Update Docker Hub description
20 | id: description
21 | uses: peter-evans/dockerhub-description@v2
22 | with:
23 | username: ${{ secrets.DOCKER_HUB_USERNAME }}
24 | password: ${{ secrets.DOCKER_HUB_PASSWORD }}
25 | repository: ${{ env.DOCKER_IMAGE }}
26 | short-description: ${{ github.event.repository.description }}
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/*
2 | .idea/*
3 | .test/*
4 | kubernetes-ingress
5 | dist/
6 | .code-generator/
7 | bin/golangci-lint
8 | bin/check-commit
9 | .local/*
10 | __debug_bin*
11 |
--------------------------------------------------------------------------------
/.gitlab/kind-config.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kind.x-k8s.io/v1alpha4
2 | networking:
3 | ipFamily: dual
4 | apiServerAddress: 0.0.0.0
5 | apiServerPort: 6443
6 | # add to the apiServer certSANs the name of the docker (dind) service in order to be able to reach the cluster through it
7 | kubeadmConfigPatchesJSON6902:
8 | - group: kubeadm.k8s.io
9 | version: KUBEADM_VER
10 | kind: ClusterConfiguration
11 | patch: |
12 | - op: add
13 | path: /apiServer/certSANs/-
14 | value: docker
15 | kind: Cluster
16 | nodes:
17 | - role: control-plane
18 | image: CI_REGISTRY_GO/kindest/node:K8S_VERSION
19 | extraPortMappings:
20 | - hostPort: 30080
21 | containerPort: 30080
22 | #listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
23 | #protocol: udp # Optional, defaults to tcp
24 | - hostPort: 30443
25 | containerPort: 30443
26 | - hostPort: 31024
27 | containerPort: 31024
28 | - hostPort: 32766
29 | containerPort: 32766
30 | - hostPort: 32767
31 | containerPort: 32767
32 | kubeadmConfigPatches:
33 | - |
34 | kind: ClusterConfiguration
35 | controllerManager:
36 | extraArgs:
37 | max-endpoints-per-slice: "5"
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | linters-settings:
2 | govet:
3 | shadow: true
4 | gocyclo:
5 | min-complexity: 42
6 | cyclop:
7 | max-complexity: 42
8 | dupl:
9 | threshold: 200
10 | revive:
11 | rules:
12 | - name: var-naming
13 | severity: warning
14 | disabled: true
15 | linters:
16 | enable-all: true
17 | disable:
18 | - ireturn
19 | - tagliatelle
20 | - dupl
21 | - exhaustive
22 | - funlen
23 | - gci
24 | - gochecknoglobals
25 | - gocognit
26 | - goconst
27 | - gocyclo
28 | - godot
29 | - lll
30 | - nestif
31 | - nlreturn
32 | - wrapcheck
33 | - wsl
34 | - nakedret
35 | - paralleltest
36 | - testpackage
37 | - varnamelen
38 | - exhaustruct
39 | - nonamedreturns
40 | - forcetypeassert
41 | - depguard
42 | - mnd
43 | - inamedparam
44 | - asasalint
45 | - err113 # maybe tmp disable
46 | - recvcheck # maybe tmp disable
47 | - tenv # deprecated
48 | issues:
49 | exclude:
50 | - "tag is not aligned, should be:" # this is harder to read
51 |
--------------------------------------------------------------------------------
/Makefile.ci:
--------------------------------------------------------------------------------
1 | .PHONY: ci-e2e-parallel
2 | ci-e2e-parallel:
3 | go clean -testcache
4 | KIND_URL=docker CGO_ENABLED=0 gotest -t e2e_parallel
5 |
6 | .PHONY: ci-e2e-https
7 | ci-e2e-https:
8 | go clean -testcache
9 | KIND_URL=docker CGO_ENABLED=0 gotest -t e2e_https
10 |
11 | .PHONY: ci-e2e-sequential-1
12 | ci-e2e-sequential-1:
13 | go clean -testcache
14 | KIND_URL=docker CGO_ENABLED=0 gotest -t e2e_sequential -n 2 -s 0 -p 1
15 |
16 | .PHONY: ci-e2e-sequential-2
17 | ci-e2e-sequential-2:
18 | go clean -testcache
19 | KIND_URL=docker CGO_ENABLED=0 gotest -t e2e_sequential -n 2 -s 1 -p 1
20 |
--------------------------------------------------------------------------------
/assets/images/haproxy-weblogo-210x49.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/assets/images/haproxy-weblogo-210x49.png
--------------------------------------------------------------------------------
/assets/license-header.txt:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 |
--------------------------------------------------------------------------------
/bin/check-commit.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | V=$(./check-commit tag)
3 |
4 | if echo "$V" | grep -q "v$CHECK_COMMIT"; then
5 | echo "$V"
6 | else
7 | echo "go install github.com/haproxytech/check-commit/v5@v$CHECK_COMMIT"
8 | GOBIN=$(pwd) go install github.com/haproxytech/check-commit/v5@v$CHECK_COMMIT
9 | fi
10 |
--------------------------------------------------------------------------------
/bin/lint-check.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | V=$(./golangci-lint --version)
3 |
4 | case "$V" in
5 | *$GOLANGCI_LINT_VERSION*) echo "$V" ;;
6 | *) curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(pwd) "v$GOLANGCI_LINT_VERSION" ;;
7 | esac
8 |
--------------------------------------------------------------------------------
/crs/api/ingress/v1/doc.go:
--------------------------------------------------------------------------------
1 | // Package v1 contains the core v1 API group
2 | //
3 | // +k8s:deepcopy-gen=package
4 | // +groupName=ingress.v1.haproxy.org
5 | package v1
6 |
--------------------------------------------------------------------------------
/crs/api/ingress/v3/doc.go:
--------------------------------------------------------------------------------
1 | // Package v3 contains the core v3 API group
2 | //
3 | // +k8s:deepcopy-gen=package
4 | // +groupName=ingress.v3.haproxy.org
5 | package v3
6 |
--------------------------------------------------------------------------------
/crs/controller-gen/version_check_test.go:
--------------------------------------------------------------------------------
1 | package controllergenversion
2 |
3 | // Blank import just to ensure via go.mod that we have a specific controller-gen version
4 | import _ "sigs.k8s.io/controller-tools/pkg/version"
5 |
--------------------------------------------------------------------------------
/crs/converters/defaults-spec.go:
--------------------------------------------------------------------------------
1 | // Copyright 2022 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package converters
16 |
17 | import (
18 | cnv2 "github.com/haproxytech/client-native/v5/models"
19 | convert "github.com/haproxytech/client-native/v6/configuration/convert/v2v3"
20 | cnv3 "github.com/haproxytech/client-native/v6/models"
21 | v1 "github.com/haproxytech/kubernetes-ingress/crs/api/ingress/v1"
22 | v3 "github.com/haproxytech/kubernetes-ingress/crs/api/ingress/v3"
23 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
24 | )
25 |
26 | func DeepConvertDefaultsSpecV1toV3(i v1.DefaultsSpec) v3.DefaultsSpec {
27 | v3Defaults := v3.DefaultsSpec{}
28 | logger := utils.GetLogger()
29 |
30 | // Defaults
31 | defaultsv3t, err := convert.V2Tov3[cnv2.Defaults, cnv3.Defaults](i.Config)
32 | if err != nil {
33 | logger.Error(err)
34 | return v3.DefaultsSpec{}
35 | }
36 | v3Defaults.Defaults = *defaultsv3t
37 |
38 | return v3Defaults
39 | }
40 |
--------------------------------------------------------------------------------
/crs/definition/embed.go:
--------------------------------------------------------------------------------
1 | package definition
2 |
3 | import _ "embed"
4 |
5 | //go:embed ingress.v3.haproxy.org_defaults.yaml
6 | var Defaults []byte
7 |
8 | //go:embed ingress.v3.haproxy.org_globals.yaml
9 | var Globals []byte
10 |
11 | //go:embed ingress.v3.haproxy.org_backends.yaml
12 | var Backends []byte
13 |
14 | //go:embed ingress.v3.haproxy.org_tcps.yaml
15 | var TCPs []byte
16 |
17 | func GetCRDs() map[string][]byte {
18 | return map[string][]byte{
19 | "defaults.ingress.v3.haproxy.org": Defaults,
20 | "globals.ingress.v3.haproxy.org": Globals,
21 | "backends.ingress.v3.haproxy.org": Backends,
22 | "tcps.ingress.v3.haproxy.org": TCPs,
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v1/clientset/versioned/fake/doc.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // This package has the automatically generated fake clientset.
19 | package fake
20 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v1/clientset/versioned/scheme/doc.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // This package contains the scheme of the automatically generated clientset.
19 | package scheme
20 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v1/clientset/versioned/typed/ingress/v1/doc.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // This package has the automatically generated typed clients.
19 | package v1
20 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v1/clientset/versioned/typed/ingress/v1/fake/doc.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // Package fake has the automatically generated clients.
19 | package fake
20 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v1/clientset/versioned/typed/ingress/v1/generated_expansion.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | package v1
19 |
20 | type BackendExpansion interface{}
21 |
22 | type DefaultsExpansion interface{}
23 |
24 | type GlobalExpansion interface{}
25 |
26 | type TCPExpansion interface{}
27 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v3/clientset/versioned/fake/doc.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // This package has the automatically generated fake clientset.
19 | package fake
20 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v3/clientset/versioned/scheme/doc.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // This package contains the scheme of the automatically generated clientset.
19 | package scheme
20 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v3/clientset/versioned/typed/ingress/v3/doc.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // This package has the automatically generated typed clients.
19 | package v3
20 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v3/clientset/versioned/typed/ingress/v3/fake/doc.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // Package fake has the automatically generated clients.
19 | package fake
20 |
--------------------------------------------------------------------------------
/crs/generated/api/ingress/v3/clientset/versioned/typed/ingress/v3/generated_expansion.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2019 HAProxy Technologies LLC
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 |
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | package v3
19 |
20 | type BackendExpansion interface{}
21 |
22 | type DefaultsExpansion interface{}
23 |
24 | type GlobalExpansion interface{}
25 |
26 | type TCPExpansion interface{}
27 |
--------------------------------------------------------------------------------
/crs/remove-fields-from-crds.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | yq -i 'del(.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.servers)' crs/definition/ingress.v3.haproxy.org_backends.yaml
4 |
--------------------------------------------------------------------------------
/deploy/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | - haproxy-ingress.yaml
5 |
--------------------------------------------------------------------------------
/deploy/tests/config/0.namespace.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: haproxy-controller
6 |
--------------------------------------------------------------------------------
/deploy/tests/config/2.2.ingressclass.yaml:
--------------------------------------------------------------------------------
1 | kind: IngressClass
2 | apiVersion: networking.k8s.io/v1
3 | metadata:
4 | name: haproxy
5 | spec:
6 | controller: haproxy.org/ingress-controller/haproxy
7 |
--------------------------------------------------------------------------------
/deploy/tests/config/2.configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: haproxy-kubernetes-ingress
5 | namespace: haproxy-controller
6 | data:
7 | global-config-snippet: |
8 | stats socket 0.0.0.0:31024
9 | syslog-server: |
10 | address: stdout, format: raw, facility:daemon
11 | maxconn: "1000"
12 | server-slots: "4"
13 | timeout-client: 50s
14 | timeout-connect: 5s
15 | timeout-http-keep-alive: 1m
16 | timeout-http-request: 5s
17 | timeout-queue: 5s
18 | timeout-server: 50s
19 | timeout-tunnel: 1h
20 | cr-global: haproxy-controller/global-full
21 |
--------------------------------------------------------------------------------
/deploy/tests/config/crd/job-crd.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: Job
3 | metadata:
4 | name: haproxy-ingress-crd # each deploymnent should have a unique name, in example we always recreate the custer
5 | namespace: haproxy-controller
6 | spec:
7 | template:
8 | spec:
9 | serviceAccountName: haproxy-kubernetes-ingress-crd
10 | containers:
11 | - name: haproxy-ingress-crd
12 | image: haproxytech/kubernetes-ingress:latest
13 | imagePullPolicy: Never
14 | command: ["./haproxy-ingress-controller","--job-check-crd"]
15 | restartPolicy: Never
16 | backoffLimit: 0
17 |
--------------------------------------------------------------------------------
/deploy/tests/config/crd/rbac.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: haproxy-kubernetes-ingress-crd
6 | namespace: haproxy-controller
7 | ---
8 | kind: ClusterRole
9 | apiVersion: rbac.authorization.k8s.io/v1
10 | metadata:
11 | name: haproxy-kubernetes-ingress-crd
12 | rules:
13 | - apiGroups:
14 | - "apiextensions.k8s.io"
15 | resources:
16 | - customresourcedefinitions
17 | verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
18 | ---
19 | kind: ClusterRoleBinding
20 | apiVersion: rbac.authorization.k8s.io/v1
21 | metadata:
22 | name: haproxy-kubernetes-ingress-crd
23 | namespace: haproxy-controller
24 | roleRef:
25 | apiGroup: rbac.authorization.k8s.io
26 | kind: ClusterRole
27 | name: haproxy-kubernetes-ingress-crd
28 | subjects:
29 | - kind: ServiceAccount
30 | name: haproxy-kubernetes-ingress-crd
31 | namespace: haproxy-controller
32 |
--------------------------------------------------------------------------------
/deploy/tests/config/echo-app.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: http-echo
5 | spec:
6 | replicas: 1
7 | selector:
8 | matchLabels:
9 | app: http-echo
10 | template:
11 | metadata:
12 | labels:
13 | app: http-echo
14 | spec:
15 | containers:
16 | - name: http-echo
17 | image: "haproxytech/http-echo:latest"
18 | imagePullPolicy: Never
19 | ports:
20 | - name: http
21 | containerPort: 8888
22 | protocol: TCP
23 | - name: https
24 | containerPort: 8443
25 | protocol: TCP
26 | ---
27 | kind: Service
28 | apiVersion: v1
29 | metadata:
30 | name: http-echo
31 | spec:
32 | ports:
33 | - name: http
34 | protocol: TCP
35 | port: 80
36 | targetPort: http
37 | - name: https
38 | protocol: TCP
39 | port: 443
40 | targetPort: https
41 | selector:
42 | app: http-echo
43 | ---
44 | kind: Ingress
45 | apiVersion: networking.k8s.io/v1
46 | metadata:
47 | name: http-echo
48 | spec:
49 | ingressClassName: haproxy
50 | rules:
51 | - host: "echo.haproxy.local"
52 | http:
53 | paths:
54 | - path: /
55 | pathType: Prefix
56 | backend:
57 | service:
58 | name: http-echo
59 | port:
60 | name: http
61 |
--------------------------------------------------------------------------------
/deploy/tests/config/experimental/gwapi-echo-app.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gateway.networking.k8s.io/v1alpha2
2 | kind: TCPRoute
3 | metadata:
4 | name: route1
5 | namespace: default
6 | spec:
7 | parentRefs:
8 | - group: gateway.networking.k8s.io
9 | kind: Gateway
10 | name: gateway1
11 | namespace: default
12 | rules:
13 | - backendRefs:
14 | - group: ''
15 | kind: Service
16 | name: http-echo
17 | namespace: default
18 | port: 80
19 | weight: 13
20 |
--------------------------------------------------------------------------------
/deploy/tests/config/experimental/gwapi-rbac.yaml:
--------------------------------------------------------------------------------
1 | kind: ClusterRole
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | metadata:
4 | name: haproxy-kubernetes-ingress-gwapi
5 | rules:
6 | - apiGroups:
7 | - "gateway.networking.k8s.io"
8 | resources:
9 | - referencegrants
10 | - gateways
11 | - gatewayclasses
12 | - tcproutes
13 | verbs:
14 | - get
15 | - list
16 | - watch
17 | - apiGroups:
18 | - "gateway.networking.k8s.io"
19 | resources:
20 | - gatewayclasses/status
21 | - gateways/status
22 | - tcproutes/status
23 | verbs:
24 | - update
25 | ---
26 | kind: ClusterRoleBinding
27 | apiVersion: rbac.authorization.k8s.io/v1
28 | metadata:
29 | name: haproxy-kubernetes-ingress-gwapi
30 | namespace: haproxy-controller
31 | roleRef:
32 | apiGroup: rbac.authorization.k8s.io
33 | kind: ClusterRole
34 | name: haproxy-kubernetes-ingress-gwapi
35 | subjects:
36 | - kind: ServiceAccount
37 | name: haproxy-kubernetes-ingress
38 | namespace: haproxy-controller
39 |
--------------------------------------------------------------------------------
/deploy/tests/config/experimental/gwapi-resources.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: gateway.networking.k8s.io/v1alpha2
3 | kind: GatewayClass
4 | metadata:
5 | name: haproxy-gwc
6 | spec:
7 | controllerName: haproxy.org/gateway-controller
8 | ---
9 | apiVersion: gateway.networking.k8s.io/v1alpha2
10 | kind: Gateway
11 | metadata:
12 | name: gateway1
13 | namespace: default
14 | spec:
15 | gatewayClassName: haproxy-gwc
16 | listeners:
17 | - allowedRoutes:
18 | kinds:
19 | - group: gateway.networking.k8s.io
20 | kind: TCPRoute
21 | namespaces:
22 | from: All
23 | name: listener1
24 | port: 8000
25 | protocol: TCP
26 | ---
27 | apiVersion: gateway.networking.k8s.io/v1alpha2
28 | kind: ReferenceGrant
29 | metadata:
30 | name: refgrantns1
31 | namespace: default
32 | spec:
33 | from:
34 | - group: "gateway.networking.k8s.io"
35 | kind: "TCPRoute"
36 | namespace: default
37 | to:
38 | - group: ""
39 | kind: "Service"
40 |
--------------------------------------------------------------------------------
/deploy/tests/delete.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | clustername=${1:-dev}
3 | kind delete cluster --name $clustername
4 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/access-control/config/patternfile-a.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: patternfiles
5 | namespace: haproxy-controller
6 | data:
7 | ips: |
8 | 192.168.0.0/24
9 | 192.168.1.0/24
10 | ips2: |
11 | 192.169.0.0/24
12 | 192.169.1.0/24
13 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/access-control/config/patternfile-empty.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: patternfiles
5 | namespace: haproxy-controller
6 | data: {}
7 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/basic-auth/suite_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build e2e_parallel
16 |
17 | package basicauth
18 |
19 | import (
20 | "testing"
21 |
22 | "github.com/stretchr/testify/suite"
23 |
24 | "github.com/haproxytech/kubernetes-ingress/deploy/tests/e2e"
25 | )
26 |
27 | type HTTPBasicAuthSuite struct {
28 | suite.Suite
29 | test e2e.Test
30 | client *e2e.Client
31 | tmplData tmplData
32 | }
33 |
34 | type tmplData struct {
35 | Host string
36 | }
37 |
38 | func (suite *HTTPBasicAuthSuite) SetupSuite() {
39 | var err error
40 | suite.test, err = e2e.NewTest()
41 | suite.Require().NoError(err)
42 | suite.tmplData = tmplData{Host: suite.test.GetNS() + ".test"}
43 | suite.client, err = e2e.NewHTTPClient(suite.tmplData.Host)
44 | suite.Require().NoError(err)
45 | }
46 |
47 | func (suite *HTTPBasicAuthSuite) TearDownSuite() {
48 | suite.test.TearDown()
49 | }
50 |
51 | func TestHTTPBasicAuthSuite(t *testing.T) {
52 | suite.Run(t, new(HTTPBasicAuthSuite))
53 | }
54 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/config-snippet/config/backend-cfg-snippet.yaml:
--------------------------------------------------------------------------------
1 | kind: Service
2 | apiVersion: v1
3 | metadata:
4 | name: http-echo
5 | annotations:
6 | backend-config-snippet: |
7 | http-request set-header e2e-test %[str(test)]
8 | spec:
9 | ipFamilyPolicy: RequireDualStack
10 | ports:
11 | - name: http
12 | protocol: TCP
13 | port: 80
14 | targetPort: http
15 | - name: https
16 | protocol: TCP
17 | port: 443
18 | targetPort: https
19 | selector:
20 | app: http-echo
21 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/config-snippet/config/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: haproxy-kubernetes-ingress
5 | namespace: haproxy-controller
6 | data:
7 | frontend-config-snippet: |
8 | unique-id-format %{+X}o\ %ci:%cp_%fi:%fp_%Ts_%rt:%pid
9 | unique-id-header X-Unique-ID
10 | syslog-server: |
11 | address: stdout, format: raw, facility:daemon
12 | maxconn: "1000"
13 | server-slots: "4"
14 | timeout-client: 50s
15 | timeout-connect: 5s
16 | timeout-http-keep-alive: 1m
17 | timeout-http-request: 5s
18 | timeout-queue: 5s
19 | timeout-server: 50s
20 | timeout-tunnel: 1h
21 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/config-snippet/config/deploy.yaml.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Deployment
3 | apiVersion: apps/v1
4 | metadata:
5 | name: http-echo
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: http-echo
11 | template:
12 | metadata:
13 | labels:
14 | app: http-echo
15 | spec:
16 | containers:
17 | - name: http-echo
18 | image: haproxytech/http-echo:latest
19 | imagePullPolicy: Never
20 | args:
21 | ports:
22 | - name: http
23 | containerPort: 8888
24 | protocol: TCP
25 | - name: https
26 | containerPort: 8443
27 | protocol: TCP
28 | ---
29 | kind: Service
30 | apiVersion: v1
31 | metadata:
32 | name: http-echo
33 | spec:
34 | ipFamilyPolicy: RequireDualStack
35 | ports:
36 | - name: http
37 | protocol: TCP
38 | port: 80
39 | targetPort: http
40 | - name: https
41 | protocol: TCP
42 | port: 443
43 | targetPort: https
44 | selector:
45 | app: http-echo
46 | ---
47 | kind: Ingress
48 | apiVersion: networking.k8s.io/v1
49 | metadata:
50 | name: http-echo
51 | spec:
52 | ingressClassName: haproxy
53 | rules:
54 | - host: {{ .Host }}
55 | http:
56 | paths:
57 | - path: /
58 | pathType: Prefix
59 | backend:
60 | service:
61 | name: http-echo
62 | port:
63 | name: http
64 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/cors/config/configmap.yaml.tmpl:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: haproxy-kubernetes-ingress
5 | namespace: haproxy-controller
6 | data:
7 | {{range .ConfigMapAnnotations}}
8 | {{ .Key }}: {{ .Value }}
9 | {{end}}
10 | global-config-snippet: |
11 | stats socket 0.0.0.0:31024
12 | syslog-server: |
13 | address: stdout, format: raw, facility:daemon
14 | maxconn: "1000"
15 | server-slots: "4"
16 | timeout-client: 50s
17 | timeout-connect: 5s
18 | timeout-http-keep-alive: 1m
19 | timeout-http-request: 5s
20 | timeout-queue: 5s
21 | timeout-server: 50s
22 | timeout-tunnel: 1h
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v1/backend-cr.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v1.haproxy.org/v1
2 | kind: Backend
3 | metadata:
4 | name: mybackend
5 | spec:
6 | config:
7 | balance:
8 | algorithm: "leastconn"
9 | abortonclose: disabled
10 | name: foo
11 | default_server:
12 | verify: none
13 | resolve-prefer: ipv4
14 | check-sni: example.com
15 | sni: str(example.com)
16 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v1/tcp-cr-add-services.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v1.haproxy.org/v1
2 | kind: TCP
3 | metadata:
4 | name: tcp-1
5 | annotations:
6 | ingress.class: haproxy
7 | spec:
8 | - name: tcp-http-echo-80
9 | frontend:
10 | name: fe-http-echo-80
11 | tcplog: true
12 | log_format: "%{+Q}o %t %s"
13 | binds:
14 | - name: v4
15 | port: 32766
16 | - name: v4v6
17 | address: "::"
18 | port: 32766
19 | v4v6: true
20 | service:
21 | name: "http-echo"
22 | port: 80
23 | services:
24 | - name: "http-echo-2"
25 | port: 443
26 | - name: "http-echo-2"
27 | port: 80
28 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v1/tcp-cr-backend-switching-rule-acls.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v1.haproxy.org/v1
2 | kind: TCP
3 | metadata:
4 | name: tcp-1
5 | annotations:
6 | ingress.class: haproxy
7 | spec:
8 | - name: tcp-test
9 | frontend:
10 | name: fe-http-echo
11 | tcplog: true
12 | log_format: "%{+Q}o %t %s"
13 | binds:
14 | - name: v4
15 | address: 0.0.0.0
16 | port: 32766
17 | acl_list:
18 | - acl_name: switch_be_0
19 | criterion: req_ssl_sni
20 | index: 0
21 | value: -i backend0.example.com
22 | - acl_name: switch_be_1
23 | criterion: req_ssl_sni
24 | index: 1
25 | value: -i backend1.example.com
26 | backend_switching_rule_list:
27 | - cond: if
28 | cond_test: 'switch_be_0'
29 | index: 0
30 | name: e2e-tests-crd-tcp_http-echo-0_https
31 | - cond: if
32 | cond_test: 'switch_be_1'
33 | index: 1
34 | name: e2e-tests-crd-tcp_http-echo-1_https
35 | tcp_request_rule_list:
36 | - type: inspect-delay
37 | timeout: 5000
38 | index: 0
39 | - type: content
40 | action: accept
41 | cond: if
42 | cond_test: "{ req_ssl_hello_type 1 }"
43 | index: 1
44 | service:
45 | name: "http-echo"
46 | port: 443
47 | services:
48 | - name: "http-echo-0"
49 | port: 443
50 | - name: "http-echo-1"
51 | port: 443
52 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v1/tcp-cr-backend-switching-rule.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v1.haproxy.org/v1
2 | kind: TCP
3 | metadata:
4 | name: tcp-1
5 | annotations:
6 | ingress.class: haproxy
7 | spec:
8 | - name: tcp-test
9 | frontend:
10 | name: fe-http-echo
11 | tcplog: true
12 | log_format: "%{+Q}o %t %s"
13 | binds:
14 | - name: v4
15 | address: 0.0.0.0
16 | port: 32766
17 | backend_switching_rule_list:
18 | - cond: if
19 | cond_test: '{ req_ssl_sni -i backend0.example.com }'
20 | index: 0
21 | name: e2e-tests-crd-tcp_http-echo-0_https
22 | - cond: if
23 | cond_test: '{ req_ssl_sni -i backend1.example.com }'
24 | index: 1
25 | name: e2e-tests-crd-tcp_http-echo-1_https
26 | tcp_request_rule_list:
27 | - type: inspect-delay
28 | timeout: 5000
29 | index: 0
30 | - type: content
31 | action: accept
32 | cond: if
33 | cond_test: "{ req_ssl_hello_type 1 }"
34 | index: 1
35 | service:
36 | name: "http-echo"
37 | port: 443
38 | services:
39 | - name: "http-echo-0"
40 | port: 443
41 | - name: "http-echo-1"
42 | port: 443
43 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v1/tcp-cr-no-ingress-class.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v1.haproxy.org/v1
2 | kind: TCP
3 | metadata:
4 | name: tcp-1
5 | spec:
6 | - name: tcp-http-echo-80
7 | frontend:
8 | name: fe-http-echo-80
9 | tcplog: true
10 | log_format: "%{+Q}o %t %s"
11 | binds:
12 | - name: v4
13 | port: 32766
14 | - name: v4v6
15 | address: "::"
16 | port: 32766
17 | v4v6: true
18 | service:
19 | name: "http-echo"
20 | port: 80
21 | services:
22 | - name: "http-echo-2"
23 | port: 443
24 | - name: "http-echo-2"
25 | port: 80
26 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v1/tcp-cr-ssl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v1.haproxy.org/v1
2 | kind: TCP
3 | metadata:
4 | name: tcp-1
5 | annotations:
6 | ingress.class: haproxy
7 | spec:
8 | - name: tcp-http-echo-443
9 | frontend:
10 | name: fe-http-echo-443
11 | tcplog: true
12 | log_format: "%{+Q}o %t %s"
13 | binds:
14 | - name: v4
15 | ssl: true
16 | ssl_certificate: tcp-test-cert
17 | port: 32766
18 | - name: v4v6
19 | address: "::"
20 | port: 32766
21 | v4v6: true
22 | service:
23 | name: "http-echo"
24 | port: 443
25 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v1/tcp-cr.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v1.haproxy.org/v1
2 | kind: TCP
3 | metadata:
4 | name: tcp-1
5 | annotations:
6 | ingress.class: haproxy
7 | spec:
8 | - name: tcp-http-echo-80
9 | frontend:
10 | name: fe-http-echo-80
11 | tcplog: true
12 | log_format: "%{+Q}o %t %s"
13 | binds:
14 | - name: v4
15 | port: 32766
16 | - name: v4v6
17 | address: "::"
18 | port: 32766
19 | v4v6: true
20 | service:
21 | name: "http-echo"
22 | port: 80
23 | - name: tcp-http-echo-81
24 | frontend:
25 | name: fe-http-echo-81
26 | tcplog: true
27 | log_format: "%{+Q}o %t %s"
28 | binds:
29 | - name: v4acceptproxy
30 | port: 32767
31 | accept_proxy: true
32 | service:
33 | name: "http-echo"
34 | port: 81
35 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v3/backend-cr.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v3.haproxy.org/v3
2 | kind: Backend
3 | metadata:
4 | creationTimestamp: null
5 | name: mybackend
6 | spec:
7 | abortonclose: disabled
8 | balance:
9 | algorithm: leastconn
10 | default_server:
11 | check-sni: example.com
12 | resolve-prefer: ipv4
13 | sni: str(example.com)
14 | verify: none
15 | name: foo
16 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v3/tcp-cr-add-services.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v3.haproxy.org/v3
2 | kind: TCP
3 | metadata:
4 | name: tcp-1
5 | annotations:
6 | ingress.class: haproxy
7 | spec:
8 | - name: tcp-http-echo-80
9 | frontend:
10 | name: fe-http-echo-80
11 | tcplog: true
12 | log_format: "%{+Q}o %t %s"
13 | binds:
14 | v4:
15 | port: 32766
16 | name: v4
17 | v4v6:
18 | address: "::"
19 | name: v4v6
20 | port: 32766
21 | v4v6: true
22 | service:
23 | name: "http-echo"
24 | port: 80
25 | services:
26 | - name: "http-echo-2"
27 | port: 443
28 | - name: "http-echo-2"
29 | port: 80
30 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v3/tcp-cr-backend-switching-rule-acls.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v3.haproxy.org/v3
2 | kind: TCP
3 | metadata:
4 | annotations:
5 | ingress.class: haproxy
6 | creationTimestamp: null
7 | name: tcp-1
8 | spec:
9 | - frontend:
10 | acl_list:
11 | - acl_name: switch_be_0
12 | criterion: req_ssl_sni
13 | value: -i backend0.example.com
14 | - acl_name: switch_be_1
15 | criterion: req_ssl_sni
16 | value: -i backend1.example.com
17 | backend_switching_rule_list:
18 | - cond: if
19 | cond_test: switch_be_0
20 | name: e2e-tests-crd-tcp_http-echo-0_https
21 | - cond: if
22 | cond_test: switch_be_1
23 | name: e2e-tests-crd-tcp_http-echo-1_https
24 | binds:
25 | v4:
26 | address: 0.0.0.0
27 | name: v4
28 | port: 32766
29 | log_format: '%{+Q}o %t %s'
30 | name: fe-http-echo
31 | tcp_request_rule_list:
32 | - timeout: 5000
33 | type: inspect-delay
34 | - action: accept
35 | cond: if
36 | cond_test: '{ req_ssl_hello_type 1 }'
37 | type: content
38 | tcplog: true
39 | name: tcp-test
40 | service:
41 | name: http-echo
42 | port: 443
43 | services:
44 | - name: http-echo-0
45 | port: 443
46 | - name: http-echo-1
47 | port: 443
48 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v3/tcp-cr-backend-switching-rule.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v3.haproxy.org/v3
2 | kind: TCP
3 | metadata:
4 | annotations:
5 | ingress.class: haproxy
6 | creationTimestamp: null
7 | name: tcp-1
8 | spec:
9 | - frontend:
10 | backend_switching_rule_list:
11 | - cond: if
12 | cond_test: '{ req_ssl_sni -i backend0.example.com }'
13 | name: e2e-tests-crd-tcp_http-echo-0_https
14 | - cond: if
15 | cond_test: '{ req_ssl_sni -i backend1.example.com }'
16 | name: e2e-tests-crd-tcp_http-echo-1_https
17 | binds:
18 | v4:
19 | address: 0.0.0.0
20 | name: v4
21 | port: 32766
22 | log_format: '%{+Q}o %t %s'
23 | name: fe-http-echo
24 | tcp_request_rule_list:
25 | - timeout: 5000
26 | type: inspect-delay
27 | - action: accept
28 | cond: if
29 | cond_test: '{ req_ssl_hello_type 1 }'
30 | type: content
31 | tcplog: true
32 | name: tcp-test
33 | service:
34 | name: http-echo
35 | port: 443
36 | services:
37 | - name: http-echo-0
38 | port: 443
39 | - name: http-echo-1
40 | port: 443
41 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v3/tcp-cr-no-ingress-class.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v3.haproxy.org/v3
2 | kind: TCP
3 | metadata:
4 | creationTimestamp: null
5 | name: tcp-1
6 | spec:
7 | - frontend:
8 | binds:
9 | v4:
10 | name: v4
11 | port: 32766
12 | v4v6:
13 | address: '::'
14 | name: v4v6
15 | port: 32766
16 | v4v6: true
17 | log_format: '%{+Q}o %t %s'
18 | name: fe-http-echo-80
19 | tcplog: true
20 | name: tcp-http-echo-80
21 | service:
22 | name: http-echo
23 | port: 80
24 | services:
25 | - name: http-echo-2
26 | port: 443
27 | - name: http-echo-2
28 | port: 80
29 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v3/tcp-cr-ssl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v3.haproxy.org/v3
2 | kind: TCP
3 | metadata:
4 | annotations:
5 | ingress.class: haproxy
6 | creationTimestamp: null
7 | name: tcp-1
8 | spec:
9 | - frontend:
10 | binds:
11 | v4:
12 | name: v4
13 | port: 32766
14 | ssl: true
15 | ssl_certificate: tcp-test-cert
16 | v4v6:
17 | address: '::'
18 | name: v4v6
19 | port: 32766
20 | v4v6: true
21 | log_format: '%{+Q}o %t %s'
22 | name: fe-http-echo-443
23 | tcplog: true
24 | name: tcp-http-echo-443
25 | service:
26 | name: http-echo
27 | port: 443
28 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/crd-v3/tcp-cr.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v3.haproxy.org/v3
2 | kind: TCP
3 | metadata:
4 | annotations:
5 | ingress.class: haproxy
6 | creationTimestamp: null
7 | name: tcp-1
8 | spec:
9 | - frontend:
10 | binds:
11 | v4:
12 | name: v4
13 | port: 32766
14 | v4v6:
15 | address: '::'
16 | name: v4v6
17 | port: 32766
18 | v4v6: true
19 | log_format: '%{+Q}o %t %s'
20 | name: fe-http-echo-80
21 | tcplog: true
22 | name: tcp-http-echo-80
23 | service:
24 | name: http-echo
25 | port: 80
26 | - frontend:
27 | binds:
28 | v4acceptproxy:
29 | accept_proxy: true
30 | name: v4acceptproxy
31 | port: 32767
32 | log_format: '%{+Q}o %t %s'
33 | name: fe-http-echo-81
34 | tcplog: true
35 | name: tcp-http-echo-81
36 | service:
37 | name: http-echo
38 | port: 81
39 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/deploy-index.yaml.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Deployment
3 | apiVersion: apps/v1
4 | metadata:
5 | name: http-echo-{{ .EchoAppIndex }}
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: http-echo-{{ .EchoAppIndex }}
11 | template:
12 | metadata:
13 | labels:
14 | app: http-echo-{{ .EchoAppIndex }}
15 | spec:
16 | containers:
17 | - name: http-echo
18 | image: haproxytech/http-echo:latest
19 | imagePullPolicy: Never
20 | args:
21 | - --default-response=hostname
22 | ports:
23 | - name: http
24 | containerPort: 8888
25 | protocol: TCP
26 | - name: https
27 | containerPort: 8443
28 | protocol: TCP
29 | ---
30 | kind: Service
31 | apiVersion: v1
32 | metadata:
33 | name: http-echo-{{ .EchoAppIndex }}
34 | spec:
35 | ipFamilyPolicy: RequireDualStack
36 | ports:
37 | - name: http
38 | protocol: TCP
39 | port: 80
40 | targetPort: http
41 | - name: https
42 | protocol: TCP
43 | port: 443
44 | targetPort: https
45 | selector:
46 | app: http-echo-{{ .EchoAppIndex }}
47 | ---
48 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd-tcp/config/deploy.yaml.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Deployment
3 | apiVersion: apps/v1
4 | metadata:
5 | name: http-echo
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: http-echo
11 | template:
12 | metadata:
13 | labels:
14 | app: http-echo
15 | spec:
16 | containers:
17 | - name: http-echo
18 | image: haproxytech/http-echo:latest
19 | imagePullPolicy: Never
20 | args:
21 | - --default-response=hostname
22 | ports:
23 | - name: http
24 | containerPort: 8888
25 | protocol: TCP
26 | - name: https
27 | containerPort: 8443
28 | protocol: TCP
29 | ---
30 | kind: Service
31 | apiVersion: v1
32 | metadata:
33 | name: http-echo
34 | {{- if ne .BackendCrName "" }}
35 | annotations:
36 | cr-backend: {{ .BackendCrNamespace }}/{{ .BackendCrName }}
37 | {{- end }}
38 | spec:
39 | ipFamilyPolicy: RequireDualStack
40 | ports:
41 | - name: http
42 | protocol: TCP
43 | port: 80
44 | targetPort: http
45 | - name: https
46 | protocol: TCP
47 | port: 443
48 | targetPort: https
49 | - name: http2
50 | protocol: TCP
51 | port: 81
52 | targetPort: http
53 | selector:
54 | app: http-echo
55 | ---
56 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd/config/deploy.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Deployment
3 | apiVersion: apps/v1
4 | metadata:
5 | name: http-echo
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: http-echo
11 | template:
12 | metadata:
13 | creationTimestamp: null
14 | labels:
15 | app: http-echo
16 | spec:
17 | containers:
18 | - name: http-echo
19 | image: haproxytech/http-echo:latest
20 | imagePullPolicy: Never
21 | args:
22 | - --default-response=hostname
23 | ports:
24 | - name: http
25 | containerPort: 8888
26 | protocol: TCP
27 | - name: https
28 | containerPort: 8443
29 | protocol: TCP
30 | ---
31 | kind: Service
32 | apiVersion: v1
33 | metadata:
34 | name: http-echo
35 | spec:
36 | ipFamilyPolicy: RequireDualStack
37 | ports:
38 | - name: http
39 | protocol: TCP
40 | port: 80
41 | targetPort: http
42 | - name: https
43 | protocol: TCP
44 | port: 443
45 | targetPort: https
46 | selector:
47 | app: http-echo
48 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/crd/config/ingress.yaml.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Ingress
3 | apiVersion: networking.k8s.io/v1
4 | metadata:
5 | name: http-echo
6 | annotations:
7 | {{- range .IngAnnotations}}
8 | {{ .Key }}: "{{ .Value }}"
9 | {{- end}}
10 | spec:
11 | ingressClassName: haproxy
12 | rules:
13 | - host: {{ .Host }}
14 | http:
15 | paths:
16 | - path: /
17 | pathType: Prefix
18 | backend:
19 | service:
20 | name: http-echo
21 | port:
22 | name: http
23 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/dump.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package e2e
16 |
17 | import "strings"
18 |
19 | func (t Test) GetIngressControllerFile(path string) (string, error) {
20 | po, err := t.getIngressControllerPod()
21 | if err != nil {
22 | return "", err
23 | }
24 | out, errExec := t.execute("", "kubectl", "exec", "-i", "-n", "haproxy-controller",
25 | po, "--", "cat", path)
26 |
27 | return out, errExec
28 | }
29 |
30 | func (t Test) getIngressControllerPod() (string, error) {
31 | out, errExec := t.execute("", "kubectl", "get", "pods", "-n", "haproxy-controller",
32 | "-l", "run=haproxy-ingress", "-o", "name", "--field-selector=status.phase==Running", "-l", "run=haproxy-ingress")
33 | return strings.TrimSuffix(out, "\n"), errExec
34 | }
35 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/endpoints/config/tcp.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: ConfigMap
4 | metadata:
5 | name: haproxy-kubernetes-ingress-tcp
6 | namespace: haproxy-controller
7 | data:
8 | 32766: "e2e-tests-endpoints/http-echo:443"
9 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/endpoints/not_ready_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build e2e_sequential
16 |
17 | package endpoints
18 |
19 | import (
20 | "github.com/haproxytech/kubernetes-ingress/deploy/tests/e2e"
21 | )
22 |
23 | func (suite *EndpointsSuite) Test_Non_Ready_Endpoints() {
24 | suite.tmplData.NotReady = true
25 | suite.tmplData.Replicas = 3
26 | suite.Require().NoError(suite.test.Apply("config/endpoints.yaml.tmpl", suite.test.GetNS(), suite.tmplData))
27 | suite.Require().Eventually(func() bool {
28 | res, cls, err := suite.client.Do()
29 | if res == nil {
30 | suite.T().Log(err)
31 | return false
32 | }
33 | defer cls()
34 | return res.StatusCode == 200
35 | }, e2e.WaitDuration, e2e.TickDuration)
36 | }
37 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/endpoints/tcp_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build e2e_sequential
16 |
17 | package endpoints
18 |
19 | import "io"
20 |
21 | func (suite *EndpointsSuite) Test_TCP_Reach() {
22 | counter := map[string]int{}
23 | for i := 0; i < 4; i++ {
24 | func() {
25 | res, cls, err := suite.client.Do()
26 | if err != nil {
27 | suite.Require().NoError(err)
28 | return
29 | }
30 | defer cls()
31 | body, err := io.ReadAll(res.Body)
32 | if err != nil {
33 | suite.Error(err)
34 | return
35 | }
36 | counter[string(body)]++
37 | }()
38 | }
39 | for _, v := range counter {
40 | suite.Equal(4, v)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/global-config/config/configmap-maxconn.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: haproxy-kubernetes-ingress
5 | namespace: haproxy-controller
6 | data:
7 | # Mandatory config
8 | global-config-snippet: |
9 | stats socket 0.0.0.0:31024
10 | syslog-server: |
11 | address: stdout, format: raw, facility:daemon
12 | # Optional config
13 | maxconn: "1111"
14 | server-slots: "4"
15 | timeout-client: 50s
16 | timeout-connect: 5s
17 | timeout-http-keep-alive: 1m
18 | timeout-http-request: 5s
19 | timeout-queue: 5s
20 | timeout-server: 50s
21 | timeout-tunnel: 1h
22 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/global-config/config/configmap-pp-1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: haproxy-kubernetes-ingress
5 | namespace: haproxy-controller
6 | data:
7 | # Mandatory config
8 | global-config-snippet: |
9 | stats socket 0.0.0.0:31024
10 | syslog-server: |
11 | address: stdout, format: raw, facility:daemon
12 | # Optional config
13 | proxy-protocol: 0.0.0.0/0
14 | maxconn: "1000"
15 | server-slots: "4"
16 | timeout-client: 50s
17 | timeout-connect: 5s
18 | timeout-http-keep-alive: 1m
19 | timeout-http-request: 5s
20 | timeout-queue: 5s
21 | timeout-server: 50s
22 | timeout-tunnel: 1h
23 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/global-config/config/configmap-pp-2.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: haproxy-kubernetes-ingress
5 | namespace: haproxy-controller
6 | data:
7 | # Mandatory config
8 | global-config-snippet: |
9 | stats socket 0.0.0.0:31024
10 | syslog-server: |
11 | address: stdout, format: raw, facility:daemon
12 | # Optional config
13 | proxy-protocol: 192.168.1.1
14 | maxconn: "1000"
15 | server-slots: "4"
16 | timeout-client: 50s
17 | timeout-connect: 5s
18 | timeout-http-keep-alive: 1m
19 | timeout-http-request: 5s
20 | timeout-queue: 5s
21 | timeout-server: 50s
22 | timeout-tunnel: 1h
23 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/global-config/maxconn_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build e2e_sequential
16 |
17 | package globalconfig
18 |
19 | import (
20 | "github.com/haproxytech/kubernetes-ingress/deploy/tests/e2e"
21 | )
22 |
23 | func (suite *GlobalConfigSuite) TestMaxconn() {
24 | suite.Require().NoError(suite.test.Apply("config/configmap-maxconn.yaml", "", nil))
25 | suite.maxconn = "1111"
26 | suite.Eventually(suite.checkMaxconn, e2e.WaitDuration, e2e.TickDuration)
27 |
28 | suite.Require().NoError(suite.test.Apply("../../config/2.configmap.yaml", "", nil))
29 | suite.maxconn = "1000"
30 | suite.Eventually(suite.checkMaxconn, e2e.WaitDuration, e2e.TickDuration)
31 | }
32 |
33 | func (suite *GlobalConfigSuite) checkMaxconn() bool {
34 | r, err := e2e.GetGlobalHAProxyInfo()
35 | if err != nil {
36 | suite.T().Log(err)
37 | return false
38 | }
39 | return r.Maxconn == suite.maxconn
40 | }
41 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/global-config/suite_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build e2e_sequential
16 |
17 | package globalconfig
18 |
19 | import (
20 | "testing"
21 |
22 | "github.com/stretchr/testify/suite"
23 |
24 | "github.com/haproxytech/kubernetes-ingress/deploy/tests/e2e"
25 | )
26 |
27 | type GlobalConfigSuite struct {
28 | suite.Suite
29 | test e2e.Test
30 | maxconn string
31 | }
32 |
33 | func (suite *GlobalConfigSuite) SetupSuite() {
34 | var err error
35 | suite.test, err = e2e.NewTest()
36 | suite.Require().NoError(err)
37 | }
38 |
39 | func (suite *GlobalConfigSuite) TearDownSuite() {
40 | suite.test.TearDown()
41 | }
42 |
43 | func TestGlobalConfigSuite(t *testing.T) {
44 | suite.Run(t, new(GlobalConfigSuite))
45 | }
46 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/haproxy-files/config/deploy.yaml.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Service
3 | apiVersion: v1
4 | metadata:
5 | name: http-echo
6 | spec:
7 | ipFamilyPolicy: RequireDualStack
8 | ports:
9 | - name: http
10 | protocol: TCP
11 | port: 80
12 | targetPort: http
13 | - name: https
14 | protocol: TCP
15 | port: 443
16 | targetPort: https
17 | selector:
18 | app: http-echo
19 | ---
20 | kind: Ingress
21 | apiVersion: networking.k8s.io/v1
22 | metadata:
23 | name: http-echo
24 | annotations:
25 | backend-config-snippet: http-after-response set-header result %[var(txn.path),ltrim(/),map(patterns/mapping)]
26 | spec:
27 | ingressClassName: haproxy
28 | rules:
29 | - host: {{ .Host }}
30 | http:
31 | paths:
32 | - path: /
33 | pathType: Prefix
34 | backend:
35 | service:
36 | name: http-echo
37 | port:
38 | name: http
39 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/haproxy-files/config/errorfiles.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: errorfiles
5 | namespace: haproxy-controller
6 | data:
7 | 503: |-
8 | HTTP/1.1 521 Web server is down
9 | Cache-Control: no-cache
10 | Connection: close
11 | Content-Type: text/html
12 |
13 |
Oops, that's embarrassing!
14 | There are no servers available to handle your request.
15 |
16 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/haproxy-files/config/patternfiles-1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: patternfiles
5 | namespace: haproxy-controller
6 | data:
7 | mapping: |
8 | H+DbITVEMAJDRS4EzVF4gVDfTmyUFB3RzEkCIST9 0
9 | GBxqv9YZHQ5dBLMjTjBbyjd4/wS0F0ETZtsnLsYI 1
10 | 7tFRKRoboeFENmfTSHj+gjJKFjtOw2u+G+1d13rO 2
11 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/haproxy-files/config/patternfiles-2.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: patternfiles
5 | namespace: haproxy-controller
6 | data:
7 | mapping: |
8 | F3ITB+V5w0Yo8ZeS8LO3mkNlFBOxS3i9TDYfVjJv 0
9 | Yn9MvTzjAeLqp7MKE7g7thlf6jc2WRYTNoya+Cqb 1
10 | Y6FX16EEqxJr/B9M2Pzzt/NvivoDjZE2FTr4boBb 2
11 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/https-runtime/config/crd-v1/backend-crd.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v1.haproxy.org/v1
2 | kind: Backend
3 | metadata:
4 | name: be-test
5 | spec:
6 | config:
7 | name: test-be-simple
8 | abortonclose: "enabled"
9 | accept_invalid_http_response: "enabled"
10 | default_server:
11 | check: "enabled"
12 | acls:
13 | - acl_name: switch_be_0
14 | criterion: req_ssl_sni
15 | index: 0
16 | value: -i backend100.example.com
17 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/https-runtime/config/crd-v3/backend-crd.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: ingress.v3.haproxy.org/v3
2 | kind: Backend
3 | metadata:
4 | creationTimestamp: null
5 | name: be-test
6 | spec:
7 | abortonclose: enabled
8 | accept_invalid_http_response: enabled
9 | acl_list:
10 | - acl_name: switch_be_0
11 | criterion: req_ssl_sni
12 | value: -i backend100.example.com
13 | default_server:
14 | check: enabled
15 | name: test-be-simple
16 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/https-runtime/suite_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build e2e_sequential
16 |
17 | package httpsruntime
18 |
19 | import (
20 | "testing"
21 |
22 | "github.com/stretchr/testify/suite"
23 |
24 | "github.com/haproxytech/kubernetes-ingress/deploy/tests/e2e"
25 | )
26 |
27 | type HTTPSSuite struct {
28 | suite.Suite
29 | test e2e.Test
30 | client *e2e.Client
31 | tmplData tmplData
32 | }
33 |
34 | type tmplData struct {
35 | Port string
36 | }
37 |
38 | func (suite *HTTPSSuite) SetupSuite() {
39 | var err error
40 | suite.test, err = e2e.NewTest()
41 | suite.Require().NoError(err)
42 | }
43 |
44 | func (suite *HTTPSSuite) TearDownSuite() {
45 | suite.test.TearDown()
46 | }
47 |
48 | func TestHTTPSSuite(t *testing.T) {
49 | suite.Run(t, new(HTTPSSuite))
50 | }
51 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/https/config/ingress.yaml.tmpl:
--------------------------------------------------------------------------------
1 | kind: Ingress
2 | apiVersion: networking.k8s.io/v1
3 | metadata:
4 | name: http-echo
5 | annotations:
6 | {{range .IngAnnotations}}
7 | {{ .Key }}: {{ .Value}}
8 | {{end}}
9 | spec:
10 | ingressClassName: haproxy
11 | {{if .TLSEnabled}}
12 | tls:
13 | - hosts:
14 | - {{ .Host }}
15 | secretName: haproxy-offload-test
16 | - hosts:
17 | - default.haproxy
18 | secretName: haproxy-default # Another cert to make sure HAProxy picks the right one
19 | {{end}}
20 | rules:
21 | - host: {{ .Host }}
22 | http:
23 | paths:
24 | - path: /
25 | pathType: Prefix
26 | backend:
27 | service:
28 | name: http-echo
29 | port:
30 | name: {{ .Port }}
31 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/ingress-match/config/deploy.yaml.tmpl:
--------------------------------------------------------------------------------
1 | {{- range $_,$i := .Apps }}
2 | ---
3 | apiVersion: apps/v1
4 | kind: Deployment
5 | metadata:
6 | name: http-echo-{{$i}}
7 | spec:
8 | replicas: 1
9 | selector:
10 | matchLabels:
11 | app: http-echo-{{$i}}
12 | template:
13 | metadata:
14 | labels:
15 | app: http-echo-{{$i}}
16 | spec:
17 | containers:
18 | - name: http-echo-{{$i}}
19 | image: haproxytech/http-echo:latest
20 | imagePullPolicy: Never
21 | args:
22 | - --default-response=hostname
23 | ports:
24 | - name: http
25 | containerPort: 8888
26 | protocol: TCP
27 | - name: https
28 | containerPort: 8443
29 | protocol: TCP
30 | ---
31 | apiVersion: v1
32 | kind: Service
33 | metadata:
34 | name: http-echo-{{$i}}
35 | spec:
36 | ipFamilyPolicy: RequireDualStack
37 | type: ClusterIP
38 | ports:
39 | - name: http
40 | protocol: TCP
41 | port: 80
42 | targetPort: http
43 | - name: https
44 | protocol: TCP
45 | port: 443
46 | targetPort: https
47 | selector:
48 | app: http-echo-{{$i}}
49 | {{- end }}
50 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/ingress-match/config/ingress.yaml.tmpl:
--------------------------------------------------------------------------------
1 | {{$pathType:=.PathTypeSupported}}
2 | ---
3 | kind: Ingress
4 | apiVersion: networking.k8s.io/v1
5 | metadata:
6 | name: http-echo
7 | spec:
8 | ingressClassName: haproxy
9 | rules:
10 | {{- range .Rules }}
11 | - host: "{{.Host}}"
12 | http:
13 | paths:
14 | - path: {{.Path}}
15 | {{- if $pathType}}
16 | pathType: {{.PathType}}
17 | {{- end}}
18 | backend:
19 | service:
20 | name: {{.Service}}
21 | port:
22 | name: http
23 | {{- end}}
24 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/ingressclass/config/deploy.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: http-echo
5 | spec:
6 | selector:
7 | matchLabels:
8 | app: http-echo
9 | template:
10 | metadata:
11 | labels:
12 | app: http-echo
13 | spec:
14 | containers:
15 | - name: http-echo
16 | image: haproxytech/http-echo:latest
17 | imagePullPolicy: Never
18 | args:
19 | - --default-response=hostname
20 | ports:
21 | - name: http
22 | containerPort: 8888
23 | protocol: TCP
24 | - name: https
25 | containerPort: 8443
26 | protocol: TCP
27 | ---
28 | kind: Service
29 | apiVersion: v1
30 | metadata:
31 | name: http-echo
32 | spec:
33 | ipFamilyPolicy: RequireDualStack
34 | ports:
35 | - name: http
36 | protocol: TCP
37 | port: 80
38 | targetPort: http
39 | - name: https
40 | protocol: TCP
41 | port: 443
42 | targetPort: https
43 | selector:
44 | app: http-echo
45 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/ingressclass/config/ingress.yaml.tmpl:
--------------------------------------------------------------------------------
1 | kind: Ingress
2 | apiVersion: networking.k8s.io/v1
3 | metadata:
4 | name: http-echo
5 | spec:
6 | {{ if .IngressClassName}}
7 | ingressClassName: {{ .IngressClassName}}
8 | {{ end }}
9 | rules:
10 | - host: {{ .Host }}
11 | http:
12 | paths:
13 | - path: /
14 | pathType: Prefix
15 | backend:
16 | service:
17 | name: http-echo
18 | port:
19 | name: http
20 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/ingressclass/config/ingressclass.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: networking.k8s.io/v1
3 | kind: IngressClass
4 | metadata:
5 | name: haproxy
6 | spec:
7 | controller: haproxy.org/ingress-controller/haproxy
8 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/map-updates/config/deploy.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: http-echo
5 | spec:
6 | replicas: 1
7 | selector:
8 | matchLabels:
9 | app: http-echo
10 | template:
11 | metadata:
12 | labels:
13 | app: http-echo
14 | spec:
15 | containers:
16 | - name: http-echo
17 | image: mo3m3n/http-echo:v1.0.0
18 | args:
19 | ports:
20 | - name: http
21 | containerPort: 8888
22 | protocol: TCP
23 | - name: https
24 | containerPort: 8443
25 | protocol: TCP
26 | ---
27 | kind: Service
28 | apiVersion: v1
29 | metadata:
30 | name: http-echo
31 | spec:
32 | ipFamilyPolicy: RequireDualStack
33 | ports:
34 | - name: http
35 | protocol: TCP
36 | port: 80
37 | targetPort: http
38 | - name: https
39 | protocol: TCP
40 | port: 443
41 | targetPort: https
42 | selector:
43 | app: http-echo
44 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/map-updates/config/ingress.yaml.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Ingress
3 | apiVersion: networking.k8s.io/v1
4 | metadata:
5 | name: http-echo
6 | spec:
7 | ingressClassName: haproxy
8 | rules:
9 | - host: {{ .Host }}
10 | http:
11 | paths:
12 | {{- range $path := .Paths}}
13 | - path: /{{$path}}
14 | pathType: ImplementationSpecific
15 | backend:
16 | service:
17 | name: http-echo
18 | port:
19 | name: http
20 | {{- end}}
21 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/rate-limiting/config/deploy.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Deployment
3 | apiVersion: apps/v1
4 | metadata:
5 | name: http-echo
6 | spec:
7 | replicas: 1
8 | selector:
9 | matchLabels:
10 | app: http-echo
11 | template:
12 | metadata:
13 | creationTimestamp: null
14 | labels:
15 | app: http-echo
16 | spec:
17 | containers:
18 | - name: http-echo
19 | image: haproxytech/http-echo:latest
20 | imagePullPolicy: Never
21 | args:
22 | - --default-response=hostname
23 | ports:
24 | - name: http
25 | containerPort: 8888
26 | protocol: TCP
27 | - name: https
28 | containerPort: 8443
29 | protocol: TCP
30 | ---
31 | kind: Service
32 | apiVersion: v1
33 | metadata:
34 | name: http-echo
35 | spec:
36 | ipFamilyPolicy: RequireDualStack
37 | ports:
38 | - name: http
39 | protocol: TCP
40 | port: 80
41 | targetPort: http
42 | - name: https
43 | protocol: TCP
44 | port: 443
45 | targetPort: https
46 | selector:
47 | app: http-echo
48 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/rate-limiting/config/ingress.yaml.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Ingress
3 | apiVersion: networking.k8s.io/v1
4 | metadata:
5 | name: http-echo
6 | annotations:
7 | {{- range .IngAnnotations}}
8 | {{ .Key }}: "{{ .Value }}"
9 | {{- end}}
10 | spec:
11 | ingressClassName: haproxy
12 | rules:
13 | - host: {{ .Host }}
14 | http:
15 | paths:
16 | - path: /
17 | pathType: Prefix
18 | backend:
19 | service:
20 | name: http-echo
21 | port:
22 | name: http
23 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/send-proxy-protocol/config/deploy.yaml.tmpl:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: http-echo
5 | spec:
6 | replicas: 1
7 | selector:
8 | matchLabels:
9 | app: http-echo
10 | template:
11 | metadata:
12 | labels:
13 | app: http-echo
14 | spec:
15 | containers:
16 | - name: http-echo
17 | image: 'haproxytech/proxy-protocol:latest'
18 | imagePullPolicy: IfNotPresent
19 | ports:
20 | - name: http
21 | containerPort: 8080
22 | protocol: TCP
23 | ---
24 | kind: Service
25 | apiVersion: v1
26 | metadata:
27 | name: http-echo
28 | annotations:
29 | send-proxy-protocol: proxy-v1
30 | spec:
31 | ipFamilyPolicy: RequireDualStack
32 | ports:
33 | - name: http
34 | protocol: TCP
35 | port: 8080
36 | targetPort: http
37 | selector:
38 | app: http-echo
39 | ---
40 | kind: Ingress
41 | apiVersion: networking.k8s.io/v1
42 | metadata:
43 | name: http-echo
44 | spec:
45 | ingressClassName: haproxy
46 | rules:
47 | - host: {{ .Host }}
48 | http:
49 | paths:
50 | - path: /
51 | pathType: Prefix
52 | backend:
53 | service:
54 | name: http-echo
55 | port:
56 | name: http
57 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/service-discovery/config/ingress.yaml.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Ingress
3 | apiVersion: networking.k8s.io/v1
4 | metadata:
5 | name: http-echo
6 | spec:
7 | ingressClassName: haproxy
8 | rules:
9 | - host: {{ .Host }}
10 | http:
11 | paths:
12 | - path: /
13 | pathType: Prefix
14 | backend:
15 | service:
16 | name: {{ .ServiceName }}
17 | port:
18 | {{ .PortType }}: {{ .ServicePort }}
19 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/set-header/config/deploy.yaml:
--------------------------------------------------------------------------------
1 | kind: Deployment
2 | apiVersion: apps/v1
3 | metadata:
4 | name: http-echo
5 | spec:
6 | replicas: 1
7 | selector:
8 | matchLabels:
9 | app: http-echo
10 | template:
11 | metadata:
12 | labels:
13 | app: http-echo
14 | spec:
15 | containers:
16 | - name: http-echo
17 | image: haproxytech/http-echo:latest
18 | imagePullPolicy: Never
19 | args:
20 | ports:
21 | - name: http
22 | containerPort: 8888
23 | protocol: TCP
24 | - name: https
25 | containerPort: 8443
26 | protocol: TCP
27 | ---
28 | kind: Service
29 | apiVersion: v1
30 | metadata:
31 | name: http-echo
32 | spec:
33 | ipFamilyPolicy: RequireDualStack
34 | ports:
35 | - name: http
36 | protocol: TCP
37 | port: 80
38 | targetPort: http
39 | - name: https
40 | protocol: TCP
41 | port: 443
42 | targetPort: https
43 | selector:
44 | app: http-echo
45 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/set-header/config/ingress.yaml.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | kind: Ingress
3 | apiVersion: networking.k8s.io/v1
4 | metadata:
5 | name: http-echo
6 | annotations:
7 | {{- range .IngAnnotations}}
8 | {{ .Key }}: "{{ .Value }}"
9 | {{- end}}
10 | spec:
11 | ingressClassName: haproxy
12 | rules:
13 | - host: {{ .Host }}
14 | http:
15 | paths:
16 | - path: /
17 | pathType: Prefix
18 | backend:
19 | service:
20 | name: http-echo
21 | port:
22 | name: http
23 |
--------------------------------------------------------------------------------
/deploy/tests/e2e/tls-auth/config/client-auth.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | kind: ConfigMap
3 | apiVersion: v1
4 | metadata:
5 | name: haproxy-kubernetes-ingress
6 | namespace: haproxy-controller
7 | data:
8 | ssl-certificate: e2e-tests-tls-auth/default-cert
9 | client-ca: e2e-tests-tls-auth/client-ca
10 | syslog-server: |
11 | address: stdout, format: raw, facility:daemon
12 | maxconn: "1000"
13 | server-slots: "4"
14 | timeout-client: 50s
15 | timeout-connect: 5s
16 | timeout-http-keep-alive: 1m
17 | timeout-http-request: 5s
18 | timeout-queue: 5s
19 | timeout-server: 50s
20 | timeout-tunnel: 1h
21 |
--------------------------------------------------------------------------------
/deploy/tests/images/http-echo/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.24-alpine AS builder
2 |
3 | COPY *.go /src/
4 | COPY go.mod /src/go.mod
5 |
6 | RUN cd /src && go build -o echo-http
7 |
8 | FROM alpine:3
9 | RUN apk --no-cache add openssl
10 | WORKDIR /app
11 | COPY --from=builder /src/echo-http .
12 | COPY generate-cert.sh .
13 | RUN chmod +x generate-cert.sh
14 |
15 | ENTRYPOINT ["./echo-http"]
16 | CMD []
17 |
--------------------------------------------------------------------------------
/deploy/tests/images/http-echo/README.md:
--------------------------------------------------------------------------------
1 | # http-echo
2 |
3 | A simple golang HTTP/S server that echoes back request attributes to the client in JSON formats.
4 | By default the certificate CN is the hostname of the machine where the program is running.
5 |
6 | ## How to use
7 |
8 | ```bash
9 | docker build -t haproxytech/http-echo -f deploy/tests/images/http-echo/Dockerfile deploy/tests/images/http-echo
10 | docker run -p 8888:80 -p 8443:443 --rm -t haproxytech/http-echo
11 | ```
12 |
13 | ## Output example
14 |
15 | ```bash
16 | curl -b "test=bar" -k https://localhost:8443/path\?a\=foo1\&b\=foo2
17 | ````
18 | ```json
19 | {
20 | "http": {
21 | "cookies": [
22 | "test=bar"
23 | ],
24 | "headers": {
25 | "Accept": "*/*",
26 | "Cookie": "test=bar",
27 | "User-Agent": "curl/7.70.0"
28 | },
29 | "host": "localhost:8443",
30 | "method": "GET",
31 | "path": "/path",
32 | "protocol": "HTTP/2.0",
33 | "query": "a=foo1\u0026b=foo2",
34 | "raw": "GET /path?a=foo1\u0026b=foo2 HTTP/1.1\r\nHost: localhost:8443\r\nUser-Agent: curl/7.70.0\r\nAccept: */*\r\nCookie: test=bar\r\n\r\n"
35 | },
36 | "os": {
37 | "hostname": "traktour"
38 | },
39 | "tcp": {
40 | "ip": "[::1]",
41 | "port": "53364"
42 | },
43 | "tls": {
44 | "cipher": "TLS_AES_128_GCM_SHA256",
45 | "sni": "localhost"
46 | }
47 | }
48 | ```
49 |
50 |
51 | ## Credits
52 |
53 | [mendhak/docker-http-https-echo](https://github.com/mendhak/docker-http-https-echo)
54 |
--------------------------------------------------------------------------------
/deploy/tests/images/http-echo/generate-cert.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 |
3 | set -e
4 | if [ -z $SUBJECT ];
5 | then
6 | SUBJECT="/C=FR/L=PARIS/O=Echo HTTP/CN=$(hostname)"
7 | fi
8 | openssl req -x509 -nodes -days 365 \
9 | -newkey rsa:2048 \
10 | -keyout server.key \
11 | -out server.crt \
12 | -subj "$SUBJECT"
13 |
--------------------------------------------------------------------------------
/deploy/tests/images/http-echo/go.mod:
--------------------------------------------------------------------------------
1 | module echo-http
2 |
3 | go 1.24
4 |
--------------------------------------------------------------------------------
/deploy/tests/images/proxy-protocol/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.22-alpine AS builder
2 |
3 | COPY *.go /src/
4 | COPY go.mod /src/go.mod
5 | COPY go.sum /src/go.sum
6 |
7 | RUN cd /src && go build -o proxy-protocol
8 |
9 | FROM alpine:3
10 | WORKDIR /app
11 | COPY --from=builder /src/proxy-protocol .
12 |
13 | ENTRYPOINT ["./proxy-protocol"]
14 | CMD []
15 |
--------------------------------------------------------------------------------
/deploy/tests/images/proxy-protocol/README.md:
--------------------------------------------------------------------------------
1 | # proxy-protocol
2 |
3 | A simple Go web server backed by PROXY Protocol.
4 |
5 | ## How to use
6 |
7 | ```bash
8 | docker build -t haproxytech/proxy-protocol -f deploy/tests/images/proxy-protocol/Dockerfile deploy/tests/images/proxy-protocol
9 | docker run -p 8080:8080 --rm -t haproxytech/proxy-protocol
10 | ```
11 |
12 | ## Output example
13 |
14 | ```
15 | $: curl --haproxy-protocol --http1.1 http://localhost:8080/
16 | hello!
17 | ````
18 |
19 | ## Credits
20 |
21 | [github.com/pires/go-proxyproto](https://github.com/pires/go-proxyproto)
--------------------------------------------------------------------------------
/deploy/tests/images/proxy-protocol/go.mod:
--------------------------------------------------------------------------------
1 | module proxy-protocol
2 |
3 | go 1.22.0
4 |
5 | require github.com/pires/go-proxyproto v0.8.0
6 |
--------------------------------------------------------------------------------
/deploy/tests/images/proxy-protocol/go.sum:
--------------------------------------------------------------------------------
1 | github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0=
2 | github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY=
3 |
--------------------------------------------------------------------------------
/deploy/tests/images/proxy-protocol/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net"
6 | "net/http"
7 | "os"
8 |
9 | "github.com/pires/go-proxyproto"
10 | )
11 |
12 | func main() {
13 | // Create a TCP listener on port 8080
14 | addr := ":8080"
15 | tcpListener, err := net.Listen("tcp", addr)
16 | if err != nil {
17 | fmt.Fprintf(os.Stderr, "Error creating TCP listener: %v\n", err)
18 | os.Exit(1)
19 | }
20 |
21 | // Wrap it with the PROXY protocol listener
22 | proxyListener := &proxyproto.Listener{Listener: tcpListener}
23 |
24 | // Ensure the listener is closed on shutdown
25 | defer proxyListener.Close()
26 |
27 | // HTTP handler
28 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
29 | fmt.Fprint(w, "hello!")
30 | })
31 |
32 | // Serve using custom listener
33 | fmt.Printf("Listening on %s with PROXY protocol support...\n", addr)
34 | if err := http.Serve(proxyListener, nil); err != nil {
35 | fmt.Fprintf(os.Stderr, "HTTP server error: %v\n", err)
36 | os.Exit(1)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/deploy/tests/kind-config.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kind.x-k8s.io/v1alpha4
2 | networking:
3 | ipFamily: dual
4 | apiServerAddress: "127.0.0.1"
5 | apiServerPort: 6443
6 | kind: Cluster
7 | nodes:
8 | - role: control-plane
9 | image: kindest/node:v1.32.2
10 | extraPortMappings:
11 | - hostPort: 30080
12 | containerPort: 30080
13 | #listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
14 | #protocol: udp # Optional, defaults to tcp
15 | - hostPort: 30443
16 | containerPort: 30443
17 | - hostPort: 31024
18 | containerPort: 31024
19 | - hostPort: 32766
20 | containerPort: 32766
21 | - hostPort: 32767
22 | containerPort: 32767
23 | - hostPort: 32765 # gwapi
24 | containerPort: 32765
25 | kubeadmConfigPatches:
26 | - |
27 | kind: ClusterConfiguration
28 | controllerManager:
29 | extraArgs:
30 | max-endpoints-per-slice: "5"
31 | node-cidr-mask-size-ipv4: "21"
32 | - |
33 | apiVersion: kubelet.config.k8s.io/v1beta1
34 | kind: KubeletConfiguration
35 | metadata:
36 | name: config
37 | maxPods: 2048
38 |
--------------------------------------------------------------------------------
/deploy/tests/rebuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | command -v kind >/dev/null 2>&1 || { echo >&2 "Kind not installed. Aborting."; exit 1; }
5 | command -v kubectl >/dev/null 2>&1 || { echo >&2 "Kubectl not installed. Aborting."; exit 1; }
6 | DIR=$(dirname "$0")
7 |
8 | echo "delete image of ingress controller"
9 | kubectl delete -f $DIR/config/3.ingress-controller.yaml
10 |
11 | echo "building image for ingress controller"
12 | docker build -t haproxytech/kubernetes-ingress -f build/Dockerfile .
13 | kind --name=dev load docker-image haproxytech/kubernetes-ingress:latest
14 |
15 | echo "deploying Ingress Controller ..."
16 | kubectl apply -f $DIR/config/3.ingress-controller.yaml
17 |
18 | echo "wait --for=condition=ready ..."
19 | COUNTER=0
20 | while [ $COUNTER -lt 150 ]; do
21 | sleep 2
22 | kubectl get pods -n haproxy-controller --no-headers --selector=run=haproxy-ingress | awk '{print "haproxy-controller/haproxy-kubernetes-ingress " $3 " " $5}'
23 | result=$(kubectl get pods -n haproxy-controller --no-headers --selector=run=haproxy-ingress | awk '{print $3}')
24 | if [ "$result" = "Running" ]; then
25 | COUNTER=151
26 | else
27 | COUNTER=`expr $COUNTER + 1`
28 | fi
29 | done
30 |
31 | kubectl wait --for=condition=ready --timeout=10s pod -l run=haproxy-ingress -n haproxy-controller
32 |
--------------------------------------------------------------------------------
/deploy/tests/tnr/routeacl/usebackend_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package routeacl
16 |
17 | import (
18 | "os"
19 | "path/filepath"
20 | "strings"
21 | )
22 |
23 | func (suite *UseBackendSuite) TestUseBackend() {
24 | // This test addresses https://github.com/haproxytech/kubernetes-ingress/issues/476
25 | suite.UseBackendFixture()
26 | suite.Run("Modifying service annotations should not duplicate use_backend clause", func() {
27 | contents, err := os.ReadFile(filepath.Join(suite.test.TempDir, "haproxy.cfg"))
28 | if err != nil {
29 | suite.T().Error(err.Error())
30 | }
31 | c := strings.Count(string(contents), "use_backend ns_myappservice_https if { path -m beg / } { cookie(staging) -m found }")
32 | suite.Exactly(c, 2, "use_backend for route-acl is repeated %d times but expected 2", c)
33 | })
34 | }
35 |
--------------------------------------------------------------------------------
/deploy/tests/ut/acls/acls_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package acls
16 |
17 | import (
18 | "os"
19 | "path/filepath"
20 | "strings"
21 | )
22 |
23 | func (suite *ACLSuite) TestACL() {
24 | suite.UseACLFixture()
25 | contents, err := os.ReadFile(filepath.Join(suite.test.TempDir, "haproxy.cfg"))
26 | if err != nil {
27 | suite.T().Error(err.Error())
28 | }
29 |
30 | suite.Run("acl cookie_found", func() {
31 | c := strings.Count(string(contents), "acl cookie_found cook(JSESSIONID) -m found")
32 | suite.Exactly(c, 1, "acl cookie_found is repeated %d times but expected 1", c)
33 | c = strings.Count(string(contents), "acl is_ticket path_beg -i /ticket")
34 | suite.Exactly(c, 1, "acl is_ticket is repeated %d times but expected 1", c)
35 | })
36 |
37 | suite.Run("acl is_ticket", func() {
38 | c := strings.Count(string(contents), "acl is_ticket path_beg -i /ticket")
39 | suite.Exactly(c, 1, "acl is_ticket is repeated %d times but expected 1", c)
40 | })
41 | }
42 |
--------------------------------------------------------------------------------
/deploy/tests/ut/httprequests/httprequests_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package httprequests
16 |
17 | import (
18 | "os"
19 | "path/filepath"
20 | "strings"
21 | )
22 |
23 | func (suite *HTTPRequestsSuite) TestHTTPRequests() {
24 | suite.UseHTTPRequestsFixture()
25 | contents, err := os.ReadFile(filepath.Join(suite.test.TempDir, "haproxy.cfg"))
26 | if err != nil {
27 | suite.T().Fatal(err.Error())
28 | }
29 |
30 | suite.Run("http-request set-var(txn.admintenant)", func() {
31 | c := strings.Count(string(contents), "http-request set-var(txn.admintenant) str({{RUN.serviceId2}})")
32 | suite.Exactly(c, 1, "http-request set-var(txn.admintenant) is repeated %d times but expected 1", c)
33 | })
34 |
35 | suite.Run("http-request track-sc1 txn.key", func() {
36 | c := strings.Count(string(contents), " table connected.local if cookie_found")
37 | suite.Exactly(c, 1, "http-request track-sc1 txn.key is repeated %d times but expected 1", c)
38 | })
39 | }
40 |
--------------------------------------------------------------------------------
/documentation/README.md:
--------------------------------------------------------------------------------
1 |
2 | # 
3 |
4 | ## HAProxy kubernetes ingress controller 3.0
5 |
6 | ### Documentation
7 |
8 | - [Controller options](controller.md)
9 | - [Custom resource definitions](custom-resources.md)
10 | - [Annotations](annotations.md)
11 | - [Prometheus](prometheus.md)
12 |
13 | ### Lifecycle
14 |
15 | - [Lifecycle](lifecycle.md)
16 |
17 | #### Experimental
18 | - [Gateway API](gateway-api.md)
19 |
20 | #### Additional
21 | - [Supervisor](pebble.md)
22 |
23 | This is autogenerated from [doc.yaml](doc.yaml). Description can be found in [generator readme](gen/README.md)
24 |
25 |
--------------------------------------------------------------------------------
/documentation/gen/go.mod:
--------------------------------------------------------------------------------
1 | module doc-gen
2 |
3 | go 1.24
4 |
5 | require (
6 | github.com/google/renameio v1.0.1
7 | gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99
8 | )
9 |
--------------------------------------------------------------------------------
/documentation/gen/go.sum:
--------------------------------------------------------------------------------
1 | github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
2 | github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
3 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
4 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5 | gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99 h1:dbuHpmKjkDzSOMKAWl10QNlgaZUd3V1q99xc81tt2Kc=
6 | gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
7 |
--------------------------------------------------------------------------------
/documentation/gen/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | func main() {
4 | var cn Conf
5 | cn.getConf()
6 |
7 | cn.generateReadme()
8 | cn.generateReadmeAnnotations()
9 | cn.generateReadmeController()
10 | cn.generateSupport()
11 | // cn.saveConf()
12 | // cn.saveDocConf()
13 | }
14 |
--------------------------------------------------------------------------------
/documentation/gen/version.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "strings"
7 | )
8 |
9 | type Version struct {
10 | Major int
11 | Minor int
12 | }
13 |
14 | // Implements the Unmarshaler interface of the yaml pkg.
15 | func (v *Version) UnmarshalYAML(unmarshal func(interface{}) error) error {
16 | var data string
17 | err := unmarshal(&data)
18 | if err != nil {
19 | return err
20 | }
21 |
22 | parts := strings.Split(data, ".")
23 | if len(parts) != 2 {
24 | return fmt.Errorf("version is not in correct format")
25 | }
26 | v.Major, err = strconv.Atoi(parts[0])
27 | if err != nil {
28 | return err
29 | }
30 | v.Minor, err = strconv.Atoi(parts[1])
31 | if err != nil {
32 | return err
33 | }
34 | return nil
35 | }
36 |
37 | func (v *Version) String() string {
38 | return fmt.Sprintf("%d.%d", v.Major, v.Minor)
39 | }
40 |
41 | func (v *Version) LowerOrEqual(active Version) bool {
42 | if active.Major < v.Major {
43 | return false
44 | }
45 | if active.Major != v.Major {
46 | return true
47 | }
48 | if active.Minor < v.Minor {
49 | return false
50 | }
51 | return true
52 | }
53 |
54 | func (v Version) MarshalYAML() (interface{}, error) {
55 | return v.String(), nil
56 | }
57 |
--------------------------------------------------------------------------------
/documentation/lifecycle.md:
--------------------------------------------------------------------------------
1 |
2 | # 
3 |
4 | ## HAProxy kubernetes ingress controller
5 |
6 | ### Lifecycle
7 |
8 | | Version | GA | EOL | HAProxy | *k8s versions |
9 | | -:|:-:|:-:|:-:|:-:|
10 | | **3.1** | 2025-01 | 2026-02 | 3.1 | 1.32, 1.31, 1.30 |
11 | | **3.0** | 2024-06 | 2025-06 | 3.0 | 1.30, 1.29, 1.28 |
12 | | **1.11** | 2024-02 | 2025-02 | 2.8 | 1.28, 1.27, 1.26 |
13 | | **1.10** | 2023-04 | 2024-06 | 2.7 | 1.27, 1.26, 1.25 |
14 | | **1.9** | 2022-10 | 2023-11 | 2.6 | 1.25, 1.24, 1.23 |
15 | | **1.8** | 2022-06 | 2023-05 | 2.5 | 1.23, 1.22, 1.21 |
16 |
17 | **Note:** for specific version of controller, only k8s versions that are thoroughly tested with that version are listed
18 |
19 | This is autogenerated from [lifecycle.yaml](lifecycle.yaml). Description can be found in [generator readme](gen/README.md)
20 |
--------------------------------------------------------------------------------
/documentation/lifecycle.yaml:
--------------------------------------------------------------------------------
1 | versions:
2 | - version: "3.1"
3 | ga: 2025-01
4 | min_eol: 2026-02
5 | k8s:
6 | - "1.32"
7 | - "1.31"
8 | - "1.30"
9 | - version: "3.0"
10 | ga: 2024-06
11 | min_eol: 2025-06
12 | k8s:
13 | - "1.30"
14 | - "1.29"
15 | - "1.28"
16 | - version: "1.11"
17 | ga: 2024-02
18 | min_eol: 2025-02
19 | k8s:
20 | - "1.28"
21 | - "1.27"
22 | - "1.26"
23 | haproxy: "2.8"
24 | - version: "1.10"
25 | ga: 2023-04
26 | min_eol: 2024-06
27 | k8s:
28 | - "1.27"
29 | - "1.26"
30 | - "1.25"
31 | haproxy: "2.7"
32 | - version: "1.9"
33 | ga: 2022-10
34 | min_eol: 2023-11
35 | k8s:
36 | - "1.25"
37 | - "1.24"
38 | - "1.23"
39 | haproxy: "2.6"
40 | - version: "1.8"
41 | ga: 2022-06
42 | min_eol: 2023-05
43 | k8s:
44 | - "1.23"
45 | - "1.22"
46 | - "1.21"
47 | haproxy: "2.5"
48 |
--------------------------------------------------------------------------------
/documentation/tcp-cr-full-example/echo-0.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | annotations:
6 | deployment.kubernetes.io/revision: "1"
7 | name: http-echo-0
8 | spec:
9 | progressDeadlineSeconds: 600
10 | replicas: 1
11 | revisionHistoryLimit: 10
12 | selector:
13 | matchLabels:
14 | app: http-echo-0
15 | strategy:
16 | rollingUpdate:
17 | maxSurge: 25%
18 | maxUnavailable: 25%
19 | type: RollingUpdate
20 | template:
21 | metadata:
22 | labels:
23 | app: http-echo-0
24 | spec:
25 | containers:
26 | - args:
27 | - --default-response=hostname
28 | image: haproxytech/http-echo:latest
29 | imagePullPolicy: Never
30 | name: http-echo
31 | ports:
32 | - containerPort: 8888
33 | name: http
34 | protocol: TCP
35 | - containerPort: 8443
36 | name: https
37 | protocol: TCP
38 | terminationMessagePath: /dev/termination-log
39 | terminationMessagePolicy: File
40 | dnsPolicy: ClusterFirst
41 | restartPolicy: Always
42 | schedulerName: default-scheduler
43 | terminationGracePeriodSeconds: 30
44 | ---
45 | apiVersion: v1
46 | kind: Service
47 | metadata:
48 | name: http-echo-0
49 | spec:
50 | internalTrafficPolicy: Cluster
51 | ipFamilies:
52 | - IPv4
53 | - IPv6
54 | ipFamilyPolicy: RequireDualStack
55 | ports:
56 | - name: http
57 | port: 80
58 | targetPort: http
59 | - name: https
60 | port: 443
61 | targetPort: https
62 | selector:
63 | app: http-echo-0
64 |
--------------------------------------------------------------------------------
/documentation/tcp-cr-full-example/echo.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | annotations:
6 | deployment.kubernetes.io/revision: "1"
7 | name: http-echo
8 | spec:
9 | progressDeadlineSeconds: 600
10 | replicas: 1
11 | revisionHistoryLimit: 10
12 | selector:
13 | matchLabels:
14 | app: http-echo
15 | strategy:
16 | rollingUpdate:
17 | maxSurge: 25%
18 | maxUnavailable: 25%
19 | type: RollingUpdate
20 | template:
21 | metadata:
22 | labels:
23 | app: http-echo
24 | spec:
25 | containers:
26 | - args:
27 | - --default-response=hostname
28 | image: haproxytech/http-echo:latest
29 | imagePullPolicy: Never
30 | name: http-echo
31 | ports:
32 | - containerPort: 8888
33 | name: http
34 | protocol: TCP
35 | - containerPort: 8443
36 | name: https
37 | protocol: TCP
38 | terminationMessagePath: /dev/termination-log
39 | terminationMessagePolicy: File
40 | dnsPolicy: ClusterFirst
41 | restartPolicy: Always
42 | schedulerName: default-scheduler
43 | terminationGracePeriodSeconds: 30
44 | ---
45 | apiVersion: v1
46 | kind: Service
47 | metadata:
48 | name: http-echo
49 | spec:
50 | internalTrafficPolicy: Cluster
51 | ipFamilies:
52 | - IPv4
53 | - IPv6
54 | ipFamilyPolicy: RequireDualStack
55 | ports:
56 | - name: http
57 | port: 80
58 | targetPort: http
59 | - name: https
60 | port: 443
61 | targetPort: https
62 | selector:
63 | app: http-echo
64 |
--------------------------------------------------------------------------------
/examples/test-informers/replay-delete.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | curl -X DELETE -H "Content-Type: application/yaml" --data-binary @configmap.yaml http://localhost:8081
3 | curl -X DELETE -H "Content-Type: application/yaml" --data-binary @echo-app.yaml http://localhost:8081
4 | curl -X DELETE -H "Content-Type: application/yaml" --data-binary @echo.endpointslices.yaml http://localhost:8081
5 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/aux-cfg/type:
--------------------------------------------------------------------------------
1 | oneshot
2 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/aux-cfg/up:
--------------------------------------------------------------------------------
1 | /etc/s6-overlay/scripts/01-aux-cfg
2 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/haproxy/dependencies.d/aux-cfg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/fs/etc/s6-overlay/s6-rc.d/haproxy/dependencies.d/aux-cfg
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/haproxy/dependencies.d/base:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/fs/etc/s6-overlay/s6-rc.d/haproxy/dependencies.d/base
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/haproxy/dependencies.d/sigusr1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/fs/etc/s6-overlay/s6-rc.d/haproxy/dependencies.d/sigusr1
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/haproxy/run:
--------------------------------------------------------------------------------
1 | #!/command/with-contenv sh
2 |
3 | MEMLIMIT=$(free -m | awk '/Mem:/ {printf "%d\n", int($2 * 2 / 3)}')
4 |
5 | CG_LIMIT_FILE="/sys/fs/cgroup/memory/memory.limit_in_bytes"
6 | if [ -f "/sys/fs/cgroup/cgroup.controllers" ]; then
7 | CG_LIMIT_FILE="/sys/fs/cgroup/memory.max"
8 | fi
9 |
10 | if [ -r "${CG_LIMIT_FILE}" ]; then
11 | if grep -q '^max$' "${CG_LIMIT_FILE}"; then
12 | MEMLIMIT_CG="${MEMLIMIT}"
13 | else
14 | MEMLIMIT_CG=$(awk '{printf "%d\n", int($1 / 1024 / 1024 * 2 / 3)}' "${CG_LIMIT_FILE}")
15 | fi
16 |
17 | if [ "${MEMLIMIT_CG}" -gt 0 ]; then
18 | if [ "${MEMLIMIT_CG}" -lt "${MEMLIMIT}" ]; then
19 | MEMLIMIT="${MEMLIMIT_CG}"
20 | fi
21 | fi
22 | fi
23 |
24 | echo "Memory limit for HAProxy: ${MEMLIMIT}MiB"
25 |
26 | # if master socket is changed, that needs to be aligned in pkg/haproxy/process/interface.go
27 | exec /usr/local/sbin/haproxy -W -db -m "${MEMLIMIT}" -S /var/run/haproxy-master.sock,level,admin -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/haproxy-aux.cfg
28 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/haproxy/type:
--------------------------------------------------------------------------------
1 | longrun
2 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/ingress-controller/dependencies.d/aux-cfg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/fs/etc/s6-overlay/s6-rc.d/ingress-controller/dependencies.d/aux-cfg
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/ingress-controller/dependencies.d/base:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/fs/etc/s6-overlay/s6-rc.d/ingress-controller/dependencies.d/base
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/ingress-controller/dependencies.d/haproxy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/fs/etc/s6-overlay/s6-rc.d/ingress-controller/dependencies.d/haproxy
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/ingress-controller/dependencies.d/sigusr1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/fs/etc/s6-overlay/s6-rc.d/ingress-controller/dependencies.d/sigusr1
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/ingress-controller/finish:
--------------------------------------------------------------------------------
1 | #!/command/with-contenv sh
2 |
3 | if [ "${1}" -ne 0 ] && [ "${1}" -ne 256 ]; then
4 | echo "Ingress Controller exited with fatal code ${1}, taking down the S6 supervision tree"
5 |
6 | exec /run/s6/basedir/bin/halt
7 | fi
8 |
9 | echo "Ingress Controller exited with code ${1}, restarting..."
10 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/ingress-controller/run:
--------------------------------------------------------------------------------
1 | #!/command/with-contenv sh
2 |
3 | MEMLIMIT=$(free -m | awk '/Mem:/ {printf "%d\n", int($2 / 3)}')
4 |
5 | CG_LIMIT_FILE="/sys/fs/cgroup/memory/memory.limit_in_bytes"
6 | if [ -f "/sys/fs/cgroup/cgroup.controllers" ]; then
7 | CG_LIMIT_FILE="/sys/fs/cgroup/memory.max"
8 | fi
9 |
10 | if [ -r "${CG_LIMIT_FILE}" ]; then
11 | if grep -q '^max$' "${CG_LIMIT_FILE}"; then
12 | MEMLIMIT_CG="${MEMLIMIT}"
13 | else
14 | MEMLIMIT_CG=$(awk '{printf "%d\n", int($1 / 1024 / 1024 / 3)}' "${CG_LIMIT_FILE}")
15 | fi
16 |
17 | if [ "${MEMLIMIT_CG}" -gt 0 ]; then
18 | if [ "${MEMLIMIT_CG}" -lt "${MEMLIMIT}" ]; then
19 | MEMLIMIT="${MEMLIMIT_CG}"
20 | fi
21 | fi
22 | fi
23 |
24 | export GOMEMLIMIT="${MEMLIMIT}MiB"
25 |
26 | echo "Memory limit for Ingress Controller: ${GOMEMLIMIT}"
27 |
28 | exec /haproxy-ingress-controller --with-s6-overlay ${EXTRA_OPTIONS}
29 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/ingress-controller/type:
--------------------------------------------------------------------------------
1 | longrun
2 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/sigusr1/type:
--------------------------------------------------------------------------------
1 | oneshot
2 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/sigusr1/up:
--------------------------------------------------------------------------------
1 | /etc/s6-overlay/scripts/00-sigusr1
2 |
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/user/contents.d/haproxy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/fs/etc/s6-overlay/s6-rc.d/user/contents.d/haproxy
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/s6-rc.d/user/contents.d/ingress-controller:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haproxytech/kubernetes-ingress/b7036e43cc162b92f3ff830ed5592c3a984eeb3e/fs/etc/s6-overlay/s6-rc.d/user/contents.d/ingress-controller
--------------------------------------------------------------------------------
/fs/etc/s6-overlay/scripts/00-sigusr1:
--------------------------------------------------------------------------------
1 | #!/command/with-contenv sh
2 |
3 | SVSCAN_PATH="/run/s6/basedir/run-image/service/.s6-svscan"
4 |
5 | if [ ! -f "${SVSCAN_PATH}/SIGUSR1" ]; then
6 | cat > "${SVSCAN_PATH}/SIGUSR1" < maxProcs {
39 | v = maxProcs
40 | }
41 | a.global.Nbthread = int64(v)
42 | return nil
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/annotations/ingress/reqPathRewrite.go:
--------------------------------------------------------------------------------
1 | package ingress
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/rules"
9 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
10 | )
11 |
12 | type ReqPathRewrite struct {
13 | rules *rules.List
14 | name string
15 | }
16 |
17 | func NewReqPathRewrite(n string, r *rules.List) *ReqPathRewrite {
18 | return &ReqPathRewrite{name: n, rules: r}
19 | }
20 |
21 | func (a *ReqPathRewrite) GetName() string {
22 | return a.name
23 | }
24 |
25 | func (a *ReqPathRewrite) Process(k store.K8s, annotations ...map[string]string) (err error) {
26 | input := strings.TrimSpace(common.GetValue(a.GetName(), annotations...))
27 | if input == "" {
28 | return
29 | }
30 | for _, rule := range strings.Split(input, "\n") {
31 | parts := strings.Fields(strings.TrimSpace(rule))
32 |
33 | var rewrite *rules.ReqPathRewrite
34 | switch len(parts) {
35 | case 1:
36 | rewrite = &rules.ReqPathRewrite{
37 | PathMatch: "(.*)",
38 | PathFmt: parts[0],
39 | }
40 | case 2:
41 | rewrite = &rules.ReqPathRewrite{
42 | PathMatch: parts[0],
43 | PathFmt: parts[1],
44 | }
45 | default:
46 | return fmt.Errorf("incorrect value '%s', path-rewrite takes 1 or 2 params ", input)
47 | }
48 | a.rules.Add(rewrite)
49 | }
50 | return
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/annotations/ingress/reqSetHdr.go:
--------------------------------------------------------------------------------
1 | package ingress
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/rules"
9 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
10 | )
11 |
12 | type SetHdr struct {
13 | rules *rules.List
14 | name string
15 | response bool
16 | }
17 |
18 | func NewReqSetHdr(n string, r *rules.List) *SetHdr {
19 | return &SetHdr{name: n, rules: r}
20 | }
21 |
22 | func NewResSetHdr(n string, r *rules.List) *SetHdr {
23 | return &SetHdr{name: n, rules: r, response: true}
24 | }
25 |
26 | func (a *SetHdr) GetName() string {
27 | return a.name
28 | }
29 |
30 | func (a *SetHdr) Process(k store.K8s, annotations ...map[string]string) (err error) {
31 | input := common.GetValue(a.GetName(), annotations...)
32 | if input == "" {
33 | return
34 | }
35 | for _, param := range strings.Split(input, "\n") {
36 | if param == "" {
37 | continue
38 | }
39 | indexSpace := strings.IndexByte(param, ' ')
40 | if indexSpace == -1 {
41 | return fmt.Errorf("incorrect value '%s' in request-set-header annotation", param)
42 | }
43 | a.rules.Add(&rules.SetHdr{
44 | HdrName: param[:indexSpace],
45 | HdrFormat: "\"" + param[indexSpace+1:] + "\"",
46 | Response: a.response,
47 | })
48 | }
49 | return
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/annotations/ingress/reqSetHost.go:
--------------------------------------------------------------------------------
1 | package ingress
2 |
3 | import (
4 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
5 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/rules"
6 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
7 | )
8 |
9 | type ReqSetHost struct {
10 | rules *rules.List
11 | name string
12 | }
13 |
14 | func NewReqSetHost(n string, r *rules.List) *ReqSetHost {
15 | return &ReqSetHost{name: n, rules: r}
16 | }
17 |
18 | func (a *ReqSetHost) GetName() string {
19 | return a.name
20 | }
21 |
22 | func (a *ReqSetHost) Process(k store.K8s, annotations ...map[string]string) (err error) {
23 | input := common.GetValue(a.GetName(), annotations...)
24 | if input == "" {
25 | return
26 | }
27 | a.rules.Add(&rules.SetHdr{
28 | HdrName: "Host",
29 | HdrFormat: input,
30 | })
31 | return
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/annotations/ingress/srcIPHdr.go:
--------------------------------------------------------------------------------
1 | package ingress
2 |
3 | import (
4 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
5 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/rules"
6 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
7 | )
8 |
9 | type SrcIPHdr struct {
10 | rules *rules.List
11 | name string
12 | }
13 |
14 | func NewSrcIPHdr(n string, r *rules.List) *SrcIPHdr {
15 | return &SrcIPHdr{name: n, rules: r}
16 | }
17 |
18 | func (a *SrcIPHdr) GetName() string {
19 | return a.name
20 | }
21 |
22 | func (a *SrcIPHdr) Process(k store.K8s, annotations ...map[string]string) (err error) {
23 | input := common.GetValue(a.GetName(), annotations...)
24 | if input == "" {
25 | return
26 | }
27 | a.rules.Add(&rules.ReqSetSrc{
28 | HeaderName: input,
29 | })
30 | return
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/annotations/service/abortOnClose.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/haproxytech/client-native/v6/models"
5 |
6 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
7 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
8 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
9 | )
10 |
11 | type AbortOnClose struct {
12 | backend *models.Backend
13 | name string
14 | }
15 |
16 | func NewAbortOnClose(n string, b *models.Backend) *AbortOnClose {
17 | return &AbortOnClose{name: n, backend: b}
18 | }
19 |
20 | func (a *AbortOnClose) GetName() string {
21 | return a.name
22 | }
23 |
24 | func (a *AbortOnClose) Process(k store.K8s, annotations ...map[string]string) error {
25 | input := common.GetValue(a.GetName(), annotations...)
26 | var enabled bool
27 | var err error
28 | if input != "" {
29 | enabled, err = utils.GetBoolValue(input, "abortonclose")
30 | if err != nil {
31 | return err
32 | }
33 | }
34 | if enabled {
35 | a.backend.Abortonclose = "enabled"
36 | } else {
37 | a.backend.Abortonclose = "disabled"
38 | }
39 | return nil
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/annotations/service/backendForwardedFor.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
9 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
10 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
11 | )
12 |
13 | type ForwardedFor struct {
14 | backend *models.Backend
15 | name string
16 | }
17 |
18 | func NewForwardedFor(n string, b *models.Backend) *ForwardedFor {
19 | return &ForwardedFor{name: n, backend: b}
20 | }
21 |
22 | func (a *ForwardedFor) GetName() string {
23 | return a.name
24 | }
25 |
26 | func (a *ForwardedFor) Process(k store.K8s, annotations ...map[string]string) error {
27 | input := common.GetValue(a.GetName(), annotations...)
28 | if input == "" {
29 | a.backend.Forwardfor = nil
30 | return nil
31 | }
32 | var params *models.Forwardfor
33 | enabled, err := utils.GetBoolValue(input, "forwarded-for")
34 | if err != nil {
35 | return err
36 | }
37 | if enabled {
38 | params = &models.Forwardfor{
39 | Enabled: utils.PtrString("enabled"),
40 | }
41 | if err = params.Validate(nil); err != nil {
42 | return fmt.Errorf("forwarded-for: %w", err)
43 | }
44 | }
45 | a.backend.Forwardfor = params
46 | return nil
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/annotations/service/check.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/haproxytech/client-native/v6/models"
5 |
6 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
7 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
8 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
9 | )
10 |
11 | type Check struct {
12 | backend *models.Backend
13 | name string
14 | }
15 |
16 | func NewCheck(n string, b *models.Backend) *Check {
17 | return &Check{name: n, backend: b}
18 | }
19 |
20 | func (a *Check) GetName() string {
21 | return a.name
22 | }
23 |
24 | // the value models.DefaultSever.Check should be a bool value and not an enum [enabled, disabled]
25 | // this avoids an uncessary update when models.DefaultSever.Check is set form empty to "disabled"
26 | func (a *Check) Process(k store.K8s, annotations ...map[string]string) error {
27 | input := common.GetValue(a.GetName(), annotations...)
28 | if input == "" {
29 | if a.backend.DefaultServer != nil {
30 | a.backend.DefaultServer.Check = ""
31 | }
32 | return nil
33 | }
34 | enabled, err := utils.GetBoolValue(input, "check")
35 | if err != nil {
36 | return err
37 | }
38 | if !enabled {
39 | if a.backend.DefaultServer != nil {
40 | a.backend.DefaultServer.Check = ""
41 | }
42 | return nil
43 | }
44 | if a.backend.DefaultServer == nil {
45 | a.backend.DefaultServer = &models.DefaultServer{ServerParams: models.ServerParams{Check: "enabled"}}
46 | } else {
47 | a.backend.DefaultServer.Check = "enabled"
48 | }
49 | return nil
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/annotations/service/checkHTTP.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "errors"
5 | "strings"
6 |
7 | "github.com/haproxytech/client-native/v6/models"
8 |
9 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
10 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
11 | )
12 |
13 | type CheckHTTP struct {
14 | backend *models.Backend
15 | name string
16 | }
17 |
18 | func NewCheckHTTP(n string, b *models.Backend) *CheckHTTP {
19 | return &CheckHTTP{name: n, backend: b}
20 | }
21 |
22 | func (a *CheckHTTP) GetName() string {
23 | return a.name
24 | }
25 |
26 | func (a *CheckHTTP) Process(k store.K8s, annotations ...map[string]string) error {
27 | input := common.GetValue(a.GetName(), annotations...)
28 | if input == "" {
29 | a.backend.AdvCheck = ""
30 | a.backend.HttpchkParams = nil
31 | return nil
32 | }
33 | var params *models.HttpchkParams
34 | checkHTTPParams := strings.Fields(strings.TrimSpace(input))
35 | switch len(checkHTTPParams) {
36 | case 0:
37 | return errors.New("httpchk option: incorrect number of params")
38 | case 1:
39 | params = &models.HttpchkParams{
40 | URI: checkHTTPParams[0],
41 | }
42 | case 2:
43 | params = &models.HttpchkParams{
44 | Method: checkHTTPParams[0],
45 | URI: checkHTTPParams[1],
46 | }
47 | default:
48 | params = &models.HttpchkParams{
49 | Method: checkHTTPParams[0],
50 | URI: checkHTTPParams[1],
51 | Version: strings.Join(checkHTTPParams[2:], " "),
52 | }
53 | }
54 |
55 | a.backend.AdvCheck = "httpchk"
56 | a.backend.HttpchkParams = params
57 | return nil
58 | }
59 |
--------------------------------------------------------------------------------
/pkg/annotations/service/checkInter.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/haproxytech/client-native/v6/models"
5 |
6 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
7 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
8 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
9 | )
10 |
11 | type CheckInter struct {
12 | backend *models.Backend
13 | name string
14 | }
15 |
16 | func NewCheckInter(n string, b *models.Backend) *CheckInter {
17 | return &CheckInter{name: n, backend: b}
18 | }
19 |
20 | func (a *CheckInter) GetName() string {
21 | return a.name
22 | }
23 |
24 | func (a *CheckInter) Process(k store.K8s, annotations ...map[string]string) error {
25 | input := common.GetValue(a.GetName(), annotations...)
26 | if input == "" {
27 | if a.backend.DefaultServer != nil {
28 | a.backend.DefaultServer.Inter = nil
29 | }
30 | return nil
31 | }
32 | value, err := utils.ParseTime(input)
33 | if err != nil {
34 | return err
35 | }
36 | if a.backend.DefaultServer == nil {
37 | a.backend.DefaultServer = &models.DefaultServer{}
38 | }
39 | a.backend.DefaultServer.Inter = value
40 | return nil
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/annotations/service/maxconn.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "strconv"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
9 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
10 | )
11 |
12 | type Maxconn struct {
13 | backend *models.Backend
14 | name string
15 | }
16 |
17 | func NewMaxconn(n string, b *models.Backend) *Maxconn {
18 | return &Maxconn{name: n, backend: b}
19 | }
20 |
21 | func (a *Maxconn) GetName() string {
22 | return a.name
23 | }
24 |
25 | func (a *Maxconn) Process(k store.K8s, annotations ...map[string]string) error {
26 | input := common.GetValue(a.GetName(), annotations...)
27 | if input == "" {
28 | if a.backend.DefaultServer != nil {
29 | a.backend.DefaultServer.Maxconn = nil
30 | }
31 | return nil
32 | }
33 | v, err := strconv.ParseInt(input, 10, 64)
34 | if err != nil {
35 | return err
36 | }
37 | // adjust backend maxconn when using multiple HAProxy Instances
38 | if len(k.HaProxyPods) != 0 {
39 | v /= int64(len(k.HaProxyPods))
40 | }
41 | if a.backend.DefaultServer == nil {
42 | a.backend.DefaultServer = &models.DefaultServer{}
43 | }
44 | a.backend.DefaultServer.Maxconn = &v
45 | return nil
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/annotations/service/proto.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
9 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
10 | )
11 |
12 | type Proto struct {
13 | backend *models.Backend
14 | name string
15 | }
16 |
17 | func NewProto(n string, b *models.Backend) *Proto {
18 | return &Proto{name: n, backend: b}
19 | }
20 |
21 | func (a *Proto) GetName() string {
22 | return a.name
23 | }
24 |
25 | func (a *Proto) Process(k store.K8s, annotations ...map[string]string) error {
26 | input := common.GetValue(a.GetName(), annotations...)
27 | if input == "h2" {
28 | if a.backend.DefaultServer == nil {
29 | a.backend.DefaultServer = &models.DefaultServer{}
30 | }
31 | a.backend.DefaultServer.Proto = "h2"
32 | return nil
33 | } else if a.backend.DefaultServer == nil {
34 | return nil
35 | }
36 | switch input {
37 | case "":
38 | a.backend.DefaultServer.Proto = ""
39 | case "h1":
40 | // Forces H1 even when SSL is enabled
41 | a.backend.DefaultServer.Alpn = ""
42 | a.backend.DefaultServer.Proto = ""
43 | default:
44 | return fmt.Errorf("unknown proto %s", input)
45 | }
46 | return nil
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/annotations/service/ssl.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/haproxytech/client-native/v6/models"
5 |
6 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
7 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
8 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
9 | )
10 |
11 | type SSL struct {
12 | backend *models.Backend
13 | name string
14 | }
15 |
16 | func NewSSL(n string, b *models.Backend) *SSL {
17 | return &SSL{name: n, backend: b}
18 | }
19 |
20 | func (a *SSL) GetName() string {
21 | return a.name
22 | }
23 |
24 | func (a *SSL) Process(k store.K8s, annotations ...map[string]string) error {
25 | input := common.GetValue(a.GetName(), annotations...)
26 | var enabled bool
27 | var err error
28 | if input != "" {
29 | enabled, err = utils.GetBoolValue(input, "server-ssl")
30 | if err != nil {
31 | return err
32 | }
33 | }
34 | if enabled {
35 | if a.backend.DefaultServer == nil {
36 | a.backend.DefaultServer = &models.DefaultServer{}
37 | }
38 | a.backend.DefaultServer.Ssl = "enabled"
39 | a.backend.DefaultServer.Alpn = "h2,http/1.1"
40 | a.backend.DefaultServer.Verify = "none"
41 | } else if a.backend.DefaultServer != nil {
42 | a.backend.DefaultServer.Ssl = ""
43 | a.backend.DefaultServer.Alpn = ""
44 | a.backend.DefaultServer.Verify = ""
45 | }
46 | return nil
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/annotations/service/timeoutCheck.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/haproxytech/client-native/v6/models"
5 |
6 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
7 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
8 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
9 | )
10 |
11 | type TimeoutCheck struct {
12 | backend *models.Backend
13 | name string
14 | }
15 |
16 | func NewTimeoutCheck(n string, b *models.Backend) *TimeoutCheck {
17 | return &TimeoutCheck{name: n, backend: b}
18 | }
19 |
20 | func (a *TimeoutCheck) GetName() string {
21 | return a.name
22 | }
23 |
24 | func (a *TimeoutCheck) Process(k store.K8s, annotations ...map[string]string) error {
25 | input := common.GetValue(a.GetName(), annotations...)
26 | if input == "" {
27 | a.backend.CheckTimeout = nil
28 | return nil
29 | }
30 | timeout, err := utils.ParseTime(input)
31 | if err != nil {
32 | return err
33 | }
34 | a.backend.CheckTimeout = timeout
35 | return nil
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/annotations/service/timeoutServer.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/haproxytech/client-native/v6/models"
5 |
6 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations/common"
7 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
8 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
9 | )
10 |
11 | type TimeoutServer struct {
12 | backend *models.Backend
13 | name string
14 | }
15 |
16 | func NewTimeoutServer(n string, b *models.Backend) *TimeoutServer {
17 | return &TimeoutServer{name: n, backend: b}
18 | }
19 |
20 | func (a *TimeoutServer) GetName() string {
21 | return a.name
22 | }
23 |
24 | func (a *TimeoutServer) Process(k store.K8s, annotations ...map[string]string) error {
25 | input := common.GetValue(a.GetName(), annotations...)
26 | if input == "" {
27 | a.backend.ServerTimeout = nil
28 | return nil
29 | }
30 | timeout, err := utils.ParseTime(input)
31 | if err != nil {
32 | return err
33 | }
34 | a.backend.ServerTimeout = timeout
35 | return nil
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/controller/constants/const.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package constants
16 |
17 | //nolint:golint, stylecheck
18 | const (
19 | DefaultsSectionName = "haproxytech"
20 | SSL_FRONTEND = "ssl"
21 | SSL_BACKEND = "ssl-backend"
22 | HTTP_FRONTEND = "http"
23 | HTTPS_FRONTEND = "https"
24 | )
25 |
--------------------------------------------------------------------------------
/pkg/fs/fs-delayed.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package fs
16 |
17 | import (
18 | "sync"
19 | )
20 |
21 | var (
22 | delayedFunc map[string]func()
23 | muDelayed sync.Mutex
24 | )
25 | var delayedWriter = New()
26 |
27 | // AddDelayedFunc adds a function to be called prior to restarting of HAProxy
28 | func AddDelayedFunc(name string, f func()) {
29 | muDelayed.Lock()
30 | defer muDelayed.Unlock()
31 | if delayedFunc == nil {
32 | delayedFunc = make(map[string]func())
33 | }
34 | delayedFunc[name] = f
35 | }
36 |
37 | func RunDelayedFuncs() {
38 | muDelayed.Lock()
39 | defer muDelayed.Unlock()
40 | if delayedFunc == nil {
41 | return
42 | }
43 | for _, f := range delayedFunc {
44 | delayedWriter.Write(f)
45 | }
46 | clear(delayedFunc)
47 | delayedWriter.WaitUntilWritesDone()
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/handler/handler.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package handler
16 |
17 | import (
18 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
19 | )
20 |
21 | var logger = utils.GetLogger()
22 |
--------------------------------------------------------------------------------
/pkg/handler/refresh.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package handler
16 |
17 | import (
18 | "github.com/haproxytech/kubernetes-ingress/pkg/annotations"
19 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy"
20 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
21 | )
22 |
23 | type Refresh struct{}
24 |
25 | func (handler Refresh) Update(k store.K8s, h haproxy.HAProxy, a annotations.Annotations) (err error) {
26 | cleanCrts := true
27 | cleanCrtsAnn, _ := annotations.ParseBool("clean-certs", k.ConfigMaps.Main.Annotations)
28 | // cleanCrtsAnn is empty if clean-certs not set or set with a non boolean value => error
29 | if cleanCrtsAnn == "false" {
30 | cleanCrts = false
31 | }
32 | // Certs
33 | if cleanCrts {
34 | h.RefreshCerts(h.HAProxyClient)
35 | }
36 | // Rules
37 | h.RefreshRules(h.HAProxyClient)
38 | // Maps
39 | h.RefreshMaps(h.HAProxyClient)
40 |
41 | return
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/haproxy/api/capture.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import "github.com/haproxytech/client-native/v6/models"
4 |
5 | func (c *clientNative) CaptureCreate(id int64, frontend string, rule models.Capture) error {
6 | configuration, err := c.nativeAPI.Configuration()
7 | if err != nil {
8 | return err
9 | }
10 | return configuration.CreateDeclareCapture(id, frontend, &rule, c.activeTransaction, 0)
11 | }
12 |
13 | func (c *clientNative) CaptureDeleteAll(frontend string) (err error) {
14 | configuration, err := c.nativeAPI.Configuration()
15 | if err != nil {
16 | return
17 | }
18 | _, rules, err := configuration.GetDeclareCaptures(frontend, c.activeTransaction)
19 | if err != nil {
20 | return
21 | }
22 | for range rules {
23 | if err = configuration.DeleteDeclareCapture(0, frontend, c.activeTransaction, 0); err != nil {
24 | break
25 | }
26 | }
27 | return
28 | }
29 |
30 | func (c *clientNative) CapturesGet(frontend string) (models.Captures, error) {
31 | configuration, err := c.nativeAPI.Configuration()
32 | if err != nil {
33 | return nil, err
34 | }
35 |
36 | _, rules, err := configuration.GetDeclareCaptures(frontend, c.activeTransaction)
37 | if err != nil {
38 | return nil, err
39 | }
40 | return rules, nil
41 | }
42 |
43 | func (c *clientNative) CapturesReplace(frontend string, rules models.Captures) error {
44 | configuration, err := c.nativeAPI.Configuration()
45 | if err != nil {
46 | return err
47 | }
48 |
49 | err = configuration.ReplaceDeclareCaptures(frontend, rules, c.activeTransaction, 0)
50 | if err != nil {
51 | return err
52 | }
53 | return nil
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqAcceptContent.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
9 | )
10 |
11 | type ReqAcceptContent struct{}
12 |
13 | func (r ReqAcceptContent) GetType() Type {
14 | return REQ_ACCEPT_CONTENT
15 | }
16 |
17 | func (r ReqAcceptContent) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
18 | if frontend.Mode == "http" {
19 | return errors.New("tcp accept-content rule is only available in TCP frontends")
20 | }
21 | tcpRule := models.TCPRequestRule{
22 | Action: "reject",
23 | Type: "content",
24 | Cond: "if",
25 | CondTest: "!{ req_ssl_hello_type 1 }",
26 | }
27 | return client.FrontendTCPRequestRuleCreate(0, frontend.Name, tcpRule, ingressACL)
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqBasicAuth.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
9 | )
10 |
11 | type ReqBasicAuth struct {
12 | Credentials map[string][]byte
13 | AuthGroup string
14 | AuthRealm string
15 | }
16 |
17 | func (r ReqBasicAuth) GetType() Type {
18 | return REQ_AUTH
19 | }
20 |
21 | func (r ReqBasicAuth) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) (err error) {
22 | var userList bool
23 | userList, err = client.UserListExistsByGroup(r.AuthGroup)
24 | if err != nil {
25 | return
26 | }
27 | if !userList {
28 | err = client.UserListCreateByGroup(r.AuthGroup, r.Credentials)
29 | if err != nil {
30 | return
31 | }
32 | }
33 | httpRule := models.HTTPRequestRule{
34 | Type: "auth",
35 | AuthRealm: r.AuthRealm,
36 | Cond: "if",
37 | CondTest: fmt.Sprintf("!{ http_auth_group(%s) authenticated-users }", r.AuthGroup),
38 | }
39 | if err = client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL); err != nil {
40 | return
41 | }
42 |
43 | return
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqCapture.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/haproxytech/client-native/v6/models"
5 |
6 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
7 | )
8 |
9 | type ReqCapture struct {
10 | Expression string
11 | CaptureLen int64
12 | }
13 |
14 | func (r ReqCapture) GetType() Type {
15 | return REQ_CAPTURE
16 | }
17 |
18 | func (r ReqCapture) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
19 | if frontend.Mode == "tcp" {
20 | tcpRule := models.TCPRequestRule{
21 | Type: "content",
22 | Action: "capture",
23 | CaptureLen: r.CaptureLen,
24 | Expr: r.Expression,
25 | }
26 | return client.FrontendTCPRequestRuleCreate(0, frontend.Name, tcpRule, ingressACL)
27 | }
28 | httpRule := models.HTTPRequestRule{
29 | Type: "capture",
30 | CaptureSample: r.Expression,
31 | CaptureLen: r.CaptureLen,
32 | }
33 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqDeny.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
9 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/maps"
10 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
11 | )
12 |
13 | type ReqDeny struct {
14 | SrcIPsMap maps.Path
15 | AllowList bool
16 | }
17 |
18 | func (r ReqDeny) GetType() Type {
19 | return REQ_DENY
20 | }
21 |
22 | func (r ReqDeny) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
23 | not := ""
24 | if r.AllowList {
25 | not = "!"
26 | }
27 | if frontend.Mode == "tcp" {
28 | tcpRule := models.TCPRequestRule{
29 | Type: "content",
30 | Action: "reject",
31 | Cond: "if",
32 | CondTest: fmt.Sprintf("%s{ src -f %s }", not, r.SrcIPsMap),
33 | }
34 | return client.FrontendTCPRequestRuleCreate(0, frontend.Name, tcpRule, ingressACL)
35 | }
36 | httpRule := models.HTTPRequestRule{
37 | Type: "deny",
38 | DenyStatus: utils.PtrInt64(403),
39 | Cond: "if",
40 | CondTest: fmt.Sprintf("%s{ src -f %s }", not, r.SrcIPsMap),
41 | }
42 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqInspectDelay.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
9 | )
10 |
11 | type ReqInspectDelay struct {
12 | Timeout *int64
13 | }
14 |
15 | func (r ReqInspectDelay) GetType() Type {
16 | return REQ_INSPECT_DELAY
17 | }
18 |
19 | func (r ReqInspectDelay) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
20 | if frontend.Mode == "http" {
21 | return errors.New("tcp inspect-delay rule is only available in TCP frontends")
22 | }
23 | tcpRule := models.TCPRequestRule{
24 | Type: "inspect-delay",
25 | Timeout: r.Timeout,
26 | }
27 | return client.FrontendTCPRequestRuleCreate(0, frontend.Name, tcpRule, ingressACL)
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqPathRewrite.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
9 | )
10 |
11 | type ReqPathRewrite struct {
12 | PathMatch string
13 | PathFmt string
14 | }
15 |
16 | func (r ReqPathRewrite) GetType() Type {
17 | return REQ_PATH_REWRITE
18 | }
19 |
20 | func (r ReqPathRewrite) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
21 | if frontend.Mode == "tcp" {
22 | return errors.New("SSL redirect cannot be configured in TCP mode")
23 | }
24 | httpRule := models.HTTPRequestRule{
25 | Type: "replace-path",
26 | PathMatch: r.PathMatch,
27 | PathFmt: r.PathFmt,
28 | }
29 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqProxyProtocol.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
9 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/maps"
10 | )
11 |
12 | type ReqProxyProtocol struct {
13 | SrcIPsMap maps.Path
14 | }
15 |
16 | func (r ReqProxyProtocol) GetType() Type {
17 | return REQ_PROXY_PROTOCOL
18 | }
19 |
20 | func (r ReqProxyProtocol) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
21 | tcpRule := models.TCPRequestRule{
22 | Type: "connection",
23 | Action: models.TCPRequestRuleActionExpectDashProxy,
24 | Cond: "if",
25 | CondTest: fmt.Sprintf("{ src -f %s }", r.SrcIPsMap),
26 | }
27 | return client.FrontendTCPRequestRuleCreate(0, frontend.Name, tcpRule, ingressACL)
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqRatelimit.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 |
7 | "github.com/haproxytech/client-native/v6/models"
8 |
9 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
10 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
11 | )
12 |
13 | type ReqRateLimit struct {
14 | TableName string
15 | ReqsLimit int64
16 | DenyStatusCode int64
17 | }
18 |
19 | func (r ReqRateLimit) GetType() Type {
20 | return REQ_RATELIMIT
21 | }
22 |
23 | func (r ReqRateLimit) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
24 | if frontend.Mode == "tcp" {
25 | return errors.New("request Track cannot be configured in TCP mode")
26 | }
27 | httpRule := models.HTTPRequestRule{
28 | Type: "deny",
29 | DenyStatus: utils.PtrInt64(r.DenyStatusCode),
30 | Cond: "if",
31 | CondTest: fmt.Sprintf("{ sc0_http_req_rate(%s) gt %d }", r.TableName, r.ReqsLimit),
32 | }
33 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqRequestRedirect.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 |
7 | "github.com/haproxytech/client-native/v6/models"
8 |
9 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
10 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
11 | )
12 |
13 | type RequestRedirect struct {
14 | Host string
15 | RedirectCode int64
16 | RedirectPort int
17 | SSLRequest bool
18 | SSLRedirect bool
19 | }
20 |
21 | func (r RequestRedirect) GetType() Type {
22 | return REQ_REDIRECT
23 | }
24 |
25 | func (r RequestRedirect) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
26 | if frontend.Mode == "tcp" {
27 | return errors.New("request redirection cannot be configured in TCP mode")
28 | }
29 | var rule string
30 | if r.SSLRedirect {
31 | rule = fmt.Sprintf("https://%%[hdr(host),field(1,:)]:%d%%[capture.req.uri]", r.RedirectPort)
32 | } else {
33 | scheme := "http"
34 | if r.SSLRequest {
35 | scheme = "https"
36 | }
37 | rule = fmt.Sprintf(scheme+"://%s%%[capture.req.uri]", r.Host)
38 | }
39 | httpRule := models.HTTPRequestRule{
40 | Type: "redirect",
41 | RedirCode: utils.PtrInt64(r.RedirectCode),
42 | RedirValue: rule,
43 | RedirType: "location",
44 | }
45 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqRequestRedirectQuic.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
9 | )
10 |
11 | type RequestRedirectQuic struct{}
12 |
13 | func (r RequestRedirectQuic) GetType() Type {
14 | return REQ_REDIRECT
15 | }
16 |
17 | func (r RequestRedirectQuic) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
18 | if frontend.Mode == "tcp" {
19 | return errors.New("request redirection cannot be configured in TCP mode")
20 | }
21 |
22 | httpRule := models.HTTPRequestRule{
23 | Type: "redirect",
24 | Cond: "unless",
25 | CondTest: "{ ssl_fc }",
26 | RedirType: "scheme",
27 | RedirValue: "https",
28 | }
29 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqReturnStatus.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
8 | )
9 |
10 | //nolint:golint,stylecheck
11 | var MIME_TYPE_TEXT_PLAIN string = "text/plain"
12 |
13 | type ReqReturnStatus struct {
14 | StatusCode int64
15 | }
16 |
17 | func (r ReqReturnStatus) GetType() Type {
18 | return REQ_RETURN_STATUS
19 | }
20 |
21 | func (r ReqReturnStatus) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
22 | if frontend.Mode == "tcp" {
23 | return errors.New("HTTP status cannot be set in TCP mode")
24 | }
25 | httpRule := models.HTTPRequestRule{
26 | ReturnStatusCode: &r.StatusCode,
27 | Type: "return",
28 | }
29 | ingressACL += " METH_OPTIONS"
30 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqSetSrc.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/haproxytech/client-native/v6/models"
7 |
8 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
9 | )
10 |
11 | type ReqSetSrc struct {
12 | HeaderName string
13 | }
14 |
15 | func (r ReqSetSrc) GetType() Type {
16 | return REQ_SET_SRC
17 | }
18 |
19 | func (r ReqSetSrc) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
20 | if len(r.HeaderName) == 0 {
21 | return nil
22 | }
23 | if frontend.Mode == "tcp" {
24 | tcpRule := models.TCPRequestRule{
25 | Type: "set-src",
26 | Expr: fmt.Sprintf("hdr(%s)", r.HeaderName),
27 | }
28 | return client.FrontendTCPRequestRuleCreate(0, frontend.Name, tcpRule, ingressACL)
29 | }
30 | httpRule := models.HTTPRequestRule{
31 | Type: "set-src",
32 | Expr: fmt.Sprintf("hdr(%s)", r.HeaderName),
33 | }
34 | ingressACL += " || !{ var(txn.path_match) -m found }"
35 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqSetVar.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/haproxytech/client-native/v6/models"
5 |
6 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
7 | )
8 |
9 | type ReqSetVar struct {
10 | Name string
11 | Scope string
12 | Expression string
13 | CondTest string
14 | }
15 |
16 | func (r ReqSetVar) GetType() Type {
17 | return REQ_SET_VAR
18 | }
19 |
20 | func (r ReqSetVar) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
21 | if frontend.Mode == "tcp" {
22 | tcpRule := models.TCPRequestRule{
23 | Type: "content",
24 | Action: "set-var",
25 | VarName: r.Name,
26 | VarScope: r.Scope,
27 | Expr: r.Expression,
28 | }
29 | return client.FrontendTCPRequestRuleCreate(0, frontend.Name, tcpRule, ingressACL)
30 | }
31 | httpRule := models.HTTPRequestRule{
32 | Type: "set-var",
33 | VarName: r.Name,
34 | VarScope: r.Scope,
35 | VarExpr: r.Expression,
36 | }
37 | if r.CondTest != "" {
38 | httpRule.Cond = "if"
39 | httpRule.CondTest = r.CondTest
40 | }
41 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/reqTrack.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 |
7 | "github.com/haproxytech/client-native/v6/models"
8 |
9 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
10 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
11 | )
12 |
13 | type ReqTrack struct {
14 | TableName string
15 | TablePeriod *int64
16 | TableSize *int64
17 | TrackKey string
18 | }
19 |
20 | func (r ReqTrack) GetType() Type {
21 | return REQ_TRACK
22 | }
23 |
24 | func (r ReqTrack) Create(client api.HAProxyClient, frontend *models.Frontend, ingressACL string) error {
25 | if frontend.Mode == "tcp" {
26 | return errors.New("request Track cannot be configured in TCP mode")
27 | }
28 |
29 | // Create tracking table.
30 | if !client.BackendUsed(r.TableName) {
31 | backend := models.Backend{
32 | BackendBase: models.BackendBase{
33 | Name: r.TableName,
34 | StickTable: &models.ConfigStickTable{
35 | Peers: "localinstance",
36 | Type: "ip",
37 | Size: r.TableSize,
38 | Store: fmt.Sprintf("http_req_rate(%d)", *r.TablePeriod),
39 | },
40 | },
41 | }
42 | // Create tracking table.
43 | client.BackendCreateOrUpdate(backend)
44 | }
45 |
46 | // Create rule
47 | httpRule := models.HTTPRequestRule{
48 | Type: "track-sc",
49 | TrackScStickCounter: utils.PtrInt64(0),
50 | TrackScKey: r.TrackKey,
51 | TrackScTable: r.TableName,
52 | }
53 | return client.FrontendHTTPRequestRuleCreate(0, frontend.Name, httpRule, ingressACL)
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/haproxy/rules/types.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | // Order matters !
4 | // Rules will be evaluated by HAProxy in the defined order.
5 | type Type int
6 |
7 | //nolint:golint,stylecheck
8 | const (
9 | REQ_ACCEPT_CONTENT Type = iota
10 | REQ_INSPECT_DELAY
11 | REQ_PROXY_PROTOCOL
12 | REQ_SET_VAR
13 | REQ_SET_SRC
14 | REQ_DENY
15 | REQ_TRACK
16 | REQ_AUTH
17 | REQ_RATELIMIT
18 | REQ_CAPTURE
19 | REQ_REDIRECT
20 | REQ_FORWARDED_PROTO
21 | REQ_SET_HEADER
22 | REQ_SET_HOST
23 | REQ_PATH_REWRITE
24 | REQ_RETURN_STATUS
25 | RES_SET_HEADER
26 | )
27 |
28 | var constLookup = map[Type]string{
29 | REQ_ACCEPT_CONTENT: "REQ_ACCEPT_CONTENT",
30 | REQ_INSPECT_DELAY: "REQ_INSPECT_DELAY",
31 | REQ_PROXY_PROTOCOL: "REQ_PROXY_PROTOCOL",
32 | REQ_SET_VAR: "REQ_SET_VAR",
33 | REQ_SET_SRC: "REQ_SET_SRC",
34 | REQ_DENY: "REQ_DENY",
35 | REQ_TRACK: "REQ_TRACK",
36 | REQ_AUTH: "REQ_AUTH",
37 | REQ_RATELIMIT: "REQ_RATELIMIT",
38 | REQ_CAPTURE: "REQ_CAPTURE",
39 | REQ_REDIRECT: "REQ_REDIRECT",
40 | REQ_FORWARDED_PROTO: "REQ_FORWARDED_PROTO",
41 | REQ_SET_HEADER: "REQ_SET_HEADER",
42 | REQ_SET_HOST: "REQ_SET_HOST",
43 | REQ_PATH_REWRITE: "REQ_PATH_REWRITE",
44 | RES_SET_HEADER: "RES_SET_HEADER",
45 | REQ_RETURN_STATUS: "REQ_RETURN_STATUS",
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/ingress/types.go:
--------------------------------------------------------------------------------
1 | package ingress
2 |
3 | import (
4 | "github.com/haproxytech/kubernetes-ingress/pkg/store"
5 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
6 | corev1 "k8s.io/api/core/v1"
7 | )
8 |
9 | var logger = utils.GetLogger()
10 |
11 | type Sync struct {
12 | Service *corev1.Service
13 | Ingress *store.Ingress
14 | }
15 |
--------------------------------------------------------------------------------
/pkg/k8s/informer-utils.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8s
16 |
17 | import (
18 | k8smeta "github.com/haproxytech/kubernetes-ingress/pkg/k8s/meta"
19 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
20 | "k8s.io/apimachinery/pkg/types"
21 | )
22 |
23 | func ToSyncDataEvent(meta k8smeta.MetaInfoer, data interface{}, uid types.UID, resourceVersion string) k8ssync.SyncDataEvent {
24 | return k8ssync.SyncDataEvent{
25 | SyncType: meta.GetType(),
26 | Namespace: meta.GetNamespace(),
27 | Name: meta.GetName(),
28 | Data: data,
29 | UID: uid,
30 | ResourceVersion: resourceVersion,
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/k8s/logging.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8s
16 |
17 | import (
18 | k8smeta "github.com/haproxytech/kubernetes-ingress/pkg/k8s/meta"
19 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
20 | "k8s.io/apimachinery/pkg/types"
21 | )
22 |
23 | func logIncomingK8sEvent(logger utils.Logger, meta k8smeta.MetaInfoer, uid types.UID, resourceVersion string, additionalInfo ...string) {
24 | logger.Tracef("[RUNTIME] [K8s] %s %s: %s %s/%s ",
25 | meta.GetType(),
26 | meta.GetStatus(),
27 | meta.GetName(),
28 | uid,
29 | resourceVersion,
30 | additionalInfo)
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/k8s/meta/meta.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package meta
16 |
17 | import (
18 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
19 | )
20 |
21 | type MetaInfoer interface {
22 | GetNamespace() string
23 | GetName() string
24 | GetType() k8ssync.SyncType
25 | GetStatus() string
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/k8s/transform/transform-backend.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8stransform
16 |
17 | import (
18 | v3 "github.com/haproxytech/kubernetes-ingress/crs/api/ingress/v3"
19 | )
20 |
21 | func TransformBackend(obj interface{}) (interface{}, error) {
22 | backend, ok := obj.(*v3.Backend)
23 | if !ok {
24 | return obj, nil
25 | }
26 |
27 | // Fields to remove
28 | backend.Spec.Servers = nil
29 |
30 | return backend, nil
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/k8s/transform/transform-common.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8stransform
16 |
17 | import (
18 | ammeta "k8s.io/apimachinery/pkg/api/meta"
19 | )
20 |
21 | func TransformCommon(obj interface{}) (interface{}, error) {
22 | data, err := ammeta.Accessor(obj)
23 | if err != nil {
24 | return obj, err
25 | }
26 |
27 | data.SetManagedFields(nil)
28 |
29 | return data, nil
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/k8s/transform/transform-configmap.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8stransform
16 |
17 | func TransformConfigmap(obj interface{}) (interface{}, error) {
18 | return TransformCommon(obj)
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/k8s/transform/transform-endpoints.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8stransform
16 |
17 | func TransformEndpoints(obj interface{}) (interface{}, error) {
18 | return TransformCommon(obj)
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/k8s/transform/transform-ingressclass.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8stransform
16 |
17 | func TransformIngressClass(obj interface{}) (interface{}, error) {
18 | return TransformCommon(obj)
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/k8s/transform/transform-namespace.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8stransform
16 |
17 | func TransformNamespace(obj interface{}) (interface{}, error) {
18 | return TransformCommon(obj)
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/k8s/transform/transform-secret.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8stransform
16 |
17 | func TransformSecret(obj interface{}) (interface{}, error) {
18 | return TransformCommon(obj)
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/k8s/transform/transform-service.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package k8stransform
16 |
17 | func TransformService(obj interface{}) (interface{}, error) {
18 | return TransformCommon(obj)
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/rules/acls/acls.go:
--------------------------------------------------------------------------------
1 | package acls
2 |
3 | import (
4 | "github.com/haproxytech/client-native/v6/models"
5 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
6 | "github.com/haproxytech/kubernetes-ingress/pkg/haproxy/instance"
7 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
8 | )
9 |
10 | //nolint:golint,stylecheck
11 | type ACL_DESTINATION string
12 |
13 | //nolint:golint,stylecheck
14 | const (
15 | ACL_FRONTEND ACL_DESTINATION = "frontend"
16 | ACL_BACKEND ACL_DESTINATION = "backend"
17 | )
18 |
19 | func PopulateBackend(client api.HAProxyClient, name string, acls models.Acls) {
20 | Populate(client, name, acls, ACL_BACKEND)
21 | }
22 |
23 | func PopulateFrontend(client api.HAProxyClient, name string, acls models.Acls) {
24 | Populate(client, name, acls, ACL_FRONTEND)
25 | }
26 |
27 | func Populate(client api.ACL, name string, rules models.Acls, resource ACL_DESTINATION) {
28 | currentAcls, errAcls := client.ACLsGet(string(resource), name)
29 |
30 | // There is a resource ...
31 | if errAcls == nil {
32 | diffAcls := rules.Diff(currentAcls)
33 | // ... with different acls from the resource.
34 | if len(diffAcls) != 0 {
35 | err := client.ACLsReplace(string(resource), name, rules)
36 | if err != nil {
37 | utils.GetLogger().Err(err)
38 | return
39 | }
40 | // ... we reload because we created some acls.
41 | instance.Reload("%s '%s', acls updated: %+v", resource, name, utils.JSONDiff(diffAcls))
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/rules/constant.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package rules
16 |
17 | type ParentType string
18 |
19 | const (
20 | ParentTypeFrontend ParentType = "frontend"
21 | ParentTypeBackend ParentType = "backend"
22 | )
23 |
--------------------------------------------------------------------------------
/pkg/store/events-cr-backend.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | v3 "github.com/haproxytech/kubernetes-ingress/crs/api/ingress/v3"
19 | )
20 |
21 | func (k *K8s) EventBackendCR(namespace, name string, data *v3.Backend) bool {
22 | ns := k.GetNamespace(namespace)
23 | if data == nil {
24 | delete(ns.CRs.Backends, name)
25 | return true
26 | }
27 | ns.CRs.Backends[name] = &data.Spec
28 | return true
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/store/events-cr-defaults.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | v3 "github.com/haproxytech/kubernetes-ingress/crs/api/ingress/v3"
19 | )
20 |
21 | func (k *K8s) EventDefaultsCR(namespace, name string, data *v3.Defaults) bool {
22 | ns := k.GetNamespace(namespace)
23 | if data == nil {
24 | delete(ns.CRs.Defaults, name)
25 | return true
26 | }
27 | ns.CRs.Defaults[name] = &data.Spec.Defaults
28 | return true
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/store/events-cr-global.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | v3 "github.com/haproxytech/kubernetes-ingress/crs/api/ingress/v3"
19 | )
20 |
21 | func (k *K8s) EventGlobalCR(namespace, name string, data *v3.Global) bool {
22 | ns := k.GetNamespace(namespace)
23 | if data == nil {
24 | delete(ns.CRs.Global, name)
25 | return true
26 | }
27 | ns.CRs.Global[name] = &data.Spec.Global
28 | return true
29 | }
30 |
--------------------------------------------------------------------------------
/pkg/store/status.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | type Status string
18 |
19 | const (
20 | ADDED Status = "ADDED"
21 | DELETED Status = "DELETED"
22 | ERROR Status = "ERROR"
23 | EMPTY Status = ""
24 | MODIFIED Status = "MODIFIED"
25 | )
26 |
--------------------------------------------------------------------------------
/pkg/store/types-configmap.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
19 | )
20 |
21 | func (a ConfigMap) GetType() k8ssync.SyncType {
22 | return k8ssync.CONFIGMAP
23 | }
24 |
25 | func (a ConfigMap) GetName() string {
26 | return a.Name
27 | }
28 |
29 | func (a ConfigMap) GetNamespace() string {
30 | return a.Namespace
31 | }
32 |
33 | func (a ConfigMap) GetStatus() string {
34 | return string(a.Status)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/store/types-endpoints.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
19 | )
20 |
21 | func (a Endpoints) GetType() k8ssync.SyncType {
22 | return k8ssync.ENDPOINTS
23 | }
24 |
25 | func (a Endpoints) GetName() string {
26 | return a.SliceName
27 | }
28 |
29 | func (a Endpoints) GetNamespace() string {
30 | return a.Namespace
31 | }
32 |
33 | func (a Endpoints) GetStatus() string {
34 | return string(a.Status)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/store/types-ingress.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
19 | )
20 |
21 | func (i Ingress) GetType() k8ssync.SyncType {
22 | return k8ssync.INGRESS
23 | }
24 |
25 | func (i Ingress) GetName() string {
26 | return i.Name
27 | }
28 |
29 | func (i Ingress) GetNamespace() string {
30 | return i.Namespace
31 | }
32 |
33 | func (i Ingress) GetStatus() string {
34 | return string(i.Status)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/store/types-ingressclass.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
19 | )
20 |
21 | func (a IngressClass) GetType() k8ssync.SyncType {
22 | return k8ssync.INGRESS_CLASS
23 | }
24 |
25 | func (a IngressClass) GetName() string {
26 | return a.Name
27 | }
28 |
29 | func (a IngressClass) GetNamespace() string {
30 | return ""
31 | }
32 |
33 | func (a IngressClass) GetStatus() string {
34 | return string(a.Status)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/store/types-namespace.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
19 | )
20 |
21 | func (ns Namespace) GetType() k8ssync.SyncType {
22 | return k8ssync.NAMESPACE
23 | }
24 |
25 | func (ns Namespace) GetName() string {
26 | return ns.Name
27 | }
28 |
29 | func (ns Namespace) GetNamespace() string {
30 | return ns.Name
31 | }
32 |
33 | func (ns Namespace) GetStatus() string {
34 | return string(ns.Status)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/store/types-pod.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
19 | )
20 |
21 | func (i PodEvent) GetType() k8ssync.SyncType {
22 | return k8ssync.POD
23 | }
24 |
25 | func (i PodEvent) GetName() string {
26 | return i.Name
27 | }
28 |
29 | func (i PodEvent) GetNamespace() string {
30 | return i.Namespace
31 | }
32 |
33 | func (i PodEvent) GetStatus() string {
34 | return string(i.Status)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/store/types-secret.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
19 | )
20 |
21 | func (a Secret) GetType() k8ssync.SyncType {
22 | return k8ssync.SECRET
23 | }
24 |
25 | func (a Secret) GetName() string {
26 | return a.Name
27 | }
28 |
29 | func (a Secret) GetNamespace() string {
30 | return a.Namespace
31 | }
32 |
33 | func (a Secret) GetStatus() string {
34 | return string(a.Status)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/store/types-service.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package store
16 |
17 | import (
18 | k8ssync "github.com/haproxytech/kubernetes-ingress/pkg/k8s/sync"
19 | )
20 |
21 | func (a Service) GetType() k8ssync.SyncType {
22 | return k8ssync.SERVICE
23 | }
24 |
25 | func (a Service) GetName() string {
26 | return a.Name
27 | }
28 |
29 | func (a Service) GetNamespace() string {
30 | return a.Namespace
31 | }
32 |
33 | func (a Service) GetStatus() string {
34 | return string(a.Status)
35 | }
36 |
--------------------------------------------------------------------------------
/pkg/store/types-utils.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/haproxytech/kubernetes-ingress/pkg/utils"
7 | )
8 |
9 | func (gw *Gateway) IsValid() error {
10 | if len(gw.Listeners) == 0 {
11 | return fmt.Errorf("Gateway '%s/%s' has no listeners", gw.Namespace, gw.Name)
12 | }
13 | err := utils.Errors{}
14 | combinations := map[string]struct{}{}
15 | for _, listener := range gw.Listeners {
16 | hostname := ""
17 | if listener.Hostname != nil {
18 | hostname = *listener.Hostname
19 | }
20 | key := fmt.Sprintf("%s/%d/%s", hostname, listener.Port, listener.Protocol)
21 | if _, found := combinations[key]; found {
22 | err.Add(fmt.Errorf("duplicate combination hostname/port/protocol '%s' in listeners from gateway '%s/%s", key, gw.Namespace, gw.Name))
23 | }
24 | combinations[key] = struct{}{}
25 | }
26 | return err.Result()
27 | }
28 |
29 | func (tcproutes TCPRoutes) Less(i, j int) bool {
30 | tcprouteI := tcproutes[i]
31 | tcprouteJ := tcproutes[j]
32 | if !tcprouteI.CreationTime.Equal(tcprouteJ.CreationTime) {
33 | return tcprouteI.CreationTime.Before(tcprouteJ.CreationTime)
34 | }
35 | return tcprouteI.Namespace+tcprouteI.Name < tcprouteJ.Namespace+tcprouteJ.Name
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/utils/errors.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "errors"
5 | )
6 |
7 | type Errors []error
8 |
9 | func (e *Errors) Add(errors ...error) {
10 | for _, err := range errors {
11 | if err != nil {
12 | *e = append(*e, err)
13 | }
14 | }
15 | }
16 |
17 | func (e *Errors) Result() error {
18 | var result string
19 | for _, err := range *e {
20 | result += err.Error() + "\n"
21 | }
22 | if result == "" {
23 | return nil
24 | }
25 | return errors.New(result)
26 | }
27 |
28 | func (e *Errors) AddErrors(errors Errors) {
29 | for _, err := range errors {
30 | e.Add((err))
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/utils/flags-experimental.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package utils
16 |
17 | import (
18 | "strings"
19 | )
20 |
21 | type Experimental struct {
22 | UseIngressMerge bool
23 | }
24 |
25 | const (
26 | flagSeparator = ","
27 | // Experimental flags
28 | flagUseIngressMerge = "use-ingress-merge"
29 | )
30 |
31 | // UnmarshalFlag Unmarshal flag
32 | func (e *Experimental) UnmarshalFlag(value string) error {
33 | var errors Errors
34 | flags := strings.Split(value, flagSeparator)
35 |
36 | // Then parse
37 | for _, flag := range flags {
38 | if flag == flagUseIngressMerge {
39 | e.UseIngressMerge = true
40 | continue
41 | }
42 | }
43 |
44 | return errors.Result()
45 | }
46 |
47 | // MarshalFlag Marshals flag
48 | func (e Experimental) MarshalFlag() (string, error) {
49 | flags := []string{}
50 | if e.UseIngressMerge {
51 | flags = append(flags, flagUseIngressMerge)
52 | }
53 | return strings.Join(flags, flagSeparator), nil
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/utils/orderedset.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import "sort"
4 |
5 | type OrderedSet[K comparable, T any] struct {
6 | items []T
7 | seen map[K]struct{}
8 | keyFn func(T) K
9 | lessFn func(a, b T) bool
10 | }
11 |
12 | func NewOrderedSet[K comparable, T any](keyFn func(T) K, lessFn func(a, b T) bool) *OrderedSet[K, T] {
13 | return &OrderedSet[K, T]{
14 | items: []T{},
15 | seen: make(map[K]struct{}),
16 | keyFn: keyFn,
17 | lessFn: lessFn,
18 | }
19 | }
20 |
21 | func (os *OrderedSet[K, T]) Add(item T) {
22 | key := os.keyFn(item)
23 | if _, exists := os.seen[key]; exists {
24 | return
25 | }
26 |
27 | i := sort.Search(len(os.items), func(i int) bool {
28 | return os.lessFn(item, os.items[i])
29 | })
30 | os.items = append(os.items, item)
31 | copy(os.items[i+1:], os.items[i:])
32 | os.items[i] = item
33 | os.seen[key] = struct{}{}
34 | }
35 |
36 | func (os *OrderedSet[K, T]) Remove(item T) {
37 | key := os.keyFn(item)
38 | if _, exists := os.seen[key]; !exists {
39 | return
40 | }
41 | delete(os.seen, key)
42 | for i, v := range os.items {
43 | if os.keyFn(v) == key {
44 | os.items = append(os.items[:i], os.items[i+1:]...)
45 | break
46 | }
47 | }
48 | }
49 |
50 | func (os *OrderedSet[K, T]) Items() []T {
51 | return os.items
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/version/runtime.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package version
16 |
17 | import (
18 | "errors"
19 | "runtime/debug"
20 | )
21 |
22 | func Set() error {
23 | buildinfo, ok := debug.ReadBuildInfo()
24 | if !ok {
25 | return errors.New("not able to read build data")
26 | }
27 | GitRepo = buildinfo.Main.Path
28 | GitCommitDate = get(buildinfo, "vcs.time")
29 | GitCommit = get(buildinfo, "vcs.revision")
30 | if len(GitCommit) > 8 {
31 | GitCommit = GitCommit[:8]
32 | }
33 |
34 | return nil
35 | }
36 |
37 | func get(buildInfo *debug.BuildInfo, key string) string {
38 | for _, setting := range buildInfo.Settings {
39 | if setting.Key == key {
40 | return setting.Value
41 | }
42 | }
43 | return ""
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/version/version.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 HAProxy Technologies LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package version
16 |
17 | // GitRepo ...
18 | var GitRepo = ""
19 |
20 | // GitTag ...
21 | var GitTag = "dev"
22 |
23 | // GitCommit ...
24 | var GitCommit = ""
25 |
26 | // GitCommitDate ...
27 | var GitCommitDate = ""
28 |
29 | // IngressControllerInfo console pretty print
30 | const IngressControllerInfo = `
31 | _ _ _ ____
32 | | | | | / \ | _ \ _ __ _____ ___ _
33 | | |_| | / _ \ | |_) | '__/ _ \ \/ / | | |
34 | | _ |/ ___ \| __/| | | (_) > <| |_| |
35 | |_| |_/_/ \_\_| |_| \___/_/\_\\__, |
36 | _ __ _ |___/ ___ ____
37 | | |/ / _| |__ ___ _ __ _ __ ___| |_ ___ ___ |_ _/ ___|
38 | | ' / | | | '_ \ / _ \ '__| '_ \ / _ \ __/ _ \/ __| | | |
39 | | . \ |_| | |_) | __/ | | | | | __/ || __/\__ \ | | |___
40 | |_|\_\__,_|_.__/ \___|_| |_| |_|\___|\__\___||___/ |___\____|
41 |
42 | `
43 |
--------------------------------------------------------------------------------
/test/tcp-cr/expectations/check-collisions/coll-address-port.yaml:
--------------------------------------------------------------------------------
1 | - tcpmodel:
2 | name: service1CollAddPort
3 | frontend:
4 | frontendbase:
5 | name: fe11
6 | binds:
7 | acceptproxy:
8 | accept_proxy: true
9 | port: 1
10 | other:
11 | port: 11
12 | service:
13 | name: service1
14 | port: 443
15 | parent_name: tcp-1
16 | namespace: ns
17 | collision_status: ERROR
18 | reason: "-- Collision AddPort :1 with ns/tcp-1/service1 -- Collision AddPort :11 with
19 | ns/tcp-1/service1 "
20 | creation_timestamp: 2024-06-16T11:45:26.371Z
21 | - tcpmodel:
22 | name: service1
23 | frontend:
24 | frontendbase:
25 | name: fe1
26 | binds:
27 | acceptproxy:
28 | accept_proxy: true
29 | port: 1
30 | other:
31 | port: 11
32 | service:
33 | name: service1
34 | port: 443
35 | parent_name: tcp-1
36 | namespace: ns
37 | creation_timestamp: 2024-05-16T11:45:26.371Z
38 | - tcpmodel:
39 | name: service2
40 | frontend:
41 | frontendbase:
42 | name: fe2
43 | binds:
44 | acceptproxy:
45 | accept_proxy: true
46 | port: 2
47 | other:
48 | port: 22
49 | service:
50 | name: service2
51 | port: 443
52 | parent_name: tcp-1
53 | namespace: ns
54 | creation_timestamp: 2024-05-16T11:45:26.371Z
55 |
--------------------------------------------------------------------------------
/test/tcp-cr/expectations/has-collisions/coll-fe-name.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | fe1:
3 | - tcpmodel:
4 | name: service1CollFeName
5 | frontend:
6 | frontendbase:
7 | name: fe1
8 | binds:
9 | acceptproxy:
10 | accept_proxy: true
11 | port: 100
12 | other:
13 | port: 101
14 | service:
15 | name: service1
16 | port: 443
17 | parent_name: tcp-1
18 | namespace: ns
19 | collision_status: ERROR
20 | reason: "-- Collision FE.Name with ns/tcp-1/service1"
21 | creation_timestamp: 2024-07-16T11:45:26.371Z
22 | - tcpmodel:
23 | name: service1
24 | frontend:
25 | frontendbase:
26 | name: fe1
27 | binds:
28 | acceptproxy:
29 | accept_proxy: true
30 | port: 1
31 | other:
32 | port: 11
33 | service:
34 | name: service1
35 | port: 443
36 | parent_name: tcp-1
37 | namespace: ns
38 | collision_status: ERROR
39 | reason: "-- Collision FE.Name with ns/tcp-1/service1CollFeName"
40 | creation_timestamp: 2024-05-16T11:45:26.371Z
41 |
--------------------------------------------------------------------------------
/test/tcp-cr/expectations/no-collision.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - tcpmodel:
3 | name: service1
4 | frontend:
5 | frontendbase:
6 | name: fe1
7 | binds:
8 | acceptproxy:
9 | accept_proxy: true
10 | port: 1
11 | other:
12 | port: 11
13 | service:
14 | name: service1
15 | port: 443
16 | parent_name: tcp-1
17 | namespace: ns
18 | creation_timestamp: 2024-05-16T11:45:26.371Z
19 | - tcpmodel:
20 | name: service2
21 | frontend:
22 | frontendbase:
23 | name: fe2
24 | binds:
25 | acceptproxy:
26 | accept_proxy: true
27 | port: 2
28 | other:
29 | port: 22
30 | service:
31 | name: service2
32 | port: 443
33 | parent_name: tcp-1
34 | namespace: ns
35 | creation_timestamp: 2024-05-16T11:45:26.371Z
36 |
--------------------------------------------------------------------------------
/test/tcp-cr/expectations/ordered.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | items:
3 | - tcpmodel:
4 | name: service1
5 | frontend:
6 | frontendbase:
7 | name: fe1
8 | binds:
9 | other:
10 | port: 1
11 | acceptproxy:
12 | accept_proxy: true
13 | port: 11
14 | service:
15 | name: service1
16 | port: 443
17 | parent_name: tcp-1
18 | namespace: ns
19 | creation_timestamp: 2024-07-16T11:45:26.371Z
20 | - tcpmodel:
21 | name: service1
22 | frontend:
23 | frontendbase:
24 | name: fe11
25 | binds:
26 | other:
27 | port: 1
28 | acceptproxy:
29 | accept_proxy: true
30 | port: 11
31 | service:
32 | name: service1
33 | port: 443
34 | parent_name: tcp-1
35 | namespace: ns
36 | creation_timestamp: 2024-06-16T11:45:26.371Z
37 | - tcpmodel:
38 | name: service2
39 | frontend:
40 | frontendbase:
41 | name: fe2
42 | binds:
43 | acceptproxy:
44 | accept_proxy: true
45 | port: 2
46 | other:
47 | port: 22
48 | service:
49 | name: service2
50 | port: 443
51 | parent_name: tcp-1
52 | namespace: ns
53 | creation_timestamp: 2024-06-16T11:45:26.371Z
54 |
--------------------------------------------------------------------------------
/test/tcp-cr/manifests/tcp1-coll-address-port-2.yaml:
--------------------------------------------------------------------------------
1 | tcpmodel:
2 | name: service1CollAddPort2
3 | frontend:
4 | frontendbase:
5 | name: fe111
6 | binds:
7 | acceptproxy:
8 | port: 1
9 | accept_proxy: true
10 | other:
11 | port: 111
12 | service:
13 | name: service1
14 | port: 443
15 | namespace: ns
16 | creation_timestamp: 2024-08-16T11:45:26.371Z
17 |
--------------------------------------------------------------------------------
/test/tcp-cr/manifests/tcp1-coll-address-port.yaml:
--------------------------------------------------------------------------------
1 | tcpmodel:
2 | name: service1CollAddPort
3 | frontend:
4 | frontendbase:
5 | name: fe11
6 | binds:
7 | acceptproxy:
8 | port: 1
9 | accept_proxy: true
10 | other:
11 | port: 11
12 | service:
13 | name: service1
14 | port: 443
15 | namespace: ns
16 | creation_timestamp: 2024-06-16T11:45:26.371Z
17 |
--------------------------------------------------------------------------------
/test/tcp-cr/manifests/tcp1-coll-fe-name.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | tcpmodel:
3 | name: service1CollFeName
4 | frontend:
5 | frontendbase:
6 | name: fe1
7 | binds:
8 | acceptproxy:
9 | port: 100
10 | accept_proxy: true
11 | other:
12 | port: 101
13 | service:
14 | name: service1
15 | port: 443
16 | namespace: ns
17 | creation_timestamp: 2024-07-16T11:45:26.371Z
18 |
--------------------------------------------------------------------------------
/test/tcp-cr/manifests/tcp1.yaml:
--------------------------------------------------------------------------------
1 | tcpmodel:
2 | name: service1
3 | frontend:
4 | frontendbase:
5 | name: fe1
6 | binds:
7 | acceptproxy:
8 | accept_proxy: true
9 | port: 1
10 | other:
11 | port: 11
12 | service:
13 | name: service1
14 | port: 443
15 | namespace: ns
16 | creation_timestamp: 2024-05-16T11:45:26.371Z
17 |
--------------------------------------------------------------------------------
/test/tcp-cr/manifests/tcp2-coll-address-port.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | tcpmodel:
3 | name: service2CollAddrPort
4 | frontend:
5 | frontendbase:
6 | name: fe2
7 | binds:
8 | acceptproxy:
9 | port: 2
10 | accept_proxy: true
11 | other:
12 | port: 234567
13 | service:
14 | name: service2
15 | port: 443
16 | namespace: ns
17 | creation_timestamp: 2024-06-16T11:45:26.371Z
18 |
--------------------------------------------------------------------------------
/test/tcp-cr/manifests/tcp2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | tcpmodel:
3 | name: service2
4 | frontend:
5 | frontendbase:
6 | name: fe2
7 | binds:
8 | acceptproxy:
9 | port: 2
10 | accept_proxy: true
11 | other:
12 | port: 22
13 | service:
14 | name: service2
15 | port: 443
16 | namespace: ns
17 | creation_timestamp: 2024-05-16T11:45:26.371Z
18 |
--------------------------------------------------------------------------------
/test/tcp-cr/manifests/tcp3.yaml:
--------------------------------------------------------------------------------
1 | tcpmodel:
2 | name: service3
3 | frontend:
4 | frontendbase:
5 | name: fe3
6 | binds:
7 | acceptproxy:
8 | port: 3
9 | accept_proxy: true
10 | other:
11 | port: 33
12 | service:
13 | name: service3
14 | port: 443
15 | namespace: ns
16 | creation_timestamp: 2024-05-16T11:45:26.371Z
17 |
--------------------------------------------------------------------------------
/test/tcp-cr/manifests/tcp4.yaml:
--------------------------------------------------------------------------------
1 | tcpmodel:
2 | name: service4
3 | frontend:
4 | frontendbase:
5 | name: fe4
6 | binds:
7 | acceptproxy:
8 | port: 4
9 | accept_proxy: true
10 | other:
11 | port: 44
12 | service:
13 | name: service4
14 | port: 443
15 | namespace: ns
16 | creation_timestamp: 2024-05-16T11:45:26.371Z
17 |
--------------------------------------------------------------------------------
/test/tcp-cr/manifests/unordered.yaml:
--------------------------------------------------------------------------------
1 | items:
2 | - tcpmodel:
3 | name: service2
4 | frontend:
5 | frontendbase:
6 | name: fe2
7 | binds:
8 | acceptproxy:
9 | accept_proxy: true
10 | port: 2
11 | other:
12 | port: 22
13 | service:
14 | name: service2
15 | port: 443
16 | parent_name: tcp-1
17 | namespace: ns
18 | creation_timestamp: 2024-06-16T11:45:26.371Z
19 | - tcpmodel:
20 | name: service1
21 | frontend:
22 | frontendbase:
23 | name: fe11
24 | binds:
25 | acceptproxy:
26 | accept_proxy: true
27 | port: 1
28 | other:
29 | port: 1
30 | service:
31 | name: service1
32 | port: 443
33 | parent_name: tcp-1
34 | namespace: ns
35 | creation_timestamp: 2024-06-16T11:45:26.371Z
36 | - tcpmodel:
37 | name: service1
38 | frontend:
39 | frontendbase:
40 | name: fe1
41 | binds:
42 | acceptproxy:
43 | accept_proxy: true
44 | port: 11
45 | other:
46 | port: 1
47 | service:
48 | name: service1
49 | port: 443
50 | parent_name: tcp-1
51 | namespace: ns
52 | creation_timestamp: 2024-07-16T11:45:26.371Z
53 |
--------------------------------------------------------------------------------
/test/transform/data/ingress/dupl-1.yaml:
--------------------------------------------------------------------------------
1 | kind: Ingress
2 | apiVersion: networking.k8s.io/v1
3 | metadata:
4 | name: testingress
5 | annotations:
6 | ingress.class: haproxy
7 | spec:
8 | tls:
9 | - hosts:
10 | - test1.haproxy
11 | - test1.haproxy
12 | - test1.haproxy
13 | secretName: test1
14 | - hosts:
15 | - test2.haproxy
16 | secretName: test2
17 | rules:
18 | - host: "test.haproxy"
19 | http:
20 | paths:
21 | - path: /
22 | pathType: Prefix
23 | backend:
24 | service:
25 | name: foo1
26 | port:
27 | name: http
28 | - host: "test.haproxy"
29 | http:
30 | paths:
31 | - path: /
32 | pathType: Prefix
33 | backend:
34 | service:
35 | name: foo1
36 | port:
37 | name: http
38 | - host: "test.haproxy"
39 | http:
40 | paths:
41 | - path: /
42 | pathType: Prefix
43 | backend:
44 | service:
45 | name: foo1
46 | port:
47 | name: http
48 | - host: "test2.haproxy"
49 | http:
50 | paths:
51 | - path: /
52 | pathType: Prefix
53 | backend:
54 | service:
55 | name: foo2
56 | port:
57 | name: http
58 |
--------------------------------------------------------------------------------
/test/transform/data/ingress/expectation/no-duplicate.yaml:
--------------------------------------------------------------------------------
1 | kind: Ingress
2 | apiVersion: networking.k8s.io/v1
3 | metadata:
4 | name: testingress
5 | annotations:
6 | ingress.class: haproxy
7 | spec:
8 | tls:
9 | - hosts:
10 | - test1.haproxy
11 | secretName: test1
12 | - hosts:
13 | - test2.haproxy
14 | secretName: test2
15 | rules:
16 | - host: "test.haproxy"
17 | http:
18 | paths:
19 | - path: /
20 | pathType: Prefix
21 | backend:
22 | service:
23 | name: foo1
24 | port:
25 | name: http
26 | - host: "test2.haproxy"
27 | http:
28 | paths:
29 | - path: /
30 | pathType: Prefix
31 | backend:
32 | service:
33 | name: foo2
34 | port:
35 | name: http
36 |
--------------------------------------------------------------------------------
/test/transform/data/ingress/no-duplicate.yaml:
--------------------------------------------------------------------------------
1 | kind: Ingress
2 | apiVersion: networking.k8s.io/v1
3 | metadata:
4 | name: testingress
5 | annotations:
6 | ingress.class: haproxy
7 | spec:
8 | tls:
9 | - hosts:
10 | - test1.haproxy
11 | secretName: test1
12 | - hosts:
13 | - test2.haproxy
14 | secretName: test2
15 | rules:
16 | - host: "test.haproxy"
17 | http:
18 | paths:
19 | - path: /
20 | pathType: Prefix
21 | backend:
22 | service:
23 | name: foo1
24 | port:
25 | name: http
26 | - host: "test2.haproxy"
27 | http:
28 | paths:
29 | - path: /
30 | pathType: Prefix
31 | backend:
32 | service:
33 | name: foo2
34 | port:
35 | name: http
36 |
--------------------------------------------------------------------------------
/test/transform/data/rule/dupl-1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - host: "test.haproxy"
3 | http:
4 | paths:
5 | - path: /
6 | pathType: Prefix
7 | backend:
8 | service:
9 | name: foo1
10 | port:
11 | name: http
12 | - host: "test.haproxy"
13 | http:
14 | paths:
15 | - path: /
16 | pathType: Prefix
17 | backend:
18 | service:
19 | name: foo1
20 | port:
21 | name: http
22 | - host: "test2.haproxy"
23 | http:
24 | paths:
25 | - path: /
26 | pathType: Prefix
27 | backend:
28 | service:
29 | name: foo2
30 | port:
31 | name: http
32 |
--------------------------------------------------------------------------------
/test/transform/data/rule/expectation/no-duplicate.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - host: "test.haproxy"
3 | http:
4 | paths:
5 | - path: /
6 | pathType: Prefix
7 | backend:
8 | service:
9 | name: foo1
10 | port:
11 | name: http
12 | - host: "test2.haproxy"
13 | http:
14 | paths:
15 | - path: /
16 | pathType: Prefix
17 | backend:
18 | service:
19 | name: foo2
20 | port:
21 | name: http
22 |
--------------------------------------------------------------------------------
/test/transform/data/rule/no-dupl-1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - host: "test.haproxy"
3 | http:
4 | paths:
5 | - path: /
6 | pathType: Prefix
7 | backend:
8 | service:
9 | name: foo1
10 | port:
11 | name: http
12 | - host: "test.haproxy"
13 | http:
14 | paths:
15 | - path: /
16 | pathType: Prefix
17 | backend:
18 | service:
19 | name: foo111 ### It's not the same rule, it should stay
20 | port:
21 | name: http
22 | - host: "test2.haproxy"
23 | http:
24 | paths:
25 | - path: /
26 | pathType: Prefix
27 | backend:
28 | service:
29 | name: foo2
30 | port:
31 | name: http
32 |
--------------------------------------------------------------------------------
/test/transform/data/rule/no-dupl-2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - host: "test.haproxy"
3 | http:
4 | paths:
5 | - path: /
6 | pathType: Prefix
7 | backend:
8 | service:
9 | name: foo1
10 | port:
11 | name: http
12 | - host: "test.haproxy"
13 | http:
14 | paths:
15 | - path: /
16 | pathType: Prefix
17 | backend:
18 | service:
19 | name: foo1
20 | port:
21 | name: http
22 | - path: /foo12
23 | pathType: Prefix
24 | backend:
25 | service:
26 | name: foo12
27 | port:
28 | name: http
29 | - host: "test2.haproxy"
30 | http:
31 | paths:
32 | - path: /
33 | pathType: Prefix
34 | backend:
35 | service:
36 | name: foo2
37 | port:
38 | name: http
39 |
--------------------------------------------------------------------------------
/test/transform/data/rule/no-duplicate.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - host: "test.haproxy"
3 | http:
4 | paths:
5 | - path: /
6 | pathType: Prefix
7 | backend:
8 | service:
9 | name: foo1
10 | port:
11 | name: http
12 | - host: "test2.haproxy"
13 | http:
14 | paths:
15 | - path: /
16 | pathType: Prefix
17 | backend:
18 | service:
19 | name: foo2
20 | port:
21 | name: http
22 |
--------------------------------------------------------------------------------
/test/transform/data/tls/dupl-both.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # tls:
3 | - hosts:
4 | - test1.haproxy
5 | - test1.haproxy
6 | - test1.haproxy
7 | - test1.haproxy
8 | secretName: test1
9 | - hosts:
10 | - test2.haproxy
11 | - test2.haproxy
12 | secretName: test2
13 |
--------------------------------------------------------------------------------
/test/transform/data/tls/dupl-hosts.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # tls:
3 | - hosts:
4 | - test1.haproxy
5 | - test1.haproxy
6 | - test1.haproxy
7 | - test1.haproxy
8 | secretName: test1
9 | - hosts:
10 | - test2.haproxy
11 | secretName: test2
12 |
--------------------------------------------------------------------------------
/test/transform/data/tls/dupl-tls-2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # tls:
3 | - hosts:
4 | - test1.haproxy
5 | secretName: test1
6 | - hosts:
7 | - test1.haproxy
8 | - test111.haproxy
9 | secretName: test1
10 | - hosts:
11 | - test112.haproxy
12 | secretName: test1
13 | - hosts:
14 | - test112.haproxy
15 | - test1121.haproxy
16 | secretName: test1
17 | - hosts:
18 | - test1.haproxy
19 | secretName: test1
20 | - hosts:
21 | - test1.haproxy
22 | - test111.haproxy
23 | secretName: test1
24 | - hosts:
25 | - test2.haproxy
26 | secretName: test2
27 | - hosts:
28 | - test2.haproxy
29 | secretName: test2
30 |
--------------------------------------------------------------------------------
/test/transform/data/tls/dupl-tls.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # tls:
3 | - hosts:
4 | - test1.haproxy
5 | secretName: test1
6 | - hosts:
7 | - test1.haproxy
8 | secretName: test1
9 | - hosts:
10 | - test1.haproxy
11 | secretName: test1
12 | - hosts:
13 | - test1.haproxy
14 | secretName: test1
15 | - hosts:
16 | - test2.haproxy
17 | secretName: test2
18 | - hosts:
19 | - test2.haproxy
20 | secretName: test2
21 |
--------------------------------------------------------------------------------
/test/transform/data/tls/expectation/dupl-tls-2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # tls:
3 | - hosts:
4 | - test1.haproxy
5 | secretName: test1
6 | - hosts:
7 | - test1.haproxy
8 | - test111.haproxy
9 | secretName: test1
10 | - hosts:
11 | - test112.haproxy
12 | secretName: test1
13 | - hosts:
14 | - test112.haproxy
15 | - test1121.haproxy
16 | secretName: test1
17 | - hosts:
18 | - test2.haproxy
19 | secretName: test2
20 |
--------------------------------------------------------------------------------
/test/transform/data/tls/expectation/no-duplicate.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # tls:
3 | - hosts:
4 | - test1.haproxy
5 | secretName: test1
6 | - hosts:
7 | - test2.haproxy
8 | secretName: test2
9 |
--------------------------------------------------------------------------------
/test/transform/data/tls/no-duplicate.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # tls:
3 | - hosts:
4 | - test1.haproxy
5 | secretName: test1
6 | - hosts:
7 | - test2.haproxy
8 | secretName: test2
9 |
--------------------------------------------------------------------------------