<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) 2015, Joyent, Inc.
 */


var assert = require('assert-plus');
var sprintf = require('extsprintf').sprintf;
var util = require('util');
var format = util.format;
var vasync = require('vasync');
var semver = require('semver');
var ProgressBar = require('progbar').ProgressBar;

var errors = require('../errors'),
    SDCClientError = errors.SDCClientError,
    UpdateError = errors.UpdateError,
    MultiError = errors.MultiError;

var common = require('../common');
var steps = require('../steps');

var Procedure = require('./procedure').Procedure;

/**
 * Procedure for updating the different agent services.
 */
function UpdateAgentV1(options) {
    assert.arrayOfObject(options.changes, 'options.changes');
    this.changes = options.changes;
}
util.inherits(UpdateAgentV1, Procedure);


UpdateAgentV1.prototype.summarize = function uaSummarize() {
    var c0 = this.changes[0];
    var img = c0.image;
    var out = [sprintf('update "%s" service to image %s ',
                c0.service.name, img.uuid),
            common.indent(sprintf('%s@%s', img.name, img.version)),
            sprintf('in %d servers', c0.insts.length)];
    return out.join('\n');
};

// The minimal required CNAPI version (CNAPI-508, CNAPI-511):
UpdateAgentV1.MIN_CNAPI_VERSION = '20150407T172714Z';
// The first cn-agent version able to run install_agent task, including
// updating itself through cn-agent-setup service:
UpdateAgentV1.MIN_CN_AGENT_VERSION = '2015-11-14T08:05:36Z';


// TODO: Ensure contact with all the selected servers (all the setup servers
// when none is given).
UpdateAgentV1.prototype.execute = function uaExecute(opts, callback) {
    assert.object(opts, 'opts');
    assert.object(opts.sdcadm, 'opts.sdcadm');
    assert.object(opts.plan, 'opts.plan');
    assert.object(opts.log, 'opts.log');
    assert.func(opts.progress, 'opts.progress');
    assert.string(opts.wrkDir, 'opts.wrkDir');
    assert.number(opts.concurrency, 'opts.concurrency');
    assert.func(callback, 'callback');
    var self = this;
    var progress = opts.progress;
    var sdcadm = opts.sdcadm;
    var log = opts.log;
    // Given we may have errors for some CNs, and not from some others, we
    // need to store errors and report at end:
    var errs = [];
    // Progress bar
    var bar;
    var completed = 0;

    function updateAgent(change, nextSvc) {
        log.debug({change: change}, 'updateAgent');

        var cnAgentInsts = [];

        var context = {
            progress: progress,
            log: log,
            sdcadm: sdcadm
        };

        vasync.pipeline({arg: context, funcs: [
            /*
             * Check if cn-agent service is already on SAPI. Otherwise,
             * inform the user how to add it.
             */
            function checkCnAgentSvcOnSapi(_, next) {
                sdcadm.getSvc({
                    svc: 'cn-agent',
                    app: sdcadm.sdc.uuid,
                    allowNone: true
                }, function (err, svc) {
                    if (err) {
                        next(err);
                    } else if (!svc) {
                        next(new UpdateError(
                            'cn-agent service does not exist. Please run:\n' +
                            '\n    sdcadm experimental add-new-agent-svcs\n' +
                            '\nand install latest agentsshar using:\n\n    ' +
                            'sdcadm experimental upate-agents --all --latest' +
                            '\n\nbefore trying to update individual agents'));
                    } else {
                        next();
                    }
                });
            },
            /*
             * Unless CNAPI has been updated to a version newer than
             * MIN_CNAPI_VERSION, tell the user about the CNAPI version
             * required for the update.
             */
            function checkMinCNAPIVersion(_, next) {
                progress('Verifying that CNAPI is able to run agent updates');
                sdcadm.listInsts({
                    svcs: ['cnapi', 'cn-agent']
                }, function (err, instances) {
                    if (err) {
                        next(err);
                    } else {
                        var cnapiInsts = instances.filter(function (i) {
                            return (i.service === 'cnapi');
                        });
                        cnAgentInsts = instances.filter(function (i) {
                            return (i.service === 'cn-agent');
                        });
                        var parts = cnapiInsts[0].version.split('-');
                        var curImg = parts[parts.length - 2];
                        if (UpdateAgentV1.MIN_CNAPI_VERSION > curImg) {
                            next(new UpdateError(format(
                                'image for cnapi is too old for `sdcadm ' +
                                'update agents` (min image build date\n' +
                                'is "%s" current image build date is' +
                                ' "%s")',
                                UpdateAgentV1.MIN_CNAPI_VERSION,
                                curImg
                            )));
                        } else if (!cnAgentInsts.length) {
                            next(new UpdateError('cn-agent is not installed ' +
                                'on any Compute Node.\nIn order to be able to' +
                                'update individual agents you need to run:\n' +
                                'sdcadm experimental add-new-agent-svcs\n' +
                                'and update agentsshar using:\n' +
                                'sdcadm experimental update-agents'));
                        } else {
                            next();
                        }
                    }
                });
            },

            function checkCNsAvailability(_, next) {
                sdcadm.cnapi.listServers({
                    uuids: change.insts.map(function (i) {
                        return (i.server);
                    }).join(',')
                }, function (sErr, servers) {
                    if (sErr) {
                        return next(new errors.SDCClientError(sErr, 'cnapi'));
                    }
                    var unavailable = [];
                    servers.forEach(function (srv) {
                        if (srv.status !== 'running' ||
                            (srv.status === 'running' &&
                             srv.transitional_status !== '')) {
                            unavailable.push(srv.uuid);
                        }<commit_msg>TOOLS-1521 sdcadm should avoid updating duplicated agent instances on the same CN Reviewed by: <NAME> <<EMAIL>><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 2016, Joyent, Inc.
 */


var assert = require('assert-plus');
var sprintf = require('extsprintf').sprintf;
var util = require('util');
var format = util.format;
var vasync = require('vasync');
var semver = require('semver');
var ProgressBar = require('progbar').ProgressBar;

var errors = require('../errors'),
    SDCClientError = errors.SDCClientError,
    UpdateError = errors.UpdateError,
    MultiError = errors.MultiError;

var common = require('../common');
var steps = require('../steps');

var Procedure = require('./procedure').Procedure;

/**
 * Procedure for updating the different agent services.
 */
function UpdateAgentV1(options) {
    assert.arrayOfObject(options.changes, 'options.changes');
    this.changes = options.changes;
}
util.inherits(UpdateAgentV1, Procedure);


UpdateAgentV1.prototype.summarize = function uaSummarize() {
    var c0 = this.changes[0];
    var img = c0.image;
    var out = [sprintf('update "%s" service to image %s ',
                c0.service.name, img.uuid),
            common.indent(sprintf('%s@%s', img.name, img.version)),
            sprintf('in %d servers', c0.insts.length)];
    return out.join('\n');
};

// The minimal required CNAPI version (CNAPI-508, CNAPI-511):
UpdateAgentV1.MIN_CNAPI_VERSION = '20150407T172714Z';
// The first cn-agent version able to run install_agent task, including
// updating itself through cn-agent-setup service:
UpdateAgentV1.MIN_CN_AGENT_VERSION = '2015-11-14T08:05:36Z';


// TODO: Ensure contact with all the selected servers (all the setup servers
// when none is given).
UpdateAgentV1.prototype.execute = function uaExecute(opts, callback) {
    assert.object(opts, 'opts');
    assert.object(opts.sdcadm, 'opts.sdcadm');
    assert.object(opts.plan, 'opts.plan');
    assert.object(opts.log, 'opts.log');
    assert.func(opts.progress, 'opts.progress');
    assert.string(opts.wrkDir, 'opts.wrkDir');
    assert.number(opts.concurrency, 'opts.concurrency');
    assert.func(callback, 'callback');
    var self = this;
    var progress = opts.progress;
    var sdcadm = opts.sdcadm;
    var log = opts.log;
    // Given we may have errors for some CNs, and not from some others, we
    // need to store errors and report at end:
    var errs = [];
    // Progress bar
    var bar;
    var completed = 0;

    function updateAgent(change, nextSvc) {
        log.debug({change: change}, 'updateAgent');

        var cnAgentInsts = [];

        var context = {
            progress: progress,
            log: log,
            sdcadm: sdcadm
        };

        vasync.pipeline({arg: context, funcs: [
            /*
             * Check if cn-agent service is already on SAPI. Otherwise,
             * inform the user how to add it.
             */
            function checkCnAgentSvcOnSapi(_, next) {
                sdcadm.getSvc({
                    svc: 'cn-agent',
                    app: sdcadm.sdc.uuid,
                    allowNone: true
                }, function (err, svc) {
                    if (err) {
                        next(err);
                    } else if (!svc) {
                        next(new UpdateError(
                            'cn-agent service does not exist. Please run:\n' +
                            '\n    sdcadm experimental add-new-agent-svcs\n' +
                            '\nand install latest agentsshar using:\n\n    ' +
                            'sdcadm experimental upate-agents --all --latest' +
                            '\n\nbefore trying to update individual agents'));
                    } else {
                        next();
                    }
                });
            },
            /*
             * Unless CNAPI has been updated to a version newer than
             * MIN_CNAPI_VERSION, tell the user about the CNAPI version
             * required for the update.
             */
            function checkMinCNAPIVersion(_, next) {
                progress('Verifying that CNAPI is able to run agent updates');
                sdcadm.listInsts({
                    svcs: ['cnapi', 'cn-agent']
                }, function (err, instances) {
                    if (err) {
                        next(err);
                    } else {
                        var cnapiInsts = instances.filter(function (i) {
                            return (i.service === 'cnapi');
                        });
                        cnAgentInsts = instances.filter(function (i) {
                            return (i.service === 'cn-agent');
                        });
                        var parts = cnapiInsts[0].version.split('-');
                        var curImg = parts[parts.length - 2];
                        if (UpdateAgentV1.MIN_CNAPI_VERSION > curImg) {
                            next(new UpdateError(format(
                                'image for cnapi is too old for `sdcadm ' +
                                'update agents` (min image build date\n' +
                                'is "%s" current image build date is' +
                                ' "%s")',
                                UpdateAgentV1.MIN_CNAPI_VERSION,
                                curImg
                            )));
                        } else if (!cnAgentInsts.length) {
                            next(new UpdateError('cn-agent is not installed ' +
                                'on any Compute Node.\nIn order to be able to' +
                                'update individual agents you need to run:\n' +
                                'sdcadm experimental add-new-agent-svcs\n' +
                                'and update agentsshar using:\n' +
                                'sdcadm experimental update-agents'));
                        } else {
                            next();
                        }
                    }
                });
            },

            /*
             * Guard against duplicate agent instance entries (see TOOLS-1521)
             */
            function preventDuplicateInstances(_, next) {
                var instUUIDs = change.insts.map(function (ins) {
                    return ins.instance;
                });

                var duplicates = instUUIDs.some(function (ins, pos) {
                    return (instUUIDs.indexOf(ins) !== pos);
                });

                if (duplicates.length) {
                    return next(new UpdateError(format(
                        'there are duplicated instances for agent %s',
                        change.insts[0].service)));
                }
                next();
            },

            function checkCNsAvailability(_, next) {
                sdcadm.cnapi.listServers({
                    uuids: change.insts.map(function (i) {
                        return (i.server);
                    }).join(',')
                }, function (sErr, servers) {
                    if (sErr) {
                        return next(new errors.SDCClientError(sErr, 'cnapi'));
                    }
                    var unavailable = [];
                    servers.forEach(function (srv) {
                        if (srv.status !== 'running' ||
                            (srv.status === 'running' &&
                             srv.transitional_status !== '')) {
                            unavailable.push(srv.uuid);
                        }
{'fraction_non_alphanumeric': 0.10884446878422782, 'fraction_numerical': 0.008556955093099672, 'mean_word_length': 1.3797035347776512, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4419729', 'n_tokens_mistral': 3975, 'n_tokens_neox': 3732, 'n_words': 997}