@katmer/core 0.0.3
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/README.md +1 -0
- package/cli/katmer.js +28 -0
- package/cli/run.ts +16 -0
- package/index.ts +5 -0
- package/lib/config.ts +82 -0
- package/lib/interfaces/config.interface.ts +113 -0
- package/lib/interfaces/executor.interface.ts +13 -0
- package/lib/interfaces/module.interface.ts +170 -0
- package/lib/interfaces/provider.interface.ts +214 -0
- package/lib/interfaces/task.interface.ts +100 -0
- package/lib/katmer.ts +126 -0
- package/lib/lookup/env.lookup.ts +13 -0
- package/lib/lookup/file.lookup.ts +23 -0
- package/lib/lookup/index.ts +46 -0
- package/lib/lookup/url.lookup.ts +21 -0
- package/lib/lookup/var.lookup.ts +13 -0
- package/lib/module.ts +560 -0
- package/lib/module_registry.ts +64 -0
- package/lib/modules/apt-repository/apt-repository.module.ts +435 -0
- package/lib/modules/apt-repository/apt-sources-list.ts +363 -0
- package/lib/modules/apt.module.ts +546 -0
- package/lib/modules/archive.module.ts +280 -0
- package/lib/modules/become.module.ts +119 -0
- package/lib/modules/copy.module.ts +807 -0
- package/lib/modules/cron.module.ts +541 -0
- package/lib/modules/debug.module.ts +231 -0
- package/lib/modules/gather_facts.module.ts +605 -0
- package/lib/modules/git.module.ts +243 -0
- package/lib/modules/hostname.module.ts +213 -0
- package/lib/modules/http/http.curl.module.ts +342 -0
- package/lib/modules/http/http.local.module.ts +253 -0
- package/lib/modules/http/http.module.ts +298 -0
- package/lib/modules/index.ts +14 -0
- package/lib/modules/package.module.ts +283 -0
- package/lib/modules/script.module.ts +121 -0
- package/lib/modules/set_fact.module.ts +171 -0
- package/lib/modules/systemd_service.module.ts +373 -0
- package/lib/modules/template.module.ts +478 -0
- package/lib/providers/local.provider.ts +336 -0
- package/lib/providers/provider_response.ts +20 -0
- package/lib/providers/ssh/ssh.provider.ts +420 -0
- package/lib/providers/ssh/ssh.utils.ts +31 -0
- package/lib/schemas/katmer_config.schema.json +358 -0
- package/lib/target_resolver.ts +298 -0
- package/lib/task/controls/environment.control.ts +42 -0
- package/lib/task/controls/index.ts +13 -0
- package/lib/task/controls/loop.control.ts +89 -0
- package/lib/task/controls/register.control.ts +23 -0
- package/lib/task/controls/until.control.ts +64 -0
- package/lib/task/controls/when.control.ts +25 -0
- package/lib/task/task.ts +225 -0
- package/lib/utils/ajv.utils.ts +24 -0
- package/lib/utils/cls.ts +4 -0
- package/lib/utils/datetime.utils.ts +15 -0
- package/lib/utils/errors.ts +25 -0
- package/lib/utils/execute-shell.ts +116 -0
- package/lib/utils/file.utils.ts +68 -0
- package/lib/utils/http.utils.ts +10 -0
- package/lib/utils/json.utils.ts +15 -0
- package/lib/utils/number.utils.ts +9 -0
- package/lib/utils/object.utils.ts +11 -0
- package/lib/utils/os.utils.ts +31 -0
- package/lib/utils/path.utils.ts +9 -0
- package/lib/utils/renderer/render_functions.ts +3 -0
- package/lib/utils/renderer/renderer.ts +89 -0
- package/lib/utils/renderer/twig.ts +191 -0
- package/lib/utils/string.utils.ts +33 -0
- package/lib/utils/typed-event-emitter.ts +26 -0
- package/lib/utils/unix.utils.ts +91 -0
- package/lib/utils/windows.utils.ts +92 -0
- package/package.json +67 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import fs from "fs-extra"
|
|
2
|
+
import git from "isomorphic-git"
|
|
3
|
+
import http from "isomorphic-git/http/node"
|
|
4
|
+
import {
|
|
5
|
+
type ModuleCommonReturn,
|
|
6
|
+
type ModuleConstraints
|
|
7
|
+
} from "../interfaces/module.interface"
|
|
8
|
+
import type { Katmer } from "../interfaces/task.interface"
|
|
9
|
+
import type { KatmerProvider } from "../interfaces/provider.interface"
|
|
10
|
+
import { SSHProvider } from "../providers/ssh/ssh.provider"
|
|
11
|
+
import { LocalProvider } from "../providers/local.provider"
|
|
12
|
+
import { KatmerModule } from "../module"
|
|
13
|
+
|
|
14
|
+
declare module "../interfaces/task.interface" {
|
|
15
|
+
export namespace Katmer {
|
|
16
|
+
export interface TaskActions {
|
|
17
|
+
git?: GitModuleOptions
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Manage Git checkouts on the target machine.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* This module is inspired by **Ansible's `ansible.builtin.git`** module.
|
|
26
|
+
*
|
|
27
|
+
* Provider behavior:
|
|
28
|
+
* - **Local provider**:
|
|
29
|
+
* - Uses {@link https://isomorphic-git.org | isomorphic-git}
|
|
30
|
+
* - Does NOT require system `git`
|
|
31
|
+
* - Ideal for controller-side checkouts and reproducible environments
|
|
32
|
+
*
|
|
33
|
+
* - **SSH provider**:
|
|
34
|
+
* - Uses system-installed `git` on the target host
|
|
35
|
+
* - Supports Linux, macOS, and Windows (`git.exe`)
|
|
36
|
+
* - Honors `become` and shell handling via provider
|
|
37
|
+
*
|
|
38
|
+
* Idempotency:
|
|
39
|
+
* - `changed=false` when the repository is already at the desired revision
|
|
40
|
+
* - `changed=true` on clone, checkout, pull, or reset
|
|
41
|
+
*
|
|
42
|
+
* @examples
|
|
43
|
+
* Clone a repository:
|
|
44
|
+
* ```yaml
|
|
45
|
+
* - name: Clone repo
|
|
46
|
+
* git:
|
|
47
|
+
* repo: https://github.com/org/project.git
|
|
48
|
+
* dest: /opt/project
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* Checkout a specific tag:
|
|
52
|
+
* ```yaml
|
|
53
|
+
* - name: Checkout release
|
|
54
|
+
* git:
|
|
55
|
+
* repo: https://github.com/org/project.git
|
|
56
|
+
* dest: /srv/app
|
|
57
|
+
* version: v1.4.2
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* Force reset to main:
|
|
61
|
+
* ```yaml
|
|
62
|
+
* - name: Force sync
|
|
63
|
+
* git:
|
|
64
|
+
* repo: git@github.com:org/app.git
|
|
65
|
+
* dest: /srv/app
|
|
66
|
+
* version: main
|
|
67
|
+
* force: true
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export class GitModule extends KatmerModule<
|
|
71
|
+
GitModuleOptions,
|
|
72
|
+
GitModuleResult,
|
|
73
|
+
KatmerProvider
|
|
74
|
+
> {
|
|
75
|
+
static name = "git" as const
|
|
76
|
+
|
|
77
|
+
constraints = {
|
|
78
|
+
platform: {
|
|
79
|
+
local: true,
|
|
80
|
+
any: { packages: ["git"] }
|
|
81
|
+
}
|
|
82
|
+
} satisfies ModuleConstraints
|
|
83
|
+
|
|
84
|
+
async check(): Promise<void> {
|
|
85
|
+
if (!this.params?.repo) throw new Error("git: 'repo' is required")
|
|
86
|
+
if (!this.params?.dest) throw new Error("git: 'dest' is required")
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async initialize(): Promise<void> {}
|
|
90
|
+
async cleanup(): Promise<void> {}
|
|
91
|
+
|
|
92
|
+
async execute(ctx: Katmer.TaskContext): Promise<GitModuleResult> {
|
|
93
|
+
const p = normalizeOptions(this.params)
|
|
94
|
+
|
|
95
|
+
if (ctx.provider instanceof LocalProvider) {
|
|
96
|
+
return this.runLocal(ctx, p)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (ctx.provider instanceof SSHProvider) {
|
|
100
|
+
return this.runSsh(ctx as Katmer.TaskContext<SSHProvider>, p)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
changed: false,
|
|
105
|
+
failed: true,
|
|
106
|
+
msg: `git: unsupported provider ${ctx.provider?.constructor?.name}`
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
111
|
+
// Local (isomorphic-git)
|
|
112
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
private async runLocal(
|
|
115
|
+
_ctx: Katmer.TaskContext<LocalProvider>,
|
|
116
|
+
p: NormalizedGitOptions
|
|
117
|
+
): Promise<GitModuleResult> {
|
|
118
|
+
const exists = await fs.pathExists(p.dest)
|
|
119
|
+
let changed = false
|
|
120
|
+
|
|
121
|
+
if (!exists) {
|
|
122
|
+
await git.clone({
|
|
123
|
+
fs,
|
|
124
|
+
http,
|
|
125
|
+
dir: p.dest,
|
|
126
|
+
url: p.repo,
|
|
127
|
+
ref: p.version,
|
|
128
|
+
depth: p.depth
|
|
129
|
+
})
|
|
130
|
+
changed = true
|
|
131
|
+
} else {
|
|
132
|
+
const head = await git.resolveRef({ fs, dir: p.dest, ref: "HEAD" })
|
|
133
|
+
await git.fetch({ fs, http, dir: p.dest, ref: p.version })
|
|
134
|
+
await git.checkout({ fs, dir: p.dest, ref: p.version })
|
|
135
|
+
const newHead = await git.resolveRef({ fs, dir: p.dest, ref: "HEAD" })
|
|
136
|
+
if (head !== newHead) changed = true
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
changed,
|
|
141
|
+
failed: false,
|
|
142
|
+
revision: await git.resolveRef({ fs, dir: p.dest, ref: "HEAD" })
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
147
|
+
// SSH (system git)
|
|
148
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
private async runSsh(
|
|
151
|
+
ctx: Katmer.TaskContext<SSHProvider>,
|
|
152
|
+
p: NormalizedGitOptions
|
|
153
|
+
): Promise<GitModuleResult> {
|
|
154
|
+
const sh = ctx.provider.os.family === "windows" ? "" : "set -e; "
|
|
155
|
+
const q = (s: string) => JSON.stringify(s)
|
|
156
|
+
|
|
157
|
+
const exists = await ctx.execSafe(`${sh} test -d ${q(p.dest)}/.git`)
|
|
158
|
+
|
|
159
|
+
let changed = false
|
|
160
|
+
|
|
161
|
+
if (exists.code !== 0) {
|
|
162
|
+
await ctx.exec(
|
|
163
|
+
`${sh} git clone ${p.depth ? `--depth ${p.depth}` : ""} ${q(
|
|
164
|
+
p.repo
|
|
165
|
+
)} ${q(p.dest)}`
|
|
166
|
+
)
|
|
167
|
+
changed = true
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const revBefore = await ctx.execSafe(
|
|
171
|
+
`${sh} git -C ${q(p.dest)} rev-parse HEAD`
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if (p.force) {
|
|
175
|
+
await ctx.exec(
|
|
176
|
+
`${sh} git -C ${q(p.dest)} fetch --all && git -C ${q(
|
|
177
|
+
p.dest
|
|
178
|
+
)} reset --hard ${q(p.version || "")}`
|
|
179
|
+
)
|
|
180
|
+
changed = true
|
|
181
|
+
} else {
|
|
182
|
+
await ctx.exec(`${sh} git -C ${q(p.dest)} fetch`)
|
|
183
|
+
await ctx.exec(`${sh} git -C ${q(p.dest)} checkout ${q(p.version || "")}`)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const revAfter = await ctx.execSafe(
|
|
187
|
+
`${sh} git -C ${q(p.dest)} rev-parse HEAD`
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
if (revBefore.stdout !== revAfter.stdout) changed = true
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
changed,
|
|
194
|
+
failed: false,
|
|
195
|
+
revision: revAfter.stdout?.trim()
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* ───────────────────────── Types ───────────────────────── */
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Options for the {@link GitModule | `git`} module.
|
|
204
|
+
*
|
|
205
|
+
* @public
|
|
206
|
+
*/
|
|
207
|
+
export interface GitModuleOptions {
|
|
208
|
+
/** Repository URL (HTTPS or SSH). */
|
|
209
|
+
repo: string
|
|
210
|
+
/** Destination directory on the target. */
|
|
211
|
+
dest: string
|
|
212
|
+
/** Branch, tag, or commit to checkout. */
|
|
213
|
+
version?: string
|
|
214
|
+
/** Force reset to the given version. */
|
|
215
|
+
force?: boolean
|
|
216
|
+
/** Create a shallow clone with the given depth. */
|
|
217
|
+
depth?: number
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Result of the git operation.
|
|
222
|
+
*
|
|
223
|
+
* @public
|
|
224
|
+
*/
|
|
225
|
+
export interface GitModuleResult extends ModuleCommonReturn {
|
|
226
|
+
/** Final commit hash after execution. */
|
|
227
|
+
revision?: string
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* ───────────────────────── Internals ───────────────────────── */
|
|
231
|
+
|
|
232
|
+
type NormalizedGitOptions = Required<Pick<GitModuleOptions, "repo" | "dest">> &
|
|
233
|
+
Omit<GitModuleOptions, "repo" | "dest">
|
|
234
|
+
|
|
235
|
+
function normalizeOptions(p: GitModuleOptions): NormalizedGitOptions {
|
|
236
|
+
return {
|
|
237
|
+
repo: p.repo,
|
|
238
|
+
dest: p.dest,
|
|
239
|
+
version: p.version ?? "HEAD",
|
|
240
|
+
force: p.force ?? false,
|
|
241
|
+
depth: p.depth
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ModuleCommonReturn,
|
|
3
|
+
type ModuleConstraints
|
|
4
|
+
} from "../interfaces/module.interface"
|
|
5
|
+
import type { Katmer } from "../interfaces/task.interface"
|
|
6
|
+
import type { SSHProvider } from "../providers/ssh/ssh.provider"
|
|
7
|
+
import { KatmerModule } from "../module"
|
|
8
|
+
|
|
9
|
+
declare module "../interfaces/task.interface" {
|
|
10
|
+
export namespace Katmer {
|
|
11
|
+
export interface TaskActions {
|
|
12
|
+
hostname?: HostnameModuleOptions
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get or set the system hostname.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* - When no options are provided, the module gathers the current hostname facts and returns them as JSON.
|
|
22
|
+
* - When "name" is provided, the module sets the transient hostname (runtime) and optionally persists it to the appropriate config
|
|
23
|
+
* (e.g., /etc/hostname for most Linux distros or hostnamectl if available).
|
|
24
|
+
* - The module attempts to be idempotent: if the current hostname already matches the desired one, changed=false.
|
|
25
|
+
*
|
|
26
|
+
* @examples
|
|
27
|
+
* ```yaml
|
|
28
|
+
* - name: Get hostname facts
|
|
29
|
+
* hostname: {}
|
|
30
|
+
*
|
|
31
|
+
* - name: Set runtime hostname only
|
|
32
|
+
* hostname:
|
|
33
|
+
* name: "app-node-01"
|
|
34
|
+
*
|
|
35
|
+
* - name: Set and persist hostname
|
|
36
|
+
* hostname:
|
|
37
|
+
* name: "app-node-01"
|
|
38
|
+
* persist: true
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export class HostnameModule extends KatmerModule<
|
|
42
|
+
HostnameModuleOptions,
|
|
43
|
+
HostnameModuleResult,
|
|
44
|
+
SSHProvider
|
|
45
|
+
> {
|
|
46
|
+
static name = "hostname" as const
|
|
47
|
+
|
|
48
|
+
constraints = {
|
|
49
|
+
platform: {
|
|
50
|
+
linux: true,
|
|
51
|
+
darwin: true,
|
|
52
|
+
windows: true
|
|
53
|
+
}
|
|
54
|
+
} satisfies ModuleConstraints
|
|
55
|
+
|
|
56
|
+
async check(_ctx: Katmer.TaskContext<SSHProvider>): Promise<void> {}
|
|
57
|
+
|
|
58
|
+
async initialize(_ctx: Katmer.TaskContext<SSHProvider>): Promise<void> {}
|
|
59
|
+
|
|
60
|
+
async cleanup(_ctx: Katmer.TaskContext<SSHProvider>): Promise<void> {}
|
|
61
|
+
|
|
62
|
+
async execute(
|
|
63
|
+
ctx: Katmer.TaskContext<SSHProvider>
|
|
64
|
+
): Promise<HostnameModuleResult> {
|
|
65
|
+
const { name, persist = false } = this.params
|
|
66
|
+
|
|
67
|
+
const osfam = ctx.provider.os.family
|
|
68
|
+
const run = async (cmd: string) => {
|
|
69
|
+
const r = await ctx.exec(cmd)
|
|
70
|
+
if (r.code !== 0) throw r
|
|
71
|
+
return r.stdout.trim()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Gather current facts (single roundtrip)
|
|
75
|
+
const factsCmd = `
|
|
76
|
+
cur_short="$(hostname -s 2>/dev/null || true)"
|
|
77
|
+
cur_fqdn="$(hostname -f 2>/dev/null || hostname 2>/dev/null || true)"
|
|
78
|
+
cur_domain=""
|
|
79
|
+
# Derive domain from FQDN when possible
|
|
80
|
+
case "$cur_fqdn" in
|
|
81
|
+
*.*) cur_domain="\${cur_fqdn#*.}";;
|
|
82
|
+
*) cur_domain="";;
|
|
83
|
+
esac
|
|
84
|
+
printf '{"short":"%s","fqdn":"%s","domain":"%s"}' "$cur_short" "$cur_fqdn" "$cur_domain"
|
|
85
|
+
`.trim()
|
|
86
|
+
|
|
87
|
+
let changed = false
|
|
88
|
+
let current: HostnameFacts
|
|
89
|
+
try {
|
|
90
|
+
const out = await run(factsCmd)
|
|
91
|
+
current = JSON.parse(out) as HostnameFacts
|
|
92
|
+
} catch (e: any) {
|
|
93
|
+
// Fallback best-effort parse
|
|
94
|
+
const curShort = await run("hostname -s 2>/dev/null || true")
|
|
95
|
+
const curFqdn =
|
|
96
|
+
(await ctx.exec("hostname -f 2>/dev/null")).stdout.trim() ||
|
|
97
|
+
(await run("hostname 2>/dev/null || true"))
|
|
98
|
+
const curDomain =
|
|
99
|
+
curFqdn.includes(".") ? curFqdn.split(".").slice(1).join(".") : ""
|
|
100
|
+
current = { short: curShort, fqdn: curFqdn, domain: curDomain }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!name) {
|
|
104
|
+
// Read-only
|
|
105
|
+
return {
|
|
106
|
+
changed: false,
|
|
107
|
+
facts: current,
|
|
108
|
+
stdout: JSON.stringify(current)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Set runtime hostname if needed
|
|
113
|
+
if (name !== current.short && name !== current.fqdn) {
|
|
114
|
+
// Prefer hostnamectl when available; otherwise use hostname command
|
|
115
|
+
const hasHostnamectl =
|
|
116
|
+
(
|
|
117
|
+
await ctx.exec("command -v hostnamectl >/dev/null 2>&1; echo $?")
|
|
118
|
+
).stdout.trim() === "0"
|
|
119
|
+
const cmd =
|
|
120
|
+
hasHostnamectl ?
|
|
121
|
+
`hostnamectl set-hostname ${JSON.stringify(name)}`
|
|
122
|
+
: `hostname ${JSON.stringify(name)}`
|
|
123
|
+
const r = await ctx.exec(cmd)
|
|
124
|
+
if (r.code !== 0) {
|
|
125
|
+
throw {
|
|
126
|
+
changed: false,
|
|
127
|
+
msg: r.stderr || r.stdout || "failed to set hostname"
|
|
128
|
+
} satisfies HostnameModuleResult
|
|
129
|
+
}
|
|
130
|
+
changed = true
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Persist if requested (best-effort, Linux-focused)
|
|
134
|
+
if (persist) {
|
|
135
|
+
// If hostnamectl exists, it usually persists. Still ensure /etc/hostname matches for classic systems.
|
|
136
|
+
const etcHostname = "/etc/hostname"
|
|
137
|
+
const check = await ctx.exec(
|
|
138
|
+
`test -w ${JSON.stringify(etcHostname)}; echo $?`
|
|
139
|
+
)
|
|
140
|
+
if (check.stdout.trim() === "0") {
|
|
141
|
+
// Avoid extra change if content already matches
|
|
142
|
+
const read = await ctx.exec(
|
|
143
|
+
`cat ${JSON.stringify(etcHostname)} 2>/dev/null || echo ""`
|
|
144
|
+
)
|
|
145
|
+
if (read.stdout.trim() !== name.trim()) {
|
|
146
|
+
const write = await ctx.exec(
|
|
147
|
+
`printf %s ${JSON.stringify(name.trim())} > ${JSON.stringify(etcHostname)}`
|
|
148
|
+
)
|
|
149
|
+
if (write.code !== 0) {
|
|
150
|
+
throw {
|
|
151
|
+
changed,
|
|
152
|
+
msg: write.stderr || write.stdout || "failed to persist hostname"
|
|
153
|
+
} satisfies HostnameModuleResult
|
|
154
|
+
}
|
|
155
|
+
changed = true
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Re-gather to return final state
|
|
161
|
+
const finalOut = await run(factsCmd)
|
|
162
|
+
const facts = JSON.parse(finalOut) as HostnameFacts
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
changed,
|
|
166
|
+
facts,
|
|
167
|
+
stdout: JSON.stringify(facts)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Options for hostname module.
|
|
174
|
+
* @public
|
|
175
|
+
*/
|
|
176
|
+
export interface HostnameModuleOptions {
|
|
177
|
+
/**
|
|
178
|
+
* Desired hostname. If omitted, module only gathers current hostname facts.
|
|
179
|
+
*/
|
|
180
|
+
name?: string
|
|
181
|
+
/**
|
|
182
|
+
* Whether to persist the hostname to system config (e.g., /etc/hostname).
|
|
183
|
+
* @defaultValue false
|
|
184
|
+
*/
|
|
185
|
+
persist?: boolean
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Hostname facts returned by the module.
|
|
190
|
+
* @public
|
|
191
|
+
*/
|
|
192
|
+
export interface HostnameFacts {
|
|
193
|
+
/**
|
|
194
|
+
* Short host name (without domain).
|
|
195
|
+
*/
|
|
196
|
+
short: string
|
|
197
|
+
/**
|
|
198
|
+
* Fully-qualified domain name if resolvable, otherwise the plain hostname.
|
|
199
|
+
*/
|
|
200
|
+
fqdn: string
|
|
201
|
+
/**
|
|
202
|
+
* Derived domain part from FQDN (empty if not applicable).
|
|
203
|
+
*/
|
|
204
|
+
domain: string
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Result of hostname module execution.
|
|
209
|
+
* @public
|
|
210
|
+
*/
|
|
211
|
+
export interface HostnameModuleResult extends ModuleCommonReturn {
|
|
212
|
+
facts?: HostnameFacts
|
|
213
|
+
}
|