@catladder/cli 1.69.0 → 1.70.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/dist/apps/cli/cli.js +2 -0
- package/dist/apps/cli/cli.js.map +1 -1
- package/dist/apps/cli/commands/{project/commandCopyDB.d.ts → cloudSQL/commandRestoreDb.d.ts} +0 -0
- package/dist/apps/cli/commands/cloudSQL/commandRestoreDb.js +150 -0
- package/dist/apps/cli/commands/cloudSQL/commandRestoreDb.js.map +1 -0
- package/dist/apps/cli/commands/cloudSQL/index.d.ts +3 -0
- package/dist/apps/cli/commands/{project/commandCopyDB.js → cloudSQL/index.js} +9 -39
- package/dist/apps/cli/commands/cloudSQL/index.js.map +1 -0
- package/dist/apps/cli/commands/project/index.js +0 -2
- package/dist/apps/cli/commands/project/index.js.map +1 -1
- package/dist/bundles/catenv/index.js +1 -1
- package/dist/bundles/cli/index.js +2 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/apps/cli/cli.ts +2 -0
- package/src/apps/cli/commands/cloudSQL/commandRestoreDb.ts +132 -0
- package/src/apps/cli/commands/cloudSQL/index.ts +8 -0
- package/src/apps/cli/commands/project/index.ts +1 -2
- package/dist/apps/cli/commands/project/commandCopyDB.js.map +0 -1
- package/src/apps/cli/commands/project/commandCopyDB.ts +0 -92
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"node": ">=12.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@catladder/pipeline": "1.
|
|
27
|
+
"@catladder/pipeline": "1.70.0",
|
|
28
28
|
"@kubernetes/client-node": "^0.16.2",
|
|
29
29
|
"@tsconfig/node14": "^1.0.1",
|
|
30
30
|
"@types/common-tags": "^1.8.0",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"typescript": "^4.5.4",
|
|
58
58
|
"vorpal": "^1.12.0"
|
|
59
59
|
},
|
|
60
|
-
"version": "1.
|
|
60
|
+
"version": "1.70.0"
|
|
61
61
|
}
|
package/src/apps/cli/cli.ts
CHANGED
|
@@ -4,6 +4,7 @@ import packageInfos from "../../packageInfos";
|
|
|
4
4
|
import { stopAllPortForwards } from "../../utils/portForward";
|
|
5
5
|
import general from "./commands/general";
|
|
6
6
|
import mongodb from "./commands/mongodb";
|
|
7
|
+
import cloudSQL from "./commands/cloudSQL";
|
|
7
8
|
import project from "./commands/project";
|
|
8
9
|
import theStuffThatReallyMatters from "./commands/theStuffThatReallyMatters";
|
|
9
10
|
|
|
@@ -29,6 +30,7 @@ export default async () => {
|
|
|
29
30
|
|
|
30
31
|
general(vorpal);
|
|
31
32
|
project(vorpal);
|
|
33
|
+
cloudSQL(vorpal);
|
|
32
34
|
mongodb(vorpal);
|
|
33
35
|
theStuffThatReallyMatters(vorpal);
|
|
34
36
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { spawn } from "child-process-promise";
|
|
2
|
+
import type Vorpal from "vorpal";
|
|
3
|
+
|
|
4
|
+
const createProxy = async (instance: string, port: number) => {
|
|
5
|
+
const proxy = spawn(
|
|
6
|
+
`cloud_sql_proxy -instances ${instance}=tcp:${port}`,
|
|
7
|
+
[],
|
|
8
|
+
{ shell: "bash" }
|
|
9
|
+
);
|
|
10
|
+
// wait until it starts
|
|
11
|
+
await spawn(
|
|
12
|
+
`echo -n "Waiting for proxy"
|
|
13
|
+
until echo > /dev/tcp/localhost/${port}; do
|
|
14
|
+
sleep 0.2
|
|
15
|
+
echo -n "."
|
|
16
|
+
done 2>/dev/null`,
|
|
17
|
+
[],
|
|
18
|
+
{ shell: "bash" }
|
|
19
|
+
);
|
|
20
|
+
const stop = () => proxy.childProcess.kill();
|
|
21
|
+
process.on("beforeExit", stop);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
stop,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default async (vorpal: Vorpal) =>
|
|
29
|
+
vorpal
|
|
30
|
+
.command(
|
|
31
|
+
"cloud-sql-restore-db",
|
|
32
|
+
"restore a db from one source to another target"
|
|
33
|
+
)
|
|
34
|
+
.action(async function restoreDb() {
|
|
35
|
+
const { sourceInstance } = await this.prompt({
|
|
36
|
+
type: "input",
|
|
37
|
+
name: "sourceInstance",
|
|
38
|
+
|
|
39
|
+
message: "Source instance (connection string)? 🤔 ",
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const SOURCE_INSTANCE_PORT = 54399;
|
|
43
|
+
const TARGET_INSTANCE_PORT = 54499;
|
|
44
|
+
|
|
45
|
+
const sourceProxy = await createProxy(
|
|
46
|
+
sourceInstance,
|
|
47
|
+
SOURCE_INSTANCE_PORT
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const { sourcePassword } = await this.prompt({
|
|
51
|
+
type: "input",
|
|
52
|
+
name: "sourcePassword",
|
|
53
|
+
|
|
54
|
+
message: "Source Password? 🤔 ",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const { sourceDbName } = await this.prompt({
|
|
58
|
+
type: "input",
|
|
59
|
+
name: "sourceDbName",
|
|
60
|
+
|
|
61
|
+
message: "Source DB name? 🤔 ",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const { targetInstance } = await this.prompt({
|
|
65
|
+
type: "input",
|
|
66
|
+
name: "targetInstance",
|
|
67
|
+
|
|
68
|
+
message: "Targe INSTANCE (connection string)? 🤔 ",
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const targetProxy = await createProxy(
|
|
72
|
+
targetInstance,
|
|
73
|
+
TARGET_INSTANCE_PORT
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const { targetPassword } = await this.prompt({
|
|
77
|
+
type: "input",
|
|
78
|
+
name: "targetPassword",
|
|
79
|
+
|
|
80
|
+
message: "Target Password? 🤔 ",
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const { targetDbName } = await this.prompt({
|
|
84
|
+
type: "input",
|
|
85
|
+
name: "targetDbName",
|
|
86
|
+
|
|
87
|
+
message: "Target DB name? 🤔 ",
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const { shouldContinue } = await this.prompt({
|
|
91
|
+
type: "confirm",
|
|
92
|
+
name: "shouldContinue",
|
|
93
|
+
message: `This will drop ${targetInstance}/${targetDbName} and replace it with ${sourceInstance}/${sourceDbName}. Continue? 🤔 `,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (!shouldContinue) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const targetPSQL = (command: string) =>
|
|
101
|
+
`PGPASSWORD=${targetPassword} psql -p ${TARGET_INSTANCE_PORT} --host=localhost --user=postgres -q ${command}`;
|
|
102
|
+
|
|
103
|
+
const copyDBScript = `
|
|
104
|
+
set -e
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
dumptmp=$(mktemp /tmp/dump.XXXXXX)
|
|
109
|
+
|
|
110
|
+
echo "Dumping file to $dumptmp"
|
|
111
|
+
pg_dump --dbname=postgres://postgres:${sourcePassword}@localhost:${SOURCE_INSTANCE_PORT}/${sourceDbName} --no-owner --no-privileges > $dumptmp
|
|
112
|
+
echo "dump done"
|
|
113
|
+
${targetPSQL(
|
|
114
|
+
`-c 'drop database "${targetDbName}" WITH (FORCE)' 1> /dev/null || true`
|
|
115
|
+
)}
|
|
116
|
+
${targetPSQL(`-c 'create database "${targetDbName}"' 1> /dev/null`)}
|
|
117
|
+
echo "Restoring dump..."
|
|
118
|
+
${targetPSQL(`"${targetDbName}" < $dumptmp 1> /dev/null`)}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
echo "Clean up..."
|
|
122
|
+
set +e
|
|
123
|
+
rm $dumptmp
|
|
124
|
+
echo "\n🐱 Done!"
|
|
125
|
+
`;
|
|
126
|
+
try {
|
|
127
|
+
await spawn(copyDBScript, [], { shell: "bash", stdio: "inherit" });
|
|
128
|
+
} finally {
|
|
129
|
+
sourceProxy.stop();
|
|
130
|
+
targetProxy.stop();
|
|
131
|
+
}
|
|
132
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type Vorpal from "vorpal";
|
|
2
2
|
import commandCloudSqlProxy from "./commandCloudSqlProxy";
|
|
3
3
|
import commandConfigSecrets from "./commandConfigSecrets";
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
import commandDeletePods from "./commandDeletePods";
|
|
6
6
|
import commandDeleteProject from "./commandDeleteProject";
|
|
7
7
|
import commandEnvVars from "./commandEnvVars";
|
|
@@ -51,7 +51,6 @@ export default async (vorpal: Vorpal) => {
|
|
|
51
51
|
commandConfigSecrets(vorpal);
|
|
52
52
|
commandSecretsClearBackups(vorpal);
|
|
53
53
|
commandDeletePods(vorpal);
|
|
54
|
-
commandCopyDB(vorpal);
|
|
55
54
|
|
|
56
55
|
commandGetShell(vorpal);
|
|
57
56
|
commandPortForward(vorpal);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"commandCopyDB.js","sourceRoot":"","sources":["../../../../../src/apps/cli/commands/project/commandCopyDB.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,wEAI6C;AAE7C,2DAA2D;AAE3D,sBAAe,UAAO,MAAc;;;;;gBAClC,KAAA,CAAA,KAAA,MAAM;qBACH,OAAO,CACN,wBAAwB,EACxB,2CAA2C,CAC5C,CAAA;qBACA,YAAY,CAAA;gBAAC,qBAAM,IAAA,kCAAgB,GAAE,EAAA;oBALxC,sBAAA,cAKgB,SAAwB,EAAC;qBACtC,MAAM,CAAC,SAAe,MAAM,CAAC,EAAgB;wBAAd,YAAY,kBAAA;;;;;;oCACpC,KAAyB,IAAA,8BAAW,EAAC,YAAY,CAAC,EAAhD,GAAG,SAAA,EAAE,aAAa,mBAAA,CAA+B;oCACvB,qBAAM,IAAA,mCAAgB,GAAE,EAAA;;oCAApD,KAA4B,SAAwB,EAAlD,YAAY,kBAAA,EAAE,OAAO,aAAA;oCAEF,qBAAM,IAAI,CAAC,MAAM,CAAC;4CAC3C,IAAI,EAAE,SAAS;4CACf,IAAI,EAAE,gBAAgB;4CACtB,OAAO,EACL,sFAAsF;yCACzF,CAAC,EAAA;;oCALM,cAAc,GAAK,CAAA,SAKzB,CAAA,eALoB;oCAOtB,IAAI,CAAC,cAAc,EAAE;wCACnB,sBAAO;qCACR;;;;;iBA6DF,CAAC,EAAA;;;KAAA,EAAC"}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { spawn } from "child-process-promise";
|
|
2
|
-
import type Vorpal from "vorpal";
|
|
3
|
-
import {
|
|
4
|
-
getEnvVars,
|
|
5
|
-
getProjectConfig,
|
|
6
|
-
parseChoice,
|
|
7
|
-
} from "../../../../config/getProjectConfig";
|
|
8
|
-
import { readPass } from "../../../../utils/passwordstore";
|
|
9
|
-
import { envAndComponents } from "./utils/autocompletions";
|
|
10
|
-
|
|
11
|
-
export default async (vorpal: Vorpal) =>
|
|
12
|
-
vorpal
|
|
13
|
-
.command(
|
|
14
|
-
"copy-db <envComponent>",
|
|
15
|
-
"replace local db with the one from an env"
|
|
16
|
-
)
|
|
17
|
-
.autocomplete(await envAndComponents())
|
|
18
|
-
.action(async function copyDB({ envComponent }) {
|
|
19
|
-
const { env, componentName } = parseChoice(envComponent);
|
|
20
|
-
const { customerName, appName } = await getProjectConfig();
|
|
21
|
-
|
|
22
|
-
const { shouldContinue } = await this.prompt({
|
|
23
|
-
type: "confirm",
|
|
24
|
-
name: "shouldContinue",
|
|
25
|
-
message:
|
|
26
|
-
"This will drop your local database and replace it with the remote one. Continue? 🤔 ",
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
if (!shouldContinue) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// TODO: reimpleent with new config
|
|
34
|
-
/*
|
|
35
|
-
throw new Error("needs reimplementation with new config");
|
|
36
|
-
const GOOGLE_CLOUD_SQL_REGION = "europe-west6"; // currently hardcoded
|
|
37
|
-
const { POSTGRESQL_PASSWORD } = await getEnvVars(
|
|
38
|
-
this,
|
|
39
|
-
env,
|
|
40
|
-
componentName
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const LOCAL_PORT = 54321;
|
|
44
|
-
|
|
45
|
-
const instanceName = `${"xxxxxx reimplement shoulld be project id"}:${GOOGLE_CLOUD_SQL_REGION}:${customerName}-${appName}-${env}=tcp:${LOCAL_PORT}`;
|
|
46
|
-
const cloudsqlCredentials = await readPass(GOOGLE_CLOUD_SQL_PASS_PATH);
|
|
47
|
-
|
|
48
|
-
const { POSTGRESQL_URL } = process.env;
|
|
49
|
-
const matches = new RegExp(/\w+:\/\/.*@.*\/(\w*)()/g).exec(
|
|
50
|
-
POSTGRESQL_URL
|
|
51
|
-
);
|
|
52
|
-
if (!matches) {
|
|
53
|
-
throw new Error("Could not determine db name.");
|
|
54
|
-
}
|
|
55
|
-
const localDBName = matches[1];
|
|
56
|
-
|
|
57
|
-
const copyDBScript = `
|
|
58
|
-
set -e
|
|
59
|
-
credtmp=$(mktemp /tmp/cred.XXXXXX)
|
|
60
|
-
echo '${cloudsqlCredentials}' > $credtmp
|
|
61
|
-
echo "Opening connection..."
|
|
62
|
-
cloud_sql_proxy -instances ${instanceName} -credential_file $credtmp &> /dev/null &
|
|
63
|
-
PROXY_PID=$!
|
|
64
|
-
|
|
65
|
-
echo -n "Waiting for proxy"
|
|
66
|
-
until echo > /dev/tcp/localhost/${LOCAL_PORT}; do
|
|
67
|
-
sleep 0.2
|
|
68
|
-
echo -n "."
|
|
69
|
-
done 2>/dev/null
|
|
70
|
-
echo
|
|
71
|
-
|
|
72
|
-
dumptmp=$(mktemp /tmp/dump.XXXXXX)
|
|
73
|
-
|
|
74
|
-
echo "Dumping file to $dumptmp"
|
|
75
|
-
pg_dump --dbname=postgres://postgres:${POSTGRESQL_PASSWORD}@localhost:${LOCAL_PORT}/${componentName} --no-owner --no-privileges > $dumptmp
|
|
76
|
-
psql -q -c "drop database ${localDBName}" 1> /dev/null
|
|
77
|
-
psql -q -c "create database ${localDBName}" 1> /dev/null
|
|
78
|
-
echo "Restoring dump..."
|
|
79
|
-
psql -q ${localDBName} < $dumptmp 1> /dev/null
|
|
80
|
-
|
|
81
|
-
echo "Clean up..."
|
|
82
|
-
set +e
|
|
83
|
-
kill -9 $PROXY_PID
|
|
84
|
-
wait $PROXY_PID 2> /dev/null
|
|
85
|
-
rm $credtmp
|
|
86
|
-
rm $dumptmp
|
|
87
|
-
echo "\n🐱 Done!"
|
|
88
|
-
`;
|
|
89
|
-
|
|
90
|
-
await spawn(copyDBScript, [], { shell: "bash", stdio: "inherit" });
|
|
91
|
-
*/
|
|
92
|
-
});
|