-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
instance: add migration System (#1312)
* migration: add initial skeleton * make etcd tracing better * mostly make it work? * test * fix * get cluster version * fix version * fix * add tests for iml * show coverage * add cleanup * add CI to build web for bundle analysis * exclude api files from coverage * fix * fix trace
- Loading branch information
Showing
19 changed files
with
525 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package log_iml_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"beryju.io/gravity/pkg/extconfig" | ||
"beryju.io/gravity/pkg/extconfig/log_iml" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestInMemoryLogger(t *testing.T) { | ||
iml := log_iml.Get() | ||
iml.Flush() | ||
extconfig.Get().Logger().Debug("test") | ||
msgs := iml.Messages() | ||
assert.Len(t, msgs, 1) | ||
} | ||
|
||
func TestInMemoryLogger_Trunc(t *testing.T) { | ||
iml := log_iml.Get() | ||
iml.Flush() | ||
for i := 0; i <= iml.MaxSize(); i++ { | ||
extconfig.Get().Logger().Debug("test") | ||
} | ||
// Log one more message | ||
extconfig.Get().Logger().Debug("test") | ||
msgs := iml.Messages() | ||
assert.Len(t, msgs, iml.MaxSize()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package migrate | ||
|
||
import ( | ||
"context" | ||
|
||
"beryju.io/gravity/pkg/storage" | ||
"github.com/Masterminds/semver/v3" | ||
) | ||
|
||
func MustParseConstraint(input string) *semver.Constraints { | ||
c, err := semver.NewConstraint(input) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return c | ||
} | ||
|
||
type InlineMigration struct { | ||
MigrationName string | ||
ActivateOnVersion *semver.Constraints | ||
HookFunc func(context.Context) (*storage.Client, error) | ||
CleanupFunc func(context.Context) error | ||
} | ||
|
||
func (im *InlineMigration) Name() string { | ||
return im.MigrationName | ||
} | ||
|
||
func (im *InlineMigration) Check(clusterVersion *semver.Version, ctx context.Context) (bool, error) { | ||
check := im.ActivateOnVersion.Check(clusterVersion) | ||
return check, nil | ||
} | ||
|
||
func (im *InlineMigration) Hook(ctx context.Context) (*storage.Client, error) { | ||
return im.HookFunc(ctx) | ||
} | ||
|
||
func (im *InlineMigration) Cleanup(ctx context.Context) error { | ||
if im.CleanupFunc != nil { | ||
return im.CleanupFunc(ctx) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package migrate | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"sort" | ||
|
||
"beryju.io/gravity/pkg/extconfig" | ||
"beryju.io/gravity/pkg/instance/types" | ||
"beryju.io/gravity/pkg/roles" | ||
"beryju.io/gravity/pkg/storage" | ||
"github.com/Masterminds/semver/v3" | ||
clientv3 "go.etcd.io/etcd/client/v3" | ||
"go.uber.org/zap" | ||
) | ||
|
||
type Migrator struct { | ||
ri roles.Instance | ||
log *zap.Logger | ||
migrations []roles.Migration | ||
} | ||
|
||
func New(ri roles.Instance) *Migrator { | ||
return &Migrator{ | ||
ri: ri, | ||
log: ri.Log().Named("migrator"), | ||
migrations: make([]roles.Migration, 0), | ||
} | ||
} | ||
|
||
func (mi *Migrator) GetClusterVersion() (*semver.Version, error) { | ||
type partialInstanceInfo struct { | ||
Version string `json:"version" required:"true"` | ||
} | ||
instances, err := mi.ri.KV().Get( | ||
context.Background(), | ||
mi.ri.KV().Key( | ||
types.KeyInstance, | ||
).Prefix(true).String(), | ||
clientv3.WithPrefix(), | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// Gather all instances in the cluster and parse their versions | ||
version := []*semver.Version{} | ||
for _, inst := range instances.Kvs { | ||
pi := partialInstanceInfo{} | ||
err = json.Unmarshal(inst.Value, &pi) | ||
if err != nil { | ||
mi.log.Warn("failed to parse instance info", zap.Error(err)) | ||
continue | ||
} | ||
v, err := semver.NewVersion(pi.Version) | ||
if err != nil { | ||
mi.log.Warn("failed to parse instance version", zap.Error(err)) | ||
continue | ||
} | ||
version = append(version, v) | ||
} | ||
sort.Sort(semver.Collection(version)) | ||
if len(version) < 1 { | ||
return semver.MustParse(extconfig.FullVersion()), nil | ||
} | ||
return version[0], nil | ||
} | ||
|
||
func (mi *Migrator) Run(ctx context.Context) (*storage.Client, error) { | ||
cv, err := mi.GetClusterVersion() | ||
if err != nil { | ||
return nil, err | ||
} | ||
mi.log.Debug("Checking migrations to activate for cluster version", zap.String("clusterVersion", cv.String())) | ||
cli := mi.ri.KV() | ||
for _, m := range mi.migrations { | ||
mi.log.Debug("Checking if migration needs to be run", zap.String("migration", m.Name())) | ||
enabled, err := m.Check(cv, ctx) | ||
if err != nil { | ||
mi.log.Warn("failed to check if migration should be enabled", zap.String("migration", m.Name()), zap.Error(err)) | ||
return nil, err | ||
} | ||
if enabled { | ||
_cli, err := m.Hook(ctx) | ||
if err != nil { | ||
mi.log.Warn("failed to hook for migration", zap.String("migration", m.Name()), zap.Error(err)) | ||
return nil, err | ||
} | ||
mi.log.Info("Enabling migration", zap.String("migration", m.Name())) | ||
cli = _cli | ||
} else { | ||
mi.log.Info("Running cleanup for migration", zap.String("migration", m.Name())) | ||
err := m.Cleanup(ctx) | ||
if err != nil { | ||
mi.log.Warn("failed to cleanup migration", zap.String("migration", m.Name()), zap.Error(err)) | ||
continue | ||
} | ||
} | ||
} | ||
return cli, nil | ||
} | ||
|
||
func (mi *Migrator) AddMigration(migration roles.Migration) { | ||
mi.migrations = append(mi.migrations, migration) | ||
} |
Oops, something went wrong.