Added agent tag processing.
Ylian Saint-Hilaire committed
Sep 23, 2020 at 15:34 UTC
61cc2399cc173fe16680d1fc64849050aedf65e5
2 files changed
+93
-9
meshagent.js
+82
-8
@@ -1474,13 +1474,17 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1474
if (obj.agentInfo.capabilities & 0x40) return;
1475
if ((command == null) || (command == null)) return; // Safety, should never happen.
1476
1477
+ // If the device is pending a change, hold.
1478
+ if (obj.deviceChanging === true) { setTimeout(function () { ChangeAgentCoreInfo(command); }, 100); return; }
1479
+ obj.deviceChanging = true;
1480
+
1481
// Check that the mesh exists
1482
const mesh = parent.meshes[obj.dbMeshKey];
1479
- if (mesh == null) return;
1483
+ if (mesh == null) { delete obj.deviceChanging; return; }
1484
1485
// Get the node and change it if needed
1486
db.Get(obj.dbNodeKey, function (err, nodes) { // TODO: THIS IS A BIG RACE CONDITION HERE, WE NEED TO FIX THAT. If this call is made twice at the same time on the same device, data will be missed.
1483
- if ((nodes == null) || (nodes.length != 1)) return;
1487
+ if ((nodes == null) || (nodes.length != 1)) { delete obj.deviceChanging; return; }
1488
const device = nodes[0];
1489
if (device.agent) {
1490
var changes = [], change = 0, log = 0;
@@ -1538,6 +1542,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1542
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1543
parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid, [obj.dbNodeKey]), obj, event);
1544
}
1545
+
1546
+ // Device change is done.
1547
+ delete obj.deviceChanging;
1548
}
1549
});
1550
}
@@ -1551,9 +1558,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1558
const mesh = parent.meshes[obj.dbMeshKey];
1559
if (mesh == null) return;
1560
1561
+ // If the device is pending a change, hold.
1562
+ if (obj.deviceChanging === true) { setTimeout(function () { ChangeAgentLocationInfo(command); }, 100); return; }
1563
+ obj.deviceChanging = true;
1564
+
1565
// Get the node and change it if needed
1566
db.Get(obj.dbNodeKey, function (err, nodes) {
1556
- if ((nodes == null) || (nodes.length != 1)) { return; }
1567
+ if ((nodes == null) || (nodes.length != 1)) { delete obj.deviceChanging; return; }
1568
const device = nodes[0];
1569
if (device.agent) {
1570
var changes = [], change = 0;
@@ -1580,27 +1591,87 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1591
parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid, [obj.dbNodeKey]), obj, event);
1592
}
1593
}
1594
+
1595
+ // Done changing the device
1596
+ delete obj.deviceChanging;
1597
});
1598
}
1599
1600
// Update the mesh agent tab in the database
1601
function ChangeAgentTag(tag) {
1602
if (obj.agentInfo.capabilities & 0x40) return;
1589
- if (tag.length == 0) { tag = null; }
1603
+ if ((tag != null) && (tag.length == 0)) { tag = null; }
1604
+
1605
+ // If the device is pending a change, hold.
1606
+ if (obj.deviceChanging === true) { setTimeout(function () { ChangeAgentCoreInfo(command); }, 100); return; }
1607
+ obj.deviceChanging = true;
1608
+
1609
// Get the node and change it if needed
1610
db.Get(obj.dbNodeKey, function (err, nodes) {
1592
- if ((nodes == null) || (nodes.length != 1)) return;
1611
+ if ((nodes == null) || (nodes.length != 1)) { delete obj.deviceChanging; return; }
1612
const device = nodes[0];
1613
if (device.agent) {
1595
- if (device.agent.tag != tag) {
1614
+ // Parse the agent tag
1615
+ var agentTag = null, serverName = null, serverDesc = null, serverTags = null;
1616
+ if (tag != null) {
1617
+ var taglines = tag.split('\r\n').join('\n').split('\r').join('\n').split('\n');
1618
+ for (var i in taglines) {
1619
+ var tagline = taglines[i].trim();
1620
+ if (tagline.length > 0) {
1621
+ if (tagline.startsWith('~')) {
1622
+ if (tagline.startsWith('~ServerName:') && (tagline.length > 12) && (serverName == null)) { serverName = tagline.substring(12).trim(); }
1623
+ if (tagline.startsWith('~ServerDesc:') && (tagline.length > 12) && (serverDesc == null)) { serverDesc = tagline.substring(12).trim(); }
1624
+ if (tagline.startsWith('~ServerTags:') && (tagline.length > 12) && (serverTags == null)) { serverTags = tagline.substring(12).split(','); for (var j in serverTags) { serverTags[j] = serverTags[j].trim(); } }
1625
+ } else { if (agentTag == null) { agentTag = tagline; } }
1626
+ }
1627
+ }
1628
+ }
1629
+
1630
+ // Set the agent tag
1631
+ var changes = false;
1632
+ if (device.agent.tag != agentTag) { device.agent.tag = agentTag; if ((device.agent.tag == null) || (device.agent.tag == '')) { delete device.agent.tag; } changes = true; }
1633
+ if (domain.agenttag != null) {
1634
+ // Set the device's server name
1635
+ if ((serverName != null) && (domain.agenttag.servername === 1) && (device.name != serverName)) { device.name = serverName; changes = true; }
1636
+
1637
+ // Set the device's server description
1638
+ if ((serverDesc != null) && (domain.agenttag.serverdesc === 1) && (device.desc != serverDesc)) { device.desc = serverDesc; changes = true; }
1639
+
1640
+ // Set the device's server description if there is no description
1641
+ if ((serverDesc != null) && (domain.agenttag.serverdesc === 2) && (device.desc != serverDesc) && ((device.desc == null) || (device.desc == ''))) { device.desc = serverDesc; changes = true; }
1642
+
1643
+ if ((serverTags != null) && (domain.agenttag.servertags != null) && (domain.agenttag.servertags != 0)) {
1644
+ // Sort the tags
1645
+ serverTags.sort();
1646
+
1647
+ // Stringify the tags
1648
+ var st2 = '', st1 = serverTags.join(',');
1649
+ if (device.tags != null) { st2 = device.tags.join(','); }
1650
+
1651
+ // Set the device's server tags
1652
+ if ((domain.agenttag.servertags === 1) && (st1 != st2)) { device.tags = serverTags; changes = true; }
1653
+
1654
+ // Set the device's server tags if there are not tags
1655
+ if ((domain.agenttag.servertags === 2) && (st2 == '')) { device.tags = serverTags; changes = true; }
1656
+
1657
+ // Append to device's server tags
1658
+ if ((domain.agenttag.servertags === 3) && (st1 != st2)) {
1659
+ if (device.tags == null) { device.tags = []; }
1660
+ for (var i in serverTags) { if (device.tags.indexOf(serverTags[i]) == -1) { device.tags.push(serverTags[i]); } }
1661
+ device.tags.sort();
1662
+ changes = true;
1663
+ }
1664
+ }
1665
+ }
1666
+
1667
+ if (changes == true) {
1668
// Do some clean up if needed, these values should not be in the database.
1669
if (device.conn != null) { delete device.conn; }
1670
if (device.pwr != null) { delete device.pwr; }
1671
if (device.agct != null) { delete device.agct; }
1672
if (device.cict != null) { delete device.cict; }
1673
1602
- // Set the new tag
1603
- device.agent.tag = tag;
1674
+ // Update the device
1675
db.Set(device);
1676
1677
// Event the node change
@@ -1609,6 +1680,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1680
parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(device.meshid, [obj.dbNodeKey]), obj, event);
1681
}
1682
}
1683
+
1684
+ // Done changing the device
1685
+ delete obj.deviceChanging;
1686
});
1687
}
1688
meshcentral-config-schema.json
+11
-1
@@ -196,6 +196,16 @@
196
"ldapOptions": { "type": "object", "description": "LDAP options passed to ldapauth-fork" },
197
"agentInviteCodes": { "type": "boolean", "default": false, "description": "Enabled a feature where you can set one or more invitation codes in a device group. You can then give a invitation link to users who can use it to download the agent." },
198
"agentNoProxy": { "type": "boolean", "default": false, "description": "When enabled, all newly installed MeshAgents will be instructed to no use a HTTP/HTTPS proxy even if one is configured on the remote system" },
199
+ "agentTag": {
200
+ "type": "object",
201
+ "description": "This section is used to indicate if parts of the meshagent.tag file should be used to set server-side device properties.",
202
+ "additionalProperties": false,
203
+ "properties": {
204
+ "ServerName": { "type": "integer", "default": 0, "description": "Action taken if one of the lines in meshagent.tag contains ~ServerName:name. 0=Ignore, 1=Set." },
205
+ "ServerDesc": { "type": "integer", "default": 0, "description": "Action taken if one of the lines in meshagent.tag contains ~ServerDesc:desc. 0=Ignore, 1=Set, 2=SetIfEmpty." },
206
+ "ServerTags": { "type": "integer", "default": 0, "description": "Action taken if one of the lines in meshagent.tag contains ~ServerTags:tag1,tag2,tag3. 0=Ignore, 1=Set, 2=SetIfEmpty, 3=Append." }
207
+ }
208
+ },
209
"geoLocation": { "type": "boolean", "default": false, "description": "Enables the geo-location feature and device location map in the user interface, this feature is not being worked on." },
210
"novnc": { "type": "boolean", "default": true, "description": "When enabled, activates the built-in web-based noVNC client." },
211
"mstsc": { "type": "boolean", "default": false, "description": "When enabled, activates the built-in web-based RDP client." },
@@ -204,7 +214,7 @@
214
"customUI": { "type": "object" },
215
"consentMessages": {
216
"type": "object",
207
- "description": "This section is user to customize user consent prompts, these show up when asking if a remote session is allowed or not.",
217
+ "description": "This section is used to customize user consent prompts, these show up when asking if a remote session is allowed or not.",
218
"additionalProperties": false,
219
"properties": {
220
"Title": { "type": "string" },