Skip to content

Commit 937075f

Browse files
authored
Merge pull request #8774 from romayalon/romy-cli-fix-unset-issue
NC | CLI | Fix for unsettable flags issues
2 parents a3bc7dd + 9f981fa commit 937075f

File tree

12 files changed

+87
-38
lines changed

12 files changed

+87
-38
lines changed

docs/NooBaaNonContainerized/CI&Tests.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Run `NC mocha tests` with root permissions -
8787

8888
#### NC mocha tests
8989
The following is a list of `NC mocha test` files -
90-
1. `test_nc_nsfs_cli.js` - Tests NooBaa CLI.
90+
1. `test_nc_cli.js` - Tests NooBaa CLI.
9191
2. `test_nc_health` - Tests NooBaa Health CLI.
9292
3. `test_nsfs_glacier_backend.js` - Tests NooBaa Glacier Backend.
9393
4. `test_nc_with_a_couple_of_forks.js` - Tests the `bucket_namespace_cache` when running with a couple of forks. Please notice that it uses `nc_coretest` with setup that includes a couple of forks.
@@ -99,7 +99,7 @@ The following is a list of `NC jest tests` files -
9999
2. `test_nc_master_keys.test.js` - Tests NC master key manager (store type = file).
100100
3. `test_nc_master_keys_exec.test.js` - Tests NC master key manager (store type = executable).
101101
4. `test_nc_nsfs_bucket_cli.test.js` - Tests NooBaa CLI bucket commands.
102-
5. `test_nc_nsfs_account_cli.test.js` - Tests NooBaa CLI account commands.
102+
5. `test_nc_account_cli.test.js` - Tests NooBaa CLI account commands.
103103
6. `test_nc_nsfs_anonymous_cli.test.js` - Tests NooBaa CLI anonymous account commands.
104104
7. `test_nc_nsfs_config_schema_validation.test.js` - Tests NC config.json schema validation.
105105
8. `test_nc_nsfs_bucket_schema_validation.test.js` - Tests NC bucket schema validation.

docs/NooBaaNonContainerized/NooBaaCLI.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,11 @@ noobaa-cli account update --name <account_name> [--new_name][--uid][--gid][--use
168168

169169
- `supplemental_groups`
170170
- Type: String
171-
- Description: Specifies additional FS groups (GID) a user can be a part of. Allows access to directories/files having one or more of the provided groups. A String of GIDs separated by commas. unset with ''
171+
- Description: Specifies additional FS groups (GID) a user can be a part of. Allows access to directories/files having one or more of the provided groups. A String of GIDs separated by commas. Unset with ''.
172172

173173
- `new_buckets_path`
174174
- Type: String
175-
- Description: Specifies a file system directory to be used for creating underlying directories that represent buckets created by an account using the S3 API.
175+
- Description: Specifies a file system directory to be used for creating underlying directories that represent buckets created by an account using the S3 API. Unset with ''.
176176

177177
- `regenerate`
178178
- Type: Boolean
@@ -189,15 +189,15 @@ noobaa-cli account update --name <account_name> [--new_name][--uid][--gid][--use
189189
- `fs_backend`
190190
- Type: String
191191
- Enum: none | GPFS | CEPH_FS | NFSv4
192-
- Description: Specifies the file system of new_buckets_path (default config.NSFS_NC_STORAGE_BACKEND).
192+
- Description: Specifies the file system of new_buckets_path (default config.NSFS_NC_STORAGE_BACKEND). Unset with ''.
193193

194194
- `allow_bucket_creation`
195195
- Type: Boolean
196196
- Description: Specifies if the account to explicitly allow or block bucket creation.
197197

198198
- `force_md5_etag`
199199
- Type: Boolean
200-
- Description: Set the account to force md5 ETag calculation.
200+
- Description: Set the account to force md5 ETag calculation. Unset with ''.
201201

202202
- `anonymous`
203203
- Type: Boolean
@@ -365,16 +365,16 @@ noobaa-cli bucket update --name <bucket_name> [--new_name] [--owner]
365365

366366
- `bucket_policy`
367367
- Type: String
368-
- Description: Set the bucket policy, type is a string of valid JSON policy.
368+
- Description: Set the bucket policy, type is a string of valid JSON policy. Unset with ''.
369369

370370
- `fs_backend`
371371
- Type: String
372372
- Enum: none | GPFS | CEPH_FS | NFSv4
373-
- Description: Specifies the file system of the bucket (default config.NSFS_NC_STORAGE_BACKEND), unset with ''.
373+
- Description: Specifies the file system of the bucket (default config.NSFS_NC_STORAGE_BACKEND), Unset with ''.
374374

375375
- `force_md5_etag`
376376
- Type: Boolean
377-
- Description: Set the bucket to force md5 ETag calculation.
377+
- Description: Set the bucket to force md5 ETag calculation. Unset with ''.
378378

379379

380380
### Bucket Status
@@ -441,7 +441,7 @@ noobaa-cli whitelist --ips <ips>
441441
#### Flags -
442442
- `ips` (Required)
443443
- Type: String
444-
- Description: Specifies the white list of server IPs for S3 access. Example - '["127.0.0.1", "192.0.10.0", "3002:0bd6:0000:0000:0000:ee00:0033:6778"]'
444+
- Description: Specifies the white list of server IPs for S3 access. Example - '["127.0.0.1", "192.0.10.0", "3002:0bd6:0000:0000:0000:ee00:0033:6778"]'. Unset with '[]'.
445445

446446

447447
## Managing Glacier

src/manage_nsfs/manage_nsfs_cli_errors.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ ManageCLIError.InvalidArgumentType = Object.freeze({
9292
http_code: 400,
9393
});
9494

95+
ManageCLIError.UnsetArgumentIsInvalid = Object.freeze({
96+
code: 'UnsetArgumentIsInvalid',
97+
message: 'Argument can not be unset or it was unset incorrectly, its value must be set or unset correctly or check there are no leading spaces',
98+
http_code: 400,
99+
});
100+
95101
ManageCLIError.InvalidType = Object.freeze({
96102
code: 'InvalidType',
97103
message: 'Invalid type, available types are account, bucket, logging, whitelist, upgrade, notification or connection.',

src/manage_nsfs/manage_nsfs_constants.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,21 @@ const BOOLEAN_STRING_VALUES = ['true', 'false'];
164164
const BOOLEAN_STRING_OPTIONS = new Set(['allow_bucket_creation', 'regenerate', 'wide', 'show_secrets', 'force',
165165
'force_md5_etag', 'iam_operate_on_root_account', 'all_account_details', 'all_bucket_details', 'anonymous']);
166166

167-
//options that can be unset using ''
168-
const LIST_UNSETABLE_OPTIONS = ['fs_backend', 's3_policy', 'force_md5_etag'];
167+
// CLI UNSET VALUES
168+
const CLI_EMPTY_STRING = '';
169+
const CLI_EMPTY_STRING_ARRAY = '[]';
170+
171+
const CLI_EMPTY_VALUES = new Set([CLI_EMPTY_STRING, CLI_EMPTY_STRING_ARRAY]);
172+
173+
// options that can be unset using '' / '[]'
174+
const UNSETTABLE_OPTIONS_OBJ = Object.freeze({
175+
'fs_backend': CLI_EMPTY_STRING,
176+
'bucket_policy': CLI_EMPTY_STRING,
177+
'force_md5_etag': CLI_EMPTY_STRING,
178+
'supplemental_groups': CLI_EMPTY_STRING,
179+
'new_buckets_path': CLI_EMPTY_STRING,
180+
'ips': CLI_EMPTY_STRING_ARRAY,
181+
});
169182

170183
const LIST_ACCOUNT_FILTERS = ['uid', 'gid', 'user', 'name', 'access_key'];
171184
const LIST_BUCKET_FILTERS = ['name'];
@@ -181,7 +194,10 @@ exports.OPTION_TYPE = OPTION_TYPE;
181194
exports.FROM_FILE = FROM_FILE;
182195
exports.BOOLEAN_STRING_VALUES = BOOLEAN_STRING_VALUES;
183196
exports.BOOLEAN_STRING_OPTIONS = BOOLEAN_STRING_OPTIONS;
184-
exports.LIST_UNSETABLE_OPTIONS = LIST_UNSETABLE_OPTIONS;
197+
exports.UNSETTABLE_OPTIONS_OBJ = UNSETTABLE_OPTIONS_OBJ;
198+
exports.CLI_EMPTY_VALUES = CLI_EMPTY_VALUES;
199+
exports.CLI_EMPTY_STRING = CLI_EMPTY_STRING;
200+
exports.CLI_EMPTY_STRING_ARRAY = CLI_EMPTY_STRING_ARRAY;
185201

186202
exports.LIST_ACCOUNT_FILTERS = LIST_ACCOUNT_FILTERS;
187203
exports.LIST_BUCKET_FILTERS = LIST_BUCKET_FILTERS;

src/manage_nsfs/manage_nsfs_help_utils.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ Usage:
9898
9999
Flags:
100100
101-
--ips <string> Set configuring for allowed IP addresses; format: '["127.0.0.1", "192.0.10.0", "3002:0bd6:0000:0000:0000:ee00:0033:6778"]'
101+
--ips <string> Set configuring for allowed IP addresses; format: '["127.0.0.1", "192.0.10.0", "3002:0bd6:0000:0000:0000:ee00:0033:6778"]', unset using '[]'
102102
103103
`;
104104

@@ -161,12 +161,12 @@ Flags:
161161
--uid <number> (optional) Update the User Identifier (UID)
162162
--gid <number> (optional) Update the Group Identifier (GID)
163163
--supplemental_groups <string> (optional) Update the list of supplemental groups (List of GID) seperated by comma(,) example: 211,202,23 - it will override existing list (unset with '')
164-
--new_buckets_path <string> (optional) Update the filesystem's root path where each subdirectory is a bucket
164+
--new_buckets_path <string> (optional) Update the filesystem's root path where each subdirectory is a bucket (unset with '')
165165
--user <string> (optional) Update the OS user name (instead of uid and gid)
166166
--regenerate (optional) Update automatically generated access key and secret key
167167
--access_key <string> (optional) Update the access key
168168
--secret_key <string> (optional) Update the secret key
169-
--fs_backend <none | GPFS | CEPH_FS | NFSv4> (optional) Update the filesystem type of new_buckets_path (default config.NSFS_NC_STORAGE_BACKEND)
169+
--fs_backend <none | GPFS | CEPH_FS | NFSv4> (optional) Update the filesystem type of new_buckets_path (default config.NSFS_NC_STORAGE_BACKEND), (unset with '')
170170
--allow_bucket_creation <true | false> (optional) Update the account to explicitly allow or block bucket creation
171171
--force_md5_etag <true | false> (optional) Update the account to force md5 etag calculation (unset with '') (will override default config.NSFS_NC_STORAGE_BACKEND)
172172
--iam_operate_on_root_account <true | false> (optional) Update the account to create root accounts instead of IAM users in IAM API requests.

src/manage_nsfs/manage_nsfs_validations.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const bucket_policy_utils = require('../endpoint/s3/s3_bucket_policy_utils');
1212
const { throw_cli_error, get_options_from_file, get_boolean_or_string_value, get_bucket_owner_account_by_id,
1313
is_name_update, is_access_key_update } = require('../manage_nsfs/manage_nsfs_cli_utils');
1414
const { TYPES, ACTIONS, VALID_OPTIONS, OPTION_TYPE, FROM_FILE, BOOLEAN_STRING_VALUES, BOOLEAN_STRING_OPTIONS,
15-
GLACIER_ACTIONS, LIST_UNSETABLE_OPTIONS, ANONYMOUS, DIAGNOSE_ACTIONS, UPGRADE_ACTIONS } = require('../manage_nsfs/manage_nsfs_constants');
15+
GLACIER_ACTIONS, UNSETTABLE_OPTIONS_OBJ, CLI_EMPTY_VALUES, ANONYMOUS, DIAGNOSE_ACTIONS, UPGRADE_ACTIONS } = require('../manage_nsfs/manage_nsfs_constants');
1616
const { check_root_account_owns_user } = require('../nc/nc_utils');
1717
const { validate_username } = require('../util/validation_utils');
1818
const notifications_util = require('../util/notifications_util');
@@ -158,16 +158,19 @@ function validate_no_extra_options(type, action, input_options, is_options_from_
158158
}
159159

160160
/**
161-
* validate_options_type_by_value check the type of the value that match what we expect.
161+
* validate_options_type_by_value checks the type of the value that match what we expect.
162+
* another check is for unset value (specified by ''/'[]') - it'll be allowed only for flags specified in UNSETTABLE_OPTIONS_OBJ
162163
* @param {object} input_options_with_data object with flag (key) and value
163164
*/
164165
function validate_options_type_by_value(input_options_with_data) {
165166
for (const [option, value] of Object.entries(input_options_with_data)) {
166167
const type_of_option = OPTION_TYPE[option];
167168
const type_of_value = typeof value;
169+
const is_empty_cli_value = CLI_EMPTY_VALUES.has(value);
170+
const is_unsettable_option_match_value = UNSETTABLE_OPTIONS_OBJ[option] === value;
168171
if (type_of_value !== type_of_option) {
169-
// special case for unset value (specified by '').
170-
if (LIST_UNSETABLE_OPTIONS.includes(option) && value === '') {
172+
// if unset is allowed but the type is not string, we allow it
173+
if (is_empty_cli_value && is_unsettable_option_match_value) {
171174
continue;
172175
}
173176
// special case for names, although the type is string we want to allow numbers as well
@@ -192,6 +195,12 @@ function validate_options_type_by_value(input_options_with_data) {
192195
const details = `type of flag ${option} should be ${type_of_option} (and the received value is ${value})`;
193196
throw_cli_error(ManageCLIError.InvalidArgumentType, details);
194197
}
198+
// special case for unset value (specified by '' or '[]').
199+
if (is_empty_cli_value && !is_unsettable_option_match_value) {
200+
let details = `flag value of ${option} is '${value}' but this option can't be unset via '${value}'.`;
201+
if (UNSETTABLE_OPTIONS_OBJ[option] !== undefined) details += ` Please use '${UNSETTABLE_OPTIONS_OBJ[option]}' instead.`;
202+
throw_cli_error(ManageCLIError.UnsetArgumentIsInvalid, details);
203+
}
195204
}
196205
}
197206

src/test/system_tests/test_utils.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ const IS_GPFS = !_.isUndefined(GPFS_ROOT_PATH);
2222
const TMP_PATH = get_tmp_path();
2323
const TEST_TIMEOUT = 60 * 1000;
2424

25+
// NC CLI Constants
26+
const CLI_UNSET_EMPTY_STRING = "''";
27+
2528
/**
2629
* TMP_PATH is a path to the tmp path based on the process platform
2730
* in contrast to linux, /tmp/ path on mac is a symlink to /private/tmp/
@@ -814,3 +817,4 @@ exports.update_system_json = update_system_json;
814817
exports.fail_test_if_default_config_dir_exists = fail_test_if_default_config_dir_exists;
815818
exports.create_config_dir = create_config_dir;
816819
exports.clean_config_dir = clean_config_dir;
820+
exports.CLI_UNSET_EMPTY_STRING = CLI_UNSET_EMPTY_STRING;

src/test/unit_tests/jest_tests/test_nc_nsfs_account_cli.test.js renamed to src/test/unit_tests/jest_tests/test_nc_account_cli.test.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const path = require('path');
1212
const os_util = require('../../../util/os_utils');
1313
const fs_utils = require('../../../util/fs_utils');
1414
const { ConfigFS } = require('../../../sdk/config_fs');
15-
const { set_path_permissions_and_owner, create_fs_user_by_platform,
15+
const { set_path_permissions_and_owner, create_fs_user_by_platform, CLI_UNSET_EMPTY_STRING,
1616
delete_fs_user_by_platform, TMP_PATH, set_nc_config_dir_in_config } = require('../../system_tests/test_utils');
1717
const { TYPES, ACTIONS, ANONYMOUS } = require('../../../manage_nsfs/manage_nsfs_constants');
1818
const ManageCLIError = require('../../../manage_nsfs/manage_nsfs_cli_errors').ManageCLIError;
@@ -801,8 +801,7 @@ describe('manage nsfs cli account flow', () => {
801801
it('cli update account unset new_buckets_path', async () => {
802802
const { name } = defaults;
803803
//in exec_manage_cli an empty string is passed as no input. so operation fails on invalid type. use the string '' instead
804-
const empty_string = '\'\'';
805-
const account_options = { config_root, name, new_buckets_path: empty_string};
804+
const account_options = { config_root, name, new_buckets_path: CLI_UNSET_EMPTY_STRING};
806805
const action = ACTIONS.UPDATE;
807806
await exec_manage_cli(type, action, account_options);
808807
let new_account_details = await config_fs.get_account_by_name(name, config_fs_account_options);
@@ -859,8 +858,7 @@ describe('manage nsfs cli account flow', () => {
859858
expect(new_account_details.force_md5_etag).toBe(true);
860859

861860
// unset force_md5_etag
862-
const empty_string = '\'\'';
863-
account_options.force_md5_etag = empty_string;
861+
account_options.force_md5_etag = CLI_UNSET_EMPTY_STRING;
864862
await exec_manage_cli(type, action, account_options);
865863
new_account_details = await config_fs.get_account_by_name(name, config_fs_account_options);
866864
expect(new_account_details.force_md5_etag).toBeUndefined();
@@ -890,13 +888,21 @@ describe('manage nsfs cli account flow', () => {
890888
expect(new_account_details.iam_operate_on_root_account).toBe(true);
891889

892890
// unset iam_operate_on_root_account (is not allowed)
893-
const empty_string = '\'\'';
894-
account_options.iam_operate_on_root_account = empty_string;
891+
account_options.iam_operate_on_root_account = CLI_UNSET_EMPTY_STRING;
895892
const res = await exec_manage_cli(type, action, account_options);
896893
expect(JSON.parse(res.stdout).error.code).toBe(
897894
ManageCLIError.InvalidArgumentType.code);
898895
});
899896

897+
it(`should fail - cli update account unset flag access_key with ''`, async function() {
898+
// unset access_key (is not allowed)
899+
const action = ACTIONS.UPDATE;
900+
const { name } = defaults;
901+
const account_options = { config_root, name, access_key: CLI_UNSET_EMPTY_STRING };
902+
const res = await exec_manage_cli(type, action, account_options);
903+
expect(JSON.parse(res.stdout).error.code).toBe(ManageCLIError.UnsetArgumentIsInvalid.code);
904+
});
905+
900906
it('cli update account iam_operate_on_root_account true when account owns a bucket', async function() {
901907
// cli create bucket
902908
const bucket_name = 'my-bucket';

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const path = require('path');
99
const os_util = require('../../../util/os_utils');
1010
const fs_utils = require('../../../util/fs_utils');
1111
const { ConfigFS } = require('../../../sdk/config_fs');
12-
const { set_path_permissions_and_owner, TMP_PATH, generate_s3_policy,
12+
const { set_path_permissions_and_owner, TMP_PATH, generate_s3_policy, CLI_UNSET_EMPTY_STRING,
1313
set_nc_config_dir_in_config } = require('../../system_tests/test_utils');
1414
const { ACTIONS, TYPES } = require('../../../manage_nsfs/manage_nsfs_constants');
1515
const { get_process_fs_context, is_path_exists, get_bucket_tmpdir_full_path } = require('../../../util/native_fs_utils');
@@ -505,8 +505,7 @@ describe('manage nsfs cli bucket flow', () => {
505505
expect(bucket_config.force_md5_etag).toBe(true);
506506

507507
// unset force_md5_etag
508-
const empty_string = '\'\'';
509-
bucket_options.force_md5_etag = empty_string;
508+
bucket_options.force_md5_etag = CLI_UNSET_EMPTY_STRING;
510509
await exec_manage_cli(TYPES.BUCKET, action, bucket_options);
511510
bucket_config = await config_fs.get_bucket_by_name(bucket_defaults.name);
512511
expect(bucket_config.force_md5_etag).toBeUndefined();

src/test/unit_tests/nc_index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require('./test_namespace_fs');
99
require('./test_ns_list_objects');
1010
require('./test_namespace_fs_mpu');
1111
require('./test_nb_native_fs');
12-
require('./test_nc_nsfs_cli');
12+
require('./test_nc_cli');
1313
require('./test_nc_health');
1414
require('./test_nsfs_access');
1515
require('./test_nsfs_integration');

0 commit comments

Comments
 (0)