mirror of
https://github.com/SigNoz/signoz.git
synced 2026-04-14 16:00:27 +01:00
* feat: adding cloud integration type for refactor * refactor: store interfaces to use local types and error * feat: adding sql store implementation * refactor: removing interface check * feat: adding updated types for cloud integration * refactor: using struct for map * refactor: update cloud integration types and module interface * fix: correct GetService signature and remove shadowed Data field * feat: implement cloud integration store * refactor: adding comments and removed wrong code * refactor: streamlining types * refactor: add comments for backward compatibility in PostableAgentCheckInRequest * refactor: update Dashboard struct comments and remove unused fields * refactor: split upsert store method * feat: adding integration test * refactor: clean up types * refactor: renaming service type to service id * refactor: using serviceID type * feat: adding method for service id creation * refactor: updating store methods * refactor: clean up * refactor: clean up * refactor: review comments * refactor: clean up * feat: adding handlers * fix: lint and ci issues * fix: lint issues * fix: update error code for service not found * feat: adding handler skeleton * chore: removing todo comment * feat: adding frontend openapi schema * feat: adding module implementation for create account * fix: returning valid error instead of panic * fix: module test * refactor: simplify ingestion key retrieval logic * feat: adding module implementation for AWS * refactor: ci lint changes * refactor: python formatting change * fix: new storable account func was unsetting provider account id * refactor: python lint changes * refactor: adding validation on update account request * refactor: reverting older tests and adding new tests * chore: lint changes * feat: using service account for API key * refactor: renaming tests and cleanup * refactor: removing dashboard overview images * feat: adding service definition store * chore: adding TODO comments * feat: adding API for getting connection credentials * feat: adding openapi spec for the endpoint * feat: adding tests for credential API * feat: adding cloud integration config * refactor: updating test with new env variable for config * refactor: moving few cloud provider interface methods to types * refactor: review comments resolution * refactor: lint changes * refactor: code clean up * refactor: removing email domain function * refactor: review comments and clean up * refactor: lint fixes * refactor: review changes - Added get connected account module method - Fixed integration tests - Removed cloud integration store as callback function's param * refactor: changing wrong dashboard id for EKS definition
437 lines
11 KiB
Go
437 lines
11 KiB
Go
package implcloudintegration
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/SigNoz/signoz/pkg/http/binding"
|
|
"github.com/SigNoz/signoz/pkg/http/render"
|
|
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
|
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
|
"github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
|
|
"github.com/SigNoz/signoz/pkg/valuer"
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
type handler struct {
|
|
module cloudintegration.Module
|
|
}
|
|
|
|
func NewHandler(module cloudintegration.Module) cloudintegration.Handler {
|
|
return &handler{
|
|
module: module,
|
|
}
|
|
}
|
|
|
|
func (handler *handler) GetConnectionCredentials(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
creds, err := handler.module.GetConnectionCredentials(ctx, valuer.MustNewUUID(claims.OrgID), provider)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, creds)
|
|
}
|
|
|
|
func (handler *handler) CreateAccount(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
postableAccount := new(cloudintegrationtypes.PostableAccount)
|
|
err = binding.JSON.BindBody(r.Body, postableAccount)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
accountConfig, err := cloudintegrationtypes.NewAccountConfigFromPostable(provider, postableAccount.Config)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
account := cloudintegrationtypes.NewAccount(valuer.MustNewUUID(claims.OrgID), provider, accountConfig)
|
|
err = handler.module.CreateAccount(ctx, account)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
connectionArtifact, err := handler.module.GetConnectionArtifact(ctx, account, postableAccount)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusCreated, cloudintegrationtypes.NewGettableAccountWithConnectionArtifact(account, connectionArtifact))
|
|
}
|
|
|
|
func (handler *handler) GetAccount(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
accountID, err := valuer.NewUUID(mux.Vars(r)["id"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
account, err := handler.module.GetAccount(ctx, valuer.MustNewUUID(claims.OrgID), accountID, provider)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, account)
|
|
}
|
|
|
|
func (handler *handler) ListAccounts(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
accounts, err := handler.module.ListAccounts(ctx, valuer.MustNewUUID(claims.OrgID), provider)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, cloudintegrationtypes.NewGettableAccounts(accounts))
|
|
}
|
|
|
|
func (handler *handler) UpdateAccount(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
cloudIntegrationID, err := valuer.NewUUID(mux.Vars(r)["id"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
req := new(cloudintegrationtypes.UpdatableAccount)
|
|
if err := binding.JSON.BindBody(r.Body, req); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
account, err := handler.module.GetConnectedAccount(ctx, valuer.MustNewUUID(claims.OrgID), cloudIntegrationID, provider)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
accountConfig, err := cloudintegrationtypes.NewAccountConfigFromUpdatable(provider, req)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
if err := account.Update(provider, accountConfig); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
err = handler.module.UpdateAccount(ctx, account)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusNoContent, nil)
|
|
}
|
|
|
|
func (handler *handler) DisconnectAccount(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
cloudIntegrationID, err := valuer.NewUUID(mux.Vars(r)["id"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
err = handler.module.DisconnectAccount(ctx, valuer.MustNewUUID(claims.OrgID), cloudIntegrationID, provider)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusNoContent, nil)
|
|
}
|
|
|
|
func (handler *handler) ListServicesMetadata(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
queryParams := new(cloudintegrationtypes.ListServicesMetadataParams)
|
|
if err := binding.Query.BindQuery(r.URL.Query(), queryParams); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
orgID := valuer.MustNewUUID(claims.OrgID)
|
|
// check if integration account exists and is not removed.
|
|
if !queryParams.CloudIntegrationID.IsZero() {
|
|
_, err := handler.module.GetConnectedAccount(ctx, orgID, queryParams.CloudIntegrationID, provider)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
services, err := handler.module.ListServicesMetadata(ctx, orgID, provider, queryParams.CloudIntegrationID)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, cloudintegrationtypes.NewGettableServicesMetadata(services))
|
|
}
|
|
|
|
func (handler *handler) GetService(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
serviceID, err := cloudintegrationtypes.NewServiceID(provider, mux.Vars(r)["service_id"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
queryParams := new(cloudintegrationtypes.GetServiceParams)
|
|
if err := binding.Query.BindQuery(r.URL.Query(), queryParams); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
// check if integration account exists and is not removed.
|
|
if !queryParams.CloudIntegrationID.IsZero() {
|
|
_, err := handler.module.GetConnectedAccount(ctx, valuer.MustNewUUID(claims.OrgID), queryParams.CloudIntegrationID, provider)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
svc, err := handler.module.GetService(ctx, valuer.MustNewUUID(claims.OrgID), serviceID, provider, queryParams.CloudIntegrationID)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, svc)
|
|
}
|
|
|
|
func (handler *handler) UpdateService(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
serviceID, err := cloudintegrationtypes.NewServiceID(provider, mux.Vars(r)["service_id"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
req := new(cloudintegrationtypes.UpdatableService)
|
|
if err := binding.JSON.BindBody(r.Body, req); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
cloudIntegrationID, err := valuer.NewUUID(mux.Vars(r)["id"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
orgID := valuer.MustNewUUID(claims.OrgID)
|
|
|
|
// check if integration account exists and is not removed.
|
|
_, err = handler.module.GetConnectedAccount(ctx, orgID, cloudIntegrationID, provider)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
svc, err := handler.module.GetService(ctx, orgID, serviceID, provider, cloudIntegrationID)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
// update or create service
|
|
if svc.CloudIntegrationService == nil {
|
|
cloudIntegrationService := cloudintegrationtypes.NewCloudIntegrationService(serviceID, cloudIntegrationID, req.Config)
|
|
err = handler.module.CreateService(ctx, orgID, cloudIntegrationService, provider)
|
|
} else {
|
|
err = svc.CloudIntegrationService.Update(provider, serviceID, req.Config)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
err = handler.module.UpdateService(ctx, orgID, svc.CloudIntegrationService, provider)
|
|
}
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusNoContent, nil)
|
|
}
|
|
|
|
func (handler *handler) AgentCheckIn(rw http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
claims, err := authtypes.ClaimsFromContext(ctx)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
req := new(cloudintegrationtypes.PostableAgentCheckIn)
|
|
if err := binding.JSON.BindBody(r.Body, req); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
// Map old fields → new fields for backward compatibility with old agents
|
|
// Old agents send account_id (=> cloudIntegrationId) and cloud_account_id (=> providerAccountId)
|
|
if req.ID != "" {
|
|
id, err := valuer.NewUUID(req.ID)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
req.CloudIntegrationID = id
|
|
req.ProviderAccountID = req.AccountID
|
|
}
|
|
|
|
resp, err := handler.module.AgentCheckIn(ctx, valuer.MustNewUUID(claims.OrgID), provider, &req.AgentCheckInRequest)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, cloudintegrationtypes.NewGettableAgentCheckIn(provider, resp))
|
|
}
|