@kronos-integration/service-systemd 2.5.2
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/LICENSE +23 -0
- package/README.md +107 -0
- package/package.json +69 -0
- package/src/service.mjs +213 -0
- package/systemd-linux-arm64.node +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (c) 2019-2021 by Kronos-Integration
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
15
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
16
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
17
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
18
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
19
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
20
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
21
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
22
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
23
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
[](https://www.npmjs.com/package/@kronos-integration/service-systemd)
|
|
2
|
+
[](https://opensource.org/licenses/BSD-3-Clause)
|
|
3
|
+
[](https://bundlephobia.com/result?p=@kronos-integration/service-systemd)
|
|
4
|
+
[](https://npmjs.org/package/@kronos-integration/service-systemd)
|
|
5
|
+
[](https://github.com/Kronos-Integration/service-systemd/issues)
|
|
6
|
+
[](https://actions-badge.atrox.dev/Kronos-Integration/service-systemd/goto)
|
|
7
|
+
[](https://github.com/prettier/prettier)
|
|
8
|
+
[](http://commitizen.github.io/cz-cli/)
|
|
9
|
+
[](https://snyk.io/test/github/Kronos-Integration/service-systemd)
|
|
10
|
+
[](https://coveralls.io/github/Kronos-Integration/service-systemd)
|
|
11
|
+
|
|
12
|
+
# @kronos-integration/service-systemd
|
|
13
|
+
|
|
14
|
+
kronos systemd integration
|
|
15
|
+
|
|
16
|
+
* sync node state to systemd with notify (done)
|
|
17
|
+
* propagate config into kronos (done)
|
|
18
|
+
* propagate socket activations into kronos (partly)
|
|
19
|
+
* start / stop / restart / reload initiated from systemd (partly)
|
|
20
|
+
* log into journal (done)
|
|
21
|
+
|
|
22
|
+
# usage
|
|
23
|
+
|
|
24
|
+
# API
|
|
25
|
+
|
|
26
|
+
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
|
27
|
+
|
|
28
|
+
### Table of Contents
|
|
29
|
+
|
|
30
|
+
* [JournalLogger](#journallogger)
|
|
31
|
+
* [FileDescriptor](#filedescriptor)
|
|
32
|
+
* [Properties](#properties)
|
|
33
|
+
* [SystemdConfig](#systemdconfig)
|
|
34
|
+
* [Properties](#properties-1)
|
|
35
|
+
* [listeningFileDescriptors](#listeningfiledescriptors)
|
|
36
|
+
* [loadConfig](#loadconfig)
|
|
37
|
+
* [ServiceSystemd](#servicesystemd)
|
|
38
|
+
* [endpoints](#endpoints)
|
|
39
|
+
|
|
40
|
+
## JournalLogger
|
|
41
|
+
|
|
42
|
+
**Extends ServiceLogger**
|
|
43
|
+
|
|
44
|
+
Forward logs entries to the journal.
|
|
45
|
+
|
|
46
|
+
## FileDescriptor
|
|
47
|
+
|
|
48
|
+
Type: [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)
|
|
49
|
+
|
|
50
|
+
### Properties
|
|
51
|
+
|
|
52
|
+
* `name` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?**
|
|
53
|
+
* `fd` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)**
|
|
54
|
+
|
|
55
|
+
## SystemdConfig
|
|
56
|
+
|
|
57
|
+
**Extends ServiceConfig**
|
|
58
|
+
|
|
59
|
+
Provides config from CONFIGURATION_DIRECTORY.
|
|
60
|
+
Also injects listeningFileDescriptors into the config
|
|
61
|
+
|
|
62
|
+
### Properties
|
|
63
|
+
|
|
64
|
+
* `configurationDirectory` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** taken from CONFIGURATION_DIRECTORY
|
|
65
|
+
|
|
66
|
+
### listeningFileDescriptors
|
|
67
|
+
|
|
68
|
+
listeningFileDescriptors as passed in LISTEN_FDS and LISTEN_FDNAMES.
|
|
69
|
+
|
|
70
|
+
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[FileDescriptor](#filedescriptor)>**
|
|
71
|
+
|
|
72
|
+
### loadConfig
|
|
73
|
+
|
|
74
|
+
Load config from configuration dir.
|
|
75
|
+
Additionally pass listeninfFileDescriptions into config.
|
|
76
|
+
|
|
77
|
+
## ServiceSystemd
|
|
78
|
+
|
|
79
|
+
**Extends ServiceProviderMixin(Service, JournalLogger, SystemdConfig)**
|
|
80
|
+
|
|
81
|
+
Kronos bridge to systemd:
|
|
82
|
+
|
|
83
|
+
* sync node state to systemd with notify
|
|
84
|
+
* propagate config into kronos world
|
|
85
|
+
* propagate socket activations into kronos (partly)
|
|
86
|
+
* start / stop / restart / reload initiated from systemd
|
|
87
|
+
* log into journal
|
|
88
|
+
|
|
89
|
+
### endpoints
|
|
90
|
+
|
|
91
|
+
Definition of the predefined endpoints.
|
|
92
|
+
|
|
93
|
+
* info *in*
|
|
94
|
+
|
|
95
|
+
Returns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** predefined endpoints
|
|
96
|
+
|
|
97
|
+
# install
|
|
98
|
+
|
|
99
|
+
With [npm](http://npmjs.org) do:
|
|
100
|
+
|
|
101
|
+
```shell
|
|
102
|
+
npm install @kronos-integration/service-systemd
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
# license
|
|
106
|
+
|
|
107
|
+
BSD-2-Clause
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kronos-integration/service-systemd",
|
|
3
|
+
"version": "2.5.2",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/service.mjs"
|
|
10
|
+
},
|
|
11
|
+
"description": "kronos systemd integration",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"journal",
|
|
14
|
+
"kronos-service",
|
|
15
|
+
"notify",
|
|
16
|
+
"systemd"
|
|
17
|
+
],
|
|
18
|
+
"contributors": [
|
|
19
|
+
{
|
|
20
|
+
"name": "Markus Felten",
|
|
21
|
+
"email": "markus.felten@gmx.de"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"license": "BSD-2-Clause",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "npm run test:ava",
|
|
27
|
+
"test:ava": "ava --timeout 2m tests/*.mjs",
|
|
28
|
+
"cover": "c8 -x 'tests/**/*' --temp-directory build/tmp ava --timeout 2m tests/*.mjs && c8 report -r lcov -o build/coverage --temp-directory build/tmp",
|
|
29
|
+
"docs": "documentation readme --section=API ./src/**/*.mjs",
|
|
30
|
+
"lint": "npm run lint:docs",
|
|
31
|
+
"lint:docs": "documentation lint ./src/**/*.mjs",
|
|
32
|
+
"build": "cmake-js compile"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@kronos-integration/service": "^10.4.7",
|
|
36
|
+
"config-expander": "^12.0.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"ava": "^3.15.0",
|
|
40
|
+
"c8": "^7.9.0",
|
|
41
|
+
"cmake-js": "^6.2.1",
|
|
42
|
+
"documentation": "^13.2.5",
|
|
43
|
+
"execa": "^5.1.1",
|
|
44
|
+
"node-addon-api": "^4.0.0",
|
|
45
|
+
"semantic-release": "^18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=16.10.0"
|
|
49
|
+
},
|
|
50
|
+
"os": [
|
|
51
|
+
"linux"
|
|
52
|
+
],
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "https://github.com/Kronos-Integration/service-systemd.git"
|
|
56
|
+
},
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/Kronos-Integration/service-systemd/issues"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://github.com/Kronos-Integration/service-systemd#readme",
|
|
61
|
+
"native": "${dirname}/${basename}-${os}-${arch}.node",
|
|
62
|
+
"template": {
|
|
63
|
+
"inheritFrom": [
|
|
64
|
+
"arlac77/template-arlac77-github",
|
|
65
|
+
"arlac77/template-cmake",
|
|
66
|
+
"arlac77/template-kronos-component"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/service.mjs
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { expand } from "config-expander";
|
|
2
|
+
import {
|
|
3
|
+
ServiceProviderMixin,
|
|
4
|
+
Service,
|
|
5
|
+
ServiceLogger,
|
|
6
|
+
ServiceConfig
|
|
7
|
+
} from "@kronos-integration/service";
|
|
8
|
+
import { Module } from "module";
|
|
9
|
+
import { arch, constants } from "os";
|
|
10
|
+
|
|
11
|
+
const filename = new URL(`../systemd-linux-${arch()}.node`, import.meta.url)
|
|
12
|
+
.pathname;
|
|
13
|
+
const m = new Module(filename);
|
|
14
|
+
m.filename = filename;
|
|
15
|
+
process.dlopen(m, filename, constants.dlopen.RTLD_NOW);
|
|
16
|
+
const {
|
|
17
|
+
LISTEN_FDS_START,
|
|
18
|
+
notify_with_fds,
|
|
19
|
+
notify,
|
|
20
|
+
journal_print_object
|
|
21
|
+
} = m.exports;
|
|
22
|
+
|
|
23
|
+
export { notify, notify_with_fds, journal_print_object };
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Forward logs entries to the journal.
|
|
27
|
+
*/
|
|
28
|
+
class JournalLogger extends ServiceLogger {
|
|
29
|
+
static get name() {
|
|
30
|
+
return "systemd-logger";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static get description() {
|
|
34
|
+
return "Forward log entries into systemd journal";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
logEntry(entry) {
|
|
38
|
+
journal_print_object(entry);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
* @typedef {Object} FileDescriptor
|
|
45
|
+
* @property {string?} name
|
|
46
|
+
* @property {number} fd
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Provides config from CONFIGURATION_DIRECTORY.
|
|
51
|
+
* Also injects listeningFileDescriptors into the config
|
|
52
|
+
* @property {string} configurationDirectory taken from CONFIGURATION_DIRECTORY
|
|
53
|
+
*/
|
|
54
|
+
class SystemdConfig extends ServiceConfig {
|
|
55
|
+
static get name() {
|
|
56
|
+
return "systemd-config";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static get description() {
|
|
60
|
+
return "Synchronize configuration with systemd";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
configurationDirectory = process.env.CONFIGURATION_DIRECTORY;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* listeningFileDescriptors as passed in LISTEN_FDS and LISTEN_FDNAMES.
|
|
67
|
+
* @return {FileDescriptor[]}
|
|
68
|
+
*/
|
|
69
|
+
get listeningFileDescriptors() {
|
|
70
|
+
const count = Number(process.env.LISTEN_FDS) || 0;
|
|
71
|
+
const fdNames = (process.env.LISTEN_FDNAMES || "").split(":");
|
|
72
|
+
const arr = new Array(count);
|
|
73
|
+
for (let i = 0; i < count; i++) {
|
|
74
|
+
arr[i] = {
|
|
75
|
+
fd: LISTEN_FDS_START + i
|
|
76
|
+
};
|
|
77
|
+
if (fdNames[i]) {
|
|
78
|
+
arr[i].name = fdNames[i];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
this.trace(`listeningFileDescriptors ${JSON.stringify(arr)}`);
|
|
82
|
+
return arr;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Load config from configuration dir.
|
|
87
|
+
* Additionally pass listeninfFileDescriptions into config.
|
|
88
|
+
*/
|
|
89
|
+
async loadConfig() {
|
|
90
|
+
notify("RELOADING=1");
|
|
91
|
+
if (this.configurationDirectory) {
|
|
92
|
+
this.trace(`load: ${this.configurationDirectory}/config.json`);
|
|
93
|
+
await this.configure(
|
|
94
|
+
await expand("${include('config.json')}", {
|
|
95
|
+
constants: {
|
|
96
|
+
basedir: this.configurationDirectory
|
|
97
|
+
},
|
|
98
|
+
default: {}
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
for (const listener of this.listeningFileDescriptors) {
|
|
104
|
+
if (listener.name === undefined) {
|
|
105
|
+
this.warn(`listener without name ${JSON.stringify(listener)}`);
|
|
106
|
+
} else {
|
|
107
|
+
await this.configureValue(listener.name, listener);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async _stop() {
|
|
113
|
+
const lfd = this.listeningFileDescriptors;
|
|
114
|
+
const state = "FDSTORE=1" + lfd.map(l => `\nFDNAME=${l.name}`).join("");
|
|
115
|
+
const rc = notify_with_fds(state, lfd.map(l => l.fd));
|
|
116
|
+
this.info(`${state} (${rc})`);
|
|
117
|
+
|
|
118
|
+
return super._stop();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async _start() {
|
|
122
|
+
await super._start();
|
|
123
|
+
|
|
124
|
+
process.on("SIGHUP", async () => {
|
|
125
|
+
await this.loadConfig();
|
|
126
|
+
notify("READY=1");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
await this.loadConfig();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Kronos bridge to systemd:
|
|
135
|
+
* - sync node state to systemd with notify
|
|
136
|
+
* - propagate config into kronos world
|
|
137
|
+
* - propagate socket activations into kronos (partly)
|
|
138
|
+
* - start / stop / restart / reload initiated from systemd
|
|
139
|
+
* - log into journal
|
|
140
|
+
*/
|
|
141
|
+
export class ServiceSystemd extends ServiceProviderMixin(
|
|
142
|
+
Service,
|
|
143
|
+
JournalLogger,
|
|
144
|
+
SystemdConfig
|
|
145
|
+
) {
|
|
146
|
+
static get name() {
|
|
147
|
+
return "systemd";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static get description() {
|
|
151
|
+
return "Bridge to systemd";
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
get autostart() {
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Definition of the predefined endpoints.
|
|
160
|
+
* - info _in_
|
|
161
|
+
* @return {Object} predefined endpoints
|
|
162
|
+
*/
|
|
163
|
+
static get endpoints() {
|
|
164
|
+
return {
|
|
165
|
+
...super.endpoints,
|
|
166
|
+
info: {
|
|
167
|
+
in: true,
|
|
168
|
+
receive: "info"
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async _start() {
|
|
174
|
+
process.on("warning", warning => this.warn(warning));
|
|
175
|
+
process.on("SIGINT", () => {
|
|
176
|
+
this.info("SIGINT");
|
|
177
|
+
this.stop();
|
|
178
|
+
});
|
|
179
|
+
process.on("SIGTERM", async () => {
|
|
180
|
+
await this.stop();
|
|
181
|
+
process.exit(0);
|
|
182
|
+
});
|
|
183
|
+
process.on("beforeExit", code => this.stop());
|
|
184
|
+
process.on("exit", code => this.stop());
|
|
185
|
+
return super._start();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
stateChanged(oldState, newState) {
|
|
189
|
+
super.stateChanged(oldState, newState);
|
|
190
|
+
switch (newState) {
|
|
191
|
+
case "running":
|
|
192
|
+
notify("READY=1");
|
|
193
|
+
break;
|
|
194
|
+
|
|
195
|
+
case "stopping":
|
|
196
|
+
notify("STOPPING=1");
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
info()
|
|
202
|
+
{
|
|
203
|
+
return this.toJSONWithOptions({
|
|
204
|
+
includeRuntimeInfo: true,
|
|
205
|
+
includeDefaults: true,
|
|
206
|
+
includeName: true,
|
|
207
|
+
includeConfig: false,
|
|
208
|
+
includePrivate: false
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export default ServiceSystemd;
|
|
Binary file
|