add operation results structs (#253)
* add operation results structs Operations, both backup and restore, need to hold the results of their operation, and be able to marshal the struct to json for output.
This commit is contained in:
parent
ed3844b714
commit
abc8b44718
@ -13,26 +13,34 @@ import (
|
|||||||
// BackupOperation wraps an operation with backup-specific props.
|
// BackupOperation wraps an operation with backup-specific props.
|
||||||
type BackupOperation struct {
|
type BackupOperation struct {
|
||||||
operation
|
operation
|
||||||
Version string
|
|
||||||
|
Results BackupResults `json:"results"`
|
||||||
|
Targets []string `json:"selectors"` // todo: replace with Selectors
|
||||||
|
Version string `json:"version"`
|
||||||
|
|
||||||
account account.Account
|
account account.Account
|
||||||
|
}
|
||||||
|
|
||||||
Targets []string // something for targets/filter/source/app&users/etc
|
// BackupResults aggregate the details of the result of the operation.
|
||||||
|
type BackupResults struct {
|
||||||
|
summary
|
||||||
|
metrics
|
||||||
|
// todo: RestorePoint RestorePoint
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBackupOperation constructs and validates a backup operation.
|
// NewBackupOperation constructs and validates a backup operation.
|
||||||
func NewBackupOperation(
|
func NewBackupOperation(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
opts OperationOpts,
|
opts Options,
|
||||||
kw *kopia.KopiaWrapper,
|
kw *kopia.KopiaWrapper,
|
||||||
acct account.Account,
|
acct account.Account,
|
||||||
targets []string,
|
targets []string,
|
||||||
) (BackupOperation, error) {
|
) (BackupOperation, error) {
|
||||||
op := BackupOperation{
|
op := BackupOperation{
|
||||||
operation: newOperation(opts, kw),
|
operation: newOperation(opts, kw),
|
||||||
|
Targets: targets,
|
||||||
Version: "v0",
|
Version: "v0",
|
||||||
account: acct,
|
account: acct,
|
||||||
Targets: targets,
|
|
||||||
}
|
}
|
||||||
if err := op.validate(); err != nil {
|
if err := op.validate(); err != nil {
|
||||||
return BackupOperation{}, err
|
return BackupOperation{}, err
|
||||||
|
|||||||
@ -43,20 +43,20 @@ func (suite *BackupOpIntegrationSuite) TestNewBackupOperation() {
|
|||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
opts operations.OperationOpts
|
opts operations.Options
|
||||||
kw *kopia.KopiaWrapper
|
kw *kopia.KopiaWrapper
|
||||||
acct account.Account
|
acct account.Account
|
||||||
targets []string
|
targets []string
|
||||||
errCheck assert.ErrorAssertionFunc
|
errCheck assert.ErrorAssertionFunc
|
||||||
}{
|
}{
|
||||||
{"good", operations.OperationOpts{}, kw, acct, nil, assert.NoError},
|
{"good", operations.Options{}, kw, acct, nil, assert.NoError},
|
||||||
{"missing kopia", operations.OperationOpts{}, nil, acct, nil, assert.Error},
|
{"missing kopia", operations.Options{}, nil, acct, nil, assert.Error},
|
||||||
}
|
}
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
_, err := operations.NewBackupOperation(
|
_, err := operations.NewBackupOperation(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
operations.OperationOpts{},
|
operations.Options{},
|
||||||
test.kw,
|
test.kw,
|
||||||
test.acct,
|
test.acct,
|
||||||
nil)
|
nil)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
multierror "github.com/hashicorp/go-multierror"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/alcionai/corso/internal/kopia"
|
"github.com/alcionai/corso/internal/kopia"
|
||||||
@ -18,35 +19,38 @@ const (
|
|||||||
Failed
|
Failed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------
|
||||||
|
// Operation Core
|
||||||
|
// --------------------------------------------------------------------------------
|
||||||
|
|
||||||
// An operation tracks the in-progress workload of some long-running process.
|
// An operation tracks the in-progress workload of some long-running process.
|
||||||
// Specific processes (eg: backups, restores, etc) are expected to wrap operation
|
// Specific processes (eg: backups, restores, etc) are expected to wrap operation
|
||||||
// with process specific details.
|
// with process specific details.
|
||||||
type operation struct {
|
type operation struct {
|
||||||
ID uuid.UUID // system generated identifier
|
ID uuid.UUID `json:"id"` // system generated identifier
|
||||||
CreatedAt time.Time // datetime of the operation's creation
|
CreatedAt time.Time `json:"createdAt"` // datetime of the operation's creation
|
||||||
|
Options Options `json:"options"`
|
||||||
|
Status opStatus `json:"status"`
|
||||||
|
|
||||||
options OperationOpts
|
kopia *kopia.KopiaWrapper
|
||||||
kopia *kopia.KopiaWrapper
|
|
||||||
|
|
||||||
Status opStatus
|
|
||||||
Errors []error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OperationOpts configure some parameters of the operation
|
// Options configure some parameters of the operation
|
||||||
type OperationOpts struct {
|
type Options struct {
|
||||||
|
// todo: collision handling
|
||||||
|
// todo: fast fail vs best attempt
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOperation(
|
func newOperation(
|
||||||
opts OperationOpts,
|
opts Options,
|
||||||
kw *kopia.KopiaWrapper,
|
kw *kopia.KopiaWrapper,
|
||||||
) operation {
|
) operation {
|
||||||
return operation{
|
return operation{
|
||||||
ID: uuid.New(),
|
ID: uuid.New(),
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
options: opts,
|
Options: opts,
|
||||||
kopia: kw,
|
kopia: kw,
|
||||||
Status: InProgress,
|
Status: InProgress,
|
||||||
Errors: []error{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,3 +60,22 @@ func (op operation) validate() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------
|
||||||
|
// Results
|
||||||
|
// --------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Summary tracks the total files touched and errors produced
|
||||||
|
// during an operation.
|
||||||
|
type summary struct {
|
||||||
|
ItemsRead int `json:"itemsRead,omitempty"`
|
||||||
|
ItemsWritten int `json:"itemsWritten,omitempty"`
|
||||||
|
ReadErrors multierror.Error `json:"readErrors,omitempty"`
|
||||||
|
WriteErrors multierror.Error `json:"writeErrors,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metrics tracks performance details such as timing, throughput, etc.
|
||||||
|
type metrics struct {
|
||||||
|
StartedAt time.Time `json:"startedAt"`
|
||||||
|
CompletedAt time.Time `json:"completedAt"`
|
||||||
|
}
|
||||||
|
|||||||
@ -19,8 +19,7 @@ func TestOperationSuite(t *testing.T) {
|
|||||||
|
|
||||||
func (suite *OperationSuite) TestNewOperation() {
|
func (suite *OperationSuite) TestNewOperation() {
|
||||||
t := suite.T()
|
t := suite.T()
|
||||||
op := newOperation(OperationOpts{}, nil)
|
op := newOperation(Options{}, nil)
|
||||||
assert.NotNil(t, op.Errors)
|
|
||||||
assert.NotNil(t, op.ID)
|
assert.NotNil(t, op.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +35,7 @@ func (suite *OperationSuite) TestOperation_Validate() {
|
|||||||
}
|
}
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
op := newOperation(OperationOpts{}, test.kw)
|
op := newOperation(Options{}, test.kw)
|
||||||
test.errCheck(t, op.validate())
|
test.errCheck(t, op.validate())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,18 +13,25 @@ import (
|
|||||||
// RestoreOperation wraps an operation with restore-specific props.
|
// RestoreOperation wraps an operation with restore-specific props.
|
||||||
type RestoreOperation struct {
|
type RestoreOperation struct {
|
||||||
operation
|
operation
|
||||||
Version string
|
|
||||||
|
|
||||||
restorePointID string
|
RestorePointID string `json:"restorePointID"`
|
||||||
account account.Account
|
Results RestoreResults `json:"results"`
|
||||||
|
Targets []string `json:"selectors"` // todo: replace with Selectors
|
||||||
|
Version string `json:"bersion"`
|
||||||
|
|
||||||
Targets []string // something for targets/filter/source/app&users/etc
|
account account.Account
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreResults aggregate the details of the results of the operation.
|
||||||
|
type RestoreResults struct {
|
||||||
|
summary
|
||||||
|
metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRestoreOperation constructs and validates a restore operation.
|
// NewRestoreOperation constructs and validates a restore operation.
|
||||||
func NewRestoreOperation(
|
func NewRestoreOperation(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
opts OperationOpts,
|
opts Options,
|
||||||
kw *kopia.KopiaWrapper,
|
kw *kopia.KopiaWrapper,
|
||||||
acct account.Account,
|
acct account.Account,
|
||||||
restorePointID string,
|
restorePointID string,
|
||||||
@ -32,10 +39,10 @@ func NewRestoreOperation(
|
|||||||
) (RestoreOperation, error) {
|
) (RestoreOperation, error) {
|
||||||
op := RestoreOperation{
|
op := RestoreOperation{
|
||||||
operation: newOperation(opts, kw),
|
operation: newOperation(opts, kw),
|
||||||
|
RestorePointID: restorePointID,
|
||||||
|
Targets: targets,
|
||||||
Version: "v0",
|
Version: "v0",
|
||||||
account: acct,
|
account: acct,
|
||||||
restorePointID: restorePointID,
|
|
||||||
Targets: targets,
|
|
||||||
}
|
}
|
||||||
if err := op.validate(); err != nil {
|
if err := op.validate(); err != nil {
|
||||||
return RestoreOperation{}, err
|
return RestoreOperation{}, err
|
||||||
@ -51,7 +58,7 @@ func (op RestoreOperation) validate() error {
|
|||||||
// Run begins a synchronous restore operation.
|
// Run begins a synchronous restore operation.
|
||||||
// todo (keepers): return stats block in first param.
|
// todo (keepers): return stats block in first param.
|
||||||
func (op *RestoreOperation) Run(ctx context.Context) error {
|
func (op *RestoreOperation) Run(ctx context.Context) error {
|
||||||
dc, err := op.kopia.RestoreSingleItem(ctx, op.restorePointID, op.Targets)
|
dc, err := op.kopia.RestoreSingleItem(ctx, op.RestorePointID, op.Targets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "retrieving service data")
|
return errors.Wrap(err, "retrieving service data")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,20 +37,20 @@ func (suite *RestoreOpIntegrationSuite) TestNewRestoreOperation() {
|
|||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
opts operations.OperationOpts
|
opts operations.Options
|
||||||
kw *kopia.KopiaWrapper
|
kw *kopia.KopiaWrapper
|
||||||
acct account.Account
|
acct account.Account
|
||||||
targets []string
|
targets []string
|
||||||
errCheck assert.ErrorAssertionFunc
|
errCheck assert.ErrorAssertionFunc
|
||||||
}{
|
}{
|
||||||
{"good", operations.OperationOpts{}, kw, acct, nil, assert.NoError},
|
{"good", operations.Options{}, kw, acct, nil, assert.NoError},
|
||||||
{"missing kopia", operations.OperationOpts{}, nil, acct, nil, assert.Error},
|
{"missing kopia", operations.Options{}, nil, acct, nil, assert.Error},
|
||||||
}
|
}
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
_, err := operations.NewRestoreOperation(
|
_, err := operations.NewRestoreOperation(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
operations.OperationOpts{},
|
operations.Options{},
|
||||||
test.kw,
|
test.kw,
|
||||||
test.acct,
|
test.acct,
|
||||||
"restore-point-id",
|
"restore-point-id",
|
||||||
|
|||||||
@ -94,7 +94,7 @@ func (r *Repository) Close(ctx context.Context) error {
|
|||||||
func (r Repository) NewBackup(ctx context.Context, targets []string) (operations.BackupOperation, error) {
|
func (r Repository) NewBackup(ctx context.Context, targets []string) (operations.BackupOperation, error) {
|
||||||
return operations.NewBackupOperation(
|
return operations.NewBackupOperation(
|
||||||
ctx,
|
ctx,
|
||||||
operations.OperationOpts{},
|
operations.Options{},
|
||||||
r.dataLayer,
|
r.dataLayer,
|
||||||
r.Account,
|
r.Account,
|
||||||
targets)
|
targets)
|
||||||
@ -104,7 +104,7 @@ func (r Repository) NewBackup(ctx context.Context, targets []string) (operations
|
|||||||
func (r Repository) NewRestore(ctx context.Context, restorePointID string, targets []string) (operations.RestoreOperation, error) {
|
func (r Repository) NewRestore(ctx context.Context, restorePointID string, targets []string) (operations.RestoreOperation, error) {
|
||||||
return operations.NewRestoreOperation(
|
return operations.NewRestoreOperation(
|
||||||
ctx,
|
ctx,
|
||||||
operations.OperationOpts{},
|
operations.Options{},
|
||||||
r.dataLayer,
|
r.dataLayer,
|
||||||
r.Account,
|
r.Account,
|
||||||
restorePointID,
|
restorePointID,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user