airfoil 0.4.0 → 0.4.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/dist/index.js +401 -739
- package/package.json +9 -6
- package/src/commands/cluster/index.ts +13 -37
- package/src/commands/cluster/namespace/create.ts +278 -61
- package/src/commands/cluster/namespace/delete.ts +9 -13
- package/src/commands/cluster/namespace/get.ts +12 -14
- package/src/commands/cluster/namespace/list.ts +16 -34
- package/src/commands/cluster/{topic → table}/create.ts +79 -96
- package/src/commands/cluster/{tenant → table}/delete.ts +15 -17
- package/src/commands/cluster/table/get.ts +62 -0
- package/src/commands/cluster/table/list.ts +61 -0
- package/src/commands/dev.ts +17 -13
- package/src/commands/sql.ts +13 -23
- package/src/index.ts +6 -6
- package/src/utils/client.ts +3 -3
- package/src/utils/docker.ts +101 -7
- package/src/utils/options.ts +1 -1
- package/src/utils/wings.ts +18 -14
- package/src/commands/cluster/data-lake/create-iceberg.ts +0 -59
- package/src/commands/cluster/data-lake/create-parquet.ts +0 -59
- package/src/commands/cluster/data-lake/create.ts +0 -10
- package/src/commands/cluster/data-lake/delete.ts +0 -54
- package/src/commands/cluster/data-lake/get.ts +0 -40
- package/src/commands/cluster/data-lake/list.ts +0 -62
- package/src/commands/cluster/object-store/create-aws.ts +0 -104
- package/src/commands/cluster/object-store/create-azure.ts +0 -96
- package/src/commands/cluster/object-store/create-google.ts +0 -87
- package/src/commands/cluster/object-store/create-s3.ts +0 -114
- package/src/commands/cluster/object-store/create.ts +0 -21
- package/src/commands/cluster/object-store/delete.ts +0 -56
- package/src/commands/cluster/object-store/get.ts +0 -49
- package/src/commands/cluster/object-store/list.ts +0 -62
- package/src/commands/cluster/tenant/create.ts +0 -44
- package/src/commands/cluster/tenant/get.ts +0 -40
- package/src/commands/cluster/tenant/list.ts +0 -53
- package/src/commands/cluster/topic/delete.ts +0 -65
- package/src/commands/cluster/topic/get.ts +0 -51
- package/src/commands/cluster/topic/list.ts +0 -61
package/src/utils/docker.ts
CHANGED
|
@@ -12,32 +12,126 @@ export const checkDockerVersion = () =>
|
|
|
12
12
|
export const createDockerVolume = (volumeName: string) =>
|
|
13
13
|
Effect.gen(function* () {
|
|
14
14
|
const docker = yield* ChildProcess.make("docker", ["volume", "create", volumeName]);
|
|
15
|
+
const exitCode = yield* docker.exitCode;
|
|
16
|
+
if (exitCode !== 0) {
|
|
17
|
+
return yield* Effect.fail(new Error(`Docker volume create failed with code ${exitCode}`));
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const createDockerNetwork = (networkName: string) =>
|
|
22
|
+
Effect.gen(function* () {
|
|
23
|
+
const docker = yield* ChildProcess.make("docker", ["network", "create", networkName]);
|
|
24
|
+
const exitCode = yield* docker.exitCode;
|
|
25
|
+
if (exitCode !== 0) {
|
|
26
|
+
return yield* Effect.fail(new Error(`Docker network create failed with code ${exitCode}`));
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export const removeDockerContainer = (containerName: string) =>
|
|
31
|
+
Effect.gen(function* () {
|
|
32
|
+
const docker = yield* ChildProcess.make("docker", ["rm", "-f", containerName], {
|
|
33
|
+
stdout: "ignore",
|
|
34
|
+
stderr: "ignore",
|
|
35
|
+
});
|
|
15
36
|
yield* docker.exitCode;
|
|
16
37
|
});
|
|
17
38
|
|
|
39
|
+
export const removeDockerNetwork = (networkName: string) =>
|
|
40
|
+
Effect.gen(function* () {
|
|
41
|
+
const docker = yield* ChildProcess.make("docker", ["network", "rm", networkName], {
|
|
42
|
+
stdout: "ignore",
|
|
43
|
+
stderr: "ignore",
|
|
44
|
+
});
|
|
45
|
+
yield* docker.exitCode;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const pullDockerImage = (image: string) =>
|
|
49
|
+
Effect.gen(function* () {
|
|
50
|
+
const docker = yield* ChildProcess.make("docker", ["pull", image], {
|
|
51
|
+
stdout: "inherit",
|
|
52
|
+
stderr: "inherit",
|
|
53
|
+
});
|
|
54
|
+
const exitCode = yield* docker.exitCode;
|
|
55
|
+
if (exitCode !== 0) {
|
|
56
|
+
return yield* Effect.fail(new Error(`Docker pull failed with code ${exitCode}`));
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
18
60
|
export const runDockerContainer = (image: string, volumeName: string) =>
|
|
19
61
|
Effect.gen(function* () {
|
|
62
|
+
const networkName = "airfoil-dev";
|
|
63
|
+
const seaweedContainerName = "airfoil-seaweedfs";
|
|
64
|
+
|
|
65
|
+
yield* removeDockerContainer(seaweedContainerName);
|
|
66
|
+
yield* removeDockerNetwork(networkName);
|
|
67
|
+
yield* createDockerNetwork(networkName);
|
|
68
|
+
yield* Effect.addFinalizer(() =>
|
|
69
|
+
removeDockerNetwork(networkName).pipe(Effect.catchCause(() => Effect.void)),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
73
|
+
const seaweed = ChildProcess.make("docker", [
|
|
74
|
+
"run",
|
|
75
|
+
"-d",
|
|
76
|
+
"--rm",
|
|
77
|
+
"--name",
|
|
78
|
+
seaweedContainerName,
|
|
79
|
+
"--network",
|
|
80
|
+
networkName,
|
|
81
|
+
"--network-alias",
|
|
82
|
+
"seaweedfs",
|
|
83
|
+
"-e",
|
|
84
|
+
"AWS_ACCESS_KEY_ID=wingsdevaccesskey",
|
|
85
|
+
"-e",
|
|
86
|
+
"AWS_SECRET_ACCESS_KEY=wingsdevsecretkey",
|
|
87
|
+
"-e",
|
|
88
|
+
"S3_BUCKET=default-bucket",
|
|
89
|
+
"-v",
|
|
90
|
+
`${volumeName}:/data`,
|
|
91
|
+
"-p",
|
|
92
|
+
"8333:8333",
|
|
93
|
+
"chrislusf/seaweedfs:4.29",
|
|
94
|
+
"weed",
|
|
95
|
+
"mini",
|
|
96
|
+
"-s3",
|
|
97
|
+
"-dir=/data",
|
|
98
|
+
]);
|
|
99
|
+
|
|
100
|
+
yield* spawner.string(seaweed).pipe(Effect.map(String.trim));
|
|
101
|
+
yield* Effect.addFinalizer(() =>
|
|
102
|
+
removeDockerContainer(seaweedContainerName).pipe(Effect.catchCause(() => Effect.void)),
|
|
103
|
+
);
|
|
104
|
+
|
|
20
105
|
const docker = yield* ChildProcess.make("docker", [
|
|
21
106
|
"run",
|
|
22
107
|
"-it",
|
|
23
108
|
"--rm",
|
|
24
109
|
"--name",
|
|
25
110
|
"wings-dev",
|
|
26
|
-
"
|
|
27
|
-
|
|
111
|
+
"--network",
|
|
112
|
+
networkName,
|
|
113
|
+
"-e",
|
|
114
|
+
"AWS_ACCESS_KEY_ID=wingsdevaccesskey",
|
|
115
|
+
"-e",
|
|
116
|
+
"AWS_SECRET_ACCESS_KEY=wingsdevsecretkey",
|
|
117
|
+
"-e",
|
|
118
|
+
"AWS_ENDPOINT=http://seaweedfs:8333",
|
|
119
|
+
"-e",
|
|
120
|
+
"AWS_BUCKET_NAME=default-bucket",
|
|
121
|
+
"-e",
|
|
122
|
+
"AWS_DEFAULT_REGION=us-east-1",
|
|
123
|
+
"-e",
|
|
124
|
+
"AWS_ALLOW_HTTP=true",
|
|
28
125
|
"-p",
|
|
29
126
|
"7777:7777",
|
|
30
|
-
"-p",
|
|
31
|
-
"7780:7780",
|
|
32
127
|
image,
|
|
33
128
|
"dev",
|
|
34
|
-
"--
|
|
35
|
-
"--metadata.address=0.0.0.0:7777",
|
|
129
|
+
"--grpc.address=0.0.0.0:7777",
|
|
36
130
|
]);
|
|
37
131
|
|
|
38
132
|
const exitCode = yield* docker.exitCode;
|
|
39
133
|
|
|
40
134
|
if (exitCode !== 0) {
|
|
41
|
-
yield* Effect.fail(new Error(`Docker process exited with code ${exitCode}`));
|
|
135
|
+
return yield* Effect.fail(new Error(`Docker process exited with code ${exitCode}`));
|
|
42
136
|
}
|
|
43
137
|
});
|
package/src/utils/options.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Flag } from "effect/unstable/cli";
|
|
|
5
5
|
*/
|
|
6
6
|
export const hostOption = Flag.string("host").pipe(
|
|
7
7
|
Flag.withDescription("Server host"),
|
|
8
|
-
Flag.withDefault("
|
|
8
|
+
Flag.withDefault("127.0.0.1"),
|
|
9
9
|
);
|
|
10
10
|
|
|
11
11
|
export const portOption = Flag.integer("port").pipe(
|
package/src/utils/wings.ts
CHANGED
|
@@ -56,25 +56,29 @@ export const downloadWings = (version: string, targetPath: string, isStress = fa
|
|
|
56
56
|
const client = yield* HttpClient.HttpClient;
|
|
57
57
|
|
|
58
58
|
const filename = getBinaryFilename(isStress);
|
|
59
|
+
const tempPath = `${targetPath}.download`;
|
|
59
60
|
|
|
60
61
|
const downloadPath = version === "latest" ? "latest/download" : `download/${version}`;
|
|
61
62
|
const url = `${GITHUB_RELEASES_URL}/${downloadPath}/${filename}`;
|
|
62
63
|
|
|
63
64
|
yield* fs.makeDirectory(WINGS_DIR, { recursive: true });
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
yield* fs.remove(tempPath).pipe(Effect.ignore);
|
|
66
|
+
|
|
67
|
+
const download = Effect.gen(function* () {
|
|
68
|
+
const response = yield* client.get(url);
|
|
69
|
+
const buffer = yield* HttpClientResponse.matchStatus({
|
|
70
|
+
200: (response) => response.arrayBuffer,
|
|
71
|
+
orElse: (response) =>
|
|
72
|
+
Effect.fail(new Error(`Failed to download Wings from ${url}: ${response.status}`)),
|
|
73
|
+
})(response);
|
|
74
|
+
|
|
75
|
+
yield* fs.writeFile(tempPath, new Uint8Array(buffer));
|
|
76
|
+
yield* verifyChecksum(version, tempPath, isStress);
|
|
77
|
+
yield* fs.chmod(tempPath, 0o755);
|
|
78
|
+
yield* fs.rename(tempPath, targetPath);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
yield* download.pipe(Effect.onError(() => fs.remove(tempPath).pipe(Effect.ignore)));
|
|
78
82
|
});
|
|
79
83
|
|
|
80
84
|
/**
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import { WingsClusterMetadata } from "@useairfoil/wings";
|
|
3
|
-
import { printTable } from "console-table-printer";
|
|
4
|
-
import { Effect } from "effect";
|
|
5
|
-
import { Command, Flag } from "effect/unstable/cli";
|
|
6
|
-
|
|
7
|
-
import { makeClusterMetadataLayer } from "../../../utils/client.js";
|
|
8
|
-
import { hostOption, portOption } from "../../../utils/options.js";
|
|
9
|
-
|
|
10
|
-
const parentOption = Flag.string("parent").pipe(
|
|
11
|
-
Flag.withDescription("Parent tenant in format: tenants/{tenant}"),
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
const dataLakeIdOption = Flag.string("data-lake-id").pipe(
|
|
15
|
-
Flag.withDescription("Unique identifier for the data lake"),
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
export const createDataLakeIcebergCommand = Command.make(
|
|
19
|
-
"iceberg",
|
|
20
|
-
{
|
|
21
|
-
parent: parentOption,
|
|
22
|
-
dataLakeId: dataLakeIdOption,
|
|
23
|
-
host: hostOption,
|
|
24
|
-
port: portOption,
|
|
25
|
-
},
|
|
26
|
-
({ parent, dataLakeId, host, port }) =>
|
|
27
|
-
Effect.gen(function* () {
|
|
28
|
-
p.intro("🏞️ Create Iceberg Data Lake");
|
|
29
|
-
|
|
30
|
-
const layer = makeClusterMetadataLayer(host, port);
|
|
31
|
-
|
|
32
|
-
const s = p.spinner();
|
|
33
|
-
s.start("Creating Iceberg data lake...");
|
|
34
|
-
|
|
35
|
-
const result = yield* WingsClusterMetadata.createDataLake({
|
|
36
|
-
parent,
|
|
37
|
-
dataLakeId,
|
|
38
|
-
dataLakeConfig: {
|
|
39
|
-
_tag: "iceberg",
|
|
40
|
-
iceberg: {},
|
|
41
|
-
},
|
|
42
|
-
}).pipe(
|
|
43
|
-
Effect.provide(layer),
|
|
44
|
-
Effect.tapError(() => Effect.sync(() => s.stop("Failed to create data lake"))),
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
s.stop("Iceberg data lake created successfully");
|
|
48
|
-
|
|
49
|
-
yield* Effect.sync(() => {
|
|
50
|
-
printTable([
|
|
51
|
-
{
|
|
52
|
-
name: result.name,
|
|
53
|
-
type: "Iceberg",
|
|
54
|
-
},
|
|
55
|
-
]);
|
|
56
|
-
p.outro("✓ Done");
|
|
57
|
-
});
|
|
58
|
-
}),
|
|
59
|
-
).pipe(Command.withDescription("Create a new Iceberg data lake"));
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import { WingsClusterMetadata } from "@useairfoil/wings";
|
|
3
|
-
import { printTable } from "console-table-printer";
|
|
4
|
-
import { Effect } from "effect";
|
|
5
|
-
import { Command, Flag } from "effect/unstable/cli";
|
|
6
|
-
|
|
7
|
-
import { makeClusterMetadataLayer } from "../../../utils/client.js";
|
|
8
|
-
import { hostOption, portOption } from "../../../utils/options.js";
|
|
9
|
-
|
|
10
|
-
const parentOption = Flag.string("parent").pipe(
|
|
11
|
-
Flag.withDescription("Parent tenant in format: tenants/{tenant}"),
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
const dataLakeIdOption = Flag.string("data-lake-id").pipe(
|
|
15
|
-
Flag.withDescription("Unique identifier for the data lake"),
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
export const createDataLakeParquetCommand = Command.make(
|
|
19
|
-
"parquet",
|
|
20
|
-
{
|
|
21
|
-
parent: parentOption,
|
|
22
|
-
dataLakeId: dataLakeIdOption,
|
|
23
|
-
host: hostOption,
|
|
24
|
-
port: portOption,
|
|
25
|
-
},
|
|
26
|
-
({ parent, dataLakeId, host, port }) =>
|
|
27
|
-
Effect.gen(function* () {
|
|
28
|
-
p.intro("🏞️ Create Parquet Data Lake");
|
|
29
|
-
|
|
30
|
-
const layer = makeClusterMetadataLayer(host, port);
|
|
31
|
-
|
|
32
|
-
const s = p.spinner();
|
|
33
|
-
s.start("Creating Parquet data lake...");
|
|
34
|
-
|
|
35
|
-
const result = yield* WingsClusterMetadata.createDataLake({
|
|
36
|
-
parent,
|
|
37
|
-
dataLakeId,
|
|
38
|
-
dataLakeConfig: {
|
|
39
|
-
_tag: "parquet",
|
|
40
|
-
parquet: {},
|
|
41
|
-
},
|
|
42
|
-
}).pipe(
|
|
43
|
-
Effect.provide(layer),
|
|
44
|
-
Effect.tapError(() => Effect.sync(() => s.stop("Failed to create data lake"))),
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
s.stop("Parquet data lake created successfully");
|
|
48
|
-
|
|
49
|
-
yield* Effect.sync(() => {
|
|
50
|
-
printTable([
|
|
51
|
-
{
|
|
52
|
-
name: result.name,
|
|
53
|
-
type: "Parquet",
|
|
54
|
-
},
|
|
55
|
-
]);
|
|
56
|
-
p.outro("✓ Done");
|
|
57
|
-
});
|
|
58
|
-
}),
|
|
59
|
-
).pipe(Command.withDescription("Create a new Parquet data lake"));
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
2
|
-
import { Command } from "effect/unstable/cli";
|
|
3
|
-
|
|
4
|
-
import { createDataLakeIcebergCommand } from "./create-iceberg.js";
|
|
5
|
-
import { createDataLakeParquetCommand } from "./create-parquet.js";
|
|
6
|
-
|
|
7
|
-
export const createDataLakeCommand = Command.make("create-data-lake", {}, () => Effect.void).pipe(
|
|
8
|
-
Command.withDescription("Create a new data lake"),
|
|
9
|
-
Command.withSubcommands([createDataLakeIcebergCommand, createDataLakeParquetCommand]),
|
|
10
|
-
);
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import { WingsClusterMetadata } from "@useairfoil/wings";
|
|
3
|
-
import { Effect } from "effect";
|
|
4
|
-
import { Command, Flag } from "effect/unstable/cli";
|
|
5
|
-
|
|
6
|
-
import { makeClusterMetadataLayer } from "../../../utils/client.js";
|
|
7
|
-
import { forceOption, hostOption, portOption } from "../../../utils/options.js";
|
|
8
|
-
|
|
9
|
-
const nameOption = Flag.string("name").pipe(
|
|
10
|
-
Flag.withDescription("Data lake name in format: tenants/{tenant}/data-lakes/{data-lake}"),
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
export const deleteDataLakeCommand = Command.make(
|
|
14
|
-
"delete-data-lake",
|
|
15
|
-
{
|
|
16
|
-
name: nameOption,
|
|
17
|
-
force: forceOption,
|
|
18
|
-
host: hostOption,
|
|
19
|
-
port: portOption,
|
|
20
|
-
},
|
|
21
|
-
({ name, force, host, port }) =>
|
|
22
|
-
Effect.gen(function* () {
|
|
23
|
-
p.intro("🗑️ Delete Data Lake");
|
|
24
|
-
|
|
25
|
-
if (!force) {
|
|
26
|
-
const confirm = yield* Effect.tryPromise({
|
|
27
|
-
try: () =>
|
|
28
|
-
p.confirm({
|
|
29
|
-
message: `Are you sure you want to delete data lake ${name}?`,
|
|
30
|
-
initialValue: false,
|
|
31
|
-
}),
|
|
32
|
-
catch: () => new Error("Failed to confirm deletion"),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
if (p.isCancel(confirm) || !confirm) {
|
|
36
|
-
p.cancel("Deletion cancelled");
|
|
37
|
-
process.exit(0);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const layer = makeClusterMetadataLayer(host, port);
|
|
42
|
-
|
|
43
|
-
const s = p.spinner();
|
|
44
|
-
s.start("Deleting data lake...");
|
|
45
|
-
|
|
46
|
-
yield* WingsClusterMetadata.deleteDataLake({ name }).pipe(
|
|
47
|
-
Effect.provide(layer),
|
|
48
|
-
Effect.tapError(() => Effect.sync(() => s.stop("Failed to delete data lake"))),
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
s.stop("Data lake deleted successfully");
|
|
52
|
-
p.outro("✓ Done");
|
|
53
|
-
}),
|
|
54
|
-
).pipe(Command.withDescription("Delete a data lake from the cluster"));
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import { WingsClusterMetadata } from "@useairfoil/wings";
|
|
3
|
-
import { printTable } from "console-table-printer";
|
|
4
|
-
import { Effect } from "effect";
|
|
5
|
-
import { Command, Flag } from "effect/unstable/cli";
|
|
6
|
-
|
|
7
|
-
import { makeClusterMetadataLayer } from "../../../utils/client.js";
|
|
8
|
-
import { hostOption, portOption } from "../../../utils/options.js";
|
|
9
|
-
|
|
10
|
-
const nameOption = Flag.string("name").pipe(
|
|
11
|
-
Flag.withDescription("Data lake name in format: tenants/{tenant}/data-lakes/{data-lake}"),
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
export const getDataLakeCommand = Command.make(
|
|
15
|
-
"get-data-lake",
|
|
16
|
-
{
|
|
17
|
-
name: nameOption,
|
|
18
|
-
host: hostOption,
|
|
19
|
-
port: portOption,
|
|
20
|
-
},
|
|
21
|
-
({ name, host, port }) =>
|
|
22
|
-
Effect.gen(function* () {
|
|
23
|
-
const layer = makeClusterMetadataLayer(host, port);
|
|
24
|
-
|
|
25
|
-
const s = p.spinner();
|
|
26
|
-
s.start("Fetching data lake...");
|
|
27
|
-
|
|
28
|
-
const dataLake = yield* WingsClusterMetadata.getDataLake({ name }).pipe(
|
|
29
|
-
Effect.provide(layer),
|
|
30
|
-
Effect.tapError(() => Effect.sync(() => s.stop("Failed to get data lake"))),
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
s.stop("Data lake retrieved");
|
|
34
|
-
|
|
35
|
-
yield* Effect.sync(() => {
|
|
36
|
-
printTable([{ name: dataLake.name, type: dataLake.dataLakeConfig._tag || "-" }]);
|
|
37
|
-
p.outro("✓ Done");
|
|
38
|
-
});
|
|
39
|
-
}),
|
|
40
|
-
).pipe(Command.withDescription("Get details of a specific data lake"));
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import { WingsClusterMetadata } from "@useairfoil/wings";
|
|
3
|
-
import { printTable } from "console-table-printer";
|
|
4
|
-
import { Effect, Option } from "effect";
|
|
5
|
-
import { Command, Flag } from "effect/unstable/cli";
|
|
6
|
-
|
|
7
|
-
import { makeClusterMetadataLayer } from "../../../utils/client.js";
|
|
8
|
-
import { hostOption, pageSizeOption, pageTokenOption, portOption } from "../../../utils/options.js";
|
|
9
|
-
|
|
10
|
-
const parentOption = Flag.string("parent").pipe(
|
|
11
|
-
Flag.withDescription("Parent tenant in format: tenants/{tenant}"),
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
export const listDataLakesCommand = Command.make(
|
|
15
|
-
"list-data-lakes",
|
|
16
|
-
{
|
|
17
|
-
parent: parentOption,
|
|
18
|
-
pageSize: pageSizeOption,
|
|
19
|
-
pageToken: pageTokenOption,
|
|
20
|
-
host: hostOption,
|
|
21
|
-
port: portOption,
|
|
22
|
-
},
|
|
23
|
-
({ parent, pageSize, pageToken, host, port }) =>
|
|
24
|
-
Effect.gen(function* () {
|
|
25
|
-
const layer = makeClusterMetadataLayer(host, port);
|
|
26
|
-
|
|
27
|
-
const s = p.spinner();
|
|
28
|
-
s.start("Fetching data lakes...");
|
|
29
|
-
|
|
30
|
-
const response = yield* WingsClusterMetadata.listDataLakes({
|
|
31
|
-
parent,
|
|
32
|
-
pageSize,
|
|
33
|
-
pageToken: Option.getOrUndefined(pageToken),
|
|
34
|
-
}).pipe(
|
|
35
|
-
Effect.provide(layer),
|
|
36
|
-
Effect.tapError(() => Effect.sync(() => s.stop("Failed to list data lakes"))),
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
s.stop(`Found ${response.dataLakes.length} data lake(s)`);
|
|
40
|
-
|
|
41
|
-
yield* Effect.sync(() => {
|
|
42
|
-
if (response.dataLakes.length === 0) {
|
|
43
|
-
p.log.warn("No data lakes found");
|
|
44
|
-
} else {
|
|
45
|
-
printTable(
|
|
46
|
-
response.dataLakes.map(
|
|
47
|
-
(dataLake: { name: string; dataLakeConfig: { _tag?: string | null } }) => ({
|
|
48
|
-
name: dataLake.name,
|
|
49
|
-
type: dataLake.dataLakeConfig._tag || "-",
|
|
50
|
-
}),
|
|
51
|
-
),
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (response.nextPageToken) {
|
|
56
|
-
p.log.info(`Next page token: ${response.nextPageToken}`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
p.outro("✓ Done");
|
|
60
|
-
});
|
|
61
|
-
}),
|
|
62
|
-
).pipe(Command.withDescription("List all data lakes belonging to a tenant"));
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import { WingsClusterMetadata } from "@useairfoil/wings";
|
|
3
|
-
import { printTable } from "console-table-printer";
|
|
4
|
-
import { Effect, Option } from "effect";
|
|
5
|
-
import { Command, Flag } from "effect/unstable/cli";
|
|
6
|
-
|
|
7
|
-
import { makeClusterMetadataLayer } from "../../../utils/client.js";
|
|
8
|
-
import { hostOption, portOption } from "../../../utils/options.js";
|
|
9
|
-
|
|
10
|
-
const parentOption = Flag.string("parent").pipe(
|
|
11
|
-
Flag.withDescription("Parent tenant in format: tenants/{tenant}"),
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
const objectStoreIdOption = Flag.string("object-store-id").pipe(
|
|
15
|
-
Flag.withDescription("Unique identifier for the object store"),
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
const bucketNameOption = Flag.string("bucket-name").pipe(
|
|
19
|
-
Flag.withDescription("AWS S3 bucket name"),
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const prefixOption = Flag.string("prefix").pipe(
|
|
23
|
-
Flag.withDescription("Bucket prefix (optional)"),
|
|
24
|
-
Flag.optional,
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const accessKeyIdOption = Flag.string("access-key-id").pipe(
|
|
28
|
-
Flag.withDescription("AWS_ACCESS_KEY_ID"),
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const secretAccessKeyOption = Flag.string("secret-access-key").pipe(
|
|
32
|
-
Flag.withDescription("AWS_SECRET_ACCESS_KEY"),
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
const regionOption = Flag.string("region").pipe(
|
|
36
|
-
Flag.withDescription("AWS_DEFAULT_REGION (e.g., us-east-1)"),
|
|
37
|
-
Flag.optional,
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
export const createObjectStoreAwsCommand = Command.make(
|
|
41
|
-
"aws",
|
|
42
|
-
{
|
|
43
|
-
parent: parentOption,
|
|
44
|
-
objectStoreId: objectStoreIdOption,
|
|
45
|
-
bucketName: bucketNameOption,
|
|
46
|
-
prefix: prefixOption,
|
|
47
|
-
accessKeyId: accessKeyIdOption,
|
|
48
|
-
secretAccessKey: secretAccessKeyOption,
|
|
49
|
-
region: regionOption,
|
|
50
|
-
host: hostOption,
|
|
51
|
-
port: portOption,
|
|
52
|
-
},
|
|
53
|
-
({
|
|
54
|
-
parent,
|
|
55
|
-
objectStoreId,
|
|
56
|
-
bucketName,
|
|
57
|
-
prefix,
|
|
58
|
-
accessKeyId,
|
|
59
|
-
secretAccessKey,
|
|
60
|
-
region,
|
|
61
|
-
host,
|
|
62
|
-
port,
|
|
63
|
-
}) =>
|
|
64
|
-
Effect.gen(function* () {
|
|
65
|
-
p.intro("🗄️ Create AWS S3 Object Store");
|
|
66
|
-
|
|
67
|
-
const layer = makeClusterMetadataLayer(host, port);
|
|
68
|
-
|
|
69
|
-
const s = p.spinner();
|
|
70
|
-
s.start("Creating AWS S3 object store...");
|
|
71
|
-
|
|
72
|
-
const result = yield* WingsClusterMetadata.createObjectStore({
|
|
73
|
-
parent,
|
|
74
|
-
objectStoreId,
|
|
75
|
-
objectStoreConfig: {
|
|
76
|
-
_tag: "aws",
|
|
77
|
-
aws: {
|
|
78
|
-
bucketName,
|
|
79
|
-
prefix: Option.getOrUndefined(prefix),
|
|
80
|
-
accessKeyId,
|
|
81
|
-
secretAccessKey,
|
|
82
|
-
region: Option.getOrUndefined(region),
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
}).pipe(
|
|
86
|
-
Effect.provide(layer),
|
|
87
|
-
Effect.tapError(() => Effect.sync(() => s.stop("Failed to create AWS object store"))),
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
s.stop("AWS S3 object store created successfully");
|
|
91
|
-
|
|
92
|
-
yield* Effect.sync(() => {
|
|
93
|
-
printTable([
|
|
94
|
-
{
|
|
95
|
-
name: result.name,
|
|
96
|
-
type: "AWS S3",
|
|
97
|
-
bucket: bucketName,
|
|
98
|
-
region: Option.getOrUndefined(region) || "-",
|
|
99
|
-
},
|
|
100
|
-
]);
|
|
101
|
-
p.outro("✓ Done");
|
|
102
|
-
});
|
|
103
|
-
}),
|
|
104
|
-
).pipe(Command.withDescription("Create a new AWS S3 object store"));
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import * as p from "@clack/prompts";
|
|
2
|
-
import { WingsClusterMetadata } from "@useairfoil/wings";
|
|
3
|
-
import { printTable } from "console-table-printer";
|
|
4
|
-
import { Effect, Option } from "effect";
|
|
5
|
-
import { Command, Flag } from "effect/unstable/cli";
|
|
6
|
-
|
|
7
|
-
import { makeClusterMetadataLayer } from "../../../utils/client.js";
|
|
8
|
-
import { hostOption, portOption } from "../../../utils/options.js";
|
|
9
|
-
|
|
10
|
-
const parentOption = Flag.string("parent").pipe(
|
|
11
|
-
Flag.withDescription("Parent tenant in format: tenants/{tenant}"),
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
const objectStoreIdOption = Flag.string("object-store-id").pipe(
|
|
15
|
-
Flag.withDescription("Unique identifier for the object store"),
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
const containerNameOption = Flag.string("container-name").pipe(
|
|
19
|
-
Flag.withDescription("Azure container name"),
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const prefixOption = Flag.string("prefix").pipe(
|
|
23
|
-
Flag.withDescription("Container prefix (optional)"),
|
|
24
|
-
Flag.optional,
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const storageAccountNameOption = Flag.string("storage-account-name").pipe(
|
|
28
|
-
Flag.withDescription("AZURE_STORAGE_ACCOUNT_NAME"),
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const storageAccountKeyOption = Flag.string("storage-account-key").pipe(
|
|
32
|
-
Flag.withDescription("AZURE_STORAGE_ACCOUNT_KEY"),
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
export const createObjectStoreAzureCommand = Command.make(
|
|
36
|
-
"azure",
|
|
37
|
-
{
|
|
38
|
-
parent: parentOption,
|
|
39
|
-
objectStoreId: objectStoreIdOption,
|
|
40
|
-
containerName: containerNameOption,
|
|
41
|
-
prefix: prefixOption,
|
|
42
|
-
storageAccountName: storageAccountNameOption,
|
|
43
|
-
storageAccountKey: storageAccountKeyOption,
|
|
44
|
-
host: hostOption,
|
|
45
|
-
port: portOption,
|
|
46
|
-
},
|
|
47
|
-
({
|
|
48
|
-
parent,
|
|
49
|
-
objectStoreId,
|
|
50
|
-
containerName,
|
|
51
|
-
prefix,
|
|
52
|
-
storageAccountName,
|
|
53
|
-
storageAccountKey,
|
|
54
|
-
host,
|
|
55
|
-
port,
|
|
56
|
-
}) =>
|
|
57
|
-
Effect.gen(function* () {
|
|
58
|
-
p.intro("🗄️ Create Azure Blob Storage Object Store");
|
|
59
|
-
|
|
60
|
-
const layer = makeClusterMetadataLayer(host, port);
|
|
61
|
-
|
|
62
|
-
const s = p.spinner();
|
|
63
|
-
s.start("Creating Azure object store...");
|
|
64
|
-
|
|
65
|
-
const result = yield* WingsClusterMetadata.createObjectStore({
|
|
66
|
-
parent,
|
|
67
|
-
objectStoreId,
|
|
68
|
-
objectStoreConfig: {
|
|
69
|
-
_tag: "azure",
|
|
70
|
-
azure: {
|
|
71
|
-
containerName,
|
|
72
|
-
prefix: Option.getOrUndefined(prefix),
|
|
73
|
-
storageAccountName,
|
|
74
|
-
storageAccountKey,
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
}).pipe(
|
|
78
|
-
Effect.provide(layer),
|
|
79
|
-
Effect.tapError(() => Effect.sync(() => s.stop("Failed to create Azure object store"))),
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
s.stop("Azure object store created successfully");
|
|
83
|
-
|
|
84
|
-
yield* Effect.sync(() => {
|
|
85
|
-
printTable([
|
|
86
|
-
{
|
|
87
|
-
name: result.name,
|
|
88
|
-
type: "Azure Blob",
|
|
89
|
-
container: containerName,
|
|
90
|
-
account: storageAccountName,
|
|
91
|
-
},
|
|
92
|
-
]);
|
|
93
|
-
p.outro("✓ Done");
|
|
94
|
-
});
|
|
95
|
-
}),
|
|
96
|
-
).pipe(Command.withDescription("Create a new Azure Blob Storage object store"));
|