diff --git a/api/dashboards.go b/api/dashboards.go index 1f8723ca..e11e3034 100644 --- a/api/dashboards.go +++ b/api/dashboards.go @@ -114,7 +114,7 @@ func (s *DashNGoImpl) ListDashboards(filterReq filters.Filter) []*models.Hit { var orgsPayload []*models.OrgDTO orgList, err := s.client.Orgs.SearchOrgs(orgs.NewSearchOrgsParams(), s.getAdminAuth()) if err != nil { - log.Warnf("Error getting organizations: %s", err.Error()) + log.Warn("Error getting organizations") orgsPayload = make([]*models.OrgDTO, 0) } else { orgsPayload = orgList.GetPayload() diff --git a/api/login.go b/api/login.go index 48a74bea..ebf4e519 100644 --- a/api/login.go +++ b/api/login.go @@ -41,7 +41,8 @@ func (s *DashNGoImpl) Login() { func (s *DashNGoImpl) getAdminAuth() runtime.ClientAuthInfoWriter { if s.grafanaConf.UserName == "" { - log.Fatal("Unable to get Admin Auth. Credentials are missing") + log.Warnf("Unable to get Admin Auth. Basic Auth credentials, continueing with token") + return s.getAuth() } return &gapi.BasicAuthenticator{ Username: s.grafanaConf.UserName, diff --git a/api/user.go b/api/user.go index 8e03da26..be080e3a 100644 --- a/api/user.go +++ b/api/user.go @@ -9,6 +9,7 @@ import ( "github.com/esnet/gdg/config" gapi "github.com/esnet/grafana-swagger-api-golang" "github.com/esnet/grafana-swagger-api-golang/goclient/client/admin_users" + "github.com/esnet/grafana-swagger-api-golang/goclient/client/api_keys" "github.com/esnet/grafana-swagger-api-golang/goclient/client/users" "github.com/esnet/grafana-swagger-api-golang/goclient/models" "github.com/gosimple/slug" @@ -27,6 +28,50 @@ type UsersApi interface { ExportUsers() []models.UserProfileDTO PromoteUser(userLogin string) (string, error) DeleteAllUsers() []string + //TODO: clean up and expose API Keys management via CLI + CreateAdminAPIKey(name string) *models.NewAPIKeyResult + DeleteAPIKey(id int64) error + ClearAPIKeys() error +} + +func (s *DashNGoImpl) ClearAPIKeys() error { + p := api_keys.NewGetAPIkeysParams() + keys, err := s.client.APIKeys.GetAPIkeys(p, s.getAuth()) + if err != nil { + return err + } + for _, key := range keys.GetPayload() { + err := s.DeleteAPIKey(key.ID) + if err != nil { + log.Warnf("Failed to delete API key %d named %s", key.ID, key.Name) + } + } + + return nil +} + +func (s *DashNGoImpl) CreateAdminAPIKey(name string) *models.NewAPIKeyResult { + p := api_keys.NewAddAPIkeyParams() + p.Body = &models.AddCommand{ + Name: name, + Role: "admin", + } + newKey, err := s.client.APIKeys.AddAPIkey(p, s.getAuth()) + if err != nil { + log.Fatal("unable to create a new API Key") + } + return newKey.GetPayload() + +} +func (s *DashNGoImpl) DeleteAPIKey(id int64) error { + p := api_keys.NewDeleteAPIkeyParams() + p.ID = id + _, err := s.client.APIKeys.DeleteAPIkey(p, s.getAuth()) + if err != nil { + return fmt.Errorf("failed to delete API Key: %d", id) + } + return nil + } func DefaultUserPassword(username string) string { diff --git a/documentation/content/en/docs/releases/gdg_0.4.1.md b/documentation/content/en/docs/releases/gdg_0.4.1.md new file mode 100644 index 00000000..8bc84887 --- /dev/null +++ b/documentation/content/en/docs/releases/gdg_0.4.1.md @@ -0,0 +1,22 @@ +--- +title: "0.4.1 DRAFT" +description: "DRAFT Release Notes for v0.4.1" +date: 2023-03-31T15:21:01+02:00 +lastmod: 2020-10-13T15:21:01+02:00 +draft: true +images: [] +weight: 198 +toc: true +--- +# DRAFT: Release Notes for v0.4.1 + + +### New Features + +#### Library Elements Connections + + - Added support for libraryelement connections. This option allows you to see what dashboards are using the given library. + - note: You won't be able to delete the library element while there are dashboards utilizing it. +### Bugs: + - FIXED: Addressing Login issue when Basic Auth is omitted. #144 + diff --git a/integration_tests/cloud_integration_test.go b/integration_tests/cloud_integration_test.go index 707361ce..5f7a9507 100644 --- a/integration_tests/cloud_integration_test.go +++ b/integration_tests/cloud_integration_test.go @@ -12,7 +12,7 @@ func TestCloudDataSourceCRUD(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) //Wipe all data from grafana dsFilter := api.NewDataSourceFilter("") @@ -45,7 +45,7 @@ func TestDashboardCloudCRUD(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) //Wipe all data from grafana dashFilter := api.NewDashboardFilter("", "", "") diff --git a/integration_tests/dashboard_integration_test.go b/integration_tests/dashboard_integration_test.go index 3624b2c7..2177086c 100644 --- a/integration_tests/dashboard_integration_test.go +++ b/integration_tests/dashboard_integration_test.go @@ -4,6 +4,8 @@ import ( "github.com/esnet/gdg/api" "github.com/esnet/gdg/api/filters" "github.com/esnet/grafana-swagger-api-golang/goclient/models" + "gopkg.in/yaml.v3" + "os" "strings" "testing" @@ -17,11 +19,78 @@ import ( // - Add single dashboard test -d <> // - Add Folder dashboard test -f <> +func TestDashboardAPIKeyCRUD(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + //TODO: convert to a token based pattern + apiClient, _ := initTest(t, nil) + testData, _ := os.ReadFile("conf/testing.yml") + data := map[string]interface{}{} + err := yaml.Unmarshal(testData, &data) + assert.Nil(t, err) + + apiClient.ClearAPIKeys() //Remove any old data + newKey := apiClient.CreateAdminAPIKey("testing") + + level1 := data["contexts"].(map[string]interface{}) + level2 := level1["testing"].(map[string]interface{}) + level2["token"] = newKey.Key + level2["user_name"] = "" + level2["password"] = "" + + updatedCfg, err := yaml.Marshal(data) + assert.Nil(t, err) + newCfg := "conf/tokenTest.yml" + err = os.WriteFile(newCfg, updatedCfg, 0644) + assert.Nil(t, err) + + apiClient, _ = initTest(t, &newCfg) + + filtersEntity := api.NewDashboardFilter("", "", "") + log.Info("Exporting all dashboards") + apiClient.ExportDashboards(filtersEntity) + log.Info("Listing all dashboards") + boards := apiClient.ListDashboards(filtersEntity) + log.Infof("Imported %d dashboards", len(boards)) + ignoredSkipped := true + var generalBoard *models.Hit + var otherBoard *models.Hit + for ndx, board := range boards { + log.Infof(board.Slug) + if board.Slug == "latency-patterns" { + ignoredSkipped = false + } + if board.Slug == "individual-flows" { + generalBoard = boards[ndx] + } + if board.Slug == "flow-information" { + otherBoard = boards[ndx] + } + } + assert.NotNil(t, otherBoard) + assert.NotNil(t, generalBoard) + assert.True(t, ignoredSkipped) + validateGeneralBoard(t, generalBoard) + validateOtherBoard(t, otherBoard) + //Import Dashboards + log.Info("Importing Dashboards") + list := apiClient.ImportDashboards(filtersEntity) + assert.Equal(t, len(list), len(boards)) + log.Info("Deleting Dashboards") + deleteList := apiClient.DeleteAllDashboards(filtersEntity) + assert.Equal(t, len(deleteList), len(boards)) + log.Info("List Dashboards again") + boards = apiClient.ListDashboards(filtersEntity) + assert.Equal(t, len(boards), 0) +} + func TestDashboardCRUD(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) filtersEntity := api.NewDashboardFilter("", "", "") log.Info("Exporting all dashboards") apiClient.ExportDashboards(filtersEntity) @@ -64,7 +133,7 @@ func TestDashboardTagsFilter(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) emptyFilter := filters.NewBaseFilter() filtersEntity := api.NewDashboardFilter("", "", "") @@ -101,7 +170,7 @@ func TestWildcardFilter(t *testing.T) { } // Setup Filters - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) emptyFilter := filters.NewBaseFilter() filtersEntity := api.NewDashboardFilter("", "", "") diff --git a/integration_tests/datasource_integration_test.go b/integration_tests/datasource_integration_test.go index 4dade0d1..43eaccad 100644 --- a/integration_tests/datasource_integration_test.go +++ b/integration_tests/datasource_integration_test.go @@ -14,7 +14,7 @@ func TestDataSourceCRUD(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) filtersEntity := api.NewDataSourceFilter("") log.Info("Exporting all datasources") apiClient.ExportDataSources(filtersEntity) @@ -47,7 +47,7 @@ func TestDataSourceFilter(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - initTest(t) + initTest(t, nil) testingContext := config.Config().Contexts()["testing"] testingContext.GetDataSourceSettings().Filters = &config.DataSourceFilters{ diff --git a/integration_tests/folder_integration_test.go b/integration_tests/folder_integration_test.go index 881a90be..e61757f9 100644 --- a/integration_tests/folder_integration_test.go +++ b/integration_tests/folder_integration_test.go @@ -11,7 +11,7 @@ func TestFolderCRUD(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) log.Info("Exporting all folders") apiClient.ExportFolder(nil) log.Info("Listing all Folders") diff --git a/integration_tests/integration_common.go b/integration_tests/integration_common.go index b54e486f..85c66718 100644 --- a/integration_tests/integration_common.go +++ b/integration_tests/integration_common.go @@ -14,8 +14,13 @@ import ( "github.com/stretchr/testify/assert" ) -func initTest(t *testing.T) (api.ApiService, *viper.Viper) { - config.InitConfig("testing.yml", "'") +func initTest(t *testing.T, cfgName *string) (api.ApiService, *viper.Viper) { + if cfgName == nil { + cfgName = new(string) + *cfgName = "testing.yml" + } + + config.InitConfig(*cfgName, "'") conf := config.Config().ViperConfig() assert.NotNil(t, conf) conf.Set("context_name", "testing") diff --git a/integration_tests/libraryelements_integration_test.go b/integration_tests/libraryelements_integration_test.go index 23bd0f3a..04886d38 100644 --- a/integration_tests/libraryelements_integration_test.go +++ b/integration_tests/libraryelements_integration_test.go @@ -14,7 +14,7 @@ func TestLibraryElementsCRUD(t *testing.T) { t.Skip("skipping integration test") } - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) apiClient.DeleteAllDashboards(api.NewDashboardFilter("", "", "")) filtersEntity := api.NewDashboardFilter("", "", "") log.Info("Exporting all Library Elements") diff --git a/integration_tests/organizations_integration_test.go b/integration_tests/organizations_integration_test.go index bcf5eb63..ca563fbb 100644 --- a/integration_tests/organizations_integration_test.go +++ b/integration_tests/organizations_integration_test.go @@ -10,7 +10,7 @@ func TestOrgs(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) orgs := apiClient.ListOrganizations() assert.Equal(t, len(orgs), 1) mainOrg := orgs[0] diff --git a/integration_tests/users_integration_test.go b/integration_tests/users_integration_test.go index 9f356036..b646394c 100644 --- a/integration_tests/users_integration_test.go +++ b/integration_tests/users_integration_test.go @@ -10,7 +10,7 @@ func TestUsers(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - apiClient, _ := initTest(t) + apiClient, _ := initTest(t, nil) users := apiClient.ListUsers() assert.Equal(t, len(users), 1) adminUser := users[0]