From 984a8cba603cf954fb21c089a9c013e49347634d Mon Sep 17 00:00:00 2001 From: pape Date: Mon, 28 Oct 2024 14:48:25 +0100 Subject: [PATCH 1/3] :hammer: fix blackWhiteList feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sans ce changement les nouveaux projects ne sont jamais créés si au moins un projet est présent dans le blacklist et que la fonctionnalité whitelist n'est pas activée --- internal/services/provisionner.go | 32 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/internal/services/provisionner.go b/internal/services/provisionner.go index 14f90eed..4112fefd 100644 --- a/internal/services/provisionner.go +++ b/internal/services/provisionner.go @@ -71,25 +71,23 @@ func GenerateProjects(context []*types.Project, blackWhiteList *types.BlackWhite for _, auth := range context { - // if whitelist boolean set we search namespace in configmap whitelist - if utils.Config.Whitelist { // if configmap with whitelist exist and not empty - if blackWhiteList.Whitelist[0] != "" && utils.Include(blackWhiteList.Whitelist, auth.Namespace()) { - utils.Log.Info().Msgf("Project %s is whitelisted", auth.Namespace()) - generateProject(auth) - } else { - utils.Log.Error().Msgf("Cannot find project %s in whitelist", auth.Namespace()) - } - } else if blackWhiteList.Blacklist[0] != "" { // if configmap with blacklist exist and not empty - if utils.Include(blackWhiteList.Blacklist, auth.Namespace()) { - utils.Log.Info().Msgf("delete project %s in blacklist", auth.Namespace()) - deleteProject(auth) - } else { - utils.Log.Info().Msgf("Cannot find project %s in blacklist", auth.Namespace()) - } - } else { // if configmap not exist and bool whitelist is false + switch { + //we treat blacklisted projects as a priority + case blackWhiteList.Blacklist[0] != "" && utils.Include(blackWhiteList.Blacklist, auth.Namespace()): + utils.Log.Info().Msgf("delete project %s in blacklist", auth.Namespace()) + deleteProject(auth) + continue + // If whitelist is enabled, do not create project unless it's explictly mentioned + case utils.Config.Whitelist == true && utils.Include(blackWhiteList.Whitelist, auth.Namespace()): + utils.Log.Info().Msgf("Project %s is whitelisted", auth.Namespace()) + generateProject(auth) + //do not generate project if whitelist is enabled and project not present on whitelisted projects + case utils.Config.Whitelist == true && !utils.Include(blackWhiteList.Whitelist, auth.Namespace()): + utils.Log.Error().Msgf("Cannot find project %s in whitelist", auth.Namespace()) + //Generate projects if whitelist is disabled and no projects in blacklist + default: generateProject(auth) } - } } From dd1868d875b46afe422111e991e62c018b652ff0 Mon Sep 17 00:00:00 2001 From: pape Date: Tue, 5 Nov 2024 23:55:51 +0100 Subject: [PATCH 2/3] :hammer: make the function GenerateProjects easily testable --- internal/services/provisionner.go | 35 +++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/internal/services/provisionner.go b/internal/services/provisionner.go index 4112fefd..53dd0a97 100644 --- a/internal/services/provisionner.go +++ b/internal/services/provisionner.go @@ -61,34 +61,47 @@ func GenerateResources() error { blackWhiteList = MakeBlackWhitelist(blacklistCM.Data) } - GenerateProjects(auths, &blackWhiteList) + createdproject, deletedprojects, ignoredProjects := GenerateProjects(auths, &blackWhiteList) + for _, project := range ignoredProjects { + utils.Log.Error().Msgf("Cannot find project %s in whitelist", project.Namespace()) + } + for _, project := range deletedprojects { + utils.Log.Info().Msgf("delete project %s in blacklist", project.Namespace()) + deleteProject(project) + } + // now that the project is well categorized we know that a project cannot be at the same time to be deleted and to be generated + for _, project := range createdproject { + utils.Log.Info().Msgf("Project %s is whitelisted", project.Namespace()) + generateProject(project) + } return nil } // A loop wrapper for generateProject // splitted for unit test ! -func GenerateProjects(context []*types.Project, blackWhiteList *types.BlackWhitelist) { +func GenerateProjects(context []*types.Project, blackWhiteList *types.BlackWhitelist) ([]*types.Project, []*types.Project, []*types.Project) { + var createdProjects, deletedProjects, ignoredProjects []*types.Project for _, auth := range context { switch { - //we treat blacklisted projects as a priority + //we treat blacklisted projects as a priority, project will be deleted case blackWhiteList.Blacklist[0] != "" && utils.Include(blackWhiteList.Blacklist, auth.Namespace()): - utils.Log.Info().Msgf("delete project %s in blacklist", auth.Namespace()) - deleteProject(auth) + deletedProjects = append(deletedProjects,auth) continue // If whitelist is enabled, do not create project unless it's explictly mentioned case utils.Config.Whitelist == true && utils.Include(blackWhiteList.Whitelist, auth.Namespace()): - utils.Log.Info().Msgf("Project %s is whitelisted", auth.Namespace()) - generateProject(auth) - //do not generate project if whitelist is enabled and project not present on whitelisted projects + createdProjects = append(createdProjects,auth) + //project will be ignored if whitelist is enabled and project not present on whitelisted projects case utils.Config.Whitelist == true && !utils.Include(blackWhiteList.Whitelist, auth.Namespace()): - utils.Log.Error().Msgf("Cannot find project %s in whitelist", auth.Namespace()) - //Generate projects if whitelist is disabled and no projects in blacklist + ignoredProjects = append(ignoredProjects,auth) + //project will be created if whitelist is disabled and no projects in blacklist default: - generateProject(auth) + createdProjects = append(createdProjects,auth) } } + + return createdProjects, deletedProjects, ignoredProjects } // generate a project config or update it if exists From c7d1fa2d39546d666f4495939a26f7bcbdeab656 Mon Sep 17 00:00:00 2001 From: "DIEYE Pape Mademba (CA-GIP)" Date: Thu, 14 Nov 2024 16:11:33 +0100 Subject: [PATCH 3/3] :hammer: adapt unit test for more flexibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vu que nous avons adapter la fonction sur le précédent commit pour qu'il soit mieux testable, nous modifions ici les tests unitaires de la fonctions GenerateProject --- internal/services/blackwhitelist_test.go | 281 ++++++++++++++++------- 1 file changed, 199 insertions(+), 82 deletions(-) diff --git a/internal/services/blackwhitelist_test.go b/internal/services/blackwhitelist_test.go index ff8996cd..013b7dfe 100644 --- a/internal/services/blackwhitelist_test.go +++ b/internal/services/blackwhitelist_test.go @@ -1,10 +1,8 @@ -package services_test +package services import ( "encoding/json" "testing" - - "github.com/ca-gip/kubi/internal/services" "github.com/ca-gip/kubi/internal/utils" v12 "github.com/ca-gip/kubi/pkg/apis/cagip/v1" "github.com/ca-gip/kubi/pkg/types" @@ -42,7 +40,7 @@ func TestBlackWhiteList(t *testing.T) { t.Run("with_nil_object", func(t *testing.T) { - result := services.MakeBlackWhitelist(nil) + result := MakeBlackWhitelist(nil) assert.Equal(t, []string([]string{""}), result.Blacklist) assert.Equal(t, []string([]string{""}), result.Whitelist) }) @@ -50,7 +48,7 @@ func TestBlackWhiteList(t *testing.T) { t.Run("with_empty_map", func(t *testing.T) { blackWhitelistData := map[string]string{} - result := services.MakeBlackWhitelist(blackWhitelistData) + result := MakeBlackWhitelist(blackWhitelistData) assert.Equal(t, []string([]string{""}), result.Blacklist) assert.Equal(t, []string([]string{""}), result.Whitelist) }) @@ -61,7 +59,7 @@ func TestBlackWhiteList(t *testing.T) { "dzadz$Ùdzadza": "fefezfez, 6z556/*/R/ÉR*/", } - result := services.MakeBlackWhitelist(blackWhitelistData) + result := MakeBlackWhitelist(blackWhitelistData) assert.Equal(t, []string([]string{""}), result.Blacklist) assert.Equal(t, []string([]string{""}), result.Whitelist) }) @@ -72,7 +70,7 @@ func TestBlackWhiteList(t *testing.T) { "whitelist": "", } - result := services.MakeBlackWhitelist(blackWhitelistData) + result := MakeBlackWhitelist(blackWhitelistData) assert.Equal(t, []string([]string{"native-developpement", " native-integration"}), result.Blacklist) assert.Equal(t, []string([]string{""}), result.Whitelist) }) @@ -86,151 +84,270 @@ func TestGenerateProjects(t *testing.T) { Project: "native", Environment: "development", }, + { + Project: "native", + Environment: "integration", + }, + { + Project: "native", + Environment: "production", + }, } + + //WHITELIST - t.Run("with_empty_whitelist", func(t *testing.T) { + t.Run("blacklisted projects are deleted and no whithelisted projects are ignored", func(t *testing.T) { blackWhitelistData := map[string]string{ "blacklist": "native-development,native-integration", "whitelist": "", } + expectedCreate := []*types.Project{ + } + expectedDelete := []*types.Project{ + { + Project: "native", + Environment: "development", + }, + { + Project: "native", + Environment: "integration", + }, + } + expectedIgnore := []*types.Project{ + { + Project: "native", + Environment: "production", + }, + } - blackWhitelist := services.MakeBlackWhitelist(blackWhitelistData) + blackWhitelist := MakeBlackWhitelist(blackWhitelistData) utils.Config = &types.Config{Whitelist: true} - result := GenerateProjects(fakeProject, &blackWhitelist) - assert.Equal(t, []bool{false}, result) + gotCreated,gotDeleted,gotIgnored := GenerateProjects(fakeProject, &blackWhitelist) + assert.ElementsMatch(t,gotCreated,expectedCreate, "the expected create projects match created list ") + assert.ElementsMatch(t,gotDeleted,expectedDelete, "the expected delete projects match deleted list ") + assert.ElementsMatch(t,gotIgnored,expectedIgnore, "the expected ignore projects match ignored list") }) - t.Run("with_equal_whitelist", func(t *testing.T) { + t.Run("blacklist takes priority and no whitlisted projects are ignored", func(t *testing.T) { blackWhitelistData := map[string]string{ "blacklist": "native-development,native-integration", "whitelist": "native-development", } - blackWhitelist := services.MakeBlackWhitelist(blackWhitelistData) + expectedCreate := []*types.Project{ + } + + expectedDelete := []*types.Project{ + { + Project: "native", + Environment: "development", + }, + { + Project: "native", + Environment: "integration", + }, + } + + expectedIgnore := []*types.Project{ + { + Project: "native", + Environment: "production", + }, + } + blackWhitelist := MakeBlackWhitelist(blackWhitelistData) utils.Config = &types.Config{Whitelist: true} - result := GenerateProjects(fakeProject, &blackWhitelist) - assert.Equal(t, []bool{true}, result) + gotCreated,gotDeleted,gotIgnored := GenerateProjects(fakeProject, &blackWhitelist) + assert.ElementsMatch(t,gotCreated,expectedCreate, "the expected create projects match created list ") + assert.ElementsMatch(t,gotDeleted,expectedDelete, "the expected delete projects match deleted list ") + assert.ElementsMatch(t,gotIgnored,expectedIgnore, "the expected ignore projects match ignored list") }) - t.Run("with_not_equal_whitelist", func(t *testing.T) { + t.Run("no project is created unless explicitly defined in whitelist; blacklisted projects are deleted", func(t *testing.T) { blackWhitelistData := map[string]string{ "blacklist": "native-development,native-integration", - "whitelist": "native-divelopment", + "whitelist": "native-production", + } + + expectedCreate := []*types.Project{ + { + Project: "native", + Environment: "production", + }, + } + + expectedDelete := []*types.Project{ + { + Project: "native", + Environment: "development", + }, + { + Project: "native", + Environment: "integration", + }, + } + + expectedIgnore := []*types.Project{ } - blackWhitelist := services.MakeBlackWhitelist(blackWhitelistData) + blackWhitelist := MakeBlackWhitelist(blackWhitelistData) utils.Config = &types.Config{Whitelist: true} - result := GenerateProjects(fakeProject, &blackWhitelist) - assert.Equal(t, []bool{false}, result) + gotCreated,gotDeleted,gotIgnored := GenerateProjects(fakeProject, &blackWhitelist) + assert.ElementsMatch(t,gotCreated,expectedCreate, "the expected create projects match created list ") + assert.ElementsMatch(t,gotDeleted,expectedDelete, "the expected delete projects match deleted list ") + assert.ElementsMatch(t,gotIgnored,expectedIgnore, "the expected ignore projects match ignored list") }) - t.Run("with_faildata_whitelist", func(t *testing.T) { + t.Run("ignore all projects if confimap contains invalid data", func(t *testing.T) { blackWhitelistData := map[string]string{ "blaaeza": "rrzerzF", } - blackWhitelist := services.MakeBlackWhitelist(blackWhitelistData) + expectedCreate := []*types.Project{ + } + + expectedDelete := []*types.Project{ + } + + expectedIgnore := []*types.Project{ + { + Project: "native", + Environment: "development", + }, + { + Project: "native", + Environment: "integration", + }, + { + Project: "native", + Environment: "production", + }, + } + blackWhitelist := MakeBlackWhitelist(blackWhitelistData) utils.Config = &types.Config{Whitelist: true} - result := GenerateProjects(fakeProject, &blackWhitelist) - assert.Equal(t, []bool{false}, result) + gotCreated,gotDeleted,gotIgnored := GenerateProjects(fakeProject, &blackWhitelist) + assert.ElementsMatch(t,gotCreated,expectedCreate, "the expected create projects match created list ") + assert.ElementsMatch(t,gotDeleted,expectedDelete, "the expected delete projects match deleted list ") + assert.ElementsMatch(t,gotIgnored,expectedIgnore, "the expected ignore projects match ignored list") }) //BLACKLIST - t.Run("with_empty_blacklist", func(t *testing.T) { + t.Run("Projects are created unless explicitly blacklisted", func(t *testing.T) { blackWhitelistData := map[string]string{ "blacklist": "", "whitelist": "native-development", } - blackWhitelist := services.MakeBlackWhitelist(blackWhitelistData) - - utils.Config = &types.Config{Whitelist: false} - result := GenerateProjects(fakeProject, &blackWhitelist) - assert.Equal(t, []bool{false}, result) - }) + expectedCreate := []*types.Project{ + { + Project: "native", + Environment: "development", + }, + { + Project: "native", + Environment: "integration", + }, + { + Project: "native", + Environment: "production", + }, + } - t.Run("with_equal_blacklist", func(t *testing.T) { + expectedDelete := []*types.Project{ + } - blackWhitelistData := map[string]string{ - "blacklist": "native-development,native-integration", - "whitelist": "native-development", + expectedIgnore := []*types.Project{ } - blackWhitelist := services.MakeBlackWhitelist(blackWhitelistData) + blackWhitelist := MakeBlackWhitelist(blackWhitelistData) utils.Config = &types.Config{Whitelist: false} - result := GenerateProjects(fakeProject, &blackWhitelist) - assert.Equal(t, []bool{true}, result) + gotCreated,gotDeleted,gotIgnored := GenerateProjects(fakeProject, &blackWhitelist) + assert.ElementsMatch(t,gotCreated,expectedCreate, "the expected create projects match created list ") + assert.ElementsMatch(t,gotDeleted,expectedDelete, "the expected delete projects match deleted list ") + assert.ElementsMatch(t,gotIgnored,expectedIgnore, "the expected ignore projects match ignored list") }) - t.Run("with_not_equal_blacklist", func(t *testing.T) { + + + t.Run("project don't require whitelisting to be created", func(t *testing.T) { blackWhitelistData := map[string]string{ - "blacklist": "native-devilopment,native-integration", - "whitelist": "native-divelopment", + "blacklist": "native-development,native-integration", + "whitelist": "", + } + expectedCreate := []*types.Project{ + { + Project: "native", + Environment: "production", + }, } - blackWhitelist := services.MakeBlackWhitelist(blackWhitelistData) + expectedDelete := []*types.Project{ + { + Project: "native", + Environment: "development", + }, + { + Project: "native", + Environment: "integration", + }, + } + + expectedIgnore := []*types.Project{ + } + + blackWhitelist := MakeBlackWhitelist(blackWhitelistData) utils.Config = &types.Config{Whitelist: false} - result := GenerateProjects(fakeProject, &blackWhitelist) - assert.Equal(t, []bool{false}, result) + gotCreated,gotDeleted,gotIgnored := GenerateProjects(fakeProject, &blackWhitelist) + assert.ElementsMatch(t,gotCreated,expectedCreate, "the expected create projects match created list ") + assert.ElementsMatch(t,gotDeleted,expectedDelete, "the expected delete projects match deleted list ") + assert.ElementsMatch(t,gotIgnored,expectedIgnore, "the expected ignore projects match ignored list") }) - t.Run("with_faildata_blacklist", func(t *testing.T) { + t.Run("all projects are created if confimap contains invalid data", func(t *testing.T) { blackWhitelistData := map[string]string{ "blaaeza": "rrzerzF", } + expectedCreate := []*types.Project{ + { + Project: "native", + Environment: "development", + }, + { + Project: "native", + Environment: "integration", + }, + { + Project: "native", + Environment: "production", + }, + } - blackWhitelist := services.MakeBlackWhitelist(blackWhitelistData) - - utils.Config = &types.Config{Whitelist: false} - result := GenerateProjects(fakeProject, &blackWhitelist) - assert.Equal(t, []bool{false}, result) - }) - -} + expectedDelete := []*types.Project{ + } -// Mock of GenerateProjects func from provisionner. TODO : refacto to be testable -func GenerateProjects(context []*types.Project, blackWhiteList *types.BlackWhitelist) []bool { - - var boolList []bool - - for _, auth := range context { - - // if whitelist boolean set we search namespace in configmap whitelist - if utils.Config.Whitelist { // if configmap with whitelist exist and not empty - if blackWhiteList.Whitelist[0] != "" && utils.Include(blackWhiteList.Whitelist, auth.Namespace()) { - utils.Log.Info().Msgf("Project %s is whitelisted", auth.Namespace()) - boolList = append(boolList, true) - } else { - utils.Log.Error().Msgf("Cannot find project %s in whitelist", auth.Namespace()) - boolList = append(boolList, false) - } - } else if blackWhiteList.Blacklist[0] != "" { // if configmap with blacklist exist and not empty - if utils.Include(blackWhiteList.Blacklist, auth.Namespace()) { - utils.Log.Info().Msgf("delete project %s in blacklist", auth.Namespace()) - boolList = append(boolList, true) - } else { - utils.Log.Info().Msgf("Cannot find project %s in blacklist", auth.Namespace()) - boolList = append(boolList, false) - } - } else { // if configmap not exist and bool whitelist is false - boolList = append(boolList, false) + expectedIgnore := []*types.Project{ } - } + blackWhitelist := MakeBlackWhitelist(blackWhitelistData) - return boolList -} + utils.Config = &types.Config{Whitelist: false} + gotCreated,gotDeleted,gotIgnored := GenerateProjects(fakeProject, &blackWhitelist) + assert.ElementsMatch(t,gotCreated,expectedCreate, "the expected create projects match created list ") + assert.ElementsMatch(t,gotDeleted,expectedDelete, "the expected delete projects match deleted list ") + assert.ElementsMatch(t,gotIgnored,expectedIgnore, "the expected ignore projects match ignored list") + }) + +} \ No newline at end of file