Skip to content

Commit

Permalink
Merge pull request #18 from slr71/main
Browse files Browse the repository at this point in the history
CORE-2016: support effective dates for rates and default quota limits.
  • Loading branch information
slr71 authored Dec 16, 2024
2 parents d092903 + 4f10a52 commit 36f15cd
Show file tree
Hide file tree
Showing 17 changed files with 914 additions and 256 deletions.
4 changes: 4 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
QMS_DATABASE_URI=postgres://de@localhost/qms?sslmode=disable
QMS_USERNAME_SUFFIX=iplantcollaborative.org
QMS_NATS_CLUSTER=nats://localhost:4222
19 changes: 19 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash

_PWD=$(pwd)
_APP=`echo $_PWD | grep -Eo -i '([[:alnum:]-]*)$'`
echo "Starting $_APP environment..."
export PATH="$_PWD/bin:$PATH"

export PRJ_ROOT_DIR=$(realpath "$_PWD")

[ -f ${PRJ_ROOT_DIR}/.env ] && source ${PRJ_ROOT_DIR}/.env || { echo "Missing ${PRJ_ROOT_DIR}/.env!"; exit 1; }
## Export all VARS in .env
ALL_ENV_PRJ_VARS=($(grep -E '^[[:space:]]*[A-Z_][A-Z0-9_]*[[:space:]]*=' ${PRJ_ROOT_DIR}/.env | cut -f1 -d"=" | tr '\n' ' '))
for idx in "${!ALL_ENV_PRJ_VARS[@]}"; do
# echo "idx: $idx :: ${ALL_ENV_PRJ_VARS[idx]}=${!ALL_ENV_PRJ_VARS[idx]}"
eval "export ${ALL_ENV_PRJ_VARS[idx]}='${!ALL_ENV_PRJ_VARS[idx]}'"
done

## GOPRIVATE="gitlab.com/cyverse*,github.com/cyverse*,bitbucket.org/cyverse*"
export GOPRIVATE="gitlab.com/cyverse*"
5 changes: 3 additions & 2 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:

jobs:
call-workflow-passing-data:
uses: cyverse-de/github-workflows/.github/workflows/golangci-lint.yml@v0.0.4
uses: cyverse-de/github-workflows/.github/workflows/golangci-lint.yml@v0.1.8
with:
go-version: 1.22
go-version: 1.23
golangci-lint-version: v1.62.2
2 changes: 1 addition & 1 deletion .github/workflows/skaffold-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
call-workflow-passing-data:
uses: cyverse-de/github-workflows/.github/workflows/skaffold-build.yml@v0.0.7
uses: cyverse-de/github-workflows/.github/workflows/skaffold-build.yml@v0.1.6
with:
build-prerelease: ${{ contains(github.ref_name, '-rc') }}
secrets:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ configs/local.yml
configs/local.yaml
**/dotenv
dev-test/
.env
local.mod
local.sum
104 changes: 56 additions & 48 deletions app/addons.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,72 +17,55 @@ import (
)

func (a *App) addAddon(ctx context.Context, request *qms.AddAddonRequest) *qms.AddonResponse {
var newAddon *db.Addon
d := db.New(a.db)

reqAddon := request.Addon
response := qmsinit.NewAddonResponse()

if reqAddon.Name == "" {
response.Error = serrors.NatsError(ctx, errors.New("name must be set"))
return response
}

if reqAddon.Description == "" {
response.Error = serrors.NatsError(ctx, errors.New("descriptions must be set"))
return response
}

if reqAddon.DefaultAmount <= 0.0 {
response.Error = serrors.NatsError(ctx, errors.New("default_amount must be greater than 0.0"))
return response
// Validate the incoming request.
requestedAddon := db.NewAddonFromQMS(request.Addon)
if err := requestedAddon.Validate(); err != nil {
response.Error = serrors.NatsError(ctx, err)
}

if reqAddon.ResourceType.Name == "" && reqAddon.ResourceType.Uuid == "" {
response.Error = serrors.NatsError(ctx, errors.New("resource_type.name or resource_type.uuid must be set"))
return response
if err := requestedAddon.ValidateAddonRateUniqueness(); err != nil {
response.Error = serrors.NatsError(ctx, err)
}

var lookupRT *db.ResourceType

// Start a transaction.
tx, err := d.Begin()
if err != nil {
response.Error = serrors.NatsError(ctx, err)
return response
}
defer func() {
_ = tx.Rollback()
}()
err = tx.Wrap(func() error {

if reqAddon.ResourceType.Name != "" && reqAddon.ResourceType.Uuid == "" {
lookupRT, err = d.GetResourceTypeByName(ctx, reqAddon.ResourceType.Name, db.WithTX(tx))
// Look up the resource type.
resourceType, err := d.LookupResoureType(ctx, &requestedAddon.ResourceType, db.WithTX(tx))
if err != nil {
response.Error = serrors.NatsError(ctx, err)
return response
return err
}
} else {
lookupRT, err = d.GetResourceType(ctx, reqAddon.ResourceType.Uuid, db.WithTX(tx))
requestedAddon.ResourceType = *resourceType

// Add the addon to the database.
addonID, err := d.AddAddon(ctx, requestedAddon, db.WithTX(tx))
if err != nil {
response.Error = serrors.NatsError(ctx, err)
return response
return err
}
}

newAddon := db.NewAddonFromQMS(request.Addon)
newAddon.ResourceType = *lookupRT
// Retrieve the addon from the database.
newAddon, err = d.GetAddonByID(ctx, addonID, db.WithTX(tx))
if err != nil {
return err
}

newID, err := d.AddAddon(ctx, newAddon, db.WithTX(tx))
return nil
})
if err != nil {
response.Error = serrors.NatsError(ctx, err)
return response
}

if err = tx.Commit(); err != nil {
response.Error = serrors.NatsError(ctx, err)
return response
}

// Return the inserted addon.
response.Addon = newAddon.ToQMSType()
response.Addon.Uuid = newID
return response
}

Expand Down Expand Up @@ -191,14 +174,28 @@ func (a *App) updateAddon(ctx context.Context, request *qms.UpdateAddonRequest)

updateAddon := db.NewUpdateAddonFromQMS(request)

result, err := d.UpdateAddon(ctx, updateAddon)
tx, err := d.Begin()
if err != nil {
response.Error = serrors.NatsError(ctx, err)
return response
}
err = tx.Wrap(func() error {
_, err := d.UpdateAddon(ctx, updateAddon, db.WithTX(tx))
if err != nil {
return err
}

response.Addon = result.ToQMSType()
result, err := d.GetAddonByID(ctx, updateAddon.ID, db.WithTX(tx))
if err != nil {
return err
}
response.Addon = result.ToQMSType()

return nil
})
if err != nil {
response.Error = serrors.NatsError(ctx, err)
}
return response
}

Expand Down Expand Up @@ -314,15 +311,26 @@ func (a *App) listSubscriptionAddons(ctx context.Context, request *requests.ByUU
response := qmsinit.NewSubscriptionAddonListResponse()

d := db.New(a.db)

results, err := d.ListSubscriptionAddons(ctx, request.Uuid)
tx, err := d.Begin()
if err != nil {
response.Error = serrors.NatsError(ctx, err)
return response
}

for _, addon := range results {
response.SubscriptionAddons = append(response.SubscriptionAddons, addon.ToQMSType())
err = tx.Wrap(func() error {
results, err := d.ListSubscriptionAddons(ctx, request.Uuid, db.WithTX(tx))
if err != nil {
return err
}

for _, addon := range results {
response.SubscriptionAddons = append(response.SubscriptionAddons, addon.ToQMSType())
}

return nil
})
if err != nil {
response.Error = serrors.NatsError(ctx, err)
}

return response
Expand Down
86 changes: 43 additions & 43 deletions app/plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,9 @@ func (a *App) listPlans(ctx context.Context) *qms.PlanList {
return response
}

for _, p := range plans {
newP := &qms.Plan{
Uuid: p.ID,
Name: p.Name,
Description: p.Description,
PlanQuotaDefaults: []*qms.QuotaDefault{},
}

for _, q := range p.QuotaDefaults {
newP.PlanQuotaDefaults = append(newP.PlanQuotaDefaults, &qms.QuotaDefault{
Uuid: q.ID,
QuotaValue: q.QuotaValue,
ResourceType: &qms.ResourceType{
Uuid: q.ResourceType.ID,
Name: q.ResourceType.Name,
Unit: q.ResourceType.Unit,
},
})
}

response.Plans = append(response.Plans, newP)
response.Plans = make([]*qms.Plan, len(plans))
for i, p := range plans {
response.Plans[i] = p.ToQMSPlan()
}

return response
Expand Down Expand Up @@ -83,44 +65,62 @@ func (a *App) addPlan(ctx context.Context, request *qms.AddPlanRequest) *qms.Pla

d := db.New(a.db)

var qd []db.PlanQuotaDefault
var newPlanID string
tx, err := d.Begin()
if err != nil {
response.Error = errors.NatsError(ctx, err)
return response
}
err = tx.Wrap(func() error {
var err error

for _, pqd := range request.Plan.PlanQuotaDefaults {
qd = append(qd, db.PlanQuotaDefault{
QuotaValue: float64(pqd.QuotaValue),
ResourceType: db.ResourceType{
ID: pqd.ResourceType.Uuid,
Name: pqd.ResourceType.Name,
Unit: pqd.ResourceType.Unit,
},
})
incomingPlan := db.NewPlanFromQMS(request.Plan)
err := incomingPlan.Validate()
if err != nil {
return err
}

existingPlan, err := d.GetPlanByName(ctx, incomingPlan.Name, db.WithTX(tx))
if err != nil {
return err
} else if existingPlan != nil {
return fmt.Errorf("a plan named %s already exists", incomingPlan.Name)
}

newPlanID, err = d.AddPlan(ctx, &db.Plan{
Name: request.Plan.Name,
Description: request.Plan.Description,
QuotaDefaults: qd,
}, db.WithTX(tx))
for i, pqd := range incomingPlan.QuotaDefaults {
rt, err := d.LookupResoureType(ctx, &pqd.ResourceType, db.WithTX(tx))
if err != nil {
return err
}
incomingPlan.QuotaDefaults[i].ResourceType = *rt
}

return err
err = incomingPlan.ValidateQuotaDefaultUniqueness()
if err != nil {
return err
}

err = incomingPlan.ValidatePlanRateUniqueness()
if err != nil {
return err
}

newPlanID, err := d.AddPlan(ctx, incomingPlan, db.WithTX(tx))
if err != nil {
return err
}

plan, err := d.GetPlanByID(ctx, newPlanID, db.WithTX(tx))
if err != nil {
return err
}

response.Plan = plan.ToQMSPlan()
return nil
})

if err != nil {
response.Error = errors.NatsError(ctx, err)
return response
}

response.Plan = request.Plan
response.Plan.Uuid = newPlanID

return response
}

Expand Down
Loading

0 comments on commit 36f15cd

Please sign in to comment.