github.com/sequix/cortex@v1.1.6/pkg/ruler/api.go (about)

     1  package ruler
     2  
     3  import (
     4  	"database/sql"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/http"
     8  
     9  	"github.com/go-kit/kit/log/level"
    10  	"github.com/gorilla/mux"
    11  
    12  	"github.com/sequix/cortex/pkg/configs"
    13  	"github.com/sequix/cortex/pkg/configs/db"
    14  	"github.com/sequix/cortex/pkg/util"
    15  	"github.com/weaveworks/common/user"
    16  )
    17  
    18  // API implements the configs api.
    19  type API struct {
    20  	db db.DB
    21  	http.Handler
    22  }
    23  
    24  // NewAPIFromConfig makes a new API from our database config.
    25  func NewAPIFromConfig(cfg db.Config) (*API, error) {
    26  	db, err := db.New(cfg)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  	return NewAPI(db), nil
    31  }
    32  
    33  // NewAPI creates a new API.
    34  func NewAPI(db db.DB) *API {
    35  	a := &API{db: db}
    36  	r := mux.NewRouter()
    37  	a.RegisterRoutes(r)
    38  	a.Handler = r
    39  	return a
    40  }
    41  
    42  // RegisterRoutes registers the configs API HTTP routes with the provided Router.
    43  func (a *API) RegisterRoutes(r *mux.Router) {
    44  	for _, route := range []struct {
    45  		name, method, path string
    46  		handler            http.HandlerFunc
    47  	}{
    48  		{"get_rules", "GET", "/api/prom/rules", a.getConfig},
    49  		{"cas_rules", "POST", "/api/prom/rules", a.casConfig},
    50  	} {
    51  		r.Handle(route.path, route.handler).Methods(route.method).Name(route.name)
    52  	}
    53  }
    54  
    55  // getConfig returns the request configuration.
    56  func (a *API) getConfig(w http.ResponseWriter, r *http.Request) {
    57  	userID, _, err := user.ExtractOrgIDFromHTTPRequest(r)
    58  	if err != nil {
    59  		http.Error(w, err.Error(), http.StatusUnauthorized)
    60  		return
    61  	}
    62  	logger := util.WithContext(r.Context(), util.Logger)
    63  
    64  	cfg, err := a.db.GetRulesConfig(r.Context(), userID)
    65  	if err == sql.ErrNoRows {
    66  		http.Error(w, "No configuration", http.StatusNotFound)
    67  		return
    68  	} else if err != nil {
    69  		level.Error(logger).Log("msg", "error getting config", "err", err)
    70  		http.Error(w, err.Error(), http.StatusInternalServerError)
    71  		return
    72  	}
    73  
    74  	w.Header().Set("Content-Type", "application/json")
    75  	if err := json.NewEncoder(w).Encode(cfg); err != nil {
    76  		level.Error(logger).Log("msg", "error encoding config", "err", err)
    77  		http.Error(w, err.Error(), http.StatusInternalServerError)
    78  		return
    79  	}
    80  }
    81  
    82  type configUpdateRequest struct {
    83  	OldConfig configs.RulesConfig `json:"old_config"`
    84  	NewConfig configs.RulesConfig `json:"new_config"`
    85  }
    86  
    87  func (a *API) casConfig(w http.ResponseWriter, r *http.Request) {
    88  	userID, _, err := user.ExtractOrgIDFromHTTPRequest(r)
    89  	if err != nil {
    90  		http.Error(w, err.Error(), http.StatusUnauthorized)
    91  		return
    92  	}
    93  	logger := util.WithContext(r.Context(), util.Logger)
    94  
    95  	var updateReq configUpdateRequest
    96  	if err := json.NewDecoder(r.Body).Decode(&updateReq); err != nil {
    97  		level.Error(logger).Log("msg", "error decoding json body", "err", err)
    98  		http.Error(w, err.Error(), http.StatusBadRequest)
    99  		return
   100  	}
   101  
   102  	if _, err = updateReq.NewConfig.Parse(); err != nil {
   103  		level.Error(logger).Log("msg", "invalid rules", "err", err)
   104  		http.Error(w, fmt.Sprintf("Invalid rules: %v", err), http.StatusBadRequest)
   105  		return
   106  	}
   107  
   108  	updated, err := a.db.SetRulesConfig(r.Context(), userID, updateReq.OldConfig, updateReq.NewConfig)
   109  	if err != nil {
   110  		level.Error(logger).Log("msg", "error storing config", "err", err)
   111  		http.Error(w, err.Error(), http.StatusInternalServerError)
   112  		return
   113  	}
   114  	if !updated {
   115  		http.Error(w, "Supplied configuration doesn't match current configuration", http.StatusConflict)
   116  	}
   117  	w.WriteHeader(http.StatusNoContent)
   118  }