-
Notifications
You must be signed in to change notification settings - Fork 0
/
application_utils.go
346 lines (294 loc) · 12.3 KB
/
application_utils.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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
package application
import (
"context"
"net/http"
"strings"
applicationclient "github.com/equinor/radix-cicd-canary/generated-client/radixapi/client/application"
environmentclient "github.com/equinor/radix-cicd-canary/generated-client/radixapi/client/environment"
apiclient "github.com/equinor/radix-cicd-canary/generated-client/radixapi/client/platform"
"github.com/equinor/radix-cicd-canary/generated-client/radixapi/models"
"github.com/equinor/radix-cicd-canary/scenarios/utils/config"
httpUtils "github.com/equinor/radix-cicd-canary/scenarios/utils/http"
kubeUtils "github.com/equinor/radix-cicd-canary/scenarios/utils/kubernetes"
"github.com/equinor/radix-cicd-canary/scenarios/utils/test"
errors "github.com/pkg/errors"
"github.com/rs/zerolog/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
)
const (
publicDomainNameEnvironmentVariable = "RADIX_PUBLIC_DOMAIN_NAME"
canonicalEndpointEnvironmentVariable = "RADIX_CANONICAL_DOMAIN_NAME"
)
// Register Will register application
func Register(ctx context.Context, cfg config.Config, appName, appRepo, appSharedSecret, appCreator, configBranch, configurationItem string, appAdminGroup string, appReaderGroups []string) (*apiclient.RegisterApplicationOK, error) {
impersonateUser := cfg.GetImpersonateUser()
impersonateGroup := cfg.GetImpersonateGroups()
bodyParameters := models.ApplicationRegistrationRequest{
ApplicationRegistration: &models.ApplicationRegistration{
Name: &appName,
Repository: &appRepo,
SharedSecret: &appSharedSecret,
Creator: &appCreator,
AdGroups: []string{appAdminGroup},
ReaderAdGroups: appReaderGroups,
ConfigBranch: &configBranch,
ConfigurationItem: configurationItem,
},
}
params := apiclient.NewRegisterApplicationParams().
WithImpersonateUser(impersonateUser).
WithImpersonateGroup(impersonateGroup).
WithContext(ctx).
WithApplicationRegistration(&bodyParameters)
client := httpUtils.GetPlatformClient(cfg)
return client.RegisterApplication(params, nil)
}
// DeleteByImpersonatedUser Deletes an application by the impersonated user
func DeleteByImpersonatedUser(ctx context.Context, cfg config.Config, appName string) error {
impersonateUser := cfg.GetImpersonateUser()
impersonateGroup := cfg.GetImpersonateGroups()
log.Ctx(ctx).Debug().Msgf("delete an application %s by the impersonamed user %v, group %s", appName, impersonateUser, *impersonateGroup)
params := applicationclient.NewDeleteApplicationParams().
WithImpersonateUser(impersonateUser).
WithImpersonateGroup(impersonateGroup).
WithContext(ctx).
WithAppName(appName)
return deleteApplication(cfg, appName, params)
}
// DeleteByServiceAccount an application by the service account
func DeleteByServiceAccount(ctx context.Context, cfg config.Config, appName string) error {
err := IsDefined(ctx, cfg, appName)
if err != nil {
return err
}
log.Ctx(ctx).Debug().Msgf("delete an application by the service account: %s", appName)
params := applicationclient.NewDeleteApplicationParams().
WithContext(ctx).
WithAppName(appName)
return deleteApplication(cfg, appName, params)
}
func RegenerateDeployKey(ctx context.Context, cfg config.Config, appName, privateKey, sharedSecret string) error {
impersonateUser := cfg.GetImpersonateUser()
impersonateGroup := cfg.GetImpersonateGroups()
log.Ctx(ctx).Debug().Str("impersonateGroup", *impersonateGroup).Str("impersonateUser", *impersonateUser).Msg("regenerate deploy key for application by the impersonamed user")
params := applicationclient.NewRegenerateDeployKeyParams().
WithImpersonateUser(impersonateUser).
WithImpersonateGroup(impersonateGroup).
WithAppName(appName).
WithRegenerateDeployKeyAndSecretData(&models.RegenerateDeployKeyAndSecretData{
PrivateKey: privateKey,
SharedSecret: sharedSecret,
},
)
client := httpUtils.GetApplicationClient(cfg)
_, err := client.RegenerateDeployKey(params, nil)
if err != nil {
return errors.Wrapf(err, "failed regenerating deploy key for the application %s", appName)
}
return nil
}
func HasDeployKey(ctx context.Context, cfg config.Config, appName, expectedDeployKey string) error {
actualDeployKey, err := GetDeployKey(ctx, cfg, appName)
if err != nil {
return err
}
if strings.TrimSpace(expectedDeployKey) != strings.TrimSpace(actualDeployKey) {
return errors.Errorf("application %s does not have the expected deploy key", appName)
}
return nil
}
func IsDeployKeyDefined(ctx context.Context, cfg config.Config, appName string) error {
actualDeployKey, err := GetDeployKey(ctx, cfg, appName)
if err != nil {
return err
}
if strings.TrimSpace(actualDeployKey) == "" {
return errors.Errorf("deploy key for application %s is not defined", appName)
}
return nil
}
func GetDeployKey(ctx context.Context, cfg config.Config, appName string) (string, error) {
impersonateUser := cfg.GetImpersonateUser()
impersonateGroup := cfg.GetImpersonateGroups()
log.Ctx(ctx).Debug().Str("impersonateGroup", *impersonateGroup).Str("impersonateUser", *impersonateUser).Msg("get deploy key for application by the impersonated user")
params := applicationclient.NewGetDeployKeyAndSecretParams().
WithImpersonateUser(impersonateUser).
WithImpersonateGroup(impersonateGroup).
WithContext(ctx).
WithAppName(appName)
client := httpUtils.GetApplicationClient(cfg)
response, err := client.GetDeployKeyAndSecret(params, nil)
if err != nil {
return "", errors.Wrapf(err, "failed getting deploy key for the application %s", appName)
}
return *response.Payload.PublicDeployKey, nil
}
func deleteApplication(cfg config.Config, appName string, params *applicationclient.DeleteApplicationParams) error {
client := httpUtils.GetApplicationClient(cfg)
_, err := client.DeleteApplication(params, nil)
if err != nil {
return errors.Wrapf(err, "failed deleting the application %s", appName)
}
return nil
}
// Deploy Deploy application
func Deploy(ctx context.Context, cfg config.Config, appName, toEnvironment string) (*applicationclient.TriggerPipelineDeployOK, error) {
impersonateUser := cfg.GetImpersonateUser()
impersonateGroup := cfg.GetImpersonateGroups()
bodyParameters := models.PipelineParametersDeploy{
ToEnvironment: toEnvironment,
}
params := applicationclient.NewTriggerPipelineDeployParams().
WithImpersonateUser(impersonateUser).
WithImpersonateGroup(impersonateGroup).
WithContext(ctx).
WithAppName(appName).
WithPipelineParametersDeploy(&bodyParameters)
client := httpUtils.GetApplicationClient(cfg)
return client.TriggerPipelineDeploy(params, nil)
}
// IsDefined Checks if application is defined
func IsDefined(ctx context.Context, cfg config.Config, appName string) error {
_, err := Get(ctx, cfg, appName)
if err == nil {
return nil
}
return errors.Errorf("application %s is not defined", appName)
}
func appNamespacesDoNotExist(ctx context.Context, appName string) error {
nsList, err := kubeUtils.GetKubernetesClient().CoreV1().Namespaces().List(ctx, metav1.ListOptions{
LabelSelector: labels.Set{"radix-app": appName}.String(),
})
if err != nil {
return errors.WithStack(err)
}
if len(nsList.Items) > 0 {
return errors.Errorf("there are %d namespaces for the application %s", len(nsList.Items), appName)
}
return nil
}
// DeleteIfExist Delete application if it exists
func DeleteIfExist(ctx context.Context, cfg config.Config, appName string) error {
err := DeleteByServiceAccount(ctx, cfg, appName)
if err != nil {
return nil
}
return test.WaitForCheckFuncOrTimeout(ctx, cfg, func(cfg config.Config, ctx context.Context) error {
return appNamespacesDoNotExist(ctx, appName)
})
}
// Get gets an application by appName
func Get(ctx context.Context, cfg config.Config, appName string) (*models.Application, error) {
params := applicationclient.NewGetApplicationParams().
WithAppName(appName).
WithContext(ctx).
WithImpersonateUser(cfg.GetImpersonateUser()).
WithImpersonateGroup(cfg.GetImpersonateGroups())
client := httpUtils.GetApplicationClient(cfg)
result, err := client.GetApplication(params, nil)
if err != nil {
return nil, errors.WithStack(err)
}
return result.Payload, nil
}
// IsAliasDefined Checks if app alias is defined
func IsAliasDefined(ctx context.Context, cfg config.Config, appName string) error {
appAlias := getAlias(ctx, cfg, appName)
if appAlias != nil {
log.Ctx(ctx).Info().Msgf("App alias for application %s is defined: %s", appName, *appAlias)
return nil
}
log.Ctx(ctx).Info().Msg("App alias for application is not yet defined")
return errors.Errorf("public alias for application %s is not defined", appName)
}
func getAlias(ctx context.Context, cfg config.Config, appName string) *string {
impersonateUser := cfg.GetImpersonateUser()
impersonateGroup := cfg.GetImpersonateGroups()
params := applicationclient.NewGetApplicationParams().
WithAppName(appName).
WithContext(ctx).
WithImpersonateUser(impersonateUser).
WithImpersonateGroup(impersonateGroup)
client := httpUtils.GetApplicationClient(cfg)
applicationDetails, err := client.GetApplication(params, nil)
if err == nil && applicationDetails.Payload != nil && applicationDetails.Payload.AppAlias != nil {
return applicationDetails.Payload.AppAlias.URL
}
return nil
}
// IsRunningInActiveCluster Check if app is running in active cluster
func IsRunningInActiveCluster(publicDomainName, canonicalDomainName string) bool {
return !strings.EqualFold(publicDomainName, canonicalDomainName)
}
// TryGetPublicDomainName Waits for public domain name to be defined
func TryGetPublicDomainName(ctx context.Context, cfg config.Config, appName, environmentName, componentName string) (string, error) {
publicDomainName := getEnvVariable(ctx, cfg, appName, environmentName, componentName, publicDomainNameEnvironmentVariable)
if publicDomainName == "" {
return "", errors.Errorf("public domain name variable for application %s, component %s in environment %s is empty", appName, componentName, environmentName)
}
return publicDomainName, nil
}
// TryGetCanonicalDomainName Waits for canonical domain name to be defined
func TryGetCanonicalDomainName(ctx context.Context, cfg config.Config, appName, environmentName, componentName string) (string, error) {
canonicalDomainName := getEnvVariable(ctx, cfg, appName, environmentName, componentName, canonicalEndpointEnvironmentVariable)
if canonicalDomainName == "" {
return "", errors.Errorf("canonical domain name variable for application %s, component %s in environment %s is empty", appName, componentName, environmentName)
}
return canonicalDomainName, nil
}
func getEnvVariable(ctx context.Context, cfg config.Config, appName, envName, forComponentName, variableName string) string {
impersonateUser := cfg.GetImpersonateUser()
impersonateGroup := cfg.GetImpersonateGroups()
params := environmentclient.NewGetEnvironmentParams().
WithAppName(appName).
WithEnvName(envName).
WithContext(ctx).
WithImpersonateUser(impersonateUser).
WithImpersonateGroup(impersonateGroup)
client := httpUtils.GetEnvironmentClient(cfg)
environmentDetails, err := client.GetEnvironment(params, nil)
if err == nil &&
environmentDetails.Payload != nil &&
environmentDetails.Payload.ActiveDeployment != nil {
for _, component := range environmentDetails.Payload.ActiveDeployment.Components {
componentName := *component.Name
if componentName == forComponentName {
return component.Variables[variableName]
}
}
}
return ""
}
// AreResponding Checks if all endpoint responds
func AreResponding(ctx context.Context, urls ...string) error {
for _, url := range urls {
responded := IsResponding(ctx, url)
if !responded {
return errors.New("not all endpoints respond")
}
}
return nil
}
// IsResponding Checks if endpoint is responding
func IsResponding(ctx context.Context, url string) bool {
req := httpUtils.CreateRequest(url, "GET", nil)
client := http.DefaultClient
resp, err := client.Do(req)
logger := log.Ctx(ctx)
if err == nil && resp.StatusCode == 200 {
logger.Info().Msg("App alias responded ok")
return true
}
if err != nil {
logger.Debug().Msgf("Failed request to %s with the alias: %v", url, err)
}
if resp != nil {
logger.Debug().Msgf("Request to alias '%s' returned status %v", url, resp.StatusCode)
}
if err == nil && resp == nil {
logger.Debug().Msgf("Request to alias returned, no response and no err: %s", url)
}
logger.Info().Msgf("Alias is still not responding: %s", url)
return false
}