diff --git a/.golangci.yaml b/.golangci.yaml index 3b17bcda4..f4e0e47ed 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -87,6 +87,9 @@ linters: - linters: - godot path: internal/annotation/load_balancer.go + - linters: + - godot + path: internal/config/load_balancer_envs.go - linters: - errcheck - gosec diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index de7f96015..19a7f0eb1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -64,7 +64,7 @@ repos: require_serial: false additional_dependencies: [prettier@3.7.4] files: \.(md|ya?ml)$ - exclude: ^(CHANGELOG.md|chart/templates/.*|chart/.snapshots/.*|docs/reference/load_balancer_annotations\.md)$ + exclude: ^(CHANGELOG.md|chart/templates/.*|chart/.snapshots/.*|docs/reference/load_balancer_.*\.md|)$ - repo: local hooks: diff --git a/README.md b/README.md index e9c49f6c9..804425d82 100644 --- a/README.md +++ b/README.md @@ -106,9 +106,9 @@ export ROBOT_PASSWORD= go test ./tests/e2e -tags e2e,robot -v ``` -### Annotation Reference Generation +### Annotation and Environment Variable Reference Generation -The [Load Balancer annotation reference](docs/reference/load_balancer_annotations.md) is autogenerated via a custom written tool. This tool can be found at `tools/doc_generation.go`. +The [Load Balancer annotation reference](docs/reference/load_balancer_annotations.md) and the [Load Balancer environment variable reference](docs/reference/load_balancer_envs.md) are autogenerated via a custom written tool. This tool can be found at `tools/doc_generation.go`. The docstring format contains a description, starting with the constant name. The next lines can contain additional information about the annotation. Supported fields are: @@ -116,6 +116,7 @@ The docstring format contains a description, starting with the constant name. Th - `Default`: Specifies the default value of the annotation. When no default value is set, `-` is displayed. - `Read-only`: Specifies whether the annotation is read-only or not. If the annotation is read-only, it will be set by the HCCM and cannot be set by the user. - `Internal`: Specifies whether the annotation is for internal use only. If the annotation is internal, it will not be displayed in the reference documentation. +- You can reference other annotations or env vars by wrapping the target constant name in square brackets, e.g. `[LBAlgorithmType]`. #### Example diff --git a/docs/reference/load_balancer_annotations.md b/docs/reference/load_balancer_annotations.md index 563c8b4ec..367c5fa09 100644 --- a/docs/reference/load_balancer_annotations.md +++ b/docs/reference/load_balancer_annotations.md @@ -5,42 +5,42 @@ This page contains all annotations, which can be specified at a Service of type - Read-only annotations are set by the Cloud Controller Manager. - Enums are depicted in the `Type` column and possible options are separated via the pipe symbol `|`. -| Annotation | Type | Default | Read-only | Description | +| Name | Type | Default | Read-only | Description | | --- | --- | --- | --- | --- | -| `load-balancer.hetzner.cloud/algorithm-type` | `round_robin \| least_connections` | `round_robin` | `No` | Specifies the algorithm type of the Load Balancer. | -| `load-balancer.hetzner.cloud/certificate-type` | `uploaded \| managed` | `uploaded` | `No` | Defines the type of certificate the Load Balancer should use. | -| `load-balancer.hetzner.cloud/disable-private-ingress` | `bool` | `false` | `No` | Disables the use of the private network for ingress. | -| `load-balancer.hetzner.cloud/disable-public-network` | `bool` | `false` | `No` | Disables the public network of the Hetzner Cloud Load Balancer. It will still have a public network assigned, but all traffic is routed over the private network. | -| `load-balancer.hetzner.cloud/health-check-http-domain` | `string` | `-` | `No` | Specifies the domain we try to access when performing the health check. | -| `load-balancer.hetzner.cloud/health-check-http-path` | `string` | `-` | `No` | Specifies the path we try to access when performing the health check. | -| `load-balancer.hetzner.cloud/health-check-http-validate-certificate` | `bool` | `-` | `No` | Specifies whether the health check should validate the SSL certificate that comes from the target nodes. | -| `load-balancer.hetzner.cloud/health-check-interval` | `int` | `-` | `No` | Specifies the interval in which time we perform a health check in seconds. | -| `load-balancer.hetzner.cloud/health-check-port` | `int` | `-` | `No` | Specifies the port the health check is be performed on. | -| `load-balancer.hetzner.cloud/health-check-protocol` | `tcp \| http \| https` | `tcp` | `No` | Sets the protocol the health check should be performed over. | -| `load-balancer.hetzner.cloud/health-check-retries` | `int` | `-` | `No` | Specifies the number of time a health check is retried until a target is marked as unhealthy. | -| `load-balancer.hetzner.cloud/health-check-timeout` | `int` | `-` | `No` | Specifies the timeout of a single health check. | -| `load-balancer.hetzner.cloud/hostname` | `string` | `-` | `No` | Specifies the hostname of the Load Balancer. This will be used as ingress address instead of the Load Balancer IP addresses if specified. | -| `load-balancer.hetzner.cloud/http-certificates` | `string` | `-` | `No` | A comma separated list of IDs or Names of Certificates assigned to the service. | -| `load-balancer.hetzner.cloud/http-cookie-lifetime` | `int` | `-` | `No` | Specifies the lifetime of the HTTP cookie. | -| `load-balancer.hetzner.cloud/http-cookie-name` | `string` | `-` | `No` | Specifies the cookie name when using HTTP or HTTPS as protocol. | -| `load-balancer.hetzner.cloud/http-managed-certificate-domains` | `string` | `-` | `No` | Contains a comma separated list of the domain names of the managed certificate. All domains are used to create a single managed certificate. | -| `load-balancer.hetzner.cloud/http-managed-certificate-name` | `string` | `-` | `No` | Contains the name of the managed certificate to create by the Cloud Controller manager. Ignored if `load-balancer.hetzner.cloud/http-managed-certificate-name` is missing or set to "uploaded". | -| `load-balancer.hetzner.cloud/http-redirect-http` | `bool` | `false` | `No` | Create a redirect from HTTP to HTTPS. | -| `load-balancer.hetzner.cloud/http-status-codes` | `string` | `-` | `No` | Is a comma separated list of HTTP status codes which we expect. | -| `load-balancer.hetzner.cloud/http-sticky-sessions` | `bool` | `false` | `No` | Enables the sticky sessions feature of Hetzner Cloud HTTP Load Balancers. | -| `load-balancer.hetzner.cloud/id` | `string` | `-` | `Yes` | Is the ID assigned to the Hetzner Cloud Load Balancer by the backend. Deprecated: This annotation is not used. It is reserved for possible future use. | | `load-balancer.hetzner.cloud/ipv4` | `string` | `-` | `Yes` | Is the public IPv4 address assigned to the Load Balancer by the backend. | | `load-balancer.hetzner.cloud/ipv4-rdns` | `string` | `-` | `Yes` | Is the reverse DNS record assigned to the IPv4 address of the Load Balancer. | | `load-balancer.hetzner.cloud/ipv6` | `string` | `-` | `Yes` | Is the public IPv6 address assigned to the Load Balancer by the backend. | -| `load-balancer.hetzner.cloud/ipv6-disabled` | `bool` | `false` | `No` | Disables the use of IPv6 for the Load Balancer. Set this annotation if you use external-dns. | | `load-balancer.hetzner.cloud/ipv6-rdns` | `string` | `-` | `Yes` | Is the reverse DNS record assigned to the IPv6 address of the Load Balancer. | -| `load-balancer.hetzner.cloud/location` | `string` | `-` | `No` | Specifies the location where the Load Balancer will be created in. Changing the location to a different value after the load balancer was created has no effect. In order to move a load balancer to a different location it is necessary to delete and re-create it. Note, that this will lead to the load balancer getting new public IPs assigned. Mutually exclusive with LBNetworkZone. | +| `load-balancer.hetzner.cloud/ipv6-disabled` | `bool` | `false` | `No` | Disables the use of IPv6 for the Load Balancer. Set this annotation if you use external-dns. | | `load-balancer.hetzner.cloud/name` | `string` | `-` | `No` | Is the name of the Load Balancer. The name will be visible in the Hetzner Cloud API console. | -| `load-balancer.hetzner.cloud/network-zone` | `string` | `-` | `No` | Specifies the network zone where the Load Balancer will be created in. Changing the network zone to a different value after the load balancer was created has no effect. In order to move a load balancer to a different network zone it is necessary to delete and re-create it. Note, that this will lead to the load balancer getting new public IPs assigned. Mutually exclusive with LBLocation. | -| `load-balancer.hetzner.cloud/node-selector` | `string` | `-` | `No` | Can be set to restrict which Nodes are added as targets to the Load Balancer. It accepts a Kubernetes label selector string, using either the set-based or equality-based formats. If the selector can not be parsed, the targets in the Load Balancer are not updated and an Event is created with the error message. Format: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors | +| `load-balancer.hetzner.cloud/disable-public-network` | `bool` | `false` | `No` | Disables the public network of the Hetzner Cloud Load Balancer. It will still have a public network assigned, but all traffic is routed over the private network. | +| `load-balancer.hetzner.cloud/disable-private-ingress` | `bool` | `false` | `No` | Disables the use of the private network for ingress. | +| `load-balancer.hetzner.cloud/use-private-ip` | `bool` | `false` | `No` | Configures the Load Balancer to use the private IP for Load Balancer server targets. | | `load-balancer.hetzner.cloud/private-ipv4` | `string` | `-` | `No` | Specifies the IPv4 address to assign to the load balancer in the private network that it's attached to. | | `load-balancer.hetzner.cloud/private-subnet-ip-range` | `string` | `-` | `No` | Specifies an existing subnet to which the load balancer will be attached. The value must be in the CIDR notation. The subnet must belong to the network defined in the CCM configuration and must already exist. See: https://docs.hetzner.cloud/reference/cloud#network-actions-add-a-subnet-to-a-network | +| `load-balancer.hetzner.cloud/hostname` | `string` | `-` | `No` | Specifies the hostname of the Load Balancer. This will be used as ingress address instead of the Load Balancer IP addresses if specified. | | `load-balancer.hetzner.cloud/protocol` | `tcp \| http \| https` | `tcp` | `No` | Specifies the protocol of the service. | +| `load-balancer.hetzner.cloud/algorithm-type` | `round_robin \| least_connections` | `round_robin` | `No` | Specifies the algorithm type of the Load Balancer. | | `load-balancer.hetzner.cloud/type` | `string` | `lb11` | `No` | Specifies the type of the Load Balancer. | -| `load-balancer.hetzner.cloud/use-private-ip` | `bool` | `false` | `No` | Configures the Load Balancer to use the private IP for Load Balancer server targets. | +| `load-balancer.hetzner.cloud/location` | `string` | `-` | `No` | Specifies the location where the Load Balancer will be created in. Changing the location to a different value after the load balancer was created has no effect. In order to move a load balancer to a different location it is necessary to delete and re-create it. Note, that this will lead to the load balancer getting new public IPs assigned. Mutually exclusive with `load-balancer.hetzner.cloud/network-zone`. | +| `load-balancer.hetzner.cloud/network-zone` | `string` | `-` | `No` | Specifies the network zone where the Load Balancer will be created in. Changing the network zone to a different value after the load balancer was created has no effect. In order to move a load balancer to a different network zone it is necessary to delete and re-create it. Note, that this will lead to the load balancer getting new public IPs assigned. Mutually exclusive with `load-balancer.hetzner.cloud/location`. | +| `load-balancer.hetzner.cloud/node-selector` | `string` | `-` | `No` | Can be set to restrict which Nodes are added as targets to the Load Balancer. It accepts a Kubernetes label selector string, using either the set-based or equality-based formats. If the selector can not be parsed, the targets in the Load Balancer are not updated and an Event is created with the error message. Format: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors | | `load-balancer.hetzner.cloud/uses-proxyprotocol` | `bool` | `false` | `No` | Specifies if the Load Balancer services should use the proxy protocol. | +| `load-balancer.hetzner.cloud/http-cookie-name` | `string` | `-` | `No` | Specifies the cookie name when using HTTP or HTTPS as protocol. | +| `load-balancer.hetzner.cloud/http-cookie-lifetime` | `int` | `-` | `No` | Specifies the lifetime of the HTTP cookie. | +| `load-balancer.hetzner.cloud/certificate-type` | `uploaded \| managed` | `uploaded` | `No` | Defines the type of certificate the Load Balancer should use. | +| `load-balancer.hetzner.cloud/http-certificates` | `string` | `-` | `No` | A comma separated list of IDs or Names of Certificates assigned to the service. | +| `load-balancer.hetzner.cloud/http-managed-certificate-name` | `string` | `-` | `No` | Contains the name of the managed certificate to create by the Cloud Controller manager. Ignored if `load-balancer.hetzner.cloud/certificate-type` is missing or set to "uploaded". | +| `load-balancer.hetzner.cloud/http-managed-certificate-domains` | `string` | `-` | `No` | Contains a comma separated list of the domain names of the managed certificate. All domains are used to create a single managed certificate. | +| `load-balancer.hetzner.cloud/http-redirect-http` | `bool` | `false` | `No` | Create a redirect from HTTP to HTTPS. | +| `load-balancer.hetzner.cloud/http-sticky-sessions` | `bool` | `false` | `No` | Enables the sticky sessions feature of Hetzner Cloud HTTP Load Balancers. | +| `load-balancer.hetzner.cloud/health-check-protocol` | `tcp \| http \| https` | `tcp` | `No` | Sets the protocol the health check should be performed over. | +| `load-balancer.hetzner.cloud/health-check-port` | `int` | `-` | `No` | Specifies the port the health check is be performed on. | +| `load-balancer.hetzner.cloud/health-check-interval` | `int` | `-` | `No` | Specifies the interval in which time we perform a health check in seconds. | +| `load-balancer.hetzner.cloud/health-check-timeout` | `int` | `-` | `No` | Specifies the timeout of a single health check. | +| `load-balancer.hetzner.cloud/health-check-retries` | `int` | `-` | `No` | Specifies the number of time a health check is retried until a target is marked as unhealthy. | +| `load-balancer.hetzner.cloud/health-check-http-domain` | `string` | `-` | `No` | Specifies the domain we try to access when performing the health check. | +| `load-balancer.hetzner.cloud/health-check-http-path` | `string` | `-` | `No` | Specifies the path we try to access when performing the health check. | +| `load-balancer.hetzner.cloud/health-check-http-validate-certificate` | `bool` | `-` | `No` | Specifies whether the health check should validate the SSL certificate that comes from the target nodes. | +| `load-balancer.hetzner.cloud/http-status-codes` | `string` | `-` | `No` | Is a comma separated list of HTTP status codes which we expect. | +| `load-balancer.hetzner.cloud/id` | `string` | `-` | `Yes` | Is the ID assigned to the Hetzner Cloud Load Balancer by the backend. Deprecated: This annotation is not used. It is reserved for possible future use. | diff --git a/docs/reference/load_balancer_envs.md b/docs/reference/load_balancer_envs.md new file mode 100644 index 000000000..a05d811db --- /dev/null +++ b/docs/reference/load_balancer_envs.md @@ -0,0 +1,24 @@ +# Load Balancer Environment Variables + +This page contains all environment variables, which can be specified to configure the Load Balancer controller of hcloud-cloud-controller-manager. + +Some environment variables define global defaults. These defaults can be overridden by setting the corresponding annotation. If you remove such an annotation while a global default is configured, the global default will be applied again. + +Enums are depicted in the `Type` column and possible options are separated via the pipe symbol `|`. + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `HCLOUD_LOAD_BALANCERS_ENABLED` | `bool` | `true` | Controls whether the load balancer controller of HCCM should run. | +| `HCLOUD_LOAD_BALANCERS_LOCATION` | `string` | `-` | Specifies the default location where the Load Balancer will be created in. Mutually exclusive with `HCLOUD_LOAD_BALANCERS_NETWORK_ZONE`. | +| `HCLOUD_LOAD_BALANCERS_NETWORK_ZONE` | `string` | `-` | Specifies the default network zone where the Load Balancer will be created in. Mutually exclusive with `HCLOUD_LOAD_BALANCERS_LOCATION`. | +| `HCLOUD_LOAD_BALANCERS_DISABLE_PRIVATE_INGRESS` | `bool` | `false` | Disables the use of the private network for ingress by default. | +| `HCLOUD_LOAD_BALANCERS_USE_PRIVATE_IP` | `bool` | `false` | Configures the Load Balancer to use the private IP for Load Balancer server targets by default. | +| `HCLOUD_LOAD_BALANCERS_DISABLE_IPV6` | `bool` | `false` | Disables the use of IPv6 for the Load Balancer by default. | +| `HCLOUD_LOAD_BALANCERS_ALGORITHM_TYPE` | `round_robin \| least_connections` | `round_robin` | Configures the default Load Balancer algorithm. | +| `HCLOUD_LOAD_BALANCERS_DISABLE_PUBLIC_NETWORK` | `bool` | `false` | Disables the public interface of the Load Balancer by default. | +| `HCLOUD_LOAD_BALANCERS_HEALTH_CHECK_INTERVAL` | `int` | `10` | Configures the default time interval in seconds in which health checks are performed. | +| `HCLOUD_LOAD_BALANCERS_HEALTH_CHECK_RETRIES` | `int` | `3` | Configures the default amount of unsuccessful retries needed until a target is considered unhealthy. | +| `HCLOUD_LOAD_BALANCERS_HEALTH_CHECK_TIMEOUT` | `int` | `15` | Configures the default time in seconds after an attempt is considered a timeout. | +| `HCLOUD_LOAD_BALANCERS_PRIVATE_SUBNET_IP_RANGE` | `string` | `-` | Configures the default IP range in CIDR block notation of the subnet to attach to. | +| `HCLOUD_LOAD_BALANCERS_TYPE` | `string` | `lb11` | Configures the default Load Balancer type this Load Balancer should be created with. | +| `HCLOUD_LOAD_BALANCERS_USES_PROXYPROTOCOL` | `bool` | `false` | Enables the proxyprotocol for a Load Balancer service by default. | diff --git a/internal/annotation/load_balancer.go b/internal/annotation/load_balancer.go index e7b3a8e57..df95f53db 100644 --- a/internal/annotation/load_balancer.go +++ b/internal/annotation/load_balancer.go @@ -111,7 +111,7 @@ const ( // location it is necessary to delete and re-create it. Note, that this // will lead to the load balancer getting new public IPs assigned. // - // Mutually exclusive with LBNetworkZone. + // Mutually exclusive with [LBNetworkZone]. // // Type: string LBLocation Name = "load-balancer.hetzner.cloud/location" @@ -125,7 +125,7 @@ const ( // that this will lead to the load balancer getting new public IPs // assigned. // - // Mutually exclusive with LBLocation. + // Mutually exclusive with [LBLocation]. // // Type: string LBNetworkZone Name = "load-balancer.hetzner.cloud/network-zone" @@ -175,7 +175,7 @@ const ( // LBSvcHTTPManagedCertificateName contains the name of the managed // certificate to create by the Cloud Controller manager. Ignored if - // LBSvcHTTPCertificateType is missing or set to "uploaded". + // [LBSvcHTTPCertificateType] is missing or set to "uploaded". // // Type: string LBSvcHTTPManagedCertificateName Name = "load-balancer.hetzner.cloud/http-managed-certificate-name" diff --git a/internal/config/config.go b/internal/config/config.go index 57e7b122b..05f97504e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -34,21 +34,6 @@ const ( hcloudNetworkDisableAttachedCheck = "HCLOUD_NETWORK_DISABLE_ATTACHED_CHECK" hcloudNetworkRoutesEnabled = "HCLOUD_NETWORK_ROUTES_ENABLED" - hcloudLoadBalancersAlgorithmType = "HCLOUD_LOAD_BALANCERS_ALGORITHM_TYPE" - hcloudLoadBalancersDisableIPv6 = "HCLOUD_LOAD_BALANCERS_DISABLE_IPV6" - hcloudLoadBalancersDisablePrivateIngress = "HCLOUD_LOAD_BALANCERS_DISABLE_PRIVATE_INGRESS" - hcloudLoadBalancersDisablePublicNetwork = "HCLOUD_LOAD_BALANCERS_DISABLE_PUBLIC_NETWORK" - hcloudLoadBalancersEnabled = "HCLOUD_LOAD_BALANCERS_ENABLED" - hcloudLoadBalancersHealthCheckInterval = "HCLOUD_LOAD_BALANCERS_HEALTH_CHECK_INTERVAL" - hcloudLoadBalancersHealthCheckRetries = "HCLOUD_LOAD_BALANCERS_HEALTH_CHECK_RETRIES" - hcloudLoadBalancersHealthCheckTimeout = "HCLOUD_LOAD_BALANCERS_HEALTH_CHECK_TIMEOUT" - hcloudLoadBalancersLocation = "HCLOUD_LOAD_BALANCERS_LOCATION" - hcloudLoadBalancersNetworkZone = "HCLOUD_LOAD_BALANCERS_NETWORK_ZONE" - hcloudLoadBalancersPrivateSubnetIPRange = "HCLOUD_LOAD_BALANCERS_PRIVATE_SUBNET_IP_RANGE" - hcloudLoadBalancersType = "HCLOUD_LOAD_BALANCERS_TYPE" - hcloudLoadBalancersUsePrivateIP = "HCLOUD_LOAD_BALANCERS_USE_PRIVATE_IP" - hcloudLoadBalancersUsesProxyProtocol = "HCLOUD_LOAD_BALANCERS_USES_PROXYPROTOCOL" - hcloudMetricsEnabled = "HCLOUD_METRICS_ENABLED" hcloudMetricsAddress = "HCLOUD_METRICS_ADDRESS" ) diff --git a/internal/config/load_balancer_envs.go b/internal/config/load_balancer_envs.go new file mode 100644 index 000000000..37c64141b --- /dev/null +++ b/internal/config/load_balancer_envs.go @@ -0,0 +1,95 @@ +package config + +const ( + // hcloudLoadBalancersEnabled controls whether the load balancer controller of HCCM should run. + // + // Type: bool + // Default: true + hcloudLoadBalancersEnabled = "HCLOUD_LOAD_BALANCERS_ENABLED" + + // hcloudLoadBalancersLocation specifies the default location where the Load Balancer will be + // created in. + // + // Mutually exclusive with [hcloudLoadBalancersNetworkZone]. + // + // Type: string + hcloudLoadBalancersLocation = "HCLOUD_LOAD_BALANCERS_LOCATION" + + // hcloudLoadBalancersNetworkZone specifies the default network zone where the Load Balancer will be + // created in. + // + // Mutually exclusive with [hcloudLoadBalancersLocation]. + // + // Type: string + hcloudLoadBalancersNetworkZone = "HCLOUD_LOAD_BALANCERS_NETWORK_ZONE" + + // hcloudLoadBalancersDisablePrivateIngress disables the use of the private network for ingress by default. + // + // Type: bool + // Default: false + hcloudLoadBalancersDisablePrivateIngress = "HCLOUD_LOAD_BALANCERS_DISABLE_PRIVATE_INGRESS" + + // hcloudLoadBalancersUsePrivateIP configures the Load Balancer to use the private IP for + // Load Balancer server targets by default. + // + // Type: bool + // Default: false + hcloudLoadBalancersUsePrivateIP = "HCLOUD_LOAD_BALANCERS_USE_PRIVATE_IP" + + // hcloudLoadBalancersDisableIPv6 disables the use of IPv6 for the Load Balancer by default. + // + // Type: bool + // Default: false + hcloudLoadBalancersDisableIPv6 = "HCLOUD_LOAD_BALANCERS_DISABLE_IPV6" + + // hcloudLoadBalancersAlgorithmType configures the default Load Balancer algorithm. + // + // Type: round_robin | least_connections + // Default: round_robin + hcloudLoadBalancersAlgorithmType = "HCLOUD_LOAD_BALANCERS_ALGORITHM_TYPE" + + // hcloudLoadBalancersDisablePublicNetwork disables the public interface of the Load Balancer by default. + // + // Type: bool + // Default: false + hcloudLoadBalancersDisablePublicNetwork = "HCLOUD_LOAD_BALANCERS_DISABLE_PUBLIC_NETWORK" + + // hcloudLoadBalancersHealthCheckInterval configures the default time interval in seconds + // in which health checks are performed. + // + // Type: int + // Default: 10 + hcloudLoadBalancersHealthCheckInterval = "HCLOUD_LOAD_BALANCERS_HEALTH_CHECK_INTERVAL" + + // hcloudLoadBalancersHealthCheckRetries configures the default amount of unsuccessful retries + // needed until a target is considered unhealthy. + // + // Type: int + // Default: 3 + hcloudLoadBalancersHealthCheckRetries = "HCLOUD_LOAD_BALANCERS_HEALTH_CHECK_RETRIES" + + // hcloudLoadBalancersHealthCheckTimeout configures the default time in seconds after an attempt is + // considered a timeout. + // + // Type: int + // Default: 15 + hcloudLoadBalancersHealthCheckTimeout = "HCLOUD_LOAD_BALANCERS_HEALTH_CHECK_TIMEOUT" + + // hcloudLoadBalancersPrivateSubnetIPRange configures the default IP range in CIDR block notation of + // the subnet to attach to. + // + // Type: string + hcloudLoadBalancersPrivateSubnetIPRange = "HCLOUD_LOAD_BALANCERS_PRIVATE_SUBNET_IP_RANGE" + + // hcloudLoadBalancersType configures the default Load Balancer type this Load Balancer should be created with. + // + // Type: string + // Default: lb11 + hcloudLoadBalancersType = "HCLOUD_LOAD_BALANCERS_TYPE" + + // hcloudLoadBalancersUsesProxyProtocol enables the proxyprotocol for a Load Balancer service by default. + // + // Type: bool + // Default: false + hcloudLoadBalancersUsesProxyProtocol = "HCLOUD_LOAD_BALANCERS_USES_PROXYPROTOCOL" +) diff --git a/tools/doc_generation.go b/tools/doc_generation.go index 2cb062a7d..115bdd535 100644 --- a/tools/doc_generation.go +++ b/tools/doc_generation.go @@ -6,25 +6,24 @@ import ( "go/ast" "go/parser" "go/token" - "maps" "os" - "slices" "strconv" "strings" "text/template" ) -type Template struct { - AnnotationsTable string +type TemplateData struct { + ConstTable string } -type Table struct { - table map[string]*TableEntry +type ConstantDocTable struct { + entries map[string]*DocEntry } -type TableEntry struct { - commentLines []string - constName string +type DocEntry struct { + rawCommentLines []string + constName string + pos int Description string Type string @@ -33,54 +32,55 @@ type TableEntry struct { Internal bool } -func NewTable() *Table { - return &Table{ - table: make(map[string]*TableEntry), +func NewDocTable() *ConstantDocTable { + return &ConstantDocTable{ + entries: make(map[string]*DocEntry), } } -func (t *Table) AddEntry(annotation, constName string) { - t.table[annotation] = &TableEntry{ - commentLines: make([]string, 0), - constName: constName, +func (t *ConstantDocTable) AddEntry(constValue, constName string, pos int) { + t.entries[constValue] = &DocEntry{ + rawCommentLines: make([]string, 0), + constName: constName, + pos: pos, } } -func (t *Table) AppendComment(annotation, value string) { +func (t *ConstantDocTable) AppendComment(constValue, value string) { // trim comment artifacts comment := strings.Trim(value, "/ \n") if comment == "" { return } - t.table[annotation].commentLines = append(t.table[annotation].commentLines, comment) + t.entries[constValue].rawCommentLines = append(t.entries[constValue].rawCommentLines, comment) } -func (t *Table) FromAST(node ast.Node) (*Table, error) { +func (t *ConstantDocTable) FromAST(node ast.Node) (*ConstantDocTable, error) { ast.Inspect(node, t.visitFunc()) - for annotation, entry := range t.table { + for constValue, entry := range t.entries { commentBuilder := strings.Builder{} - for i, line := range entry.commentLines { - if val := getValueFromLine(line, "Type: "); val != "" { + for i, line := range entry.rawCommentLines { + if val := parseMetadataValue(line, "Type: "); val != "" { entry.Type = val continue } - if val := getValueFromLine(line, "Default: "); val != "" { + if val := parseMetadataValue(line, "Default: "); val != "" { entry.Default = val continue } - if val := getValueFromLine(line, "Read-only: "); val != "" { + if val := parseMetadataValue(line, "Read-only: "); val != "" { if readOnly, err := strconv.ParseBool(val); err == nil { entry.ReadOnly = readOnly } continue } - if val := getValueFromLine(line, "Internal: "); val != "" { + if val := parseMetadataValue(line, "Internal: "); val != "" { if internal, err := strconv.ParseBool(val); err == nil { entry.Internal = internal } @@ -98,15 +98,15 @@ func (t *Table) FromAST(node ast.Node) (*Table, error) { } if entry.Type == "" { - return nil, fmt.Errorf("missing Type for annotation %s", annotation) + return nil, fmt.Errorf("missing Type for %s", constValue) } comment := strings.Trim(commentBuilder.String(), " ") - for _, entryInner := range t.table { + for constValueInner, entryInner := range t.entries { comment = strings.ReplaceAll( comment, - fmt.Sprintf("%s ", entryInner.constName), - fmt.Sprintf("`%s` ", annotation), + fmt.Sprintf("[%s]", entryInner.constName), + fmt.Sprintf("`%s`", constValueInner), ) } entry.Description = comment @@ -115,49 +115,55 @@ func (t *Table) FromAST(node ast.Node) (*Table, error) { return t, nil } -func (t *Table) String() string { +func (t *ConstantDocTable) String(hasReadOnlyColumn bool) string { tableStr := strings.Builder{} - tableStr.WriteString("| Annotation | Type | Default | Read-only | Description |\n") - tableStr.WriteString("| --- | --- | --- | --- | --- |\n") + if hasReadOnlyColumn { + tableStr.WriteString("| Name | Type | Default | Read-only | Description |\n") + tableStr.WriteString("| --- | --- | --- | --- | --- |\n") + } else { + tableStr.WriteString("| Name | Type | Default | Description |\n") + tableStr.WriteString("| --- | --- | --- | --- |\n") + } - annotations := slices.Sorted(maps.Keys(t.table)) + constValues := make([]string, len(t.entries)) + for constValue, entry := range t.entries { + constValues[entry.pos] = constValue + } - for _, annotation := range annotations { - // Skip internal annotations - if t.table[annotation].Internal { + for _, constValue := range constValues { + // Skip internal const values + if t.entries[constValue].Internal { continue } // Escape pipe characters in Type to avoid breaking the table - typeVal := strings.ReplaceAll(t.table[annotation].Type, "|", "\\|") + typeVal := strings.ReplaceAll(t.entries[constValue].Type, "|", "\\|") defaultVal := "-" - if t.table[annotation].Default != "" { - defaultVal = t.table[annotation].Default + if t.entries[constValue].Default != "" { + defaultVal = t.entries[constValue].Default } - readOnlyVal := "No" - if t.table[annotation].ReadOnly { - readOnlyVal = "Yes" + tableStr.WriteString(fmt.Sprintf("| `%s` ", constValue)) + tableStr.WriteString(fmt.Sprintf("| `%s` ", typeVal)) + tableStr.WriteString(fmt.Sprintf("| `%s` ", defaultVal)) + + if hasReadOnlyColumn { + readOnlyVal := "No" + if t.entries[constValue].ReadOnly { + readOnlyVal = "Yes" + } + tableStr.WriteString(fmt.Sprintf("| `%s` ", readOnlyVal)) } - tableStr.WriteString( - fmt.Sprintf( - "| `%s` | `%s` | `%s` | `%s` | %s |\n", - annotation, - typeVal, - defaultVal, - readOnlyVal, - t.table[annotation].Description, - ), - ) + tableStr.WriteString(fmt.Sprintf("| %s |\n", t.entries[constValue].Description)) } return tableStr.String() } -func (t *Table) visitFunc() func(n ast.Node) bool { +func (t *ConstantDocTable) visitFunc() func(n ast.Node) bool { return func(n ast.Node) bool { genDecl, ok := n.(*ast.GenDecl) if !ok { @@ -168,7 +174,7 @@ func (t *Table) visitFunc() func(n ast.Node) bool { return true } - for _, spec := range genDecl.Specs { + for pos, spec := range genDecl.Specs { valueSpec, ok := spec.(*ast.ValueSpec) if !ok { continue @@ -190,12 +196,12 @@ func (t *Table) visitFunc() func(n ast.Node) bool { } constName := valueSpec.Names[0].Name - annotation := strings.ReplaceAll(literal.Value, "\"", "") + value := strings.ReplaceAll(literal.Value, "\"", "") - t.AddEntry(annotation, constName) + t.AddEntry(value, constName, pos) for _, comment := range valueSpec.Doc.List { - t.AppendComment(annotation, comment.Text) + t.AppendComment(value, comment.Text) } } @@ -203,7 +209,7 @@ func (t *Table) visitFunc() func(n ast.Node) bool { } } -func getValueFromLine(line, key string) string { +func parseMetadataValue(line, key string) string { parts := strings.Split(line, key) if len(parts) > 1 { return strings.Trim(parts[1], " \n.") @@ -211,32 +217,32 @@ func getValueFromLine(line, key string) string { return "" } -func run(templatePath string, annotationsPath string, outputPath string) error { +func generateDocs(templatePath string, constFilePath string, outputPath string, hasReadOnlyColumn bool) error { // Read template file - tmplStr, err := os.ReadFile(templatePath) + templateContent, err := os.ReadFile(templatePath) if err != nil { return err } // Parse AST - node, err := parser.ParseFile(&token.FileSet{}, annotationsPath, nil, parser.ParseComments) + astNode, err := parser.ParseFile(&token.FileSet{}, constFilePath, nil, parser.ParseComments) if err != nil { return fmt.Errorf("error parsing file: %w", err) } // Create table from AST - table, err := NewTable().FromAST(node) + docTable, err := NewDocTable().FromAST(astNode) if err != nil { return err } // Create Markdown file from template - tmpl, err := template.New("annotations").Parse(string(tmplStr)) + tmpl, err := template.New("consts").Parse(string(templateContent)) if err != nil { return fmt.Errorf("error parsing template: %w", err) } - tmplData := Template{AnnotationsTable: table.String()} + tmplData := TemplateData{ConstTable: docTable.String(hasReadOnlyColumn)} var buf bytes.Buffer if err := tmpl.Execute(&buf, tmplData); err != nil { return fmt.Errorf("error executing template: %w", err) @@ -265,7 +271,17 @@ func main() { lbAnnotationsPath := "../internal/annotation/load_balancer.go" lbOutputPath := "../docs/reference/load_balancer_annotations.md" - if err := run(lbTemplatePath, lbAnnotationsPath, lbOutputPath); err != nil { + // Generate Load Balancer env documentation + lbEnvTemplatePath := "./load_balancer_envs.md.tmpl" + lbEnvPath := "../internal/config/load_balancer_envs.go" + lbEnvOutputPath := "../docs/reference/load_balancer_envs.md" + + if err := generateDocs(lbTemplatePath, lbAnnotationsPath, lbOutputPath, true); err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } + + if err := generateDocs(lbEnvTemplatePath, lbEnvPath, lbEnvOutputPath, false); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } diff --git a/tools/load_balancer_annotations.md.tmpl b/tools/load_balancer_annotations.md.tmpl index e62f50b7e..cc50d3251 100644 --- a/tools/load_balancer_annotations.md.tmpl +++ b/tools/load_balancer_annotations.md.tmpl @@ -5,4 +5,4 @@ This page contains all annotations, which can be specified at a Service of type - Read-only annotations are set by the Cloud Controller Manager. - Enums are depicted in the `Type` column and possible options are separated via the pipe symbol `|`. -{{.AnnotationsTable}} +{{.ConstTable}} diff --git a/tools/load_balancer_envs.md.tmpl b/tools/load_balancer_envs.md.tmpl new file mode 100644 index 000000000..316955769 --- /dev/null +++ b/tools/load_balancer_envs.md.tmpl @@ -0,0 +1,9 @@ +# Load Balancer Environment Variables + +This page contains all environment variables, which can be specified to configure the Load Balancer controller of hcloud-cloud-controller-manager. + +Some environment variables define global defaults. These defaults can be overridden by setting the corresponding annotation. If you remove such an annotation while a global default is configured, the global default will be applied again. + +Enums are depicted in the `Type` column and possible options are separated via the pipe symbol `|`. + +{{.ConstTable}}