Skip to content

Commit

Permalink
Refactored TotalUsage
Browse files Browse the repository at this point in the history
Added UserTotalUsage for usage aggregation by user
Added ProjectTotalUsage for usage aggregation by project
  • Loading branch information
ya-enot committed Jul 13, 2020
1 parent 1b03aa6 commit 23128c6
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 30 deletions.
19 changes: 13 additions & 6 deletions satellite/admin/adminql/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ const (
// Query is immutable graphql request
Query = "Query"

// TotalUsageQuery is a query name for total usage
TotalUsageQuery = "totalUsage"
// UserTotalUsageQuery is a query name for total usage for user
UserTotalUsageQuery = "userTotalUsage"
// ProjectTotalUsageQuery is a query name for total usage for Project
ProjectTotalUsageQuery = "projectTotalUsage"
// UserQuery is a query name for user
UserQuery = "user"
// UserByEmailQuery is a query name for user by email
Expand All @@ -38,10 +40,15 @@ func rootQuery(service *service.Service, types *TypeCreator) *graphql.Object {
return graphql.NewObject(graphql.ObjectConfig{
Name: Query,
Fields: graphql.Fields{
TotalUsageQuery: &graphql.Field{
Type: types.totalUsage,
Args: graphqlTotalUsageQueryArgs(),
Resolve: graphqlTotalUsageQueryResolve(service),
UserTotalUsageQuery: &graphql.Field{
Type: types.userTotalUsage,
Args: graphqlUserTotalUsageQueryArgs(),
Resolve: graphqlUserTotalUsageQueryResolve(service),
},
ProjectTotalUsageQuery: &graphql.Field{
Type: types.projectTotalUsage,
Args: graphqlProjectTotalUsageQueryArgs(),
Resolve: graphqlProjectTotalUsageQueryResolve(service),
},
UserQuery: &graphql.Field{
Type: types.user,
Expand Down
80 changes: 74 additions & 6 deletions satellite/admin/adminql/type_usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ import (
const (
// TotalUsageType is a graphql type for total usage
TotalUsageType = "TotalUsage"
// UserTotalUsageType is a graphql type for total usage for user
UserTotalUsageType = "UserTotalUsage"
// ProjectTotalUsageType is a graphql type for total usage for project
ProjectTotalUsageType = "ProjectTotalUsage"
// UsageLimitType is a graphql type for usage limit
UsageLimitType = "UsageLimit"

// FieldUsage is a field name for usage
FieldUsage = "usage"
// FieldEgress is a field name for egress
FieldEgress = "egress"
// FieldEgressLimit is a field name for egress limit
Expand All @@ -26,15 +32,41 @@ const (
FieldStorageLimit = "storageLimit"
)

// graphqlTotalUsage creates *graphql.Object type representation of satellite.admin.TotalUsage
// TODO: simplify
func graphqlTotalUsage() *graphql.Object {
// graphqlUserTotalUsage creates *graphql.Object type representation of satellite.admin.UserTotalUsage
func graphqlUserTotalUsage(c *TypeCreator) *graphql.Object {
return graphql.NewObject(graphql.ObjectConfig{
Name: TotalUsageType,
Name: UserTotalUsageType,
Fields: graphql.Fields{
FieldUserID: &graphql.Field{
Type: graphql.NewNonNull(graphql.ID),
},
FieldUsage: &graphql.Field{
Type: graphql.NewNonNull(c.totalUsage),
},
},
})
}

// graphqlProjectTotalUsage creates *graphql.Object type representation of satellite.admin.ProjectTotalUsage
func graphqlProjectTotalUsage(c *TypeCreator) *graphql.Object {
return graphql.NewObject(graphql.ObjectConfig{
Name: ProjectTotalUsageType,
Fields: graphql.Fields{
FieldProjectID: &graphql.Field{
Type: graphql.NewNonNull(graphql.ID),
},
FieldUsage: &graphql.Field{
Type: graphql.NewNonNull(c.totalUsage),
},
},
})
}

// graphqlTotalUsage creates *graphql.Object type representation of satellite.admin.UserTotalUsage
func graphqlTotalUsage() *graphql.Object {
return graphql.NewObject(graphql.ObjectConfig{
Name: TotalUsageType,
Fields: graphql.Fields{
FieldSince: &graphql.Field{
Type: graphql.NewNonNull(graphql.DateTime),
},
Expand Down Expand Up @@ -75,7 +107,7 @@ func graphqlUsageLimit() *graphql.Object {
})
}

func graphqlTotalUsageQueryArgs() graphql.FieldConfigArgument {
func graphqlUserTotalUsageQueryArgs() graphql.FieldConfigArgument {
return graphql.FieldConfigArgument{
FieldUserID: &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.ID),
Expand All @@ -89,7 +121,7 @@ func graphqlTotalUsageQueryArgs() graphql.FieldConfigArgument {
}
}

func graphqlTotalUsageQueryResolve(service *service.Service) func(graphql.ResolveParams) (interface{}, error) {
func graphqlUserTotalUsageQueryResolve(service *service.Service) func(graphql.ResolveParams) (interface{}, error) {
return func(p graphql.ResolveParams) (interface{}, error) {
inputID, _ := p.Args[FieldUserID].(string)
since, _ := p.Args[FieldSince].(time.Time)
Expand All @@ -111,6 +143,42 @@ func graphqlTotalUsageQueryResolve(service *service.Service) func(graphql.Resolv
}
}

func graphqlProjectTotalUsageQueryArgs() graphql.FieldConfigArgument {
return graphql.FieldConfigArgument{
FieldProjectID: &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.ID),
},
FieldSince: &graphql.ArgumentConfig{
Type: graphql.DateTime,
},
FieldBefore: &graphql.ArgumentConfig{
Type: graphql.DateTime,
},
}
}

func graphqlProjectTotalUsageQueryResolve(service *service.Service) func(graphql.ResolveParams) (interface{}, error) {
return func(p graphql.ResolveParams) (interface{}, error) {
inputID, _ := p.Args[FieldProjectID].(string)
since, _ := p.Args[FieldSince].(time.Time)
before, _ := p.Args[FieldBefore].(time.Time)

if since.IsZero() {
since = time.Now()
}
if before.IsZero() {
before = time.Now()
}

id, err := uuid.Parse(inputID)
if err != nil {
return nil, err
}

return service.GetTotalUsageForProject(p.Context, *id, since, before)
}
}

func graphqlUpdateUsageLimitMutationArgs() graphql.FieldConfigArgument {
return graphql.FieldConfigArgument{
FieldProjectID: &graphql.ArgumentConfig{
Expand Down
28 changes: 19 additions & 9 deletions satellite/admin/adminql/typecreator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ type TypeCreator struct {
query *graphql.Object
mutation *graphql.Object

totalUsage *graphql.Object
user *graphql.Object
project *graphql.Object
apiKey *graphql.Object
apiKeyCreate *graphql.Object
usageLimit *graphql.Object
storageNode *graphql.Object
storageNodeUsage *graphql.Object
userTotalUsage *graphql.Object
projectTotalUsage *graphql.Object
totalUsage *graphql.Object
user *graphql.Object
project *graphql.Object
apiKey *graphql.Object
apiKeyCreate *graphql.Object
usageLimit *graphql.Object
storageNode *graphql.Object
storageNodeUsage *graphql.Object

cursor *graphql.InputObject
}
Expand All @@ -42,7 +44,7 @@ func (c *TypeCreator) Create(log *zap.Logger, s *service.Service) error {
}

c.apiKey = graphqlAPIKey()
if err := c.totalUsage.Error(); err != nil {
if err := c.apiKey.Error(); err != nil {
return err
}
c.storageNodeUsage = graphqlStorageNodeUsage()
Expand All @@ -55,6 +57,14 @@ func (c *TypeCreator) Create(log *zap.Logger, s *service.Service) error {
if err := c.apiKeyCreate.Error(); err != nil {
return err
}
c.userTotalUsage = graphqlUserTotalUsage(c)
if err := c.userTotalUsage.Error(); err != nil {
return err
}
c.projectTotalUsage = graphqlProjectTotalUsage(c)
if err := c.projectTotalUsage.Error(); err != nil {
return err
}

// composite entities
c.project = graphqlProject(s, c)
Expand Down
54 changes: 45 additions & 9 deletions satellite/admin/service/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,20 @@ import (
"storj.io/storj/satellite/accounting"
)

// TotalUsage is an object that describes data usage aggregation for multiple projects
type TotalUsage struct {
UserID uuid.UUID `json:"userId"`
// UserTotalUsage is an object that describes data usage aggregation for all projects of user
type UserTotalUsage struct {
UserID uuid.UUID `json:"userId"`
Usage Usage
}

// ProjectTotalUsage is an object that describes data usage aggregation for all projects of user
type ProjectTotalUsage struct {
ProjectID uuid.UUID `json:"projectId"`
Usage Usage
}

// Usage is an object that describes data usage aggregation
type Usage struct {
Since time.Time `json:"since"`
Before time.Time `json:"before"`
Egress int64 `json:"egress"`
Expand Down Expand Up @@ -77,27 +88,52 @@ func (s *Service) getUsageLimit(ctx context.Context, projectID uuid.UUID) (*Usag
}

// GetTotalUsageForUser aggregates data usage for all user projects
func (s *Service) GetTotalUsageForUser(ctx context.Context, userID uuid.UUID, since time.Time, before time.Time) (*TotalUsage, error) {
func (s *Service) GetTotalUsageForUser(ctx context.Context, userID uuid.UUID, since time.Time, before time.Time) (*UserTotalUsage, error) {
projects, err := s.consoleDB.Projects().GetByUserID(ctx, userID)
if nil != err {
return nil, err
}
total := TotalUsage{
total := UserTotalUsage{
UserID: userID,
Since: since,
Before: before,
Usage: Usage{
Since: since,
Before: before,
},
}
for _, project := range projects {
usage, err := s.projectDB.GetProjectTotal(ctx, project.ID, since, before)
if nil != err {
return nil, err
}
mergeUsage(&total, usage)
mergeUsage(&total.Usage, usage)
}
return &total, nil
}

func mergeUsage(t *TotalUsage, p *accounting.ProjectUsage) {
// GetTotalUsageForProject aggregates data usage for project
func (s *Service) GetTotalUsageForProject(ctx context.Context, projectID uuid.UUID, since time.Time, before time.Time) (*ProjectTotalUsage, error) {
total := ProjectTotalUsage{
ProjectID: projectID,
Usage: Usage{
Since: since,
Before: before,
},
}
usage, err := s.projectDB.GetProjectTotal(ctx, projectID, since, before)
if nil != err {
return nil, err
}
mergeUsage(&total.Usage, usage)
return &total, nil
}

func mergeUsage(t *Usage, p *accounting.ProjectUsage) {
if t.Since.After(p.Since) {
t.Since = p.Since
}
if p.Before.After(t.Before) {
t.Before = p.Before
}
t.Egress += p.Egress
t.Object += p.ObjectCount
t.Storage += p.Storage
Expand Down

0 comments on commit 23128c6

Please sign in to comment.