Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/ingestion rules v1 APIs #2476

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
5314518
feat: opamp server application
srikanthccv Nov 30, 2022
4feca79
Merge branch 'develop' into opamp
pranay01 Nov 30, 2022
6729558
chore: resolve conflicts
srikanthccv Dec 23, 2022
7ef38ec
chore: opamp
srikanthccv Dec 23, 2022
50e1661
Merge branch 'opamp' of github.com:SigNoz/signoz into opamp
srikanthccv Dec 24, 2022
e234a84
Merge branch 'develop' into opamp
srikanthccv Dec 27, 2022
c8509e6
chore: refactor server implementation
srikanthccv Dec 28, 2022
e1116a3
chore: add Stop
srikanthccv Jan 2, 2023
a934a0a
Merge branch 'develop' into opamp
palashgdev Jan 4, 2023
f22d5fa
Merge branch 'develop' into opamp
srikanthccv Jan 20, 2023
23a4f89
Merge branch 'develop' into opamp
srikanthccv Mar 9, 2023
d319ec1
Merge branch 'opamp' of github.com:SigNoz/signoz into opamp
srikanthccv Mar 9, 2023
70794a9
chore: merged opamp updates
Mar 9, 2023
a3cad2b
chore: removed all errorf
Mar 9, 2023
0fe8932
chore: added a comment about zero version
Mar 9, 2023
9df43ca
feat: added user context for created by
Mar 13, 2023
efa1d7d
chore: changed debugf to debug
Mar 13, 2023
56148c5
chore: removed lb from opamp + added config parser
Mar 13, 2023
e72b5b4
chore: pulled updates on ingestion rules api
Mar 13, 2023
42a53a2
feat: added user context logic
Mar 13, 2023
77f4da8
fix: added userid to ConfigNewVersion()
Mar 13, 2023
f37b836
chore: removed user id from contxt and added config parser
Mar 14, 2023
f95b57e
chore: merged changes from agent conf
Mar 14, 2023
c098d59
chore: resolved some changes to newConfigVersion()
Mar 14, 2023
f979385
chore: resolved some changes to newConfigVersion()
Mar 14, 2023
7306f05
chore: fixed minor compile issues
Mar 14, 2023
2755551
chore: removed user context
Mar 14, 2023
3d8cbaa
fix: issue with sql get latest config
Mar 14, 2023
703ba3a
feat: added lb exporter config
Mar 18, 2023
1735844
feat: added default-otel config for lb exporter
Mar 18, 2023
a3c153e
feat: added default otel config for opamp
Mar 21, 2023
18ec83c
chore: removed todo messagE
Mar 21, 2023
77c73d9
chore: added some comments and merged auth middleware
Mar 21, 2023
55463e6
chore: merged develop
Mar 21, 2023
c362719
fix: solved some merge issues
Mar 21, 2023
759d651
Merge branch 'develop' into feat/ingestion_rules_v1
palashgdev Mar 22, 2023
939bf24
Merge branch 'develop' into feat/ingestion_rules_v1
mindhash Apr 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 62 additions & 31 deletions ee/query-service/app/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/gorilla/mux"
"go.signoz.io/signoz/ee/query-service/dao"
"go.signoz.io/signoz/ee/query-service/ingestionRules"
"go.signoz.io/signoz/ee/query-service/interfaces"
"go.signoz.io/signoz/ee/query-service/license"
baseapp "go.signoz.io/signoz/pkg/query-service/app"
Expand All @@ -15,11 +16,13 @@ import (
)

type APIHandlerOptions struct {
DataConnector interfaces.DataConnector
AppDao dao.ModelDao
RulesManager *rules.Manager
FeatureFlags baseint.FeatureLookup
LicenseManager *license.Manager
DataConnector interfaces.DataConnector
AppDao dao.ModelDao
RulesManager *rules.Manager
FeatureFlags baseint.FeatureLookup
LicenseManager *license.Manager
Authenticator *baseapp.AuthMiddleware
IngestionController *ingestionRules.IngestionController
}

type APIHandler struct {
Expand All @@ -31,10 +34,11 @@ type APIHandler struct {
func NewAPIHandler(opts APIHandlerOptions) (*APIHandler, error) {

baseHandler, err := baseapp.NewAPIHandler(baseapp.APIHandlerOpts{
Reader: opts.DataConnector,
AppDao: opts.AppDao,
RuleManager: opts.RulesManager,
FeatureFlags: opts.FeatureFlags})
Reader: opts.DataConnector,
AppDao: opts.AppDao,
RuleManager: opts.RulesManager,
FeatureFlags: opts.FeatureFlags,
Authenticator: opts.Authenticator})

if err != nil {
return nil, err
Expand All @@ -59,6 +63,10 @@ func (ah *APIHandler) LM() *license.Manager {
return ah.opts.LicenseManager
}

func (ah *APIHandler) Auth() *baseapp.AuthMiddleware {
return ah.opts.Authenticator
}

func (ah *APIHandler) AppDao() dao.ModelDao {
return ah.opts.AppDao
}
Expand All @@ -69,66 +77,89 @@ func (ah *APIHandler) CheckFeature(f string) bool {
}

// RegisterRoutes registers routes for this handler on the given router
func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *baseapp.AuthMiddleware) {
func (ah *APIHandler) RegisterRoutes(router *mux.Router) {
// note: add ee override methods first

// routes available only in ee version
router.HandleFunc("/api/v1/licenses",
am.AdminAccess(ah.listLicenses)).
ah.Auth().AdminAccess(ah.listLicenses)).
Methods(http.MethodGet)

router.HandleFunc("/api/v1/licenses",
am.AdminAccess(ah.applyLicense)).
ah.Auth().AdminAccess(ah.applyLicense)).
Methods(http.MethodPost)

router.HandleFunc("/api/v1/featureFlags",
am.OpenAccess(ah.getFeatureFlags)).
ah.Auth().OpenAccess(ah.getFeatureFlags)).
Methods(http.MethodGet)

router.HandleFunc("/api/v1/loginPrecheck",
am.OpenAccess(ah.precheckLogin)).
ah.Auth().OpenAccess(ah.precheckLogin)).
Methods(http.MethodGet)

// paid plans specific routes
router.HandleFunc("/api/v1/complete/saml",
am.OpenAccess(ah.receiveSAML)).
ah.Auth().OpenAccess(ah.receiveSAML)).
Methods(http.MethodPost)

router.HandleFunc("/api/v1/complete/google",
am.OpenAccess(ah.receiveGoogleAuth)).
ah.Auth().OpenAccess(ah.receiveGoogleAuth)).
Methods(http.MethodGet)

router.HandleFunc("/api/v1/orgs/{orgId}/domains",
am.AdminAccess(ah.listDomainsByOrg)).
ah.Auth().AdminAccess(ah.listDomainsByOrg)).
Methods(http.MethodGet)

router.HandleFunc("/api/v1/domains",
am.AdminAccess(ah.postDomain)).
ah.Auth().AdminAccess(ah.postDomain)).
Methods(http.MethodPost)

router.HandleFunc("/api/v1/domains/{id}",
am.AdminAccess(ah.putDomain)).
ah.Auth().AdminAccess(ah.putDomain)).
Methods(http.MethodPut)

router.HandleFunc("/api/v1/domains/{id}",
am.AdminAccess(ah.deleteDomain)).
ah.Auth().AdminAccess(ah.deleteDomain)).
Methods(http.MethodDelete)

router.HandleFunc("/api/v1/dropRules/{version}",
ah.Auth().AdminAccess(ah.listDropRules)).
Methods(http.MethodGet)

router.HandleFunc("/api/v1/dropRules/{version}/deploy",
ah.Auth().AdminAccess(ah.deployDropRules)).
Methods(http.MethodPost)

router.HandleFunc("/api/v1/dropRules",
ah.Auth().AdminAccess(ah.createDropRule)).
Methods(http.MethodPost)

router.HandleFunc("/api/v1/samplingRules/{version}/deploy",
ah.Auth().AdminAccess(ah.deploySamplingRules)).
Methods(http.MethodPost)

router.HandleFunc("/api/v1/samplingRules/{version}",
ah.Auth().AdminAccess(ah.listSamplingRules)).
Methods(http.MethodGet)

router.HandleFunc("/api/v1/samplingRules",
ah.Auth().AdminAccess(ah.createSamplingRule)).
Methods(http.MethodPost)

// base overrides
router.HandleFunc("/api/v1/version", am.OpenAccess(ah.getVersion)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/invite/{token}", am.OpenAccess(ah.getInvite)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/register", am.OpenAccess(ah.registerUser)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/login", am.OpenAccess(ah.loginUser)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/traces/{traceId}", am.ViewAccess(ah.searchTraces)).Methods(http.MethodGet)
router.HandleFunc("/api/v2/metrics/query_range", am.ViewAccess(ah.queryRangeMetricsV2)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/version", ah.Auth().OpenAccess(ah.getVersion)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/invite/{token}", ah.Auth().OpenAccess(ah.getInvite)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/register", ah.Auth().OpenAccess(ah.registerUser)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/login", ah.Auth().OpenAccess(ah.loginUser)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/traces/{traceId}", ah.Auth().ViewAccess(ah.searchTraces)).Methods(http.MethodGet)
router.HandleFunc("/api/v2/metrics/query_range", ah.Auth().ViewAccess(ah.queryRangeMetricsV2)).Methods(http.MethodPost)

// PAT APIs
router.HandleFunc("/api/v1/pat", am.OpenAccess(ah.createPAT)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/pat", am.OpenAccess(ah.getPATs)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/pat/{id}", am.OpenAccess(ah.deletePAT)).Methods(http.MethodDelete)

ah.APIHandler.RegisterRoutes(router, am)
router.HandleFunc("/api/v1/pat", ah.Auth().OpenAccess(ah.createPAT)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/pat", ah.Auth().OpenAccess(ah.getPATs)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/pat/{id}", ah.Auth().OpenAccess(ah.deletePAT)).Methods(http.MethodDelete)

ah.APIHandler.RegisterRoutes(router)
}

func (ah *APIHandler) getVersion(w http.ResponseWriter, r *http.Request) {
Expand Down
19 changes: 19 additions & 0 deletions ee/query-service/app/api/dropRules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package api

import (
"net/http"

"go.signoz.io/signoz/pkg/query-service/agentConf"
)

func (ah *APIHandler) listDropRules(w http.ResponseWriter, r *http.Request) {
ah.listIngestionRulesHandler(w, r, agentConf.ElementTypeSamplingRules)
}

func (ah *APIHandler) createDropRule(w http.ResponseWriter, r *http.Request) {
ah.createIngestionRule(w, r, agentConf.ElementTypeDropRules)
}

func (ah *APIHandler) deployDropRules(w http.ResponseWriter, r *http.Request) {
ah.redeployIngestionRule(w, r, agentConf.ElementTypeDropRules)
}
161 changes: 161 additions & 0 deletions ee/query-service/app/api/ingestionRules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package api

import (
"context"
"encoding/json"
"net/http"
"strconv"

"github.com/gorilla/mux"
"go.signoz.io/signoz/ee/query-service/ingestionRules"
"go.signoz.io/signoz/ee/query-service/model"
"go.signoz.io/signoz/pkg/query-service/agentConf"
"go.uber.org/zap"
)

// ingestion rules handler - combines common methods for drop and sampling rules

// parseAgentConfigVersion parses the version string from URL path.
func parseAgentConfigVersion(r *http.Request) (int, *model.ApiError) {
// parse version from path and respond with
// - (-1) to indicate no version specified in the url path but the user is looking for the latest version
// - (0) indicates a failure in parsing
// - non-zero (>0) to indicate user is looking for a specific version

versionString := mux.Vars(r)["version"]

if versionString == "latest" {
return -1, nil
}

version64, err := strconv.ParseInt(versionString, 0, 8)

if err != nil {
return 0, model.BadRequestStr("invalid version number")
}

return int(version64), nil
}

func (ah *APIHandler) listIngestionRulesHandler(w http.ResponseWriter, r *http.Request, elementType agentConf.ElementTypeDef) {

version, err := parseAgentConfigVersion(r)
if err != nil {
RespondError(w, model.BadRequestStr("invalid version"), nil)
return
}

var payload *ingestionRules.IngestionRulesResponse
var apierr *model.ApiError

if version > 0 {
payload, apierr = ah.listIngestionRulesByVersion(context.Background(), version, elementType)
} else {
payload, apierr = ah.listIngestionRules(context.Background(), elementType)
}

if apierr != nil {
RespondError(w, apierr, payload)
return
}
ah.Respond(w, payload)
}

// listIngestionRules lists rules for latest version
func (ah *APIHandler) listIngestionRules(ctx context.Context, elementType agentConf.ElementTypeDef) (*ingestionRules.IngestionRulesResponse, *model.ApiError) {

// get lateset agent config
lastestConfig, err := agentConf.GetLatestVersion(ctx, elementType)
if err != nil || lastestConfig == nil {
zap.S().Errorf("failed to get latest agent config version ", err)
return nil, model.InternalErrorStr("Failed to get latest agent config version")
}

payload, apierr := ah.opts.IngestionController.GetRulesByVersion(ctx, lastestConfig.Version, elementType)
if apierr != nil {
return payload, apierr
}

history, err := agentConf.GetConfigHistory(ctx, elementType, 10)
if apierr != nil {
return payload, apierr
}
payload.History = history
return payload, nil
}

// listIngestionRulesByVersion lists rules along with config version history
func (ah *APIHandler) listIngestionRulesByVersion(ctx context.Context, version int, elementType agentConf.ElementTypeDef) (*ingestionRules.IngestionRulesResponse, *model.ApiError) {

payload, apierr := ah.opts.IngestionController.GetRulesByVersion(ctx, version, elementType)
if apierr != nil {
return payload, apierr
}

history, err := agentConf.GetConfigHistory(ctx, elementType, 10)
if err != nil {
zap.S().Errorf("failed to retreive config history for element type", elementType, err)
return payload, model.InternalErrorStr("failed to retrieve agent config history")
}

payload.History = history
return payload, nil
}

func (ah *APIHandler) createIngestionRule(w http.ResponseWriter, r *http.Request, elementType agentConf.ElementTypeDef) {
ctx := context.Background()
userPayload, err := ah.Auth().GetUserFromRequest(r)
if err != nil {
RespondError(w, model.BadRequestStr("failed to identify user from the request"), nil)
}

req := ingestionRules.PostableIngestionRules{}

if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
RespondError(w, model.BadRequest(err), nil)
return
}

createRule := func(ctx context.Context, userId string, postable []ingestionRules.PostableIngestionRule) (*ingestionRules.IngestionRulesResponse, *model.ApiError) {
if len(postable) == 0 {
zap.S().Warnf("found no rules in the http request, this will delete all the rules")
}

for _, p := range postable {
if apierr := p.IsValid(); apierr != nil {
zap.S().Debugf("received invalid dropping rule in the POST request", apierr)
return nil, apierr
}
}

return ah.opts.IngestionController.ApplyRules(ctx, userId, elementType, postable)
}

ingestionRuleResponse, apierr := createRule(ctx, userPayload.User.Id, req.Rules)
if apierr != nil {
RespondError(w, apierr, nil)
return
}

ah.Respond(w, ingestionRuleResponse)
}

func (ah *APIHandler) redeployIngestionRule(w http.ResponseWriter, r *http.Request, elementType agentConf.ElementTypeDef) {
version, apierr := parseAgentConfigVersion(r)
if apierr != nil {
RespondError(w, apierr, nil)
return
}

if version == 0 {
RespondError(w, model.BadRequestStr("config version required"), nil)
return
}

if err := agentConf.Redeploy(context.Background(), elementType, version); err != nil {
RespondError(w, model.InternalError(err), nil)
return
}

ah.Respond(w, "deployment started")
}
16 changes: 16 additions & 0 deletions ee/query-service/app/api/pat.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ func generatePATToken() string {
}

func (ah *APIHandler) createPAT(w http.ResponseWriter, r *http.Request) {

if !ah.CheckFeature(model.Pat) {
RespondError(w, model.BadRequestStr("feature unavailable, please upgrade to EE"), nil)
return
}

ctx := context.Background()

req := model.PAT{}
Expand Down Expand Up @@ -57,6 +63,11 @@ func (ah *APIHandler) createPAT(w http.ResponseWriter, r *http.Request) {
}

func (ah *APIHandler) getPATs(w http.ResponseWriter, r *http.Request) {
if !ah.CheckFeature(model.Pat) {
RespondError(w, model.BadRequestStr("feature unavailable, please upgrade to EE"), nil)
return
}

ctx := context.Background()
user, err := auth.GetUserFromRequest(r)
if err != nil {
Expand All @@ -76,6 +87,11 @@ func (ah *APIHandler) getPATs(w http.ResponseWriter, r *http.Request) {
}

func (ah *APIHandler) deletePAT(w http.ResponseWriter, r *http.Request) {
if !ah.CheckFeature(model.Pat) {
RespondError(w, model.BadRequestStr("feature unavailable, please upgrade to EE"), nil)
return
}

ctx := context.Background()
id := mux.Vars(r)["id"]
user, err := auth.GetUserFromRequest(r)
Expand Down
Loading