Sync app quota to correct number, reset and disable rows quota

This commit is contained in:
Rory Powell 2022-01-11 17:49:42 +00:00
parent d3a0534798
commit ea82983ebd
10 changed files with 105 additions and 32 deletions

View File

@ -21,6 +21,7 @@ exports.StaticDatabases = {
name: "global-db", name: "global-db",
docs: { docs: {
apiKeys: "apikeys", apiKeys: "apikeys",
usageQuota: "usage_quota",
}, },
}, },
// contains information about tenancy and so on // contains information about tenancy and so on
@ -28,7 +29,6 @@ exports.StaticDatabases = {
name: "global-info", name: "global-info",
docs: { docs: {
tenants: "tenants", tenants: "tenants",
usageQuota: "usage_quota",
}, },
}, },
} }

View File

@ -450,7 +450,7 @@ async function getScopedConfig(db, params) {
function generateNewUsageQuotaDoc() { function generateNewUsageQuotaDoc() {
return { return {
_id: StaticDatabases.PLATFORM_INFO.docs.usageQuota, _id: StaticDatabases.GLOBAL.docs.usageQuota,
quotaReset: Date.now() + 2592000000, quotaReset: Date.now() + 2592000000,
usageQuota: { usageQuota: {
automationRuns: 0, automationRuns: 0,

View File

@ -68,4 +68,5 @@ module.exports = {
}, },
StaticDatabases, StaticDatabases,
constants: require("./constants"), constants: require("./constants"),
migrations: require("./migrations"),
} }

View File

@ -7,11 +7,13 @@ exports.MIGRATION_DBS = {
exports.MIGRATIONS = { exports.MIGRATIONS = {
USER_EMAIL_VIEW_CASING: "user_email_view_casing", USER_EMAIL_VIEW_CASING: "user_email_view_casing",
SYNC_APP_AND_RESET_ROWS_QUOTAS: "sync_app_and_reset_rows_quotas",
} }
const DB_LOOKUP = { const DB_LOOKUP = {
[exports.MIGRATION_DBS.GLOBAL_DB]: [ [exports.MIGRATION_DBS.GLOBAL_DB]: [
exports.MIGRATIONS.USER_EMAIL_VIEW_CASING, exports.MIGRATIONS.USER_EMAIL_VIEW_CASING,
exports.MIGRATIONS.SYNC_APP_AND_RESET_ROWS_QUOTAS,
], ],
} }

View File

@ -17,14 +17,14 @@ const METHOD_MAP = {
} }
const DOMAIN_MAP = { const DOMAIN_MAP = {
rows: usageQuota.Properties.ROW, // rows: usageQuota.Properties.ROW, // works - disabled
upload: usageQuota.Properties.UPLOAD, // upload: usageQuota.Properties.UPLOAD, // doesn't work yet
views: usageQuota.Properties.VIEW, // views: usageQuota.Properties.VIEW, // doesn't work yet
users: usageQuota.Properties.USER, // users: usageQuota.Properties.USER, // doesn't work yet
applications: usageQuota.Properties.APPS, applications: usageQuota.Properties.APPS,
// this will not be updated by endpoint calls // this will not be updated by endpoint calls
// instead it will be updated by triggerInfo // instead it will be updated by triggerInfo
automationRuns: usageQuota.Properties.AUTOMATION, // automationRuns: usageQuota.Properties.AUTOMATION, // doesn't work yet
} }
function getProperty(url) { function getProperty(url) {

View File

@ -0,0 +1,27 @@
const { MIGRATIONS, MIGRATION_DBS, migrateIfRequired } =
require("@budibase/auth").migrations
const { getGlobalDB } = require("@budibase/auth/tenancy")
const { getUsageQuotaDoc } = require("../utilities/usageQuota")
const { getAllApps } = require("@budibase/auth/db")
const CouchDB = require("../db")
exports.migrate = async () => {
await migrateIfRequired(
MIGRATION_DBS.GLOBAL_DB,
MIGRATIONS.SYNC_APP_AND_RESET_ROWS_QUOTAS,
async () => {
const globalDb = getGlobalDB()
const usageDoc = await getUsageQuotaDoc(globalDb)
// reset the rows
usageDoc.usageQuota.rows = 0
// sync the apps
const apps = await getAllApps(CouchDB, { dev: true })
const appCount = apps ? apps.length : 0
usageDoc.usageQuota.apps = appCount
await globalDb.put(usageDoc)
}
)
}

View File

@ -0,0 +1,39 @@
const { getGlobalDB } = require("@budibase/auth/tenancy")
const TestConfig = require("../../tests/utilities/TestConfiguration")
const { getUsageQuotaDoc, update, Properties } = require("../../utilities/usageQuota")
const { migrate } = require("../sync_app_and_reset_rows_quotas")
const env = require("../../environment")
describe("Sync App And Reset Rows Quotas Migration", () => {
let config = new TestConfig(false)
beforeEach(async () => {
await config.init()
env._set("USE_QUOTAS", 1)
})
afterAll(config.end)
it("migrates successfully", async () => {
// create the usage quota doc and mock usages
const db = getGlobalDB()
await getUsageQuotaDoc(db)
await update(Properties.APPS, 3)
await update(Properties.ROW, 300)
let usageDoc = await getUsageQuotaDoc(db)
expect(usageDoc.usageQuota.apps).toEqual(3)
expect(usageDoc.usageQuota.rows).toEqual(300)
// create an extra app to test the migration
await config.createApp("quota-test")
// migrate
await migrate()
// assert the migration worked
usageDoc = await getUsageQuotaDoc(db)
expect(usageDoc.usageQuota.apps).toEqual(2)
expect(usageDoc.usageQuota.rows).toEqual(0)
})
})

View File

@ -5,24 +5,20 @@ const {
generateNewUsageQuotaDoc, generateNewUsageQuotaDoc,
} = require("@budibase/auth/db") } = require("@budibase/auth/db")
function getNewQuotaReset() {
return Date.now() + 2592000000
}
exports.Properties = { exports.Properties = {
ROW: "rows", ROW: "rows", // mostly works - disabled - app / table deletion not yet accounted for
UPLOAD: "storage", UPLOAD: "storage", // doesn't work yet
VIEW: "views", VIEW: "views", // doesn't work yet
USER: "users", USER: "users", // doesn't work yet
AUTOMATION: "automationRuns", AUTOMATION: "automationRuns", // doesn't work yet
APPS: "apps", APPS: "apps", // works
EMAILS: "emails", EMAILS: "emails", // doesn't work yet
} }
async function getUsageQuotaDoc(db) { exports.getUsageQuotaDoc = async db => {
let quota let quota
try { try {
quota = await db.get(StaticDatabases.PLATFORM_INFO.docs.usageQuota) quota = await db.get(StaticDatabases.GLOBAL.docs.usageQuota)
} catch (err) { } catch (err) {
// doc doesn't exist. Create it // doc doesn't exist. Create it
quota = await db.post(generateNewUsageQuotaDoc()) quota = await db.post(generateNewUsageQuotaDoc())
@ -45,15 +41,7 @@ exports.update = async (property, usage) => {
try { try {
const db = getGlobalDB() const db = getGlobalDB()
const quota = await getUsageQuotaDoc(db) const quota = await exports.getUsageQuotaDoc(db)
// Check if the quota needs reset
if (Date.now() >= quota.quotaReset) {
quota.quotaReset = getNewQuotaReset()
for (let prop of Object.keys(quota.usageQuota)) {
quota.usageQuota[prop] = 0
}
}
// increment the quota // increment the quota
quota.usageQuota[property] += usage quota.usageQuota[property] += usage

View File

@ -0,0 +1,18 @@
// UNUSED CODE
// Preserved for future use
/* eslint-disable no-unused-vars */
function getNewQuotaReset() {
return Date.now() + 2592000000
}
function resetQuotasIfRequired(quota) {
// Check if the quota needs reset
if (Date.now() >= quota.quotaReset) {
quota.quotaReset = getNewQuotaReset()
for (let prop of Object.keys(quota.usageQuota)) {
quota.usageQuota[prop] = 0
}
}
}

View File

@ -69,9 +69,7 @@ exports.adminUser = async ctx => {
if (!env.SELF_HOSTED) { if (!env.SELF_HOSTED) {
// could be a scenario where it exists, make sure its clean // could be a scenario where it exists, make sure its clean
try { try {
const usageQuota = await db.get( const usageQuota = await db.get(StaticDatabases.GLOBAL.docs.usageQuota)
StaticDatabases.PLATFORM_INFO.docs.usageQuota
)
if (usageQuota) { if (usageQuota) {
await db.remove(usageQuota._id, usageQuota._rev) await db.remove(usageQuota._id, usageQuota._rev)
} }