Skip to content

Commit

Permalink
Merge pull request #8839 from romayalon/romy-lifecycle-cli
Browse files Browse the repository at this point in the history
NC | CLI | Lifecycle worker
  • Loading branch information
romayalon authored Mar 4, 2025
2 parents c62b217 + b418f8e commit 16133d6
Show file tree
Hide file tree
Showing 9 changed files with 386 additions and 113 deletions.
26 changes: 26 additions & 0 deletions src/cmd/manage_nsfs.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
/* Copyright (C) 2020 NooBaa */
'use strict';

// DO NOT PUT NEW REQUIREMENTS BEFORE SETTING process.env.NC_NSFS_NO_DB_ENV = 'true'
// NC nsfs deployments specifying process.env.LOCAL_MD_SERVER=true deployed together with a db
// when a system_store object is initialized VaccumAnalyzer is being called once a day.
// when NC nsfs deployed without db we would like to avoid running VaccumAnalyzer in any flow there is
// because running it will cause a panic.
if (process.env.LOCAL_MD_SERVER !== 'true') {
process.env.NC_NSFS_NO_DB_ENV = 'true';
}

const dbg = require('../util/debug_module')(__filename);
if (!dbg.get_process_name()) dbg.set_process_name('noobaa-cli');

const _ = require('lodash');
const minimist = require('minimist');
const config = require('../../config');
Expand All @@ -16,6 +27,7 @@ const { account_id_cache } = require('../sdk/accountspace_fs');
const ManageCLIError = require('../manage_nsfs/manage_nsfs_cli_errors').ManageCLIError;
const ManageCLIResponse = require('../manage_nsfs/manage_nsfs_cli_responses').ManageCLIResponse;
const manage_nsfs_glacier = require('../manage_nsfs/manage_nsfs_glacier');
const noobaa_cli_lifecycle = require('../manage_nsfs/nc_lifecycle');
const manage_nsfs_logging = require('../manage_nsfs/manage_nsfs_logging');
const noobaa_cli_diagnose = require('../manage_nsfs/diagnose');
const noobaa_cli_upgrade = require('../manage_nsfs/upgrade');
Expand Down Expand Up @@ -79,6 +91,8 @@ async function main(argv = minimist(process.argv.slice(2))) {
await notification_management();
} else if (type === TYPES.CONNECTION) {
await connection_management(action, user_input);
} else if (type === TYPES.LIFECYCLE) {
await lifecycle_management();
} else {
throw_cli_error(ManageCLIError.InvalidType);
}
Expand Down Expand Up @@ -858,5 +872,17 @@ async function list_connections() {
return conns;
}

////////////////////
///// LIFECYCLE ////
////////////////////

/**
* lifecycle_management runs the nc lifecycle management
* @returns {Promise<void>}
*/
async function lifecycle_management() {
await noobaa_cli_lifecycle.run_lifecycle(config_fs);
}

exports.main = main;
if (require.main === module) main();
96 changes: 1 addition & 95 deletions src/cmd/nsfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,14 @@ if (process.env.LOCAL_MD_SERVER === 'true') {
//const js_utils = require('../util/js_utils');
const nb_native = require('../util/nb_native');
//const schema_utils = require('../util/schema_utils');
const RpcError = require('../rpc/rpc_error');
const ObjectSDK = require('../sdk/object_sdk');
const { cluster } = require('../util/fork_utils');
const NamespaceFS = require('../sdk/namespace_fs');
const BucketSpaceSimpleFS = require('../sdk/bucketspace_simple_fs');
const BucketSpaceFS = require('../sdk/bucketspace_fs');
const SensitiveString = require('../util/sensitive_string');
const endpoint_stats_collector = require('../sdk/endpoint_stats_collector');
//const { RPC_BUFFERS } = require('../rpc');
const AccountSDK = require('../sdk/account_sdk');
const NsfsObjectSDK = require('../sdk/nsfs_object_sdk');
const AccountSpaceFS = require('../sdk/accountspace_fs');
const NoobaaEvent = require('../manage_nsfs/manage_nsfs_events_utils').NoobaaEvent;
const { set_debug_level } = require('../manage_nsfs/manage_nsfs_cli_utils');
Expand Down Expand Up @@ -121,98 +119,6 @@ function print_usage() {

let nsfs_config_root;

class NsfsObjectSDK extends ObjectSDK {
constructor(fs_root, fs_config, account, versioning, config_root, nsfs_system) {
// const rpc_client_hooks = new_rpc_client_hooks();
// rpc_client_hooks.account.read_account_by_access_key = async ({ access_key }) => {
// if (access_key) {
// return { access_key };
// }
// };
// rpc_client_hooks.bucket.read_bucket_sdk_info = async ({ name }) => {
// if (name) {
// return { name };
// }
// };
let bucketspace;
if (config_root) {
bucketspace = new BucketSpaceFS({ config_root }, endpoint_stats_collector.instance());
} else {
bucketspace = new BucketSpaceSimpleFS({ fs_root });
}
super({
rpc_client: null,
internal_rpc_client: null,
object_io: null,
bucketspace,
stats: endpoint_stats_collector.instance(),
});
this.nsfs_config_root = nsfs_config_root;
this.nsfs_fs_root = fs_root;
this.nsfs_fs_config = fs_config;
this.nsfs_account = account;
this.nsfs_versioning = versioning;
this.nsfs_namespaces = {};
this.nsfs_system = nsfs_system;
if (!config_root) {
this._get_bucket_namespace = bucket_name => this._simple_get_single_bucket_namespace(bucket_name);
this.load_requesting_account = auth_req => this._simple_load_requesting_account(auth_req);
this.read_bucket_sdk_policy_info = bucket_name => this._simple_read_bucket_sdk_policy_info(bucket_name);
this.read_bucket_sdk_config_info = () => undefined;
this.read_bucket_usage_info = () => undefined;
this.read_bucket_sdk_website_info = () => undefined;
this.read_bucket_sdk_namespace_info = () => undefined;
this.read_bucket_sdk_caching_info = () => undefined;
}
}

async _simple_get_single_bucket_namespace(bucket_name) {
const existing_ns = this.nsfs_namespaces[bucket_name];
if (existing_ns) return existing_ns;
const ns_fs = new NamespaceFS({
fs_backend: this.nsfs_fs_config.backend,
bucket_path: this.nsfs_fs_root + '/' + bucket_name,
bucket_id: 'nsfs',
namespace_resource_id: undefined,
access_mode: undefined,
versioning: this.nsfs_versioning,
stats: endpoint_stats_collector.instance(),
force_md5_etag: false,
});
this.nsfs_namespaces[bucket_name] = ns_fs;
return ns_fs;
}

async _simple_load_requesting_account(auth_req) {
const access_key = this.nsfs_account.access_keys?.[0]?.access_key;
if (access_key) {
const token = this.get_auth_token();
if (!token) {
throw new RpcError('UNAUTHORIZED', `Anonymous access to bucket not allowed`);
}
if (token.access_key !== access_key.unwrap()) {
throw new RpcError('INVALID_ACCESS_KEY_ID', `Account with access_key not found`);
}
}
this.requesting_account = this.nsfs_account;
}

async _simple_read_bucket_sdk_policy_info(bucket_name) {
return {
s3_policy: {
Version: '2012-10-17',
Statement: [{
Effect: 'Allow',
Action: ['*'],
Resource: ['*'],
Principal: [new SensitiveString('*')],
}]
},
bucket_owner: new SensitiveString('nsfs'),
owner_account: new SensitiveString('nsfs-id'), // temp
};
}
}

// NsfsAccountSDK was based on NsfsObjectSDK
// simple flow was not implemented
Expand Down
24 changes: 7 additions & 17 deletions src/manage_nsfs/health.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ const native_fs_utils = require('../util/native_fs_utils');
const { read_stream_join } = require('../util/buffer_utils');
const { make_https_request } = require('../util/http_utils');
const { TYPES } = require('./manage_nsfs_constants');
const { get_boolean_or_string_value, throw_cli_error, write_stdout_response, get_bucket_owner_account_by_id } = require('./manage_nsfs_cli_utils');
const { get_boolean_or_string_value, throw_cli_error, write_stdout_response,
get_bucket_owner_account_by_id, get_service_status, NOOBAA_SERVICE_NAME } = require('./manage_nsfs_cli_utils');
const { ManageCLIResponse } = require('./manage_nsfs_cli_responses');
const ManageCLIError = require('./manage_nsfs_cli_errors').ManageCLIError;
const notifications_util = require('../util/notifications_util');


const HOSTNAME = 'localhost';
const NOOBAA_SERVICE = 'noobaa';

const health_errors = {
NOOBAA_SERVICE_FAILED: {
Expand Down Expand Up @@ -118,7 +118,7 @@ class NSFSHealth {
async nc_nsfs_health() {
let endpoint_state;
let memory;
const noobaa_service_state = await this.get_service_state(NOOBAA_SERVICE);
const noobaa_service_state = await this.get_service_state(NOOBAA_SERVICE_NAME);
const { service_status, pid } = noobaa_service_state;
if (pid !== '0') {
endpoint_state = await this.get_endpoint_response();
Expand All @@ -139,7 +139,7 @@ class NSFSHealth {
if (this.all_account_details) account_details = await this.get_account_status();
if (this.all_connection_details) connection_details = await this.get_connection_status();
const health = {
service_name: NOOBAA_SERVICE,
service_name: NOOBAA_SERVICE_NAME,
status: service_health,
memory: memory,
error: error_code,
Expand Down Expand Up @@ -210,18 +210,8 @@ class NSFSHealth {
}

async get_service_state(service_name) {
let service_status;
let pid;
try {
service_status = await os_util.exec('systemctl show -p ActiveState --value ' + service_name, {
ignore_rc: false,
return_stdout: true,
trim_stdout: true,
});
} catch (err) {
dbg.warn('could not receive service active state', service_name, err);
service_status = 'missing service status info';
}
const service_status = await get_service_status(service_name);
try {
pid = await os_util.exec('systemctl show --property MainPID --value ' + service_name, {
ignore_rc: false,
Expand Down Expand Up @@ -308,13 +298,13 @@ class NSFSHealth {
async get_service_memory_usage() {
let memory_status;
try {
memory_status = await os_util.exec('systemctl status ' + NOOBAA_SERVICE + ' | grep Memory ', {
memory_status = await os_util.exec('systemctl status ' + NOOBAA_SERVICE_NAME + ' | grep Memory ', {
ignore_rc: false,
return_stdout: true,
trim_stdout: true,
});
} catch (err) {
dbg.warn('could not receive service active state', NOOBAA_SERVICE, err);
dbg.warn('could not receive service active state', NOOBAA_SERVICE_NAME, err);
memory_status = 'Memory: missing memory info';
}
if (memory_status) {
Expand Down
16 changes: 16 additions & 0 deletions src/manage_nsfs/manage_nsfs_cli_errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,22 @@ ManageCLIError.NoSuchConnection = Object.freeze({
http_code: 404,
});

//////////////////////////////
// LIFECYCLE ERRORS //
//////////////////////////////

ManageCLIError.SystemJsonIsMissing = Object.freeze({
code: 'SystemJsonIsMissing',
message: 'Lifecycle worker can not run when system.json is missing.',
http_code: 400,
});

ManageCLIError.NooBaaServiceIsNotActive = Object.freeze({
code: 'NooBaaServiceIsNotActive',
message: 'Lifecycle worker can not run when NooBaa service is not active.',
http_code: 400,
});

///////////////////////////////
// ERRORS MAPPING //
///////////////////////////////
Expand Down
25 changes: 25 additions & 0 deletions src/manage_nsfs/manage_nsfs_cli_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
'use strict';

const dbg = require('../util/debug_module')(__filename);
const os_util = require('../util/os_utils');
const nb_native = require('../util/nb_native');
const native_fs_utils = require('../util/native_fs_utils');
const ManageCLIError = require('../manage_nsfs/manage_nsfs_cli_errors').ManageCLIError;
Expand All @@ -12,6 +13,7 @@ const { BOOLEAN_STRING_VALUES } = require('../manage_nsfs/manage_nsfs_constants'
const NoobaaEvent = require('../manage_nsfs/manage_nsfs_events_utils').NoobaaEvent;
const { account_id_cache } = require('../sdk/accountspace_fs');

const NOOBAA_SERVICE_NAME = 'noobaa';

function throw_cli_error(error, detail, event_arg) {
const error_event = NSFS_CLI_ERROR_EVENT_MAP[error.code];
Expand Down Expand Up @@ -175,6 +177,27 @@ function is_access_key_update(data) {
return new_access_key && cur_access_key && new_access_key !== cur_access_key;
}

/**
* get_service_status returns the active state of a service
* TODO: probablt better to return boolean but requires refactoring in Health script
* @param {String} service_name
* @returns {Promise<String>}
*/
async function get_service_status(service_name) {
let service_status;
try {
service_status = await os_util.exec('systemctl show -p ActiveState --value ' + service_name, {
ignore_rc: false,
return_stdout: true,
trim_stdout: true,
});
} catch (err) {
dbg.warn('could not receive service active state', service_name, err);
service_status = 'missing service status info';
}
return service_status;
}

// EXPORTS
exports.throw_cli_error = throw_cli_error;
exports.write_stdout_response = write_stdout_response;
Expand All @@ -187,3 +210,5 @@ exports.has_access_keys = has_access_keys;
exports.set_debug_level = set_debug_level;
exports.is_name_update = is_name_update;
exports.is_access_key_update = is_access_key_update;
exports.get_service_status = get_service_status;
exports.NOOBAA_SERVICE_NAME = NOOBAA_SERVICE_NAME;
5 changes: 4 additions & 1 deletion src/manage_nsfs/manage_nsfs_constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const TYPES = Object.freeze({
DIAGNOSE: 'diagnose',
UPGRADE: 'upgrade',
NOTIFICATION: 'notification',
CONNECTION: 'connection'
CONNECTION: 'connection',
LIFECYCLE: 'lifecycle'
});

const ACTIONS = Object.freeze({
Expand Down Expand Up @@ -95,6 +96,7 @@ const VALID_OPTIONS_CONNECTION = {
'status': new Set(['name', 'decrypt', ...CLI_MUTUAL_OPTIONS]),
};

const VALID_OPTIONS_LIFECYCLE = new Set([...CLI_MUTUAL_OPTIONS]);

const VALID_OPTIONS_WHITELIST = new Set(['ips', ...CLI_MUTUAL_OPTIONS]);

Expand All @@ -111,6 +113,7 @@ const VALID_OPTIONS = {
upgrade_options: VALID_OPTIONS_UPGRADE,
notification_options: VALID_OPTIONS_NOTIFICATION,
connection_options: VALID_OPTIONS_CONNECTION,
lifecycle_options: VALID_OPTIONS_LIFECYCLE
};

const OPTION_TYPE = {
Expand Down
Loading

0 comments on commit 16133d6

Please sign in to comment.