Skip to content

Commit 35fdde3

Browse files
committed
added snapshot
1 parent 5dafda7 commit 35fdde3

File tree

13 files changed

+300
-63
lines changed

13 files changed

+300
-63
lines changed

splitio/admin/admin.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func NewServer(options *Options) (*AdminServer, error) {
9696
observabilityController.Register(admin)
9797

9898
if options.Snapshotter != nil {
99-
snapshotController := controllers.NewSnapshotController(options.Logger, options.Snapshotter)
99+
snapshotController := controllers.NewSnapshotController(options.Logger, options.Snapshotter, options.FlagSpecVersion)
100100
snapshotController.Register(admin)
101101
}
102102

splitio/admin/controllers/dashboard.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,5 +166,6 @@ func (c *DashboardController) gatherStats() *dashboard.GlobalStats {
166166
LoggedMessages: errorMessages,
167167
Uptime: int64(c.runtime.Uptime().Seconds()),
168168
FlagSets: getFlagSetsInfo(c.storages.SplitStorage),
169+
RuleBasedSegments: bundleRBInfo(c.storages.RuleBasedSegmentsStorage),
169170
}
170171
}

splitio/admin/controllers/helpers.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,22 @@ func getProxyRequestCount(metrics storage.TelemetryRuntimeConsumer) (ok int64, e
316316

317317
return okCount, errorCount
318318
}
319+
320+
func bundleRBInfo(rbStorage storage.RuleBasedSegmentsStorage) []dashboard.RBSummary {
321+
all := rbStorage.All()
322+
summaries := make([]dashboard.RBSummary, 0, len(all))
323+
for _, segment := range all {
324+
excludedSegments := make([]string, 0, len(segment.Excluded.Segments))
325+
for _, seg := range segment.Excluded.Segments {
326+
excludedSegments = append(excludedSegments, seg.Name)
327+
}
328+
summaries = append(summaries, dashboard.RBSummary{
329+
Name: segment.Name,
330+
ChangeNumber: segment.ChangeNumber,
331+
Active: segment.Status == "ACTIVE",
332+
ExcludedKeys: segment.Excluded.Keys,
333+
ExcludedSegments: excludedSegments,
334+
})
335+
}
336+
return summaries
337+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package controllers
2+
3+
import (
4+
"testing"
5+
6+
"github.com/splitio/go-split-commons/v8/dtos"
7+
"github.com/splitio/go-split-commons/v8/storage/mocks"
8+
"github.com/splitio/split-synchronizer/v5/splitio/admin/views/dashboard"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestBundleRBInfo(t *testing.T) {
13+
rb := &mocks.MockRuleBasedSegmentStorage{}
14+
rb.On("All").Return([]dtos.RuleBasedSegmentDTO{
15+
{Name: "rb1", ChangeNumber: 1, Status: "ACTIVE", Excluded: dtos.ExcludedDTO{Keys: []string{"one"}}},
16+
{Name: "rb2", ChangeNumber: 2, Status: "ARCHIVED"},
17+
}, nil)
18+
result := bundleRBInfo(rb)
19+
assert.Len(t, result, 2)
20+
assert.ElementsMatch(t, result, []dashboard.RBSummary{
21+
{Name: "rb1", ChangeNumber: 1, Active: true, ExcludedKeys: []string{"one"}, ExcludedSegments: []string{}},
22+
{Name: "rb2", ChangeNumber: 2, Active: false, ExcludedKeys: nil, ExcludedSegments: []string{}},
23+
})
24+
}

splitio/admin/controllers/snapshot.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ import (
1414

1515
// SnapshotController bundles endpoints associated to snapshot management
1616
type SnapshotController struct {
17-
logger logging.LoggerInterface
18-
db storage.Snapshotter
17+
logger logging.LoggerInterface
18+
db storage.Snapshotter
19+
version string
1920
}
2021

2122
// NewSnapshotController constructs a new snapshot controller
22-
func NewSnapshotController(logger logging.LoggerInterface, db storage.Snapshotter) *SnapshotController {
23-
return &SnapshotController{logger: logger, db: db}
23+
func NewSnapshotController(logger logging.LoggerInterface, db storage.Snapshotter, version string) *SnapshotController {
24+
return &SnapshotController{logger: logger, db: db, version: version}
2425
}
2526

2627
// Register mounts the endpoints int he provided router
@@ -38,7 +39,7 @@ func (c *SnapshotController) downloadSnapshot(ctx *gin.Context) {
3839
return
3940
}
4041

41-
s, err := snapshot.New(snapshot.Metadata{Version: 1, Storage: snapshot.StorageBoltDB}, b)
42+
s, err := snapshot.New(snapshot.Metadata{Version: 1, Storage: snapshot.StorageBoltDB, SpecVersion: c.version}, b)
4243
if err != nil {
4344
c.logger.Error("error building snapshot: ", err)
4445
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "error building snapshot"})

splitio/admin/controllers/snapshot_test.go

Lines changed: 15 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package controllers
22

33
import (
44
"bytes"
5-
"io/ioutil"
5+
"io"
66
"net/http"
77
"net/http/httptest"
88
"testing"
@@ -13,31 +13,23 @@ import (
1313
"github.com/splitio/go-toolkit/v5/logging"
1414

1515
"github.com/gin-gonic/gin"
16+
"github.com/stretchr/testify/assert"
1617
)
1718

1819
func TestDownloadProxySnapshot(t *testing.T) {
1920
// Read DB snapshot for test
2021
path := "../../../test/snapshot/proxy.snapshot"
2122
snap, err := snapshot.DecodeFromFile(path)
22-
if err != nil {
23-
t.Error(err)
24-
return
25-
}
23+
assert.Nil(t, err)
2624

2725
tmpDataFile, err := snap.WriteDataToTmpFile()
28-
if err != nil {
29-
t.Error(err)
30-
return
31-
}
26+
assert.Nil(t, err)
3227

3328
// loading snapshot from disk
3429
dbInstance, err := persistent.NewBoltWrapper(tmpDataFile, nil)
35-
if err != nil {
36-
t.Error(err)
37-
return
38-
}
30+
assert.Nil(t, err)
3931

40-
ctrl := NewSnapshotController(logging.NewLogger(nil), dbInstance)
32+
ctrl := NewSnapshotController(logging.NewLogger(nil), dbInstance, "1.3")
4133

4234
resp := httptest.NewRecorder()
4335
ctx, router := gin.CreateTestContext(resp)
@@ -46,35 +38,19 @@ func TestDownloadProxySnapshot(t *testing.T) {
4638
ctx.Request, _ = http.NewRequest(http.MethodGet, "/snapshot", nil)
4739
router.ServeHTTP(resp, ctx.Request)
4840

49-
responseBody, err := ioutil.ReadAll(resp.Body)
50-
if err != nil {
51-
t.Error(err)
52-
return
53-
}
41+
responseBody, err := io.ReadAll(resp.Body)
42+
assert.Nil(t, err)
5443

5544
snapRes, err := snapshot.Decode(responseBody)
56-
if err != nil {
57-
t.Error(err)
58-
return
59-
}
45+
assert.Nil(t, err)
6046

61-
if snapRes.Meta().Version != 1 {
62-
t.Error("Invalid Metadata version")
63-
}
64-
65-
if snapRes.Meta().Storage != 1 {
66-
t.Error("Invalid Metadata storage")
67-
}
47+
assert.Equal(t, uint64(1), snapRes.Meta().Version)
48+
assert.Equal(t, uint64(1), snapRes.Meta().Storage)
49+
assert.Equal(t, "1.3", snapRes.Meta().SpecVersion)
6850

6951
dat, err := snap.Data()
70-
if err != nil {
71-
t.Error(err)
72-
}
52+
assert.Nil(t, err)
7353
resData, err := snapRes.Data()
74-
if err != nil {
75-
t.Error(err)
76-
}
77-
if bytes.Compare(dat, resData) != 0 {
78-
t.Error("loaded snapshot is different to downloaded")
79-
}
54+
assert.Nil(t, err)
55+
assert.Equal(t, 0, bytes.Compare(dat, resData))
8056
}

splitio/admin/views/dashboard/main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ type GlobalStats struct {
108108
EventsLambda float64 `json:"eventsLambda"`
109109
Uptime int64 `json:"uptime"`
110110
FlagSets []FlagSetsSummary `json:"flagSets"`
111+
RuleBasedSegments []RBSummary `json:"ruleBasedSegments"`
111112
}
112113

113114
// SplitSummary encapsulates a minimalistic view of feature flag properties to be presented in the dashboard
@@ -151,6 +152,14 @@ type FlagSetsSummary struct {
151152
FeatureFlags string `json:"featureFlags"`
152153
}
153154

155+
type RBSummary struct {
156+
Name string `json:"name"`
157+
ChangeNumber int64 `json:"cn"`
158+
Active bool `json:"active"`
159+
ExcludedKeys []string `json:"excludedKeys"`
160+
ExcludedSegments []string `json:"excludedSegments"`
161+
}
162+
154163
// RGBA bundles input to CSS's rgba function
155164
type RGBA struct {
156165
Red int32

splitio/commitversion.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ This file is created automatically, please do not edit
55
*/
66

77
// CommitVersion is the version of the last commit previous to release
8-
const CommitVersion = "1fbc498"
8+
const CommitVersion = "5dafda7"

splitio/common/snapshot/snapshot.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/gob"
88
"errors"
99
"fmt"
10+
"io"
1011
"io/ioutil"
1112
"os"
1213
"path/filepath"
@@ -38,8 +39,9 @@ var ErrMetadataRead = errors.New("snapshot metadata cannot be decoded")
3839

3940
// Metadata represents the Snapshot metadata object
4041
type Metadata struct {
41-
Version uint64
42-
Storage uint64
42+
Version uint64
43+
Storage uint64
44+
SpecVersion string
4345
}
4446

4547
// Snapshot represents a snapshot struct with metadata and data
@@ -71,7 +73,7 @@ func (s *Snapshot) Meta() Metadata {
7173
func (s *Snapshot) Data() ([]byte, error) {
7274
gz, err := gzip.NewReader(bytes.NewBuffer(s.data))
7375
defer gz.Close()
74-
data, err := ioutil.ReadAll(gz)
76+
data, err := io.ReadAll(gz)
7577
if err != nil {
7678
return nil, fmt.Errorf("error reading gzip data: %w", err)
7779
}
@@ -80,11 +82,12 @@ func (s *Snapshot) Data() ([]byte, error) {
8082

8183
// Encode returns the bytes slice snapshot representation
8284
// Snapshot Layout:
83-
// |metadata-size|metadata|data|
8485
//
85-
// metadata-size: uint64 (8 bytes) specifies the amount of metadata bytes
86-
// metadata: Gob encoded of Metadata struct
87-
// data: Proxy data, byte slice. The Metadata have information about it, Storage, Gzipped and version.
86+
// |metadata-size|metadata|data|
87+
//
88+
// metadata-size: uint64 (8 bytes) specifies the amount of metadata bytes
89+
// metadata: Gob encoded of Metadata struct
90+
// data: Proxy data, byte slice. The Metadata have information about it, Storage, Gzipped and version.
8891
func (s *Snapshot) Encode() ([]byte, error) {
8992

9093
metaBytes, err := metaToBytes(s.meta)

splitio/proxy/initialization.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func Start(logger logging.LoggerInterface, cfg *pconf.Main) error {
8484

8585
// Proxy storages already implement the observable interface, so no need to wrap them
8686
splitStorage := storage.NewProxySplitStorage(dbInstance, logger, flagsets.NewFlagSetFilter(cfg.FlagSetsFilter), cfg.Initialization.Snapshot != "")
87-
ruleBasedStorage := storage.NewProxyRuleBasedSegmentsStorage(logger)
87+
ruleBasedStorage := storage.NewProxyRuleBasedSegmentsStorage(dbInstance, logger, cfg.Initialization.Snapshot != "")
8888
segmentStorage := storage.NewProxySegmentStorage(dbInstance, logger, cfg.Initialization.Snapshot != "")
8989
largeSegmentStorage := inmemory.NewLargeSegmentsStorage()
9090

@@ -208,10 +208,11 @@ func Start(logger logging.LoggerInterface, cfg *pconf.Main) error {
208208

209209
rtm := common.NewRuntime(false, syncManager, logger, "Split Proxy", nil, nil, appMonitor, servicesMonitor)
210210
storages := adminCommon.Storages{
211-
SplitStorage: splitStorage,
212-
SegmentStorage: segmentStorage,
213-
LocalTelemetryStorage: localTelemetryStorage,
214-
LargeSegmentStorage: largeSegmentStorage,
211+
SplitStorage: splitStorage,
212+
SegmentStorage: segmentStorage,
213+
LocalTelemetryStorage: localTelemetryStorage,
214+
LargeSegmentStorage: largeSegmentStorage,
215+
RuleBasedSegmentsStorage: ruleBasedStorage,
215216
}
216217

217218
// --------------------------- ADMIN DASHBOARD ------------------------------

0 commit comments

Comments
 (0)