Skip to content

Commit 8212ebf

Browse files
authored
Merge branch 'main' into 6840-tour-styles-fix
2 parents 9d11c4a + 784ded5 commit 8212ebf

4 files changed

Lines changed: 192 additions & 2 deletions

File tree

forge/db/controllers/Project.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,8 @@ module.exports = {
488488
const days = autoStackUpdate.days
489489
const hours = autoStackUpdate.hours
490490
// generate random day and hour in ranges
491-
const day = days[Math.round(days.length * Math.random())]
492-
const hour = hours[Math.round(hours.length * Math.random())]
491+
const day = days[Math.floor(days.length * Math.random())]
492+
const hour = hours[Math.floor(hours.length * Math.random())]
493493
await instance.updateSetting(`${KEY_STACK_UPGRADE_HOUR}_${day}`, { hour })
494494
}
495495
}

forge/ee/lib/autoUpdateStacks/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ module.exports.init = async function (app) {
22
app.config.features.register('autoStackUpdate', true, true)
33

44
app.housekeeper.registerTask(require('./tasks/upgrade-stack'))
5+
app.housekeeper.registerTask(require('./tasks/enforce-team-rules'))
56
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* If a Team changes TeamType apply new AutoUpdate rules
3+
*/
4+
const { KEY_STACK_UPGRADE_HOUR } = require('../../../../db/models/ProjectSettings')
5+
const { randomInt } = require('../../../../housekeeper/utils')
6+
7+
module.exports = {
8+
name: 'fixTeamStackUpdateRules',
9+
startup: false,
10+
schedule: `${randomInt(0, 29)} ${randomInt(0, 23)} * * *`, // random time every day
11+
run: async function (app) {
12+
if (app.config.features.enabled('autoStackUpdate')) {
13+
app.log.info('Running AutoStackUpgrade Teams Tests')
14+
const teamTypes = await app.db.models.TeamType.getAll({}, { active: true })
15+
for (const teamType of teamTypes.types) {
16+
if (teamType) {
17+
const typeProperties = teamType.properties
18+
if (typeProperties.autoStackUpdate?.allowDisable === false) {
19+
app.log.info(`Found TeamType ${teamType.name} needs to enforce AutoStackUpdate`)
20+
const autoStackUpdate = teamType.getProperty('autoStackUpdate')
21+
// this TeamType needs to enforce restart rules.
22+
// get all teams with this type, then get all instances in those teams
23+
const teams = await app.db.models.Team.findAll({
24+
where: {
25+
TeamTypeId: teamType.id
26+
}
27+
})
28+
for (const team of teams) {
29+
if (team) {
30+
const instances = await app.db.models.Project.byTeam(team.id)
31+
for (const instance of instances) {
32+
if (instance) {
33+
let found = false
34+
for (let day = 0; day < 7; day++) {
35+
const k = await instance.getSetting(`${KEY_STACK_UPGRADE_HOUR}_${day}`)
36+
if (k) {
37+
found = true
38+
break
39+
}
40+
}
41+
42+
if (!found) {
43+
const days = autoStackUpdate.days
44+
const hours = autoStackUpdate.hours
45+
// generate random day and hour in ranges
46+
const day = days[Math.floor(days.length * Math.random())]
47+
const hour = hours[Math.floor(hours.length * Math.random())]
48+
app.log.info(`AutoStackUpgrade: applying update schedule ${day}/${hour} to instance ${instance.id} in team ${team.hashid}`)
49+
await instance.updateSetting(`${KEY_STACK_UPGRADE_HOUR}_${day}`, { hour })
50+
}
51+
}
52+
}
53+
}
54+
}
55+
}
56+
}
57+
}
58+
}
59+
}
60+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
const { Op } = require('sequelize')
2+
const should = require('should') // eslint-disable-line
3+
4+
const { KEY_STACK_UPGRADE_HOUR } = require('../../../../../../forge/db/models/ProjectSettings')
5+
const enforceTeamRulesTask = require('../../../../../../forge/ee/lib/autoUpdateStacks/tasks/enforce-team-rules')
6+
const setup = require('../../setup')
7+
8+
describe('Automatic Stack Upgrade', function () {
9+
let app
10+
11+
before(async function () {
12+
setup.setupStripe()
13+
app = await setup()
14+
15+
const defaultTeamType = await app.db.models.TeamType.findOne({ where: { id: 1 } })
16+
17+
const autoTeamTypeProperties = {
18+
name: 'AutoUpdate',
19+
order: 2,
20+
description: 'TeamType that forces Stack Updates',
21+
properties: {
22+
users: {
23+
limit: 10
24+
},
25+
runtimes: {
26+
limit: 20
27+
},
28+
devices: {
29+
productId: 'prod_device',
30+
priceId: 'price_device',
31+
description: '$5/month',
32+
limit: 10
33+
},
34+
billing: {
35+
productId: 'prod_team',
36+
priceId: 'price_team',
37+
description: '$10/month',
38+
proration: 'always_invoice'
39+
},
40+
trial: {
41+
active: false
42+
},
43+
enableAllFeatures: true,
44+
features: {
45+
fileStorageLimit: null,
46+
contextLimit: null
47+
},
48+
teamBroker: {
49+
clients: {
50+
limit: 10
51+
}
52+
},
53+
autoStackUpdate: {
54+
enabled: true,
55+
days: [0, 6],
56+
hours: [0, 1, 2, 3, 4],
57+
allowDisable: false
58+
}
59+
}
60+
}
61+
62+
autoTeamTypeProperties.instances = defaultTeamType.properties.instances
63+
64+
const autoTeamType = await app.db.models.TeamType.create(autoTeamTypeProperties)
65+
app.autoTeamType = autoTeamType
66+
})
67+
68+
after(async function () {
69+
if (app) {
70+
await app.close()
71+
app = null
72+
}
73+
setup.resetStripe()
74+
})
75+
76+
describe('Update after TeamType change', async function () {
77+
it('Instance properties updated', async function () {
78+
const instanceStartSettings = await app.db.models.ProjectSettings.findAll({
79+
where: {
80+
ProjectId: app.instance.id,
81+
key: {
82+
[Op.like]: `${KEY_STACK_UPGRADE_HOUR}_%`
83+
}
84+
}
85+
})
86+
instanceStartSettings.should.have.length(0)
87+
await app.team.updateTeamType(app.autoTeamType, { interval: 'month' })
88+
await enforceTeamRulesTask.run(app)
89+
const instanceAfterSettings = await app.db.models.ProjectSettings.findAll({
90+
where: {
91+
ProjectId: app.instance.id,
92+
key: {
93+
[Op.like]: `${KEY_STACK_UPGRADE_HOUR}_%`
94+
}
95+
}
96+
})
97+
instanceAfterSettings.should.have.length(1)
98+
instanceAfterSettings[0].value.hour.should.be.oneOf([0, 1, 2, 3, 4])
99+
const day = parseInt(instanceAfterSettings[0].key.split('_')[1])
100+
day.should.be.oneOf([0, 6])
101+
})
102+
it('Existing Instance properties not updated', async function () {
103+
// depends on previous test
104+
const instanceStartSettings = await app.db.models.ProjectSettings.findAll({
105+
where: {
106+
ProjectId: app.instance.id,
107+
key: {
108+
[Op.like]: `${KEY_STACK_UPGRADE_HOUR}_%`
109+
}
110+
}
111+
})
112+
instanceStartSettings.should.have.length(1)
113+
const day = parseInt(instanceStartSettings[0].key.split('_')[1])
114+
const hour = instanceStartSettings[0].value.hour
115+
await enforceTeamRulesTask.run(app)
116+
const instanceAfterSettings = await app.db.models.ProjectSettings.findAll({
117+
where: {
118+
ProjectId: app.instance.id,
119+
key: {
120+
[Op.like]: `${KEY_STACK_UPGRADE_HOUR}_%`
121+
}
122+
}
123+
})
124+
instanceAfterSettings.should.have.length(1)
125+
day.should.equal(parseInt(instanceAfterSettings[0].key.split('_')[1]))
126+
hour.should.equal(instanceAfterSettings[0].value.hour)
127+
})
128+
})
129+
})

0 commit comments

Comments
 (0)