Skip to content

Commit 7015998

Browse files
authored
Merge pull request #8279 from romayalon/romy-config-dir-restructure-config-fs
NC | Config Dir Restructure
2 parents 46ccb82 + e2285af commit 7015998

31 files changed

+1537
-921
lines changed

src/cmd/manage_nsfs.js

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const minimist = require('minimist');
88
const config = require('../../config');
99
const P = require('../util/promise');
1010
const nb_native = require('../util/nb_native');
11-
const { ConfigFS, JSON_SUFFIX } = require('../sdk/config_fs');
11+
const { ConfigFS } = require('../sdk/config_fs');
1212
const cloud_utils = require('../util/cloud_utils');
1313
const native_fs_utils = require('../util/native_fs_utils');
1414
const mongo_utils = require('../util/mongo_utils');
@@ -387,8 +387,8 @@ async function add_account(data) {
387387
await manage_nsfs_validations.validate_account_args(config_fs, data, ACTIONS.ADD, undefined);
388388

389389
const access_key = has_access_keys(data.access_keys) ? data.access_keys[0].access_key : undefined;
390-
const name_exists = await config_fs.is_account_exists({ name: data.name });
391-
const access_key_exists = access_key && await config_fs.is_account_exists({ access_key });
390+
const name_exists = await config_fs.is_account_exists_by_name(data.name);
391+
const access_key_exists = access_key && await config_fs.is_account_exists_by_access_key(access_key);
392392

393393
const event_arg = data.name ? data.name : access_key;
394394
if (name_exists || access_key_exists) {
@@ -405,7 +405,7 @@ async function add_account(data) {
405405
// for validating against the schema we need an object, hence we parse it back to object
406406
const account = encrypted_data ? JSON.parse(encrypted_data) : data;
407407
nsfs_schema_utils.validate_account_schema(account);
408-
await config_fs.create_account_config_file(data.name, account, true);
408+
await config_fs.create_account_config_file(account);
409409
write_stdout_response(ManageCLIResponse.AccountCreated, data, { account: event_arg });
410410
}
411411

@@ -434,7 +434,7 @@ async function update_account(data, is_flag_iam_operate_on_root_account) {
434434
// for validating against the schema we need an object, hence we parse it back to object
435435
const account = encrypted_data ? JSON.parse(encrypted_data) : data;
436436
nsfs_schema_utils.validate_account_schema(account);
437-
await config_fs.update_account_config_file(data.name, account, undefined, undefined);
437+
await config_fs.update_account_config_file(account);
438438
write_stdout_response(ManageCLIResponse.AccountUpdated, data);
439439
return;
440440
}
@@ -446,9 +446,9 @@ async function update_account(data, is_flag_iam_operate_on_root_account) {
446446
secret_key: data.access_keys[0].secret_key,
447447
};
448448

449-
const name_exists = update_name && await config_fs.is_account_exists({ name: data.name });
449+
const name_exists = update_name && await config_fs.is_account_exists_by_name(data.name, undefined);
450450
const access_key_exists = update_access_key &&
451-
await config_fs.is_account_exists({ access_key: data.access_keys[0].access_key.unwrap() });
451+
await config_fs.is_account_exists_by_access_key(data.access_keys[0].access_key.unwrap());
452452

453453
if (name_exists || access_key_exists) {
454454
const err_code = name_exists ? ManageCLIError.AccountNameAlreadyExists : ManageCLIError.AccountAccessKeyAlreadyExists;
@@ -465,18 +465,17 @@ async function update_account(data, is_flag_iam_operate_on_root_account) {
465465
// for validating against the schema we need an object, hence we parse it back to object
466466
const parsed_data = JSON.parse(encrypted_data);
467467
nsfs_schema_utils.validate_account_schema(parsed_data);
468-
if (update_name) {
469-
await config_fs.create_account_config_file(new_name, parsed_data, true, [cur_access_key]);
470-
await config_fs.delete_account_config_file(cur_name, data.access_keys);
471-
} else if (update_access_key) {
472-
await config_fs.update_account_config_file(cur_name, parsed_data, parsed_data.access_keys, [cur_access_key]);
473-
}
468+
await config_fs.update_account_config_file(parsed_data, {
469+
old_name: update_name && cur_name,
470+
new_access_keys_to_link: update_access_key && parsed_data.access_keys,
471+
access_keys_to_delete: update_access_key && [{ access_key: cur_access_key }]
472+
});
474473
write_stdout_response(ManageCLIResponse.AccountUpdated, data);
475474
}
476475

477476
async function delete_account(data) {
478477
await manage_nsfs_validations.validate_account_args(config_fs, data, ACTIONS.DELETE, undefined);
479-
await config_fs.delete_account_config_file(data.name, data.access_keys);
478+
await config_fs.delete_account_config_file(data);
480479
write_stdout_response(ManageCLIResponse.AccountDeleted, '', { account: data.name });
481480
}
482481

@@ -578,19 +577,10 @@ function filter_bucket(bucket, filters) {
578577
* @param {object} [filters]
579578
*/
580579
async function list_config_files(type, wide, show_secrets, filters = {}) {
581-
let entries;
582-
// in case we have a filter by name, we don't need to read all the entries and iterate them
583-
// instead we "mock" the entries array to have one entry and it is the name by the filter (we add it for performance)
580+
let entries = [];
581+
const should_filter = Object.keys(filters).length > 0;
584582
const is_filter_by_name = filters.name !== undefined;
585-
if (is_filter_by_name) {
586-
entries = [{'name': filters.name + JSON_SUFFIX}];
587-
} else {
588-
entries = type === TYPES.ACCOUNT ?
589-
await config_fs.list_root_accounts() :
590-
await config_fs.list_buckets();
591-
}
592583

593-
const should_filter = Object.keys(filters).length > 0;
594584
// decryption causing mkm initalization
595585
// decrypt only if data has access_keys and show_secrets = true (no need to decrypt if show_secrets = false but should_filter = true)
596586
const options = {
@@ -599,19 +589,27 @@ async function list_config_files(type, wide, show_secrets, filters = {}) {
599589
silent_if_missing: true
600590
};
601591

592+
// in case we have a filter by name, we don't need to read all the entries and iterate them
593+
// instead we "mock" the entries array to have one entry and it is the name by the filter (we add it for performance)
594+
if (is_filter_by_name) {
595+
entries = [filters.name];
596+
} else if (type === TYPES.ACCOUNT) {
597+
entries = await config_fs.list_accounts();
598+
} else if (type === TYPES.BUCKET) {
599+
entries = await config_fs.list_buckets();
600+
}
601+
602602
let config_files_list = await P.map_with_concurrency(10, entries, async entry => {
603-
if (entry.name.endsWith(JSON_SUFFIX)) {
604-
if (wide || should_filter) {
605-
const data = type === TYPES.ACCOUNT ?
606-
await config_fs.get_account_by_name(entry.name, options) :
607-
await config_fs.get_bucket_by_name(entry.name, options);
608-
if (!data) return undefined;
609-
if (should_filter && !filter_list_item(type, data, filters)) return undefined;
610-
// remove secrets on !show_secrets && should filter
611-
return wide ? _.omit(data, show_secrets ? [] : ['access_keys']) : { name: entry.name.slice(0, entry.name.indexOf(JSON_SUFFIX)) };
612-
} else {
613-
return { name: entry.name.slice(0, entry.name.indexOf(JSON_SUFFIX)) };
614-
}
603+
if (wide || should_filter) {
604+
const data = type === TYPES.ACCOUNT ?
605+
await config_fs.get_account_by_name(entry, options) :
606+
await config_fs.get_bucket_by_name(entry, options);
607+
if (!data) return undefined;
608+
if (should_filter && !filter_list_item(type, data, filters)) return undefined;
609+
// remove secrets on !show_secrets && should filter
610+
return wide ? _.omit(data, show_secrets ? [] : ['access_keys']) : { name: entry };
611+
} else {
612+
return { name: entry };
615613
}
616614
});
617615
// it inserts undefined for the entry '.noobaa-config-nsfs' and we wish to remove it

src/deploy/NVA_build/standalone_deploy_nsfs.sh

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,8 @@ function execute() {
1010

1111
# Please note that the command we use here are without "sudo" because we are running from the container with Root permissions
1212
function main() {
13-
# Add accounts to run ceph tests
14-
execute "node src/cmd/manage_nsfs account add --name cephalt --new_buckets_path ${FS_ROOT_1} --uid 1000 --gid 1000" nsfs_cephalt.log
15-
execute "node src/cmd/manage_nsfs account add --name cephtenant --new_buckets_path ${FS_ROOT_2} --uid 2000 --gid 2000" nsfs_cephtenant.log
16-
1713
# Start noobaa service
1814
execute "node src/cmd/nsfs" nsfs.log
19-
2015
# Wait for sometime to process to start
2116
sleep 10
2217
}

src/manage_nsfs/health.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ const nb_native = require('../util/nb_native');
1010
const native_fs_utils = require('../util/native_fs_utils');
1111
const { read_stream_join } = require('../util/buffer_utils');
1212
const { make_https_request } = require('../util/http_utils');
13-
const { JSON_SUFFIX } = require('../sdk/config_fs');
1413
const { TYPES } = require('./manage_nsfs_constants');
1514
const { get_boolean_or_string_value, throw_cli_error, write_stdout_response } = require('./manage_nsfs_cli_utils');
1615
const { ManageCLIResponse } = require('./manage_nsfs_cli_responses');
@@ -327,7 +326,7 @@ class NSFSHealth {
327326
config_root_type_exists = await this.config_fs.validate_config_dir_exists(config_dir_path);
328327
} else if (type === TYPES.ACCOUNT) {
329328
// TODO - handle iam accounts when directory structure changes - read_account_by_id
330-
config_dir_path = this.config_fs.accounts_dir_path;
329+
config_dir_path = this.config_fs.accounts_by_name_dir_path;
331330
config_root_type_exists = await this.config_fs.validate_config_dir_exists(config_dir_path);
332331
}
333332
// TODO - this is not a good handling for that - we need to take it to an upper level
@@ -339,15 +338,16 @@ class NSFSHealth {
339338
};
340339
}
341340

342-
const entries = type === TYPES.BUCKET ?
343-
await this.config_fs.list_buckets() :
344-
await this.config_fs.list_root_accounts();
345-
346-
const config_files = entries.filter(entree => !native_fs_utils.isDirectory(entree) && entree.name.endsWith(JSON_SUFFIX));
341+
let config_files;
342+
if (type === TYPES.BUCKET) {
343+
config_files = await this.config_fs.list_buckets();
344+
} else {
345+
config_files = await this.config_fs.list_accounts();
346+
}
347347
for (const config_file of config_files) {
348348
// config_file get data or push error
349349
const { config_data = undefined, err_obj = undefined } =
350-
await this.get_config_file_data_or_error_object(type, config_file.name);
350+
await this.get_config_file_data_or_error_object(type, config_file);
351351
if (!config_data && err_obj) {
352352
invalid_storages.push(err_obj.invalid_storage);
353353
continue;
@@ -395,9 +395,9 @@ class NSFSHealth {
395395
} catch (err) {
396396
let err_code;
397397
const config_file_path = type === TYPES.BUCKET ?
398-
await this.config_fs.get_bucket_path_by_name(config_file_name) :
398+
this.config_fs.get_bucket_path_by_name(config_file_name) :
399399
// TODO - should be changed to id when moving to new structure for supporting iam accounts
400-
await this.config_fs.get_account_path_by_name(config_file_name);
400+
this.config_fs.get_account_path_by_name(config_file_name);
401401

402402
if (err.code === 'ENOENT') {
403403
dbg.log1(`Error: Config file path should be a valid path`, config_file_path, err);

src/manage_nsfs/manage_nsfs_validations.js

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@
33

44
const config = require('../../config');
55
const dbg = require('../util/debug_module')(__filename);
6-
const path = require('path');
76
const net = require('net');
87
const P = require('../util/promise');
9-
const nb_native = require('../util/nb_native');
108
const string_utils = require('../util/string_utils');
11-
const { JSON_SUFFIX } = require('../sdk/config_fs');
129
const native_fs_utils = require('../util/native_fs_utils');
1310
const ManageCLIError = require('../manage_nsfs/manage_nsfs_cli_errors').ManageCLIError;
1411
const bucket_policy_utils = require('../endpoint/s3/s3_bucket_policy_utils');
@@ -354,7 +351,7 @@ async function validate_bucket_args(config_fs, data, action) {
354351
if (data.s3_policy) {
355352
try {
356353
await bucket_policy_utils.validate_s3_policy(data.s3_policy, data.name,
357-
async principal => config_fs.is_account_exists({ name: principal })
354+
async principal => config_fs.is_account_exists_by_name(principal, account.owner)
358355
);
359356
} catch (err) {
360357
dbg.error('validate_bucket_args invalid bucket policy err:', err);
@@ -482,16 +479,14 @@ function _validate_access_keys(access_key, secret_key) {
482479
* @param {string} account_name
483480
*/
484481
async function validate_account_not_owns_buckets(config_fs, account_name) {
485-
const entries = await config_fs.list_buckets();
486-
await P.map_with_concurrency(10, entries, async entry => {
487-
if (entry.name.endsWith(JSON_SUFFIX)) {
488-
const data = await config_fs.get_bucket_by_name(entry.name, { silent_if_missing: true });
489-
if (data && data.bucket_owner === account_name) {
490-
const detail_msg = `Account ${account_name} has bucket ${data.name}`;
491-
throw_cli_error(ManageCLIError.AccountDeleteForbiddenHasBuckets, detail_msg);
492-
}
493-
return data;
482+
const bucket_names = await config_fs.list_buckets();
483+
await P.map_with_concurrency(10, bucket_names, async bucket_name => {
484+
const data = await config_fs.get_bucket_by_name(bucket_name, { silent_if_missing: true });
485+
if (data && data.bucket_owner === account_name) {
486+
const detail_msg = `Account ${account_name} has bucket ${data.name}`;
487+
throw_cli_error(ManageCLIError.AccountDeleteForbiddenHasBuckets, detail_msg);
494488
}
489+
return data;
495490
});
496491
}
497492

@@ -503,24 +498,20 @@ async function validate_account_not_owns_buckets(config_fs, account_name) {
503498
* @param {string} action
504499
*/
505500
async function check_if_root_account_does_not_have_IAM_users(config_fs, account_to_check, action) {
506-
const fs_context = config_fs.fs_context;
507-
const entries = await nb_native().fs.readdir(fs_context, config_fs.accounts_dir_path);
508-
await P.map_with_concurrency(10, entries, async entry => {
509-
if (entry.name.endsWith(JSON_SUFFIX)) {
510-
const full_path = path.join(config_fs.accounts_dir_path, entry.name);
511-
const account_data = await config_fs.get_config_data(full_path);
512-
if (entry.name.includes(config.NSFS_TEMP_CONF_DIR_NAME)) return undefined;
513-
const is_root_account_owns_user = check_root_account_owns_user(account_to_check, account_data);
514-
if (is_root_account_owns_user) {
515-
const detail_msg = `Account ${account_to_check.name} has IAM account ${account_data.name}`;
516-
if (action === ACTIONS.DELETE) {
517-
throw_cli_error(ManageCLIError.AccountDeleteForbiddenHasIAMAccounts, detail_msg);
518-
}
519-
// else it is called with action ACTIONS.UPDATE
520-
throw_cli_error(ManageCLIError.AccountCannotBeRootAccountsManager, detail_msg);
501+
// TODO - For supporting IAM, we need to check if {config_dir}/identities/{account_id}/users/ has anything inside
502+
const account_names = await config_fs.list_accounts();
503+
await P.map_with_concurrency(10, account_names, async account_name => {
504+
const account_data = await config_fs.get_account_by_name(account_name);
505+
const is_root_account_owns_user = check_root_account_owns_user(account_to_check, account_data);
506+
if (is_root_account_owns_user) {
507+
const detail_msg = `Account ${account_to_check.name} has IAM account ${account_data.name}`;
508+
if (action === ACTIONS.DELETE) {
509+
throw_cli_error(ManageCLIError.AccountDeleteForbiddenHasIAMAccounts, detail_msg);
521510
}
522-
return account_data;
511+
// else it is called with action ACTIONS.UPDATE
512+
throw_cli_error(ManageCLIError.AccountCannotBeRootAccountsManager, detail_msg);
523513
}
514+
return account_data;
524515
});
525516
}
526517

0 commit comments

Comments
 (0)