feat: detect service connections and instance health
This commit is contained in:
parent
47e9982d7f
commit
be7bb5f871
@ -152,12 +152,22 @@ enum InstanceStatus {
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
enum HealthyStatus {
|
||||
HEALTHY
|
||||
UNHEALTHY
|
||||
MAINTENANCE
|
||||
UNKNOWN
|
||||
UNAVAILABLE
|
||||
}
|
||||
|
||||
type Instance {
|
||||
id: ID!
|
||||
name: String!
|
||||
machineId: ID!
|
||||
status: InstanceStatus!
|
||||
healthy: Boolean
|
||||
healthy: HealthyStatus
|
||||
watchers: [String]
|
||||
jobs: [String]
|
||||
}
|
||||
|
||||
type Datacenter {
|
||||
|
@ -3,7 +3,6 @@
|
||||
exports[`renders <A /> correctly 1`] = `
|
||||
.jleQxG {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects;
|
||||
text-decoration-skip: objects;
|
||||
}
|
||||
|
||||
@ -72,7 +71,6 @@ exports[`renders <Button /> correctly 1`] = `
|
||||
line-height: 1.15;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
-webkit-text-transform: none;
|
||||
text-transform: none;
|
||||
-webkit-appearance: button;
|
||||
-moz-appearance: button;
|
||||
@ -374,7 +372,6 @@ exports[`renders <Select /> correctly 1`] = `
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
margin: 0;
|
||||
-webkit-text-transform: none;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ const VAsync = require('vasync');
|
||||
|
||||
// local modules
|
||||
const Transform = require('./transform');
|
||||
const { DEPLOYMENT_GROUP, SERVICE, HASH } = require('../watch');
|
||||
const { DEPLOYMENT_GROUP, SERVICE, HASH } = require('../watch/machines');
|
||||
|
||||
|
||||
const NON_IMPORTABLE_STATES = [
|
||||
@ -77,7 +77,7 @@ class Data extends EventEmitter {
|
||||
this._db = new Penseur.Db(settings.name, settings.db);
|
||||
this._dockerCompose = new DockerClient(settings.dockerComposeHost);
|
||||
this._docker = new Dockerode(settings.docker);
|
||||
this._watcher = null;
|
||||
this._machines = null;
|
||||
this._triton = null;
|
||||
|
||||
Triton.createClient({
|
||||
@ -96,8 +96,8 @@ class Data extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
setWatcher (watcher) {
|
||||
this._watcher = watcher;
|
||||
setMachinesWatcher (machinesWatcher) {
|
||||
this._machines = machinesWatcher;
|
||||
}
|
||||
|
||||
connect (cb) {
|
||||
@ -1854,10 +1854,6 @@ class Data extends EventEmitter {
|
||||
updateInstance (clientInstance, cb) {
|
||||
const instance = Transform.toInstance(clientInstance);
|
||||
|
||||
if (typeof instance.healthy !== 'boolean') {
|
||||
instance.healthy = null;
|
||||
}
|
||||
|
||||
this._db.instances.update([instance], (err) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
@ -2073,11 +2069,11 @@ class Data extends EventEmitter {
|
||||
}
|
||||
|
||||
getImportableDeploymentGroups (args, cb) {
|
||||
if (!this._watcher) {
|
||||
if (!this._machines) {
|
||||
return cb(null, []);
|
||||
}
|
||||
|
||||
const machines = this._watcher.getContainers();
|
||||
const machines = this._machines.getContainers();
|
||||
|
||||
if (!Array.isArray(machines)) {
|
||||
return cb(null, []);
|
||||
@ -2123,12 +2119,12 @@ class Data extends EventEmitter {
|
||||
importDeploymentGroup ({ deploymentGroupSlug }, cb) {
|
||||
console.log(`-> import requested for ${deploymentGroupSlug}`);
|
||||
|
||||
if (!this._watcher) {
|
||||
if (!this._machines) {
|
||||
console.log('-> watcher not yet defined');
|
||||
return cb(null, null);
|
||||
}
|
||||
|
||||
const machines = this._watcher.getContainers();
|
||||
const machines = this._machines.getContainers();
|
||||
|
||||
if (!Array.isArray(machines)) {
|
||||
console.log('-> no machines found');
|
||||
|
@ -165,19 +165,22 @@ exports.fromInstance = function (instance) {
|
||||
name: instance.name,
|
||||
machineId: instance.machine_id,
|
||||
status: instance.status,
|
||||
ips: instance.ips,
|
||||
healthy: instance.healthy
|
||||
healthy: instance.healthy,
|
||||
watchers: instance.watchers,
|
||||
jobs: instance.jobs
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
exports.toInstance = function (clientInstance) {
|
||||
return clean({
|
||||
id: clientInstance.id,
|
||||
name: clientInstance.name,
|
||||
machine_id: clientInstance.machineId,
|
||||
status: clientInstance.status,
|
||||
ips: clientInstance.ips,
|
||||
healthy: clientInstance.healthy
|
||||
healthy: clientInstance.healthy,
|
||||
watchers: clientInstance.watchers,
|
||||
jobs: clientInstance.jobs
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -6,8 +6,8 @@ const Piloted = require('piloted');
|
||||
const Data = require('./data');
|
||||
const Pack = require('../package.json');
|
||||
const Resolvers = require('./resolvers');
|
||||
const Watch = require('./watch');
|
||||
const WatchHealth = require('./watch/health');
|
||||
const ContainerPilotWatcher = require('./watch/container-pilot');
|
||||
const MachinesWatcher = require('./watch/machines');
|
||||
|
||||
|
||||
const internals = {};
|
||||
@ -24,7 +24,8 @@ module.exports = function (server, options, next) {
|
||||
}
|
||||
|
||||
const data = new Data(options.data);
|
||||
const watcher = new Watch(Object.assign(options.watch, {
|
||||
const cpWatcher = new ContainerPilotWatcher(Object.assign(options.watch, { data }));
|
||||
const machinesWatcher = new MachinesWatcher(Object.assign(options.watch, {
|
||||
data
|
||||
}));
|
||||
|
||||
@ -32,10 +33,9 @@ module.exports = function (server, options, next) {
|
||||
// portal depends on watcher and vice-versa
|
||||
// I'm sure there is a better way to organize this domains
|
||||
// but this works for now
|
||||
data.setWatcher(watcher);
|
||||
data.setMachinesWatcher(machinesWatcher);
|
||||
|
||||
const healthWatcher = new WatchHealth(Object.assign(options.health, { data }));
|
||||
healthWatcher.on('error', (err) => {
|
||||
cpWatcher.on('error', (err) => {
|
||||
server.log(['error'], err);
|
||||
});
|
||||
|
||||
@ -51,8 +51,9 @@ module.exports = function (server, options, next) {
|
||||
server.bind(data);
|
||||
|
||||
Piloted.on('refresh', internals.refresh(data));
|
||||
watcher.poll();
|
||||
healthWatcher.poll();
|
||||
|
||||
machinesWatcher.poll();
|
||||
cpWatcher.poll();
|
||||
|
||||
server.register([
|
||||
{
|
||||
|
429
packages/portal-api/lib/watch/container-pilot.js
Normal file
429
packages/portal-api/lib/watch/container-pilot.js
Normal file
@ -0,0 +1,429 @@
|
||||
'use strict';
|
||||
|
||||
const Events = require('events');
|
||||
const Flatten = require('lodash.flatten');
|
||||
const Triton = require('triton');
|
||||
const VAsync = require('vasync');
|
||||
const Wreck = require('wreck');
|
||||
const CIDRMatcher = require('cidr-matcher');
|
||||
const ForceArray = require('force-array');
|
||||
const Get = require('lodash.get');
|
||||
const Uniq = require('lodash.uniq');
|
||||
const Queue = require('./queue');
|
||||
|
||||
module.exports = class ContainerPilotWatcher extends Events {
|
||||
constructor (options) {
|
||||
super();
|
||||
|
||||
options = options || {};
|
||||
|
||||
// todo assert options
|
||||
this._data = options.data;
|
||||
this._frequency = options.frequency || 1000;
|
||||
|
||||
Triton.createClient({
|
||||
profile: {
|
||||
url: options.url || process.env.SDC_URL,
|
||||
account: options.account || process.env.SDC_ACCOUNT,
|
||||
keyId: options.keyId || process.env.SDC_KEY_ID
|
||||
}
|
||||
}, (err, client) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
this._triton = client.cloudapi;
|
||||
});
|
||||
}
|
||||
|
||||
poll () {
|
||||
if (this._timeoutId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._timeoutId = setTimeout(() => {
|
||||
this.check((err) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
delete this._timeoutId;
|
||||
this.poll();
|
||||
});
|
||||
}, this._frequency);
|
||||
}
|
||||
|
||||
_getDeploymentGroups (cb) {
|
||||
const getInstances = (service, next) => {
|
||||
service.instances({}, (err, instances) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
next(null, Object.assign({}, service, {
|
||||
instances
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
const getServices = (deploymentGroup, next) => {
|
||||
deploymentGroup.services({}, (err, services) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: services,
|
||||
func: getInstances
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
next(null, Object.assign({}, deploymentGroup, {
|
||||
services: result.successes
|
||||
}));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeploymentGroups = (err, deploymentGroups) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: deploymentGroups,
|
||||
func: getServices
|
||||
}, (err, result) => {
|
||||
cb(err, result.successes);
|
||||
});
|
||||
};
|
||||
|
||||
const getDeploymentGroups = (err, portal) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
portal.deploymentGroups({}, handleDeploymentGroups);
|
||||
};
|
||||
|
||||
this._data.getPortal({}, getDeploymentGroups);
|
||||
}
|
||||
|
||||
_getNetworks (networkIds = [], cb) {
|
||||
VAsync.forEachParallel({
|
||||
inputs: networkIds,
|
||||
func: (id, next) => {
|
||||
this._triton.getNetwork(id, next);
|
||||
}
|
||||
}, (err, results) => {
|
||||
cb(err, ForceArray((results || {}).successes));
|
||||
});
|
||||
}
|
||||
|
||||
_getPublicIps (machine, cb) {
|
||||
this._getNetworks(machine.networks, (err, networks) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
const privateNetworkSubnets = networks
|
||||
.filter((network) => {
|
||||
return !network['public'];
|
||||
})
|
||||
.map((network) => {
|
||||
return network.subnet;
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
const cidr = new CIDRMatcher(privateNetworkSubnets);
|
||||
|
||||
const nonPrivateIps = machine.ips.filter((ip) => {
|
||||
return !cidr.contains(ip);
|
||||
});
|
||||
|
||||
cb(null, nonPrivateIps);
|
||||
});
|
||||
}
|
||||
|
||||
_fetchInstanceStatus (instance, cb) {
|
||||
const { machineId } = instance;
|
||||
|
||||
const handleStatuses = (err, results) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
return cb();
|
||||
}
|
||||
|
||||
const statuses = ForceArray((results || {}).successes);
|
||||
|
||||
const status = statuses.filter(Boolean).shift();
|
||||
|
||||
if (!status) {
|
||||
return cb(null, instance);
|
||||
}
|
||||
|
||||
const services = ForceArray(status.Services).filter(({ Name }) => {
|
||||
return Name !== 'containerpilot';
|
||||
});
|
||||
|
||||
cb(null, Object.assign({}, instance, {
|
||||
cp: Object.assign({}, status, {
|
||||
Services: services
|
||||
})
|
||||
}));
|
||||
};
|
||||
|
||||
const fetchStatus = (ip, next) => {
|
||||
Wreck.get(`http://${ip}:9090/status`, {
|
||||
timeout: 1000 // 1s
|
||||
}, (err, res, payload) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(payload)) {
|
||||
payload = payload.toString();
|
||||
}
|
||||
|
||||
try {
|
||||
const status = JSON.parse(payload);
|
||||
next(null, status);
|
||||
} catch (err) {
|
||||
next();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handlePublicIps = (err, ips) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
return cb();
|
||||
}
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: ips,
|
||||
func: fetchStatus
|
||||
}, handleStatuses);
|
||||
};
|
||||
|
||||
this._triton.getMachine(machineId, (err, machine) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
return cb();
|
||||
}
|
||||
|
||||
this._getPublicIps(machine, handlePublicIps);
|
||||
});
|
||||
}
|
||||
|
||||
_fetchServiceStatus (service, cb) {
|
||||
VAsync.forEachParallel({
|
||||
inputs: service.instances,
|
||||
func: (instance, next) => {
|
||||
this._fetchInstanceStatus(instance, next);
|
||||
}
|
||||
}, (err, results) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
cb(null, Object.assign({}, service, {
|
||||
instances: ForceArray((results || {}).successes)
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
_fetchDeploymentGroupStatus (dg, cb) {
|
||||
VAsync.forEachParallel({
|
||||
inputs: dg.services,
|
||||
func: (service, next) => {
|
||||
this._fetchServiceStatus(service, next);
|
||||
}
|
||||
}, (err, results) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
cb(null, Object.assign({}, dg, {
|
||||
services: ForceArray((results || {}).successes)
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
_saveInstance ({ id, healthy, watchers, jobs }, cb) {
|
||||
if (!id) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
this._data.updateInstance({
|
||||
id,
|
||||
healthy,
|
||||
watchers,
|
||||
jobs
|
||||
}, cb);
|
||||
}
|
||||
|
||||
_saveService ({ id, instances, connections }, cb) {
|
||||
if (!id) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: instances,
|
||||
func: (instance, next) => {
|
||||
this._saveInstance(instance, next);
|
||||
}
|
||||
}, (err) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
this._data.updateService({
|
||||
id,
|
||||
connections
|
||||
}, cb);
|
||||
});
|
||||
}
|
||||
|
||||
_saveDeploymentGroup (dg, cb) {
|
||||
VAsync.forEachParallel({
|
||||
inputs: dg.services,
|
||||
func: (service, next) => {
|
||||
this._saveService(service, next);
|
||||
}
|
||||
}, cb);
|
||||
}
|
||||
|
||||
check (cb) {
|
||||
if (!this._triton) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
const resolveServiceConnections = ({ services, service }) => {
|
||||
const watches = Uniq(
|
||||
Flatten(ForceArray(service.instances).map(({ watches }) => { return watches; }))
|
||||
);
|
||||
|
||||
return watches
|
||||
.map((jobName) => {
|
||||
return services.reduce((serviceId, service) => {
|
||||
if (serviceId) {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
const thisServiceJobs = Uniq(
|
||||
Flatten(ForceArray(service.instances).map(({ jobs }) => { return jobs; }))
|
||||
);
|
||||
|
||||
if (thisServiceJobs.indexOf(jobName) >= 0) {
|
||||
return service.id;
|
||||
}
|
||||
|
||||
return serviceId;
|
||||
}, null);
|
||||
})
|
||||
.filter(Boolean);
|
||||
};
|
||||
|
||||
const resolveInstanceHealth = ({ name }, instance) => {
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!instance.cp) {
|
||||
return 'UNAVAILABLE';
|
||||
}
|
||||
|
||||
const jobNames = Get(instance, 'cp.Services');
|
||||
|
||||
const serviceJobs = jobNames.filter(({ Name }) => { return Name === name; });
|
||||
|
||||
if (serviceJobs.length) {
|
||||
return serviceJobs.shift().Status.toUpperCase();
|
||||
}
|
||||
|
||||
const almostJobNameRegexp = new RegExp(`${name}-.*`);
|
||||
const almostServiceJobs = jobNames.filter((n) => {
|
||||
return almostJobNameRegexp.test(n);
|
||||
});
|
||||
|
||||
if (almostServiceJobs.length) {
|
||||
return almostServiceJobs.shift().Status.toUpperCase();
|
||||
}
|
||||
|
||||
return 'UNKNOWN';
|
||||
};
|
||||
|
||||
const handleStatuses = (err, results) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
const dgs = ForceArray((results || {}).successes)
|
||||
.map((dg) => {
|
||||
return Object.assign({}, dg, {
|
||||
services: ForceArray(dg.services).map((service) => {
|
||||
return Object.assign({}, service, {
|
||||
instances: ForceArray(service.instances).map((instance) => {
|
||||
return Object.assign({}, instance, {
|
||||
healthy: resolveInstanceHealth(service, instance),
|
||||
jobs: Get(instance, 'cp.Services', []).map(
|
||||
({ Name }) => { return Name; }
|
||||
),
|
||||
watches: Get(instance, 'cp.Watches', [])
|
||||
});
|
||||
})
|
||||
});
|
||||
})
|
||||
});
|
||||
})
|
||||
.map((dg) => {
|
||||
return Object.assign({}, dg, {
|
||||
services: ForceArray(dg.services).map((service) => {
|
||||
return Object.assign({}, service, {
|
||||
connections: resolveServiceConnections({
|
||||
services: dg.services,
|
||||
service
|
||||
})
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: dgs,
|
||||
func: (dg, next) => {
|
||||
Queue(dg.id, () => {
|
||||
return new Promise((resolve) => {
|
||||
this._saveDeploymentGroup(dg, (err) => {
|
||||
resolve();
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}, cb);
|
||||
};
|
||||
|
||||
const fetchStatuses = (err, dgs) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
return cb();
|
||||
}
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: dgs,
|
||||
func: (dg, next) => {
|
||||
this._fetchDeploymentGroupStatus(dg, next);
|
||||
}
|
||||
}, handleStatuses);
|
||||
};
|
||||
|
||||
this._getDeploymentGroups(fetchStatuses);
|
||||
}
|
||||
};
|
||||
|
@ -1,159 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const Events = require('events');
|
||||
const Consulite = require('consulite');
|
||||
const VAsync = require('vasync');
|
||||
|
||||
|
||||
module.exports = class Health extends Events {
|
||||
constructor (options) {
|
||||
super();
|
||||
|
||||
options = options || {};
|
||||
|
||||
// todo assert options
|
||||
this._data = options.data;
|
||||
this._frequency = options.frequency || 2000;
|
||||
}
|
||||
|
||||
poll () {
|
||||
if (this._timeoutId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._timeoutId = setTimeout(() => {
|
||||
this.check((err) => {
|
||||
if (err) {
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
delete this._timeoutId;
|
||||
this.poll();
|
||||
});
|
||||
}, this._frequency);
|
||||
}
|
||||
|
||||
// check() follows these steps:
|
||||
// 1. grab all services from the db
|
||||
// 2. filter to only the unique consul hosts
|
||||
// 3. grab all instances from the db
|
||||
// 4. query each consul host for service names
|
||||
// 5. query the respective consul host for service health
|
||||
// 6. match node to instance using the address and update `healthy` if the status changes
|
||||
check (cb) {
|
||||
// 1. grab all services from the db
|
||||
this._data.services.all((err, services) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
if (!services) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
// 2. filter to only the unique consul hosts
|
||||
const consulHosts = [];
|
||||
services.forEach((service) => {
|
||||
if (!service.consul) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (consulHosts.indexOf(service.consul) === -1) {
|
||||
consulHosts.push(service.consul);
|
||||
}
|
||||
});
|
||||
|
||||
// 3. grab all instances from the db
|
||||
this._data.instances.all((err, instances) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
// we match consul nodes using the IP address, remove those that won't match
|
||||
instances = instances.filter((instance) => {
|
||||
return instance.ips && instance.ips.length;
|
||||
});
|
||||
|
||||
// include consul host on each instance
|
||||
// helps to identify the correct instance when comparing addresses
|
||||
instances.forEach((instance) => {
|
||||
const service = services.find((service) => {
|
||||
return (service.instance_ids.indexOf(instance.id) !== -1);
|
||||
});
|
||||
|
||||
if (service) {
|
||||
instance.consul = service.consul;
|
||||
}
|
||||
});
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: consulHosts,
|
||||
// 4. query each consul host for service names
|
||||
// 5. query the respective consul host for service health
|
||||
func: this._checkServicesHealth
|
||||
}, (err, results) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
// 6. match node to instance using the address and update `healthy` if the status changes
|
||||
this._findAndUpdateInstances(instances, results.successes, cb);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_checkServicesHealth (consul, cb) {
|
||||
const consulite = new Consulite({ consul });
|
||||
|
||||
consulite.getServiceNames((err, consulServices) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
// filter out telemetry services
|
||||
consulServices = consulServices.filter((consulService) => {
|
||||
return consulService !== 'containerpilot';
|
||||
});
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: consulServices,
|
||||
func: (consulService, next) => {
|
||||
consulite.getServiceStatus(consulService, (err, nodes) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
nodes = nodes.map((node) => {
|
||||
node.consul = consul;
|
||||
return node;
|
||||
});
|
||||
|
||||
next(null, nodes);
|
||||
});
|
||||
}
|
||||
}, cb);
|
||||
});
|
||||
}
|
||||
|
||||
_findAndUpdateInstances (instances, nodes, cb) {
|
||||
VAsync.forEachPipeline({
|
||||
inputs: nodes,
|
||||
func: (node, next) => {
|
||||
const healthy = (node.status === 'passing');
|
||||
|
||||
const instance = instances.find((instance) => {
|
||||
return (instance.ips.indexOf(node.address) !== -1) &&
|
||||
(instance.consul === node.consul) &&
|
||||
(instance.healthy !== healthy);
|
||||
});
|
||||
|
||||
if (!instance) {
|
||||
return next();
|
||||
}
|
||||
|
||||
this._data.updateInstance({ id: instance.id, healthy }, next);
|
||||
}
|
||||
}, cb);
|
||||
}
|
||||
};
|
@ -1,13 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
// const Assert = require('assert');
|
||||
const Throat = require('throat');
|
||||
const TritonWatch = require('triton-watch');
|
||||
const Get = require('lodash.get');
|
||||
const Find = require('lodash.find');
|
||||
const Util = require('util');
|
||||
const ForceArray = require('force-array');
|
||||
const VAsync = require('vasync');
|
||||
const Queue = require('./queue');
|
||||
|
||||
|
||||
const DEPLOYMENT_GROUP = 'docker:label:com.docker.compose.project';
|
||||
@ -52,7 +52,7 @@ const SERVICE_DELETING_STATUSES = [
|
||||
'UNKNOWN'
|
||||
];
|
||||
|
||||
module.exports = class Watcher {
|
||||
module.exports = class MachineWatcher {
|
||||
constructor (options) {
|
||||
options = options || {};
|
||||
|
||||
@ -71,7 +71,6 @@ module.exports = class Watcher {
|
||||
}
|
||||
});
|
||||
|
||||
this._queues = {};
|
||||
this._waitingForPlan = [];
|
||||
this._isTritonWatchPolling = false;
|
||||
|
||||
@ -112,16 +111,6 @@ module.exports = class Watcher {
|
||||
return this._tritonWatch.getContainers();
|
||||
}
|
||||
|
||||
pushToQueue (deploymentGroupId, cb) {
|
||||
if (this._queues[deploymentGroupId]) {
|
||||
this._queues[deploymentGroupId](cb);
|
||||
return;
|
||||
}
|
||||
|
||||
this._queues[deploymentGroupId] = Throat(1);
|
||||
this._queues[deploymentGroupId](cb);
|
||||
}
|
||||
|
||||
getDeploymentGroup (name, cb) {
|
||||
this._data.getDeploymentGroup({ name }, (err, deploymentGroup) => {
|
||||
if (err) {
|
||||
@ -178,7 +167,6 @@ module.exports = class Watcher {
|
||||
const instance = {
|
||||
name: machine.name,
|
||||
status,
|
||||
ips: machine.ips,
|
||||
machineId: machine.id
|
||||
};
|
||||
|
||||
@ -203,7 +191,6 @@ module.exports = class Watcher {
|
||||
|
||||
const updatedInstance = {
|
||||
id: instance.id,
|
||||
ips: machine.ips,
|
||||
status: (machine.state || '').toUpperCase()
|
||||
};
|
||||
|
||||
@ -630,7 +617,7 @@ module.exports = class Watcher {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pushToQueue(deploymentGroup.id, () => {
|
||||
Queue(deploymentGroup.id, () => {
|
||||
return new Promise((resolve) => {
|
||||
assertService(deploymentGroup, (err) => {
|
||||
if (err) {
|
18
packages/portal-api/lib/watch/queue.js
Normal file
18
packages/portal-api/lib/watch/queue.js
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const Throat = require('throat');
|
||||
|
||||
module.exports = (() => {
|
||||
const _queues = {};
|
||||
|
||||
// pushToQueue
|
||||
return (id, cb) => {
|
||||
if (_queues[id]) {
|
||||
_queues[id](cb);
|
||||
return;
|
||||
}
|
||||
|
||||
_queues[id] = Throat(1);
|
||||
_queues[id](cb);
|
||||
};
|
||||
})();
|
@ -27,11 +27,12 @@
|
||||
"hapi-swagger": "^7.7.0",
|
||||
"inert": "^4.2.0",
|
||||
"lab": "^14.0.1",
|
||||
"vision": "^4.1.1"
|
||||
"vision": "^4.1.1",
|
||||
"wreck": "^12.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"boom": "^5.1.0",
|
||||
"consulite": "^2.0.0",
|
||||
"cidr-matcher": "^1.0.5",
|
||||
"docker-compose-client": "^1.0.8",
|
||||
"dockerode": "^2.5.0",
|
||||
"graphi": "^2.2.1",
|
||||
@ -40,6 +41,7 @@
|
||||
"lodash.find": "^4.6.0",
|
||||
"lodash.flatten": "^4.4.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.uniq": "^4.5.0",
|
||||
"lodash.uniqby": "^4.7.0",
|
||||
"param-case": "^2.1.1",
|
||||
"penseur": "^7.12.3",
|
||||
|
185
yarn.lock
185
yarn.lock
@ -198,7 +198,7 @@ ansi-styles@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
||||
|
||||
ansi-styles@^3.0.0:
|
||||
ansi-styles@^3.0.0, ansi-styles@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.1.0.tgz#09c202d5c917ec23188caa5c9cb9179cd9547750"
|
||||
dependencies:
|
||||
@ -220,8 +220,8 @@ anymatch@^1.3.0:
|
||||
micromatch "^2.1.5"
|
||||
|
||||
apollo-client@^1.4.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-1.7.0.tgz#3d6fdf6ead0a07d3e02d32d9191f26cbcfb6e4f6"
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-1.8.0.tgz#3b5d1976a06a0f82b2fc66fe71754868193dadb9"
|
||||
dependencies:
|
||||
graphql "^0.10.0"
|
||||
graphql-anywhere "^3.0.1"
|
||||
@ -456,8 +456,8 @@ arrify@^1.0.0, arrify@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
|
||||
|
||||
asap@^2.0.0, asap@~2.0.3:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||
|
||||
asn1.js@^4.0.0:
|
||||
version "4.9.1"
|
||||
@ -497,10 +497,6 @@ ast-types@0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.0.tgz#c8721c8747ae4d5b29b929e99c5317b4e8745623"
|
||||
|
||||
ast-types@0.9.6:
|
||||
version "0.9.6"
|
||||
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9"
|
||||
|
||||
async-each@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
|
||||
@ -543,14 +539,14 @@ autoprefixer@^6.0.0:
|
||||
postcss-value-parser "^3.2.3"
|
||||
|
||||
ava-init@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ava-init/-/ava-init-0.2.0.tgz#9304c8b4c357d66e3dfdae1fbff47b1199d5c55d"
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ava-init/-/ava-init-0.2.1.tgz#75ac4c8553326290d2866e63b62fa7035684bd58"
|
||||
dependencies:
|
||||
arr-exclude "^1.0.0"
|
||||
execa "^0.5.0"
|
||||
execa "^0.7.0"
|
||||
has-yarn "^1.0.0"
|
||||
read-pkg-up "^2.0.0"
|
||||
write-pkg "^2.0.0"
|
||||
write-pkg "^3.1.0"
|
||||
|
||||
ava@0.19.1:
|
||||
version "0.19.1"
|
||||
@ -1385,8 +1381,8 @@ backoff@2.4.1, backoff@^2.4.1:
|
||||
precond "0.2"
|
||||
|
||||
bail@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.1.tgz#912579de8b391aadf3c5fdf4cd2a0fc225df3bc2"
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.2.tgz#f7d6c1731630a9f9f0d4d35ed1f962e2074a1764"
|
||||
|
||||
balanced-match@^0.4.0:
|
||||
version "0.4.2"
|
||||
@ -1766,12 +1762,12 @@ camelcase@^4.0.0, camelcase@^4.1.0:
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
|
||||
|
||||
caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
|
||||
version "1.0.30000698"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000698.tgz#623a2de3458ceca379846a8f170e7b1771c7c3a3"
|
||||
version "1.0.30000699"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000699.tgz#5af491ab1c777561a32b43fe253d6a7071ccf979"
|
||||
|
||||
caniuse-lite@^1.0.30000684:
|
||||
version "1.0.30000698"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000698.tgz#8102e8978b1f36962f2a102432e4bf4eac7b6cbe"
|
||||
version "1.0.30000699"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000699.tgz#2a187b737edaa9ebedbbb56edcb53e994eceda0c"
|
||||
|
||||
capture-stack-trace@^1.0.0:
|
||||
version "1.0.0"
|
||||
@ -1824,6 +1820,14 @@ chalk@^0.4.0:
|
||||
has-color "~0.1.0"
|
||||
strip-ansi "~0.1.0"
|
||||
|
||||
chalk@^2.0.0, chalk@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.0.1.tgz#dbec49436d2ae15f536114e76d14656cdbc0f44d"
|
||||
dependencies:
|
||||
ansi-styles "^3.1.0"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^4.0.0"
|
||||
|
||||
chalk@~0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174"
|
||||
@ -1835,16 +1839,16 @@ chalk@~0.5.1:
|
||||
supports-color "^0.2.0"
|
||||
|
||||
character-entities-html4@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.0.tgz#1ab08551d3ce1fa1df08d00fb9ca1defb147a06c"
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.1.tgz#359a2a4a0f7e29d3dc2ac99bdbe21ee39438ea50"
|
||||
|
||||
character-entities-legacy@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.0.tgz#b18aad98f6b7bcc646c1e4c81f9f1956376a561a"
|
||||
|
||||
character-entities@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.0.tgz#a683e2cf75dbe8b171963531364e58e18a1b155f"
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.1.tgz#f76871be5ef66ddb7f8f8e3478ecc374c27d6dca"
|
||||
|
||||
character-reference-invalid@^1.0.0:
|
||||
version "1.1.0"
|
||||
@ -1875,6 +1879,12 @@ ci-info@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
|
||||
|
||||
cidr-matcher@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cidr-matcher/-/cidr-matcher-1.0.5.tgz#1805e49751be8fc8279a73355574e31c9f49666b"
|
||||
dependencies:
|
||||
ip "^1.0.2"
|
||||
|
||||
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
|
||||
@ -2172,13 +2182,6 @@ consulite@1.6.x:
|
||||
or-promise "1.x.x"
|
||||
wreck "10.x.x"
|
||||
|
||||
consulite@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/consulite/-/consulite-2.0.0.tgz#4d35228d24f70a8fb01fdb8ed921d4e54d8bbb16"
|
||||
dependencies:
|
||||
or-promise "1.x.x"
|
||||
wreck "12.x.x"
|
||||
|
||||
contains-path@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
|
||||
@ -2518,8 +2521,8 @@ cryptiles@3.x.x:
|
||||
boom "5.x.x"
|
||||
|
||||
crypto-browserify@^3.11.0:
|
||||
version "3.11.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
|
||||
version "3.11.1"
|
||||
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f"
|
||||
dependencies:
|
||||
browserify-cipher "^1.0.0"
|
||||
browserify-sign "^4.0.0"
|
||||
@ -2819,8 +2822,8 @@ dale-chall-formula@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/dale-chall-formula/-/dale-chall-formula-1.0.1.tgz#de3a82d485c7ab7b64c2c9c046f7f3cb75e177fd"
|
||||
|
||||
dale-chall@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/dale-chall/-/dale-chall-1.0.0.tgz#7f6e7ca357bdb3552c1ddb3c750bd9300cb895b7"
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dale-chall/-/dale-chall-1.0.1.tgz#e2dc01ba31784261520dc94f3e24367b437a677d"
|
||||
|
||||
damerau-levenshtein@^1.0.0:
|
||||
version "1.0.4"
|
||||
@ -3231,8 +3234,8 @@ es-to-primitive@^1.1.1:
|
||||
is-symbol "^1.0.1"
|
||||
|
||||
es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
|
||||
version "0.10.23"
|
||||
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.23.tgz#7578b51be974207a5487821b56538c224e4e7b38"
|
||||
version "0.10.24"
|
||||
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.24.tgz#a55877c9924bc0c8d9bd3c2cbe17495ac1709b14"
|
||||
dependencies:
|
||||
es6-iterator "2"
|
||||
es6-symbol "~3.1"
|
||||
@ -3346,8 +3349,8 @@ eslint-module-utils@^2.1.1:
|
||||
pkg-dir "^1.0.0"
|
||||
|
||||
eslint-plugin-flowtype@^2.34.0:
|
||||
version "2.34.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.34.1.tgz#ea109175645b05d37baeac53b9b65066d79b9446"
|
||||
version "2.35.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.35.0.tgz#d17494f0ae8b727c632d8b9d4b4a848e7e0c04af"
|
||||
dependencies:
|
||||
lodash "^4.15.0"
|
||||
|
||||
@ -3507,9 +3510,9 @@ esprima@^2.6.0, esprima@~2.7.1:
|
||||
version "2.7.3"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
|
||||
|
||||
esprima@^3.1.1, esprima@~3.1.0:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
|
||||
esprima@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
|
||||
|
||||
espurify@^1.6.0:
|
||||
version "1.7.0"
|
||||
@ -3717,11 +3720,11 @@ extsprintf@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
|
||||
|
||||
extsprintf@1.2.0, extsprintf@^1.2.0:
|
||||
extsprintf@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.2.0.tgz#5ad946c22f5b32ba7f8cd7426711c6e8a3fc2529"
|
||||
|
||||
extsprintf@1.3.0:
|
||||
extsprintf@1.3.0, extsprintf@^1.2.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
|
||||
@ -3793,8 +3796,8 @@ fill-range@^2.1.0:
|
||||
repeat-string "^1.5.2"
|
||||
|
||||
fillers@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fillers/-/fillers-1.1.0.tgz#0fa81fb2af369a793f2fafc08b67e60a299fc9f9"
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fillers/-/fillers-1.1.1.tgz#9d1a8f0150d47f78a898de4cd43cf079d417148e"
|
||||
|
||||
finalhandler@~1.0.3:
|
||||
version "1.0.3"
|
||||
@ -4358,15 +4361,15 @@ has-own-prop@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-1.0.0.tgz#7b5e04505ee55896ba32e5018098b481a2f8a0e5"
|
||||
|
||||
has-symbol-support-x@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.3.0.tgz#588bd6927eaa0e296afae24160659167fc2be4f8"
|
||||
has-symbol-support-x@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.0.tgz#442d89b1d0ac6cf5ff2f7b916ee539869b93a256"
|
||||
|
||||
has-to-string-tag-x@^1.2.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.3.0.tgz#78e3d98c3c0ec9413e970eb8d766249a1e13058f"
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.0.tgz#49d7bcde85c2409be38ac327e3e119a451657c7b"
|
||||
dependencies:
|
||||
has-symbol-support-x "^1.3.0"
|
||||
has-symbol-support-x "^1.4.0"
|
||||
|
||||
has-unicode@^2.0.0:
|
||||
version "2.0.1"
|
||||
@ -4629,11 +4632,11 @@ inquirer@^0.12.0:
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@^3.0.2, inquirer@^3.0.6, inquirer@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.1.1.tgz#87621c4fba4072f48a8dd71c9f9df6f100b2d534"
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.2.0.tgz#45b44c2160c729d7578c54060b3eed94487bb42b"
|
||||
dependencies:
|
||||
ansi-escapes "^2.0.0"
|
||||
chalk "^1.0.0"
|
||||
chalk "^2.0.0"
|
||||
cli-cursor "^2.1.0"
|
||||
cli-width "^2.0.0"
|
||||
external-editor "^2.0.4"
|
||||
@ -4643,8 +4646,8 @@ inquirer@^3.0.2, inquirer@^3.0.6, inquirer@^3.1.0:
|
||||
run-async "^2.2.0"
|
||||
rx-lite "^4.0.8"
|
||||
rx-lite-aggregates "^4.0.8"
|
||||
string-width "^2.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
string-width "^2.1.0"
|
||||
strip-ansi "^4.0.0"
|
||||
through "^2.3.6"
|
||||
|
||||
insync@2.x.x:
|
||||
@ -4665,6 +4668,10 @@ invert-kv@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
|
||||
|
||||
ip@^1.0.2:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
|
||||
|
||||
ipaddr.js@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec"
|
||||
@ -5206,8 +5213,8 @@ jest-snapshot@^20.0.3:
|
||||
pretty-format "^20.0.3"
|
||||
|
||||
jest-styled-components@^3.0.2:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-3.3.1.tgz#8803b9577105d11ea8681397a06f154824c8f782"
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-3.3.2.tgz#cf22c7489d417cbb19d878cdc606cec83538f4f7"
|
||||
dependencies:
|
||||
css "^2.2.1"
|
||||
|
||||
@ -5315,11 +5322,11 @@ js-tokens@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
||||
|
||||
js-yaml@^3.2.7, js-yaml@^3.4.3, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.6.0, js-yaml@^3.8.2, js-yaml@^3.8.4:
|
||||
version "3.8.4"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6"
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.0.tgz#4ffbbf25c2ac963b8299dc74da7e3740de1c18ce"
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
esprima "^3.1.1"
|
||||
esprima "^4.0.0"
|
||||
|
||||
js-yaml@~3.7.0:
|
||||
version "3.7.0"
|
||||
@ -6067,8 +6074,8 @@ miller-rabin@^4.0.0:
|
||||
brorand "^1.0.1"
|
||||
|
||||
mime-db@1.x.x:
|
||||
version "1.28.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.28.0.tgz#fedd349be06d2865b7fc57d837c6de4f17d7ac3c"
|
||||
version "1.29.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.29.0.tgz#48d26d235589651704ac5916ca06001914266878"
|
||||
|
||||
mime-db@~1.27.0:
|
||||
version "1.27.0"
|
||||
@ -7056,8 +7063,8 @@ pretty-ms@^2.0.0:
|
||||
plur "^1.0.0"
|
||||
|
||||
primer-support@*:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/primer-support/-/primer-support-4.0.6.tgz#80f3bf1ceb63fda1cf2fdbcea09b632c812e1d54"
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/primer-support/-/primer-support-4.0.7.tgz#c9c433c5a597a78226870ea3d18c4bf0e96eeab4"
|
||||
|
||||
primer-utilities@^3.0.0:
|
||||
version "3.5.0"
|
||||
@ -7552,7 +7559,7 @@ readline2@^1.0.1:
|
||||
is-fullwidth-code-point "^1.0.0"
|
||||
mute-stream "0.0.5"
|
||||
|
||||
recast@0.11.12:
|
||||
recast@0.11.12, recast@^0.11.5:
|
||||
version "0.11.12"
|
||||
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.12.tgz#a79e4d3f82d5d72a82ee177aeaa791e793bbe5d6"
|
||||
dependencies:
|
||||
@ -7561,15 +7568,6 @@ recast@0.11.12:
|
||||
private "~0.1.5"
|
||||
source-map "~0.5.0"
|
||||
|
||||
recast@^0.11.5:
|
||||
version "0.11.23"
|
||||
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3"
|
||||
dependencies:
|
||||
ast-types "0.9.6"
|
||||
esprima "~3.1.0"
|
||||
private "~0.1.5"
|
||||
source-map "~0.5.0"
|
||||
|
||||
rechoir@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
|
||||
@ -8295,7 +8293,7 @@ sntp@1.x.x:
|
||||
dependencies:
|
||||
hoek "2.x.x"
|
||||
|
||||
sort-keys@^1.1.1, sort-keys@^1.1.2:
|
||||
sort-keys@^1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
|
||||
dependencies:
|
||||
@ -8541,7 +8539,7 @@ string-width@^1.0.0, string-width@^1.0.1, string-width@^1.0.2:
|
||||
is-fullwidth-code-point "^1.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
|
||||
string-width@^2.0.0:
|
||||
string-width@^2.0.0, string-width@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.0.tgz#030664561fc146c9423ec7d978fe2457437fe6d0"
|
||||
dependencies:
|
||||
@ -8718,12 +8716,12 @@ stylelint-selector-no-utility@^1.5.0:
|
||||
stylelint "^7.0.0"
|
||||
|
||||
stylelint@^7.0.0, stylelint@^7.0.3, stylelint@^7.11.1:
|
||||
version "7.12.0"
|
||||
resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-7.12.0.tgz#bf302c265d7c2d6fe79b154a9fd873a80f8b4aa4"
|
||||
version "7.13.0"
|
||||
resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-7.13.0.tgz#111f97b6da72e775c80800d6bb6f5f869997785d"
|
||||
dependencies:
|
||||
autoprefixer "^6.0.0"
|
||||
balanced-match "^0.4.0"
|
||||
chalk "^1.1.1"
|
||||
chalk "^2.0.1"
|
||||
colorguard "^1.2.0"
|
||||
cosmiconfig "^2.1.1"
|
||||
debug "^2.6.0"
|
||||
@ -8795,9 +8793,9 @@ supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3:
|
||||
dependencies:
|
||||
has-flag "^1.0.0"
|
||||
|
||||
supports-color@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.1.0.tgz#92cc14bb3dad8928ca5656c33e19a19f20af5c7a"
|
||||
supports-color@^4.0.0, supports-color@^4.1.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.0.tgz#ad986dc7eb2315d009b4d77c8169c2231a684037"
|
||||
dependencies:
|
||||
has-flag "^2.0.0"
|
||||
|
||||
@ -9217,8 +9215,8 @@ triton@5.2.x, triton@^5.2.0:
|
||||
wordwrap "1.0.0"
|
||||
|
||||
trough@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.0.tgz#6bdedfe7f2aa49a6f3c432257687555957f342fd"
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.1.tgz#a9fd8b0394b0ae8fff82e0633a0a36ccad5b5f86"
|
||||
|
||||
try-catch@^1.0.0, try-catch@~1.0.0:
|
||||
version "1.0.0"
|
||||
@ -9610,8 +9608,8 @@ wcwidth@^1.0.0:
|
||||
defaults "^1.0.3"
|
||||
|
||||
weasels@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/weasels/-/weasels-1.1.0.tgz#f2335da6ad8630772bc515549d010bc0415192cb"
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/weasels/-/weasels-1.1.1.tgz#3f3c72ac0a8ea19f5714a814c9101e0740857b25"
|
||||
|
||||
webpack-sources@^0.2.3:
|
||||
version "0.2.3"
|
||||
@ -9721,7 +9719,7 @@ wreck@10.x.x:
|
||||
boom "4.x.x"
|
||||
hoek "4.x.x"
|
||||
|
||||
wreck@12.x.x:
|
||||
wreck@12.x.x, wreck@^12.2.2:
|
||||
version "12.2.2"
|
||||
resolved "https://registry.yarnpkg.com/wreck/-/wreck-12.2.2.tgz#e21823d34c36d672004eefa347ae8c4f6050e3db"
|
||||
dependencies:
|
||||
@ -9748,7 +9746,7 @@ write-file-stdout@0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/write-file-stdout/-/write-file-stdout-0.0.2.tgz#c252d7c7c5b1b402897630e3453c7bfe690d9ca1"
|
||||
|
||||
write-json-file@^2.0.0, write-json-file@^2.1.0, write-json-file@^2.2.0:
|
||||
write-json-file@^2.1.0, write-json-file@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-2.2.0.tgz#51862506bbb3b619eefab7859f1fd6c6d0530876"
|
||||
dependencies:
|
||||
@ -9759,14 +9757,7 @@ write-json-file@^2.0.0, write-json-file@^2.1.0, write-json-file@^2.2.0:
|
||||
sort-keys "^1.1.1"
|
||||
write-file-atomic "^2.0.0"
|
||||
|
||||
write-pkg@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-2.1.0.tgz#353aa44c39c48c21440f5c08ce6abd46141c9c08"
|
||||
dependencies:
|
||||
sort-keys "^1.1.2"
|
||||
write-json-file "^2.0.0"
|
||||
|
||||
write-pkg@^3.0.1:
|
||||
write-pkg@^3.0.1, write-pkg@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-3.1.0.tgz#030a9994cc9993d25b4e75a9f1a1923607291ce9"
|
||||
dependencies:
|
||||
|
Loading…
Reference in New Issue
Block a user