github.com/GoogleCloudPlatform/testgrid@v0.0.174/pkg/api/v1/config.go (about)

     1  /*
     2  Copyright 2021 The TestGrid Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package v1
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  	"sort"
    24  
    25  	"github.com/go-chi/chi"
    26  	"github.com/sirupsen/logrus"
    27  
    28  	"github.com/GoogleCloudPlatform/testgrid/config"
    29  	apipb "github.com/GoogleCloudPlatform/testgrid/pb/api/v1"
    30  )
    31  
    32  const scopeParam = "scope"
    33  
    34  // queryParams returns only the query parameters in the request that need to be passed through to links
    35  func queryParams(scope string) string {
    36  	if scope != "" {
    37  		return fmt.Sprintf("?scope=%s", scope)
    38  	}
    39  	return ""
    40  }
    41  
    42  // ListDashboardGroup returns every dashboard group in TestGrid
    43  func (s *Server) ListDashboardGroups(ctx context.Context, req *apipb.ListDashboardGroupsRequest) (*apipb.ListDashboardGroupsResponse, error) {
    44  	c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	c.Mutex.RLock()
    49  	defer c.Mutex.RUnlock()
    50  
    51  	var resp apipb.ListDashboardGroupsResponse
    52  	for name := range c.Config.DashboardGroups {
    53  		rsc := apipb.Resource{
    54  			Name: name,
    55  			Link: fmt.Sprintf("/dashboard-groups/%s%s", config.Normalize(name), queryParams(req.GetScope())),
    56  		}
    57  		resp.DashboardGroups = append(resp.DashboardGroups, &rsc)
    58  	}
    59  
    60  	sort.SliceStable(resp.DashboardGroups, func(i, j int) bool {
    61  		return resp.DashboardGroups[i].Name < resp.DashboardGroups[j].Name
    62  	})
    63  
    64  	return &resp, nil
    65  }
    66  
    67  // ListDashboardGroupHTTP returns every dashboard group in TestGrid
    68  // Response json: ListDashboardGroupResponse
    69  func (s Server) ListDashboardGroupHTTP(w http.ResponseWriter, r *http.Request) {
    70  	req := apipb.ListDashboardGroupsRequest{
    71  		Scope: r.URL.Query().Get(scopeParam),
    72  	}
    73  
    74  	groups, err := s.ListDashboardGroups(r.Context(), &req)
    75  	if err != nil {
    76  		http.Error(w, err.Error(), http.StatusNotFound)
    77  		return
    78  	}
    79  
    80  	s.writeJSON(w, groups)
    81  }
    82  
    83  // GetDashboardGroup returns a given dashboard group
    84  func (s *Server) GetDashboardGroup(ctx context.Context, req *apipb.GetDashboardGroupRequest) (*apipb.GetDashboardGroupResponse, error) {
    85  	c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	c.Mutex.RLock()
    90  	defer c.Mutex.RUnlock()
    91  
    92  	dashGroupName := c.NormalDashboardGroup[config.Normalize(req.GetDashboardGroup())]
    93  	group := c.Config.DashboardGroups[dashGroupName]
    94  
    95  	if group != nil {
    96  		result := apipb.GetDashboardGroupResponse{}
    97  		for _, dash := range group.DashboardNames {
    98  			rsc := apipb.Resource{
    99  				Name: dash,
   100  				Link: fmt.Sprintf("/dashboards/%s%s", config.Normalize(dash), queryParams(req.GetScope())),
   101  			}
   102  			result.Dashboards = append(result.Dashboards, &rsc)
   103  		}
   104  		sort.SliceStable(result.Dashboards, func(i, j int) bool {
   105  			return result.Dashboards[i].Name < result.Dashboards[j].Name
   106  		})
   107  		return &result, nil
   108  	}
   109  
   110  	return nil, fmt.Errorf("Dashboard group %q not found", req.GetDashboardGroup())
   111  }
   112  
   113  // GetDashboardGroupHTTP returns a given dashboard group
   114  // Response json: GetDashboardGroupResponse
   115  func (s Server) GetDashboardGroupHTTP(w http.ResponseWriter, r *http.Request) {
   116  	req := apipb.GetDashboardGroupRequest{
   117  		Scope:          r.URL.Query().Get(scopeParam),
   118  		DashboardGroup: chi.URLParam(r, "dashboard-group"),
   119  	}
   120  	resp, err := s.GetDashboardGroup(r.Context(), &req)
   121  	if err != nil {
   122  		http.Error(w, err.Error(), http.StatusNotFound)
   123  		return
   124  	}
   125  	s.writeJSON(w, resp)
   126  }
   127  
   128  // ListDashboard returns every dashboard in TestGrid
   129  func (s *Server) ListDashboards(ctx context.Context, req *apipb.ListDashboardsRequest) (*apipb.ListDashboardsResponse, error) {
   130  	c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	c.Mutex.RLock()
   135  	defer c.Mutex.RUnlock()
   136  
   137  	// TODO(sultan-duisenbay): consider moving this to config snapshot or cached config
   138  	dashboardsToGroups := make(map[string]string)
   139  	for _, groupConfig := range c.Config.DashboardGroups {
   140  		for _, dashboardName := range groupConfig.DashboardNames {
   141  			dashboardsToGroups[dashboardName] = groupConfig.Name
   142  		}
   143  	}
   144  
   145  	var resp apipb.ListDashboardsResponse
   146  	for name := range c.Config.Dashboards {
   147  		rsc := apipb.DashboardResource{
   148  			Name:               name,
   149  			Link:               fmt.Sprintf("/dashboards/%s%s", config.Normalize(name), queryParams(req.GetScope())),
   150  			DashboardGroupName: dashboardsToGroups[name],
   151  		}
   152  		resp.Dashboards = append(resp.Dashboards, &rsc)
   153  	}
   154  	sort.SliceStable(resp.Dashboards, func(i, j int) bool {
   155  		return resp.Dashboards[i].Name < resp.Dashboards[j].Name
   156  	})
   157  
   158  	return &resp, nil
   159  }
   160  
   161  // ListDashboardsHTTP returns every dashboard in TestGrid
   162  // Response json: ListDashboardResponse
   163  func (s Server) ListDashboardsHTTP(w http.ResponseWriter, r *http.Request) {
   164  	req := apipb.ListDashboardsRequest{
   165  		Scope: r.URL.Query().Get(scopeParam),
   166  	}
   167  
   168  	dashboards, err := s.ListDashboards(r.Context(), &req)
   169  	if err != nil {
   170  		http.Error(w, err.Error(), http.StatusNotFound)
   171  		return
   172  	}
   173  
   174  	s.writeJSON(w, dashboards)
   175  }
   176  
   177  // GetDashboard returns a given dashboard
   178  func (s *Server) GetDashboard(ctx context.Context, req *apipb.GetDashboardRequest) (*apipb.GetDashboardResponse, error) {
   179  	c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  	c.Mutex.RLock()
   184  	defer c.Mutex.RUnlock()
   185  
   186  	dashboardName := c.NormalDashboard[config.Normalize(req.GetDashboard())]
   187  	dashboard := c.Config.Dashboards[dashboardName]
   188  
   189  	if dashboard != nil {
   190  		result := apipb.GetDashboardResponse{
   191  			DefaultTab:          dashboard.DefaultTab,
   192  			HighlightToday:      dashboard.HighlightToday,
   193  			SuppressFailingTabs: dashboard.DownplayFailingTabs,
   194  			Notifications:       dashboard.Notifications,
   195  		}
   196  		return &result, nil
   197  	}
   198  
   199  	return nil, fmt.Errorf("Dashboard %q not found", req.GetDashboard())
   200  }
   201  
   202  // GetDashboardHTTP returns a given dashboard
   203  // Response json: GetDashboardResponse
   204  func (s Server) GetDashboardHTTP(w http.ResponseWriter, r *http.Request) {
   205  	req := apipb.GetDashboardRequest{
   206  		Scope:     r.URL.Query().Get(scopeParam),
   207  		Dashboard: chi.URLParam(r, "dashboard"),
   208  	}
   209  	resp, err := s.GetDashboard(r.Context(), &req)
   210  	if err != nil {
   211  		http.Error(w, err.Error(), http.StatusNotFound)
   212  		return
   213  	}
   214  	s.writeJSON(w, resp)
   215  }
   216  
   217  // ListDashboardTabs returns a given dashboard tabs
   218  func (s *Server) ListDashboardTabs(ctx context.Context, req *apipb.ListDashboardTabsRequest) (*apipb.ListDashboardTabsResponse, error) {
   219  	c, err := s.getConfig(ctx, logrus.WithContext(ctx), req.GetScope())
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	c.Mutex.RLock()
   224  	defer c.Mutex.RUnlock()
   225  
   226  	dashboardName := c.NormalDashboard[config.Normalize((req.GetDashboard()))]
   227  	dashboard := c.Config.Dashboards[dashboardName]
   228  
   229  	if dashboard != nil {
   230  		var dashboardTabsResponse apipb.ListDashboardTabsResponse
   231  
   232  		for _, tab := range dashboard.DashboardTab {
   233  			rsc := apipb.Resource{
   234  				Name: tab.Name,
   235  				Link: fmt.Sprintf("/dashboards/%s/tabs/%s%s", config.Normalize(dashboard.Name), config.Normalize(tab.Name), queryParams(req.GetScope())),
   236  			}
   237  			dashboardTabsResponse.DashboardTabs = append(dashboardTabsResponse.DashboardTabs, &rsc)
   238  		}
   239  		sort.SliceStable(dashboardTabsResponse.DashboardTabs, func(i, j int) bool {
   240  			return dashboardTabsResponse.DashboardTabs[i].Name < dashboardTabsResponse.DashboardTabs[j].Name
   241  		})
   242  		return &dashboardTabsResponse, nil
   243  	}
   244  	return nil, fmt.Errorf("Dashboard %q not found", req.GetDashboard())
   245  }
   246  
   247  // ListDashboardTabsHTTP returns a given dashboard tabs
   248  // Response json: ListDashboardTabsResponse
   249  func (s Server) ListDashboardTabsHTTP(w http.ResponseWriter, r *http.Request) {
   250  	req := apipb.ListDashboardTabsRequest{
   251  		Scope:     r.URL.Query().Get(scopeParam),
   252  		Dashboard: chi.URLParam(r, "dashboard"),
   253  	}
   254  
   255  	resp, err := s.ListDashboardTabs(r.Context(), &req)
   256  	if err != nil {
   257  		http.Error(w, err.Error(), http.StatusNotFound)
   258  		return
   259  	}
   260  	s.writeJSON(w, resp)
   261  }