Skip to content

Commit 36e84fd

Browse files
committed
NC | bucket owner removal
Signed-off-by: Romy <[email protected]>
1 parent 7015998 commit 36e84fd

16 files changed

+142
-130
lines changed

docs/NooBaaNonContainerized/GettingStarted.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ make_bucket: s3bucket
187187
#### 3. Check that the bucket configuration file was created successfully -
188188
```sh
189189
sudo cat /etc/noobaa.conf.d/buckets/s3bucket.json
190-
{"_id":"65cb1efcbec92b33220112d7","name":"s3bucket","owner_account":"65cb1e7c9e6ae40d499c0ae4","bucket_owner":"account1","versioning":"DISABLED","creation_date":"2023-09-26T05:56:16.252Z","path":"/tmp/fs1/s3bucket","should_create_underlying_storage":true}
190+
{"_id":"65cb1efcbec92b33220112d7","name":"s3bucket","owner_account":"65cb1e7c9e6ae40d499c0ae4","versioning":"DISABLED","creation_date":"2023-09-26T05:56:16.252Z","path":"/tmp/fs1/s3bucket","should_create_underlying_storage":true}
191191
```
192192
193193
#### 4. Check that the underlying file system bucket directory was created successfully -

src/cmd/manage_nsfs.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const noobaa_cli_diagnose = require('../manage_nsfs/diagnose');
2121
const nsfs_schema_utils = require('../manage_nsfs/nsfs_schema_utils');
2222
const { print_usage } = require('../manage_nsfs/manage_nsfs_help_utils');
2323
const { TYPES, ACTIONS, LIST_ACCOUNT_FILTERS, LIST_BUCKET_FILTERS, GLACIER_ACTIONS } = require('../manage_nsfs/manage_nsfs_constants');
24-
const { throw_cli_error, write_stdout_response, get_boolean_or_string_value, has_access_keys, set_debug_level } = require('../manage_nsfs/manage_nsfs_cli_utils');
24+
const { throw_cli_error, get_bucket_owner_account, write_stdout_response, get_boolean_or_string_value, has_access_keys, set_debug_level } = require('../manage_nsfs/manage_nsfs_cli_utils');
2525
const manage_nsfs_validations = require('../manage_nsfs/manage_nsfs_validations');
2626
const nc_mkm = require('../manage_nsfs/nc_master_key_manager').get_instance();
2727

@@ -96,8 +96,6 @@ async function fetch_bucket_data(action, user_input) {
9696
// added undefined values to keep the order the properties when printing the data object
9797
_id: undefined,
9898
name: user_input.name === undefined ? undefined : String(user_input.name),
99-
owner_account: undefined,
100-
bucket_owner: user_input.owner,
10199
tag: undefined, // if we would add the option to tag a bucket using CLI, this should be changed
102100
versioning: action === ACTIONS.ADD ? 'DISABLED' : undefined,
103101
creation_date: action === ACTIONS.ADD ? new Date().toISOString() : undefined,
@@ -126,6 +124,13 @@ async function fetch_bucket_data(action, user_input) {
126124
data = await fetch_existing_bucket_data(data);
127125
}
128126

127+
//if we're updating the owner, needs to override owner in file with the owner from user input.
128+
//if we're adding a bucket, need to set its owner id field
129+
if ((action === ACTIONS.UPDATE && user_input.owner) || (action === ACTIONS.ADD)) {
130+
const account = await get_bucket_owner_account(config_fs, user_input.owner);
131+
data.owner_account = account?._id;
132+
}
133+
129134
// override values
130135
// fs_backend deletion specified with empty string '' (but it is not part of the schema)
131136
data.fs_backend = data.fs_backend || undefined;
@@ -167,6 +172,8 @@ async function get_bucket_status(data) {
167172

168173
try {
169174
const config_data = await config_fs.get_bucket_by_name(data.name);
175+
const account_data = await config_fs.get_identity_by_id(config_data.owner_account);
176+
config_data.bucket_owner = account_data.name;
170177
write_stdout_response(ManageCLIResponse.BucketStatus, config_data);
171178
} catch (err) {
172179
const err_code = err.code === 'EACCES' ? ManageCLIError.AccessDenied : ManageCLIError.NoSuchBucket;

src/cmd/nsfs.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,6 @@ class NsfsObjectSDK extends ObjectSDK {
207207
Principal: [new SensitiveString('*')],
208208
}]
209209
},
210-
system_owner: new SensitiveString('nsfs'),
211-
bucket_owner: new SensitiveString('nsfs'),
212210
owner_account: new SensitiveString('nsfs-id'), // temp
213211
};
214212
}

src/manage_nsfs/manage_nsfs_cli_utils.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,17 @@ function write_stdout_response(response_code, detail, event_arg) {
3838
* otherwise it would throw an error
3939
* @param {import('../sdk/config_fs').ConfigFS} config_fs
4040
* @param {string} bucket_owner
41+
* @param {string} [owner_account_id]
4142
*/
42-
async function get_bucket_owner_account(config_fs, bucket_owner) {
43+
async function get_bucket_owner_account(config_fs, bucket_owner, owner_account_id) {
4344
try {
44-
const account = await config_fs.get_account_by_name(bucket_owner);
45+
const account = bucket_owner ?
46+
await config_fs.get_account_by_name(bucket_owner) :
47+
await config_fs.get_identity_by_id(owner_account_id);
4548
return account;
4649
} catch (err) {
4750
if (err.code === 'ENOENT') {
48-
const detail_msg = `bucket owner ${bucket_owner} does not exists`;
51+
const detail_msg = `bucket owner name = ${bucket_owner} id=${owner_account_id} does not exists`;
4952
throw_cli_error(ManageCLIError.BucketSetForbiddenBucketOwnerNotExists, detail_msg, {bucket_owner: bucket_owner});
5053
}
5154
throw err;

src/manage_nsfs/manage_nsfs_logging.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ async function export_bucket_logging(shared_config_fs) {
3939
*/
4040
async function get_bucket_owner_keys(log_bucket_name) {
4141
const log_bucket_config_data = await config_fs.get_bucket_by_name(log_bucket_name);
42-
const log_bucket_owner = log_bucket_config_data.bucket_owner;
43-
const owner_config_data = await config_fs.get_account_by_name(log_bucket_owner, { show_secrets: true, decrypt_secret_key: true });
42+
const log_bucket_owner = log_bucket_config_data.owner_account;
43+
const owner_config_data = await config_fs.get_identities_by_id(log_bucket_owner, { show_secrets: true, decrypt_secret_key: true });
4444
return owner_config_data.access_keys;
4545
}
4646

src/manage_nsfs/manage_nsfs_validations.js

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ async function validate_bucket_args(config_fs, data, action) {
316316
if (action === ACTIONS.ADD || action === ACTIONS.UPDATE) {
317317
if (action === ACTIONS.ADD) native_fs_utils.validate_bucket_creation({ name: data.name });
318318
if ((action === ACTIONS.UPDATE) && (data.new_name !== undefined)) native_fs_utils.validate_bucket_creation({ name: data.new_name });
319-
if ((action === ACTIONS.ADD) && (data.bucket_owner === undefined)) throw_cli_error(ManageCLIError.MissingBucketOwnerFlag);
319+
if ((action === ACTIONS.ADD) && (data.owner_account === undefined)) throw_cli_error(ManageCLIError.MissingBucketOwnerFlag);
320320
if (!data.path) throw_cli_error(ManageCLIError.MissingBucketPathFlag);
321321
// fs_backend='' used for deletion of the fs_backend property
322322
if (data.fs_backend !== undefined && !['GPFS', 'CEPH_FS', 'NFSv4'].includes(data.fs_backend)) {
@@ -328,30 +328,33 @@ async function validate_bucket_args(config_fs, data, action) {
328328
if (!exists) {
329329
throw_cli_error(ManageCLIError.InvalidStoragePath, data.path);
330330
}
331-
const account = await get_bucket_owner_account(config_fs, data.bucket_owner);
332-
const account_fs_context = await native_fs_utils.get_fs_context(account.nsfs_account_config, data.fs_backend);
331+
332+
// bucket owner validations
333+
const owner_account = await get_bucket_owner_account(config_fs, undefined, data.owner_account);
334+
const account_fs_context = await native_fs_utils.get_fs_context(owner_account.nsfs_account_config,
335+
owner_account.nsfs_account_config.fs_backend);
333336
if (!config.NC_DISABLE_ACCESS_CHECK) {
334337
const accessible = await native_fs_utils.is_dir_rw_accessible(account_fs_context, data.path);
335338
if (!accessible) {
336339
throw_cli_error(ManageCLIError.InaccessibleStoragePath, data.path);
337340
}
338341
}
339342
if (action === ACTIONS.ADD) {
340-
if (!account.allow_bucket_creation) {
341-
const detail_msg = `${data.bucket_owner} account not allowed to create new buckets. ` +
343+
if (!owner_account.allow_bucket_creation) {
344+
const detail_msg = `${owner_account.name} account not allowed to create new buckets. ` +
342345
`Please make sure to have a valid new_buckets_path and enable the flag allow_bucket_creation`;
343346
throw_cli_error(ManageCLIError.BucketCreationNotAllowed, detail_msg);
347+
}
344348
}
345-
data.owner_account = account._id; // TODO move this assignment to better place
346-
}
347-
if (account.owner) {
348-
const detail_msg = `account ${data.bucket_owner} is IAM account`;
349-
throw_cli_error(ManageCLIError.BucketSetForbiddenBucketOwnerIsIAMAccount, detail_msg, {bucket_owner: data.bucket_owner});
349+
if (owner_account.owner) {
350+
const detail_msg = `account ${owner_account.name} is IAM account`;
351+
throw_cli_error(ManageCLIError.BucketSetForbiddenBucketOwnerIsIAMAccount, detail_msg,
352+
{ bucket_owner: owner_account.name });
350353
}
351354
if (data.s3_policy) {
352355
try {
353356
await bucket_policy_utils.validate_s3_policy(data.s3_policy, data.name,
354-
async principal => config_fs.is_account_exists_by_name(principal, account.owner)
357+
async principal => config_fs.is_account_exists_by_name(principal, owner_account.owner)
355358
);
356359
} catch (err) {
357360
dbg.error('validate_bucket_args invalid bucket policy err:', err);
@@ -440,7 +443,7 @@ async function validate_account_args(config_fs, data, action, is_flag_iam_operat
440443
* @param {object} data
441444
*/
442445
async function validate_account_resources_before_deletion(config_fs, data) {
443-
await validate_account_not_owns_buckets(config_fs, data.name);
446+
await validate_account_not_owns_buckets(config_fs, data);
444447
// If it is root account (not owned by other account) then we check that it doesn't owns IAM accounts
445448
if (data.owner === undefined) {
446449
await check_if_root_account_does_not_have_IAM_users(config_fs, data, ACTIONS.DELETE);
@@ -476,14 +479,14 @@ function _validate_access_keys(access_key, secret_key) {
476479
* validate_delete_account will check if the account has at least one bucket
477480
* in case it finds one, it would throw an error
478481
* @param {import('../sdk/config_fs').ConfigFS} config_fs
479-
* @param {string} account_name
482+
* @param {Object} account_data
480483
*/
481-
async function validate_account_not_owns_buckets(config_fs, account_name) {
484+
async function validate_account_not_owns_buckets(config_fs, account_data) {
482485
const bucket_names = await config_fs.list_buckets();
483486
await P.map_with_concurrency(10, bucket_names, async bucket_name => {
484487
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}`;
488+
if (data && data.owner_account === account_data._id) {
489+
const detail_msg = `Account ${account_data.name} has bucket ${data.name}`;
487490
throw_cli_error(ManageCLIError.AccountDeleteForbiddenHasBuckets, detail_msg);
488491
}
489492
return data;

src/sdk/accountspace_fs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ class AccountSpaceFS {
672672
const bucket_names = await this.config_fs.list_buckets();
673673
await P.map_with_concurrency(10, bucket_names, async bucket_name => {
674674
const bucket_data = await this.config_fs.get_bucket_by_name(bucket_name, { silent_if_missing: true});
675-
if (bucket_data && bucket_data.bucket_owner === account_to_delete.name) {
675+
if (bucket_data && bucket_data.owner_account === account_to_delete._id) {
676676
this._throw_error_delete_conflict(action, account_to_delete, resource_name);
677677
}
678678
return bucket_data;

src/sdk/bucketspace_fs.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const nsfs_schema_utils = require('../manage_nsfs/nsfs_schema_utils');
1717
const nc_mkm = require('../manage_nsfs/nc_master_key_manager').get_instance();
1818
const { ConfigFS, JSON_SUFFIX } = require('./config_fs');
1919
const mongo_utils = require('../util/mongo_utils');
20+
const { TYPES } = require('../manage_nsfs/manage_nsfs_constants');
2021

2122
const KeysSemaphore = require('../util/keys_semaphore');
2223
const { get_umasked_mode, validate_bucket_creation, get_bucket_tmpdir_full_path, folder_delete,
@@ -121,11 +122,22 @@ class BucketSpaceFS extends BucketSpaceSimpleFS {
121122
};
122123

123124
bucket.name = new SensitiveString(bucket.name);
124-
bucket.bucket_owner = new SensitiveString(bucket.bucket_owner);
125+
// Backward compatibility will take longer without bucket owner name
126+
const account_config = await this.config_fs.get_identity_by_id(
127+
bucket.owner_account,
128+
TYPES.ACCOUNT,
129+
{ silent_if_missing: true }
130+
);
131+
132+
if (!account_config) {
133+
dbg.warn(`Bucket Owner does not exist ${bucket.owner_account}`);
134+
}
135+
bucket.bucket_owner = new SensitiveString(account_config?.name);
125136
bucket.owner_account = {
126137
id: bucket.owner_account,
127138
email: bucket.bucket_owner
128139
};
140+
129141
if (bucket.s3_policy) {
130142
for (const [s_index, statement] of bucket.s3_policy.Statement.entries()) {
131143
const statement_principal = statement.Principal || statement.NotPrincipal;
@@ -286,7 +298,6 @@ class BucketSpaceFS extends BucketSpaceSimpleFS {
286298
tag: js_utils.default_value(tag, undefined),
287299
owner_account: account._id,
288300
creator: account._id,
289-
bucket_owner: new SensitiveString(account.name),
290301
versioning: config.NSFS_VERSIONING_ENABLED && lock_enabled ? 'ENABLED' : 'DISABLED',
291302
object_lock_configuration: config.WORM_ENABLED ? {
292303
object_lock_enabled: lock_enabled ? 'Enabled' : 'Disabled',
@@ -667,7 +678,7 @@ class BucketSpaceFS extends BucketSpaceSimpleFS {
667678
// so they can be re-used
668679
async has_bucket_action_permission(bucket, account, action, bucket_path = "") {
669680
const account_identifier = account.name.unwrap();
670-
dbg.log1('has_bucket_action_permission:', bucket.name.unwrap(), account_identifier, bucket.bucket_owner.unwrap());
681+
dbg.log1('has_bucket_action_permission:', bucket.name.unwrap(), account_identifier, bucket.owner_account);
671682

672683
const is_system_owner = Boolean(bucket.system_owner) && bucket.system_owner.unwrap() === account_identifier;
673684

src/sdk/config_fs.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,10 @@ class ConfigFS {
787787
if (bucket.system_owner !== undefined) {
788788
delete bucket.system_owner;
789789
}
790+
// bucket_owner is deprecated since version 5.18
791+
if (bucket.bucket_owner !== undefined) {
792+
delete bucket.bucket_owner;
793+
}
790794
}
791795

792796
/**

src/server/system_services/schemas/nsfs_bucket_schema.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ module.exports = {
77
required: [
88
'_id',
99
'name',
10-
'bucket_owner',
1110
'owner_account',
1211
'versioning',
1312
'path',
@@ -36,7 +35,10 @@ module.exports = {
3635
system_owner: {
3736
type: 'string',
3837
},
39-
// bucket_owner is the account name
38+
/**
39+
* @deprecated bucket_owner is kept for backward compatibility,
40+
* but will no longer be included in new / updated bucket json.
41+
*/
4042
bucket_owner: {
4143
type: 'string',
4244
},

src/test/unit_tests/jest_tests/test_accountspace_fs.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1861,7 +1861,6 @@ function _new_bucket_defaults(account, bucket_name, bucket_storage_path) {
18611861
_id: '65a8edc9bc5d5bbf9db71c75',
18621862
name: bucket_name,
18631863
owner_account: account._id,
1864-
bucket_owner: new SensitiveString(account.name),
18651864
creation_date: new Date().toISOString(),
18661865
path: bucket_storage_path,
18671866
should_create_underlying_storage: true,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ describe('adjust_bucket_with_schema_updates', () => {
2222
});
2323

2424
it('should return bucket without deprecated properties (system_owner)', () => {
25-
const bucket = {name: 'bucket1', system_owner: 'account1-system-owner'};
25+
const bucket = {name: 'bucket1', system_owner: 'account1-system-owner', bucket_owner: 'account1-bucket_owner'};
2626
config_fs.adjust_bucket_with_schema_updates(bucket);
2727
expect(bucket).toBeDefined();
2828
expect(bucket).not.toHaveProperty('system_owner');
29+
expect(bucket).not.toHaveProperty('bucket_owner');
2930
});
3031
});

src/test/unit_tests/jest_tests/test_nc_nsfs_bucket_cli.test.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ describe('manage nsfs cli bucket flow', () => {
129129
await set_path_permissions_and_owner(bucket_options.path, account_defaults, 0o700);
130130
await exec_manage_cli(TYPES.BUCKET, action, bucket_options);
131131
const bucket = await config_fs.get_bucket_by_name(bucket_defaults.name);
132-
assert_bucket(bucket, bucket_options);
132+
await assert_bucket(bucket, bucket_options, config_fs);
133133
});
134134

135135
it('cli create bucket - account can not access path NC_DISABLE_ACCESS_CHECK = true - should succeed', async () => {
@@ -256,7 +256,7 @@ describe('manage nsfs cli bucket flow', () => {
256256
await exec_manage_cli(type, action, command_flags);
257257
// compare the details
258258
const bucket = await config_fs.get_bucket_by_name(bucket_defaults.name);
259-
assert_bucket(bucket, bucket_options);
259+
await assert_bucket(bucket, bucket_options, config_fs);
260260
});
261261

262262
it('cli create bucket using from_file with optional options (fs_backend)', async () => {
@@ -271,7 +271,7 @@ describe('manage nsfs cli bucket flow', () => {
271271
await exec_manage_cli(type, action, command_flags);
272272
// compare the details
273273
const bucket = await config_fs.get_bucket_by_name(bucket_defaults.name);
274-
assert_bucket(bucket, bucket_options);
274+
await assert_bucket(bucket, bucket_options, config_fs);
275275
expect(bucket.fs_backend).toEqual(bucket_options.fs_backend);
276276
});
277277

@@ -287,7 +287,7 @@ describe('manage nsfs cli bucket flow', () => {
287287
await exec_manage_cli(type, action, command_flags);
288288
// compare the details
289289
const bucket = await config_fs.get_bucket_by_name(bucket_defaults.name);
290-
assert_bucket(bucket, bucket_options);
290+
await assert_bucket(bucket, bucket_options, config_fs);
291291
expect(bucket.bucket_policy).toEqual(bucket_options.s3_policy);
292292
});
293293

@@ -511,7 +511,8 @@ describe('manage nsfs cli bucket flow', () => {
511511
await set_path_permissions_and_owner(bucket_defaults.path, account_defaults2, 0o700);
512512
await exec_manage_cli(TYPES.BUCKET, action, bucket_options);
513513
const bucket = await config_fs.get_bucket_by_name(bucket_defaults.name);
514-
expect(bucket.bucket_owner).toBe(account_defaults2.name);
514+
const owner_data = await config_fs.get_identity_by_id(bucket.owner_account);
515+
expect(owner_data.name).toBe(account_defaults2.name);
515516
});
516517

517518
it('should fail - cli bucket update - without identifier', async () => {
@@ -878,9 +879,11 @@ async function create_json_file(path_to_dir, file_name, data) {
878879
* assert_bucket will verify the fields of the buckets (only required fields)
879880
* @param {object} bucket
880881
* @param {object} bucket_options
882+
* @param {import('../../../sdk/config_fs').ConfigFS} config_fs
881883
*/
882-
function assert_bucket(bucket, bucket_options) {
884+
async function assert_bucket(bucket, bucket_options, config_fs) {
883885
expect(bucket.name).toEqual(bucket_options.name);
884-
expect(bucket.bucket_owner).toEqual(bucket_options.owner);
886+
const owner_data = await config_fs.get_identity_by_id(bucket.owner_account);
887+
expect(owner_data.name).toBe(bucket_options.owner);
885888
expect(bucket.path).toEqual(bucket_options.path);
886889
}

0 commit comments

Comments
 (0)