Skip to content

[Feature] Expose HTTP Client Config #1680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries
- (Feature) Fix CRD Schema types
- (Bugfix) Adjust Prometheus Monitor labels
- (Feature) Expose HTTP Client Config

## [1.2.41](https://github.com/arangodb/kube-arangodb/tree/1.2.41) (2024-05-24)
- (Maintenance) Bump Prometheus API Version
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ Flags:
--deployment.feature.upgrade-version-check Enable initContainer with pre version check - Required ArangoDB 3.8.0 or higher (default true)
--deployment.feature.upgrade-version-check-v2 Enable initContainer with pre version check based by Operator - Required ArangoDB 3.8.0 or higher
--features-config-map-name string Name of the Feature Map ConfigMap (default "arangodb-operator-feature-config-map")
--http1.keep-alive If false, disables HTTP keep-alives and will only use the connection to the server for a single HTTP request (default true)
--http1.transport.dial-timeout duration Maximum amount of time a dial will wait for a connect to complete (default 30s)
--http1.transport.idle-conn-timeout duration Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself. Zero means no limit (default 1m30s)
--http1.transport.idle-conn-timeout-short duration Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself. Zero means no limit (default 100ms)
--http1.transport.keep-alive-timeout duration Interval between keep-alive probes for an active network connection (default 1m30s)
--http1.transport.keep-alive-timeout-short duration Interval between keep-alive probes for an active network connection (default 100ms)
--http1.transport.max-idle-conns int Maximum number of idle (keep-alive) connections across all hosts. Zero means no limit (default 100)
--http1.transport.tls-handshake-timeout duration Maximum amount of time to wait for a TLS handshake. Zero means no timeout (default 10s)
--image.discovery.status Discover Operator Image from Pod Status by default. When disabled Pod Spec is used. (default true)
--image.discovery.timeout duration Timeout for image discovery process (default 1m0s)
--internal.scaling-integration Enable Scaling Integration
Expand Down
3 changes: 3 additions & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ func init() {
if err := reconcile.ActionsConfigGlobal.Init(&cmdMain); err != nil {
panic(err.Error())
}
if err := operatorHTTP.InitConfiguration(&cmdMain); err != nil {
panic(err.Error())
}
}

func Command() *cobra.Command {
Expand Down
24 changes: 3 additions & 21 deletions pkg/deployment/context_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,9 @@ package deployment

import (
"context"
"crypto/tls"
"fmt"
"net"
nhttp "net/http"
"strconv"
"time"

core "k8s.io/api/core/v1"
apiErrors "k8s.io/apimachinery/pkg/api/errors"
Expand All @@ -53,9 +50,11 @@ import (
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
"github.com/arangodb/kube-arangodb/pkg/operator/scope"
"github.com/arangodb/kube-arangodb/pkg/replication"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/constants"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/globals"
operatorHTTP "github.com/arangodb/kube-arangodb/pkg/util/http"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector"
persistentvolumeclaimv1 "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/persistentvolumeclaim/v1"
Expand Down Expand Up @@ -219,24 +218,7 @@ func (d *Deployment) GetAgency(ctx context.Context, agencyIDs ...string) (agency
}

func (d *Deployment) getConnConfig() (http.ConnectionConfig, error) {
transport := &nhttp.Transport{
Proxy: nhttp.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 10 * time.Second,
KeepAlive: 100 * time.Millisecond,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 100 * time.Millisecond,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}

if d.GetSpec().TLS.IsSecure() {
transport.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
transport := operatorHTTP.RoundTripperWithShortTransport(operatorHTTP.WithTransportTLS(util.BoolSwitch(d.GetSpec().TLS.IsSecure(), operatorHTTP.Insecure, nil)))

connConfig := http.ConnectionConfig{
Transport: transport,
Expand Down
8 changes: 3 additions & 5 deletions pkg/deployment/reconcile/plan_builder_tls.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -43,6 +43,7 @@ import (
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/constants"
"github.com/arangodb/kube-arangodb/pkg/util/crypto"
operatorHTTP "github.com/arangodb/kube-arangodb/pkg/util/http"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector"
memberTls "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/tls"
Expand Down Expand Up @@ -450,10 +451,7 @@ func checkServerValidCertRequest(ctx context.Context, context PlanBuilderContext
endpoint = fmt.Sprintf("https://%s:%d%s", k8sutil.CreatePodDNSNameWithDomain(apiObject, context.GetSpec().ClusterDomain, group.AsRole(), member.ID), shared.ArangoSyncMasterPort, shared.ArangoSyncStatusEndpoint)
}

tlsConfig := &tls.Config{
RootCAs: ca.AsCertPool(),
}
transport := &http.Transport{TLSClientConfig: tlsConfig}
transport := operatorHTTP.RoundTripper(operatorHTTP.WithTransportTLS(operatorHTTP.WithRootCA(ca.AsCertPool())))
client := &http.Client{Transport: transport, Timeout: time.Second}

auth, err := context.GetAuthentication()()
Expand Down
9 changes: 3 additions & 6 deletions pkg/exporter/passthru.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@
package exporter

import (
"crypto/tls"
"io"
"net/http"
"strings"
"sync"
"time"

"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
operatorHTTP "github.com/arangodb/kube-arangodb/pkg/util/http"
)

var _ http.Handler = &passthru{}
Expand All @@ -44,17 +45,13 @@ type httpClientFactory func(endpoint string) (*http.Client, *http.Request, error

func newHttpClientFactory(auth Authentication, sslVerify bool, timeout time.Duration) httpClientFactory {
return func(endpoint string) (*http.Client, *http.Request, error) {
transport := &http.Transport{}
transport := operatorHTTP.Transport(operatorHTTP.WithTransportTLS(util.BoolSwitch(sslVerify, operatorHTTP.Insecure, nil)))

req, err := http.NewRequest("GET", endpoint, nil)
if err != nil {
return nil, nil, errors.WithStack(err)
}

if !sslVerify {
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}

jwt, err := auth()
if err != nil {
return nil, nil, err
Expand Down
33 changes: 8 additions & 25 deletions pkg/storage/provisioner/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@ package client
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"io"
"net"
"net/http"
"net/url"
"time"

"github.com/arangodb/kube-arangodb/pkg/storage/provisioner"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
operatorHTTP "github.com/arangodb/kube-arangodb/pkg/util/http"
)

// New creates a new client for the provisioner API.
Expand All @@ -44,39 +43,23 @@ func New(endpoint string) (provisioner.API, error) {
u.Path = ""
return &client{
endpoint: *u,
client: &http.Client{
Transport: operatorHTTP.RoundTripper(operatorHTTP.WithTransportTLS(operatorHTTP.Insecure)),
Timeout: defaultHTTPTimeout,
},
}, nil
}

type client struct {
endpoint url.URL

client *http.Client
}

const (
defaultHTTPTimeout = time.Minute * 2
)

var (
httpClient = &http.Client{
Timeout: defaultHTTPTimeout,
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 90 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
ExpectContinueTimeout: 1 * time.Second,
},
}
)

// GetNodeInfo fetches information from the current node.
func (c *client) GetNodeInfo(ctx context.Context) (provisioner.NodeInfo, error) {
req, err := c.newRequest("GET", "/nodeinfo", nil)
Expand Down Expand Up @@ -165,7 +148,7 @@ func (c *client) newRequest(method string, localPath string, body interface{}) (
// do performs the given request and parses the result.
func (c *client) do(ctx context.Context, req *http.Request, result interface{}) error {
req = req.WithContext(ctx)
resp, err := httpClient.Do(req)
resp, err := c.client.Do(req)
if err != nil {
// Request failed
return errors.WithStack(err)
Expand Down
72 changes: 17 additions & 55 deletions pkg/util/arangod/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@ package arangod

import (
"context"
"crypto/tls"
"net"
nhttp "net/http"
"strconv"
"time"

typedCore "k8s.io/client-go/kubernetes/typed/core/v1"

Expand All @@ -39,6 +37,7 @@ import (
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/globals"
operatorHTTP "github.com/arangodb/kube-arangodb/pkg/util/http"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
)

Expand All @@ -61,58 +60,21 @@ func WithRequireAuthentication(ctx context.Context) context.Context {
return context.WithValue(ctx, requireAuthenticationKey{}, true)
}

var (
sharedHTTPTransport = &nhttp.Transport{
Proxy: nhttp.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 90 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
sharedHTTPSTransport = &nhttp.Transport{
Proxy: nhttp.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 90 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
sharedHTTPTransportShortTimeout = &nhttp.Transport{
Proxy: nhttp.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 100 * time.Millisecond,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 100 * time.Millisecond,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
sharedHTTPSTransportShortTimeout = &nhttp.Transport{
Proxy: nhttp.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 100 * time.Millisecond,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 100 * time.Millisecond,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
)
func sharedHTTPTransport() nhttp.RoundTripper {
return operatorHTTP.Transport()
}

func sharedHTTPSTransport() nhttp.RoundTripper {
return operatorHTTP.Transport(operatorHTTP.WithTransportTLS(operatorHTTP.Insecure))
}

func sharedHTTPTransportShortTimeout() nhttp.RoundTripper {
return operatorHTTP.RoundTripperWithShortTransport()
}

func sharedHTTPSTransportShortTimeout() nhttp.RoundTripper {
return operatorHTTP.RoundTripperWithShortTransport(operatorHTTP.WithTransportTLS(operatorHTTP.Insecure))
}

// CreateArangodClient creates a go-driver client for a specific member in the given group.
func CreateArangodClient(ctx context.Context, cli typedCore.CoreV1Interface, apiObject *api.ArangoDeployment, group api.ServerGroup, id string, asyncSupport bool) (driver.Client, error) {
Expand Down Expand Up @@ -192,7 +154,7 @@ func createArangodHTTPConfigForDNSNames(apiObject *api.ArangoDeployment, dnsName
}
}
connConfig := http.ConnectionConfig{
Transport: transport,
Transport: transport(),
DontFollowRedirect: true,
}
for _, dnsName := range dnsNames {
Expand Down
53 changes: 53 additions & 0 deletions pkg/util/http/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//

package http

import (
"crypto/tls"
"crypto/x509"
"net/http"
)

func RoundTripper(mods ...TransportMod) http.RoundTripper {
df := append([]TransportMod{
configuration.DefaultTransport,
}, mods...)

return Transport(df...)
}

func RoundTripperWithShortTransport(mods ...TransportMod) http.RoundTripper {
df := append([]TransportMod{
configuration.ShortTransport,
}, mods...)

return Transport(df...)
}

func Insecure(in *tls.Config) {
in.InsecureSkipVerify = true
}

func WithRootCA(ca *x509.CertPool) TransportTLSMod {
return func(in *tls.Config) {
in.RootCAs = ca
}
}
Loading