Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
# See GitHub's docs for more information on this file:
# https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every weekday
interval: "daily"

# Maintain dependencies for Go modules
- package-ecosystem: "gomod"
directory: "/server"
schedule:
# Check for updates to Go modules every weekday
interval: "daily"

# Maintain dependencies for npm
- package-ecosystem: "npm"
directory: "/frontend"
schedule:
interval: "daily"

# Maintain dependencies for Composer
- package-ecosystem: "composer"
directory: "/frontend"
schedule:
interval: "daily"
49 changes: 32 additions & 17 deletions server/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ import (
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/stripe/stripe-go/v74"
"github.com/threefoldtech/tfgrid-sdk-go/grid-client/calculator"
"github.com/threefoldtech/tfgrid-sdk-go/grid-client/deployer"
)

// App for all dependencies of backend server
type App struct {
config internal.Configuration
server server
db models.DB
redis streams.RedisClient
deployer c4sDeployer.Deployer
config internal.Configuration
server server
db models.DB
redis streams.RedisClient
deployer c4sDeployer.Deployer
calculator calculator.Calculator
}

// NewApp creates new server app all configurations
Expand Down Expand Up @@ -63,16 +66,19 @@ func NewApp(ctx context.Context, configFile string) (app *App, err error) {
}

return &App{
config: config,
server: *server,
db: db,
redis: redis,
deployer: newDeployer,
config: config,
server: *server,
db: db,
redis: redis,
deployer: newDeployer,
calculator: tfPluginClient.Calculator,
}, nil
}

// Start starts the app
func (a *App) Start(ctx context.Context) (err error) {
stripe.Key = a.config.StripeSecret

a.registerHandlers()
a.startBackgroundWorkers(ctx)

Expand All @@ -83,6 +89,9 @@ func (a *App) startBackgroundWorkers(ctx context.Context) {
// notify admins
go a.notifyAdmins()

// notify expired packages
go a.notifyUsersExpiredPackages()

// periodic deployments
go a.deployer.PeriodicRequests(ctx, substrateBlockDiffInSeconds)
go a.deployer.PeriodicDeploy(ctx, substrateBlockDiffInSeconds)
Expand All @@ -102,10 +111,11 @@ func (a *App) registerHandlers() {

// sub routes with authorization
userRouter := authRouter.PathPrefix("/user").Subrouter()
quotaRouter := authRouter.PathPrefix("/quota").Subrouter()
notificationRouter := authRouter.PathPrefix("/notification").Subrouter()
vmRouter := authRouter.PathPrefix("/vm").Subrouter()
k8sRouter := authRouter.PathPrefix("/k8s").Subrouter()
pkgRouter := authRouter.PathPrefix("/package").Subrouter()
balanceRouter := authRouter.PathPrefix("/balance").Subrouter()

// sub routes with no authorization
unAuthUserRouter := versionRouter.PathPrefix("/user").Subrouter()
Expand All @@ -114,7 +124,6 @@ func (a *App) registerHandlers() {
// sub routes with admin access
voucherRouter := adminRouter.PathPrefix("/voucher").Subrouter()
maintenanceRouter := adminRouter.PathPrefix("/maintenance").Subrouter()
balanceRouter := adminRouter.PathPrefix("/balance").Subrouter()

unAuthUserRouter.HandleFunc("/signup", WrapFunc(a.SignUpHandler)).Methods("POST", "OPTIONS")
unAuthUserRouter.HandleFunc("/signup/verify_email", WrapFunc(a.VerifySignUpCodeHandler)).Methods("POST", "OPTIONS")
Expand All @@ -129,31 +138,37 @@ func (a *App) registerHandlers() {
userRouter.HandleFunc("/apply_voucher", WrapFunc(a.ApplyForVoucherHandler)).Methods("POST", "OPTIONS")
userRouter.HandleFunc("/activate_voucher", WrapFunc(a.ActivateVoucherHandler)).Methods("PUT", "OPTIONS")

quotaRouter.HandleFunc("", WrapFunc(a.GetQuotaHandler)).Methods("GET", "OPTIONS")

notificationRouter.HandleFunc("", WrapFunc(a.ListNotificationsHandler)).Methods("GET", "OPTIONS")
notificationRouter.HandleFunc("/{id}", WrapFunc(a.UpdateNotificationsHandler)).Methods("PUT", "OPTIONS")

vmRouter.HandleFunc("", WrapFunc(a.DeployVMHandler)).Methods("POST", "OPTIONS")
vmRouter.HandleFunc("/validate/{name}", WrapFunc(a.ValidateVMNameHandler)).Methods("Get", "OPTIONS")
vmRouter.HandleFunc("/validate/{name}", WrapFunc(a.ValidateVMNameHandler)).Methods("GET", "OPTIONS")
vmRouter.HandleFunc("/{id}", WrapFunc(a.GetVMHandler)).Methods("GET", "OPTIONS")
vmRouter.HandleFunc("/{id}", WrapFunc(a.DeleteVMHandler)).Methods("DELETE", "OPTIONS")
vmRouter.HandleFunc("", WrapFunc(a.ListVMsHandler)).Methods("GET", "OPTIONS")
vmRouter.HandleFunc("", WrapFunc(a.DeleteAllVMsHandler)).Methods("DELETE", "OPTIONS")

k8sRouter.HandleFunc("", WrapFunc(a.K8sDeployHandler)).Methods("POST", "OPTIONS")
k8sRouter.HandleFunc("/validate/{name}", WrapFunc(a.ValidateK8sNameHandler)).Methods("Get", "OPTIONS")
k8sRouter.HandleFunc("/validate/{name}", WrapFunc(a.ValidateK8sNameHandler)).Methods("GET", "OPTIONS")
k8sRouter.HandleFunc("/{id}", WrapFunc(a.K8sGetHandler)).Methods("GET", "OPTIONS")
k8sRouter.HandleFunc("/{id}", WrapFunc(a.K8sDeleteHandler)).Methods("DELETE", "OPTIONS")
k8sRouter.HandleFunc("", WrapFunc(a.K8sGetAllHandler)).Methods("GET", "OPTIONS")
k8sRouter.HandleFunc("", WrapFunc(a.K8sDeleteAllHandler)).Methods("DELETE", "OPTIONS")

balanceRouter.HandleFunc("/charge", WrapFunc(a.chargeBalanceHandler)).Methods("POST", "OPTIONS")
balanceRouter.HandleFunc("/charged", WrapFunc(a.balanceChargedHandler)).Methods("POST", "OPTIONS")
balanceRouter.HandleFunc("", WrapFunc(a.getBalanceHandler)).Methods("GET", "OPTIONS")

pkgRouter.HandleFunc("/buy", WrapFunc(a.buyPackageHandler)).Methods("POST", "OPTIONS")
pkgRouter.HandleFunc("/renew", WrapFunc(a.renewPackageHandler)).Methods("PUT", "OPTIONS")
pkgRouter.HandleFunc("/", WrapFunc(a.listPackagesHandler)).Methods("GET", "OPTIONS")

unAuthMaintenanceRouter.HandleFunc("", WrapFunc(a.GetMaintenanceHandler)).Methods("GET", "OPTIONS")

// ADMIN ACCESS
adminRouter.HandleFunc("/user/all", WrapFunc(a.GetAllUsersHandler)).Methods("GET", "OPTIONS")
adminRouter.HandleFunc("/deployment/count", WrapFunc(a.GetDlsCountHandler)).Methods("GET", "OPTIONS")
balanceRouter.HandleFunc("", WrapFunc(a.GetBalanceHandler)).Methods("GET", "OPTIONS")
adminRouter.HandleFunc("/balance/tft", WrapFunc(a.GetBalanceHandler)).Methods("GET", "OPTIONS")
maintenanceRouter.HandleFunc("", WrapFunc(a.UpdateMaintenanceHandler)).Methods("PUT", "OPTIONS")

voucherRouter.HandleFunc("", WrapFunc(a.GenerateVoucherHandler)).Methods("POST", "OPTIONS")
Expand Down
30 changes: 30 additions & 0 deletions server/app/balance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Package app for c4s backend app
package app

import (
"github.com/stripe/stripe-go/v74"
"github.com/stripe/stripe-go/v74/price"
"github.com/stripe/stripe-go/v74/product"
)

// CreateBalanceProductInStripe creates a new stripe product for balance
func createBalanceProductInStripe(balance int64) (string, error) {
params := &stripe.ProductParams{Name: stripe.String("user balance")}
prod, err := product.New(params)
if err != nil {
return "", err
}

paramsPrice := &stripe.PriceParams{
Product: stripe.String(prod.ID),
UnitAmount: stripe.Int64(balance),
Currency: stripe.String(string(stripe.CurrencyUSD)),
}

priceObj, err := price.New(paramsPrice)
if err != nil {
return "", err
}

return priceObj.ID, nil
}
10 changes: 5 additions & 5 deletions server/app/k8s_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,18 @@ func (a *App) K8sDeployHandler(req *http.Request) (interface{}, Response) {
return nil, BadRequest(errors.New("invalid kubernetes data"))
}

// quota verification
quota, err := a.db.GetUserQuota(user.ID.String())
// balance verification
balance, err := a.db.GetBalanceByUserID(user.ID.String())
if err == gorm.ErrRecordNotFound {
log.Error().Err(err).Send()
return nil, NotFound(errors.New("user quota is not found"))
return nil, NotFound(errors.New("balance is not found"))
}
if err != nil {
log.Error().Err(err).Send()
return nil, InternalServerError(errors.New(internalServerErrorMsg))
}

_, err = deployer.ValidateK8sQuota(k8sDeployInput, quota.Vms, quota.PublicIPs)
err = deployer.ValidateK8sQuota(k8sDeployInput, balance)
if err != nil {
log.Error().Err(err).Send()
return nil, BadRequest(errors.New(err.Error()))
Expand All @@ -75,7 +75,7 @@ func (a *App) K8sDeployHandler(req *http.Request) (interface{}, Response) {
return nil, BadRequest(errors.New("kubernetes master name is not available, please choose a different name"))
}

err = a.deployer.Redis.PushK8sRequest(streams.K8sDeployRequest{User: user, Input: k8sDeployInput, AdminSSHKey: a.config.AdminSSHKey})
err = a.deployer.Redis.PushK8sRequest(streams.K8sDeployRequest{User: user, Input: k8sDeployInput, AdminSSHKey: a.config.AdminSSHKey, ExpirationToleranceInDays: a.config.ExpirationToleranceInDays})
if err != nil {
log.Error().Err(err).Send()
return nil, InternalServerError(errors.New(internalServerErrorMsg))
Expand Down
Loading