UNPKG

19.3 kBJavaScriptView Raw
1/*** Generated by streamline 0.10.17 (callbacks) - DO NOT EDIT ***//**
2 * Creates a new VNetUtil object.
3 *
4 * @constructor
5 */
6var azureCommon = require('azure-common');
7var xml = azureCommon.xml2js;
8var builder = require('xmlbuilder');
9var Constants = azureCommon.Constants;
10
11var jsonTransformer = require('./../commands/asm/network/jsontransform/jsontransformer');
12var networkManagementMeta = require('./../commands/asm/network/jsontransform/networkmanagementmeta.json');
13
14function VNetUtil() {
15 this.defaultCidrRange = {
16 start: 0,
17 end: 32
18 };
19
20 this.ipv4Pattern = new RegExp(/^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$/);
21 this.dnsPattern = new RegExp(/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/);
22 this.privateAddressSpacesInfo = {
23 '10.0.0.0/8': {},
24 '172.16.0.0/12': {},
25 '192.168.0.0/16': {}
26 };
27
28 for (var key in this.privateAddressSpacesInfo) {
29 var addressSpaceInfo = this.privateAddressSpacesInfo[key];
30 var parsedIpv4Cidr = this.parseIPv4Cidr(key);
31
32 addressSpaceInfo.ipv4Cidr = parsedIpv4Cidr.ipv4Cidr;
33 addressSpaceInfo.ipv4Octects = parsedIpv4Cidr.octects;
34 addressSpaceInfo.startCidr = parsedIpv4Cidr.cidr;
35 addressSpaceInfo.endCidr = this.defaultCidrRange.end;
36
37 var networkMaskOctects = this.getNetworkMaskFromCIDR(addressSpaceInfo.startCidr).octects;
38 var addressSpaceRange = this.getIPRange(addressSpaceInfo.ipv4Octects, networkMaskOctects);
39 addressSpaceInfo.ipv4StartOctects = addressSpaceRange.start;
40 addressSpaceInfo.ipv4EndOctects = addressSpaceRange.end;
41 addressSpaceInfo.ipv4Start = this.octectsToString(addressSpaceInfo.ipv4StartOctects);
42 addressSpaceInfo.ipv4End = this.octectsToString(addressSpaceInfo.ipv4EndOctects);
43 }
44}
45
46VNetUtil.prototype.setError = function(error) {
47 return {
48 error: error
49 };
50};
51
52VNetUtil.prototype.formatName = function(name) {
53 var fname = '';
54 if (name) {
55 fname = '(' + name + ') ';
56 }
57
58 return fname;
59};
60
61/**
62 * Given ip in octects format get the corresponding string format
63 *
64 * @return string
65 */
66VNetUtil.prototype.octectsToString = function(octects) {
67 return octects.octect0 + '.' + octects.octect1 + '.' +
68 octects.octect2 + '.' + octects.octect3;
69};
70
71/**
72 * Gets the default address space.
73 *
74 * @return object
75 */
76VNetUtil.prototype.defaultAddressSpaceInfo = function() {
77 return this.privateAddressSpacesInfo['10.0.0.0/8'];
78};
79
80/**
81 * Given an address space returns the corresponding private address space.
82 *
83 * @param object addressSpaceOctects The addressspace as octects
84 *
85 * @return object
86 */
87VNetUtil.prototype.getPrivateAddressSpaceInfo = function(addressSpaceOctects) {
88 var privateAddressSpaceInfo = null;
89 for (var key in this.privateAddressSpacesInfo) {
90 var addressSpaceInfo = this.privateAddressSpacesInfo[key];
91 if (this.isIPInRange(
92 addressSpaceInfo.ipv4StartOctects,
93 addressSpaceInfo.ipv4EndOctects,
94 addressSpaceOctects)) {
95 privateAddressSpaceInfo = addressSpaceInfo;
96 break;
97 }
98 }
99
100 return privateAddressSpaceInfo;
101};
102
103/**
104 * Parse the given ipv4 address and return it in octet format
105 *
106 * @param string address The IPv4 address
107 * @param string name A name to be included in the error message
108 *
109 * @return object
110 */
111VNetUtil.prototype.parseIPv4 = function(address, name) {
112 var octects = {
113 octect0: null,
114 octect1: null,
115 octect2: null,
116 octect3: null
117 };
118
119 var patternMatch = address.match(this.ipv4Pattern);
120 if (!patternMatch) {
121 var fname = this.formatName(name);
122 return this.setError('The IP address ' + fname + address + ' is invalid. ');
123 }
124
125 for (var i = 0; i < 4; i++) {
126 octects['octect' + i] = parseInt(patternMatch[i + 1], 10);
127 }
128
129 return {
130 error: null,
131 octects: octects
132 };
133};
134
135/**
136 * Parse the given ipv4 address in cidr form and return
137 * cidr and ipv4 in octet format
138 *
139 * @param string address The IPv4 address in cidr format (---.---.---.---/cidr)
140 * @param string name A name to be included in the error message
141 *
142 * @return object
143 */
144VNetUtil.prototype.parseIPv4Cidr = function(addressSpace, name) {
145 var cidr = null;
146 var fname = this.formatName(name);
147
148 var invalidIpErr = 'The address space ' + fname + addressSpace + ' is invalid. ';
149 var parts = addressSpace.split('/');
150 if (parts.length > 2) {
151 return this.setError(invalidIpErr);
152 }
153
154 if (parts.length == 2) {
155 cidr = parseInt(parts[1], 10);
156 var cidrResult = this.verfiyCIDR(cidr);
157 if (cidrResult.error) {
158 return this.setError(invalidIpErr + cidrResult.error);
159 }
160 }
161
162 var parsedIpResult = this.parseIPv4(parts[0], name);
163 if (parsedIpResult.error) {
164 return this.setError(parsedIpResult.error);
165 }
166
167 return {
168 error: null,
169 cidr: cidr,
170 octects: parsedIpResult.octects,
171 ipv4Cidr: addressSpace
172 };
173};
174
175/**
176 * Checks the given cidr is correct
177 *
178 * @param int value Possible cidr to validate
179 * @param string name Optional, a name to be included in the error message
180 * @param object range Optional, range for cidr
181 *
182 * @return object
183 */
184VNetUtil.prototype.verfiyCIDR = function(value, range, name) {
185 var fname = this.formatName(name);
186
187 if (!range) {
188 range = {
189 start: this.defaultCidrRange.start,
190 end: this.defaultCidrRange.end
191 };
192 }
193
194 if (isNaN(value) || value < range.start || value > range.end) {
195 return this.setError('cidr ' + fname + 'should be a number in the range [' + range.start + ', ' + range.end + '] ');
196 }
197
198 return {
199 error: null
200 };
201};
202
203/**
204 * Given cidr calculate number of hosts
205 *
206 * @param int cidr The cidr value
207 *
208 * @return object
209 */
210VNetUtil.prototype.getHostsCountForCIDR = function(cidr) {
211 var cidrResult = this.verfiyCIDR(cidr);
212 if (cidrResult.error) {
213 return this.setError(cidrResult.error);
214 }
215
216 return {
217 error: null,
218 hostsCount: Math.pow(2, (32 - cidr))
219 };
220};
221
222/**
223 * Given number of hosts calculate the appropriate cidr.
224 *
225 * @param int hostsCount Number of hosts
226 *
227 * @return object
228 */
229VNetUtil.prototype.getCIDRFromHostsCount = function(hostsCount) {
230 var _log2 = function(number) {
231 return Math.log(number) / Math.log(2);
232 };
233
234 var cidr = 32 - Math.ceil(_log2(hostsCount));
235 if (cidr > this.defaultCidrRange.end) {
236 cidr = this.defaultCidrRange.end;
237 }
238
239 return cidr;
240};
241
242/**
243 * Calculate the default subnet cidr for the given address space cidr
244 *
245 * @param int addressSpaceCidr The address space cidr
246 *
247 * @return object
248 */
249VNetUtil.prototype.getDefaultSubnetCIDRFromAddressSpaceCIDR = function(addressSpaceCidr) {
250 if (addressSpaceCidr >= 27) {
251 return this.defaultCidrRange.end;
252 }
253
254 return addressSpaceCidr + 3;
255};
256
257/**
258 * Checks the given ip address is in range
259 *
260 * @param object lower The lower bound IP
261 * @param object upper The upper bound IP
262 * @param object target The ip to check
263 *
264 * @return boolean
265 */
266VNetUtil.prototype.isIPInRange = function(lower, upper, target) {
267 return (target.octect0 >= lower.octect0 && target.octect0 <= upper.octect0 &&
268 target.octect1 >= lower.octect1 && target.octect1 <= upper.octect1 &&
269 target.octect2 >= lower.octect2 && target.octect2 <= upper.octect2 &&
270 target.octect3 >= lower.octect3 && target.octect3 <= upper.octect3);
271};
272
273/**
274 * Given CIDR calculate the network mask
275 *
276 * @param int cidr The cidr
277 *
278 * @return object
279 */
280VNetUtil.prototype.getNetworkMaskFromCIDR = function(cidr) {
281 var cidrResult = this.verfiyCIDR(cidr);
282 if (cidrResult.error) {
283 return this.setError(cidrResult.error);
284 }
285
286 var octects = {
287 'octect0': 0xff,
288 'octect1': 0xff,
289 'octect2': 0xff,
290 'octect3': 0xff
291 };
292
293 var i = Math.floor(cidr / 8);
294 octects['octect' + i] = (0xff << (8 - cidr % 8)) & 0xff;
295
296 for (var j = i + 1; j < 4; j++) {
297 octects['octect' + j] = 0;
298 }
299
300 return {
301 error: cidrResult.error,
302 octects: octects
303 };
304};
305
306/**
307 * Given address space and cidr calculate the range
308 *
309 * @param object addressSpace The start ip of address space
310 * @param object mask The network mask
311 *
312 * @return object
313 */
314VNetUtil.prototype.getIPRange = function(addressSpace, mask) {
315 return {
316 'start': {
317 'octect0': addressSpace.octect0 & mask.octect0,
318 'octect1': addressSpace.octect1 & mask.octect1,
319 'octect2': addressSpace.octect2 & mask.octect2,
320 'octect3': addressSpace.octect3 & mask.octect3
321 },
322 'end': {
323 'octect0': addressSpace.octect0 | (~(mask.octect0) & 0xff),
324 'octect1': addressSpace.octect1 | (~(mask.octect1) & 0xff),
325 'octect2': addressSpace.octect2 | (~(mask.octect2) & 0xff),
326 'octect3': addressSpace.octect3 | (~(mask.octect3) & 0xff)
327 }
328 };
329};
330
331/**
332 * Gets a new network configuration.
333 *
334 * @return object
335 */
336VNetUtil.prototype.getNewNetworkConfigObj = function() {
337 return {
338 VirtualNetworkConfiguration: {
339 VirtualNetworkSites: [],
340 Dns: {
341 DnsServers: []
342 }
343 }
344 };
345};
346
347/**
348 * Parse given xml configuration to json object
349 *
350 * @param string configuration The configuration xml string
351 *
352 * @return object
353 */
354VNetUtil.prototype.getNetworkConfigObj = function(configuration) {
355 function stripBOM(content) {
356 if (content.charCodeAt(0) === 0xFEFF || content.charCodeAt(0) === 0xFFFE) {
357 content = content.slice(1);
358 }
359 return content;
360 }
361
362 function attributeToKeyValue(object) {
363 for (var key in object) {
364 if (key === Constants.XML_METADATA_MARKER) {
365 for (var atrKey in object[key]) {
366 if (object[key].hasOwnProperty(atrKey)) {
367 var newKey = atrKey[0].toUpperCase() + atrKey.substr(1);
368 object[newKey] = object[key][atrKey];
369 }
370 }
371
372 delete object[key];
373 } else if (typeof(object[key]) == 'object') {
374 attributeToKeyValue(object[key]);
375 }
376 }
377 }
378
379 var networkConfig = {};
380 // xml2js parser options
381 var options = {
382 'explicitCharkey': false,
383 'trim': false,
384 'normalize': false,
385 'normalizeTags': false,
386 'attrkey': '$',
387 'charkey': '_',
388 'explicitArray': false,
389 'ignoreAttrs': false,
390 'mergeAttrs': false,
391 'explicitRoot': false,
392 'validator': null,
393 'xmlns': false,
394 'explicitChildren': false,
395 'childkey': '$$',
396 'charsAsChildren': false,
397 'async': false,
398 'strict': true
399 };
400 var transformer = new jsonTransformer();
401
402 xml.parseString(stripBOM(configuration), options, function(err, result) {
403 transformer.transform(result, networkManagementMeta.getNetworkConfig);
404 attributeToKeyValue(result.VirtualNetworkConfiguration);
405
406 networkConfig = result;
407 });
408
409 return networkConfig;
410};
411
412/**
413 * Checks if cidrs ovelaps
414 *
415 * @param string cidr1 cidr in format _._._._/__
416 *
417 * @param string cidr2 cidr in format _._._._/__
418 *
419 * @return boolean
420 */
421VNetUtil.prototype.isCidrsOverlapping = function(cidr1, cidr2) {
422 var parsedCidr1 = this.parseIPv4Cidr(cidr1);
423 if (parsedCidr1.error) {
424 throw new Error(parsedCidr1.error);
425 }
426
427 var parsedCidr2 = this.parseIPv4Cidr(cidr2);
428 if (parsedCidr2.error) {
429 throw new Error(parsedCidr2.error);
430 }
431
432 var maskObj1 = this.getNetworkMaskFromCIDR(parsedCidr1.cidr);
433 if (maskObj1.error) {
434 throw new Error(maskObj1.error);
435 }
436
437 var maskObj2 = this.getNetworkMaskFromCIDR(parsedCidr2.cidr);
438 if (maskObj2.error) {
439 throw new Error(maskObj2.error);
440 }
441
442 var ipRangeObj1 = this.getIPRange(parsedCidr1.octects, maskObj1.octects);
443 var ipRangeObj2 = this.getIPRange(parsedCidr2.octects, maskObj2.octects);
444
445 var startIp1 = ipRangeObj1.start;
446 var startIp2 = ipRangeObj2.start;
447 var endIp1 = ipRangeObj1.end;
448 var endIp2 = ipRangeObj2.end;
449
450 var overlap1 = false;
451 var overlap2 = false;
452
453 for (var i = 0; i < 4; i++) {
454 if (startIp1['octect'+i] < endIp2['octect'+i]) {
455 overlap1 = true;
456 break;
457 } else if (startIp1['octect'+i] > endIp2['octect'+i]) {
458 overlap1 = false;
459 break;
460 }
461 }
462
463 for (var j = 0; j < 4; j++) {
464 if (endIp1['octect'+j] > startIp2['octect'+j]) {
465 overlap2 = true;
466 break;
467 } else if (endIp1['octect'+j] < startIp2['octect'+j]) {
468 overlap2 = false;
469 break;
470 }
471 }
472
473 if (overlap1 && overlap2) {
474 return true;
475 } else {
476 return false;
477 }
478};
479
480/**
481 * Check if given string is valid domain name
482 *
483 * @param string domain The full DNS address
484 *
485 * @return object
486 */
487VNetUtil.prototype.isValidDns = function(domain) {
488 return this.dnsPattern.test(domain);
489};
490
491/**
492 * Parse given json object to xml configuration string
493 *
494 * @param string configuration The configuration json object
495 *
496 * @return xml string
497 */
498VNetUtil.prototype.getNetworkConfigXml = function(configurationObj) {
499 var root = builder.create('NetworkConfiguration');
500 root.att('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');
501 root.att('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
502 root.att('xmlns', 'http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration');
503
504 var eleVNet = root.ele('VirtualNetworkConfiguration');
505 var eleDns = eleVNet.ele('Dns');
506 var eleDnsServers = eleDns.ele('DnsServers');
507
508 if (configurationObj.VirtualNetworkConfiguration.Dns.DnsServers instanceof Array) {
509 for (var i = 0; i < configurationObj.VirtualNetworkConfiguration.Dns.DnsServers.length; i++) {
510 var dnsServer = configurationObj.VirtualNetworkConfiguration.Dns.DnsServers[i];
511 var eleServer = eleDnsServers.ele('DnsServer');
512 eleServer.att('name', dnsServer.Name);
513 eleServer.att('IPAddress', dnsServer.IPAddress);
514 }
515 }
516
517 var eleLocalSites = eleDns.insertAfter('LocalNetworkSites');
518
519 if (configurationObj.VirtualNetworkConfiguration.LocalNetworkSites instanceof Array) {
520 for (var l = 0; l < configurationObj.VirtualNetworkConfiguration.LocalNetworkSites.length; l++) {
521 var localSite = configurationObj.VirtualNetworkConfiguration.LocalNetworkSites[l];
522 var eleLocalSite = eleLocalSites.ele('LocalNetworkSite');
523 eleLocalSite.att('name', localSite.Name);
524 if (localSite.VPNGatewayAddress) {
525 eleLocalSite.ele('VPNGatewayAddress').text(localSite.VPNGatewayAddress);
526 }
527
528 // AddressSpace
529 var eleAddressSpace = eleLocalSite.ele('AddressSpace');
530 for (var m = 0; m < localSite.AddressSpace.length; m++) {
531 var elePrefix = eleAddressSpace.ele('AddressPrefix');
532 elePrefix.text(localSite.AddressSpace[m]);
533 }
534 }
535 }
536
537 var eleSites = eleLocalSites.insertAfter('VirtualNetworkSites');
538
539 for (var k = 0; k < configurationObj.VirtualNetworkConfiguration.VirtualNetworkSites.length; k++) {
540 var site = configurationObj.VirtualNetworkConfiguration.VirtualNetworkSites[k];
541 var eleSite = eleSites.ele('VirtualNetworkSite');
542 eleSite.att('name', site.Name);
543 if (site.AffinityGroup) {
544 eleSite.att('AffinityGroup', site.AffinityGroup);
545 }
546 if (site.Location) {
547 eleSite.att('Location', site.Location);
548 }
549
550 // AddressSpace
551 var eleSiteAddressSpace = eleSite.ele('AddressSpace');
552 for (var j = 0; j < site.AddressSpace.length; j++) {
553 var eleAdrPrefix = eleSiteAddressSpace.ele('AddressPrefix');
554 eleAdrPrefix.text(site.AddressSpace[j]);
555 }
556
557 // Subnets
558 if (site.Subnets && site.Subnets.length > 0) {
559 var eleSubnets = eleSite.ele('Subnets');
560 for (var p = 0; p < site.Subnets.length; p++) {
561 var subnet = site.Subnets[p];
562 var eleSubnet = eleSubnets.ele('Subnet');
563 eleSubnet.att('name', subnet.Name);
564 var eleSubnetAddrPrefix = eleSubnet.ele('AddressPrefix');
565 eleSubnetAddrPrefix.text(subnet.AddressPrefix);
566 }
567 }
568
569 // DnsServersRef
570 if (site.DnsServersRef && site.DnsServersRef.length > 0) {
571 var eleDnsServersRef = eleSite.ele('DnsServersRef');
572 for (var n = 0; n < site.DnsServersRef.length; n++) {
573 var serverRef = site.DnsServersRef[n];
574 var eleServerRef = eleDnsServersRef.ele('DnsServerRef');
575 eleServerRef.att('name', serverRef.Name);
576 }
577 }
578
579 // Gateway
580 if (site.Gateway) {
581 var eleGateway = eleSite.ele('Gateway');
582 if (site.Gateway.ConnectionsToLocalNetwork && site.Gateway.ConnectionsToLocalNetwork.length > 0) {
583 var eleConnectionsToLocalNetwork = eleGateway.ele('ConnectionsToLocalNetwork');
584 for (var a = 0; a < site.Gateway.ConnectionsToLocalNetwork.length; a++) {
585 var localNetworkSiteRef = site.Gateway.ConnectionsToLocalNetwork[a];
586 var eleLocalNetworkSiteRef = eleConnectionsToLocalNetwork.ele('LocalNetworkSiteRef');
587 eleLocalNetworkSiteRef.att('name', localNetworkSiteRef.Name);
588 eleLocalNetworkSiteRef.ele('Connection').att('type', localNetworkSiteRef.Connection.Type);
589 }
590 }
591 }
592
593 }
594
595 var xmlString = root.end({
596 pretty: true,
597 indent: ' ',
598 newline: '\n'
599 });
600
601 return xmlString;
602};
603
604VNetUtil.prototype.ensureRequiredParams = function (param, paramName, dependentParams) {
605 var result = {
606 error: null,
607 emptyParams: null,
608 requiredParams: null,
609 allEmpty: false
610 };
611
612 var arrayToString = function(array, combine) {
613 var arrayAsString = null;
614 if (array.length == 1) {
615 arrayAsString = array[0];
616 } else if (array.length > 1) {
617 var last = ' ' + combine + ' ' + array.pop();
618 arrayAsString = array.join(',');
619 arrayAsString += last;
620 }
621
622 return arrayAsString;
623 };
624
625 var emptyParams = [];
626 var requiresParams = [];
627 if (typeof param != 'undefined') {
628 for (var key in dependentParams) {
629 if (typeof dependentParams[key] == 'undefined') {
630 emptyParams.push(key);
631 requiresParams.push(key);
632 } else if (typeof dependentParams[key] == 'object') {
633 var emptyParams2 = [];
634 var requiresParams2 = [];
635 for (var key2 in dependentParams[key]) {
636 requiresParams2.push(key2);
637 if (typeof dependentParams[key][key2] == 'undefined') {
638 emptyParams2.push(key2);
639 }
640 }
641
642 if (emptyParams2.length == requiresParams2.length) {
643 emptyParams.push('"' + arrayToString(emptyParams2, 'or') + '"');
644 }
645
646 requiresParams.push('"' + arrayToString(requiresParams2, 'or') + '"');
647 } else {
648 requiresParams.push(key);
649 }
650 }
651 }
652
653 if (emptyParams.length > 0) {
654 var singleEmpty = emptyParams.length == 1;
655 var singleRequired = requiresParams.length == 1;
656 result.allEmpty = (emptyParams.length == requiresParams.length);
657 result.emptyParams = arrayToString(emptyParams, 'and');
658 result.requiredParams = arrayToString(requiresParams, 'and');
659
660 result.error = 'The parameter(s) ' + result.requiredParams +
661 (singleRequired ? ' is' : ' are') +
662 ' required when ' + paramName + ' is specified but ' +
663 (result.allEmpty ? 'none of them present' :
664 ('the parameter(s) ' + result.emptyParams + (singleEmpty ? ' is' : ' are') + ' not present'));
665 }
666
667 return result;
668};
669
670module.exports = VNetUtil;