Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit 3b97f54

Browse files
oneclickexport: add external_services table DB query processor (#39880)
This commit introduces a new type of processors, which perform DB queries to arbitrary tables of `frontend` database. DB queries are grouped in one array of `ExportRequest` as an alternative to previous "each export part is a separate JSON property" approach. Test plan: new unit test is added. When the REST endpoint will be in place, manual tests will also be performed.
1 parent a2272ef commit 3b97f54

File tree

4 files changed

+289
-68
lines changed

4 files changed

+289
-68
lines changed
+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package oneclickexport
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"io/ioutil"
7+
"time"
8+
9+
"github.com/sourcegraph/log"
10+
"github.com/sourcegraph/sourcegraph/internal/database"
11+
"github.com/sourcegraph/sourcegraph/internal/types"
12+
)
13+
14+
const DefaultLimit = 1000
15+
16+
var _ Processor[Limit] = &ExtSvcDBQueryProcessor{}
17+
18+
type ExtSvcDBQueryProcessor struct {
19+
db database.DB
20+
logger log.Logger
21+
Type string
22+
}
23+
24+
func (d ExtSvcDBQueryProcessor) Process(ctx context.Context, payload Limit, dir string) {
25+
externalServices, err := d.db.ExternalServices().List(
26+
ctx,
27+
database.ExternalServicesListOptions{LimitOffset: &database.LimitOffset{Limit: payload.getOrDefault(DefaultLimit)}},
28+
)
29+
if err != nil {
30+
d.logger.Error("Error during fetching external services from the DB", log.Error(err))
31+
return
32+
}
33+
34+
redactedExtSvc := make([]*RedactedExternalService, len(externalServices))
35+
36+
for idx, extSvc := range externalServices {
37+
redacted, err := convertExtSvcToRedacted(extSvc)
38+
if err != nil {
39+
d.logger.Error("Error during redacting external service code host config", log.Error(err))
40+
return
41+
}
42+
redactedExtSvc[idx] = redacted
43+
}
44+
45+
bytes, err := json.MarshalIndent(redactedExtSvc, "", " ")
46+
if err != nil {
47+
d.logger.Error("Error during marshalling the result", log.Error(err))
48+
return
49+
}
50+
51+
err = ioutil.WriteFile(dir+"/db-external-services.txt", bytes, 0644)
52+
53+
if err != nil {
54+
d.logger.Error("Error during external_services export", log.Error(err))
55+
}
56+
}
57+
58+
func (d ExtSvcDBQueryProcessor) ProcessorType() string {
59+
return d.Type
60+
}
61+
62+
type RedactedExternalService struct {
63+
ID int64
64+
Kind string
65+
DisplayName string
66+
// This is the redacted config which is the only difference between this type and
67+
// types.ExternalService
68+
Config json.RawMessage
69+
CreatedAt time.Time
70+
UpdatedAt time.Time
71+
DeletedAt time.Time
72+
LastSyncAt time.Time
73+
NextSyncAt time.Time
74+
NamespaceUserID int32
75+
NamespaceOrgID int32
76+
Unrestricted bool
77+
CloudDefault bool
78+
HasWebhooks *bool
79+
TokenExpiresAt *time.Time
80+
}
81+
82+
func convertExtSvcToRedacted(extSvc *types.ExternalService) (*RedactedExternalService, error) {
83+
config, err := extSvc.RedactedConfig()
84+
if err != nil {
85+
return nil, err
86+
}
87+
return &RedactedExternalService{
88+
ID: extSvc.ID,
89+
Kind: extSvc.Kind,
90+
DisplayName: extSvc.DisplayName,
91+
Config: json.RawMessage(config),
92+
CreatedAt: extSvc.CreatedAt,
93+
UpdatedAt: extSvc.UpdatedAt,
94+
DeletedAt: extSvc.DeletedAt,
95+
LastSyncAt: extSvc.LastSyncAt,
96+
NextSyncAt: extSvc.NextSyncAt,
97+
NamespaceUserID: extSvc.NamespaceUserID,
98+
NamespaceOrgID: extSvc.NamespaceOrgID,
99+
Unrestricted: extSvc.Unrestricted,
100+
CloudDefault: extSvc.CloudDefault,
101+
HasWebhooks: extSvc.HasWebhooks,
102+
TokenExpiresAt: extSvc.TokenExpiresAt,
103+
}, nil
104+
}
105+
106+
type Limit int
107+
108+
func (l Limit) getOrDefault(defaultValue int) int {
109+
if l == 0 {
110+
return defaultValue
111+
}
112+
return int(l)
113+
}
114+
115+
type DBQueryRequest struct {
116+
TableName string `json:"tableName"`
117+
Count Limit `json:"count"`
118+
}

cmd/frontend/oneclickexport/export.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ var _ Exporter = &DataExporter{}
2222
type DataExporter struct {
2323
logger log.Logger
2424
configProcessors map[string]Processor[ConfigRequest]
25+
dbProcessors map[string]Processor[Limit]
2526
}
2627

2728
type ExportRequest struct {
28-
IncludeSiteConfig bool `json:"includeSiteConfig"`
29-
IncludeCodeHostConfig bool `json:"includeCodeHostConfig"`
29+
IncludeSiteConfig bool `json:"includeSiteConfig"`
30+
IncludeCodeHostConfig bool `json:"includeCodeHostConfig"`
31+
DBQueries []*DBQueryRequest `json:"dbQueries"`
3032
}
3133

3234
// Export generates and returns a ZIP archive with the data, specified in request.
@@ -50,6 +52,9 @@ func (e *DataExporter) Export(ctx context.Context, request ExportRequest) ([]byt
5052
if request.IncludeCodeHostConfig {
5153
e.configProcessors["codeHostConfig"].Process(ctx, ConfigRequest{}, dir)
5254
}
55+
for _, dbQuery := range request.DBQueries {
56+
e.dbProcessors[dbQuery.TableName].Process(ctx, dbQuery.Count, dir)
57+
}
5358

5459
// 3) after all request parts are processed, zip the tmp dir and return its bytes
5560
var buf bytes.Buffer

0 commit comments

Comments
 (0)