@localctl/cli 0.2.0 → 0.3.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/LICENSE +21 -21
- package/README.md +398 -431
- package/assets/manifests/namespace-addons.yaml +4 -4
- package/assets/manifests/tls-store.yaml +8 -8
- package/bin/localctl.js +2 -2
- package/package.json +61 -54
- package/src/commands/addons.js +56 -56
- package/src/commands/doctor.js +44 -43
- package/src/commands/down.js +35 -35
- package/src/commands/exec.js +15 -15
- package/src/commands/generateManifests.js +12 -12
- package/src/commands/hosts.js +23 -23
- package/src/commands/logs.js +45 -45
- package/src/commands/profiles.js +180 -180
- package/src/commands/prune.js +49 -49
- package/src/commands/registryInfo.js +18 -18
- package/src/commands/reload.js +44 -44
- package/src/commands/secrets.js +75 -75
- package/src/commands/setup.js +36 -36
- package/src/commands/status.js +136 -136
- package/src/commands/up.js +123 -123
- package/src/index.js +38 -36
- package/src/lib/addonDirs.js +43 -43
- package/src/lib/addonLoader.js +190 -190
- package/src/lib/addons/cluster/logging/addon.yaml +46 -46
- package/src/lib/addons/cluster/logging/config/all-logs.json +21 -21
- package/src/lib/addons/cluster/monitoring/addon.yaml +33 -33
- package/src/lib/addons/mongo/addon.yaml +18 -18
- package/src/lib/addons/postgres/addon.yaml +39 -39
- package/src/lib/addons/redis/addon.yaml +29 -29
- package/src/lib/appSecrets.js +60 -60
- package/src/lib/clusterAddons.js +59 -59
- package/src/lib/clusterProvision.js +171 -170
- package/src/lib/configSchema.js +103 -103
- package/src/lib/constants.js +16 -16
- package/src/lib/engine.js +36 -20
- package/src/lib/exec.js +77 -77
- package/src/lib/hostsFile.js +79 -79
- package/src/lib/loadConfig.js +51 -51
- package/src/lib/logger.js +9 -9
- package/src/lib/manifestGen.js +210 -210
- package/src/lib/paths.js +41 -41
- package/src/lib/podman.js +72 -72
- package/src/lib/profileStore.js +134 -134
- package/src/lib/projectContext.js +32 -32
- package/src/lib/prompt.js +97 -97
- package/src/lib/toolInstall.js +30 -30
- package/src/lib/ui.js +50 -50
- package/src/lib/updateCheck.js +84 -0
- package/src/lib/updateCheckWorker.js +46 -0
- package/src/lib/workloadReadiness.js +35 -35
- package/templates/Tiltfile.tmpl +35 -35
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
apiVersion: v1
|
|
2
|
-
kind: Namespace
|
|
3
|
-
metadata:
|
|
4
|
-
name: observability
|
|
1
|
+
apiVersion: v1
|
|
2
|
+
kind: Namespace
|
|
3
|
+
metadata:
|
|
4
|
+
name: observability
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
apiVersion: traefik.io/v1alpha1
|
|
2
|
-
kind: TLSStore
|
|
3
|
-
metadata:
|
|
4
|
-
name: default
|
|
5
|
-
namespace: kube-system
|
|
6
|
-
spec:
|
|
7
|
-
defaultCertificate:
|
|
8
|
-
secretName: local-dev-tls
|
|
1
|
+
apiVersion: traefik.io/v1alpha1
|
|
2
|
+
kind: TLSStore
|
|
3
|
+
metadata:
|
|
4
|
+
name: default
|
|
5
|
+
namespace: kube-system
|
|
6
|
+
spec:
|
|
7
|
+
defaultCertificate:
|
|
8
|
+
secretName: local-dev-tls
|
package/bin/localctl.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
require('../src/index.js');
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
require('../src/index.js');
|
package/package.json
CHANGED
|
@@ -1,54 +1,61 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@localctl/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "localctl - local Kubernetes dev platform CLI",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"kubernetes",
|
|
7
|
-
"k3d",
|
|
8
|
-
"tilt",
|
|
9
|
-
"local-development",
|
|
10
|
-
"cli",
|
|
11
|
-
"devtools"
|
|
12
|
-
],
|
|
13
|
-
"homepage": "https://psilvmoreira.github.io/localctl/",
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/psilvmoreira/localctl/issues"
|
|
16
|
-
},
|
|
17
|
-
"repository": {
|
|
18
|
-
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/psilvmoreira/localctl.git",
|
|
20
|
-
"directory": "cli"
|
|
21
|
-
},
|
|
22
|
-
"author": "Pedro Moreira",
|
|
23
|
-
"license": "MIT",
|
|
24
|
-
"bin": {
|
|
25
|
-
"localctl": "bin/localctl.js"
|
|
26
|
-
},
|
|
27
|
-
"main": "src/index.js",
|
|
28
|
-
"files": [
|
|
29
|
-
"bin/",
|
|
30
|
-
"src/",
|
|
31
|
-
"templates/",
|
|
32
|
-
"assets/",
|
|
33
|
-
"schema/"
|
|
34
|
-
],
|
|
35
|
-
"scripts": {
|
|
36
|
-
"sync-assets": "node scripts/sync-assets.js",
|
|
37
|
-
"prepack": "node scripts/sync-assets.js",
|
|
38
|
-
"test": "node scripts/smoke-test.js",
|
|
39
|
-
"test:pack": "node scripts/pack-test.js"
|
|
40
|
-
},
|
|
41
|
-
"dependencies": {
|
|
42
|
-
"chalk": "^4.1.2",
|
|
43
|
-
"commander": "^11.1.0",
|
|
44
|
-
"js-yaml": "^4.1.0",
|
|
45
|
-
"zod": "^3.23.8"
|
|
46
|
-
},
|
|
47
|
-
"engines": {
|
|
48
|
-
"node": ">=18"
|
|
49
|
-
},
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@localctl/cli",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "localctl - local Kubernetes dev platform CLI",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"kubernetes",
|
|
7
|
+
"k3d",
|
|
8
|
+
"tilt",
|
|
9
|
+
"local-development",
|
|
10
|
+
"cli",
|
|
11
|
+
"devtools"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://psilvmoreira.github.io/localctl/",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/psilvmoreira/localctl/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/psilvmoreira/localctl.git",
|
|
20
|
+
"directory": "cli"
|
|
21
|
+
},
|
|
22
|
+
"author": "Pedro Moreira",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"bin": {
|
|
25
|
+
"localctl": "bin/localctl.js"
|
|
26
|
+
},
|
|
27
|
+
"main": "src/index.js",
|
|
28
|
+
"files": [
|
|
29
|
+
"bin/",
|
|
30
|
+
"src/",
|
|
31
|
+
"templates/",
|
|
32
|
+
"assets/",
|
|
33
|
+
"schema/"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"sync-assets": "node scripts/sync-assets.js",
|
|
37
|
+
"prepack": "node scripts/sync-assets.js",
|
|
38
|
+
"test": "node scripts/smoke-test.js",
|
|
39
|
+
"test:pack": "node scripts/pack-test.js"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"chalk": "^4.1.2",
|
|
43
|
+
"commander": "^11.1.0",
|
|
44
|
+
"js-yaml": "^4.1.0",
|
|
45
|
+
"zod": "^3.23.8"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"localctl": {
|
|
51
|
+
"containerEngines": {
|
|
52
|
+
"podman": "tested",
|
|
53
|
+
"docker": "experimental",
|
|
54
|
+
"rancher-desktop": "experimental"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public",
|
|
59
|
+
"provenance": true
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/commands/addons.js
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
const { listAddonNames } = require('../lib/addonDirs');
|
|
2
|
-
const { enableClusterAddon, disableClusterAddon, clusterAddonInstances } = require('../lib/clusterAddons');
|
|
3
|
-
const { ensureClusterUp } = require('../lib/clusterProvision');
|
|
4
|
-
const { getActive, clusterNameFor } = require('../lib/profileStore');
|
|
5
|
-
const ui = require('../lib/ui');
|
|
6
|
-
const logger = require('../lib/logger');
|
|
7
|
-
|
|
8
|
-
// Cluster-wide addons apply to whichever project is currently active (see "localctl profiles
|
|
9
|
-
// switch") - there's no per-app directory to resolve one from, unlike `app` commands.
|
|
10
|
-
function ensureActiveClusterUp() {
|
|
11
|
-
const active = getActive();
|
|
12
|
-
ensureClusterUp(clusterNameFor(active), active);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
module.exports = (program) => {
|
|
16
|
-
const addons = program.command('addons').description('Manage cluster-wide addons (logging, etc.) in the active project');
|
|
17
|
-
|
|
18
|
-
addons
|
|
19
|
-
.command('list')
|
|
20
|
-
.description('List available cluster-wide addons')
|
|
21
|
-
.action(() => {
|
|
22
|
-
listAddonNames('cluster').forEach((n) => console.log(n));
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
addons
|
|
26
|
-
.command('enable <name>')
|
|
27
|
-
.description('Enable a cluster-wide addon')
|
|
28
|
-
.action((name) => {
|
|
29
|
-
ensureActiveClusterUp();
|
|
30
|
-
enableClusterAddon(name);
|
|
31
|
-
logger.success(`Addon "${name}" applied.`);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
addons
|
|
35
|
-
.command('disable <name>')
|
|
36
|
-
.description('Remove a cluster-wide addon')
|
|
37
|
-
.action((name) => {
|
|
38
|
-
ensureActiveClusterUp();
|
|
39
|
-
disableClusterAddon(name);
|
|
40
|
-
logger.success(`Addon "${name}" removed.`);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
addons
|
|
44
|
-
.command('status')
|
|
45
|
-
.description('Show every addon instance in the cluster - infrastructure helpers, separate from your apps')
|
|
46
|
-
.action(() => {
|
|
47
|
-
ensureActiveClusterUp();
|
|
48
|
-
const records = clusterAddonInstances();
|
|
49
|
-
if (records.length === 0) {
|
|
50
|
-
logger.info('No addon instances found in the cluster.');
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const rows = records.map((r) => [r.release, r.owner || ui.dim('(cluster-wide)'), r.namespace, r.chart, r.ready]);
|
|
54
|
-
ui.printTable(['ADDON', 'OWNER', 'NAMESPACE', 'CHART', 'READY'], rows);
|
|
55
|
-
});
|
|
56
|
-
};
|
|
1
|
+
const { listAddonNames } = require('../lib/addonDirs');
|
|
2
|
+
const { enableClusterAddon, disableClusterAddon, clusterAddonInstances } = require('../lib/clusterAddons');
|
|
3
|
+
const { ensureClusterUp } = require('../lib/clusterProvision');
|
|
4
|
+
const { getActive, clusterNameFor } = require('../lib/profileStore');
|
|
5
|
+
const ui = require('../lib/ui');
|
|
6
|
+
const logger = require('../lib/logger');
|
|
7
|
+
|
|
8
|
+
// Cluster-wide addons apply to whichever project is currently active (see "localctl profiles
|
|
9
|
+
// switch") - there's no per-app directory to resolve one from, unlike `app` commands.
|
|
10
|
+
function ensureActiveClusterUp() {
|
|
11
|
+
const active = getActive();
|
|
12
|
+
ensureClusterUp(clusterNameFor(active), active);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = (program) => {
|
|
16
|
+
const addons = program.command('addons').description('Manage cluster-wide addons (logging, etc.) in the active project');
|
|
17
|
+
|
|
18
|
+
addons
|
|
19
|
+
.command('list')
|
|
20
|
+
.description('List available cluster-wide addons')
|
|
21
|
+
.action(() => {
|
|
22
|
+
listAddonNames('cluster').forEach((n) => console.log(n));
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
addons
|
|
26
|
+
.command('enable <name>')
|
|
27
|
+
.description('Enable a cluster-wide addon')
|
|
28
|
+
.action((name) => {
|
|
29
|
+
ensureActiveClusterUp();
|
|
30
|
+
enableClusterAddon(name);
|
|
31
|
+
logger.success(`Addon "${name}" applied.`);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
addons
|
|
35
|
+
.command('disable <name>')
|
|
36
|
+
.description('Remove a cluster-wide addon')
|
|
37
|
+
.action((name) => {
|
|
38
|
+
ensureActiveClusterUp();
|
|
39
|
+
disableClusterAddon(name);
|
|
40
|
+
logger.success(`Addon "${name}" removed.`);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
addons
|
|
44
|
+
.command('status')
|
|
45
|
+
.description('Show every addon instance in the cluster - infrastructure helpers, separate from your apps')
|
|
46
|
+
.action(() => {
|
|
47
|
+
ensureActiveClusterUp();
|
|
48
|
+
const records = clusterAddonInstances();
|
|
49
|
+
if (records.length === 0) {
|
|
50
|
+
logger.info('No addon instances found in the cluster.');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const rows = records.map((r) => [r.release, r.owner || ui.dim('(cluster-wide)'), r.namespace, r.chart, r.ready]);
|
|
54
|
+
ui.printTable(['ADDON', 'OWNER', 'NAMESPACE', 'CHART', 'READY'], rows);
|
|
55
|
+
});
|
|
56
|
+
};
|
package/src/commands/doctor.js
CHANGED
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
const { commandExists, capture } = require('../lib/exec');
|
|
2
|
-
const { detectEngine } = require('../lib/engine');
|
|
3
|
-
const { getActive, clusterNameFor } = require('../lib/profileStore');
|
|
4
|
-
const ui = require('../lib/ui');
|
|
5
|
-
const logger = require('../lib/logger');
|
|
6
|
-
|
|
7
|
-
function check(label, fn) {
|
|
8
|
-
try {
|
|
9
|
-
const passed = fn();
|
|
10
|
-
console.log(` ${passed ? ui.check : ui.cross} ${label}`);
|
|
11
|
-
return passed;
|
|
12
|
-
} catch (e) {
|
|
13
|
-
console.log(` ${ui.cross} ${label} - ${ui.dim(e.message)}`);
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
module.exports = (program) => {
|
|
19
|
-
program
|
|
20
|
-
.command('doctor')
|
|
21
|
-
.description('Check the local environment for missing/broken pieces')
|
|
22
|
-
.action(() => {
|
|
23
|
-
logger.step('Checking environment...');
|
|
24
|
-
const detected = detectEngine();
|
|
25
|
-
check(`container engine available${detected ? ` (${detected.engine})` : ''}`, () => Boolean(detected));
|
|
26
|
-
if (detected
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
check('
|
|
31
|
-
check('
|
|
32
|
-
check('
|
|
33
|
-
check('
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
};
|
|
1
|
+
const { commandExists, capture } = require('../lib/exec');
|
|
2
|
+
const { detectEngine, warnIfExperimental } = require('../lib/engine');
|
|
3
|
+
const { getActive, clusterNameFor } = require('../lib/profileStore');
|
|
4
|
+
const ui = require('../lib/ui');
|
|
5
|
+
const logger = require('../lib/logger');
|
|
6
|
+
|
|
7
|
+
function check(label, fn) {
|
|
8
|
+
try {
|
|
9
|
+
const passed = fn();
|
|
10
|
+
console.log(` ${passed ? ui.check : ui.cross} ${label}`);
|
|
11
|
+
return passed;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
console.log(` ${ui.cross} ${label} - ${ui.dim(e.message)}`);
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = (program) => {
|
|
19
|
+
program
|
|
20
|
+
.command('doctor')
|
|
21
|
+
.description('Check the local environment for missing/broken pieces')
|
|
22
|
+
.action(() => {
|
|
23
|
+
logger.step('Checking environment...');
|
|
24
|
+
const detected = detectEngine();
|
|
25
|
+
check(`container engine available${detected ? ` (${detected.engine})` : ''}`, () => Boolean(detected));
|
|
26
|
+
if (detected) warnIfExperimental(detected.engine);
|
|
27
|
+
if (detected && detected.engine === 'podman') {
|
|
28
|
+
logger.info('Podman detected: "localctl app up" will disable BuildKit automatically for image builds.');
|
|
29
|
+
}
|
|
30
|
+
check('k3d installed', () => commandExists('k3d'));
|
|
31
|
+
check('kubectl installed', () => commandExists('kubectl'));
|
|
32
|
+
check('tilt installed', () => commandExists('tilt'));
|
|
33
|
+
check('mkcert installed', () => commandExists('mkcert'));
|
|
34
|
+
check('helm installed', () => commandExists('helm'));
|
|
35
|
+
const active = getActive();
|
|
36
|
+
const activeCluster = clusterNameFor(active);
|
|
37
|
+
check(`active project's cluster exists ("${active}" -> ${activeCluster})`, () => {
|
|
38
|
+
const res = capture('k3d', ['cluster', 'list']);
|
|
39
|
+
return res.stdout.split('\n').some((line) => line.trim().split(/\s+/)[0] === activeCluster);
|
|
40
|
+
});
|
|
41
|
+
check('kubectl context reachable', () => capture('kubectl', ['cluster-info']).status === 0);
|
|
42
|
+
logger.step(`Fix any ${ui.cross} above, or run "localctl setup" (or "localctl profiles switch ${active}" for a non-default project) to (re)install/repair.`);
|
|
43
|
+
});
|
|
44
|
+
};
|
package/src/commands/down.js
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const { loadConfig } = require('../lib/loadConfig');
|
|
3
|
-
const { run, isRunning, sleepSync } = require('../lib/exec');
|
|
4
|
-
const { ensureClusterUp } = require('../lib/clusterProvision');
|
|
5
|
-
const { runFiles } = require('../lib/paths');
|
|
6
|
-
const logger = require('../lib/logger');
|
|
7
|
-
|
|
8
|
-
module.exports = (program) => {
|
|
9
|
-
program
|
|
10
|
-
.command('down')
|
|
11
|
-
.description('Tear down the app deployed from the current directory (runs "tilt down")')
|
|
12
|
-
.action(() => {
|
|
13
|
-
const cfg = loadConfig();
|
|
14
|
-
ensureClusterUp(cfg.clusterName, cfg.profile);
|
|
15
|
-
const { pidFile, portFile, logFile } = runFiles(cfg.name);
|
|
16
|
-
|
|
17
|
-
// If `localctl up` started a detached Tilt process for this app, it needs to be stopped
|
|
18
|
-
// first - otherwise it keeps live-syncing/reconciling against resources `tilt down` is
|
|
19
|
-
// about to delete out from under it.
|
|
20
|
-
if (fs.existsSync(pidFile)) {
|
|
21
|
-
const pid = parseInt(fs.readFileSync(pidFile, 'utf8'), 10);
|
|
22
|
-
if (Number.isFinite(pid) && isRunning(pid)) {
|
|
23
|
-
logger.step(`Stopping background Tilt process (pid ${pid})...`);
|
|
24
|
-
process.kill(pid, 'SIGTERM');
|
|
25
|
-
for (let i = 0; i < 20 && isRunning(pid); i += 1) sleepSync(250);
|
|
26
|
-
}
|
|
27
|
-
fs.rmSync(pidFile, { force: true });
|
|
28
|
-
}
|
|
29
|
-
fs.rmSync(portFile, { force: true });
|
|
30
|
-
fs.rmSync(logFile, { force: true });
|
|
31
|
-
|
|
32
|
-
run('tilt', ['down']);
|
|
33
|
-
logger.success(`"${cfg.name}" torn down. Run "localctl hosts sync" if you want to clean up its subdomain too.`);
|
|
34
|
-
});
|
|
35
|
-
};
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { loadConfig } = require('../lib/loadConfig');
|
|
3
|
+
const { run, isRunning, sleepSync } = require('../lib/exec');
|
|
4
|
+
const { ensureClusterUp } = require('../lib/clusterProvision');
|
|
5
|
+
const { runFiles } = require('../lib/paths');
|
|
6
|
+
const logger = require('../lib/logger');
|
|
7
|
+
|
|
8
|
+
module.exports = (program) => {
|
|
9
|
+
program
|
|
10
|
+
.command('down')
|
|
11
|
+
.description('Tear down the app deployed from the current directory (runs "tilt down")')
|
|
12
|
+
.action(() => {
|
|
13
|
+
const cfg = loadConfig();
|
|
14
|
+
ensureClusterUp(cfg.clusterName, cfg.profile);
|
|
15
|
+
const { pidFile, portFile, logFile } = runFiles(cfg.name);
|
|
16
|
+
|
|
17
|
+
// If `localctl up` started a detached Tilt process for this app, it needs to be stopped
|
|
18
|
+
// first - otherwise it keeps live-syncing/reconciling against resources `tilt down` is
|
|
19
|
+
// about to delete out from under it.
|
|
20
|
+
if (fs.existsSync(pidFile)) {
|
|
21
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf8'), 10);
|
|
22
|
+
if (Number.isFinite(pid) && isRunning(pid)) {
|
|
23
|
+
logger.step(`Stopping background Tilt process (pid ${pid})...`);
|
|
24
|
+
process.kill(pid, 'SIGTERM');
|
|
25
|
+
for (let i = 0; i < 20 && isRunning(pid); i += 1) sleepSync(250);
|
|
26
|
+
}
|
|
27
|
+
fs.rmSync(pidFile, { force: true });
|
|
28
|
+
}
|
|
29
|
+
fs.rmSync(portFile, { force: true });
|
|
30
|
+
fs.rmSync(logFile, { force: true });
|
|
31
|
+
|
|
32
|
+
run('tilt', ['down']);
|
|
33
|
+
logger.success(`"${cfg.name}" torn down. Run "localctl hosts sync" if you want to clean up its subdomain too.`);
|
|
34
|
+
});
|
|
35
|
+
};
|
package/src/commands/exec.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
const { loadConfig } = require('../lib/loadConfig');
|
|
2
|
-
const { ensureClusterUp } = require('../lib/clusterProvision');
|
|
3
|
-
const { run } = require('../lib/exec');
|
|
4
|
-
|
|
5
|
-
module.exports = (program) => {
|
|
6
|
-
program
|
|
7
|
-
.command('exec [cmd...]')
|
|
8
|
-
.description('Shell into the running app\'s pod (kubectl exec) - defaults to "sh" if no command is given')
|
|
9
|
-
.action((cmd) => {
|
|
10
|
-
const cfg = loadConfig();
|
|
11
|
-
ensureClusterUp(cfg.clusterName, cfg.profile);
|
|
12
|
-
const command = cmd && cmd.length ? cmd : ['sh'];
|
|
13
|
-
run('kubectl', ['exec', '-it', `deploy/${cfg.name}`, '-n', cfg.namespace, '--', ...command]);
|
|
14
|
-
});
|
|
15
|
-
};
|
|
1
|
+
const { loadConfig } = require('../lib/loadConfig');
|
|
2
|
+
const { ensureClusterUp } = require('../lib/clusterProvision');
|
|
3
|
+
const { run } = require('../lib/exec');
|
|
4
|
+
|
|
5
|
+
module.exports = (program) => {
|
|
6
|
+
program
|
|
7
|
+
.command('exec [cmd...]')
|
|
8
|
+
.description('Shell into the running app\'s pod (kubectl exec) - defaults to "sh" if no command is given')
|
|
9
|
+
.action((cmd) => {
|
|
10
|
+
const cfg = loadConfig();
|
|
11
|
+
ensureClusterUp(cfg.clusterName, cfg.profile);
|
|
12
|
+
const command = cmd && cmd.length ? cmd : ['sh'];
|
|
13
|
+
run('kubectl', ['exec', '-it', `deploy/${cfg.name}`, '-n', cfg.namespace, '--', ...command]);
|
|
14
|
+
});
|
|
15
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
const { loadConfig } = require('../lib/loadConfig');
|
|
2
|
-
const { generateManifests } = require('../lib/manifestGen');
|
|
3
|
-
|
|
4
|
-
module.exports = (program) => {
|
|
5
|
-
program
|
|
6
|
-
.command('generate-manifests')
|
|
7
|
-
.description('[internal, called by Tiltfile] Render k8s manifests for the app in the current directory to stdout')
|
|
8
|
-
.action(() => {
|
|
9
|
-
const cfg = loadConfig();
|
|
10
|
-
process.stdout.write(generateManifests(cfg));
|
|
11
|
-
});
|
|
12
|
-
};
|
|
1
|
+
const { loadConfig } = require('../lib/loadConfig');
|
|
2
|
+
const { generateManifests } = require('../lib/manifestGen');
|
|
3
|
+
|
|
4
|
+
module.exports = (program) => {
|
|
5
|
+
program
|
|
6
|
+
.command('generate-manifests')
|
|
7
|
+
.description('[internal, called by Tiltfile] Render k8s manifests for the app in the current directory to stdout')
|
|
8
|
+
.action(() => {
|
|
9
|
+
const cfg = loadConfig();
|
|
10
|
+
process.stdout.write(generateManifests(cfg));
|
|
11
|
+
});
|
|
12
|
+
};
|
package/src/commands/hosts.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
const { syncHosts, clearHosts, listApps } = require('../lib/hostsFile');
|
|
2
|
-
const { DOMAIN } = require('../lib/constants');
|
|
3
|
-
|
|
4
|
-
module.exports = (program) => {
|
|
5
|
-
const hosts = program.command('hosts').description(`Manage local hosts file entries for *.${DOMAIN} apps`);
|
|
6
|
-
|
|
7
|
-
hosts
|
|
8
|
-
.command('sync')
|
|
9
|
-
.description('Sync the hosts file with all registered app subdomains')
|
|
10
|
-
.action(() => syncHosts());
|
|
11
|
-
|
|
12
|
-
hosts
|
|
13
|
-
.command('list')
|
|
14
|
-
.description('List registered subdomains')
|
|
15
|
-
.action(() => {
|
|
16
|
-
listApps().forEach((s) => console.log(`${s}.${DOMAIN}`));
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
hosts
|
|
20
|
-
.command('clear')
|
|
21
|
-
.description(`[used by uninstall] Remove the entire managed *.${DOMAIN} block from the hosts file`)
|
|
22
|
-
.action(() => clearHosts());
|
|
23
|
-
};
|
|
1
|
+
const { syncHosts, clearHosts, listApps } = require('../lib/hostsFile');
|
|
2
|
+
const { DOMAIN } = require('../lib/constants');
|
|
3
|
+
|
|
4
|
+
module.exports = (program) => {
|
|
5
|
+
const hosts = program.command('hosts').description(`Manage local hosts file entries for *.${DOMAIN} apps`);
|
|
6
|
+
|
|
7
|
+
hosts
|
|
8
|
+
.command('sync')
|
|
9
|
+
.description('Sync the hosts file with all registered app subdomains')
|
|
10
|
+
.action(() => syncHosts());
|
|
11
|
+
|
|
12
|
+
hosts
|
|
13
|
+
.command('list')
|
|
14
|
+
.description('List registered subdomains')
|
|
15
|
+
.action(() => {
|
|
16
|
+
listApps().forEach((s) => console.log(`${s}.${DOMAIN}`));
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
hosts
|
|
20
|
+
.command('clear')
|
|
21
|
+
.description(`[used by uninstall] Remove the entire managed *.${DOMAIN} block from the hosts file`)
|
|
22
|
+
.action(() => clearHosts());
|
|
23
|
+
};
|
package/src/commands/logs.js
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const { run } = require('../lib/exec');
|
|
3
|
-
const { loadConfig } = require('../lib/loadConfig');
|
|
4
|
-
const { ensureClusterUp } = require('../lib/clusterProvision');
|
|
5
|
-
const { getActive, clusterNameFor } = require('../lib/profileStore');
|
|
6
|
-
const { CONFIG_PATH } = require('../lib/paths');
|
|
7
|
-
|
|
8
|
-
module.exports = (program) => {
|
|
9
|
-
program
|
|
10
|
-
.command('logs [name]')
|
|
11
|
-
.option('-n, --namespace <ns>', 'namespace override (only needed outside an app\'s own repo, or if it disagrees with what "localctl app status" shows)')
|
|
12
|
-
.option('-f, --follow', 'follow log output')
|
|
13
|
-
.description('Tail logs for a deployed app - run inside the app\'s repo to resolve it (and its project\'s namespace prefix) automatically, or pass a name')
|
|
14
|
-
.action((name, opts) => {
|
|
15
|
-
let targetName = name;
|
|
16
|
-
let namespace = opts.namespace;
|
|
17
|
-
|
|
18
|
-
if (!namespace) {
|
|
19
|
-
if (!targetName && fs.existsSync(CONFIG_PATH)) {
|
|
20
|
-
// Directory-resolved, same as `app status`/`up`/`down` - this is what a namespace-scoped
|
|
21
|
-
// project needs: its real namespace is "<scope>-<name>", not the bare app name a plain
|
|
22
|
-
// `-n <name>` default would guess.
|
|
23
|
-
const cfg = loadConfig();
|
|
24
|
-
ensureClusterUp(cfg.clusterName, cfg.profile);
|
|
25
|
-
targetName = cfg.name;
|
|
26
|
-
namespace = cfg.namespace;
|
|
27
|
-
} else if (targetName) {
|
|
28
|
-
// An explicit name from outside its own repo - no directory to resolve from, so this
|
|
29
|
-
// stays a best-effort guess (namespace = name) against the active project's cluster,
|
|
30
|
-
// same fallback `app status -a <name>` uses.
|
|
31
|
-
const active = getActive();
|
|
32
|
-
ensureClusterUp(clusterNameFor(active), active);
|
|
33
|
-
namespace = targetName;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!targetName) {
|
|
38
|
-
throw new Error('Run this from inside an app repo, or pass a name (localctl app logs <name>).');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const args = ['logs', `deploy/${targetName}`, '-n', namespace];
|
|
42
|
-
if (opts.follow) args.push('-f');
|
|
43
|
-
run('kubectl', args);
|
|
44
|
-
});
|
|
45
|
-
};
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { run } = require('../lib/exec');
|
|
3
|
+
const { loadConfig } = require('../lib/loadConfig');
|
|
4
|
+
const { ensureClusterUp } = require('../lib/clusterProvision');
|
|
5
|
+
const { getActive, clusterNameFor } = require('../lib/profileStore');
|
|
6
|
+
const { CONFIG_PATH } = require('../lib/paths');
|
|
7
|
+
|
|
8
|
+
module.exports = (program) => {
|
|
9
|
+
program
|
|
10
|
+
.command('logs [name]')
|
|
11
|
+
.option('-n, --namespace <ns>', 'namespace override (only needed outside an app\'s own repo, or if it disagrees with what "localctl app status" shows)')
|
|
12
|
+
.option('-f, --follow', 'follow log output')
|
|
13
|
+
.description('Tail logs for a deployed app - run inside the app\'s repo to resolve it (and its project\'s namespace prefix) automatically, or pass a name')
|
|
14
|
+
.action((name, opts) => {
|
|
15
|
+
let targetName = name;
|
|
16
|
+
let namespace = opts.namespace;
|
|
17
|
+
|
|
18
|
+
if (!namespace) {
|
|
19
|
+
if (!targetName && fs.existsSync(CONFIG_PATH)) {
|
|
20
|
+
// Directory-resolved, same as `app status`/`up`/`down` - this is what a namespace-scoped
|
|
21
|
+
// project needs: its real namespace is "<scope>-<name>", not the bare app name a plain
|
|
22
|
+
// `-n <name>` default would guess.
|
|
23
|
+
const cfg = loadConfig();
|
|
24
|
+
ensureClusterUp(cfg.clusterName, cfg.profile);
|
|
25
|
+
targetName = cfg.name;
|
|
26
|
+
namespace = cfg.namespace;
|
|
27
|
+
} else if (targetName) {
|
|
28
|
+
// An explicit name from outside its own repo - no directory to resolve from, so this
|
|
29
|
+
// stays a best-effort guess (namespace = name) against the active project's cluster,
|
|
30
|
+
// same fallback `app status -a <name>` uses.
|
|
31
|
+
const active = getActive();
|
|
32
|
+
ensureClusterUp(clusterNameFor(active), active);
|
|
33
|
+
namespace = targetName;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!targetName) {
|
|
38
|
+
throw new Error('Run this from inside an app repo, or pass a name (localctl app logs <name>).');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const args = ['logs', `deploy/${targetName}`, '-n', namespace];
|
|
42
|
+
if (opts.follow) args.push('-f');
|
|
43
|
+
run('kubectl', args);
|
|
44
|
+
});
|
|
45
|
+
};
|