pkg/api/v1/config.go (193 lines of code) (raw):
/*
Copyright 2021 The TestGrid Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"context"
"fmt"
"net/http"
"sort"
"github.com/go-chi/chi"
"github.com/sirupsen/logrus"
"github.com/GoogleCloudPlatform/testgrid/config"
apipb "github.com/GoogleCloudPlatform/testgrid/pb/api/v1"
)
const scopeParam = "scope"
// queryParams returns only the query parameters in the request that need to be passed through to links
func queryParams(scope string) string {
if scope != "" {
return fmt.Sprintf("?scope=%s", scope)
}
return ""
}
// ListDashboardGroup returns every dashboard group in TestGrid
func (s *Server) ListDashboardGroups(ctx context.Context, req *apipb.ListDashboardGroupsRequest) (*apipb.ListDashboardGroupsResponse, error) {
c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
if err != nil {
return nil, err
}
c.Mutex.RLock()
defer c.Mutex.RUnlock()
var resp apipb.ListDashboardGroupsResponse
for name := range c.Config.DashboardGroups {
rsc := apipb.Resource{
Name: name,
Link: fmt.Sprintf("/dashboard-groups/%s%s", config.Normalize(name), queryParams(req.GetScope())),
}
resp.DashboardGroups = append(resp.DashboardGroups, &rsc)
}
sort.SliceStable(resp.DashboardGroups, func(i, j int) bool {
return resp.DashboardGroups[i].Name < resp.DashboardGroups[j].Name
})
return &resp, nil
}
// ListDashboardGroupHTTP returns every dashboard group in TestGrid
// Response json: ListDashboardGroupResponse
func (s Server) ListDashboardGroupHTTP(w http.ResponseWriter, r *http.Request) {
req := apipb.ListDashboardGroupsRequest{
Scope: r.URL.Query().Get(scopeParam),
}
groups, err := s.ListDashboardGroups(r.Context(), &req)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
s.writeJSON(w, groups)
}
// GetDashboardGroup returns a given dashboard group
func (s *Server) GetDashboardGroup(ctx context.Context, req *apipb.GetDashboardGroupRequest) (*apipb.GetDashboardGroupResponse, error) {
c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
if err != nil {
return nil, err
}
c.Mutex.RLock()
defer c.Mutex.RUnlock()
dashGroupName := c.NormalDashboardGroup[config.Normalize(req.GetDashboardGroup())]
group := c.Config.DashboardGroups[dashGroupName]
if group != nil {
result := apipb.GetDashboardGroupResponse{}
for _, dash := range group.DashboardNames {
rsc := apipb.Resource{
Name: dash,
Link: fmt.Sprintf("/dashboards/%s%s", config.Normalize(dash), queryParams(req.GetScope())),
}
result.Dashboards = append(result.Dashboards, &rsc)
}
sort.SliceStable(result.Dashboards, func(i, j int) bool {
return result.Dashboards[i].Name < result.Dashboards[j].Name
})
return &result, nil
}
return nil, fmt.Errorf("Dashboard group %q not found", req.GetDashboardGroup())
}
// GetDashboardGroupHTTP returns a given dashboard group
// Response json: GetDashboardGroupResponse
func (s Server) GetDashboardGroupHTTP(w http.ResponseWriter, r *http.Request) {
req := apipb.GetDashboardGroupRequest{
Scope: r.URL.Query().Get(scopeParam),
DashboardGroup: chi.URLParam(r, "dashboard-group"),
}
resp, err := s.GetDashboardGroup(r.Context(), &req)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
s.writeJSON(w, resp)
}
// ListDashboard returns every dashboard in TestGrid
func (s *Server) ListDashboards(ctx context.Context, req *apipb.ListDashboardsRequest) (*apipb.ListDashboardsResponse, error) {
c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
if err != nil {
return nil, err
}
c.Mutex.RLock()
defer c.Mutex.RUnlock()
// TODO(sultan-duisenbay): consider moving this to config snapshot or cached config
dashboardsToGroups := make(map[string]string)
for _, groupConfig := range c.Config.DashboardGroups {
for _, dashboardName := range groupConfig.DashboardNames {
dashboardsToGroups[dashboardName] = groupConfig.Name
}
}
var resp apipb.ListDashboardsResponse
for name := range c.Config.Dashboards {
rsc := apipb.DashboardResource{
Name: name,
Link: fmt.Sprintf("/dashboards/%s%s", config.Normalize(name), queryParams(req.GetScope())),
DashboardGroupName: dashboardsToGroups[name],
}
resp.Dashboards = append(resp.Dashboards, &rsc)
}
sort.SliceStable(resp.Dashboards, func(i, j int) bool {
return resp.Dashboards[i].Name < resp.Dashboards[j].Name
})
return &resp, nil
}
// ListDashboardsHTTP returns every dashboard in TestGrid
// Response json: ListDashboardResponse
func (s Server) ListDashboardsHTTP(w http.ResponseWriter, r *http.Request) {
req := apipb.ListDashboardsRequest{
Scope: r.URL.Query().Get(scopeParam),
}
dashboards, err := s.ListDashboards(r.Context(), &req)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
s.writeJSON(w, dashboards)
}
// GetDashboard returns a given dashboard
func (s *Server) GetDashboard(ctx context.Context, req *apipb.GetDashboardRequest) (*apipb.GetDashboardResponse, error) {
c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
if err != nil {
return nil, err
}
c.Mutex.RLock()
defer c.Mutex.RUnlock()
dashboardName := c.NormalDashboard[config.Normalize(req.GetDashboard())]
dashboard := c.Config.Dashboards[dashboardName]
if dashboard != nil {
result := apipb.GetDashboardResponse{
DefaultTab: dashboard.DefaultTab,
HighlightToday: dashboard.HighlightToday,
SuppressFailingTabs: dashboard.DownplayFailingTabs,
Notifications: dashboard.Notifications,
}
return &result, nil
}
return nil, fmt.Errorf("Dashboard %q not found", req.GetDashboard())
}
// GetDashboardHTTP returns a given dashboard
// Response json: GetDashboardResponse
func (s Server) GetDashboardHTTP(w http.ResponseWriter, r *http.Request) {
req := apipb.GetDashboardRequest{
Scope: r.URL.Query().Get(scopeParam),
Dashboard: chi.URLParam(r, "dashboard"),
}
resp, err := s.GetDashboard(r.Context(), &req)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
s.writeJSON(w, resp)
}
// ListDashboardTabs returns a given dashboard tabs
func (s *Server) ListDashboardTabs(ctx context.Context, req *apipb.ListDashboardTabsRequest) (*apipb.ListDashboardTabsResponse, error) {
c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
if err != nil {
return nil, err
}
c.Mutex.RLock()
defer c.Mutex.RUnlock()
dashboardName := c.NormalDashboard[config.Normalize((req.GetDashboard()))]
dashboard := c.Config.Dashboards[dashboardName]
if dashboard != nil {
var dashboardTabsResponse apipb.ListDashboardTabsResponse
for _, tab := range dashboard.DashboardTab {
rsc := apipb.Resource{
Name: tab.Name,
Link: fmt.Sprintf("/dashboards/%s/tabs/%s%s", config.Normalize(dashboard.Name), config.Normalize(tab.Name), queryParams(req.GetScope())),
}
dashboardTabsResponse.DashboardTabs = append(dashboardTabsResponse.DashboardTabs, &rsc)
}
sort.SliceStable(dashboardTabsResponse.DashboardTabs, func(i, j int) bool {
return dashboardTabsResponse.DashboardTabs[i].Name < dashboardTabsResponse.DashboardTabs[j].Name
})
return &dashboardTabsResponse, nil
}
return nil, fmt.Errorf("Dashboard %q not found", req.GetDashboard())
}
// ListDashboardTabsHTTP returns a given dashboard tabs
// Response json: ListDashboardTabsResponse
func (s Server) ListDashboardTabsHTTP(w http.ResponseWriter, r *http.Request) {
req := apipb.ListDashboardTabsRequest{
Scope: r.URL.Query().Get(scopeParam),
Dashboard: chi.URLParam(r, "dashboard"),
}
resp, err := s.ListDashboardTabs(r.Context(), &req)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
s.writeJSON(w, resp)
}