function joinCluster(provider, bigIp, masterIid, options) {
        const TEMP_USER_NAME_LENGHTH = 10; // these are hex bytes - user name will be 20 chars
        const TEMP_USER_PASSWORD_LENGTH = 24; // use a multiple of 6 to prevent '=' at the end

        const now = new Date();

        let managementIp;
        let tempPassword;
        let tempUser;

        if (!masterIid) {
            return q.reject(new Error('Must have a master ID to join'));
        }

        // don't send request too often - master might be in process of syncing
        this.instance.lastJoinRequest = this.instance.lastJoinRequest || new Date(1970, 0);
        const elapsedMsFromLastJoin = now - new Date(this.instance.lastJoinRequest);
        if (elapsedMsFromLastJoin < MIN_MS_BETWEEN_JOIN_REQUESTS) {
            logger.silly('Join request is too soon after last join request.', elapsedMsFromLastJoin, 'ms');
            return q();
        }

        logger.info('Joining cluster.');

        if (provider.hasFeature(CloudProvider.FEATURE_MESSAGING)) {
            this.instance.lastJoinRequest = now;
            return provider.putInstance(this.instanceId, this.instance)
                .then((response) => {
                    logger.debug(response);
                    logger.debug('Resetting current device trust');
                    return bigIp.cluster.resetTrust();
                })
                .then((response) => {
                    logger.debug(response);

                    // Make sure we don't have a current copy of the device group
                    return bigIp.cluster.deleteDeviceGroup(options.deviceGroup);
                })
                .then((response) => {
                    logger.debug(response);
                    return bigIp.deviceInfo();
                })
                .then((response) => {
                    managementIp = response.managementAddress;

                    // Get a random user name to use
                    return cryptoUtil.generateRandomBytes(TEMP_USER_NAME_LENGHTH, 'hex');
                })
                .then((respomse) => {
                    tempUser = respomse;

                    // Get a random password for the user
                    return cryptoUtil.generateRandomBytes(TEMP_USER_PASSWORD_LENGTH, 'base64');
                })
                .then((response) => {
                    tempPassword = response;

                    // Create the temp user account
                    return bigIp.onboard.updateUser(tempUser, tempPassword, 'admin');
                })
                .then(() => {
                    logger.debug('Sending message to join cluster.');

                    const messageData = {
                        host: managementIp,
                        port: bigIp.port,
                        username: tempUser,
                        password: tempPassword,
                        hostname: this.instance.hostname,
                        deviceGroup: options.deviceGroup
                    };

                    return prepareMessageData.call(this, provider, masterIid, JSON.stringify(messageData));
                })
                .then((preppedData) => {
                    if (preppedData) {
                        return provider.sendMessage(
                            CloudProvider.MESSAGE_ADD_TO_CLUSTER,
                            {
                                toInstanceId: masterIid,
                                fromInstanceId: this.instanceId,
                                data: preppedData
                            }
                        );
                    }
                    logger.debug('No encrypted data received');
                    return q();
                })
                .catch((err) => {
                    // need to bubble up nested errors
                    return q.reject(err);
                });
        }

        // not using messaging, just send the request via iControl REST
        const masterInstance = this.instances[masterIid];

        this.instance.lastJoinRequest = now;
        return provider.putInstance(this.instanceId, this.instance)
            .then((response) => {
                logger.debug(response);
                logger.debug('Resetting current device trust');
                return bigIp.cluster.resetTrust();
            })
            .then((response) => {
                logger.debug(response);

                // Make sure we don't have a current copy of the device group
                return bigIp.cluster.deleteDeviceGroup(options.deviceGroup);
            })
            .then((response) => {
                logger.debug(response);
                return provider.getMasterCredentials(masterInstance.mgmtIp, options.port);
            })
            .then((credentials) => {
                logger.debug('Sending request to join cluster.');
                return bigIp.cluster.joinCluster(
                    options.deviceGroup,
                    masterInstance.mgmtIp,
                    credentials.username,
                    credentials.password,
                    false,
                    {
                        remotePort: options.port
                    }
                );
            });
    }
function joinCluster(provider, bigIp, masterIid, options) {
        const TEMP_USER_NAME_LENGHTH = 10; 
        const TEMP_USER_PASSWORD_LENGTH = 24; 

        const now = new Date();

        let managementIp;
        let tempPassword;
        let tempUser;

        if (!masterIid) {
            return q.reject(new Error('Must have a master ID to join'));
        }

        
        this.instance.lastJoinRequest = this.instance.lastJoinRequest || new Date(1970, 0);
        const elapsedMsFromLastJoin = now - new Date(this.instance.lastJoinRequest);
        if (elapsedMsFromLastJoin < MIN_MS_BETWEEN_JOIN_REQUESTS) {
            logger.silly('Join request is too soon after last join request.', elapsedMsFromLastJoin, 'ms');
            return q();
        }

        logger.info('Joining cluster.');

        if (provider.hasFeature(CloudProvider.FEATURE_MESSAGING)) {
            this.instance.lastJoinRequest = now;
            return provider.putInstance(this.instanceId, this.instance)
                .then((response) => {
                    logger.debug(response);
                    logger.debug('Resetting current device trust');
                    return bigIp.cluster.resetTrust();
                })
                .then((response) => {
                    logger.debug(response);

                    
                    return bigIp.cluster.deleteDeviceGroup(options.deviceGroup);
                })
                .then((response) => {
                    logger.debug(response);
                    return bigIp.deviceInfo();
                })
                .then((response) => {
                    managementIp = response.managementAddress;

                    
                    return cryptoUtil.generateRandomBytes(TEMP_USER_NAME_LENGHTH, 'hex');
                })
                .then((respomse) => {
                    tempUser = respomse;

                    
                    return cryptoUtil.generateRandomBytes(TEMP_USER_PASSWORD_LENGTH, 'base64');
                })
                .then((response) => {
                    tempPassword = response;

                    
                    return bigIp.onboard.updateUser(tempUser, tempPassword, 'admin');
                })
                .then(() => {
                    logger.debug('Sending message to join cluster.');

                    const messageData = {
                        host: managementIp,
                        port: bigIp.port,
                        username: tempUser,
                        password: tempPassword,
                        hostname: this.instance.hostname,
                        deviceGroup: options.deviceGroup
                    };

                    return prepareMessageData.call(this, provider, masterIid, JSON.stringify(messageData));
                })
                .then((preppedData) => {
                    if (preppedData) {
                        return provider.sendMessage(
                            CloudProvider.MESSAGE_ADD_TO_CLUSTER,
                            {
                                toInstanceId: masterIid,
                                fromInstanceId: this.instanceId,
                                data: preppedData
                            }
                        );
                    }
                    logger.debug('No encrypted data received');
                    return q();
                })
                .catch((err) => {
                    
                    return q.reject(err);
                });
        }

        
        const masterInstance = this.instances[masterIid];

        this.instance.lastJoinRequest = now;
        return provider.putInstance(this.instanceId, this.instance)
            .then((response) => {
                logger.debug(response);
                logger.debug('Resetting current device trust');
                return bigIp.cluster.resetTrust();
            })
            .then((response) => {
                logger.debug(response);

                
                return bigIp.cluster.deleteDeviceGroup(options.deviceGroup);
            })
            .then((response) => {
                logger.debug(response);
                return provider.getMasterCredentials(masterInstance.mgmtIp, options.port);
            })
            .then((credentials) => {
                logger.debug('Sending request to join cluster.');
                return bigIp.cluster.joinCluster(
                    options.deviceGroup,
                    masterInstance.mgmtIp,
                    credentials.username,
                    credentials.password,
                    false,
                    {
                        remotePort: options.port
                    }
                );
            });
    }
function joinCluster ( provider , bigIp , masterIid , options ) { const TEMP_USER_NAME_LENGHTH = 10 ; // these are hex bytes - user name will be 20 chars const TEMP_USER_PASSWORD_LENGTH = 24 ; // use a multiple of 6 to prevent '=' at the end const now = new Date ( ) ; let managementIp ; let tempPassword ; let tempUser ; if ( ! masterIid ) { return q . reject ( new Error ( 'Must have a master ID to join' ) ) ; } // don't send request too often - master might be in process of syncing this . instance . lastJoinRequest = this . instance . lastJoinRequest || new Date ( 1970 , 0 ) ; const elapsedMsFromLastJoin = now - new Date ( this . instance . lastJoinRequest ) ; if ( elapsedMsFromLastJoin < MIN_MS_BETWEEN_JOIN_REQUESTS ) { logger . silly ( 'Join request is too soon after last join request.' , elapsedMsFromLastJoin , 'ms' ) ; return q ( ) ; } logger . info ( 'Joining cluster.' ) ; if ( provider . hasFeature ( CloudProvider . FEATURE_MESSAGING ) ) { this . instance . lastJoinRequest = now ; return provider . putInstance ( this . instanceId , this . instance ) . then ( ( response ) => { logger . debug ( response ) ; logger . debug ( 'Resetting current device trust' ) ; return bigIp . cluster . resetTrust ( ) ; } ) . then ( ( response ) => { logger . debug ( response ) ; // Make sure we don't have a current copy of the device group return bigIp . cluster . deleteDeviceGroup ( options . deviceGroup ) ; } ) . then ( ( response ) => { logger . debug ( response ) ; return bigIp . deviceInfo ( ) ; } ) . then ( ( response ) => { managementIp = response . managementAddress ; // Get a random user name to use return cryptoUtil . generateRandomBytes ( TEMP_USER_NAME_LENGHTH , 'hex' ) ; } ) . then ( ( respomse ) => { tempUser = respomse ; // Get a random password for the user return cryptoUtil . generateRandomBytes ( TEMP_USER_PASSWORD_LENGTH , 'base64' ) ; } ) . then ( ( response ) => { tempPassword = response ; // Create the temp user account return bigIp . onboard . updateUser ( tempUser , tempPassword , 'admin' ) ; } ) . then ( ( ) => { logger . debug ( 'Sending message to join cluster.' ) ; const messageData = { host : managementIp , port : bigIp . port , username : tempUser , password : tempPassword , hostname : this . instance . hostname , deviceGroup : options . deviceGroup } ; return prepareMessageData . call ( this , provider , masterIid , JSON . stringify ( messageData ) ) ; } ) . then ( ( preppedData ) => { if ( preppedData ) { return provider . sendMessage ( CloudProvider . MESSAGE_ADD_TO_CLUSTER , { toInstanceId : masterIid , fromInstanceId : this . instanceId , data : preppedData } ) ; } logger . debug ( 'No encrypted data received' ) ; return q ( ) ; } ) . catch ( ( err ) => { // need to bubble up nested errors return q . reject ( err ) ; } ) ; } // not using messaging, just send the request via iControl REST const masterInstance = this . instances [ masterIid ] ; this . instance . lastJoinRequest = now ; return provider . putInstance ( this . instanceId , this . instance ) . then ( ( response ) => { logger . debug ( response ) ; logger . debug ( 'Resetting current device trust' ) ; return bigIp . cluster . resetTrust ( ) ; } ) . then ( ( response ) => { logger . debug ( response ) ; // Make sure we don't have a current copy of the device group return bigIp . cluster . deleteDeviceGroup ( options . deviceGroup ) ; } ) . then ( ( response ) => { logger . debug ( response ) ; return provider . getMasterCredentials ( masterInstance . mgmtIp , options . port ) ; } ) . then ( ( credentials ) => { logger . debug ( 'Sending request to join cluster.' ) ; return bigIp . cluster . joinCluster ( options . deviceGroup , masterInstance . mgmtIp , credentials . username , credentials . password , false , { remotePort : options . port } ) ; } ) ; }
Called with this bound to the caller
Called with this bound to the caller