<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

/*
 * Client library for the SDC Compute Node API (CNAPI)
 */

var util = require('util');
var format = util.format;

var RestifyClient = require('./restifyclient');



// --- Exported Client


/**
 * Constructor
 *
 * See the RestifyClient constructor for details
 */
function CNAPI(options) {
    RestifyClient.call(this, options);
}

util.inherits(CNAPI, RestifyClient);


/**
 * Gets boot params for the given CN
 *
 * @param {String} uuid : CN UUID to get<commit_msg>TOOLS-1079: CNAPI#refreshSysinfoAndWait<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

/*
 * Client library for the SDC Compute Node API (CNAPI)
 */

var util = require('util');
var format = util.format;
var assert = require('assert-plus');
var restify = require('restify');
var RestifyClient = require('./restifyclient');


/*
 * Poll a job until it reaches either the succeeded or failed state.
 * Taken from SAPI.
 *
 * Note: if a job fails, it's the caller's responsibility to check for a failed
 * job.  The error object will be null even if the job fails.
 */
function pollJob(client, job_uuid, cb) {
    var attempts = 0;
    var errors = 0;

    var timeout = 5000;  // 5 seconds
    var limit = 720;     // 1 hour

    var poll = function () {
        client.get('/jobs/' + job_uuid, function (err, req, res, job) {
            attempts++;

            if (err) {
                errors++;
                if (errors >= 5) {
                    return cb(err);
                } else {
                    return setTimeout(poll, timeout);
                }
            }

            if (job && job.execution === 'succeeded') {
                return cb(null, job);
            } else if (job && job.execution === 'failed') {
                return cb(null, job);
            } else if (attempts > limit) {
                return cb(new Error('polling for import job timed out'), job);
            }

            return setTimeout(poll, timeout);
        });
    };

    poll();
}


/*
 * Wait for a job to complete.  Returns an error if the job fails with an error
 * other than the (optional) list of expected errors. Taken from SAPI
 */
function waitForJob(url, job_uuid, cb) {
    assert.string(url, 'url');
    assert.string(job_uuid, 'job_uuid');
    assert.func(cb, 'cb');

    var client = restify.createJsonClient({url: url, agent: false});
    pollJob(client, job_uuid, function (err, job) {
        if (err) {
            return cb(err);
        }
        var result = job.chain_results.pop();
        if (result.error) {
            var errmsg = result.error.message || JSON.stringify(result.error);
            return cb(new Error(errmsg));
        } else {
            return cb();
        }
    });
}

// --- Exported Client


/**
 * Constructor
 *
 * See the RestifyClient constructor for details
 */
function CNAPI(options) {
    RestifyClient.call(this, options);
}

util.inherits(CNAPI, RestifyClient);


/**
 * Exec sysinfo into the given CN and wait for the job to complete
 *
 * @param {String} uuid: CN UUID to run sysinfo-refresh
 * @param {Object} options: Request options.
 * @param {String} wf_api_url: Workflow API url
 * @param {Function} cb: callback of the form f(err)
 */
CNAPI.prototype.refreshSysinfoAndWait =
function (uuid,  wf_api_url, options, cb) {
    if (!uuid) {
        throw new TypeError('uuid is required (string)');
    }

    if (!wf_api_url) {
        throw new TypeError('wf_api_url is required (string)');
    }

    if (typeof (options) === 'function') {
        cb = options;
        options = undefined;
    }

    var opts = { path: format('/servers/%s/sysinfo-refresh', uuid) };
    if (options && options.headers) {
        opts.headers = options.headers;
    }

    return this.post(opts, {}, function (err, res) {
        if (err) {
            return cb(err);
        }

        // Pre CNAPI-529
        if (!res.job_uuid) {
            return cb();
        }

        waitForJob(wf_api_url, res.job_uuid, function (jErr, job) {
            if (jErr) {
                return cb(jErr);
            }
            return cb(null, job);
        });
    });
};

/**
 * Gets boot params for the given CN
 *
 * @param {String} uuid : CN UUID to get
{'fraction_non_alphanumeric': 0.12775518938583352, 'fraction_numerical': 0.0074898352236250805, 'mean_word_length': 2.190443686006826, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4571801', 'n_tokens_mistral': 1477, 'n_tokens_neox': 1399, 'n_words': 470}