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

Commit a12152c

Browse files
committed
fix(#730): delete objects that are removed from templates
1 parent ca11d43 commit a12152c

12 files changed

Lines changed: 872 additions & 142 deletions

environment/service.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ func NewService() *Service {
8888
return &Service{}
8989
}
9090

91+
func NewServiceForBlob(templatesRepoBlob string) *Service {
92+
return &Service{templatesRepoBlob: templatesRepoBlob}
93+
}
94+
9195
func NewServiceForUserData(user *authclient.UserDataAttributes) *Service {
9296
service := NewService()
9397
if user != nil {
@@ -170,10 +174,16 @@ func (s *Service) retrieveTemplates(tmpls []*Template) error {
170174
)
171175
for _, template := range tmpls {
172176
if s.templatesRepoBlob != "" {
173-
fileURL := fmt.Sprintf(rawFileURLTemplate, s.getRepo(), s.templatesRepoBlob, s.getPath(template))
177+
commit, commitQuotas := getVersions(s.templatesRepoBlob)
178+
template.DefaultParams[varCommit] = commit
179+
template.DefaultParams[varCommitQuotas] = commitQuotas
180+
template.Version = commit
181+
if strings.Contains(template.Filename, "quotas") {
182+
template.Version = commitQuotas
183+
}
184+
185+
fileURL := fmt.Sprintf(rawFileURLTemplate, s.getRepo(), template.Version, s.getPath(template))
174186
content, err = utils.DownloadFile(fileURL)
175-
template.DefaultParams[varCommit] = s.templatesRepoBlob
176-
template.DefaultParams[varCommitQuotas] = s.templatesRepoBlob
177187
} else {
178188
content, err = templates.Asset(template.Filename)
179189
}
@@ -185,6 +195,16 @@ func (s *Service) retrieveTemplates(tmpls []*Template) error {
185195
return nil
186196
}
187197

198+
func getVersions(blob string) (string, string) {
199+
if strings.Contains(blob, "_") {
200+
splitVersion := strings.Split(blob, "_")
201+
if len(splitVersion) == 2 {
202+
return splitVersion[0], splitVersion[1]
203+
}
204+
}
205+
return blob, blob
206+
}
207+
188208
func (s *Service) getRepo() string {
189209
repo := strings.TrimSpace(s.templatesRepo)
190210
if repo == "" {

environment/service_test.go

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func XTestDownloadFromExistingLocation(t *testing.T) {
162162
}
163163
}
164164

165-
func TestDownloadFromGivenBlob(t *testing.T) {
165+
func TestDownloadFromGivenBlobSetAsTenantConfig(t *testing.T) {
166166
// given
167167
defer gock.OffAll()
168168
gock.New("https://raw.githubusercontent.com").
@@ -187,6 +187,68 @@ func TestDownloadFromGivenBlob(t *testing.T) {
187187
assert.Equal(t, environment.GetLabelVersion(objects[0]), "987654321")
188188
}
189189

190+
func TestDownloadFromGivenVersion(t *testing.T) {
191+
// given
192+
defer gock.OffAll()
193+
gock.New("https://raw.githubusercontent.com").
194+
Get("fabric8-services/fabric8-tenant/987654321/environment/templates/fabric8-tenant-deploy.yml").
195+
Reply(200).
196+
BodyString(defaultLocationTempl)
197+
testdoubles.SetTemplateVersions()
198+
service := environment.NewServiceForBlob("987654321")
199+
200+
// when
201+
envData, err := service.GetEnvData(context.Background(), environment.TypeRun)
202+
203+
// then
204+
require.NoError(t, err)
205+
vars := map[string]string{
206+
"USER_NAME": "dev",
207+
}
208+
objects, err := envData.Templates[0].Process(vars)
209+
require.NoError(t, err)
210+
assert.Len(t, objects, 1)
211+
assert.Equal(t, "default-location", environment.GetLabel(objects[0], "test"))
212+
assert.Equal(t, "987654321", environment.GetLabelVersion(objects[0]))
213+
}
214+
215+
func TestDownloadFromGivenVersionThatContainsTwoParts(t *testing.T) {
216+
// given
217+
defer gock.OffAll()
218+
gock.New("https://raw.githubusercontent.com").
219+
Get("fabric8-services/fabric8-tenant/98765/environment/templates/fabric8-tenant-che-mt.yml").
220+
Reply(200).
221+
BodyString(customLocationTempl)
222+
gock.New("https://raw.githubusercontent.com").
223+
Get("fabric8-services/fabric8-tenant/4321/environment/templates/fabric8-tenant-che-quotas.yml").
224+
Reply(200).
225+
BodyString(customLocationQuotas)
226+
testdoubles.SetTemplateVersions()
227+
service := environment.NewServiceForBlob("98765_4321")
228+
229+
// when
230+
envData, err := service.GetEnvData(context.Background(), environment.TypeChe)
231+
232+
// then
233+
require.NoError(t, err)
234+
vars := map[string]string{
235+
"USER_NAME": "dev",
236+
}
237+
assert.Len(t, envData.Templates, 2)
238+
objects, err := envData.Templates[0].Process(vars)
239+
require.NoError(t, err)
240+
assert.Len(t, objects, 1)
241+
assert.Equal(t, "custom-location", environment.GetLabel(objects[0], "test"))
242+
assert.Equal(t, "98765", environment.GetLabelVersion(objects[0]))
243+
assert.Equal(t, "4321", environment.GetLabel(objects[0], environment.FieldVersionQuotas))
244+
245+
objects, err = envData.Templates[1].Process(vars)
246+
require.NoError(t, err)
247+
assert.Len(t, objects, 1)
248+
assert.Empty(t, environment.GetLabel(objects[0], environment.FieldVersionQuotas))
249+
assert.Equal(t, environment.GetLabelVersion(objects[0]), "4321")
250+
}
251+
190252
func TestDownloadFromGivenBlobLocatedInCustomLocation(t *testing.T) {
191253
// given
192254
defer gock.OffAll()

openshift/action.go

Lines changed: 75 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package openshift
22

33
import (
4+
"context"
45
"fmt"
56
"github.com/fabric8-services/fabric8-common/log"
67
"github.com/fabric8-services/fabric8-tenant/cluster"
@@ -84,19 +85,21 @@ type commonNamespaceAction struct {
8485
method string
8586
actionOptions *ActionOptions
8687
tenantRepo tenant.Repository
88+
filterFunc FilterFunc
89+
requestCtx context.Context
8790
}
8891

8992
func (c *commonNamespaceAction) MethodName() string {
9093
return c.method
9194
}
9295

93-
func (c *commonNamespaceAction) getOperationSets(envService EnvironmentTypeService, client Client, filterFunc FilterFunc) (*environment.EnvData, []OperationSet, error) {
94-
env, objects, err := envService.GetEnvDataAndObjects(filterFunc)
96+
func (c *commonNamespaceAction) getOperationSets(envService EnvironmentTypeService, client Client) (*EnvAndObjectsManager, []OperationSet, error) {
97+
objectManager, err := envService.GetEnvDataAndObjects()
9598
if err != nil {
96-
return env, nil, errors.Wrap(err, "getting environment data and objects failed")
99+
return objectManager, nil, errors.Wrap(err, "getting environment data and objects failed")
97100
}
98101

99-
operationSets := []OperationSet{NewOperationSet(c.method, objects)}
102+
operationSets := []OperationSet{NewOperationSet(c.method, objectManager.GetObjects(c.filterFunc))}
100103

101104
object, shouldBeAdded := envService.AdditionalObject()
102105
if len(object) > 0 {
@@ -112,13 +115,7 @@ func (c *commonNamespaceAction) getOperationSets(envService EnvironmentTypeServi
112115
}
113116

114117
sort.Sort(environment.ByKind(operationSets[0].Objects))
115-
return env, operationSets, nil
116-
}
117-
118-
func (c *commonNamespaceAction) Filter() FilterFunc {
119-
return func(objects environment.Object) bool {
120-
return true
121-
}
118+
return objectManager, operationSets, nil
122119
}
123120

124121
func (c *commonNamespaceAction) ForceMasterTokenGlobally() bool {
@@ -187,12 +184,17 @@ func (c *CreateAction) HealingStrategy() HealingFuncGenerator {
187184
}
188185
}
189186

190-
func NewCreateAction(tenantRepo tenant.Repository, actionOpts *ActionOptions) *CreateAction {
187+
func NewCreateAction(tenantRepo tenant.Repository, requestCtx context.Context, actionOpts *ActionOptions) *CreateAction {
191188
return &CreateAction{
192189
commonNamespaceAction: &commonNamespaceAction{
193190
method: http.MethodPost,
194191
tenantRepo: tenantRepo,
195-
actionOptions: actionOpts},
192+
actionOptions: actionOpts,
193+
requestCtx: requestCtx,
194+
filterFunc: func(objects environment.Object) bool {
195+
return true
196+
},
197+
},
196198
}
197199
}
198200

@@ -208,13 +210,14 @@ func (c *CreateAction) GetNamespaceEntity(nsTypeService EnvironmentTypeService)
208210

209211
func (c *CreateAction) UpdateNamespace(env *environment.EnvData, cluster *cluster.Cluster, namespace *tenant.Namespace, failed bool) {
210212
state := tenant.Ready
213+
namespace.Version = env.Version()
211214
if failed {
212215
state = tenant.Failed
213216
}
214217
namespace.UpdateData(env, cluster, state)
215218
err := c.tenantRepo.SaveNamespace(namespace)
216219
if err != nil {
217-
sentry.LogError(nil, map[string]interface{}{
220+
sentry.LogError(c.requestCtx, map[string]interface{}{
218221
"env_type": env.EnvType,
219222
"cluster": cluster.APIURL,
220223
"tenant": namespace.TenantID,
@@ -228,16 +231,27 @@ func (c *CreateAction) ForceMasterTokenGlobally() bool {
228231
}
229232

230233
func (c *CreateAction) GetOperationSets(envService EnvironmentTypeService, client Client) (*environment.EnvData, []OperationSet, error) {
231-
return c.getOperationSets(envService, client, c.Filter())
234+
envAndObjectsManager, sets, err := c.getOperationSets(envService, client)
235+
if err != nil {
236+
return nil, sets, err
237+
}
238+
return envAndObjectsManager.EnvData, sets, nil
232239
}
233240

234-
func NewDeleteAction(tenantRepo tenant.Repository, existingNamespaces []*tenant.Namespace, deleteOpts *DeleteActionOption) *DeleteAction {
241+
func NewDeleteAction(tenantRepo tenant.Repository, requestCtx context.Context, existingNamespaces []*tenant.Namespace, deleteOpts *DeleteActionOption) *DeleteAction {
242+
filterFunc := isOfKind(AllKindsToClean...)
243+
if deleteOpts.removeFromCluster {
244+
filterFunc = isOfKind(environment.ValKindProjectRequest)
245+
}
246+
235247
return &DeleteAction{
236248
withExistingNamespacesAction: &withExistingNamespacesAction{
237249
commonNamespaceAction: &commonNamespaceAction{
238250
method: http.MethodDelete,
239251
tenantRepo: tenantRepo,
240252
actionOptions: deleteOpts.ActionOptions,
253+
requestCtx: requestCtx,
254+
filterFunc: filterFunc,
241255
},
242256
existingNamespaces: existingNamespaces,
243257
},
@@ -263,7 +277,7 @@ func (d *DeleteAction) UpdateNamespace(env *environment.EnvData, cluster *cluste
263277
err = d.tenantRepo.DeleteNamespace(namespace)
264278
}
265279
if err != nil {
266-
sentry.LogError(nil, map[string]interface{}{
280+
sentry.LogError(d.requestCtx, map[string]interface{}{
267281
"env_type": env.EnvType,
268282
"cluster": cluster.APIURL,
269283
"tenant": namespace.TenantID,
@@ -273,13 +287,6 @@ func (d *DeleteAction) UpdateNamespace(env *environment.EnvData, cluster *cluste
273287
}
274288
}
275289

276-
func (d *DeleteAction) Filter() FilterFunc {
277-
if d.deleteOptions.removeFromCluster {
278-
return isOfKind(environment.ValKindProjectRequest)
279-
}
280-
return isOfKind(AllKindsToClean...)
281-
}
282-
283290
var AllToDeleteAll = []string{environment.ValKindPod, environment.ValKindReplicationController, environment.ValKindDaemonSet,
284291
environment.ValKindDeployment, environment.ValKindReplicaSet, environment.ValKindStatefulSet, environment.ValKindJob,
285292
environment.ValKindHorizontalPodAutoScaler, environment.ValKindCronJob, environment.ValKindDeploymentConfig,
@@ -291,10 +298,11 @@ var AllToGetAndDelete = []string{environment.ValKindService}
291298
var AllKindsToClean = append(AllToDeleteAll, AllToGetAndDelete...)
292299

293300
func (d *DeleteAction) GetOperationSets(envService EnvironmentTypeService, client Client) (*environment.EnvData, []OperationSet, error) {
294-
env, objectsToDelete, err := envService.GetEnvDataAndObjects(d.Filter())
301+
objectManager, err := envService.GetEnvDataAndObjects()
295302
if err != nil {
296-
return env, nil, errors.Wrap(err, "getting environment data and objects failed")
303+
return objectManager.EnvData, nil, errors.Wrap(err, "getting environment data and objects failed")
297304
}
305+
objectsToDelete := objectManager.GetObjects(d.filterFunc)
298306
var operationSets []OperationSet
299307

300308
if !d.deleteOptions.removeFromCluster {
@@ -310,13 +318,13 @@ func (d *DeleteAction) GetOperationSets(envService EnvironmentTypeService, clien
310318
kindToGet := NewObject(kind, envService.GetNamespaceName(), "")
311319
result, err := Apply(client, http.MethodGet, kindToGet)
312320
if err != nil {
313-
return env, nil, errors.Wrapf(err,
321+
return objectManager.EnvData, nil, errors.Wrapf(err,
314322
"unable to get list of current objects of kind %s in namespace %s", kindToGet, envService.GetNamespaceName())
315323
}
316324
var returnedObj environment.Object
317325
err = yaml.Unmarshal(result.Body, &returnedObj)
318326
if err != nil {
319-
return env, nil, errors.Wrapf(err, "unable unmarshal object responded from OS "+
327+
return objectManager.EnvData, nil, errors.Wrapf(err, "unable unmarshal object responded from OS "+
320328
"while getting list of current objects of kind %s in namespace %s", kindToGet, envService.GetNamespaceName())
321329
}
322330

@@ -338,7 +346,7 @@ func (d *DeleteAction) GetOperationSets(envService EnvironmentTypeService, clien
338346
deleteOpSet := NewOperationSet(d.method, objectsToDelete)
339347
operationSets = append(operationSets, deleteOpSet)
340348

341-
return env, operationSets, nil
349+
return objectManager.EnvData, operationSets, nil
342350
}
343351

344352
func NewObject(kind, namespaceName string, name string) environment.Object {
@@ -399,13 +407,16 @@ func (d *DeleteAction) HealingStrategy() HealingFuncGenerator {
399407
})
400408
}
401409

402-
func NewUpdateAction(tenantRepo tenant.Repository, existingNamespaces []*tenant.Namespace, actionOpts *ActionOptions) *UpdateAction {
410+
func NewUpdateAction(tenantRepo tenant.Repository, requestCtx context.Context, existingNamespaces []*tenant.Namespace, actionOpts *ActionOptions) *UpdateAction {
403411
return &UpdateAction{
404412
withExistingNamespacesAction: &withExistingNamespacesAction{
405413
commonNamespaceAction: &commonNamespaceAction{
406414
method: http.MethodPatch,
407415
tenantRepo: tenantRepo,
408-
actionOptions: actionOpts},
416+
actionOptions: actionOpts,
417+
requestCtx: requestCtx,
418+
filterFunc: isNotOfKind(environment.ValKindProjectRequest),
419+
},
409420
existingNamespaces: existingNamespaces,
410421
},
411422
}
@@ -420,14 +431,15 @@ func (u *UpdateAction) GetNamespaceEntity(nsTypeService EnvironmentTypeService)
420431
}
421432

422433
func (u *UpdateAction) UpdateNamespace(env *environment.EnvData, cluster *cluster.Cluster, namespace *tenant.Namespace, failed bool) {
423-
state := tenant.Ready
424-
if failed {
425-
state = tenant.Failed
434+
state := tenant.Failed
435+
if !failed {
436+
state = tenant.Ready
437+
namespace.Version = env.Version()
426438
}
427439
namespace.UpdateData(env, cluster, state)
428440
err := u.tenantRepo.SaveNamespace(namespace)
429441
if err != nil {
430-
sentry.LogError(nil, map[string]interface{}{
442+
sentry.LogError(u.requestCtx, map[string]interface{}{
431443
"env_type": env.EnvType,
432444
"cluster": cluster.APIURL,
433445
"tenant": namespace.TenantID,
@@ -436,12 +448,35 @@ func (u *UpdateAction) UpdateNamespace(env *environment.EnvData, cluster *cluste
436448
}
437449
}
438450

439-
func (u *UpdateAction) Filter() FilterFunc {
440-
return isNotOfKind(environment.ValKindProjectRequest)
441-
}
442-
443451
func (u *UpdateAction) GetOperationSets(envService EnvironmentTypeService, client Client) (*environment.EnvData, []OperationSet, error) {
444-
return u.getOperationSets(envService, client, u.Filter())
452+
envAndObjectsManager, sets, err := u.getOperationSets(envService, client)
453+
if err != nil {
454+
return envAndObjectsManager.EnvData, sets, err
455+
}
456+
previousVersion := u.getNamespaceFor(envService.GetType()).Version
457+
objectsToDelete, err := envAndObjectsManager.GetMissingObjectsComparingWith(previousVersion)
458+
if err != nil {
459+
sentry.LogError(u.requestCtx, map[string]interface{}{
460+
"env_type": envService.GetType(),
461+
"cluster": client.MasterURL,
462+
"namespace-name": envService.GetNamespaceName(),
463+
"previous-version": previousVersion,
464+
}, err, "unable to retrieve objects that should be removed from the namespace")
465+
return envAndObjectsManager.EnvData, sets, nil
466+
}
467+
if len(objectsToDelete) > 0 {
468+
for index, set := range sets {
469+
if set.Method == http.MethodDelete {
470+
sets[index].Objects = append(sets[index].Objects, objectsToDelete...)
471+
sort.Sort(sort.Reverse(environment.ByKind(sets[index].Objects)))
472+
return envAndObjectsManager.EnvData, sets, nil
473+
}
474+
}
475+
deleteSet := NewOperationSet(http.MethodDelete, objectsToDelete)
476+
sort.Sort(sort.Reverse(environment.ByKind(deleteSet.Objects)))
477+
sets = append(sets, deleteSet)
478+
}
479+
return envAndObjectsManager.EnvData, sets, nil
445480
}
446481

447482
func (u *UpdateAction) HealingStrategy() HealingFuncGenerator {

0 commit comments

Comments
 (0)