pmcf 2.39.8 → 2.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmcf",
3
- "version": "2.39.8",
3
+ "version": "2.40.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/endpoint.mjs CHANGED
@@ -13,10 +13,6 @@ class _Endpoint {
13
13
  delete data.type;
14
14
  }
15
15
  Object.assign(this, data);
16
-
17
- if(this.port === undefined) {
18
- throw new Error(`${this.toString()}: has no port`);
19
- }
20
16
  }
21
17
 
22
18
  get type() {
@@ -28,13 +28,16 @@ export class SkeletonNetworkInterface extends ServiceOwner {
28
28
  }
29
29
 
30
30
  get host() {
31
- if(this.owner instanceof Host) {
31
+ if (this.owner instanceof Host) {
32
32
  return this.owner;
33
33
  }
34
34
  }
35
35
 
36
36
  *hosts() {
37
- yield* this.owner.hosts();
37
+ const host = this.host;
38
+ if (host) {
39
+ yield host;
40
+ }
38
41
  }
39
42
 
40
43
  get network_interface() {
@@ -12,7 +12,6 @@ export class ServiceOwner extends Base {
12
12
  set services(service) {
13
13
  const present = this._services.find(s => s.name === service.name);
14
14
 
15
- // console.log("SET SERVICE", service.name);
16
15
  if (!present) {
17
16
  this._services.push(service);
18
17
  }
package/src/service.mjs CHANGED
@@ -155,7 +155,7 @@ export class Service extends Base {
155
155
  }
156
156
 
157
157
  toString() {
158
- return `${this.type}`;
158
+ return `${super.toString()}[${this.type}]`;
159
159
  }
160
160
 
161
161
  set extends(value) {
@@ -255,24 +255,16 @@ export class Service extends Base {
255
255
  for (const ep of this.endpoints(
256
256
  e => e.protocol && e.networkInterface.kind !== "loopback"
257
257
  )) {
258
- if (ep.port === undefined) {
259
- console.error(
260
- "Endpoint without port",
261
- ep.toString(),
262
- ep.networkInterface?.kind
263
- );
264
- } else {
265
- records.push(
266
- DNSRecord(
267
- dnsFullName(`_${this.type}._${ep.protocol}.${domainName}`),
268
- "SRV",
269
- this.priority ?? 10,
270
- this.weight,
271
- ep.port,
272
- dnsFullName(this.domainName)
273
- )
274
- );
275
- }
258
+ records.push(
259
+ DNSRecord(
260
+ dnsFullName(`_${this.type}._${ep.protocol}.${domainName}`),
261
+ "SRV",
262
+ this.priority ?? 10,
263
+ this.weight,
264
+ ep.port,
265
+ dnsFullName(this.domainName)
266
+ )
267
+ );
276
268
  }
277
269
  }
278
270
 
@@ -29,6 +29,12 @@ const BINDServiceTypeDefinition = {
29
29
  extends: ExtraSourceServiceTypeDefinition,
30
30
  priority: 0.1,
31
31
  properties: {
32
+ addresses: {
33
+ type: ["network", "host", "network_interface", "location", "owner"],
34
+ collection: true,
35
+ writeable: true
36
+ },
37
+
32
38
  trusted: {
33
39
  type: address_types,
34
40
  collection: true,
@@ -115,6 +121,7 @@ export class BINDService extends ExtraSourceService {
115
121
  hasLinkLocalAdresses = true;
116
122
  hasLocationRecord = true;
117
123
  notify = true;
124
+ _addresses = [];
118
125
  _trusted = [];
119
126
  _protected = [];
120
127
  _open = [];
@@ -161,6 +168,14 @@ export class BINDService extends ExtraSourceService {
161
168
  return [this.serial, this.refresh, this.retry, this.expire, this.minimum];
162
169
  }
163
170
 
171
+ set addresses(value) {
172
+ this._addresses.push(value);
173
+ }
174
+
175
+ get addresses() {
176
+ return this._addresses;
177
+ }
178
+
164
179
  set protected(value) {
165
180
  this._protected.push(value);
166
181
  }
@@ -202,16 +217,18 @@ export class BINDService extends ExtraSourceService {
202
217
  }
203
218
 
204
219
  async *preparePackages(dir) {
205
- const location = this.owner.owner;
206
- const name = location.name;
207
- const p1 = join(dir, "p1") + "/";
220
+ const sources = this.addresses.length ? this.addresses : [this.owner];
221
+ const names = sources.map(a => a.fullName).join(" ");
222
+
223
+ const name = this.owner.owner.name;
224
+ const configPackageDir = join(dir, "config") + "/";
208
225
  const packageData = {
209
- dir: p1,
210
- sources: [new FileContentProvider(p1)],
226
+ dir: configPackageDir,
227
+ sources: [new FileContentProvider(configPackageDir)],
211
228
  outputs: this.outputs,
212
229
  properties: {
213
230
  name: `named-${name}`,
214
- description: `named definitions for ${location.fullName}`,
231
+ description: `named definitions for ${names}`,
215
232
  access: "private"
216
233
  }
217
234
  };
@@ -224,7 +241,7 @@ export class BINDService extends ExtraSourceService {
224
241
 
225
242
  if (forwarders.length) {
226
243
  await writeLines(
227
- join(p1, "etc/named/options"),
244
+ join(configPackageDir, "etc/named/options"),
228
245
  `forwarders.conf`,
229
246
  addressesStatement("forwarders", forwarders)
230
247
  );
@@ -247,18 +264,18 @@ export class BINDService extends ExtraSourceService {
247
264
  ].flat();
248
265
 
249
266
  if (acls.length) {
250
- await writeLines(join(p1, "etc/named"), `0-acl-${name}.conf`, acls);
267
+ await writeLines(join(configPackageDir, "etc/named"), `0-acl-${name}.conf`, acls);
251
268
  }
252
269
  if (forwarders.length || acls.length) {
253
270
  yield packageData;
254
271
  }
255
272
 
256
- const p2 = join(dir, "p2") + "/";
273
+ const zonesPackageDir = join(dir, "zones") + "/";
257
274
 
258
- packageData.dir = p2;
275
+ packageData.dir = zonesPackageDir;
259
276
  packageData.properties = {
260
277
  name: `named-zones-${name}`,
261
- description: `zone definitions for ${location.fullName}`,
278
+ description: `zone definitions for ${names}`,
262
279
  dependencies: ["mf-named"],
263
280
  replaces: ["mf-named-zones"],
264
281
  access: "private",
@@ -267,7 +284,7 @@ export class BINDService extends ExtraSourceService {
267
284
 
268
285
  packageData.sources = [
269
286
  new FileContentProvider(
270
- p2,
287
+ zonesPackageDir,
271
288
  {
272
289
  mode: 0o644,
273
290
  owner: "named",
@@ -281,59 +298,46 @@ export class BINDService extends ExtraSourceService {
281
298
  )
282
299
  ];
283
300
 
284
- await this.generateZoneDefs(location, packageData);
301
+ await this.generateZoneDefs(sources, packageData);
285
302
 
286
- yield packageData;
287
- }
303
+ const foreignZonesPackageDir = join(dir, "foreignZones") + "/";
288
304
 
289
- async generateZoneDefs(location, packageData) {
290
- const ttl = this.recordTTL;
291
- const nameService = this.findService({ type: "dns", priority: "<10" });
292
- const rname = this.administratorEmail.replace(/@/, ".");
305
+ packageData.dir = foreignZonesPackageDir;
306
+ packageData.properties = {
307
+ name: `named-foreign-zones-${name}`,
308
+ description: `foreign zone definitions for ${names}`,
309
+ dependencies: [`named-zones-${name}`],
310
+ access: "private",
311
+ hooks: {}
312
+ };
293
313
 
294
- const SOARecord = DNSRecord(
295
- "@",
296
- "SOA",
297
- dnsFullName(nameService.domainName),
298
- dnsFullName(rname),
299
- `(${[...this.soaUpdates].join(" ")})`
300
- );
314
+ packageData.sources = [
315
+ new FileContentProvider(
316
+ foreignZonesPackageDir,
317
+ {
318
+ mode: 0o644,
319
+ owner: "named",
320
+ group: "named"
321
+ },
322
+ {
323
+ mode: 0o755,
324
+ owner: "named",
325
+ group: "named"
326
+ }
327
+ )
328
+ ];
301
329
 
302
- const NSRecord = DNSRecord(
303
- "@",
304
- "NS",
305
- dnsFullName(nameService.ipAddressOrDomainName)
306
- );
330
+ await this.generateForeignDefs(sources, packageData);
307
331
 
308
- console.log(`${nameService}`, nameService.ipAddressOrDomainName);
332
+ yield packageData;
333
+ }
309
334
 
335
+ async generateForeignDefs(sources, packageData) {
310
336
  const configs = [];
311
337
 
312
- for (const host of location.hosts()) {
313
- for (const domain of host.foreignDomainNames) {
314
- const zone = {
315
- id: domain,
316
- file: `FOREIGN/${domain}.zone`,
317
- records: new Set([SOARecord, NSRecord])
318
- };
319
-
320
- const config = {
321
- name: `${domain}.zone.conf`,
322
- zones: [zone]
323
- };
324
- configs.push(config);
325
-
326
- if (this.hasLocationRecord) {
327
- zone.records.add(DNSRecord("location", "TXT", host.location.name));
328
- }
329
-
330
- for (const na of host.networkAddresses(
331
- na => na.networkInterface.kind != "loopback"
332
- )) {
333
- zone.records.add(
334
- DNSRecord("@", dnsRecordTypeForAddressFamily(na.family), na.address)
335
- );
336
- }
338
+ for (const source of sources) {
339
+ for (const host of source.hosts()) {
340
+ configs.push(...this.foreignDomainZones(host, this.defaultRecords));
337
341
  }
338
342
  }
339
343
 
@@ -343,139 +347,204 @@ export class BINDService extends ExtraSourceService {
343
347
  addHook(
344
348
  packageData.properties.hooks,
345
349
  "post_upgrade",
346
- `rm -f ${foreignZones.map(
347
- zone => `/var/lib/named/${zone.file}.jnl`
348
- )}\n` +
349
- `/usr/bin/named-hostname-info ${foreignZones
350
- .map(zone => zone.id)
351
- .join(" ")}|/usr/bin/named-hostname-update`
350
+ `/usr/bin/named-hostname-info ${foreignZones
351
+ .map(zone => zone.id)
352
+ .join(" ")}|/usr/bin/named-hostname-update`
352
353
  );
353
354
  }
354
355
 
355
- console.log(
356
- "LOCAL DOMAINS",
357
- location.localDomains,
358
- location.domain,
359
- location.toString()
360
- );
361
-
362
- for (const domain of location.localDomains) {
363
- const locationName = location.name;
364
- const reverseZones = new Map();
356
+ await this.writeZones(packageData, configs);
357
+ }
365
358
 
366
- const config = {
367
- name: `${domain}.zone.conf`,
368
- zones: []
369
- };
370
- configs.push(config);
359
+ async generateZoneDefs(sources, packageData) {
360
+ const configs = [];
371
361
 
372
- const locationRecord = DNSRecord("location", "TXT", locationName);
362
+ for (const source of sources) {
363
+ console.log(
364
+ "LOCAL DOMAINS",
365
+ source.localDomains,
366
+ source.domain,
367
+ source.toString()
368
+ );
373
369
 
374
- const zone = {
375
- id: domain,
376
- file: `${locationName}/${domain}.zone`,
377
- records: new Set([SOARecord, NSRecord, locationRecord])
378
- };
379
- config.zones.push(zone);
370
+ for (const domain of source.localDomains) {
371
+ const locationName = source.name;
372
+ const reverseZones = new Map();
380
373
 
381
- if (this.hasCatalog) {
382
- const catalogConfig = {
383
- name: `catalog.${domain}.zone.conf`,
374
+ const config = {
375
+ name: `${domain}.zone.conf`,
384
376
  zones: []
385
377
  };
386
- configs.push(catalogConfig);
387
-
388
- zone.catalogZone = {
389
- id: `catalog.${domain}`,
390
- file: `${locationName}/catalog.${domain}.zone`,
391
- records: new Set([
392
- SOARecord,
393
- NSRecord,
394
- DNSRecord(dnsFullName(`version.catalog.${domain}`), "TXT", '"1"')
395
- ])
378
+ configs.push(config);
379
+
380
+ const locationRecord = DNSRecord("location", "TXT", locationName);
381
+
382
+ const zone = {
383
+ id: domain,
384
+ file: `${locationName}/${domain}.zone`,
385
+ records: new Set([...this.defaultRecords, locationRecord])
396
386
  };
397
- catalogConfig.zones.push(zone.catalogZone);
398
- }
387
+ config.zones.push(zone);
388
+
389
+ if (this.hasCatalog) {
390
+ const catalogConfig = {
391
+ name: `catalog.${domain}.zone.conf`,
392
+ zones: []
393
+ };
394
+ configs.push(catalogConfig);
395
+
396
+ zone.catalogZone = {
397
+ id: `catalog.${domain}`,
398
+ file: `${locationName}/catalog.${domain}.zone`,
399
+ records: new Set([
400
+ ...this.defaultRecords,
401
+ DNSRecord(dnsFullName(`version.catalog.${domain}`), "TXT", '"1"')
402
+ ])
403
+ };
404
+ catalogConfig.zones.push(zone.catalogZone);
405
+ }
406
+
407
+ const hosts = new Set();
408
+ const addresses = new Set();
399
409
 
400
- const hosts = new Set();
401
- const addresses = new Set();
402
-
403
- for await (const {
404
- address,
405
- subnet,
406
- networkInterface,
407
- domainNames,
408
- family
409
- } of location.networkAddresses()) {
410
- if (
411
- !this.exclude.has(networkInterface.network) &&
412
- !this.excludeInterfaceKinds.has(networkInterface.kind)
413
- ) {
414
- const host = networkInterface.host;
410
+ for await (const {
411
+ address,
412
+ subnet,
413
+ networkInterface,
414
+ domainNames,
415
+ family
416
+ } of source.networkAddresses()) {
415
417
  if (
416
- !addresses.has(address) &&
417
- (this.hasLinkLocalAdresses || !isLinkLocal(address))
418
+ !this.exclude.has(networkInterface.network) &&
419
+ !this.excludeInterfaceKinds.has(networkInterface.kind)
418
420
  ) {
419
- addresses.add(address);
420
-
421
- for (const domainName of domainNames) {
422
- zone.records.add(
423
- DNSRecord(
424
- dnsFullName(domainName),
425
- dnsRecordTypeForAddressFamily(family),
426
- address
427
- )
428
- );
429
- }
430
- if (subnet && host.domain === domain) {
431
- let reverseZone = reverseZones.get(subnet.address);
432
-
433
- if (!reverseZone) {
434
- const id = reverseArpa(subnet.prefix);
435
- reverseZone = {
436
- id,
437
- type: "plain",
438
- file: `${locationName}/${id}.zone`,
439
- records: new Set([SOARecord, NSRecord])
440
- };
441
- config.zones.push(reverseZone);
442
- reverseZones.set(subnet.address, reverseZone);
421
+ const host = networkInterface.host;
422
+ if (host) {
423
+ if (
424
+ !addresses.has(address) &&
425
+ (this.hasLinkLocalAdresses || !isLinkLocal(address))
426
+ ) {
427
+ addresses.add(address);
428
+
429
+ for (const domainName of domainNames) {
430
+ zone.records.add(
431
+ DNSRecord(
432
+ dnsFullName(domainName),
433
+ dnsRecordTypeForAddressFamily(family),
434
+ address
435
+ )
436
+ );
437
+ }
438
+ if (subnet && host?.domain === domain) {
439
+ let reverseZone = reverseZones.get(subnet.address);
440
+
441
+ if (!reverseZone) {
442
+ const id = reverseArpa(subnet.prefix);
443
+ reverseZone = {
444
+ id,
445
+ type: "plain",
446
+ file: `${locationName}/${id}.zone`,
447
+ records: new Set(this.defaultRecords)
448
+ };
449
+ config.zones.push(reverseZone);
450
+ reverseZones.set(subnet.address, reverseZone);
451
+ }
452
+
453
+ for (const domainName of host.domainNames) {
454
+ reverseZone.records.add(
455
+ DNSRecord(
456
+ dnsFullName(reverseArpa(address)),
457
+ "PTR",
458
+ dnsFullName(domainName)
459
+ )
460
+ );
461
+ }
462
+ }
443
463
  }
444
464
 
445
- for (const domainName of host.domainNames) {
446
- reverseZone.records.add(
447
- DNSRecord(
448
- dnsFullName(reverseArpa(address)),
449
- "PTR",
450
- dnsFullName(domainName)
451
- )
452
- );
465
+ if (!hosts.has(host)) {
466
+ hosts.add(host);
467
+
468
+ for (const foreignDomainName of host.foreignDomainNames) {
469
+ zone.records.add(
470
+ DNSRecord(
471
+ "outfacing",
472
+ "PTR",
473
+ dnsFullName(foreignDomainName)
474
+ )
475
+ );
476
+ }
477
+
478
+ // console.log(host._services.map(s=>s.name));
479
+ for (const service of host._services) {
480
+ for (const record of service.dnsRecordsForDomainName(
481
+ host.domainName,
482
+ this.hasSVRRecords
483
+ )) {
484
+ //console.log("SERVICE",service.toString(),record.toString())
485
+
486
+ zone.records.add(record);
487
+ }
488
+ }
453
489
  }
454
490
  }
455
491
  }
492
+ }
493
+ }
494
+ }
456
495
 
457
- if (!hosts.has(host)) {
458
- hosts.add(host);
496
+ await this.writeZones(packageData, configs);
497
+ }
459
498
 
460
- for (const foreignDomainName of host.foreignDomainNames) {
461
- zone.records.add(
462
- DNSRecord("outfacing", "PTR", dnsFullName(foreignDomainName))
463
- );
464
- }
499
+ foreignDomainZones(host, records) {
500
+ return host.foreignDomainNames.map(domain => {
501
+ const zone = {
502
+ id: domain,
503
+ file: `FOREIGN/${domain}.zone`,
504
+ records: new Set(records)
505
+ };
506
+ const config = {
507
+ name: `${domain}.zone.conf`,
508
+ zones: [zone]
509
+ };
465
510
 
466
- for (const service of host.findServices()) {
467
- for (const record of service.dnsRecordsForDomainName(
468
- host.domainName,
469
- this.hasSVRRecords
470
- )) {
471
- zone.records.add(record);
472
- }
473
- }
474
- }
475
- }
511
+ if (this.hasLocationRecord) {
512
+ zone.records.add(DNSRecord("location", "TXT", host.location.name));
476
513
  }
477
- }
514
+ for (const na of host.networkAddresses(
515
+ na => na.networkInterface.kind != "loopback"
516
+ )) {
517
+ zone.records.add(
518
+ DNSRecord("@", dnsRecordTypeForAddressFamily(na.family), na.address)
519
+ );
520
+ }
521
+
522
+ return config;
523
+ });
524
+ }
525
+
526
+ get defaultRecords() {
527
+ const nameService = this.findService({ type: "dns", priority: "<10" });
528
+ const rname = this.administratorEmail.replace(/@/, ".");
529
+
530
+ const SOARecord = DNSRecord(
531
+ "@",
532
+ "SOA",
533
+ dnsFullName(nameService.domainName),
534
+ dnsFullName(rname),
535
+ `(${[...this.soaUpdates].join(" ")})`
536
+ );
537
+
538
+ const NSRecord = DNSRecord(
539
+ "@",
540
+ "NS",
541
+ dnsFullName(nameService.ipAddressOrDomainName)
542
+ );
543
+
544
+ return [SOARecord, NSRecord];
545
+ }
478
546
 
547
+ async writeZones(packageData, configs) {
479
548
  for (const config of configs) {
480
549
  console.log(`config: ${config.name}`);
481
550
 
@@ -519,7 +588,7 @@ export class BINDService extends ExtraSourceService {
519
588
  zone.file,
520
589
  [...zone.records]
521
590
  .sort(sortZoneRecords)
522
- .map(r => r.toString(maxKeyLength, ttl))
591
+ .map(r => r.toString(maxKeyLength, this.recordTTL))
523
592
  );
524
593
  }
525
594
 
@@ -5,7 +5,7 @@ export class SkeletonNetworkInterface extends ServiceOwner {
5
5
  set extends(value: any[]);
6
6
  get extends(): any[];
7
7
  get host(): Host;
8
- hosts(): Generator<any, void, any>;
8
+ hosts(): Generator<Host, void, unknown>;
9
9
  get network_interface(): this;
10
10
  get domainName(): any;
11
11
  get domainNames(): Set<any>;
@@ -254,6 +254,11 @@ export class BINDService extends ExtraSourceService {
254
254
  };
255
255
  priority: number;
256
256
  properties: {
257
+ addresses: {
258
+ type: string[];
259
+ collection: boolean;
260
+ writeable: boolean;
261
+ };
257
262
  trusted: {
258
263
  type: string[];
259
264
  collection: boolean;
@@ -353,6 +358,7 @@ export class BINDService extends ExtraSourceService {
353
358
  hasLinkLocalAdresses: boolean;
354
359
  hasLocationRecord: boolean;
355
360
  notify: boolean;
361
+ _addresses: any[];
356
362
  _trusted: any[];
357
363
  _protected: any[];
358
364
  _open: any[];
@@ -364,6 +370,8 @@ export class BINDService extends ExtraSourceService {
364
370
  expire: number;
365
371
  minimum: number;
366
372
  get soaUpdates(): number[];
373
+ set addresses(value: any[]);
374
+ get addresses(): any[];
367
375
  set protected(value: any[]);
368
376
  get protected(): any[];
369
377
  set trusted(value: any[]);
@@ -384,7 +392,16 @@ export class BINDService extends ExtraSourceService {
384
392
  access: string;
385
393
  };
386
394
  }, void, unknown>;
387
- generateZoneDefs(location: any, packageData: any): Promise<void>;
395
+ generateForeignDefs(sources: any, packageData: any): Promise<void>;
396
+ generateZoneDefs(sources: any, packageData: any): Promise<void>;
397
+ foreignDomainZones(host: any, records: any): any;
398
+ get defaultRecords(): {
399
+ type: any;
400
+ key: any;
401
+ values: any[];
402
+ toString: (maxKeyLength?: number, ttl?: string) => string;
403
+ }[];
404
+ writeZones(packageData: any, configs: any): Promise<void>;
388
405
  }
389
406
  import { ExtraSourceService } from "pmcf";
390
407
  import { FileContentProvider } from "npm-pkgbuild";