pmcf 6.63.1 → 6.64.1

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": "6.63.1",
3
+ "version": "6.64.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -55,7 +55,7 @@
55
55
  "filtered-map": "^1.0.0",
56
56
  "ip-utilties": "^3.13.1",
57
57
  "npm-pkgbuild": "^22.2.7",
58
- "pacc": "^11.17.4",
58
+ "pacc": "^11.17.5",
59
59
  "package-directory": "^8.2.0",
60
60
  "yaml": "^2.9.1"
61
61
  },
package/src/cluster.mjs CHANGED
@@ -1,39 +1,29 @@
1
+ import { duration_attribute_writable} from "pacc";
1
2
  import { host } from "./host.mjs";
3
+
2
4
  import { addType } from "./type.mjs";
3
- import {
4
- networkInterfaces_attribute,
5
- cluster_attribute
6
- } from "./common-attributes.mjs";
5
+ import { networkInterfaces_attribute } from "./common-attributes.mjs";
7
6
 
8
7
  export class cluster extends host {
9
8
  static priority = 1.5;
10
9
  static attributes = {
11
- masters: {
12
- ...networkInterfaces_attribute,
13
- name: "masters",
14
- backpointer: cluster_attribute
15
- },
16
- backups: {
17
- ...networkInterfaces_attribute,
18
- name: "backups",
19
- backpointer: cluster_attribute
20
- },
21
10
  members: {
22
11
  ...networkInterfaces_attribute,
23
12
  name: "members"
24
- }
13
+ },
14
+ checkInterval: {
15
+ ...duration_attribute_writable,
16
+ name: "checkInterval",
17
+ default: 60
18
+ },
19
+
25
20
  };
26
21
 
27
22
  static {
28
23
  addType(this);
29
24
  }
30
25
 
31
- masters = [];
32
- backups = [];
33
-
34
- get members() {
35
- return new Set(this.masters).union(new Set(this.backups));
36
- }
26
+ members = new Set();
37
27
 
38
28
  get isCluster() {
39
29
  return true;
package/src/module.mjs CHANGED
@@ -6,7 +6,6 @@ export * from "./common-attributes.mjs";
6
6
  export * from "./base.mjs";
7
7
  export * from "./credential.mjs";
8
8
  export * from "./cluster.mjs";
9
- export * from "./keepalived.mjs";
10
9
 
11
10
  export * from "./owner.mjs";
12
11
  export * from "./site.mjs";
@@ -28,6 +27,7 @@ export * from "./core-service.mjs";
28
27
  export * from "./service.mjs";
29
28
  export * from "./extra-source-service.mjs";
30
29
  export * from "./endpoint.mjs";
30
+
31
31
  export * from "./services/bind.mjs";
32
32
  export * from "./services/chrony.mjs";
33
33
  export * from "./services/kea.mjs";
@@ -43,4 +43,6 @@ export * from "./services/systemd-journal-remote.mjs";
43
43
  export * from "./services/systemd-journal-upload.mjs";
44
44
  export * from "./services/systemd-timesyncd.mjs";
45
45
  export * from "./services/systemd-resolved.mjs";
46
+ export * from "./services/keepalived.mjs";
47
+
46
48
  export * from "./initialization-context.mjs";
@@ -0,0 +1,244 @@
1
+ import { join } from "node:path";
2
+ import {
3
+ default_attribute_writable,
4
+ default_collection_attribute_writable,
5
+ enum_string_attribute_writable
6
+ } from "pacc";
7
+ import { FAMILY_IPV4 } from "ip-utilties";
8
+ import { addType } from "../type.mjs";
9
+ import { core } from "../core.mjs";
10
+ import { credential } from "../credential.mjs";
11
+ import { CoreService, serviceEndpoints } from "../core-service.mjs";
12
+ import { PROTOCOL_TCP } from "../constants.mjs";
13
+
14
+ import { writeLines } from "../utils.mjs";
15
+
16
+ export class keepalive_cluster_member extends core {
17
+ static attributes = {
18
+ cluster: {
19
+ ...default_attribute_writable,
20
+ type: "cluster",
21
+ name: "cluster"
22
+ },
23
+ role: {
24
+ ...enum_string_attribute_writable,
25
+ name: "role",
26
+ values: new Set(["master", "backup"])
27
+ }
28
+ };
29
+ static key = "cluster";
30
+ static {
31
+ addType(this);
32
+ }
33
+
34
+ get fullName() {
35
+ return this.cluster?.fullName;
36
+ }
37
+
38
+ set cluster(value) {
39
+ this._cluster = value;
40
+ value.members.add(this);
41
+ }
42
+
43
+ get cluster() {
44
+ return this._cluster;
45
+ }
46
+
47
+ get host() {
48
+ return this.owner.host;
49
+ }
50
+
51
+ get address() {
52
+ return this.owner.owner.address;
53
+ }
54
+ }
55
+
56
+ export class keepalived extends CoreService {
57
+ static priority = 1.5;
58
+ static attributes = {
59
+ clusters: {
60
+ ...default_collection_attribute_writable,
61
+ type: keepalive_cluster_member,
62
+ name: "clusters"
63
+ }
64
+ };
65
+
66
+ static {
67
+ addType(this);
68
+ }
69
+
70
+ clusters = new Map();
71
+ checkInterval = 60;
72
+
73
+ async *preparePackages(dir) {
74
+ const packageData = await this.preparePackage(dir);
75
+
76
+ for (const clusterMember of this.clusters.values()) {
77
+ const cluster = clusterMember.cluster;
78
+ const host = cluster.host;
79
+
80
+ const extra = [];
81
+
82
+ const smtp = this.smtp;
83
+
84
+ if (smtp) {
85
+ extra.push(` smtp_server ${smtp.address()}`);
86
+ }
87
+
88
+ const cfg = [
89
+ "global_defs {",
90
+ " notification_email {",
91
+ " " + this.administratorEmail,
92
+ " }",
93
+ ...extra,
94
+ ` notification_email_from keepalived@${host.domainName}`,
95
+ " enable_script_security",
96
+ " script_user root",
97
+ " max_auto_priority 20",
98
+ "}",
99
+ ""
100
+ ];
101
+
102
+ const clusterName = cluster.name;
103
+ cfg.push(`vrrp_instance ${clusterName} {`);
104
+ cfg.push(` state ${clusterMember.role.toUpperCase()}`);
105
+
106
+ const ni = clusterMember.owner.owner;
107
+
108
+ cfg.push(` interface ${ni.name}`);
109
+
110
+ for (const na of cluster.networkAddresses(
111
+ na => na.networkInterface.kind !== "loopback"
112
+ )) {
113
+ cfg.push(
114
+ ` ${
115
+ na.family === FAMILY_IPV4
116
+ ? "virtual_ipaddress"
117
+ : "virtual_ipaddress_excluded"
118
+ } {`
119
+ );
120
+ cfg.push(` ${na.cidrAddress} dev ${ni.name} label ${clusterName}`);
121
+ cfg.push(" }");
122
+ }
123
+
124
+ cfg.push(` virtual_router_id ${cluster.id}`);
125
+
126
+ let reducedPrio = 0;
127
+ /*
128
+ let reducedPrio = cluster.masters.indexOf(ni);
129
+ if (reducedPrio < 0) {
130
+ reducedPrio = cluster.backups.indexOf(ni) + 5;
131
+ }
132
+ */
133
+ const cred = new credential(this);
134
+ cred.name = `keepalived.${clusterName}.password`;
135
+ cred.localName = clusterName.toUpperCase() + "_PASSWORD";
136
+ cred._tags.add("keepalived.service");
137
+ this.credentials.set(cred.name, cred);
138
+
139
+ cfg.push(` priority ${host.priority - reducedPrio}`);
140
+ cfg.push(" smtp_alert");
141
+ cfg.push(" advert_int 5");
142
+ cfg.push(" authentication {");
143
+ cfg.push(" auth_type PASS");
144
+ cfg.push(" auth_pass pass1234");
145
+ cfg.push(" # auth_pass ${_ENV " + cred.localName + "}");
146
+ cfg.push(" # auth_pass ${" + cred.localName + "}");
147
+ cfg.push(" }");
148
+
149
+ cfg.push(
150
+ ` notify_master "/usr/bin/systemctl start ${clusterName}-master.target"`,
151
+ ` notify_backup "/usr/bin/systemctl start ${clusterName}-backup.target"`,
152
+ ` notify_fault "/usr/bin/systemctl start ${clusterName}-fault.target"`
153
+ );
154
+
155
+ cfg.push("}", "");
156
+
157
+ for (const endpoint of serviceEndpoints(cluster, {
158
+ services: "services[types[http]]",
159
+ endpoints: e =>
160
+ e.networkInterface && e.networkInterface.kind !== "loopback"
161
+ })) {
162
+ cfg.push(`virtual_server ${cluster.address} ${endpoint.port} {`);
163
+ cfg.push(` delay_loop ${cluster.checkInterval}`);
164
+ cfg.push(" lb_algo wlc");
165
+ cfg.push(" persistence_timeout 600");
166
+ cfg.push(` protocol ${endpoint.protocol.toUpperCase()}`);
167
+
168
+ for (const member of cluster.members) {
169
+ const memberService = member.host.expression(
170
+ `services[types[${endpoint.type}]][0]`
171
+ );
172
+
173
+ console.log(member.fullName, endpoint.type, memberService?.fullName);
174
+ cfg.push(` real_server ${member.address} ${memberService.port} {`);
175
+ cfg.push(` weight ${memberService.weight}`);
176
+
177
+ switch (endpoint.type) {
178
+ case "dns":
179
+ cfg.push(` DNS_CHECK {`);
180
+ cfg.push(" type A");
181
+ cfg.push(" name google.com");
182
+ cfg.push(" }");
183
+ break;
184
+ case "smtp":
185
+ cfg.push(` SMTP_CHECK {`);
186
+ cfg.push(" }");
187
+ break;
188
+
189
+ default:
190
+ switch (endpoint.protocol) {
191
+ case PROTOCOL_TCP:
192
+ cfg.push(` TCP_CHECK {`);
193
+ cfg.push(" connect_timeout 10");
194
+ cfg.push(" }");
195
+ break;
196
+ }
197
+ }
198
+
199
+ cfg.push(" }");
200
+ }
201
+
202
+ cfg.push("}", "");
203
+ break; // only one for now
204
+ }
205
+ await writeLines(
206
+ join(dir, "/usr/lib/systemd/system"),
207
+ `${clusterName}-master.target`,
208
+ [
209
+ "[Unit]",
210
+ `Description=master state of cluster ${clusterName}`,
211
+ "PartOf=keepalived.service",
212
+ `Conflicts=${clusterName}-backup.target ${clusterName}-fault.target`
213
+ ]
214
+ );
215
+
216
+ await writeLines(
217
+ join(dir, "/usr/lib/systemd/system"),
218
+ `${clusterName}-backup.target`,
219
+ [
220
+ "[Unit]",
221
+ `Description=backup state of cluster ${clusterName}`,
222
+ "PartOf=keepalived.service",
223
+ `Conflicts=${clusterName}-master.target ${clusterName}-fault.target`
224
+ ]
225
+ );
226
+
227
+ await writeLines(
228
+ join(dir, "/usr/lib/systemd/system"),
229
+ `${clusterName}-fault.target`,
230
+ [
231
+ "[Unit]",
232
+ `Description=fault state of cluster ${clusterName}`,
233
+ `Conflicts=${clusterName}-master.target ${clusterName}-backup.target`
234
+ ]
235
+ );
236
+
237
+ await this.writeSystemdCredentialConfig(dir, "keepalived.service");
238
+
239
+ await writeLines(join(dir, "etc/keepalived"), "keepalived.conf", cfg);
240
+ }
241
+
242
+ yield packageData;
243
+ }
244
+ }
@@ -1,214 +0,0 @@
1
- import { join } from "node:path";
2
- import { duration_attribute_writable } from "pacc";
3
- import { addType } from "./type.mjs";
4
- import { cluster } from "./cluster.mjs";
5
- import { credential } from "./credential.mjs";
6
- import { FAMILY_IPV4 } from "ip-utilties";
7
- import { serviceEndpoints } from "./core-service.mjs";
8
- import { PROTOCOL_TCP } from "./constants.mjs";
9
- import { credentials_attribute } from "./common-attributes.mjs";
10
-
11
- import { writeLines } from "./utils.mjs";
12
-
13
- export class keepalived extends cluster {
14
- static priority = 1.5;
15
- static attributes = {
16
- checkInterval: {
17
- ...duration_attribute_writable,
18
- name: "checkInterval",
19
- default: 60
20
- },
21
- credentials: credentials_attribute
22
- };
23
-
24
- static {
25
- addType(this);
26
- }
27
-
28
- checkInterval = 60;
29
- credentials = new Map();
30
-
31
- async *preparePackages(stagingDir) {
32
- for (const ni of [...this.owner.clusters.values()].reduce(
33
- (all, cluster) => all.union(cluster.members),
34
- new Set()
35
- )) {
36
- const host = ni.host;
37
-
38
- const packageStagingDir = join(stagingDir, host.name);
39
- const packageData = await host.preparePackage({ dir: packageStagingDir });
40
-
41
- const extra = [];
42
-
43
- const smtp = this.smtp;
44
-
45
- if (smtp) {
46
- extra.push(` smtp_server ${smtp.address()}`);
47
- }
48
-
49
- const cfg = [
50
- "global_defs {",
51
- " notification_email {",
52
- " " + this.administratorEmail,
53
- " }",
54
- ...extra,
55
- ` notification_email_from keepalived@${host.domainName}`,
56
- " enable_script_security",
57
- " script_user root",
58
- " max_auto_priority 20",
59
- "}",
60
- ""
61
- ];
62
-
63
- for (const cluster of [...this.owner.clusters.values()].sort((a, b) =>
64
- a.name.localeCompare(b.name)
65
- )) {
66
- const name = cluster.name;
67
- cfg.push(`vrrp_instance ${name} {`);
68
- cfg.push(
69
- ` state ${cluster.masters.indexOf(ni) === 0 ? "MASTER" : "BACKUP"}`
70
- );
71
- cfg.push(` interface ${ni.name}`);
72
-
73
- for (const na of cluster.networkAddresses(
74
- na => na.networkInterface.kind !== "loopback"
75
- )) {
76
- cfg.push(
77
- ` ${
78
- na.family === FAMILY_IPV4
79
- ? "virtual_ipaddress"
80
- : "virtual_ipaddress_excluded"
81
- } {`
82
- );
83
- cfg.push(` ${na.cidrAddress} dev ${ni.name} label ${name}`);
84
- cfg.push(" }");
85
- }
86
-
87
- cfg.push(` virtual_router_id ${cluster.id}`);
88
-
89
- let reducedPrio = cluster.masters.indexOf(ni);
90
- if (reducedPrio < 0) {
91
- reducedPrio = cluster.backups.indexOf(ni) + 5;
92
- }
93
-
94
- const cred = new credential(this);
95
- cred.name = `keepalived.${name}.password`;
96
- cred.localName = name.toUpperCase() + "_PASSWORD";
97
- cred._tags.add("keepalived.service");
98
- this.credentials.set(cred.name, cred);
99
-
100
- cfg.push(` priority ${host.priority - reducedPrio}`);
101
- cfg.push(" smtp_alert");
102
- cfg.push(" advert_int 5");
103
- cfg.push(" authentication {");
104
- cfg.push(" auth_type PASS");
105
- cfg.push(" auth_pass pass1234");
106
- cfg.push(" # auth_pass ${_ENV " + cred.localName + "}");
107
- cfg.push(" # auth_pass ${" + cred.localName + "}");
108
- cfg.push(" }");
109
-
110
- cfg.push(
111
- ` notify_master "/usr/bin/systemctl start ${name}-master.target"`,
112
- ` notify_backup "/usr/bin/systemctl start ${name}-backup.target"`,
113
- ` notify_fault "/usr/bin/systemctl start ${name}-fault.target"`
114
- );
115
-
116
- cfg.push("}", "");
117
-
118
- for (const endpoint of serviceEndpoints(cluster, {
119
- services: "services[types[http]]",
120
- endpoints: e =>
121
- e.networkInterface && e.networkInterface.kind !== "loopback"
122
- })) {
123
- cfg.push(`virtual_server ${cluster.address} ${endpoint.port} {`);
124
- cfg.push(` delay_loop ${cluster.checkInterval}`);
125
- cfg.push(" lb_algo wlc");
126
- cfg.push(" persistence_timeout 600");
127
- cfg.push(` protocol ${endpoint.protocol.toUpperCase()}`);
128
-
129
- for (const member of this.members) {
130
- const memberService = member.expression(
131
- `services[types[${endpoint.type}]][0]`
132
- );
133
-
134
- console.log(
135
- member.fullName,
136
- endpoint.type,
137
- memberService?.fullName
138
- );
139
- cfg.push(` real_server ${member.address} ${memberService.port} {`);
140
- cfg.push(` weight ${memberService.weight}`);
141
-
142
- switch (endpoint.type) {
143
- case "dns":
144
- cfg.push(` DNS_CHECK {`);
145
- cfg.push(" type A");
146
- cfg.push(" name google.com");
147
- cfg.push(" }");
148
- break;
149
- case "smtp":
150
- cfg.push(` SMTP_CHECK {`);
151
- cfg.push(" }");
152
- break;
153
-
154
- default:
155
- switch (endpoint.protocol) {
156
- case PROTOCOL_TCP:
157
- cfg.push(` TCP_CHECK {`);
158
- cfg.push(" connect_timeout 10");
159
- cfg.push(" }");
160
- break;
161
- }
162
- }
163
-
164
- cfg.push(" }");
165
- }
166
-
167
- cfg.push("}", "");
168
- break; // only one for now
169
- }
170
- await writeLines(
171
- join(packageStagingDir, "/usr/lib/systemd/system"),
172
- `${name}-master.target`,
173
- [
174
- "[Unit]",
175
- `Description=master state of cluster ${name}`,
176
- "PartOf=keepalived.service",
177
- `Conflicts=${name}-backup.target ${name}-fault.target`
178
- ]
179
- );
180
-
181
- await writeLines(
182
- join(packageStagingDir, "/usr/lib/systemd/system"),
183
- `${name}-backup.target`,
184
- [
185
- "[Unit]",
186
- `Description=backup state of cluster ${name}`,
187
- "PartOf=keepalived.service",
188
- `Conflicts=${name}-master.target ${name}-fault.target`
189
- ]
190
- );
191
-
192
- await writeLines(
193
- join(packageStagingDir, "/usr/lib/systemd/system"),
194
- `${name}-fault.target`,
195
- [
196
- "[Unit]",
197
- `Description=fault state of cluster ${name}`,
198
- `Conflicts=${name}-master.target ${name}-backup.target`
199
- ]
200
- );
201
-
202
- await this.writeSystemdCredentialConfig(packageStagingDir, "keepalived.service");
203
- }
204
-
205
- await writeLines(
206
- join(packageStagingDir, "etc/keepalived"),
207
- "keepalived.conf",
208
- cfg
209
- );
210
-
211
- yield packageData;
212
- }
213
- }
214
- }