Skip to content

Commit 77dc740

Browse files
committed
NC | Online Upgrade | add host config dir version | Health - add blocked hosts check
Signed-off-by: Romy <[email protected]>
1 parent 6a079ed commit 77dc740

File tree

7 files changed

+209
-63
lines changed

7 files changed

+209
-63
lines changed

src/cmd/nsfs.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ async function main(argv = minimist(process.argv.slice(2))) {
330330
const nc_upgrade_manager = new NCUpgradeManager(config_fs);
331331
await nc_upgrade_manager.update_rpm_upgrade();
332332
} else {
333-
system_data = await config_fs.init_nc_system();
333+
system_data = await config_fs.register_hostname_in_system_json();
334334
}
335335
}
336336

src/manage_nsfs/health.js

+45-2
Original file line numberDiff line numberDiff line change
@@ -450,15 +450,17 @@ class NSFSHealth {
450450
*/
451451
_get_config_dir_status(system_data) {
452452
if (!system_data) return { error: 'system data is missing' };
453+
const blocked_hosts_status = this._get_blocked_hosts_status(this.config_fs, system_data);
453454
const config_dir_data = system_data.config_directory;
454-
if (!config_dir_data) return { error: 'config directory data is missing, must upgrade config directory' };
455+
if (!config_dir_data) return { error: 'config directory data is missing, must upgrade config directory', blocked_hosts: blocked_hosts_status };
455456
const config_dir_upgrade_status = this._get_config_dir_upgrade_status(config_dir_data);
456457
return {
457458
phase: config_dir_data.phase,
458459
config_dir_version: config_dir_data.config_dir_version,
459460
upgrade_package_version: config_dir_data.upgrade_package_version,
460461
upgrade_status: config_dir_upgrade_status,
461-
error: config_dir_upgrade_status.error || undefined
462+
error: config_dir_upgrade_status.error || undefined,
463+
blocked_hosts: blocked_hosts_status
462464
};
463465
}
464466

@@ -480,6 +482,47 @@ class NSFSHealth {
480482
}
481483
}
482484

485+
/**
486+
* _get_blocked_hosts_status checks if there are any hosts blocked for updating the config directory
487+
* 1. if only config dir was upgraded (>=5.18.0) - host's config_dir_version does not exist (<5.18.0) and system's config_dir_version exists (>=5.18.0)
488+
* it means it's not blocked because the source code won't include _throw_if_config_dir_locked() but it still can create invalid config files, therefore including it in the blocked list
489+
* 2. if system's config_dir_version wasn't upgraded yet and hosts's config_dir_version exist (>= 5.18.0)
490+
* it means updates to the config directory from this host are blocked
491+
* 3. if system's config dir version does not match the hosts's config_dir_version - updates to the config directory from this host are blocked
492+
* @param {import('../sdk/config_fs').ConfigFS} config_fs
493+
* @param {Object} system_data
494+
* @returns {Object}
495+
*/
496+
_get_blocked_hosts_status(config_fs, system_data) {
497+
const system_config_dir_version = system_data.config_directory?.config_dir_version;
498+
const hosts_data = config_fs.get_hosts_data(system_data);
499+
let res;
500+
for (const host_name of Object.keys(hosts_data)) {
501+
const host_data = hosts_data[host_name];
502+
let version_compare_err;
503+
const only_config_dir_upgraded = !host_data.config_dir_version && system_config_dir_version;
504+
const only_host_upgraded = host_data.config_dir_version && !system_config_dir_version;
505+
if (only_config_dir_upgraded) {
506+
version_compare_err = `host's config_dir_version is undefined, system's config_dir_version already upgraded to ${system_config_dir_version}, updates to the config directory via the host will result with invalid config_dir files until the host source code upgrade`;
507+
} else if (only_host_upgraded) {
508+
version_compare_err = `host's config_dir_version is ${host_data.config_dir_version}, system's config_dir_version is undefined, updates to the config directory will be blocked until the config dir upgrade`;
509+
} else {
510+
version_compare_err = host_data.config_dir_version && system_config_dir_version &&
511+
config_fs.compare_host_and_config_dir_version(host_data.config_dir_version, system_config_dir_version);
512+
}
513+
if (version_compare_err !== undefined) {
514+
res = Object.assign(res || {}, {
515+
[host_name]: {
516+
host_version: host_data.current_version,
517+
host_config_dir_version: host_data.config_dir_version,
518+
error: version_compare_err
519+
}
520+
});
521+
}
522+
}
523+
return res;
524+
}
525+
483526
/**
484527
* _calc_health_status calcs the overall health status of NooBaa NC
485528
* @param {{service_status: String,

src/sdk/config_fs.js

+37-8
Original file line numberDiff line numberDiff line change
@@ -1070,15 +1070,15 @@ class ConfigFS {
10701070
}
10711071

10721072
/**
1073-
* init_nc_system creates/updates system.json file
1073+
* register_hostname_in_system_json creates/updates system.json file
10741074
* if system.json does not exist (a new system) - host and config dir data will be set on the newly created file
10751075
* else -
10761076
* 1. if the host data already exist in system.json - return
1077-
* 2. set the host data on system.json data and update the file
1077+
* 2. update the host data on system.json
10781078
* Note - config directory data on upgraded systems will be set by nc_upgrade_manager
1079-
* @returns
1079+
* @returns {Promise<Object>}
10801080
*/
1081-
async init_nc_system() {
1081+
async register_hostname_in_system_json() {
10821082
const system_data = await this.get_system_config_file({silent_if_missing: true});
10831083

10841084
let updated_system_json = system_data || {};
@@ -1176,21 +1176,40 @@ class ConfigFS {
11761176
const system_data = await this.get_system_config_file({ silent_if_missing: true });
11771177
// if system was never created, currently we allow using the CLI without creating system
11781178
// we should consider changing it to throw on this scenario as well
1179+
// https://github.com/noobaa/noobaa-core/issues/8468
11791180
if (!system_data) return;
11801181
if (!system_data.config_directory) {
11811182
throw new RpcError('CONFIG_DIR_VERSION_MISMATCH', `config_directory data is missing in system.json, any updates to the config directory are blocked until the config dir upgrade`);
11821183
}
11831184
const running_code_config_dir_version = this.config_dir_version;
11841185
const system_config_dir_version = system_data.config_directory.config_dir_version;
1186+
const ver_comparison_err = this.compare_host_and_config_dir_version(running_code_config_dir_version, system_config_dir_version);
1187+
if (ver_comparison_err !== undefined) {
1188+
throw new RpcError('CONFIG_DIR_VERSION_MISMATCH', ver_comparison_err);
1189+
}
1190+
}
1191+
1192+
/**
1193+
* compare_host_and_config_dir_version compares the version of the config dir in the system.json file
1194+
* with the config dir version of the running host
1195+
* if compare result is 0 - undefined will be returned
1196+
* else - an appropriate error string will be returned
1197+
* @param {String} running_code_config_dir_version
1198+
* @param {String} system_config_dir_version
1199+
* @returns {String | Undefined}
1200+
*/
1201+
compare_host_and_config_dir_version(running_code_config_dir_version, system_config_dir_version) {
11851202
const ver_comparison = version_compare(running_code_config_dir_version, system_config_dir_version);
1203+
dbg.log0(`config_fs.compare_host_and_config_dir_version: ver_comparison ${ver_comparison} running_code_config_dir_version ${running_code_config_dir_version} system_config_dir_version ${system_config_dir_version}`);
11861204
if (ver_comparison > 0) {
1187-
throw new RpcError('CONFIG_DIR_VERSION_MISMATCH', `running code config_dir_version=${running_code_config_dir_version} is higher than the config dir version` +
1188-
`mentioned in system.json =${system_config_dir_version}, any updates to the config directory are blocked until the config dir upgrade`);
1205+
return `running code config_dir_version=${running_code_config_dir_version} is higher than the config dir version ` +
1206+
`mentioned in system.json=${system_config_dir_version}, any updates to the config directory are blocked until the config dir upgrade`;
11891207
}
11901208
if (ver_comparison < 0) {
1191-
throw new RpcError('CONFIG_DIR_VERSION_MISMATCH', `running code config_dir_version=${running_code_config_dir_version} is lower than the config dir version` +
1192-
`mentioned in system.json =${system_config_dir_version}, any updates to the config directory are blocked until the source code upgrade`);
1209+
return `running code config_dir_version=${running_code_config_dir_version} is lower than the config dir version ` +
1210+
`mentioned in system.json=${system_config_dir_version}, any updates to the config directory are blocked until the source code upgrade`;
11931211
}
1212+
return undefined;
11941213
}
11951214

11961215
/**
@@ -1201,6 +1220,7 @@ class ConfigFS {
12011220
return {
12021221
[os.hostname()]: {
12031222
current_version: pkg.version,
1223+
config_dir_version: this.config_dir_version,
12041224
upgrade_history: {
12051225
successful_upgrades: []
12061226
},
@@ -1226,6 +1246,15 @@ class ConfigFS {
12261246
}
12271247
};
12281248
}
1249+
1250+
/**
1251+
* get_hosts_data recieves system_data and returns only the hosts data
1252+
* @param {Object} system_data
1253+
* @returns {Object}
1254+
*/
1255+
get_hosts_data(system_data) {
1256+
return _.omit(system_data, 'config_directory');
1257+
}
12291258
}
12301259

12311260
// EXPORTS

src/test/unit_tests/jest_tests/test_config_fs.test.js

+42
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/* Copyright (C) 2024 NooBaa */
22
'use strict';
33

4+
const os = require('os');
45
const path = require('path');
56
const config = require('../../../../config');
7+
const pkg = require('../../../../package.json');
68
const { TMP_PATH } = require('../../system_tests/test_utils');
79
const { get_process_fs_context } = require('../../../util/native_fs_utils');
810
const { ConfigFS } = require('../../../sdk/config_fs');
@@ -29,3 +31,43 @@ describe('adjust_bucket_with_schema_updates', () => {
2931
expect(bucket).not.toHaveProperty('bucket_owner');
3032
});
3133
});
34+
35+
describe('_get_new_hostname_data', () => {
36+
it('_get_new_hostname_data - happy path', () => {
37+
const new_hostname_data = config_fs._get_new_hostname_data();
38+
expect(new_hostname_data).toStrictEqual({
39+
[os.hostname()]: {
40+
current_version: pkg.version,
41+
config_dir_version: config_fs.config_dir_version,
42+
upgrade_history: {
43+
successful_upgrades: []
44+
},
45+
}
46+
});
47+
});
48+
});
49+
50+
describe('compare_host_and_config_dir_version', () => {
51+
it('running code config_dir_version equals to system.json config_dir_version', () => {
52+
const running_code_config_dir_version = '0.0.0';
53+
const system_config_dir_version = '0.0.0';
54+
const ver_compare_err = config_fs.compare_host_and_config_dir_version(running_code_config_dir_version, system_config_dir_version);
55+
expect(ver_compare_err).toBeUndefined();
56+
});
57+
58+
it('running code config_dir_version higher than system.json config_dir_version', () => {
59+
const running_code_config_dir_version = '1.0.0';
60+
const system_config_dir_version = '0.0.0';
61+
const ver_compare_err = config_fs.compare_host_and_config_dir_version(running_code_config_dir_version, system_config_dir_version);
62+
expect(ver_compare_err).toBe(`running code config_dir_version=${running_code_config_dir_version} is higher than the config dir version ` +
63+
`mentioned in system.json=${system_config_dir_version}, any updates to the config directory are blocked until the config dir upgrade`);
64+
});
65+
66+
it('running code config_dir_version lower than system.json config_dir_version', () => {
67+
const running_code_config_dir_version = '0.0.0';
68+
const system_config_dir_version = '1.0.0';
69+
const ver_compare_err = config_fs.compare_host_and_config_dir_version(running_code_config_dir_version, system_config_dir_version);
70+
expect(ver_compare_err).toBe(`running code config_dir_version=${running_code_config_dir_version} is lower than the config dir version ` +
71+
`mentioned in system.json=${system_config_dir_version}, any updates to the config directory are blocked until the source code upgrade`);
72+
});
73+
});

src/test/unit_tests/jest_tests/test_nc_upgrade_manager.test.js

+39-33
Original file line numberDiff line numberDiff line change
@@ -59,60 +59,61 @@ module.exports = {
5959
`;
6060
const old_expected_system_json = {
6161
[hostname]: {
62-
'current_version': '5.17.0',
63-
'upgrade_history': {
64-
'successful_upgrades': [{
65-
'timestamp': 1724687496424,
66-
'from_version': '5.16.0',
67-
'to_version': '5.17.0'
62+
current_version: '5.17.0',
63+
upgrade_history: {
64+
successful_upgrades: [{
65+
timestamp: 1724687496424,
66+
from_version: '5.16.0',
67+
to_version: '5.17.0'
6868
}]
6969
},
7070
}
7171
};
7272

7373
const old_expected_system_json_has_config_directory = {
7474
[hostname]: {
75-
'current_version': '5.18.1',
76-
'upgrade_history': {
77-
'successful_upgrades': [{
78-
'timestamp': 1724687496424,
79-
'from_version': '5.18.0',
80-
'to_version': '5.18.1'
75+
current_version: '5.18.1',
76+
upgrade_history: {
77+
successful_upgrades: [{
78+
timestamp: 1724687496424,
79+
from_version: '5.18.0',
80+
to_version: '5.18.1'
8181
}]
8282
},
8383
},
8484
config_directory: {
85-
'config_dir_version': '1.0.0',
86-
'upgrade_package_version': '5.18.0',
87-
'phase': CONFIG_DIR_PHASES.CONFIG_DIR_UNLOCKED,
88-
'upgrade_history': {
89-
'successful_upgrades': [{
90-
'timestamp': 1724687496424,
91-
'completed_scripts': [],
92-
'package_from_version': '5.17.0',
93-
'package_to_version': '5.18.0'
85+
config_dir_version: '1.0.0',
86+
upgrade_package_version: '5.18.0',
87+
phase: CONFIG_DIR_PHASES.CONFIG_DIR_UNLOCKED,
88+
upgrade_history: {
89+
successful_upgrades: [{
90+
timestamp: 1724687496424,
91+
completed_scripts: [],
92+
package_from_version: '5.17.0',
93+
package_to_version: '5.18.0'
9494
}]
9595
}
9696
}
9797
};
9898

9999
const old_expected_system_json_no_successful_upgrades = {
100100
[hostname]: {
101-
'current_version': '5.17.0',
102-
'upgrade_history': {
103-
'successful_upgrades': []
101+
current_version: '5.17.0',
102+
upgrade_history: {
103+
successful_upgrades: []
104104
},
105105
}
106106
};
107107

108108
const current_expected_system_json = {
109109
[hostname]: {
110-
'current_version': pkg.version,
111-
'upgrade_history': {
112-
'successful_upgrades': [{
113-
'timestamp': 1724687496424,
114-
'from_version': '5.17.0',
115-
'to_version': pkg.version
110+
current_version: pkg.version,
111+
config_dir_version: config_fs.config_dir_version,
112+
upgrade_history: {
113+
successful_upgrades: [{
114+
timestamp: 1724687496424,
115+
from_version: '5.17.0',
116+
to_version: pkg.version
116117
}]
117118
},
118119
}
@@ -121,9 +122,10 @@ const current_expected_system_json = {
121122

122123
const current_expected_system_json_no_successful_upgrades = {
123124
[hostname]: {
124-
'current_version': pkg.version,
125-
'upgrade_history': {
126-
'successful_upgrades': []
125+
current_version: pkg.version,
126+
config_dir_version: config_fs.config_dir_version,
127+
upgrade_history: {
128+
successful_upgrades: []
127129
},
128130
}
129131
};
@@ -207,8 +209,10 @@ describe('nc upgrade manager - upgrade RPM', () => {
207209
await nc_upgrade_manager.update_rpm_upgrade(config_fs);
208210
const system_data_after_upgrade_run = await config_fs.get_system_config_file();
209211
const new_version = pkg.version;
212+
const new_config_dir_version = config_fs.config_dir_version;
210213
const host_data_after_upgrade = system_data_after_upgrade_run[hostname];
211214
expect(host_data_after_upgrade.current_version).toStrictEqual(new_version);
215+
expect(host_data_after_upgrade.config_dir_version).toStrictEqual(new_config_dir_version);
212216
expect(host_data_after_upgrade.upgrade_history.successful_upgrades[0].from_version).toStrictEqual(
213217
old_expected_system_json[hostname].current_version);
214218
expect(host_data_after_upgrade.upgrade_history.successful_upgrades[0].to_version).toStrictEqual(new_version);
@@ -219,8 +223,10 @@ describe('nc upgrade manager - upgrade RPM', () => {
219223
await nc_upgrade_manager.update_rpm_upgrade(config_fs);
220224
const system_data_after_upgrade_run = await config_fs.get_system_config_file();
221225
const new_version = pkg.version;
226+
const new_config_dir_version = config_fs.config_dir_version;
222227
const host_data_after_upgrade = system_data_after_upgrade_run[hostname];
223228
expect(host_data_after_upgrade.current_version).toStrictEqual(new_version);
229+
expect(host_data_after_upgrade.config_dir_version).toStrictEqual(new_config_dir_version);
224230
expect(host_data_after_upgrade.upgrade_history.successful_upgrades[0].from_version).toStrictEqual(
225231
old_expected_system_json_no_successful_upgrades[hostname].current_version);
226232
expect(host_data_after_upgrade.upgrade_history.successful_upgrades[0].to_version).toStrictEqual(new_version);

0 commit comments

Comments
 (0)