Skip to content
This repository was archived by the owner on Dec 11, 2023. It is now read-only.

Commit a7b8d1a

Browse files
authored
Feature/add proxy settings (#207)
* Add Proxy setting for the Operator
1 parent 088bec9 commit a7b8d1a

File tree

11 files changed

+143
-33
lines changed

11 files changed

+143
-33
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
## Future
44

55
### Features
6-
* Separated the logic for watching the nodes into nodes_controller to handle scaling correctly ([#189](https://github.com/Dynatrace/dynatrace-oneagent-operator/pull/189), [#196](https://github.com/Dynatrace/dynatrace-oneagent-operator/pull/196))
6+
* Separated the logic for watching the nodes into nodes_controller to handle scaling correctly ([#189](https://github.com/Dynatrace/dynatrace-oneagent-operator/pull/189), [#196](https://github.com/Dynatrace/dynatrace-oneagent-operator/pull/196))
77
* Show operator phase in the `status.phase` field of the OneAgent object ([#197](https://github.com/Dynatrace/dynatrace-oneagent-operator/pull/197))
88
* Build ARM64 images for the Operator ([#201](https://github.com/Dynatrace/dynatrace-oneagent-operator/pull/201))
99
* No longer change the OneAgent .spec section to set defaults ([#206](https://github.com/Dynatrace/dynatrace-oneagent-operator/pull/206))
10+
* Added a setting to configure a proxy via the CR ([#207](https://github.com/Dynatrace/dynatrace-oneagent-operator/pull/207))
1011

1112
### Bug fixes
1213
* Handle sporadic (and benign) race conditions where the error below would appear ([#194](https://github.com/Dynatrace/dynatrace-oneagent-operator/pull/194)),
@@ -82,7 +83,7 @@
8283

8384
### [v0.4.0](https://github.com/Dynatrace/dynatrace-oneagent-operator/releases/tag/v0.4.0)
8485

85-
* Support automatic configuration of Istio to allow communication from the OneAgent pods to the Dynatrace environment.
86+
* Support automatic configuration of Istio to allow communication from the OneAgent pods to the Dynatrace environment.
8687
* Added support for Kubernetes 1.16
8788

8889
### [v0.3.1](https://github.com/Dynatrace/dynatrace-oneagent-operator/releases/tag/v0.3.1)

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ spec:
136136
# custom: label
137137
# Name of the service account for the OneAgent (optional)
138138
#serviceAccountName: "dynatrace-oneagent"
139+
# Configures a proxy for the Agent, AgentDownload and the Operator (optional)
140+
# Either provide the proxy URL directly at 'value' or create a secret with a field 'proxy' which holds your encrypted proxy URL
141+
#proxy:
142+
# value: https://my-proxy-url.com
143+
# valueFrom: nameOfMyProxySecret
139144
```
140145
Save the snippet to a file or use [./deploy/cr.yaml](https://raw.githubusercontent.com/Dynatrace/dynatrace-oneagent-operator/master/deploy/cr.yaml) from this repository and adjust its values accordingly.
141146
A secret holding tokens for authenticating to the Dynatrace cluster needs to be created upfront.

deploy/cr.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,9 @@ spec:
5656
#labels:
5757
# custom: label
5858
# Name of the service account for the OneAgent (optional)
59-
#serviceAccountName: "dynatrace-oneagent"
59+
#serviceAccountName: "dynatrace-oneagent"
60+
# Configures a proxy for the Agent, AgentDownload and the Operator (optional)
61+
# Either provide the proxy URL directly at 'value' or create a secret with a field 'proxy' which holds your encrypted proxy URL
62+
#proxy:
63+
# value: https://my-proxy-url.com
64+
# valueFrom: nameOfMyProxySecret

deploy/crds/dynatrace.com_oneagents_crd.yaml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ spec:
3535
apiVersion:
3636
description: 'APIVersion defines the versioned schema of this representation
3737
of an object. Servers should convert recognized schemas to the latest
38-
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
38+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
3939
type: string
4040
kind:
4141
description: 'Kind is a string value representing the REST resource this
4242
object represents. Servers may infer this from the endpoint the client
43-
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
43+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
4444
type: string
4545
metadata:
4646
type: object
@@ -185,6 +185,15 @@ spec:
185185
Name must be defined by creating a PriorityClass object with that
186186
name. If not specified the setting will be removed from the DaemonSet.'
187187
type: string
188+
proxy:
189+
description: 'Optional: set custom proxy settings either directly or
190+
from a secret with the field ''proxy'''
191+
properties:
192+
value:
193+
type: string
194+
valueFrom:
195+
type: string
196+
type: object
188197
resources:
189198
description: 'Optional: define resources requests and limits for single
190199
pods'

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mo
374374
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
375375
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
376376
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
377+
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
377378
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
378379
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
379380
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -565,6 +566,7 @@ github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfm
565566
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
566567
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
567568
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
569+
github.com/rogpeppe/go-internal v1.5.0 h1:Usqs0/lDK/NqTkvrmKSwA/3XkZAs7ZAW/eLeQ2MVBTw=
568570
github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
569571
github.com/rubenv/sql-migrate v0.0.0-20191025130928-9355dd04f4b3/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY=
570572
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
@@ -578,6 +580,7 @@ github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9Nz
578580
github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
579581
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
580582
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
583+
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
581584
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
582585
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
583586
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=

pkg/apis/dynatrace/v1alpha1/oneagent_types.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ type OneAgentSpec struct {
9595
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.displayName="Labels"
9696
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.x-descriptors="urn:alm:descriptor:com.tectonic.ui:advanced,urn:alm:descriptor:com.tectonic.ui:text"
9797
Labels map[string]string `json:"labels,omitempty"`
98+
// Optional: set custom proxy settings either directly or from a secret with the field 'proxy'
99+
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true
100+
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.displayName="Proxy"
101+
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.x-descriptors="urn:alm:descriptor:com.tectonic.ui:advanced,urn:alm:descriptor:com.tectonic.ui:text"
102+
Proxy *OneAgentProxy `json:"proxy,omitempty"`
98103
}
99104

100105
type OneAgentConditionType string
@@ -111,6 +116,11 @@ type OneAgentCondition struct {
111116
Message string `json:"message"`
112117
}
113118

119+
type OneAgentProxy struct {
120+
Value string `json:"value,omitempty"`
121+
ValueFrom string `json:"valueFrom,omitempty"`
122+
}
123+
114124
// Possible reasons for ApiToken and PaaSToken conditions.
115125
const (
116126
// ReasonTokenReady is set when a token has passed verifications.

pkg/apis/dynatrace/v1alpha1/zz_generated.deepcopy.go

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/controller/oneagent/oneagent_controller.go

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,12 +374,17 @@ func newPodSpecForCR(instance *dynatracev1alpha1.OneAgent) corev1.PodSpec {
374374
sa = instance.Spec.ServiceAccountName
375375
}
376376

377+
args := instance.Spec.Args
378+
if instance.Spec.Proxy != nil && (instance.Spec.Proxy.ValueFrom != "" || instance.Spec.Proxy.Value != "") {
379+
args = append(instance.Spec.Args, "--set-proxy=$(https_proxy)")
380+
}
381+
377382
// K8s 1.18+ is expected to drop the "beta.kubernetes.io" labels in favor of "kubernetes.io" which was added on K8s 1.14.
378383
// To support both older and newer K8s versions we use node affinity.
379384

380385
return corev1.PodSpec{
381386
Containers: []corev1.Container{{
382-
Args: instance.Spec.Args,
387+
Args: args,
383388
Env: prepareEnvVars(instance),
384389
Image: img,
385390
ImagePullPolicy: corev1.PullAlways,
@@ -461,12 +466,13 @@ func newPodSpecForCR(instance *dynatracev1alpha1.OneAgent) corev1.PodSpec {
461466
}
462467

463468
func prepareEnvVars(instance *dynatracev1alpha1.OneAgent) []corev1.EnvVar {
464-
var token, installerURL, skipCert *corev1.EnvVar
469+
var token, installerURL, skipCert, proxy *corev1.EnvVar
465470

466471
reserved := map[string]**corev1.EnvVar{
467472
"ONEAGENT_INSTALLER_TOKEN": &token,
468473
"ONEAGENT_INSTALLER_SCRIPT_URL": &installerURL,
469474
"ONEAGENT_INSTALLER_SKIP_CERT_CHECK": &skipCert,
475+
"https_proxy": &proxy,
470476
}
471477

472478
var envVars []corev1.EnvVar
@@ -505,7 +511,32 @@ func prepareEnvVars(instance *dynatracev1alpha1.OneAgent) []corev1.EnvVar {
505511
}
506512
}
507513

508-
return append([]corev1.EnvVar{*token, *installerURL, *skipCert}, envVars...)
514+
env := []corev1.EnvVar{*token, *installerURL, *skipCert}
515+
516+
if proxy == nil {
517+
if instance.Spec.Proxy != nil {
518+
if instance.Spec.Proxy.ValueFrom != "" {
519+
env = append(env, corev1.EnvVar{
520+
Name: "https_proxy",
521+
ValueFrom: &corev1.EnvVarSource{
522+
SecretKeyRef: &corev1.SecretKeySelector{
523+
LocalObjectReference: corev1.LocalObjectReference{Name: instance.Spec.Proxy.ValueFrom},
524+
Key: "proxy",
525+
},
526+
},
527+
})
528+
} else if instance.Spec.Proxy.Value != "" {
529+
env = append(env, corev1.EnvVar{
530+
Name: "https_proxy",
531+
Value: instance.Spec.Proxy.Value,
532+
})
533+
}
534+
}
535+
} else {
536+
env = append(env, *proxy)
537+
}
538+
539+
return append(env, envVars...)
509540
}
510541

511542
// deletePods deletes a list of pods

pkg/controller/utils/verification.go renamed to pkg/controller/utils/utils.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ import (
1111
v1 "k8s.io/api/core/v1"
1212
"k8s.io/apimachinery/pkg/api/errors"
1313
"sigs.k8s.io/controller-runtime/pkg/client"
14+
"sigs.k8s.io/controller-runtime/pkg/log"
1415
)
1516

1617
const (
1718
DynatracePaasToken = "paasToken"
1819
DynatraceApiToken = "apiToken"
1920
)
2021

22+
var logger = log.Log.WithName("dynatrace.utils")
23+
2124
// DynatraceClientFunc defines handler func for dynatrace client
2225
type DynatraceClientFunc func(rtc client.Client, instance *dynatracev1alpha1.OneAgent) (dtclient.Client, error)
2326

@@ -34,7 +37,30 @@ func BuildDynatraceClient(rtc client.Client, instance *dynatracev1alpha1.OneAgen
3437
}
3538

3639
// initialize dynatrace client
37-
var certificateValidation = dtclient.SkipCertificateValidation(instance.Spec.SkipCertCheck)
40+
var opts []dtclient.Option
41+
if instance.Spec.SkipCertCheck {
42+
opts = append(opts, dtclient.SkipCertificateValidation(true))
43+
}
44+
45+
p := instance.Spec.Proxy
46+
47+
if p != nil {
48+
if p.ValueFrom != "" {
49+
proxySecret := &corev1.Secret{}
50+
err := rtc.Get(context.TODO(), client.ObjectKey{Namespace: instance.Namespace, Name: p.ValueFrom}, proxySecret)
51+
if err != nil {
52+
logger.Info("Failed to get proxy field within proxy secret!")
53+
} else {
54+
proxyURL, err := extractToken(proxySecret, "proxy")
55+
if err != nil {
56+
return nil, err
57+
}
58+
opts = append(opts, dtclient.Proxy(proxyURL))
59+
}
60+
} else if p.Value != "" {
61+
opts = append(opts, dtclient.Proxy(p.Value))
62+
}
63+
}
3864

3965
apiToken, err := extractToken(secret, DynatraceApiToken)
4066
if err != nil {
@@ -46,7 +72,7 @@ func BuildDynatraceClient(rtc client.Client, instance *dynatracev1alpha1.OneAgen
4672
return nil, err
4773
}
4874

49-
dtc, err := dtclient.NewClient(instance.Spec.ApiUrl, apiToken, paasToken, certificateValidation)
75+
dtc, err := dtclient.NewClient(instance.Spec.ApiUrl, apiToken, paasToken, opts...)
5076

5177
return dtc, err
5278
}

pkg/dtclient/client.go

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import (
44
"crypto/tls"
55
"errors"
66
"net/http"
7+
"net/url"
78
"strings"
8-
"sync"
99
)
1010

1111
// Client is the interface for the Dynatrace REST API client.
@@ -102,8 +102,10 @@ func NewClient(url, apiToken, paasToken string, opts ...Option) (Client, error)
102102
apiToken: apiToken,
103103
paasToken: paasToken,
104104

105-
hostCache: make(map[string]hostInfo),
106-
httpClient: http.DefaultClient,
105+
hostCache: make(map[string]hostInfo),
106+
httpClient: &http.Client{
107+
Transport: http.DefaultTransport.(*http.Transport).Clone(),
108+
},
107109
}
108110

109111
for _, opt := range opts {
@@ -115,31 +117,28 @@ func NewClient(url, apiToken, paasToken string, opts ...Option) (Client, error)
115117
// Option can be passed to NewClient and customizes the created client instance.
116118
type Option func(*dynatraceClient)
117119

118-
var skipCertValidationClient *http.Client
119-
var skipCertValidationOnce sync.Once
120-
121120
// SkipCertificateValidation creates an Option that specifies whether validation of the server's TLS
122121
// certificate should be skipped. The default is false.
123122
func SkipCertificateValidation(skip bool) Option {
124123
return func(c *dynatraceClient) {
125124
if skip {
126-
skipCertValidationOnce.Do(func() {
127-
if t, ok := http.DefaultTransport.(*http.Transport); ok {
128-
t = t.Clone()
129-
if t.TLSClientConfig == nil {
130-
t.TLSClientConfig = &tls.Config{}
131-
}
132-
t.TLSClientConfig.InsecureSkipVerify = true
133-
skipCertValidationClient = &http.Client{Transport: t}
134-
} else {
135-
logger.Info("can't configure client for disable cert certification")
136-
skipCertValidationClient = &http.Client{}
137-
}
138-
})
139-
140-
c.httpClient = skipCertValidationClient
141-
} else {
142-
c.httpClient = http.DefaultClient
125+
t := c.httpClient.Transport.(*http.Transport)
126+
if t.TLSClientConfig == nil {
127+
t.TLSClientConfig = &tls.Config{}
128+
}
129+
t.TLSClientConfig.InsecureSkipVerify = true
130+
}
131+
}
132+
}
133+
134+
func Proxy(proxyURL string) Option {
135+
return func(c *dynatraceClient) {
136+
p, err := url.Parse(proxyURL)
137+
if err != nil {
138+
logger.Info("Could not parse proxy URL!")
139+
return
143140
}
141+
t := c.httpClient.Transport.(*http.Transport)
142+
t.Proxy = http.ProxyURL(p)
144143
}
145144
}

0 commit comments

Comments
 (0)