Viewing File: /usr/local/cpanel/whostmgr/docroot/templates/transfer_tool/services/workerNodes.js

/*
# app/services/workerNodes.js                      Copyright 2022 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
*/

/* global define */

define(
    [
        "angular",
        "lodash",
        "cjt/util/locale",
    ],
    function(angular, _, LOCALE) {

        "use strict";

        var MODULE_NAMESPACE = "whm.transfers.services.workerNodes";
        var SERVICE_NAME = "WorkerNodesService";
        var MODULE_REQUIREMENTS = [];
        var SERVICE_INJECTABLES = ["LOCAL_WORKER_NODES", "REMOTE_WORKER_NODES", "DEFAULT_WORKER_OPTIONS"];

        /**
         * Service for Handling Worker / Linked Nodes
         *
         * @param {object[]} LOCAL_WORKER_NODES local worker nodes possible to be used by accounts
         * @param {object[]} REMOTE_WORKER_NODES remote worker nodes that may or may not be used by individual accounts
         * @param {object} DEFAULT_WORKER_OPTIONS worker type keyed object representing the keys and defaults for the system
         * @returns instance of a workerNodesService
         */
        var SERVICE_FACTORY = function(LOCAL_WORKER_NODES, REMOTE_WORKER_NODES, DEFAULT_WORKER_OPTIONS) {

            var Service = function() {};

            Service.prototype = Object.create({});

            _.assign(Service.prototype, {

                _localWorkerNodes: null,
                _remoteWorkerNodes: null,
                _workerOptionTypes: null,
                _defaultWorkerOptions: null,
                _accountWorkerNodeOptions: {},
                _accountWorkerDefaultValues: {},

                /**
                 * Parse a raw worker node
                 *
                 * @private
                 *
                 * @param {object{alias:string,hostname:string,worker_capabilities:object}} rawWorkerNode raw worker node
                 * @returns {object} parsed worker node
                 */
                _parseWorkerNode: function _parseWorkerNode(rawWorkerNode) {
                    var workerNode = {
                        alias: rawWorkerNode["alias"],
                        hostname: rawWorkerNode["hostname"],
                        workerCapabilities: Object.keys(rawWorkerNode.worker_capabilities),
                    };
                    return workerNode;
                },

                /**
                 * Parse a set of raw worker nodes
                 *
                 * @private
                 *
                 * @param {object[]} rawWorkerNodes raw worker nodes to parse
                 * @returns {object[]} parsed worker nodes
                 */
                _parseWorkerNodes: function _parseWorkerNodes(rawWorkerNodes) {
                    return rawWorkerNodes.map(this._parseWorkerNode);
                },

                /**
                 * Get the listed of remote worker nodes
                 *
                 * @returns {object[]} parsed remote worker nodes
                 */
                getRemoteWorkerNodes: function getRemoteWorkerNodes() {
                    if (_.isNull(this._remoteWorkerNodes)) {
                        this._remoteWorkerNodes = this._parseWorkerNodes(REMOTE_WORKER_NODES);
                    }

                    return this._remoteWorkerNodes;
                },

                /**
                 * Get the list of local worker nodes
                 *
                 * @returns {object[]} parsed local worker nodes
                 */
                getLocalWorkerNodes: function getLocalWorkerNodes() {
                    if (_.isNull(this._localWorkerNodes)) {
                        this._localWorkerNodes = this._parseWorkerNodes(LOCAL_WORKER_NODES);
                    }

                    return this._localWorkerNodes;
                },

                /**
                 * Get the default worker options.
                 * These are the settings that determine which workers, what defaults, and what the modelKey is
                 *
                 * @returns {object} worker type keyed object
                 */
                getDefaultWorkerOptions: function getDefaultWorkerOptions() {
                    if ( _.isNull(this._defaultWorkerOptions) ) {
                        this._defaultWorkerOptions = DEFAULT_WORKER_OPTIONS;

                        // Check to ensure the default exists, if not, set it to local
                        Object.keys(this._defaultWorkerOptions).filter(function(workerType) {
                            return !this.getWorkerByAlias(this.getLocalWorkerNodes(), this._defaultWorkerOptions[workerType].value);
                        }, this).forEach(function(workerType) {

                            // These don't exist locally, so we should restore to controller
                            this._defaultWorkerOptions[workerType].value = ".local";
                        }, this);
                    }
                    return this._defaultWorkerOptions;
                },

                /**
                 * Get a list of worker options that are supported
                 *
                 * @returns {string[]} array of strings representing the worker types supported
                 *
                 * @example
                 * this.getWorkerOptionTypes(); // ['Mail', 'Web']
                 */
                getWorkerOptionTypes: function getWorkerOptionTypes() {
                    if (_.isNull(this._workerOptionTypes)) {
                        this._workerOptionTypes = Object.keys(this.getDefaultWorkerOptions());
                    }
                    return this._workerOptionTypes;
                },

                /**
                 * Look up a worker based on the hostname and type
                 *
                 * @param {object[]} workerList list of workers to search
                 * @param {string} hostname hostname of the worker 'host.name.com'
                 * @param {string} desiredWorkerType worker type 'Mail' etc
                 * @returns {object|null} worker type if it matches the hostname and type
                 */
                getWorkerByHostname: function getWorkerByHostname(workerList, hostname, desiredWorkerType) {
                    if (!workerList) {
                        return;
                    }

                    return _.find(workerList, function(worker) {
                        return worker.hostname === hostname && worker.workerCapabilities.indexOf(desiredWorkerType) > -1;
                    });
                },

                /**
                 * Get a worker from a worker list based on the alias
                 *
                 * @param {object[]} workerList list of workers to search
                 * @param {string} alias alias for which to search
                 * @returns {object|null} returns the worker object if it exists
                 */
                getWorkerByAlias: function getWorkerByAlias(workerList, alias) {
                    if (!workerList) {
                        return;
                    }

                    return _.find(workerList, function(worker) {
                        return worker.alias === alias;
                    });
                },

                /**
                 * Build an item for a worker list of a specific type
                 *
                 * @private
                 *
                 * @param {string} label descriptive label of the item
                 * @param {string} value specific key value for comparison
                 * @param {string} type type of worker (Mail, etc)
                 * @returns {object} worker item
                 */
                _createWorkerListTypeItem: function _createWorkerListTypeItem(label, value, type) {
                    var defaultWorkerOptions = this.getDefaultWorkerOptions();
                    var workerOption = {
                        label: label,
                        value: value,
                        modelKey: defaultWorkerOptions[type].modelKey,
                    };
                    return workerOption;
                },


                /**
                 * Build an options list for a specific type of worker for a specific account
                 *
                 * @private
                 *
                 * @param {object} account account to base to list from
                 * @param {string} workerType type of worker to build the list for
                 * @returns {object[]} list of worker options for the account
                 */
                _createAccountWorkerListType: function _createAccountWorkerListType(account, workerType) {
                    var defaultWorkerOptions = this.getDefaultWorkerOptions();
                    var remoteWorkerNodes = this.getRemoteWorkerNodes();
                    var localWorkerNodes = this.getLocalWorkerNodes();

                    var existingNodeFound;
                    var workerTypeList = [];

                    // Add local, should always be an option
                    workerTypeList.push( this._createWorkerListTypeItem( LOCALE.maketext("Use only this server. Transfer or restore locally."), ".local", workerType) );

                    // Check for a local alias that matches the hostname and workertype of the remote user type
                    if (account.workerNodes && account.workerNodes[workerType]) {
                        var remoteWorker = this.getWorkerByAlias(remoteWorkerNodes, account.workerNodes[workerType]);
                        var matchingLocalWorker = remoteWorker && this.getWorkerByHostname(localWorkerNodes, remoteWorker.hostname, workerType);
                        if (matchingLocalWorker) {
                            existingNodeFound = matchingLocalWorker.alias;
                            workerTypeList.push(this._createWorkerListTypeItem( LOCALE.maketext("Use the [asis,cPanel] account’s package configuration.") + " (" + matchingLocalWorker.hostname + ")", existingNodeFound, workerType) );
                        }
                    }

                    // Add the rest
                    localWorkerNodes.filter(function(workerNode) {
                        return workerNode.alias !== existingNodeFound;
                    }).forEach(function(workerNode) {
                        workerTypeList.push( this._createWorkerListTypeItem(workerNode.alias + " (" + workerNode.hostname + ")", workerNode.alias, workerType) );
                    }, this);

                    var defaultAlias = existingNodeFound ? existingNodeFound : defaultWorkerOptions[workerType].value;

                    workerTypeList.filter(function(workerItem) {
                        return workerItem.value === defaultAlias;
                    }).forEach(function(workerItem) {
                        workerItem.isDefault = true;
                    });

                    return workerTypeList;
                },

                /**
                 * See <getAccountWorkerNodeOptions>
                 *
                 * @private
                 */
                _createAccountWorkerLists: function _createAccountWorkerLists(account) {
                    var workerLists = {};
                    this.getWorkerOptionTypes().forEach(function(workerType) {
                        workerLists[workerType] = this._createAccountWorkerListType(account, workerType);
                    }, this);
                    return workerLists;
                },

                /**
                 * Build all the worker options for all supported types for an account
                 *
                 * @private
                 *
                 * @param {object} account
                 * @returns {object} object with lists based on specific type
                 *
                 * @example
                 * this.getAccountWorkerNodeOptions(acccount); // {'Mail':[{label:"",value,"",modelKey:"",isDefault:false},{},{},...], 'Web':[], ...}
                 */
                getAccountWorkerNodeOptions: function getAccountWorkerNodeOptions(account) {

                    var cacheKey = this._getAccountCacheKey(account);

                    if (_.isUndefined(this._accountWorkerNodeOptions[cacheKey])) {
                        this._accountWorkerNodeOptions[cacheKey] = this._createAccountWorkerLists(account);
                    }
                    return this._accountWorkerNodeOptions[cacheKey];
                },


                /**
                 * Determine if any of the worker options for an account have been altered from the default
                 *
                 * @param {object} account account to check
                 * @returns {boolean} has the account's worker options been altered
                 */
                checkWorkerOptionsAltered: function checkWorkerOptionsAltered(account) {
                    return this.getAccountWorkerDefaultValues(account).some(function(workerDefaultObj) {
                        var modelKey = workerDefaultObj.modelKey;
                        var defaultValue = workerDefaultObj.value;
                        if (account[modelKey] !== defaultValue) {
                            return true;
                        }
                        return false;
                    });
                },

                /**
                 * Get the default worker values for an account. Used to establish initial values
                 *
                 * @param {object} account account to build the list from
                 * @returns {object[]} returns a list of modelKey and values for an account
                 *
                 * @example
                 * this.getAccountWorkerDefaultValues(account); // [{modelKey:"mail_location", value:'the_default_value"},...]
                 */
                getAccountWorkerDefaultValues: function getAccountWorkerDefaultValues(account) {
                    var cacheKey = this._getAccountCacheKey(account);

                    if (_.isUndefined(this._accountWorkerDefaultValues[cacheKey])) {
                        var workerNodeOptions = this.getAccountWorkerNodeOptions(account);
                        var defaultWorkerOptions = this.getDefaultWorkerOptions();

                        var accountDefaults = [];

                        Object.keys(workerNodeOptions).forEach(function(workerType) {
                            var accountDefault = {
                                workerType: workerType,
                                modelKey: defaultWorkerOptions[workerType].modelKey
                            };

                            workerNodeOptions[workerType].forEach(function(workerOption) {
                                if (workerOption.isDefault) {
                                    accountDefault.value = workerOption.value;
                                }
                            });

                            if (!accountDefault.value) {
                                accountDefault.value = defaultWorkerOptions[workerType].value;
                            }

                            accountDefaults.push(accountDefault);
                        });

                        this._accountWorkerDefaultValues[cacheKey] = accountDefaults;
                    }

                    return this._accountWorkerDefaultValues[cacheKey];
                },

                /**
                 * Reset an account's worker settings to the defaults for that account
                 *
                 * @param {object} account
                 */
                resetAccountToDefaults: function resetAccountToDefaults(account) {

                    // Get Worker Node Default Values (this is specific to the individual account)
                    var defaultValues = this.getAccountWorkerDefaultValues(account);
                    defaultValues.forEach(function(defaultValueObj) {
                        account[defaultValueObj.modelKey] = defaultValueObj.value;
                    }, this);
                },

                /**
                 * Build a key to use for caching account lists
                 *
                 * @private
                 *
                 * @param {object} account account for which to build the key
                 * @returns {string} a string combination of the remote_user and domain, combined with a pipe
                 */
                _getAccountCacheKey: function _getAccountCacheKey(account) {

                    // This is probably over-safe. remote_user _shouldn't_ change
                    return account.remote_user + "|" + account.domain;
                }


            });

            return new Service();
        };

        SERVICE_INJECTABLES.push(SERVICE_FACTORY);

        var app = angular.module(MODULE_NAMESPACE, MODULE_REQUIREMENTS);

        // This determines which options are revealed
        app.value("DEFAULT_WORKER_OPTIONS", {
            "Mail": {
                value: ".local",
                modelKey: "mail_location"
            }
        });

        app.factory(SERVICE_NAME, SERVICE_INJECTABLES);

        return {
            "class": SERVICE_FACTORY,
            "serviceName": SERVICE_NAME,
            "namespace": MODULE_NAMESPACE
        };
    }
);
Back to Directory File Manager