@catladder/cli 0.0.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/.nvmrc +1 -0
- package/CONTRIBUTING.md +83 -0
- package/README.md +31 -0
- package/bin/catenv.sh +1 -0
- package/bin/catladder +3 -0
- package/includes/envrc +35 -0
- package/package.json +65 -0
- package/src/apps/catenv/catenv.ts +41 -0
- package/src/apps/shell/commands/general/index.ts +132 -0
- package/src/apps/shell/commands/general/namespaceAutoCompletion.ts +7 -0
- package/src/apps/shell/commands/general/portForward.ts +47 -0
- package/src/apps/shell/commands/mongodb/index.ts +10 -0
- package/src/apps/shell/commands/mongodb/projectMongoDestroyMember.ts +134 -0
- package/src/apps/shell/commands/mongodb/projectMongoGetShell.ts +41 -0
- package/src/apps/shell/commands/mongodb/projectMongoPortForward.ts +42 -0
- package/src/apps/shell/commands/mongodb/utils/index.ts +84 -0
- package/src/apps/shell/commands/project/commandCloudSqlProxy.ts +65 -0
- package/src/apps/shell/commands/project/commandConfigSecrets.ts +245 -0
- package/src/apps/shell/commands/project/commandCopyDB.ts +93 -0
- package/src/apps/shell/commands/project/commandDeletePods.ts +50 -0
- package/src/apps/shell/commands/project/commandDeleteProject.ts +34 -0
- package/src/apps/shell/commands/project/commandEnvVars.ts +17 -0
- package/src/apps/shell/commands/project/commandGetMyTotalWorktime.ts +14 -0
- package/src/apps/shell/commands/project/commandGetShell.ts +35 -0
- package/src/apps/shell/commands/project/commandGitlabCi.ts +114 -0
- package/src/apps/shell/commands/project/commandInitGitlab.ts +157 -0
- package/src/apps/shell/commands/project/commandInitProject.ts +282 -0
- package/src/apps/shell/commands/project/commandListPods.ts +21 -0
- package/src/apps/shell/commands/project/commandMigrateHelm3.ts +53 -0
- package/src/apps/shell/commands/project/commandNamespace.ts +12 -0
- package/src/apps/shell/commands/project/commandOpenCostDashboard.ts +29 -0
- package/src/apps/shell/commands/project/commandOpenDashboard.ts +27 -0
- package/src/apps/shell/commands/project/commandOpenEnv.ts +18 -0
- package/src/apps/shell/commands/project/commandOpenGit.ts +12 -0
- package/src/apps/shell/commands/project/commandOpenGrafana.ts +31 -0
- package/src/apps/shell/commands/project/commandOpenGrafanaPod.ts +46 -0
- package/src/apps/shell/commands/project/commandOpenLogs.ts +23 -0
- package/src/apps/shell/commands/project/commandPauseProject.ts +31 -0
- package/src/apps/shell/commands/project/commandPortForward.ts +45 -0
- package/src/apps/shell/commands/project/commandTriggerCronjob.ts +61 -0
- package/src/apps/shell/commands/project/commandVariables.ts +13 -0
- package/src/apps/shell/commands/project/index.ts +62 -0
- package/src/apps/shell/commands/project/utils/autocompletions.ts +7 -0
- package/src/apps/shell/commands/project/utils/ensureCluster.ts +31 -0
- package/src/apps/shell/commands/project/utils/ensureNamespace.ts +32 -0
- package/src/apps/shell/commands/project/utils/monorepo.ts +45 -0
- package/src/apps/shell/commands/shared/index.ts +31 -0
- package/src/apps/shell/commands/theStuffThatReallyMatters/index.ts +51 -0
- package/src/apps/shell/shell.ts +30 -0
- package/src/apps/shell/utils/getGoogleAuthUserNumber.ts +23 -0
- package/src/config/clusters.ts +45 -0
- package/src/config/constants.ts +5 -0
- package/src/index.ts +17 -0
- package/src/k8sApi/index.ts +17 -0
- package/src/packageInfos.ts +4 -0
- package/src/types/child-process-promise.d.ts +1 -0
- package/src/types/command-exists-promise.d.ts +1 -0
- package/src/types/git-repo-name.d.ts +1 -0
- package/src/types/types.ts +20 -0
- package/src/types/yawn-yaml.d.ts +1 -0
- package/src/utils/cluster.ts +21 -0
- package/src/utils/dashboardToken.ts +20 -0
- package/src/utils/files.ts +18 -0
- package/src/utils/formatEnvVars.ts +7 -0
- package/src/utils/getEditor.ts +16 -0
- package/src/utils/gitlab.ts +80 -0
- package/src/utils/log.ts +13 -0
- package/src/utils/passwordstore/index.ts +192 -0
- package/src/utils/portForward.ts +52 -0
- package/src/utils/preferences/index.ts +33 -0
- package/src/utils/projects/index.ts +171 -0
- package/src/utils/promise.ts +11 -0
- package/src/utils/shell.ts +20 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import open from "open";
|
|
2
|
+
import Vorpal from "vorpal";
|
|
3
|
+
import { getLocalProjectVariables } from "../../../../utils/projects";
|
|
4
|
+
|
|
5
|
+
import { envAutocompletion } from "./utils/autocompletions";
|
|
6
|
+
import ensureCluster from "./utils/ensureCluster";
|
|
7
|
+
|
|
8
|
+
export default (vorpal: Vorpal) =>
|
|
9
|
+
vorpal
|
|
10
|
+
.command("project-open-env <env>", "open the live environment")
|
|
11
|
+
.autocomplete(envAutocompletion)
|
|
12
|
+
.action(async function ({ env }) {
|
|
13
|
+
await ensureCluster.call(this);
|
|
14
|
+
const { CUSTOMER_NAME, APP_NAME } = await getLocalProjectVariables();
|
|
15
|
+
const url = `https://${APP_NAME}-${env}.${CUSTOMER_NAME}.panter.cloud`;
|
|
16
|
+
|
|
17
|
+
open(url);
|
|
18
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { exec } from "child-process-promise";
|
|
2
|
+
import Vorpal from "vorpal";
|
|
3
|
+
|
|
4
|
+
export default (vorpal: Vorpal) =>
|
|
5
|
+
vorpal
|
|
6
|
+
.command(
|
|
7
|
+
"project-open-git",
|
|
8
|
+
"open the repo on gitlab / github in your browser"
|
|
9
|
+
)
|
|
10
|
+
.action(async () => {
|
|
11
|
+
await exec("npx git-open");
|
|
12
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import open from "open";
|
|
2
|
+
import { startPortForward } from "../../../../utils/portForward";
|
|
3
|
+
import Vorpal from "vorpal";
|
|
4
|
+
import {
|
|
5
|
+
GRAFANA_PROXY_LOCAL_PORT,
|
|
6
|
+
GRAFANA_PROXY_TARGET_PORT,
|
|
7
|
+
} from "../../../../config/constants";
|
|
8
|
+
|
|
9
|
+
import { getProjectNamespace } from "../../../../utils/projects";
|
|
10
|
+
|
|
11
|
+
import { envAutocompletion } from "./utils/autocompletions";
|
|
12
|
+
import ensureCluster from "./utils/ensureCluster";
|
|
13
|
+
export default (vorpal: Vorpal) =>
|
|
14
|
+
vorpal
|
|
15
|
+
.command(
|
|
16
|
+
"project-open-grafana <env>",
|
|
17
|
+
"open Grafana dashboard for your namespace"
|
|
18
|
+
)
|
|
19
|
+
.autocomplete(envAutocompletion)
|
|
20
|
+
.action(async function ({ env }) {
|
|
21
|
+
await ensureCluster.call(this);
|
|
22
|
+
const namespace = await getProjectNamespace(env);
|
|
23
|
+
const url = `http://localhost:${GRAFANA_PROXY_LOCAL_PORT}/grafana/d/at-cost-analysis-namespace2/namespace-utilization-metrics?var-namespace=${namespace}`;
|
|
24
|
+
await startPortForward(
|
|
25
|
+
"deployment/kubecost-cost-analyzer",
|
|
26
|
+
GRAFANA_PROXY_LOCAL_PORT,
|
|
27
|
+
GRAFANA_PROXY_TARGET_PORT,
|
|
28
|
+
"kubecost"
|
|
29
|
+
);
|
|
30
|
+
open(url);
|
|
31
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import open from "open";
|
|
2
|
+
import Vorpal from "vorpal";
|
|
3
|
+
import {
|
|
4
|
+
GRAFANA_PROXY_LOCAL_PORT,
|
|
5
|
+
GRAFANA_PROXY_TARGET_PORT,
|
|
6
|
+
} from "../../../../config/constants";
|
|
7
|
+
import { logError } from "../../../../utils/log";
|
|
8
|
+
import { startPortForward } from "../../../../utils/portForward";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
getProjectNamespace,
|
|
12
|
+
getProjectPodNames,
|
|
13
|
+
} from "../../../../utils/projects";
|
|
14
|
+
|
|
15
|
+
import { envAutocompletion } from "./utils/autocompletions";
|
|
16
|
+
import ensureCluster from "./utils/ensureCluster";
|
|
17
|
+
export default (vorpal: Vorpal) =>
|
|
18
|
+
vorpal
|
|
19
|
+
.command(
|
|
20
|
+
"project-open-grafana-pod <env>",
|
|
21
|
+
"open Grafana dashboard for a specific pod"
|
|
22
|
+
)
|
|
23
|
+
.autocomplete(envAutocompletion)
|
|
24
|
+
.action(async function ({ env }) {
|
|
25
|
+
await ensureCluster.call(this);
|
|
26
|
+
const podNames = await getProjectPodNames(env);
|
|
27
|
+
if (podNames.length === 0) {
|
|
28
|
+
logError(this, "sorry, no pods found");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const { podName } = await this.prompt({
|
|
32
|
+
type: "list",
|
|
33
|
+
name: "podName",
|
|
34
|
+
choices: podNames,
|
|
35
|
+
message: "Which pod? 🤔",
|
|
36
|
+
});
|
|
37
|
+
const namespace = await getProjectNamespace(env);
|
|
38
|
+
const url = `http://localhost:${GRAFANA_PROXY_LOCAL_PORT}/grafana/d/at-cost-analysis-pod/pod-cost-and-utilization-metrics?var-namespace=${namespace}&var-pod=${podName}`;
|
|
39
|
+
await startPortForward(
|
|
40
|
+
"deployment/kubecost-cost-analyzer",
|
|
41
|
+
GRAFANA_PROXY_LOCAL_PORT,
|
|
42
|
+
GRAFANA_PROXY_TARGET_PORT,
|
|
43
|
+
"kubecost"
|
|
44
|
+
);
|
|
45
|
+
open(url);
|
|
46
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import Vorpal from "vorpal";
|
|
2
|
+
import { getCurrentConnectedClusterName } from "../../../../utils/cluster";
|
|
3
|
+
import { getProjectNamespace } from "../../../../utils/projects";
|
|
4
|
+
import { getGoogleAuthUserNumber } from "../../utils/getGoogleAuthUserNumber";
|
|
5
|
+
import { openGoogleCloudLogs } from "../shared";
|
|
6
|
+
import { envAutocompletion } from "./utils/autocompletions";
|
|
7
|
+
import ensureCluster from "./utils/ensureCluster";
|
|
8
|
+
|
|
9
|
+
export default (vorpal: Vorpal) =>
|
|
10
|
+
vorpal
|
|
11
|
+
.command(
|
|
12
|
+
"project-open-logs <env>",
|
|
13
|
+
"open google cloud logs (stackdriver logs)"
|
|
14
|
+
)
|
|
15
|
+
.autocomplete(envAutocompletion)
|
|
16
|
+
.action(async function ({ env }) {
|
|
17
|
+
await ensureCluster.call(this);
|
|
18
|
+
const clustername = await getCurrentConnectedClusterName();
|
|
19
|
+
const namespace = await getProjectNamespace(env);
|
|
20
|
+
const authGoogleNumber = await getGoogleAuthUserNumber.call(this, vorpal);
|
|
21
|
+
|
|
22
|
+
await openGoogleCloudLogs(authGoogleNumber, clustername, namespace);
|
|
23
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Vorpal from "vorpal";
|
|
2
|
+
import { exec } from "child-process-promise";
|
|
3
|
+
import { Env } from "../../../../types/types";
|
|
4
|
+
import { getProjectNamespace } from "../../../../utils/projects";
|
|
5
|
+
import { envAutocompletion } from "./utils/autocompletions";
|
|
6
|
+
|
|
7
|
+
export default (vorpal: Vorpal) =>
|
|
8
|
+
vorpal
|
|
9
|
+
.command("project-pause <env>", "halts all running pods (scales to 0)")
|
|
10
|
+
.autocomplete(envAutocompletion)
|
|
11
|
+
.action(async function ({ env }) {
|
|
12
|
+
const namespace = await getProjectNamespace(env as Env);
|
|
13
|
+
const { shouldContinue } = await this.prompt({
|
|
14
|
+
type: "confirm",
|
|
15
|
+
name: "shouldContinue",
|
|
16
|
+
message: `This will STOP all running pods in the namespace ${namespace}. You will need to manually scale back up or re-deploy. Continue? 🤔 `,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (!shouldContinue) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const fullCommand = `kubectl scale statefulset,deployment --all --replicas=0 --namespace=${namespace}`;
|
|
24
|
+
const { stdout } = await exec(fullCommand, {
|
|
25
|
+
env: {
|
|
26
|
+
...process.env,
|
|
27
|
+
DEBUG: "",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
this.log(stdout);
|
|
31
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import Vorpal from "vorpal";
|
|
2
|
+
import { logError } from "../../../../utils/log";
|
|
3
|
+
import { startPortForward } from "../../../../utils/portForward";
|
|
4
|
+
import {
|
|
5
|
+
getProjectNamespace,
|
|
6
|
+
getProjectPodNames,
|
|
7
|
+
} from "../../../../utils/projects";
|
|
8
|
+
import { envAutocompletion } from "./utils/autocompletions";
|
|
9
|
+
import ensureCluster from "./utils/ensureCluster";
|
|
10
|
+
|
|
11
|
+
export default (vorpal: Vorpal) =>
|
|
12
|
+
vorpal
|
|
13
|
+
.command("project-port-forward <env>", "start port-forwarding")
|
|
14
|
+
.autocomplete(envAutocompletion)
|
|
15
|
+
.action(async function ({ env }) {
|
|
16
|
+
await ensureCluster.call(this);
|
|
17
|
+
const namespace = await getProjectNamespace(env);
|
|
18
|
+
const podNames = await getProjectPodNames(env);
|
|
19
|
+
if (podNames.length === 0) {
|
|
20
|
+
logError(this, "sorry, no pods found");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const { podName } = await this.prompt({
|
|
24
|
+
type: "list",
|
|
25
|
+
name: "podName",
|
|
26
|
+
choices: podNames,
|
|
27
|
+
message: "Which pod? 🤔",
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const { localPort } = await this.prompt({
|
|
31
|
+
type: "number",
|
|
32
|
+
name: "localPort",
|
|
33
|
+
|
|
34
|
+
message: "Local port: ",
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const { remotePort } = await this.prompt({
|
|
38
|
+
type: "number",
|
|
39
|
+
name: "remotePort",
|
|
40
|
+
|
|
41
|
+
message: "Remote port: ",
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return startPortForward(podName, localPort, remotePort, namespace);
|
|
45
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { V1Job, V1ObjectMeta } from "@kubernetes/client-node";
|
|
2
|
+
|
|
3
|
+
import Vorpal from "vorpal";
|
|
4
|
+
import { k8sApiBatch, k8sApiBatchBeta } from "../../../../k8sApi";
|
|
5
|
+
import { logError } from "../../../../utils/log";
|
|
6
|
+
import { namespaceAutoCompletion } from "../general/namespaceAutoCompletion";
|
|
7
|
+
|
|
8
|
+
import { getProjectNamespace } from "../../../../utils/projects";
|
|
9
|
+
import { envAutocompletion } from "./utils/autocompletions";
|
|
10
|
+
import ensureCluster from "./utils/ensureCluster";
|
|
11
|
+
|
|
12
|
+
async function triggerCronjob(namespace: string) {
|
|
13
|
+
const {
|
|
14
|
+
body: { items: jobs },
|
|
15
|
+
} = await k8sApiBatchBeta.listNamespacedCronJob(namespace);
|
|
16
|
+
|
|
17
|
+
const jobNames = jobs.map((j) => j.metadata.name);
|
|
18
|
+
|
|
19
|
+
const { jobName } = await this.prompt({
|
|
20
|
+
type: "list",
|
|
21
|
+
name: "jobName",
|
|
22
|
+
choices: jobNames,
|
|
23
|
+
message: "Which cronjob? 🤔",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const cronjob = jobs.find((j) => j.metadata.name === jobName);
|
|
27
|
+
const jobSpec = cronjob.spec.jobTemplate.spec;
|
|
28
|
+
|
|
29
|
+
const job = new V1Job();
|
|
30
|
+
const metadata: Partial<V1ObjectMeta> = {
|
|
31
|
+
name: `manual-${Math.round(Date.now() / 1000)}-${cronjob.metadata.name}`,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
job.metadata = metadata as V1ObjectMeta;
|
|
35
|
+
job.spec = jobSpec;
|
|
36
|
+
try {
|
|
37
|
+
const result = await k8sApiBatch.createNamespacedJob(namespace, job);
|
|
38
|
+
|
|
39
|
+
this.log("");
|
|
40
|
+
this.log(`yeah, you got a job, man. 😺 ${result.body.metadata.name}`);
|
|
41
|
+
this.log("");
|
|
42
|
+
} catch (e) {
|
|
43
|
+
logError(this, "command failed", e.body);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export default (vorpal: Vorpal) => {
|
|
47
|
+
vorpal
|
|
48
|
+
.command("trigger-cronjob <namespace>", "trigger cronjob")
|
|
49
|
+
.autocomplete(namespaceAutoCompletion)
|
|
50
|
+
.action(async function ({ namespace }) {
|
|
51
|
+
await triggerCronjob.call(this, namespace);
|
|
52
|
+
});
|
|
53
|
+
vorpal
|
|
54
|
+
.command("project-trigger-cronjob <env>", "trigger cronjob")
|
|
55
|
+
.autocomplete(envAutocompletion)
|
|
56
|
+
.action(async function ({ env }) {
|
|
57
|
+
await ensureCluster.call(this);
|
|
58
|
+
const namespace = await getProjectNamespace(env);
|
|
59
|
+
await triggerCronjob.call(this, namespace);
|
|
60
|
+
});
|
|
61
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import yaml from "js-yaml";
|
|
2
|
+
import Vorpal from "vorpal";
|
|
3
|
+
import { getLocalProjectVariables } from "../../../../utils/projects";
|
|
4
|
+
|
|
5
|
+
export default (vorpal: Vorpal) =>
|
|
6
|
+
vorpal
|
|
7
|
+
.command("project-variables", "get local project variables")
|
|
8
|
+
.action(async function() {
|
|
9
|
+
const variables = await getLocalProjectVariables();
|
|
10
|
+
this.log("");
|
|
11
|
+
this.log(yaml.safeDump(variables));
|
|
12
|
+
this.log("");
|
|
13
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import Vorpal from "vorpal";
|
|
2
|
+
import commandCloudSqlProxy from "./commandCloudSqlProxy";
|
|
3
|
+
import commandConfigSecrets from "./commandConfigSecrets";
|
|
4
|
+
import commandCopyDB from "./commandCopyDB";
|
|
5
|
+
import commandDeletePods from "./commandDeletePods";
|
|
6
|
+
import commandDeleteProject from "./commandDeleteProject";
|
|
7
|
+
import commandEnvVars from "./commandEnvVars";
|
|
8
|
+
import commandGetMyTotalWorktime from "./commandGetMyTotalWorktime";
|
|
9
|
+
import commandGetShell from "./commandGetShell";
|
|
10
|
+
import commandGitlabCi from "./commandGitlabCi";
|
|
11
|
+
import commandInitGitlab from "./commandInitGitlab";
|
|
12
|
+
import commandInitProject from "./commandInitProject";
|
|
13
|
+
import commandListPods from "./commandListPods";
|
|
14
|
+
import commandMigrateHelm3 from "./commandMigrateHelm3";
|
|
15
|
+
import commandNamespace from "./commandNamespace";
|
|
16
|
+
import commandOpenCostDashboard from "./commandOpenCostDashboard";
|
|
17
|
+
import commandOpenDashboard from "./commandOpenDashboard";
|
|
18
|
+
import commandOpenEnv from "./commandOpenEnv";
|
|
19
|
+
import commandOpenGit from "./commandOpenGit";
|
|
20
|
+
import commandOpenLogs from "./commandOpenLogs";
|
|
21
|
+
import commandPauseProject from "./commandPauseProject";
|
|
22
|
+
import commandOpenGrafana from "./commandOpenGrafana";
|
|
23
|
+
import commandPortForward from "./commandPortForward";
|
|
24
|
+
import commandTriggerCronjob from "./commandTriggerCronjob";
|
|
25
|
+
import commandVariables from "./commandVariables";
|
|
26
|
+
import commandOpenGrafanaPod from "./commandOpenGrafanaPod";
|
|
27
|
+
|
|
28
|
+
export default (vorpal: Vorpal) => {
|
|
29
|
+
commandInitProject(vorpal);
|
|
30
|
+
commandInitGitlab(vorpal);
|
|
31
|
+
commandEnvVars(vorpal);
|
|
32
|
+
|
|
33
|
+
commandVariables(vorpal);
|
|
34
|
+
commandNamespace(vorpal);
|
|
35
|
+
commandListPods(vorpal);
|
|
36
|
+
commandPauseProject(vorpal);
|
|
37
|
+
commandDeleteProject(vorpal);
|
|
38
|
+
|
|
39
|
+
commandOpenDashboard(vorpal);
|
|
40
|
+
|
|
41
|
+
commandOpenLogs(vorpal);
|
|
42
|
+
|
|
43
|
+
commandOpenCostDashboard(vorpal);
|
|
44
|
+
|
|
45
|
+
commandOpenGrafana(vorpal);
|
|
46
|
+
commandOpenGrafanaPod(vorpal);
|
|
47
|
+
commandCloudSqlProxy(vorpal);
|
|
48
|
+
commandOpenGit(vorpal);
|
|
49
|
+
commandOpenEnv(vorpal);
|
|
50
|
+
commandTriggerCronjob(vorpal);
|
|
51
|
+
commandConfigSecrets(vorpal);
|
|
52
|
+
commandDeletePods(vorpal);
|
|
53
|
+
commandCopyDB(vorpal);
|
|
54
|
+
|
|
55
|
+
commandGetShell(vorpal);
|
|
56
|
+
commandPortForward(vorpal);
|
|
57
|
+
|
|
58
|
+
commandGitlabCi(vorpal);
|
|
59
|
+
|
|
60
|
+
commandGetMyTotalWorktime(vorpal);
|
|
61
|
+
commandMigrateHelm3(vorpal);
|
|
62
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
connectToCluster,
|
|
3
|
+
getCurrentConnectedClusterName,
|
|
4
|
+
} from "../../../../../utils/cluster";
|
|
5
|
+
import { getLocalProjectVariables } from "../../../../../utils/projects/index";
|
|
6
|
+
export default async function () {
|
|
7
|
+
const { CLUSTER_NAME } = await getLocalProjectVariables();
|
|
8
|
+
if (!CLUSTER_NAME) {
|
|
9
|
+
throw new Error("no CLUSTER_NAME configured in current project");
|
|
10
|
+
}
|
|
11
|
+
const connectedClusterName = await getCurrentConnectedClusterName();
|
|
12
|
+
|
|
13
|
+
if (CLUSTER_NAME !== connectedClusterName) {
|
|
14
|
+
this.log(
|
|
15
|
+
`you are currently connected to cluster '${connectedClusterName}'`
|
|
16
|
+
);
|
|
17
|
+
this.log(`but the project requires cluster '${CLUSTER_NAME}'`);
|
|
18
|
+
const { shouldContinue } = await this.prompt({
|
|
19
|
+
type: "confirm",
|
|
20
|
+
name: "shouldContinue",
|
|
21
|
+
default: true,
|
|
22
|
+
message: `Do you want to connect to '${CLUSTER_NAME}'?`,
|
|
23
|
+
});
|
|
24
|
+
if (!shouldContinue) {
|
|
25
|
+
this.log("abort");
|
|
26
|
+
} else {
|
|
27
|
+
await connectToCluster(CLUSTER_NAME);
|
|
28
|
+
this.log(`connected to cluster '${CLUSTER_NAME}'`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { V1Namespace, V1ObjectMeta } from "@kubernetes/client-node";
|
|
2
|
+
import k8sApi from "../../../../../k8sApi";
|
|
3
|
+
import { Env } from "../../../../../types/types";
|
|
4
|
+
import { getProjectNamespace } from "../../../../../utils/projects/index";
|
|
5
|
+
|
|
6
|
+
export default async function (env: Env) {
|
|
7
|
+
const namespace = await getProjectNamespace(env);
|
|
8
|
+
try {
|
|
9
|
+
await k8sApi.readNamespace(namespace);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
if (e.response.body && e.response.body.reason === "NotFound") {
|
|
12
|
+
this.log(`namespace '${namespace} does not exist. `);
|
|
13
|
+
const { shouldContinue } = await this.prompt({
|
|
14
|
+
type: "confirm",
|
|
15
|
+
name: "shouldContinue",
|
|
16
|
+
default: true,
|
|
17
|
+
message: `Should I create namespace '${namespace}'?`,
|
|
18
|
+
});
|
|
19
|
+
if (!shouldContinue) {
|
|
20
|
+
throw new Error("abort");
|
|
21
|
+
}
|
|
22
|
+
const namespaceBody = new V1Namespace();
|
|
23
|
+
const metadata = {
|
|
24
|
+
name: namespace,
|
|
25
|
+
};
|
|
26
|
+
namespaceBody.metadata = metadata as V1ObjectMeta;
|
|
27
|
+
await k8sApi.createNamespace(namespaceBody);
|
|
28
|
+
} else {
|
|
29
|
+
throw e;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "fs-extra";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { CommandInstance } from "vorpal";
|
|
4
|
+
import { getGitRoot } from "../../../../../utils/projects";
|
|
5
|
+
|
|
6
|
+
export const getSubAppsInMonoRepo = async () => {
|
|
7
|
+
const gitRoot = await getGitRoot();
|
|
8
|
+
return readdirSync(gitRoot)
|
|
9
|
+
.map((dir) => ({
|
|
10
|
+
componentName: dir,
|
|
11
|
+
ci: join(gitRoot, dir, ".gitlab-ci.yml"),
|
|
12
|
+
path: join(gitRoot, dir),
|
|
13
|
+
}))
|
|
14
|
+
.filter(({ ci }) => existsSync(ci));
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const getCurrentSubApp = async () => {
|
|
18
|
+
const gitRoot = await getGitRoot();
|
|
19
|
+
const subApps = await getSubAppsInMonoRepo();
|
|
20
|
+
const currentDir = process.cwd();
|
|
21
|
+
return subApps.find((a) =>
|
|
22
|
+
currentDir.startsWith(join(gitRoot, a.componentName))
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const promptForSubAppIfAny = async (
|
|
27
|
+
vorpal: CommandInstance
|
|
28
|
+
): Promise<string | null> => {
|
|
29
|
+
const currentSubApp = await getCurrentSubApp();
|
|
30
|
+
if (currentSubApp) {
|
|
31
|
+
return currentSubApp.componentName;
|
|
32
|
+
}
|
|
33
|
+
const subApps = await getSubAppsInMonoRepo();
|
|
34
|
+
if (subApps.length > 0) {
|
|
35
|
+
const { subApp } = await vorpal.prompt({
|
|
36
|
+
type: "list",
|
|
37
|
+
name: "subApp",
|
|
38
|
+
choices: subApps.map((a) => a.componentName),
|
|
39
|
+
message: "Which subapp 🤔 ?",
|
|
40
|
+
});
|
|
41
|
+
return subApp;
|
|
42
|
+
} else {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import open from "open";
|
|
2
|
+
import { GOOGLE_PROJECT } from "../../../../config/constants";
|
|
3
|
+
|
|
4
|
+
export const openGoogleCloudLogs = async (
|
|
5
|
+
googleAuthUserNumber = 0,
|
|
6
|
+
clustername?: string,
|
|
7
|
+
namespace?: string
|
|
8
|
+
) => {
|
|
9
|
+
const resource = clustername
|
|
10
|
+
? `k8s_container/cluster_name/${clustername}${
|
|
11
|
+
namespace ? `/namespace_name/${namespace}` : ""
|
|
12
|
+
}`
|
|
13
|
+
: null;
|
|
14
|
+
|
|
15
|
+
const url = `https://console.cloud.google.com/logs/viewer?project=${GOOGLE_PROJECT}${
|
|
16
|
+
resource ? `&resource=${encodeURIComponent(resource)}` : ""
|
|
17
|
+
}&authuser=${googleAuthUserNumber}`;
|
|
18
|
+
open(url);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const openGoogleCloudKubernetesDashboard = async (
|
|
22
|
+
googleAuthUserNumber = 0,
|
|
23
|
+
clustername?: string,
|
|
24
|
+
namespace?: string
|
|
25
|
+
) => {
|
|
26
|
+
const url = `https://console.cloud.google.com/kubernetes/workload?authuser=${googleAuthUserNumber}&project=${GOOGLE_PROJECT}&pageState=(%22savedViews%22:(%22c%22:%5B%22gke%2Feurope-west1-d%2F${clustername}%22%5D,${
|
|
27
|
+
namespace ? `%22n%22:%5B%22${namespace}%22%5D` : ""
|
|
28
|
+
}))`;
|
|
29
|
+
|
|
30
|
+
open(url);
|
|
31
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { spawn } from "child-process-promise";
|
|
2
|
+
import fetch from "node-fetch";
|
|
3
|
+
import Vorpal from "vorpal";
|
|
4
|
+
|
|
5
|
+
export default (vorpal: Vorpal) => {
|
|
6
|
+
vorpal.command("dadjoke", "something for jonas.").action(async function() {
|
|
7
|
+
const result = await fetch("https://icanhazdadjoke.com/", {
|
|
8
|
+
headers: {
|
|
9
|
+
Accept: "text/plain"
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
const text = await result.text();
|
|
13
|
+
this.log("");
|
|
14
|
+
this.log(text);
|
|
15
|
+
this.log("");
|
|
16
|
+
});
|
|
17
|
+
vorpal.command("pantobot", "the allknowing oracle").action(async function() {
|
|
18
|
+
const { message } = await this.prompt({
|
|
19
|
+
type: "string",
|
|
20
|
+
name: "message",
|
|
21
|
+
|
|
22
|
+
message: "Your question, unworthy?: "
|
|
23
|
+
});
|
|
24
|
+
const result = await fetch(
|
|
25
|
+
`https://paas.panter.cloud/api/pantobot/${message}`,
|
|
26
|
+
{
|
|
27
|
+
headers: {
|
|
28
|
+
Accept: "text/plain"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
const text = await result.text();
|
|
33
|
+
this.log("");
|
|
34
|
+
this.log(text);
|
|
35
|
+
this.log("");
|
|
36
|
+
});
|
|
37
|
+
let starwarsPromise: any;
|
|
38
|
+
vorpal
|
|
39
|
+
.command("starwars", "Long time ago... in a galaxy far far away...")
|
|
40
|
+
.action(async function() {
|
|
41
|
+
starwarsPromise = spawn("telnet", ["towel.blinkenlights.nl"], {
|
|
42
|
+
stdio: ["pipe", "inherit", "pipe"]
|
|
43
|
+
});
|
|
44
|
+
await starwarsPromise;
|
|
45
|
+
})
|
|
46
|
+
// we need to close it properly, because telnet towel.blinkenlights.nl has no way to cancel and stop itself
|
|
47
|
+
// this is also why we need to only inherit the stdout and not the stdin
|
|
48
|
+
.cancel(async function() {
|
|
49
|
+
starwarsPromise.childProcess.kill();
|
|
50
|
+
});
|
|
51
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import Vorpal from "vorpal";
|
|
2
|
+
// tslint:disable-next-line:no-var-requires
|
|
3
|
+
import packageInfos from "../../packageInfos";
|
|
4
|
+
import { stopAllPortForwards } from "../../utils/portForward";
|
|
5
|
+
import general from "./commands/general";
|
|
6
|
+
import mongodb from "./commands/mongodb";
|
|
7
|
+
import project from "./commands/project";
|
|
8
|
+
import theStuffThatReallyMatters from "./commands/theStuffThatReallyMatters";
|
|
9
|
+
const welcomeMessage = `catladder 2 😻 version ${packageInfos.version}`;
|
|
10
|
+
|
|
11
|
+
export default () => {
|
|
12
|
+
const vorpal = new Vorpal();
|
|
13
|
+
|
|
14
|
+
vorpal
|
|
15
|
+
.delimiter("catladder $") // emoji messes with cursor :-( https://github.com/dthree/vorpal/issues/332
|
|
16
|
+
.history("catladder")
|
|
17
|
+
.show()
|
|
18
|
+
.log("")
|
|
19
|
+
.log(welcomeMessage)
|
|
20
|
+
.log("");
|
|
21
|
+
|
|
22
|
+
general(vorpal);
|
|
23
|
+
project(vorpal);
|
|
24
|
+
mongodb(vorpal);
|
|
25
|
+
theStuffThatReallyMatters(vorpal);
|
|
26
|
+
|
|
27
|
+
process.on("exit", () => {
|
|
28
|
+
stopAllPortForwards();
|
|
29
|
+
});
|
|
30
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getPreference,
|
|
3
|
+
hasPreference,
|
|
4
|
+
setPreference,
|
|
5
|
+
} from "../../../utils/preferences";
|
|
6
|
+
|
|
7
|
+
const KEY = "googleAuthUserNumber";
|
|
8
|
+
export const getGoogleAuthUserNumber = async function () {
|
|
9
|
+
if (!(await hasPreference(KEY))) {
|
|
10
|
+
this.log(
|
|
11
|
+
"Please type in your google auth user number (0 if you have only one google account or maybe 1 if you have multiple)"
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const { authUserNumber } = await this.prompt({
|
|
15
|
+
type: "number",
|
|
16
|
+
name: "authUserNumber",
|
|
17
|
+
default: "0",
|
|
18
|
+
message: "Auth user ",
|
|
19
|
+
});
|
|
20
|
+
await setPreference(KEY, authUserNumber);
|
|
21
|
+
}
|
|
22
|
+
return getPreference(KEY);
|
|
23
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { exec } from "child-process-promise";
|
|
2
|
+
|
|
3
|
+
export type Cluster = {
|
|
4
|
+
fullName: string;
|
|
5
|
+
passToken?: string;
|
|
6
|
+
passCredentials?: {
|
|
7
|
+
ca_cert: string;
|
|
8
|
+
token: string;
|
|
9
|
+
};
|
|
10
|
+
api_url?: string;
|
|
11
|
+
connect: () => Promise<any>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const clusters: {
|
|
15
|
+
[clustername: string]: Cluster;
|
|
16
|
+
} = {
|
|
17
|
+
demo: {
|
|
18
|
+
fullName: "gke_skynet-164509_europe-west1-d_demo",
|
|
19
|
+
connect: async () =>
|
|
20
|
+
exec(
|
|
21
|
+
"gcloud container clusters get-credentials demo --zone europe-west1-d --project skynet-164509"
|
|
22
|
+
),
|
|
23
|
+
},
|
|
24
|
+
production: {
|
|
25
|
+
fullName: "gke_skynet-164509_europe-west1-d_production",
|
|
26
|
+
passCredentials: {
|
|
27
|
+
token: "syknet/clusters/production/token",
|
|
28
|
+
ca_cert: "syknet/clusters/production/ca_cert",
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
api_url: "https://35.189.234.235",
|
|
32
|
+
connect: async () =>
|
|
33
|
+
exec(
|
|
34
|
+
"gcloud container clusters get-credentials production --zone europe-west1-d --project skynet-164509"
|
|
35
|
+
),
|
|
36
|
+
},
|
|
37
|
+
panterGitlab: {
|
|
38
|
+
fullName: "gke_skynet-intern_europe-west6-a_swiss-cluster",
|
|
39
|
+
connect: async () =>
|
|
40
|
+
exec(
|
|
41
|
+
"gcloud container clusters get-credentials --project skynet-intern swiss-cluster --region europe-west6-a"
|
|
42
|
+
),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
export default clusters;
|