From 95970bc9866abddaf51f45cb81477eb30ca2e82e Mon Sep 17 00:00:00 2001 From: Nguyen Marc Date: Wed, 31 Jan 2024 19:28:40 +0100 Subject: [PATCH] refactor(cli): moved types accordingly --- cli/.mockery.yaml | 6 +- cli/cmd/job/job.go | 3 +- cli/cmd/provider/provider.go | 10 +- cli/cmd/submit/submit.go | 21 +- cli/deepsquare/deepsquare_client.go | 135 +++++++++--- cli/metascheduler/metascheduler_jobfetcher.go | 15 +- .../metascheduler_jobs_by_provider_fetcher.go | 15 +- ...scheduler_jobs_by_provider_fetcher_test.go | 13 +- .../metascheduler_jobscheduler.go | 18 +- cli/metascheduler/metascheduler_oracle.go | 4 +- .../metascheduler_oracle_integration_test.go | 4 +- .../metascheduler_providermanager.go | 137 +++++++++--- cli/metascheduler/metascheduler_rpc.go | 23 +- cli/metascheduler/metascheduler_ws.go | 10 +- cli/mocks/mockjob/Fetcher_mock.go | 148 +++++++++++++ .../mockjob/MetaScheduledIdsFetcher_mock.go | 90 ++++++++ cli/mocks/mocktypes/JobFetcher_mock.go | 146 ------------- .../MetaScheduledJobsIdsFetcher_mock.go | 90 -------- cli/tui/editor/editor_model.go | 10 +- cli/tui/nav/nav.go | 5 +- cli/tui/provider/details/details_model.go | 4 +- .../provider/details/details_model_builder.go | 16 +- cli/tui/provider/details/details_view.go | 2 +- cli/tui/provider/provider_model.go | 12 +- cli/tui/provider/provider_model_builder.go | 4 +- cli/tui/status/log/log_model.go | 5 +- .../status/log/log_watch_transition_model.go | 3 +- cli/tui/status/status_model.go | 12 +- cli/tui/status/status_watch_jobs_model.go | 5 +- .../status/topup/topup_watch_job_status.go | 3 +- cli/types/allowance/allowance.go | 27 +++ cli/types/credit/credit.go | 28 +++ cli/types/event/event_subscriber.go | 61 ++++++ cli/types/job/job.go | 86 ++++++++ cli/types/provider/provider.go | 56 +++++ cli/types/types.go | 205 ------------------ 36 files changed, 833 insertions(+), 599 deletions(-) create mode 100644 cli/mocks/mockjob/Fetcher_mock.go create mode 100644 cli/mocks/mockjob/MetaScheduledIdsFetcher_mock.go delete mode 100644 cli/mocks/mocktypes/JobFetcher_mock.go delete mode 100644 cli/mocks/mocktypes/MetaScheduledJobsIdsFetcher_mock.go create mode 100644 cli/types/allowance/allowance.go create mode 100644 cli/types/credit/credit.go create mode 100644 cli/types/event/event_subscriber.go create mode 100644 cli/types/job/job.go create mode 100644 cli/types/provider/provider.go diff --git a/cli/.mockery.yaml b/cli/.mockery.yaml index acc2e36f..c2352620 100644 --- a/cli/.mockery.yaml +++ b/cli/.mockery.yaml @@ -4,7 +4,7 @@ dir: 'mocks/mock{{.PackageName}}' mockname: '{{.InterfaceName}}' outpkg: 'mock{{.PackageName}}' packages: - github.com/deepsquare-io/grid/cli/types: + github.com/deepsquare-io/grid/cli/types/job: interfaces: - MetaScheduledJobsIdsFetcher: - JobFetcher: + MetaScheduledIdsFetcher: + Fetcher: diff --git a/cli/cmd/job/job.go b/cli/cmd/job/job.go index 27680e81..f0b4ac90 100644 --- a/cli/cmd/job/job.go +++ b/cli/cmd/job/job.go @@ -47,6 +47,7 @@ import ( "github.com/deepsquare-io/grid/cli/internal/utils" "github.com/deepsquare-io/grid/cli/metascheduler" "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/event" "github.com/erikgeiser/promptkit/confirmation" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -263,7 +264,7 @@ var Command = cli.Command{ transitions := make(chan types.JobTransition, 1) sub, err := watcher.SubscribeEvents( ctx, - types.FilterJobTransition(transitions), + event.FilterJobTransition(transitions), ) if err != nil { return err diff --git a/cli/cmd/provider/provider.go b/cli/cmd/provider/provider.go index f8015f43..c7f696d1 100644 --- a/cli/cmd/provider/provider.go +++ b/cli/cmd/provider/provider.go @@ -38,7 +38,7 @@ import ( "github.com/deepsquare-io/grid/cli/deepsquare" "github.com/deepsquare-io/grid/cli/internal/utils" "github.com/deepsquare-io/grid/cli/metascheduler" - "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/provider" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" @@ -128,9 +128,9 @@ var Command = cli.Command{ MetaschedulerAddress: common.HexToAddress(metaschedulerSmartContract), ChainID: chainID, }) - opts := make([]types.GetProviderOption, 0) + opts := make([]provider.GetProviderOption, 0) if proposal { - opts = append(opts, types.WithProposal()) + opts = append(opts, provider.WithProposal()) } providers, err := clientset.ProviderManager().GetProviders(ctx, opts...) if err != nil { @@ -155,7 +155,7 @@ var Command = cli.Command{ return err } providerAddress := common.HexToAddress(cCtx.Args().First()) - return clientset.ProviderManager().Approve(cCtx.Context, providerAddress) + return clientset.ProviderManager().ApproveProvider(cCtx.Context, providerAddress) }, }, { @@ -169,7 +169,7 @@ var Command = cli.Command{ return err } providerAddress := common.HexToAddress(cCtx.Args().First()) - return clientset.ProviderManager().Remove(cCtx.Context, providerAddress) + return clientset.ProviderManager().RemoveProvider(cCtx.Context, providerAddress) }, }, }, diff --git a/cli/cmd/submit/submit.go b/cli/cmd/submit/submit.go index c471a7aa..29325c73 100644 --- a/cli/cmd/submit/submit.go +++ b/cli/cmd/submit/submit.go @@ -89,6 +89,9 @@ import ( "github.com/deepsquare-io/grid/cli/sbatch" "github.com/deepsquare-io/grid/cli/types" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/deepsquare-io/grid/cli/types/event" + "github.com/deepsquare-io/grid/cli/types/job" + "github.com/deepsquare-io/grid/cli/types/provider" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/urfave/cli/v2" @@ -326,8 +329,8 @@ var Command = cli.Command{ if err != nil { return err } - var job sbatch.Job - if err := yaml.Unmarshal(dat, &job); err != nil { + var j sbatch.Job + if err := yaml.Unmarshal(dat, &j); err != nil { return err } @@ -389,11 +392,11 @@ var Command = cli.Command{ if !watch { jobID, err := client.SubmitJob( ctx, - &job, + &j, credits, jobNameB, - types.WithUse(usesLabels...), - types.WithAffinity(affinities...), + job.WithUse(usesLabels...), + job.WithAffinity(affinities...), ) if err != nil { return err @@ -406,13 +409,13 @@ var Command = cli.Command{ // Watch submit logic transitions := make(chan types.JobTransition, 1) - sub, err := watcher.SubscribeEvents(ctx, types.FilterJobTransition(transitions)) + sub, err := watcher.SubscribeEvents(ctx, event.FilterJobTransition(transitions)) if err != nil { return err } defer sub.Unsubscribe() - jobID, err := client.SubmitJob(ctx, &job, credits, jobNameB, types.WithUse(usesLabels...)) + jobID, err := client.SubmitJob(ctx, &j, credits, jobNameB, job.WithUse(usesLabels...)) if err != nil { return err } @@ -422,7 +425,7 @@ var Command = cli.Command{ fmt.Printf("---Waiting for job %s to be running...---\n", jobIDBig.String()) var finished = false var allocatedProviderAddress common.Address - var provider types.ProviderDetail + var provider provider.Detail msOrSchedLen, runningLen := int64(0), int64(0) // Wait for finished or running loop: @@ -587,7 +590,7 @@ var forbiddenReplacer = strings.NewReplacer( // computeWaitingTime returns min(running) + sum(waiting) func computeWaitingTime( jobID [32]byte, - provider types.ProviderDetail, + provider provider.Detail, jobs []types.Job, ) (time.Duration, error) { var waiting, running time.Duration diff --git a/cli/deepsquare/deepsquare_client.go b/cli/deepsquare/deepsquare_client.go index 7a8e7269..188cbef0 100644 --- a/cli/deepsquare/deepsquare_client.go +++ b/cli/deepsquare/deepsquare_client.go @@ -20,6 +20,7 @@ import ( "crypto/ecdsa" "crypto/tls" "crypto/x509" + "math/big" "net" "net/http" "net/url" @@ -30,6 +31,11 @@ import ( "github.com/deepsquare-io/grid/cli/metascheduler" "github.com/deepsquare-io/grid/cli/sbatch" "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/allowance" + "github.com/deepsquare-io/grid/cli/types/credit" + "github.com/deepsquare-io/grid/cli/types/event" + "github.com/deepsquare-io/grid/cli/types/job" + "github.com/deepsquare-io/grid/cli/types/provider" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" @@ -51,12 +57,12 @@ const ( // Users must call Close() at the end of the application to avoid pending connections. type Client interface { types.Logger - types.JobScheduler - types.JobFetcher - types.JobsByProviderFetcher - types.CreditManager - types.AllowanceManager - types.ProviderManager + job.Scheduler + job.Fetcher + job.ByProviderFetcher + credit.Manager + allowance.Manager + provider.Manager // Close all connections. Close() error } @@ -118,14 +124,87 @@ func (c *ClientConfig) applyDefault() { type client struct { types.Logger - types.JobScheduler - types.JobFetcher - types.JobsByProviderFetcher - types.CreditManager - types.AllowanceManager - types.ProviderManager - loggerConn *grpc.ClientConn - rpcClient *rpc.Client + job.Scheduler + job.Fetcher + job.ByProviderFetcher + CreditManager credit.Manager + AllowanceManager allowance.Manager + ProviderManager provider.Manager + loggerConn *grpc.ClientConn + rpcClient *rpc.Client +} + +// GetProvider implements Client. +func (c *client) GetProvider( + ctx context.Context, + address common.Address, + opts ...provider.GetProviderOption, +) (provider provider.Detail, err error) { + return c.ProviderManager.GetProvider(ctx, address, opts...) +} + +// GetProviders implements Client. +func (c *client) GetProviders( + ctx context.Context, + opts ...provider.GetProviderOption, +) (providers []provider.Detail, err error) { + return c.ProviderManager.GetProviders(ctx, opts...) +} + +// Approve implements Client. +func (c *client) ApproveProvider(ctx context.Context, provider common.Address) error { + return c.ProviderManager.ApproveProvider(ctx, provider) +} + +// Balance implements Client. +func (c *client) Balance(ctx context.Context) (*big.Int, error) { + return c.CreditManager.Balance(ctx) +} + +// BalanceOf implements Client. +func (c *client) BalanceOf(ctx context.Context, address common.Address) (*big.Int, error) { + return c.CreditManager.BalanceOf(ctx, address) +} + +// ClearAllowance implements Client. +func (c *client) ClearAllowance(ctx context.Context) error { + return c.AllowanceManager.ClearAllowance(ctx) +} + +// GetAllowance implements Client. +func (c *client) GetAllowance(ctx context.Context) (*big.Int, error) { + return c.AllowanceManager.GetAllowance(ctx) +} + +// ReduceToAllowance implements Client. +func (c *client) ReduceToAllowance( + ctx context.Context, + approvals <-chan types.Approval, +) (<-chan *big.Int, error) { + return c.AllowanceManager.ReduceToAllowance(ctx, approvals) +} + +// ReduceToBalance implements Client. +func (c *client) ReduceToBalance( + ctx context.Context, + transfers <-chan types.Transfer, +) (<-chan *big.Int, error) { + return c.CreditManager.ReduceToBalance(ctx, transfers) +} + +// RemoveProvider implements Client. +func (c *client) RemoveProvider(ctx context.Context, provider common.Address) error { + return c.ProviderManager.RemoveProvider(ctx, provider) +} + +// SetAllowance implements Client. +func (c *client) SetAllowance(ctx context.Context, amount *big.Int) error { + return c.AllowanceManager.SetAllowance(ctx, amount) +} + +// Transfer implements Client. +func (c *client) Transfer(ctx context.Context, to common.Address, amount *big.Int) error { + return c.CreditManager.Transfer(ctx, to, amount) } // NewClient creates a new Client for the given ClientConfig. @@ -185,15 +264,15 @@ func NewClient(ctx context.Context, c *ClientConfig) (Client, error) { fetcher := rpcClientSet.JobFetcher() runningJobsByProviderFetcher := metascheduler.NewJobsByProviderFetcher(oracle, fetcher) return &client{ - JobFetcher: fetcher, - JobScheduler: jobScheduler, - JobsByProviderFetcher: runningJobsByProviderFetcher, - CreditManager: rpcClientSet.CreditManager(), - AllowanceManager: rpcClientSet.AllowanceManager(), - ProviderManager: rpcClientSet.ProviderManager(), - Logger: logger, - loggerConn: conn, - rpcClient: rpcClient, + Fetcher: fetcher, + Scheduler: jobScheduler, + ByProviderFetcher: runningJobsByProviderFetcher, + CreditManager: rpcClientSet.CreditManager(), + AllowanceManager: rpcClientSet.AllowanceManager(), + ProviderManager: rpcClientSet.ProviderManager(), + Logger: logger, + loggerConn: conn, + rpcClient: rpcClient, }, nil } @@ -206,7 +285,7 @@ func (c *client) Close() error { // // Users must call Close() at the end of the application to avoid pending connections. type Watcher interface { - types.EventSubscriber + event.Subscriber // Close all connections. Close() error } @@ -248,7 +327,7 @@ func (c *WatcherConfig) applyDefault() { } type watcher struct { - types.EventSubscriber + event.Subscriber rpcClient *rpc.Client wsClient *rpc.Client } @@ -283,9 +362,9 @@ func NewWatcher(ctx context.Context, c *WatcherConfig) (Watcher, error) { UserPrivateKey: c.UserPrivateKey, } return &watcher{ - EventSubscriber: metascheduler.NewEventSubscriber(metaschedulerRPC, metaschedulerWS), - rpcClient: rpcClient, - wsClient: wsClient, + Subscriber: metascheduler.NewEventSubscriber(metaschedulerRPC, metaschedulerWS), + rpcClient: rpcClient, + wsClient: wsClient, }, nil } diff --git a/cli/metascheduler/metascheduler_jobfetcher.go b/cli/metascheduler/metascheduler_jobfetcher.go index e9af9f45..44aad44a 100644 --- a/cli/metascheduler/metascheduler_jobfetcher.go +++ b/cli/metascheduler/metascheduler_jobfetcher.go @@ -21,6 +21,7 @@ import ( "github.com/deepsquare-io/grid/cli/types" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/deepsquare-io/grid/cli/types/job" "github.com/ethereum/go-ethereum/accounts/abi/bind" ) @@ -40,7 +41,7 @@ func (c *jobFetcher) GetJob(ctx context.Context, id [32]byte) (types.Job, error) } type jobIterator struct { - types.JobFetcher + job.Fetcher array [][32]byte length int index int @@ -92,7 +93,7 @@ func (it *jobIterator) Error() error { return it.err } -func (c *jobFetcher) GetJobs(ctx context.Context) (types.JobLazyIterator, error) { +func (c *jobFetcher) GetJobs(ctx context.Context) (job.LazyIterator, error) { jobIDs, err := c.GetByCustomer(&bind.CallOpts{ Context: ctx, }, c.from()) @@ -104,10 +105,10 @@ func (c *jobFetcher) GetJobs(ctx context.Context) (types.JobLazyIterator, error) jobIDs[i], jobIDs[j] = jobIDs[j], jobIDs[i] } return &jobIterator{ - JobFetcher: c, - array: jobIDs, - length: len(jobIDs), - index: -1, - job: nil, + Fetcher: c, + array: jobIDs, + length: len(jobIDs), + index: -1, + job: nil, }, nil } diff --git a/cli/metascheduler/metascheduler_jobs_by_provider_fetcher.go b/cli/metascheduler/metascheduler_jobs_by_provider_fetcher.go index 856dec8b..4fea7ddf 100644 --- a/cli/metascheduler/metascheduler_jobs_by_provider_fetcher.go +++ b/cli/metascheduler/metascheduler_jobs_by_provider_fetcher.go @@ -20,22 +20,23 @@ import ( "context" "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/job" "github.com/ethereum/go-ethereum/common" ) type runningJobsByProviderFetcher struct { - types.MetaScheduledJobsIdsFetcher - types.JobFetcher + job.MetaScheduledIdsFetcher + job.Fetcher } // NewJobsByProviderFetcher instanciates a JobsByProviderFetcher. func NewJobsByProviderFetcher( - oracle types.MetaScheduledJobsIdsFetcher, - fetcher types.JobFetcher, -) types.JobsByProviderFetcher { + oracle job.MetaScheduledIdsFetcher, + fetcher job.Fetcher, +) job.ByProviderFetcher { return &runningJobsByProviderFetcher{ - MetaScheduledJobsIdsFetcher: oracle, - JobFetcher: fetcher, + MetaScheduledIdsFetcher: oracle, + Fetcher: fetcher, } } diff --git a/cli/metascheduler/metascheduler_jobs_by_provider_fetcher_test.go b/cli/metascheduler/metascheduler_jobs_by_provider_fetcher_test.go index 643d94e9..1bbcb7ae 100644 --- a/cli/metascheduler/metascheduler_jobs_by_provider_fetcher_test.go +++ b/cli/metascheduler/metascheduler_jobs_by_provider_fetcher_test.go @@ -20,9 +20,10 @@ import ( "testing" "github.com/deepsquare-io/grid/cli/metascheduler" - "github.com/deepsquare-io/grid/cli/mocks/mocktypes" + "github.com/deepsquare-io/grid/cli/mocks/mockjob" "github.com/deepsquare-io/grid/cli/types" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/deepsquare-io/grid/cli/types/job" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" @@ -31,14 +32,14 @@ import ( type MetaScheduledJobsByProviderFetcherTestSuite struct { suite.Suite - fetcher *mocktypes.JobFetcher - metascheduledJobIDsFetcher *mocktypes.MetaScheduledJobsIdsFetcher - impl types.JobsByProviderFetcher + fetcher *mockjob.Fetcher + metascheduledJobIDsFetcher *mockjob.MetaScheduledIdsFetcher + impl job.ByProviderFetcher } func (suite *MetaScheduledJobsByProviderFetcherTestSuite) BeforeTest(_, _ string) { - suite.fetcher = mocktypes.NewJobFetcher(suite.T()) - suite.metascheduledJobIDsFetcher = mocktypes.NewMetaScheduledJobsIdsFetcher(suite.T()) + suite.fetcher = mockjob.NewFetcher(suite.T()) + suite.metascheduledJobIDsFetcher = mockjob.NewMetaScheduledIdsFetcher(suite.T()) suite.impl = metascheduler.NewJobsByProviderFetcher( suite.metascheduledJobIDsFetcher, suite.fetcher, diff --git a/cli/metascheduler/metascheduler_jobscheduler.go b/cli/metascheduler/metascheduler_jobscheduler.go index ba504a9a..e34d71bd 100644 --- a/cli/metascheduler/metascheduler_jobscheduler.go +++ b/cli/metascheduler/metascheduler_jobscheduler.go @@ -21,8 +21,8 @@ import ( "math/big" "github.com/deepsquare-io/grid/cli/sbatch" - "github.com/deepsquare-io/grid/cli/types" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/deepsquare-io/grid/cli/types/job" "github.com/ethereum/go-ethereum/accounts/abi/bind" ) @@ -75,16 +75,16 @@ func (c *jobScheduler) requestNewJob( func (c *jobScheduler) SubmitJob( ctx context.Context, - job *sbatch.Job, + j *sbatch.Job, lockedAmount *big.Int, jobName [32]byte, - opts ...types.SubmitJobOption, + opts ...job.SubmitJobOption, ) ([32]byte, error) { - var o types.SubmitJobOptions + var o job.SubmitJobOptions for _, opt := range opts { opt(&o) } - hash, err := c.Submit(ctx, job) + hash, err := c.Submit(ctx, j) if err != nil { return [32]byte{}, fmt.Errorf("failed to submit job: %w", err) } @@ -106,10 +106,10 @@ func (c *jobScheduler) SubmitJob( } definition := metaschedulerabi.JobDefinition{ - Ntasks: uint64(job.Resources.Tasks), - Gpus: uint64(job.Resources.GPUs), - MemPerCpu: uint64(job.Resources.MemPerCPU), - CpusPerTask: uint64(job.Resources.CPUsPerTask), + Ntasks: uint64(j.Resources.Tasks), + Gpus: uint64(j.Resources.GPUs), + MemPerCpu: uint64(j.Resources.MemPerCPU), + CpusPerTask: uint64(j.Resources.CPUsPerTask), StorageType: 0, BatchLocationHash: hash, Uses: msUses, diff --git a/cli/metascheduler/metascheduler_oracle.go b/cli/metascheduler/metascheduler_oracle.go index 1560eeb7..4b017dbb 100644 --- a/cli/metascheduler/metascheduler_oracle.go +++ b/cli/metascheduler/metascheduler_oracle.go @@ -21,7 +21,7 @@ import ( "fmt" "net/http" - "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/job" ) // DefaultOracleURL is the default oracle URL. @@ -38,7 +38,7 @@ type OracleOptions struct { } // NewOracle instanciates an Oracle. -func NewOracle(url string, opts OracleOptions) types.MetaScheduledJobsIdsFetcher { +func NewOracle(url string, opts OracleOptions) job.MetaScheduledIdsFetcher { if url == "" { url = DefaultOracleURL } diff --git a/cli/metascheduler/metascheduler_oracle_integration_test.go b/cli/metascheduler/metascheduler_oracle_integration_test.go index d276cce5..28b9f316 100644 --- a/cli/metascheduler/metascheduler_oracle_integration_test.go +++ b/cli/metascheduler/metascheduler_oracle_integration_test.go @@ -23,14 +23,14 @@ import ( "testing" "github.com/deepsquare-io/grid/cli/metascheduler" - "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/job" "github.com/stretchr/testify/suite" ) type OracleTestSuite struct { suite.Suite - impl types.MetaScheduledJobsIdsFetcher + impl job.MetaScheduledIdsFetcher } func (suite *OracleTestSuite) BeforeTest(_, _ string) { diff --git a/cli/metascheduler/metascheduler_providermanager.go b/cli/metascheduler/metascheduler_providermanager.go index a2c6d528..725cd7d8 100644 --- a/cli/metascheduler/metascheduler_providermanager.go +++ b/cli/metascheduler/metascheduler_providermanager.go @@ -19,9 +19,12 @@ import ( "context" "fmt" "sort" + "strconv" + "strings" "github.com/deepsquare-io/grid/cli/types" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/deepsquare-io/grid/cli/types/provider" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" ) @@ -31,7 +34,7 @@ type providerManager struct { *metaschedulerabi.IProviderManager } -func (c *providerManager) Approve(ctx context.Context, provider common.Address) error { +func (c *providerManager) ApproveProvider(ctx context.Context, provider common.Address) error { opts, err := c.authOpts(ctx) if err != nil { return fmt.Errorf("failed get auth options: %w", err) @@ -47,7 +50,7 @@ func (c *providerManager) Approve(ctx context.Context, provider common.Address) return nil } -func (c *providerManager) Remove(ctx context.Context, provider common.Address) error { +func (c *providerManager) RemoveProvider(ctx context.Context, provider common.Address) error { opts, err := c.authOpts(ctx) if err != nil { return fmt.Errorf("failed get auth options: %w", err) @@ -66,9 +69,9 @@ func (c *providerManager) Remove(ctx context.Context, provider common.Address) e func (c *providerManager) GetProvider( ctx context.Context, address common.Address, - opts ...types.GetProviderOption, -) (provider types.ProviderDetail, err error) { - var o types.GetProviderOptions + opts ...provider.GetProviderOption, +) (detail provider.Detail, err error) { + var o provider.GetProviderOptions for _, opt := range opts { opt(&o) } @@ -79,7 +82,7 @@ func (c *providerManager) GetProvider( address, ) if err != nil { - return provider, WrapError(err) + return detail, WrapError(err) } } else { p, err = c.IProviderManager.GetProvider( @@ -87,7 +90,7 @@ func (c *providerManager) GetProvider( address, ) if err != nil { - return provider, WrapError(err) + return detail, WrapError(err) } } @@ -96,7 +99,7 @@ func (c *providerManager) GetProvider( address, ) if err != nil { - return provider, WrapError(err) + return detail, WrapError(err) } isValidForScheduling, err := c.IsValidForScheduling( @@ -104,7 +107,7 @@ func (c *providerManager) GetProvider( address, ) if err != nil { - return provider, WrapError(err) + return detail, WrapError(err) } jobCount, err := c.GetJobCount( @@ -112,7 +115,7 @@ func (c *providerManager) GetProvider( address, ) if err != nil { - return provider, WrapError(err) + return detail, WrapError(err) } // Sort labels @@ -120,7 +123,7 @@ func (c *providerManager) GetProvider( p.Addr = address - return types.ProviderDetail{ + return provider.Detail{ Provider: p, IsWaitingForApproval: isWaitingForApproval, IsValidForScheduling: isValidForScheduling, @@ -130,8 +133,13 @@ func (c *providerManager) GetProvider( func (c *providerManager) GetProviders( ctx context.Context, - opts ...types.GetProviderOption, -) (providers []types.ProviderDetail, err error) { + opts ...provider.GetProviderOption, +) (providers []provider.Detail, err error) { + var o provider.GetProviderOptions + for _, opt := range opts { + opt(&o) + } + it, err := c.FilterProviderWaitingForApproval(&bind.FilterOpts{Context: ctx}) if err != nil { return providers, WrapError(err) @@ -140,16 +148,12 @@ func (c *providerManager) GetProviders( _ = it.Close() }() - providerMap := make(map[common.Address]types.ProviderDetail) + providerMap := make(map[common.Address]provider.Detail) for it.Next() { - var o types.GetProviderOptions - for _, opt := range opts { - opt(&o) - } - var provider metaschedulerabi.Provider + var prov metaschedulerabi.Provider if o.Proposal { - provider, err = c.GetWaitingForApprovalProvider( + prov, err = c.GetWaitingForApprovalProvider( &bind.CallOpts{Context: ctx}, it.Event.Addr, ) @@ -157,7 +161,7 @@ func (c *providerManager) GetProviders( return providers, WrapError(err) } } else { - provider, err = c.IProviderManager.GetProvider( + prov, err = c.IProviderManager.GetProvider( &bind.CallOpts{Context: ctx}, it.Event.Addr, ) @@ -166,6 +170,11 @@ func (c *providerManager) GetProviders( } } + // Check if provider matches affinities + if len(o.Affinities) != 0 && !CheckAffinities(o.Affinities, prov.Labels) { + continue + } + isWaitingForApproval, err := c.IsWaitingForApproval( &bind.CallOpts{Context: ctx}, it.Event.Addr, @@ -190,24 +199,98 @@ func (c *providerManager) GetProviders( return providers, WrapError(err) } sort.Slice( - provider.Labels, - func(i, j int) bool { return provider.Labels[i].Key < provider.Labels[j].Key }, + prov.Labels, + func(i, j int) bool { return prov.Labels[i].Key < prov.Labels[j].Key }, ) - provider.Addr = it.Event.Addr + prov.Addr = it.Event.Addr - providerMap[it.Event.Addr] = types.ProviderDetail{ - Provider: provider, + providerMap[it.Event.Addr] = provider.Detail{ + Provider: prov, IsWaitingForApproval: isWaitingForApproval, IsValidForScheduling: isValidForScheduling, JobCount: jobCount, } } - providers = make([]types.ProviderDetail, 0, len(providerMap)) + providers = make([]provider.Detail, 0, len(providerMap)) for _, v := range providerMap { providers = append(providers, v) } return providers, nil } + +// CompareValues compares two values using the given operator. +func CompareValues(op, valueA, valueB string) bool { + numA, errA := strconv.ParseFloat(valueA, 64) + numB, errB := strconv.ParseFloat(valueB, 64) + if errA == nil && errB == nil { + switch op { + case "=", "==": + return numB == numA + case "in": + return strings.Contains(valueB, valueA) + case ">": + return numB > numA + case "<": + return numB < numA + case ">=": + return numB >= numA + case "<=": + return numB <= numA + case "!=": + return numB != numA + default: + return numB == numA + } + } else { + // Perform simple string comparison + switch op { + case "=", "==": + return valueB == valueA + case "in": + return strings.Contains(valueB, valueA) + case ">": + return valueB > valueA + case "<": + return valueB < valueA + case ">=": + return valueB >= valueA + case "<=": + return valueB <= valueA + case "!=": + return valueB != valueA + default: + return valueB == valueA + } + } +} + +// CheckAffinities checks if the given labels satisfy the given affinities. +func CheckAffinities( + affinities []types.Affinity, + labels []metaschedulerabi.Label, +) bool { + kv := make(map[string]string) + for _, affinity := range affinities { + op := strings.Trim(string(affinity.Op[:]), "\x00") + + for _, label := range labels { + // If key found and condition satisfied + if affinity.Label.Key == label.Key && + CompareValues(op, affinity.Label.Value, label.Value) { + kv[affinity.Label.Key] = affinity.Label.Value + break + } + } + } + + for _, item := range affinities { + if _, found := kv[item.Label.Key]; !found { + return false + } + } + + return true +} diff --git a/cli/metascheduler/metascheduler_rpc.go b/cli/metascheduler/metascheduler_rpc.go index 7e9562d2..46930063 100644 --- a/cli/metascheduler/metascheduler_rpc.go +++ b/cli/metascheduler/metascheduler_rpc.go @@ -21,8 +21,11 @@ import ( "math/big" "github.com/deepsquare-io/grid/cli/sbatch" - "github.com/deepsquare-io/grid/cli/types" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/deepsquare-io/grid/cli/types/allowance" + "github.com/deepsquare-io/grid/cli/types/credit" + "github.com/deepsquare-io/grid/cli/types/job" + "github.com/deepsquare-io/grid/cli/types/provider" "github.com/ethereum/go-ethereum/accounts/abi/bind" ) @@ -66,7 +69,7 @@ func NewRPCClientSet(b Backend) *RPCClientSet { // JobScheduler creates a [types.JobScheduler]. func (c *RPCClientSet) JobScheduler( sbatch sbatch.Service, -) types.JobScheduler { +) job.Scheduler { m, err := metaschedulerabi.NewMetaScheduler(c.MetaschedulerAddress, c) if err != nil { panic(fmt.Errorf("failed to instanciate MetaScheduler: %w", err)) @@ -78,8 +81,8 @@ func (c *RPCClientSet) JobScheduler( } } -// JobFetcher creates a [types.JobFetcher]. -func (c *RPCClientSet) JobFetcher() types.JobFetcher { +// JobFetcher creates a [job.Fetcher]. +func (c *RPCClientSet) JobFetcher() job.Fetcher { m, err := metaschedulerabi.NewMetaScheduler(c.MetaschedulerAddress, c) if err != nil { panic(fmt.Errorf("failed to instanciate MetaScheduler: %w", err)) @@ -99,8 +102,8 @@ func (c *RPCClientSet) JobFetcher() types.JobFetcher { } } -// CreditManager creates a [types.CreditManager]. -func (c *RPCClientSet) CreditManager() types.CreditManager { +// CreditManager creates a [credit.Manager]. +func (c *RPCClientSet) CreditManager() credit.Manager { m, err := metaschedulerabi.NewMetaScheduler(c.MetaschedulerAddress, c) if err != nil { panic(fmt.Errorf("failed to instanciate MetaScheduler: %w", err)) @@ -119,8 +122,8 @@ func (c *RPCClientSet) CreditManager() types.CreditManager { } } -// AllowanceManager creates an [types.AllowanceManager]. -func (c *RPCClientSet) AllowanceManager() types.AllowanceManager { +// AllowanceManager creates an [allowance.Manager]. +func (c *RPCClientSet) AllowanceManager() allowance.Manager { m, err := metaschedulerabi.NewMetaScheduler(c.MetaschedulerAddress, c) if err != nil { panic(fmt.Errorf("failed to instanciate MetaScheduler: %w", err)) @@ -139,8 +142,8 @@ func (c *RPCClientSet) AllowanceManager() types.AllowanceManager { } } -// ProviderManager creates a [types.ProviderManager]. -func (c *RPCClientSet) ProviderManager() types.ProviderManager { +// ProviderManager creates a [provider.Manager]. +func (c *RPCClientSet) ProviderManager() provider.Manager { m, err := metaschedulerabi.NewMetaScheduler(c.MetaschedulerAddress, c) if err != nil { panic(fmt.Errorf("failed to instanciate MetaScheduler: %w", err)) diff --git a/cli/metascheduler/metascheduler_ws.go b/cli/metascheduler/metascheduler_ws.go index 8ecd55d4..96f256f4 100644 --- a/cli/metascheduler/metascheduler_ws.go +++ b/cli/metascheduler/metascheduler_ws.go @@ -19,8 +19,8 @@ import ( "context" "fmt" - "github.com/deepsquare-io/grid/cli/types" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/deepsquare-io/grid/cli/types/event" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -38,7 +38,7 @@ type eventSubscriber struct { func NewEventSubscriber( rpc Backend, ws Backend, -) types.EventSubscriber { +) event.Subscriber { m, err := metaschedulerabi.NewMetaScheduler(rpc.MetaschedulerAddress, rpc.EthereumBackend) if err != nil { panic(fmt.Errorf("failed to instanciate MetaScheduler: %w", err)) @@ -52,11 +52,11 @@ func NewEventSubscriber( func (c *eventSubscriber) SubscribeEvents( ctx context.Context, - opts ...types.SubscriptionOption, + opts ...event.SubscriptionOption, ) (ethereum.Subscription, error) { var err error logs := make(chan ethtypes.Log, 100) - var o types.SubscriptionOptions + var o event.SubscriptionOptions for _, opt := range opts { opt(&o) } @@ -139,7 +139,7 @@ func (c *eventSubscriber) SubscribeEvents( func (c *eventSubscriber) filter( logs <-chan ethtypes.Log, - o types.SubscriptionOptions, + o event.SubscriptionOptions, ) { var creditFilterer metaschedulerabi.IERC20Filterer if o.TransferChan != nil || o.ApprovalChan != nil { diff --git a/cli/mocks/mockjob/Fetcher_mock.go b/cli/mocks/mockjob/Fetcher_mock.go new file mode 100644 index 00000000..3e5cf545 --- /dev/null +++ b/cli/mocks/mockjob/Fetcher_mock.go @@ -0,0 +1,148 @@ +// Code generated by mockery v2.32.4. DO NOT EDIT. + +package mockjob + +import ( + context "context" + + job "github.com/deepsquare-io/grid/cli/types/job" + mock "github.com/stretchr/testify/mock" + + types "github.com/deepsquare-io/grid/cli/types" +) + +// Fetcher is an autogenerated mock type for the Fetcher type +type Fetcher struct { + mock.Mock +} + +type Fetcher_Expecter struct { + mock *mock.Mock +} + +func (_m *Fetcher) EXPECT() *Fetcher_Expecter { + return &Fetcher_Expecter{mock: &_m.Mock} +} + +// GetJob provides a mock function with given fields: ctx, id +func (_m *Fetcher) GetJob(ctx context.Context, id [32]byte) (types.Job, error) { + ret := _m.Called(ctx, id) + + var r0 types.Job + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, [32]byte) (types.Job, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, [32]byte) types.Job); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Job) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, [32]byte) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Fetcher_GetJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJob' +type Fetcher_GetJob_Call struct { + *mock.Call +} + +// GetJob is a helper method to define mock.On call +// - ctx context.Context +// - id [32]byte +func (_e *Fetcher_Expecter) GetJob(ctx interface{}, id interface{}) *Fetcher_GetJob_Call { + return &Fetcher_GetJob_Call{Call: _e.mock.On("GetJob", ctx, id)} +} + +func (_c *Fetcher_GetJob_Call) Run(run func(ctx context.Context, id [32]byte)) *Fetcher_GetJob_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].([32]byte)) + }) + return _c +} + +func (_c *Fetcher_GetJob_Call) Return(_a0 types.Job, _a1 error) *Fetcher_GetJob_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Fetcher_GetJob_Call) RunAndReturn(run func(context.Context, [32]byte) (types.Job, error)) *Fetcher_GetJob_Call { + _c.Call.Return(run) + return _c +} + +// GetJobs provides a mock function with given fields: ctx +func (_m *Fetcher) GetJobs(ctx context.Context) (job.LazyIterator, error) { + ret := _m.Called(ctx) + + var r0 job.LazyIterator + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (job.LazyIterator, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) job.LazyIterator); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(job.LazyIterator) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Fetcher_GetJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJobs' +type Fetcher_GetJobs_Call struct { + *mock.Call +} + +// GetJobs is a helper method to define mock.On call +// - ctx context.Context +func (_e *Fetcher_Expecter) GetJobs(ctx interface{}) *Fetcher_GetJobs_Call { + return &Fetcher_GetJobs_Call{Call: _e.mock.On("GetJobs", ctx)} +} + +func (_c *Fetcher_GetJobs_Call) Run(run func(ctx context.Context)) *Fetcher_GetJobs_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *Fetcher_GetJobs_Call) Return(_a0 job.LazyIterator, _a1 error) *Fetcher_GetJobs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Fetcher_GetJobs_Call) RunAndReturn(run func(context.Context) (job.LazyIterator, error)) *Fetcher_GetJobs_Call { + _c.Call.Return(run) + return _c +} + +// NewFetcher creates a new instance of Fetcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewFetcher(t interface { + mock.TestingT + Cleanup(func()) +}) *Fetcher { + mock := &Fetcher{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/cli/mocks/mockjob/MetaScheduledIdsFetcher_mock.go b/cli/mocks/mockjob/MetaScheduledIdsFetcher_mock.go new file mode 100644 index 00000000..24141180 --- /dev/null +++ b/cli/mocks/mockjob/MetaScheduledIdsFetcher_mock.go @@ -0,0 +1,90 @@ +// Code generated by mockery v2.32.4. DO NOT EDIT. + +package mockjob + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// MetaScheduledIdsFetcher is an autogenerated mock type for the MetaScheduledIdsFetcher type +type MetaScheduledIdsFetcher struct { + mock.Mock +} + +type MetaScheduledIdsFetcher_Expecter struct { + mock *mock.Mock +} + +func (_m *MetaScheduledIdsFetcher) EXPECT() *MetaScheduledIdsFetcher_Expecter { + return &MetaScheduledIdsFetcher_Expecter{mock: &_m.Mock} +} + +// GetMetaScheduledJobIDs provides a mock function with given fields: ctx +func (_m *MetaScheduledIdsFetcher) GetMetaScheduledJobIDs(ctx context.Context) ([][32]byte, error) { + ret := _m.Called(ctx) + + var r0 [][32]byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([][32]byte, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) [][32]byte); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([][32]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetMetaScheduledJobIDs' +type MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call struct { + *mock.Call +} + +// GetMetaScheduledJobIDs is a helper method to define mock.On call +// - ctx context.Context +func (_e *MetaScheduledIdsFetcher_Expecter) GetMetaScheduledJobIDs(ctx interface{}) *MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call { + return &MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call{Call: _e.mock.On("GetMetaScheduledJobIDs", ctx)} +} + +func (_c *MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call) Run(run func(ctx context.Context)) *MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call) Return(_a0 [][32]byte, _a1 error) *MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call) RunAndReturn(run func(context.Context) ([][32]byte, error)) *MetaScheduledIdsFetcher_GetMetaScheduledJobIDs_Call { + _c.Call.Return(run) + return _c +} + +// NewMetaScheduledIdsFetcher creates a new instance of MetaScheduledIdsFetcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMetaScheduledIdsFetcher(t interface { + mock.TestingT + Cleanup(func()) +}) *MetaScheduledIdsFetcher { + mock := &MetaScheduledIdsFetcher{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/cli/mocks/mocktypes/JobFetcher_mock.go b/cli/mocks/mocktypes/JobFetcher_mock.go deleted file mode 100644 index 00fbd35d..00000000 --- a/cli/mocks/mocktypes/JobFetcher_mock.go +++ /dev/null @@ -1,146 +0,0 @@ -// Code generated by mockery v2.32.4. DO NOT EDIT. - -package mocktypes - -import ( - context "context" - - types "github.com/deepsquare-io/grid/cli/types" - mock "github.com/stretchr/testify/mock" -) - -// JobFetcher is an autogenerated mock type for the JobFetcher type -type JobFetcher struct { - mock.Mock -} - -type JobFetcher_Expecter struct { - mock *mock.Mock -} - -func (_m *JobFetcher) EXPECT() *JobFetcher_Expecter { - return &JobFetcher_Expecter{mock: &_m.Mock} -} - -// GetJob provides a mock function with given fields: ctx, id -func (_m *JobFetcher) GetJob(ctx context.Context, id [32]byte) (types.Job, error) { - ret := _m.Called(ctx, id) - - var r0 types.Job - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, [32]byte) (types.Job, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, [32]byte) types.Job); ok { - r0 = rf(ctx, id) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.Job) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, [32]byte) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// JobFetcher_GetJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJob' -type JobFetcher_GetJob_Call struct { - *mock.Call -} - -// GetJob is a helper method to define mock.On call -// - ctx context.Context -// - id [32]byte -func (_e *JobFetcher_Expecter) GetJob(ctx interface{}, id interface{}) *JobFetcher_GetJob_Call { - return &JobFetcher_GetJob_Call{Call: _e.mock.On("GetJob", ctx, id)} -} - -func (_c *JobFetcher_GetJob_Call) Run(run func(ctx context.Context, id [32]byte)) *JobFetcher_GetJob_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].([32]byte)) - }) - return _c -} - -func (_c *JobFetcher_GetJob_Call) Return(_a0 types.Job, _a1 error) *JobFetcher_GetJob_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *JobFetcher_GetJob_Call) RunAndReturn(run func(context.Context, [32]byte) (types.Job, error)) *JobFetcher_GetJob_Call { - _c.Call.Return(run) - return _c -} - -// GetJobs provides a mock function with given fields: ctx -func (_m *JobFetcher) GetJobs(ctx context.Context) (types.JobLazyIterator, error) { - ret := _m.Called(ctx) - - var r0 types.JobLazyIterator - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (types.JobLazyIterator, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) types.JobLazyIterator); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.JobLazyIterator) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// JobFetcher_GetJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJobs' -type JobFetcher_GetJobs_Call struct { - *mock.Call -} - -// GetJobs is a helper method to define mock.On call -// - ctx context.Context -func (_e *JobFetcher_Expecter) GetJobs(ctx interface{}) *JobFetcher_GetJobs_Call { - return &JobFetcher_GetJobs_Call{Call: _e.mock.On("GetJobs", ctx)} -} - -func (_c *JobFetcher_GetJobs_Call) Run(run func(ctx context.Context)) *JobFetcher_GetJobs_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *JobFetcher_GetJobs_Call) Return(_a0 types.JobLazyIterator, _a1 error) *JobFetcher_GetJobs_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *JobFetcher_GetJobs_Call) RunAndReturn(run func(context.Context) (types.JobLazyIterator, error)) *JobFetcher_GetJobs_Call { - _c.Call.Return(run) - return _c -} - -// NewJobFetcher creates a new instance of JobFetcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewJobFetcher(t interface { - mock.TestingT - Cleanup(func()) -}) *JobFetcher { - mock := &JobFetcher{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/cli/mocks/mocktypes/MetaScheduledJobsIdsFetcher_mock.go b/cli/mocks/mocktypes/MetaScheduledJobsIdsFetcher_mock.go deleted file mode 100644 index aa513521..00000000 --- a/cli/mocks/mocktypes/MetaScheduledJobsIdsFetcher_mock.go +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated by mockery v2.32.4. DO NOT EDIT. - -package mocktypes - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" -) - -// MetaScheduledJobsIdsFetcher is an autogenerated mock type for the MetaScheduledJobsIdsFetcher type -type MetaScheduledJobsIdsFetcher struct { - mock.Mock -} - -type MetaScheduledJobsIdsFetcher_Expecter struct { - mock *mock.Mock -} - -func (_m *MetaScheduledJobsIdsFetcher) EXPECT() *MetaScheduledJobsIdsFetcher_Expecter { - return &MetaScheduledJobsIdsFetcher_Expecter{mock: &_m.Mock} -} - -// GetMetaScheduledJobIDs provides a mock function with given fields: ctx -func (_m *MetaScheduledJobsIdsFetcher) GetMetaScheduledJobIDs(ctx context.Context) ([][32]byte, error) { - ret := _m.Called(ctx) - - var r0 [][32]byte - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) ([][32]byte, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) [][32]byte); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([][32]byte) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetMetaScheduledJobIDs' -type MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call struct { - *mock.Call -} - -// GetMetaScheduledJobIDs is a helper method to define mock.On call -// - ctx context.Context -func (_e *MetaScheduledJobsIdsFetcher_Expecter) GetMetaScheduledJobIDs(ctx interface{}) *MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call { - return &MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call{Call: _e.mock.On("GetMetaScheduledJobIDs", ctx)} -} - -func (_c *MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call) Run(run func(ctx context.Context)) *MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call) Return(_a0 [][32]byte, _a1 error) *MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call) RunAndReturn(run func(context.Context) ([][32]byte, error)) *MetaScheduledJobsIdsFetcher_GetMetaScheduledJobIDs_Call { - _c.Call.Return(run) - return _c -} - -// NewMetaScheduledJobsIdsFetcher creates a new instance of MetaScheduledJobsIdsFetcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMetaScheduledJobsIdsFetcher(t interface { - mock.TestingT - Cleanup(func()) -}) *MetaScheduledJobsIdsFetcher { - mock := &MetaScheduledJobsIdsFetcher{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/cli/tui/editor/editor_model.go b/cli/tui/editor/editor_model.go index bf2872e2..c4d9e8bd 100644 --- a/cli/tui/editor/editor_model.go +++ b/cli/tui/editor/editor_model.go @@ -34,7 +34,7 @@ import ( "github.com/deepsquare-io/grid/cli/internal/validator" "github.com/deepsquare-io/grid/cli/sbatch" "github.com/deepsquare-io/grid/cli/tui/channel" - "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/job" "github.com/mistakenelf/teacup/code" "gopkg.in/yaml.v3" ) @@ -128,8 +128,8 @@ func (m *model) submitJob(ctx context.Context, jobPath string) tea.Cmd { if err != nil { return errorMsg(err) } - var job sbatch.Job - if err := yaml.Unmarshal(dat, &job); err != nil { + var j sbatch.Job + if err := yaml.Unmarshal(dat, &j); err != nil { return errorMsg(err) } @@ -174,10 +174,10 @@ func (m *model) submitJob(ctx context.Context, jobPath string) tea.Cmd { copy(jobName[:], m.inputs[jobNameInput].Value()) jobID, err := m.client.SubmitJob( ctx, - &job, + &j, allocatedCreditsBigI, jobName, - types.WithUse(labels...), + job.WithUse(labels...), ) if err != nil { return errorMsg(err) diff --git a/cli/tui/nav/nav.go b/cli/tui/nav/nav.go index 398e68d6..8a97e511 100644 --- a/cli/tui/nav/nav.go +++ b/cli/tui/nav/nav.go @@ -36,6 +36,7 @@ import ( "github.com/deepsquare-io/grid/cli/tui/style" "github.com/deepsquare-io/grid/cli/tui/transfer" "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/event" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "go.uber.org/zap" @@ -86,8 +87,8 @@ func (m *model) watchEvents( transfers := make(chan types.Transfer, 1) sub, err := m.watcher.SubscribeEvents( ctx, - types.FilterApproval(approvals), - types.FilterTransfer(transfers), + event.FilterApproval(approvals), + event.FilterTransfer(transfers), ) if err != nil { internallog.I.Fatal(err.Error()) diff --git a/cli/tui/provider/details/details_model.go b/cli/tui/provider/details/details_model.go index c2c5ca3d..2abe5390 100644 --- a/cli/tui/provider/details/details_model.go +++ b/cli/tui/provider/details/details_model.go @@ -28,8 +28,8 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/deepsquare-io/grid/cli/internal/ether" "github.com/deepsquare-io/grid/cli/metascheduler" - "github.com/deepsquare-io/grid/cli/types" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/deepsquare-io/grid/cli/types/provider" ) const ( @@ -77,7 +77,7 @@ type model struct { // Form result duration string - types.ProviderDetail + provider.Detail } func (m model) Init() tea.Cmd { diff --git a/cli/tui/provider/details/details_model_builder.go b/cli/tui/provider/details/details_model_builder.go index b8123b6a..15147869 100644 --- a/cli/tui/provider/details/details_model_builder.go +++ b/cli/tui/provider/details/details_model_builder.go @@ -29,7 +29,7 @@ import ( "github.com/deepsquare-io/grid/cli/internal/utils" "github.com/deepsquare-io/grid/cli/internal/validator" "github.com/deepsquare-io/grid/cli/tui/style" - "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/provider" "gopkg.in/yaml.v3" ) @@ -41,7 +41,7 @@ func indent(spaces int, v string) string { } // Model is used to build the bubbletea Model for showing the provider details. -func Model(p types.ProviderDetail) tea.Model { +func Model(p provider.Detail) tea.Model { vp := viewport.New(118, style.StandardHeight) prices := fmt.Sprintf(`CPU pricing: %s credits/(CPU.min) Memory pricing: %s credits/(MB.min) @@ -132,12 +132,12 @@ Is banned: %s inputs[creditsInput].SetValue("100") return &model{ - ProviderDetail: p, - help: help, - viewport: vp, - inputs: inputs, - credits: new(big.Float), - errors: make([]error, inputsSize), + Detail: p, + help: help, + viewport: vp, + inputs: inputs, + credits: new(big.Float), + errors: make([]error, inputsSize), keyMap: keyMap{ ViewPortKeyMap: vp.KeyMap, Exit: key.NewBinding( diff --git a/cli/tui/provider/details/details_view.go b/cli/tui/provider/details/details_view.go index 325ac178..d189b0fc 100644 --- a/cli/tui/provider/details/details_view.go +++ b/cli/tui/provider/details/details_view.go @@ -26,7 +26,7 @@ import ( ) func (m model) headerView() string { - return style.LogTitle().Render(m.ProviderDetail.Addr.Hex()) + return style.LogTitle().Render(m.Detail.Addr.Hex()) } func (m model) View() string { diff --git a/cli/tui/provider/provider_model.go b/cli/tui/provider/provider_model.go index a4d7b001..149997b8 100644 --- a/cli/tui/provider/provider_model.go +++ b/cli/tui/provider/provider_model.go @@ -27,7 +27,7 @@ import ( "github.com/deepsquare-io/grid/cli/internal/utils" "github.com/deepsquare-io/grid/cli/tui/components/table" "github.com/deepsquare-io/grid/cli/tui/provider/details" - "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/provider" "go.uber.org/zap" ) @@ -45,9 +45,9 @@ func emitExitMsg() tea.Msg { } // ShowProviderDetailsMsg is the signal when a user select a provider. -type ShowProviderDetailsMsg types.ProviderDetail +type ShowProviderDetailsMsg provider.Detail -func emitShowProviderDetailsMsg(p types.ProviderDetail) tea.Cmd { +func emitShowProviderDetailsMsg(p provider.Detail) tea.Cmd { return func() tea.Msg { return ShowProviderDetailsMsg(p) } @@ -58,8 +58,8 @@ type model struct { help help.Model keyMap keyMap - client types.ProviderManager - providers map[string]types.ProviderDetail + client provider.Manager + providers map[string]provider.Detail // detailsModel is nullable detailsModel tea.Model @@ -133,7 +133,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { rows := m.initializeRows(context.TODO()) m.table.SetRows(rows) case ShowProviderDetailsMsg: - m.detailsModel = details.Model(types.ProviderDetail(msg)) + m.detailsModel = details.Model(provider.Detail(msg)) cmds = append( cmds, m.detailsModel.Init(), diff --git a/cli/tui/provider/provider_model_builder.go b/cli/tui/provider/provider_model_builder.go index 0fc547bb..48c1fa28 100644 --- a/cli/tui/provider/provider_model_builder.go +++ b/cli/tui/provider/provider_model_builder.go @@ -26,7 +26,7 @@ import ( "github.com/deepsquare-io/grid/cli/internal/utils" "github.com/deepsquare-io/grid/cli/tui/components/table" "github.com/deepsquare-io/grid/cli/tui/style" - "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/provider" ) // ModelBuilder contains the dependencies used to build the bubbletea Model for the provider page. @@ -107,7 +107,7 @@ func (b *ModelBuilder) Build() tea.Model { key.WithHelp("esc/q", "exit"), ), }, - providers: make(map[string]types.ProviderDetail), + providers: make(map[string]provider.Detail), client: b.Client, } } diff --git a/cli/tui/status/log/log_model.go b/cli/tui/status/log/log_model.go index 45923ec2..e9957a0b 100644 --- a/cli/tui/status/log/log_model.go +++ b/cli/tui/status/log/log_model.go @@ -32,6 +32,7 @@ import ( "github.com/deepsquare-io/grid/cli/metascheduler" "github.com/deepsquare-io/grid/cli/tui/channel" "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/provider" "github.com/ethereum/go-ethereum/common" "go.uber.org/zap" ) @@ -69,7 +70,7 @@ type model struct { jobID [32]byte allocatedProviderAddress common.Address - provider types.ProviderDetail + provider provider.Detail msOrSchedLen int64 runningLen int64 status metascheduler.JobStatus @@ -207,7 +208,7 @@ func reduceJobsIntoRunningOrScheduledLens( // computeWaitingTime returns min(running) + sum(waiting) func computeWaitingTime( jobID [32]byte, - provider types.ProviderDetail, + provider provider.Detail, jobs []types.Job, ) (time.Duration, error) { var waiting, running time.Duration diff --git a/cli/tui/status/log/log_watch_transition_model.go b/cli/tui/status/log/log_watch_transition_model.go index 4e94f64e..f54b6fa4 100644 --- a/cli/tui/status/log/log_watch_transition_model.go +++ b/cli/tui/status/log/log_watch_transition_model.go @@ -24,6 +24,7 @@ import ( "github.com/deepsquare-io/grid/cli/tui/channel" "github.com/deepsquare-io/grid/cli/types" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/deepsquare-io/grid/cli/types/event" ) type transitionMsg types.JobTransition @@ -39,7 +40,7 @@ func makeWatchTransitionModel( OnInit: func(c chan transitionMsg) func() error { transitions := make(chan types.JobTransition, 1) sub, err := watcher.SubscribeEvents(ctx, - types.FilterJobTransition(transitions), + event.FilterJobTransition(transitions), ) if err != nil { log.I.Fatal(err.Error()) diff --git a/cli/tui/status/status_model.go b/cli/tui/status/status_model.go index d8977dde..1b887cf2 100644 --- a/cli/tui/status/status_model.go +++ b/cli/tui/status/status_model.go @@ -35,6 +35,8 @@ import ( "github.com/deepsquare-io/grid/cli/tui/components/ticker" "github.com/deepsquare-io/grid/cli/tui/style" "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/job" + "github.com/deepsquare-io/grid/cli/types/provider" "github.com/ethereum/go-ethereum/common" "go.uber.org/zap" ) @@ -57,12 +59,12 @@ type model struct { idToJob map[[32]byte]types.Job // Index jobID to running job runningIDs map[[32]byte]bool - it types.JobLazyIterator + it job.LazyIterator help help.Model watchJobs channel.Model[transitionMsg] client deepsquare.Client keyMap keyMap - cacheProvider map[[32]byte]types.ProviderDetail + cacheProvider map[[32]byte]provider.Detail ticker ticker.Model @@ -164,13 +166,13 @@ func rowToJobID(row table.Row) [32]byte { // This method is executed before the loading of the page for SSR. func initializeRows( ctx context.Context, - fetcher types.JobFetcher, + fetcher job.Fetcher, ) ( rows []table.Row, idToRow map[[32]byte]table.Row, idToJob map[[32]byte]types.Job, runningIDs map[[32]byte]bool, - it types.JobLazyIterator, + it job.LazyIterator, ) { it, err := fetcher.GetJobs(ctx) if err != nil { @@ -445,7 +447,7 @@ func Model( ), }, client: client, - cacheProvider: make(map[[32]byte]types.ProviderDetail), + cacheProvider: make(map[[32]byte]provider.Detail), watchJobs: makeWatchJobsModel( ctx, userAddress, diff --git a/cli/tui/status/status_watch_jobs_model.go b/cli/tui/status/status_watch_jobs_model.go index cb37683d..fbda7764 100644 --- a/cli/tui/status/status_watch_jobs_model.go +++ b/cli/tui/status/status_watch_jobs_model.go @@ -22,6 +22,7 @@ import ( "github.com/deepsquare-io/grid/cli/internal/log" "github.com/deepsquare-io/grid/cli/tui/channel" "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/event" "github.com/ethereum/go-ethereum/common" "go.uber.org/zap" ) @@ -40,8 +41,8 @@ func makeWatchJobsModel( newJobs := make(chan types.NewJobRequest, 1) transitions := make(chan types.JobTransition, 1) sub, err := watcher.SubscribeEvents(ctx, - types.FilterNewJobRequest(newJobs), - types.FilterJobTransition(transitions), + event.FilterNewJobRequest(newJobs), + event.FilterJobTransition(transitions), ) if err != nil { log.I.Fatal(err.Error()) diff --git a/cli/tui/status/topup/topup_watch_job_status.go b/cli/tui/status/topup/topup_watch_job_status.go index 8b28e293..c4293c8e 100644 --- a/cli/tui/status/topup/topup_watch_job_status.go +++ b/cli/tui/status/topup/topup_watch_job_status.go @@ -22,6 +22,7 @@ import ( "github.com/deepsquare-io/grid/cli/internal/log" "github.com/deepsquare-io/grid/cli/tui/channel" "github.com/deepsquare-io/grid/cli/types" + "github.com/deepsquare-io/grid/cli/types/event" "go.uber.org/zap" ) @@ -38,7 +39,7 @@ func makeWatchJobModel( OnInit: func(c chan transitionMsg) func() error { transitions := make(chan types.JobTransition, 1) sub, err := watcher.SubscribeEvents(ctx, - types.FilterJobTransition(transitions), + event.FilterJobTransition(transitions), ) if err != nil { log.I.Fatal(err.Error()) diff --git a/cli/types/allowance/allowance.go b/cli/types/allowance/allowance.go new file mode 100644 index 00000000..4a1493e2 --- /dev/null +++ b/cli/types/allowance/allowance.go @@ -0,0 +1,27 @@ +// Package allowance describes the types and methods to interact with the +package allowance + +import ( + "context" + "math/big" + + "github.com/deepsquare-io/grid/cli/types" +) + +// Manager set the allowed quantity of credit for smart-contract interactions. +type Manager interface { + // Set the allowance for smart-contract interactions. + SetAllowance(ctx context.Context, amount *big.Int) error + + // ClearAllowance is an alias to SetAllowance 0. + ClearAllowance(ctx context.Context) error + + // Get the current allowance toward the contract. + GetAllowance(ctx context.Context) (*big.Int, error) + + // ReduceToAllowance reduces a channel of approval into allowance. + ReduceToAllowance( + ctx context.Context, + approvals <-chan types.Approval, + ) (<-chan *big.Int, error) +} diff --git a/cli/types/credit/credit.go b/cli/types/credit/credit.go new file mode 100644 index 00000000..0af6f9aa --- /dev/null +++ b/cli/types/credit/credit.go @@ -0,0 +1,28 @@ +// Package credit describes the types and methods to interact with the credits. +package credit + +import ( + "context" + "math/big" + + "github.com/deepsquare-io/grid/cli/types" + "github.com/ethereum/go-ethereum/common" +) + +// Manager handles the credits of the user. +type Manager interface { + // Balance fetches the current balance of credits. + Balance(ctx context.Context) (*big.Int, error) + + // Balance fetches the current balance of credits. + BalanceOf(ctx context.Context, address common.Address) (*big.Int, error) + + // Transfer tranfers credits from one address to another. + Transfer(ctx context.Context, to common.Address, amount *big.Int) error + + // ReduceToBalance reduces a channel of transfers into balance. + ReduceToBalance( + ctx context.Context, + transfers <-chan types.Transfer, + ) (<-chan *big.Int, error) +} diff --git a/cli/types/event/event_subscriber.go b/cli/types/event/event_subscriber.go new file mode 100644 index 00000000..8b74ee66 --- /dev/null +++ b/cli/types/event/event_subscriber.go @@ -0,0 +1,61 @@ +// Package event describes the types and methods to interact with the events. +package event + +import ( + "context" + + "github.com/deepsquare-io/grid/cli/types" + "github.com/ethereum/go-ethereum" +) + +// SubscriptionOptions contains the channels used to pass events. +type SubscriptionOptions struct { + NewJobRequestChan chan<- types.NewJobRequest + JobTransitionChan chan<- types.JobTransition + TransferChan chan<- types.Transfer + ApprovalChan chan<- types.Approval +} + +// SubscriptionOption applies default and optional parameters to the SubscribeEvents method. +type SubscriptionOption func(*SubscriptionOptions) + +// FilterTransfer allows taking the Transfer events from the subscription. +func FilterTransfer(filtered chan<- types.Transfer) SubscriptionOption { + return func(so *SubscriptionOptions) { + so.TransferChan = filtered + } +} + +// FilterApproval allows taking the Approval events from the subscription. +func FilterApproval(filtered chan<- types.Approval) SubscriptionOption { + return func(so *SubscriptionOptions) { + so.ApprovalChan = filtered + } +} + +// FilterNewJobRequest allows taking the NewJobRequest events from the subscription. +func FilterNewJobRequest( + filtered chan<- types.NewJobRequest, +) SubscriptionOption { + return func(so *SubscriptionOptions) { + so.NewJobRequestChan = filtered + } +} + +// FilterJobTransition allows taking the JobTransition events from the subscription. +func FilterJobTransition( + filtered chan<- types.JobTransition, +) SubscriptionOption { + return func(so *SubscriptionOptions) { + so.JobTransitionChan = filtered + } +} + +// Subscriber watches smart-contract events. +type Subscriber interface { + // Subscribe to metascheduler events. + SubscribeEvents( + ctx context.Context, + opts ...SubscriptionOption, + ) (ethereum.Subscription, error) +} diff --git a/cli/types/job/job.go b/cli/types/job/job.go new file mode 100644 index 00000000..052a7c2a --- /dev/null +++ b/cli/types/job/job.go @@ -0,0 +1,86 @@ +// Package job describes the types and methods to interact with the jobs. +package job + +import ( + "context" + "math/big" + + "github.com/deepsquare-io/grid/cli/sbatch" + "github.com/deepsquare-io/grid/cli/types" + "github.com/ethereum/go-ethereum/common" +) + +// SubmitJobOption is used to apply default and optional parameters for submitting a job. +type SubmitJobOption func(*SubmitJobOptions) + +// SubmitJobOptions is the object containing optional parameters for submitting a job. +type SubmitJobOptions struct { + Uses []types.Label + Affinities []types.Affinity +} + +// WithUse adds strict key-value filters to the job, which filters the available clusters. +func WithUse(labels ...types.Label) SubmitJobOption { + return func(sjo *SubmitJobOptions) { + sjo.Uses = labels + } +} + +// WithAffinity adds key-value filters with operators to the job, which filters the available clusters. +func WithAffinity(affinities ...types.Affinity) SubmitJobOption { + return func(sjo *SubmitJobOptions) { + sjo.Affinities = affinities + } +} + +// Scheduler schedules and cancels jobs. +type Scheduler interface { + // Submit a batch script to the batch service and metascheduler. + SubmitJob( + ctx context.Context, + job *sbatch.Job, + lockedAmount *big.Int, + jobName [32]byte, + opts ...SubmitJobOption, + ) ([32]byte, error) + // Cancel a job. + CancelJob(ctx context.Context, jobID [32]byte) error + // TopUp a job. + TopUpJob(ctx context.Context, jobID [32]byte, amount *big.Int) error + // Panic a job. + PanicJob(ctx context.Context, jobID [32]byte, reason string) error +} + +// LazyIterator iterates on a lazy list of jobs. +// +// When calling Next or Prev, a request will be sent to the data source. +type LazyIterator interface { + // Fetches the next job. + Next(ctx context.Context) (ok bool) + // Fetches the previous job. + Prev(ctx context.Context) (ok bool) + // Get the current job. + Current() types.Job + // Get the current error. + Error() error +} + +// Fetcher fetches jobs. +type Fetcher interface { + // Get a job. + GetJob(ctx context.Context, id [32]byte) (types.Job, error) + // Get a iterator of jobs. If there is no job, nil is returned. + GetJobs(ctx context.Context) (LazyIterator, error) +} + +// MetaScheduledIdsFetcher fetches meta-scheduled jobs ids. +// +// This contacts directly the meta-scheduler without the need to fetch all the jobs. +type MetaScheduledIdsFetcher interface { + GetMetaScheduledJobIDs(ctx context.Context) ([][32]byte, error) +} + +// ByProviderFetcher fetches the jobs meta-scheduled or running on the provider. +type ByProviderFetcher interface { + GetJobsByProvider(ctx context.Context, providerAddress common.Address) ([]types.Job, error) +} diff --git a/cli/types/provider/provider.go b/cli/types/provider/provider.go new file mode 100644 index 00000000..97568832 --- /dev/null +++ b/cli/types/provider/provider.go @@ -0,0 +1,56 @@ +// Package provider defines the interface for managing providers. +package provider + +import ( + "context" + + "github.com/deepsquare-io/grid/cli/types" + metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" + "github.com/ethereum/go-ethereum/common" +) + +// Detail contains all the specs and statuses of a Provider. +type Detail struct { + metaschedulerabi.Provider + IsWaitingForApproval bool + IsValidForScheduling bool + JobCount uint64 +} + +// GetProviderOption is an interface for options for the GetProvider method. +type GetProviderOption func(*GetProviderOptions) + +// GetProviderOptions is the structure for holding options for the GetProvider method. +type GetProviderOptions struct { + Proposal bool + Affinities []types.Affinity +} + +// WithProposal enables GetProvider to show the proposal of a provider. +func WithProposal() GetProviderOption { + return func(gpo *GetProviderOptions) { + gpo.Proposal = true + } +} + +// WithAffinity adds key-value filters with operators to the job, which filters the available clusters. +func WithAffinity(affinities ...types.Affinity) GetProviderOption { + return func(gpo *GetProviderOptions) { + gpo.Affinities = affinities + } +} + +// Manager manages admin operation of providers +type Manager interface { + ApproveProvider(ctx context.Context, provider common.Address) error + RemoveProvider(ctx context.Context, provider common.Address) error + GetProvider( + ctx context.Context, + address common.Address, + opts ...GetProviderOption, + ) (provider Detail, err error) + GetProviders( + ctx context.Context, + opts ...GetProviderOption, + ) (providers []Detail, err error) +} diff --git a/cli/types/types.go b/cli/types/types.go index 6a57163b..f9510fbb 100644 --- a/cli/types/types.go +++ b/cli/types/types.go @@ -18,13 +18,9 @@ package types import ( "context" - "math/big" loggerv1alpha1 "github.com/deepsquare-io/grid/cli/internal/logger/v1alpha1" - "github.com/deepsquare-io/grid/cli/sbatch" metaschedulerabi "github.com/deepsquare-io/grid/cli/types/abi/metascheduler" - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" ) // LogStream is a readable stream of logs. @@ -45,155 +41,6 @@ type Label metaschedulerabi.Label // Affinity is a key-value object with an operator for filtering clusters. type Affinity metaschedulerabi.Affinity -// SubmitJobOption is used to apply default and optional parameters for submitting a job. -type SubmitJobOption func(*SubmitJobOptions) - -// SubmitJobOptions is the object containing optional parameters for submitting a job. -type SubmitJobOptions struct { - Uses []Label - Affinities []Affinity -} - -// WithUse adds strict key-value filters to the job, which filters the available clusters. -func WithUse(labels ...Label) SubmitJobOption { - return func(sjo *SubmitJobOptions) { - sjo.Uses = labels - } -} - -// WithAffinity adds key-value filters with operators to the job, which filters the available clusters. -func WithAffinity(affinities ...Affinity) SubmitJobOption { - return func(sjo *SubmitJobOptions) { - sjo.Affinities = affinities - } -} - -// JobScheduler schedules and cancels jobs. -type JobScheduler interface { - // Submit a batch script to the batch service and metascheduler. - SubmitJob( - ctx context.Context, - job *sbatch.Job, - lockedAmount *big.Int, - jobName [32]byte, - opts ...SubmitJobOption, - ) ([32]byte, error) - // Cancel a job. - CancelJob(ctx context.Context, jobID [32]byte) error - // TopUp a job. - TopUpJob(ctx context.Context, jobID [32]byte, amount *big.Int) error - // Panic a job. - PanicJob(ctx context.Context, jobID [32]byte, reason string) error -} - -// JobLazyIterator iterates on a lazy list of jobs. -// -// When calling Next or Prev, a request will be sent to the data source. -type JobLazyIterator interface { - // Fetches the next job. - Next(ctx context.Context) (ok bool) - // Fetches the previous job. - Prev(ctx context.Context) (ok bool) - // Get the current job. - Current() Job - // Get the current error. - Error() error -} - -// JobFetcher fetches jobs. -type JobFetcher interface { - // Get a job. - GetJob(ctx context.Context, id [32]byte) (Job, error) - // Get a iterator of jobs. If there is no job, nil is returned. - GetJobs(ctx context.Context) (JobLazyIterator, error) -} - -// MetaScheduledJobsIdsFetcher fetches meta-scheduled jobs ids. -// -// This contacts directly the meta-scheduler without the need to fetch all the jobs. -type MetaScheduledJobsIdsFetcher interface { - GetMetaScheduledJobIDs(ctx context.Context) ([][32]byte, error) -} - -// JobsByProviderFetcher fetches the jobs meta-scheduled or running on the provider. -type JobsByProviderFetcher interface { - GetJobsByProvider(ctx context.Context, providerAddress common.Address) ([]Job, error) -} - -// CreditManager handles the credits of the user. -type CreditManager interface { - // Balance fetches the current balance of credits. - Balance(ctx context.Context) (*big.Int, error) - - // Balance fetches the current balance of credits. - BalanceOf(ctx context.Context, address common.Address) (*big.Int, error) - - // Transfer tranfers credits from one address to another. - Transfer(ctx context.Context, to common.Address, amount *big.Int) error - - // ReduceToBalance reduces a channel of transfers into balance. - ReduceToBalance( - ctx context.Context, - transfers <-chan Transfer, - ) (<-chan *big.Int, error) -} - -// AllowanceManager set the allowed quantity of credit for smart-contract interactions. -type AllowanceManager interface { - // Set the allowance for smart-contract interactions. - SetAllowance(ctx context.Context, amount *big.Int) error - - // ClearAllowance is an alias to SetAllowance 0. - ClearAllowance(ctx context.Context) error - - // Get the current allowance toward the contract. - GetAllowance(ctx context.Context) (*big.Int, error) - - // ReduceToAllowance reduces a channel of approval into allowance. - ReduceToAllowance( - ctx context.Context, - approvals <-chan Approval, - ) (<-chan *big.Int, error) -} - -// ProviderDetail contains all the specs and statuses of a Provider. -type ProviderDetail struct { - metaschedulerabi.Provider - IsWaitingForApproval bool - IsValidForScheduling bool - JobCount uint64 -} - -// GetProviderOption is an interface for options for the GetProvider method. -type GetProviderOption func(*GetProviderOptions) - -// GetProviderOptions is the structure for holding options for the GetProvider method. -type GetProviderOptions struct { - Proposal bool -} - -// WithProposal enables GetProvider to show the proposal of a provider. -func WithProposal() GetProviderOption { - return func(gpo *GetProviderOptions) { - gpo.Proposal = true - } -} - -// ProviderManager manages admin operation of providers -type ProviderManager interface { - Approve(ctx context.Context, provider common.Address) error - Remove(ctx context.Context, provider common.Address) error - GetProvider( - ctx context.Context, - address common.Address, - opts ...GetProviderOption, - ) (provider ProviderDetail, err error) - GetProviders( - ctx context.Context, - opts ...GetProviderOption, - ) (providers []ProviderDetail, err error) -} - // NewJobRequest is an event that happens when a user submit a job. type NewJobRequest *metaschedulerabi.MetaSchedulerNewJobRequestEvent @@ -205,55 +52,3 @@ type Transfer *metaschedulerabi.IERC20Transfer // Approval is an event that happens when an user sets a new allowance. type Approval *metaschedulerabi.IERC20Approval - -// SubscriptionOptions contains the channels used to pass events. -type SubscriptionOptions struct { - NewJobRequestChan chan<- NewJobRequest - JobTransitionChan chan<- JobTransition - TransferChan chan<- Transfer - ApprovalChan chan<- Approval -} - -// SubscriptionOption applies default and optional parameters to the SubscribeEvents method. -type SubscriptionOption func(*SubscriptionOptions) - -// FilterTransfer allows taking the Transfer events from the subscription. -func FilterTransfer(filtered chan<- Transfer) SubscriptionOption { - return func(so *SubscriptionOptions) { - so.TransferChan = filtered - } -} - -// FilterApproval allows taking the Approval events from the subscription. -func FilterApproval(filtered chan<- Approval) SubscriptionOption { - return func(so *SubscriptionOptions) { - so.ApprovalChan = filtered - } -} - -// FilterNewJobRequest allows taking the NewJobRequest events from the subscription. -func FilterNewJobRequest( - filtered chan<- NewJobRequest, -) SubscriptionOption { - return func(so *SubscriptionOptions) { - so.NewJobRequestChan = filtered - } -} - -// FilterJobTransition allows taking the JobTransition events from the subscription. -func FilterJobTransition( - filtered chan<- JobTransition, -) SubscriptionOption { - return func(so *SubscriptionOptions) { - so.JobTransitionChan = filtered - } -} - -// EventSubscriber watches smart-contract events. -type EventSubscriber interface { - // Subscribe to metascheduler events. - SubscribeEvents( - ctx context.Context, - opts ...SubscriptionOption, - ) (ethereum.Subscription, error) -}