-
Notifications
You must be signed in to change notification settings - Fork 70
/
transform.go
190 lines (177 loc) · 5.97 KB
/
transform.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package expose_ingress
import (
"context"
"errors"
"fmt"
"github.com/armory/spinnaker-operator/pkg/apis/spinnaker/interfaces"
"github.com/armory/spinnaker-operator/pkg/deploy/spindeploy/transformer"
"github.com/armory/spinnaker-operator/pkg/generated"
"github.com/armory/spinnaker-operator/pkg/inspect"
"github.com/armory/spinnaker-operator/pkg/util"
"github.com/go-logr/logr"
v1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"net/url"
"sigs.k8s.io/controller-runtime/pkg/client"
)
type TransformerGenerator struct{}
func (tg *TransformerGenerator) NewTransformer(svc interfaces.SpinnakerService,
client client.Client, log logr.Logger, scheme *runtime.Scheme) (transformer.Transformer, error) {
tr := ingressTransformer{svc: svc, log: log, client: client, scheme: scheme}
return &tr, nil
}
func (tg *TransformerGenerator) GetName() string {
return "ExposeAsIngress"
}
type ingressTransformer struct {
svc interfaces.SpinnakerService
log logr.Logger
client client.Client
scheme *runtime.Scheme
ing *ingressExplorer
// If Gate's path needs to be overridden
gatePathOverride string
}
func (t *ingressTransformer) TransformManifests(ctx context.Context, gen *generated.SpinnakerGeneratedConfig) error {
if !applies(t.svc) {
return nil
}
// If we need to override gate's path
if t.gatePathOverride != "" {
if err := t.setGateServerPathInDeployment(
t.gatePathOverride,
int(guessGatePort(ctx, t.svc)),
gen.Config["gate"].Deployment); err != nil {
return err
}
}
return nil
}
func (t *ingressTransformer) TransformConfig(ctx context.Context) error {
t.log.V(5).Info(fmt.Sprintf("applying ingress transform: %s", t.svc.GetExposeConfig().Type))
if !applies(t.svc) {
return nil
}
st := t.svc.GetStatus()
gateUrl, err := t.getUrlFromConfig(ctx, util.GateOverrideBaseUrlProp)
if err != nil {
return fmt.Errorf("error checking ingress URL Gate prop: %v", err)
}
// We only act when the URL has not been explicitly set by the user
if gateUrl == nil {
gateUrl, err = t.findUrlInIngress(ctx, util.GateServiceName, guessGatePort(ctx, t.svc))
// Look for the URL in ingress
if err != nil {
return err
}
if gateUrl != nil {
t.log.Info(fmt.Sprintf("setting gate overrideBaseUrl to %s", gateUrl.String()))
if err = t.svc.GetSpinnakerConfig().SetHalConfigProp(util.GateOverrideBaseUrlProp, gateUrl.String()); err != nil {
return err
}
if gateUrl.Path != "" && gateUrl.Path != "/" {
t.gatePathOverride = gateUrl.Path
if err := t.setGatePathInConfig(gateUrl.Path); err != nil {
return err
}
}
st.APIUrl = gateUrl.String()
}
}
// We only act when the URL has not been explicitly set by the user
deckUrl, err := t.getUrlFromConfig(ctx, util.DeckOverrideBaseUrlProp)
if err != nil {
return fmt.Errorf("error checking ingress URL Deck prop: %v", err)
}
if deckUrl == nil {
// Look for the URL in ingress
deckUrl, err = t.findUrlInIngress(ctx, util.DeckServiceName, util.DeckDefaultPort)
if err != nil {
return err
}
if deckUrl != nil {
t.log.Info(fmt.Sprintf("setting deck overrideBaseUrl to %s", deckUrl.String()))
if err = t.svc.GetSpinnakerConfig().SetHalConfigProp(util.DeckOverrideBaseUrlProp, deckUrl.String()); err != nil {
return err
}
st.UIUrl = deckUrl.String()
return nil
}
}
return nil
}
func (t *ingressTransformer) getUrlFromConfig(ctx context.Context, overrideUrlSetting string) (*url.URL, error) {
// ignore error, overrideBaseUrl may not be set in hal config
statusUrl, err := t.svc.GetSpinnakerConfig().GetHalConfigPropString(ctx, overrideUrlSetting)
if statusUrl == "" || err != nil {
// Ignore error
return nil, nil
}
return url.Parse(statusUrl)
}
func (t *ingressTransformer) findUrlInIngress(ctx context.Context, serviceName string, servicePort int32) (*url.URL, error) {
if t.ing == nil {
ing := &ingressExplorer{
log: t.log,
client: t.client,
scheme: t.scheme,
}
// Load ingresses in target namespace
if err := ing.loadIngresses(ctx, t.svc.GetNamespace()); err != nil {
return nil, err
}
t.ing = ing
}
t.log.V(5).Info(fmt.Sprintf("looking for service %s ingress in %d / %dingresses retrieved", serviceName, len(t.ing.extensionIngresses), len(t.ing.networkingIngresses)))
// Try to determine URL from ingress
return t.ing.getIngressUrl(serviceName, servicePort), nil
}
// setGateServerPathInDeployment overrides the readiness probe if set to exec.
// Otherwise it will assume the readiness probe was overridden by the user and not change it.
func (t *ingressTransformer) setGateServerPathInDeployment(newPath string, port int, deploy *v1.Deployment) error {
if deploy == nil {
return nil
}
c := util.GetContainerInDeployment(deploy, "gate")
if c == nil {
return errors.New("unknown gate deployment in generated manifest")
}
if c.ReadinessProbe == nil || c.ReadinessProbe.Exec != nil {
t.log.Info(fmt.Sprintf("overriding readiness probe with http get to %s on port %d", newPath, port))
c.ReadinessProbe = &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: newPath,
Port: intstr.FromInt(port),
},
},
}
}
return nil
}
func (t *ingressTransformer) setGatePathInConfig(newPath string) error {
t.log.Info("setting gate path", "path", newPath)
profile := t.svc.GetSpinnakerConfig().Profiles["gate"]
if profile == nil {
profile = interfaces.FreeForm{}
}
props := map[string]string{
"server.servlet.contextPath": newPath,
"server.tomcat.protocolHeader": "X-Forwarded-Proto",
"server.tomcat.remoteIpHeader": "X-Forwarded-For",
"server.tomcat.internalProxies": ".*",
"server.tomcat.httpsServerPort": "X-Forwarded-Port",
}
for k, p := range props {
if err := inspect.SetObjectProp(profile, k, p); err != nil {
return err
}
}
if t.svc.GetSpinnakerConfig().Profiles == nil {
t.svc.GetSpinnakerConfig().Profiles = make(map[string]interfaces.FreeForm)
}
t.svc.GetSpinnakerConfig().Profiles["gate"] = profile
return nil
}