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: QS package for integrations #4578

Merged
merged 12 commits into from
Feb 28, 2024
Prev Previous commit
Next Next commit
chore: some more cleanup
  • Loading branch information
raj-k-singh committed Feb 23, 2024
commit b147b82aa6e7a1136a775efcac3814adce61fd9c
153 changes: 90 additions & 63 deletions pkg/query-service/app/integrations/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"slices"
"strings"
"time"

"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
Expand Down Expand Up @@ -37,8 +36,8 @@ type IntegrationDetails struct {
IntegrationAssets
}

type AvailableIntegration struct {
IntegrationDetails
type IntegrationsListItem struct {
IntegrationSummary
IsInstalled bool
}

Expand All @@ -49,20 +48,25 @@ type InstalledIntegration struct {
}
type InstalledIntegrationConfig map[string]interface{}

type InstalledIntegrationWithDetails struct {
InstalledIntegration
type Integration struct {
IntegrationDetails
Installation *InstalledIntegration
}

type Manager struct {
availableIntegrationsRepo AvailableIntegrationsRepo
installedIntegrationsRepo InstalledIntegrationsRepo
}

func (m *Manager) ListAvailableIntegrations(
type IntegrationsFilter struct {
IsInstalled *bool
}

func (m *Manager) ListIntegrations(
ctx context.Context,
// Expected to have filters and pagination over time.
) ([]AvailableIntegration, *model.ApiError) {
filter *IntegrationsFilter,
// Expected to have pagination over time.
) ([]IntegrationsListItem, *model.ApiError) {
available, apiErr := m.availableIntegrationsRepo.list(ctx)
if apiErr != nil {
return nil, model.WrapApiError(
Expand All @@ -81,81 +85,61 @@ func (m *Manager) ListAvailableIntegrations(
installedIds = append(installedIds, ii.IntegrationId)
}

result := []AvailableIntegration{}
result := []IntegrationsListItem{}
for _, ai := range available {
result = append(result, AvailableIntegration{
IntegrationDetails: ai,
result = append(result, IntegrationsListItem{
IntegrationSummary: ai.IntegrationSummary,
IsInstalled: slices.Contains(installedIds, ai.Id),
})
}

if filter != nil {
if filter.IsInstalled != nil {
filteredResult := []IntegrationsListItem{}
for _, r := range result {
if r.IsInstalled == *filter.IsInstalled {
filteredResult = append(filteredResult, r)
}
}
result = filteredResult
}
}
raj-k-singh marked this conversation as resolved.
Show resolved Hide resolved

return result, nil
}

func (m *Manager) ListInstalledIntegrations(
func (m *Manager) GetIntegration(
ctx context.Context,
) ([]InstalledIntegrationWithDetails, *model.ApiError) {
installed, apiErr := m.installedIntegrationsRepo.list(ctx)
integrationId string,
) (*Integration, *model.ApiError) {
integrationDetails, apiErr := m.getIntegrationDetails(
ctx, integrationId,
)
if apiErr != nil {
return nil, model.WrapApiError(
apiErr, "could not fetch installed integrations",
)
return nil, apiErr
}

installedIds := []string{}
for _, ii := range installed {
installedIds = append(installedIds, ii.IntegrationId)
}

integrationDetails, apiErr := m.availableIntegrationsRepo.get(
ctx, installedIds,
installation, apiErr := m.getInstalledIntegration(
ctx, integrationId,
)
if apiErr != nil {
return nil, model.WrapApiError(
apiErr, "could not fetch details for installed integrations",
)
}
if len(integrationDetails) != len(installedIds) {
missingIds := []string{}
for _, iid := range installedIds {
if _, exists := integrationDetails[iid]; !exists {
missingIds = append(missingIds, iid)
}
}
return nil, model.NotFoundError(fmt.Errorf(
"could not get details for all installed integrations with id: %s",
strings.Join(missingIds, ", "),
))
return nil, apiErr
}

result := []InstalledIntegrationWithDetails{}
for _, ii := range installed {
result = append(result, InstalledIntegrationWithDetails{
InstalledIntegration: ii,
IntegrationDetails: integrationDetails[ii.IntegrationId],
})
}
return result, nil
return &Integration{
IntegrationDetails: *integrationDetails,
Installation: installation,
raj-k-singh marked this conversation as resolved.
Show resolved Hide resolved
}, nil
}

func (m *Manager) InstallIntegration(
ctx context.Context,
integrationId string,
config InstalledIntegrationConfig,
) (*AvailableIntegration, *model.ApiError) {
ais, apiErr := m.availableIntegrationsRepo.get(
ctx, []string{integrationId},
)
) (*IntegrationsListItem, *model.ApiError) {
integrationDetails, apiErr := m.getIntegrationDetails(ctx, integrationId)
if apiErr != nil {
return nil, model.WrapApiError(apiErr, fmt.Sprintf(
"could not fetch integration to be installed: %s", integrationId,
))
}

integrationDetails, wasFound := ais[integrationId]
if !wasFound {
return nil, model.NotFoundError(fmt.Errorf(
"could not find integration to be installed: %s", integrationId,
))
return nil, apiErr
}

_, apiErr = m.installedIntegrationsRepo.upsert(
Expand All @@ -167,8 +151,8 @@ func (m *Manager) InstallIntegration(
)
}

return &AvailableIntegration{
IntegrationDetails: integrationDetails,
return &IntegrationsListItem{
IntegrationSummary: integrationDetails.IntegrationSummary,
IsInstalled: true,
}, nil
}
Expand All @@ -179,3 +163,46 @@ func (m *Manager) UninstallIntegration(
) *model.ApiError {
return m.installedIntegrationsRepo.delete(ctx, integrationId)
}

// Helpers.
func (m *Manager) getIntegrationDetails(
ctx context.Context,
integrationId string,
) (*IntegrationDetails, *model.ApiError) {
ais, apiErr := m.availableIntegrationsRepo.get(
ctx, []string{integrationId},
)
if apiErr != nil {
return nil, model.WrapApiError(apiErr, fmt.Sprintf(
"could not fetch integration: %s", integrationId,
))
}

integrationDetails, wasFound := ais[integrationId]
if !wasFound {
return nil, model.NotFoundError(fmt.Errorf(
"could not find integration: %s", integrationId,
))
}
return &integrationDetails, nil
}

func (m *Manager) getInstalledIntegration(
ctx context.Context,
integrationId string,
) (*InstalledIntegration, *model.ApiError) {
iis, apiErr := m.installedIntegrationsRepo.get(
ctx, []string{integrationId},
)
if apiErr != nil {
return nil, model.WrapApiError(apiErr, fmt.Sprintf(
"could not fetch installed integration: %s", integrationId,
))
}

installation, wasFound := iis[integrationId]
if !wasFound {
return nil, nil
}
return &installation, nil
}
35 changes: 28 additions & 7 deletions pkg/query-service/app/integrations/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@ func TestIntegrationLifecycle(t *testing.T) {
mgr := NewTestIntegrationsManager(t)
ctx := context.Background()

installedIntegrations, apiErr := mgr.ListInstalledIntegrations(ctx)
ii := true
installedIntegrationsFilter := &IntegrationsFilter{
IsInstalled: &ii,
}

installedIntegrations, apiErr := mgr.ListIntegrations(
ctx, installedIntegrationsFilter,
)
require.Nil(apiErr)
require.Equal([]InstalledIntegrationWithDetails{}, installedIntegrations)
require.Equal([]IntegrationsListItem{}, installedIntegrations)

availableIntegrations, apiErr := mgr.ListAvailableIntegrations(ctx)
availableIntegrations, apiErr := mgr.ListIntegrations(ctx, nil)
require.Nil(apiErr)
require.Equal(2, len(availableIntegrations))
require.False(availableIntegrations[0].IsInstalled)
Expand All @@ -31,12 +38,19 @@ func TestIntegrationLifecycle(t *testing.T) {
require.Nil(apiErr)
require.Equal(installed.Id, availableIntegrations[1].Id)

installedIntegrations, apiErr = mgr.ListInstalledIntegrations(ctx)
integration, apiErr := mgr.GetIntegration(ctx, availableIntegrations[1].Id)
require.Nil(apiErr)
require.Equal(integration.Id, availableIntegrations[1].Id)
require.NotNil(integration.Installation)

installedIntegrations, apiErr = mgr.ListIntegrations(
ctx, installedIntegrationsFilter,
)
require.Nil(apiErr)
require.Equal(1, len(installedIntegrations))
require.Equal(availableIntegrations[1].Id, installedIntegrations[0].Id)

availableIntegrations, apiErr = mgr.ListAvailableIntegrations(ctx)
availableIntegrations, apiErr = mgr.ListIntegrations(ctx, nil)
require.Nil(apiErr)
require.Equal(2, len(availableIntegrations))
require.False(availableIntegrations[0].IsInstalled)
Expand All @@ -45,11 +59,18 @@ func TestIntegrationLifecycle(t *testing.T) {
apiErr = mgr.UninstallIntegration(ctx, installed.Id)
require.Nil(apiErr)

installedIntegrations, apiErr = mgr.ListInstalledIntegrations(ctx)
integration, apiErr = mgr.GetIntegration(ctx, availableIntegrations[1].Id)
require.Nil(apiErr)
require.Equal(integration.Id, availableIntegrations[1].Id)
require.Nil(integration.Installation)

installedIntegrations, apiErr = mgr.ListIntegrations(
ctx, installedIntegrationsFilter,
)
require.Nil(apiErr)
require.Equal(0, len(installedIntegrations))

availableIntegrations, apiErr = mgr.ListAvailableIntegrations(ctx)
availableIntegrations, apiErr = mgr.ListIntegrations(ctx, nil)
require.Nil(apiErr)
require.Equal(2, len(availableIntegrations))
require.False(availableIntegrations[0].IsInstalled)
Expand Down
11 changes: 10 additions & 1 deletion pkg/query-service/app/integrations/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import (
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
)

func NewTestIntegrationsManager(t *testing.T) *Manager {
func NewTestSqliteDB(t *testing.T) (
db *sqlx.DB, dbFilePath string,
) {
testDBFile, err := os.CreateTemp("", "test-signoz-db-*")
if err != nil {
t.Fatalf("could not create temp file for test db: %v", err)
Expand All @@ -25,6 +27,13 @@ func NewTestIntegrationsManager(t *testing.T) *Manager {
if err != nil {
t.Fatalf("could not open test db sqlite file: %v", err)
}

return testDB, testDBFilePath
}

func NewTestIntegrationsManager(t *testing.T) *Manager {
testDB, _ := NewTestSqliteDB(t)

installedIntegrationsRepo, err := NewInstalledIntegrationsSqliteRepo(testDB)
if err != nil {
t.Fatalf("could not init sqlite DB for installed integrations: %v", err)
Expand Down
Loading