@osaas/cli 0.2.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/.prettierignore +1 -0
- package/LICENSE +21 -0
- package/dist/admin/cmd.d.ts +3 -0
- package/dist/admin/cmd.d.ts.map +1 -0
- package/dist/admin/cmd.js +62 -0
- package/dist/admin/cmd.js.map +1 -0
- package/dist/admin/instance.d.ts +3 -0
- package/dist/admin/instance.d.ts.map +1 -0
- package/dist/admin/instance.js +21 -0
- package/dist/admin/instance.js.map +1 -0
- package/dist/admin/token.d.ts +2 -0
- package/dist/admin/token.d.ts.map +1 -0
- package/dist/admin/token.js +30 -0
- package/dist/admin/token.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +42 -0
- package/dist/cli.js.map +1 -0
- package/dist/user/cmd.d.ts +5 -0
- package/dist/user/cmd.d.ts.map +1 -0
- package/dist/user/cmd.js +77 -0
- package/dist/user/cmd.js.map +1 -0
- package/dist/user/util.d.ts +5 -0
- package/dist/user/util.d.ts.map +1 -0
- package/dist/user/util.js +55 -0
- package/dist/user/util.js.map +1 -0
- package/package.json +33 -0
- package/readme.md +87 -0
- package/src/admin/cmd.ts +66 -0
- package/src/admin/instance.ts +30 -0
- package/src/admin/token.ts +32 -0
- package/src/cli.ts +16 -0
- package/src/user/cmd.ts +95 -0
- package/src/user/util.ts +46 -0
- package/tsconfig.json +7 -0
package/.prettierignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dist/
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Eyevinn Technology Open Source Software Center
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../../src/admin/cmd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,MAAM,CAAC,OAAO,UAAU,QAAQ,YA2D/B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const token_1 = require("./token");
|
|
5
|
+
const client_core_1 = require("@osaas/client-core");
|
|
6
|
+
const instance_1 = require("./instance");
|
|
7
|
+
const util_1 = require("../user/util");
|
|
8
|
+
function cmdAdmin() {
|
|
9
|
+
const admin = new commander_1.Command('admin');
|
|
10
|
+
admin
|
|
11
|
+
.command('gen-pat')
|
|
12
|
+
.description('Generate a personal access token')
|
|
13
|
+
.argument('<tenantId>', 'The tenant ID')
|
|
14
|
+
.argument('<username>', 'The username')
|
|
15
|
+
.action((tenantId, username) => {
|
|
16
|
+
try {
|
|
17
|
+
const pat = (0, token_1.generatePat)(tenantId, username);
|
|
18
|
+
console.log(pat);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
console.log(err.message);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
admin
|
|
25
|
+
.command('list-instances')
|
|
26
|
+
.description('List all instances for a service and tenant')
|
|
27
|
+
.argument('<tenantId>', 'The tenant ID')
|
|
28
|
+
.argument('<serviceId>', 'The service ID')
|
|
29
|
+
.action(async (tenantId, serviceId, options, command) => {
|
|
30
|
+
try {
|
|
31
|
+
const globalOpts = command.optsWithGlobals();
|
|
32
|
+
const environment = globalOpts?.env || 'prod';
|
|
33
|
+
(0, client_core_1.Log)().info(`Listing instance for tenant ${tenantId} and service ${serviceId} in ${environment}`);
|
|
34
|
+
const instances = await (0, instance_1.listInstancesForTenant)(tenantId, serviceId, environment);
|
|
35
|
+
instances.forEach((instance) => console.log(instance));
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.log(err.message);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
admin
|
|
42
|
+
.command('remove-instance')
|
|
43
|
+
.description('Remove an instance')
|
|
44
|
+
.argument('<tenantId>', 'The Tenant Id')
|
|
45
|
+
.argument('<serviceId>', 'The Service Id')
|
|
46
|
+
.argument('<name>', 'The instance name')
|
|
47
|
+
.action(async (tenantId, serviceId, name, options, command) => {
|
|
48
|
+
try {
|
|
49
|
+
const globalOpts = command.optsWithGlobals();
|
|
50
|
+
const environment = globalOpts?.env || 'prod';
|
|
51
|
+
(0, client_core_1.Log)().info(`Removing instance ${name} for tenant ${tenantId} and service ${serviceId} in ${environment}`);
|
|
52
|
+
await (0, util_1.confirm)('Are you sure you want to remove this instance? (yes/no) ');
|
|
53
|
+
await (0, instance_1.removeInstanceForTenant)(tenantId, serviceId, name, environment);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.log(err.message);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return admin;
|
|
60
|
+
}
|
|
61
|
+
exports.default = cmdAdmin;
|
|
62
|
+
//# sourceMappingURL=cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmd.js","sourceRoot":"","sources":["../../src/admin/cmd.ts"],"names":[],"mappings":";;AAAA,yCAAoC;AACpC,mCAAsC;AACtC,oDAAyC;AACzC,yCAA6E;AAC7E,uCAAuC;AAEvC,SAAwB,QAAQ;IAC9B,MAAM,KAAK,GAAG,IAAI,mBAAO,CAAC,OAAO,CAAC,CAAC;IACnC,KAAK;SACF,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;SACvC,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC;SACtC,MAAM,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE;QAC7B,IAAI;YACF,MAAM,GAAG,GAAG,IAAA,mBAAW,EAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAClB;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,CAAC,GAAG,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;SACrC;IACH,CAAC,CAAC,CAAC;IACL,KAAK;SACF,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,6CAA6C,CAAC;SAC1D,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;SACvC,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC;SACzC,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QACtD,IAAI;YACF,MAAM,UAAU,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;YAC7C,MAAM,WAAW,GAAG,UAAU,EAAE,GAAG,IAAI,MAAM,CAAC;YAC9C,IAAA,iBAAG,GAAE,CAAC,IAAI,CACR,+BAA+B,QAAQ,gBAAgB,SAAS,OAAO,WAAW,EAAE,CACrF,CAAC;YACF,MAAM,SAAS,GAAG,MAAM,IAAA,iCAAsB,EAC5C,QAAQ,EACR,SAAS,EACT,WAAW,CACZ,CAAC;YACF,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;SACxD;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,CAAC,GAAG,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;SACrC;IACH,CAAC,CAAC,CAAC;IACL,KAAK;SACF,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,oBAAoB,CAAC;SACjC,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;SACvC,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC;SACzC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;SACvC,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;QAC5D,IAAI;YACF,MAAM,UAAU,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;YAC7C,MAAM,WAAW,GAAG,UAAU,EAAE,GAAG,IAAI,MAAM,CAAC;YAC9C,IAAA,iBAAG,GAAE,CAAC,IAAI,CACR,qBAAqB,IAAI,eAAe,QAAQ,gBAAgB,SAAS,OAAO,WAAW,EAAE,CAC9F,CAAC;YACF,MAAM,IAAA,cAAO,EACX,0DAA0D,CAC3D,CAAC;YACF,MAAM,IAAA,kCAAuB,EAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;SACvE;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,CAAC,GAAG,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;SACrC;IACH,CAAC,CAAC,CAAC;IACL,OAAO,KAAK,CAAC;AACf,CAAC;AA3DD,2BA2DC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function listInstancesForTenant(tenantId: string, serviceId: string, environment: string): Promise<string[]>;
|
|
2
|
+
export declare function removeInstanceForTenant(tenantId: string, serviceId: string, name: string, environment: string): Promise<void>;
|
|
3
|
+
//# sourceMappingURL=instance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/admin/instance.ts"],"names":[],"mappings":"AAGA,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAQnB;AAED,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,iBAQpB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.removeInstanceForTenant = exports.listInstancesForTenant = void 0;
|
|
4
|
+
const client_core_1 = require("@osaas/client-core");
|
|
5
|
+
const token_1 = require("./token");
|
|
6
|
+
async function listInstancesForTenant(tenantId, serviceId, environment) {
|
|
7
|
+
const pat = (0, token_1.generatePat)(tenantId, 'osc-admin');
|
|
8
|
+
const ctx = new client_core_1.Context({ personalAccessToken: pat, environment });
|
|
9
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
10
|
+
const instances = await (0, client_core_1.listInstances)(ctx, serviceId, serviceAccessToken);
|
|
11
|
+
return instances.map((instance) => instance.name);
|
|
12
|
+
}
|
|
13
|
+
exports.listInstancesForTenant = listInstancesForTenant;
|
|
14
|
+
async function removeInstanceForTenant(tenantId, serviceId, name, environment) {
|
|
15
|
+
const pat = (0, token_1.generatePat)(tenantId, 'osc-admin');
|
|
16
|
+
const ctx = new client_core_1.Context({ personalAccessToken: pat, environment });
|
|
17
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
18
|
+
await (0, client_core_1.removeInstance)(ctx, serviceId, name, serviceAccessToken);
|
|
19
|
+
}
|
|
20
|
+
exports.removeInstanceForTenant = removeInstanceForTenant;
|
|
21
|
+
//# sourceMappingURL=instance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.js","sourceRoot":"","sources":["../../src/admin/instance.ts"],"names":[],"mappings":";;;AAAA,oDAA4E;AAC5E,mCAAsC;AAE/B,KAAK,UAAU,sBAAsB,CAC1C,QAAgB,EAChB,SAAiB,EACjB,WAAmB;IAEnB,MAAM,GAAG,GAAG,IAAA,mBAAW,EAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAE/C,MAAM,GAAG,GAAG,IAAI,qBAAO,CAAC,EAAE,mBAAmB,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;IACnE,MAAM,kBAAkB,GAAG,MAAM,GAAG,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAEtE,MAAM,SAAS,GAAG,MAAM,IAAA,2BAAa,EAAC,GAAG,EAAE,SAAS,EAAE,kBAAkB,CAAC,CAAC;IAC1E,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,QAA0B,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC;AAZD,wDAYC;AAEM,KAAK,UAAU,uBAAuB,CAC3C,QAAgB,EAChB,SAAiB,EACjB,IAAY,EACZ,WAAmB;IAEnB,MAAM,GAAG,GAAG,IAAA,mBAAW,EAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAE/C,MAAM,GAAG,GAAG,IAAI,qBAAO,CAAC,EAAE,mBAAmB,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;IACnE,MAAM,kBAAkB,GAAG,MAAM,GAAG,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAEtE,MAAM,IAAA,4BAAc,EAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;AACjE,CAAC;AAZD,0DAYC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/admin/token.ts"],"names":[],"mappings":"AAUA,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,UAkBvB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generatePat = void 0;
|
|
4
|
+
const fast_jwt_1 = require("fast-jwt");
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
function readPatSecret() {
|
|
7
|
+
if (!process.env.PAT_SECRET) {
|
|
8
|
+
throw new Error('PAT_SECRET must be set');
|
|
9
|
+
}
|
|
10
|
+
return process.env.PAT_SECRET;
|
|
11
|
+
}
|
|
12
|
+
function generatePat(tenantId, userId, serviceLimits) {
|
|
13
|
+
const signSync = (0, fast_jwt_1.createSigner)({
|
|
14
|
+
key: readPatSecret(),
|
|
15
|
+
iss: 'token.osaas.eyevinn.se'
|
|
16
|
+
});
|
|
17
|
+
const iat = Math.round(Date.now() / 1000);
|
|
18
|
+
const patId = (0, node_crypto_1.randomUUID)();
|
|
19
|
+
const jwtClaims = {
|
|
20
|
+
iat,
|
|
21
|
+
tenantId,
|
|
22
|
+
userId,
|
|
23
|
+
patId,
|
|
24
|
+
serviceLimits
|
|
25
|
+
};
|
|
26
|
+
const token = signSync(jwtClaims);
|
|
27
|
+
return token;
|
|
28
|
+
}
|
|
29
|
+
exports.generatePat = generatePat;
|
|
30
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/admin/token.ts"],"names":[],"mappings":";;;AAAA,uCAAwC;AACxC,6CAAyC;AAEzC,SAAS,aAAa;IACpB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE;QAC3B,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;KAC3C;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;AAChC,CAAC;AAED,SAAgB,WAAW,CACzB,QAAgB,EAChB,MAAc,EACd,aAAsB;IAEtB,MAAM,QAAQ,GAAG,IAAA,uBAAY,EAAC;QAC5B,GAAG,EAAE,aAAa,EAAE;QACpB,GAAG,EAAE,wBAAwB;KAC9B,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAA,wBAAU,GAAE,CAAC;IAC3B,MAAM,SAAS,GAAG;QAChB,GAAG;QACH,QAAQ;QACR,MAAM;QACN,KAAK;QACL,aAAa;KACd,CAAC;IACF,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC;AACf,CAAC;AArBD,kCAqBC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
20
|
+
if (mod && mod.__esModule) return mod;
|
|
21
|
+
var result = {};
|
|
22
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
23
|
+
__setModuleDefault(result, mod);
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
26
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
27
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
28
|
+
};
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
const commander_1 = require("commander");
|
|
31
|
+
const cmd_1 = __importDefault(require("./admin/cmd"));
|
|
32
|
+
const cmdUser = __importStar(require("./user/cmd"));
|
|
33
|
+
const cli = new commander_1.Command();
|
|
34
|
+
cli
|
|
35
|
+
.configureHelp({ showGlobalOptions: true })
|
|
36
|
+
.option('--env <environment>', 'Environment to use');
|
|
37
|
+
cli.addCommand((0, cmd_1.default)());
|
|
38
|
+
cli.addCommand(cmdUser.cmdList());
|
|
39
|
+
cli.addCommand(cmdUser.cmdCreate());
|
|
40
|
+
cli.addCommand(cmdUser.cmdRemove());
|
|
41
|
+
cli.parse(process.argv);
|
|
42
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,yCAAoC;AACpC,sDAAmC;AACnC,oDAAsC;AAEtC,MAAM,GAAG,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE1B,GAAG;KACA,aAAa,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;KAC1C,MAAM,CAAC,qBAAqB,EAAE,oBAAoB,CAAC,CAAC;AACvD,GAAG,CAAC,UAAU,CAAC,IAAA,aAAQ,GAAE,CAAC,CAAC;AAC3B,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AAClC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;AACpC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;AACpC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmd.d.ts","sourceRoot":"","sources":["../../src/user/cmd.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,wBAAgB,OAAO,YA0BtB;AAED,wBAAgB,SAAS,YAiCxB;AAED,wBAAgB,SAAS,YAsBxB"}
|
package/dist/user/cmd.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cmdRemove = exports.cmdCreate = exports.cmdList = void 0;
|
|
4
|
+
const client_core_1 = require("@osaas/client-core");
|
|
5
|
+
const commander_1 = require("commander");
|
|
6
|
+
const util_1 = require("./util");
|
|
7
|
+
function cmdList() {
|
|
8
|
+
const list = new commander_1.Command('list');
|
|
9
|
+
list
|
|
10
|
+
.description('List all my service instances')
|
|
11
|
+
.argument('<serviceId>', 'The Service Id')
|
|
12
|
+
.action(async (serviceId, options, command) => {
|
|
13
|
+
try {
|
|
14
|
+
const globalOpts = command.optsWithGlobals();
|
|
15
|
+
const environment = globalOpts?.env || 'prod';
|
|
16
|
+
const ctx = new client_core_1.Context({ environment });
|
|
17
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
18
|
+
const instances = await (0, client_core_1.listInstances)(ctx, serviceId, serviceAccessToken);
|
|
19
|
+
return instances.map((instance) => console.log(instance.name));
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
console.log(err.message);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return list;
|
|
26
|
+
}
|
|
27
|
+
exports.cmdList = cmdList;
|
|
28
|
+
function cmdCreate() {
|
|
29
|
+
const create = new commander_1.Command('create');
|
|
30
|
+
create
|
|
31
|
+
.description('Create a service instance')
|
|
32
|
+
.argument('<serviceId>', 'The Service Id')
|
|
33
|
+
.argument('<name>', 'The instance name')
|
|
34
|
+
.option('-o, --instance-options [instanceOptions...]', 'Instance options as key value pairs (e.g. -o key1=value1 -o key2=value2)')
|
|
35
|
+
.action(async (serviceId, name, options, command) => {
|
|
36
|
+
try {
|
|
37
|
+
const globalOpts = command.optsWithGlobals();
|
|
38
|
+
const payload = (0, util_1.instanceOptsToPayload)(options.instanceOptions);
|
|
39
|
+
payload['name'] = name;
|
|
40
|
+
const environment = globalOpts?.env || 'prod';
|
|
41
|
+
const ctx = new client_core_1.Context({ environment });
|
|
42
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
43
|
+
const instance = await (0, client_core_1.createInstance)(ctx, serviceId, serviceAccessToken, payload);
|
|
44
|
+
console.log('Instance created:');
|
|
45
|
+
console.log(instance);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
console.log(err.message);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return create;
|
|
52
|
+
}
|
|
53
|
+
exports.cmdCreate = cmdCreate;
|
|
54
|
+
function cmdRemove() {
|
|
55
|
+
const remove = new commander_1.Command('remove');
|
|
56
|
+
remove
|
|
57
|
+
.description('Remove a service instance')
|
|
58
|
+
.argument('<serviceId>', 'The Service Id')
|
|
59
|
+
.argument('<name>', 'The instance name')
|
|
60
|
+
.action(async (serviceId, name, options, command) => {
|
|
61
|
+
try {
|
|
62
|
+
const globalOpts = command.optsWithGlobals();
|
|
63
|
+
const environment = globalOpts?.env || 'prod';
|
|
64
|
+
const ctx = new client_core_1.Context({ environment });
|
|
65
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
66
|
+
await (0, util_1.confirm)(`Are you sure you want to remove ${name}? (yes/no) `);
|
|
67
|
+
await (0, client_core_1.removeInstance)(ctx, serviceId, name, serviceAccessToken);
|
|
68
|
+
console.log('Instance removed');
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.log(err.message);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return remove;
|
|
75
|
+
}
|
|
76
|
+
exports.cmdRemove = cmdRemove;
|
|
77
|
+
//# sourceMappingURL=cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmd.js","sourceRoot":"","sources":["../../src/user/cmd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/user/util.ts"],"names":[],"mappings":"AAEA,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS;;EAwB/D;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.confirm = exports.instanceOptsToPayload = void 0;
|
|
7
|
+
const node_readline_1 = __importDefault(require("node:readline"));
|
|
8
|
+
function instanceOptsToPayload(opts) {
|
|
9
|
+
const payload = {};
|
|
10
|
+
if (opts) {
|
|
11
|
+
opts.map((kv) => {
|
|
12
|
+
const [key, value] = kv.split('=');
|
|
13
|
+
const subkeys = key.split('.');
|
|
14
|
+
if (subkeys.length > 1) {
|
|
15
|
+
let current = payload;
|
|
16
|
+
subkeys.forEach((subkey, index) => {
|
|
17
|
+
if (index === subkeys.length - 1) {
|
|
18
|
+
current[subkey] = value;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
if (!current[subkey]) {
|
|
22
|
+
current[subkey] = {};
|
|
23
|
+
}
|
|
24
|
+
current = current[subkey];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
payload[key] = value;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return payload;
|
|
34
|
+
}
|
|
35
|
+
exports.instanceOptsToPayload = instanceOptsToPayload;
|
|
36
|
+
async function confirm(message) {
|
|
37
|
+
const rl = node_readline_1.default.createInterface({
|
|
38
|
+
input: process.stdin,
|
|
39
|
+
output: process.stdout
|
|
40
|
+
});
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
rl.question(message || 'Are you sure? (yes/no) ', (answer) => {
|
|
43
|
+
rl.close();
|
|
44
|
+
const cleaned = answer.trim().toLowerCase();
|
|
45
|
+
if (cleaned === 'yes') {
|
|
46
|
+
resolve();
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
reject(new Error('aborted by user'));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
exports.confirm = confirm;
|
|
55
|
+
//# sourceMappingURL=util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/user/util.ts"],"names":[],"mappings":";;;;;;AAAA,kEAAqC;AAErC,SAAgB,qBAAqB,CAAC,IAA0B;IAC9D,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,IAAI,IAAI,EAAE;QACR,IAAI,CAAC,GAAG,CAAC,CAAC,EAAU,EAAE,EAAE;YACtB,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnC,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;gBACtB,IAAI,OAAO,GAAG,OAAO,CAAC;gBACtB,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;oBAChC,IAAI,KAAK,KAAK,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;wBAChC,OAAO,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;qBACzB;yBAAM;wBACL,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;4BACpB,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;yBACtB;wBACD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;qBAC3B;gBACH,CAAC,CAAC,CAAC;aACJ;iBAAM;gBACL,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;aACtB;QACH,CAAC,CAAC,CAAC;KACJ;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAxBD,sDAwBC;AAEM,KAAK,UAAU,OAAO,CAAC,OAA2B;IACvD,MAAM,EAAE,GAAG,uBAAQ,CAAC,eAAe,CAAC;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,EAAE,CAAC,QAAQ,CAAC,OAAO,IAAI,yBAAyB,EAAE,CAAC,MAAM,EAAE,EAAE;YAC3D,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC5C,IAAI,OAAO,KAAK,KAAK,EAAE;gBACrB,OAAO,EAAE,CAAC;aACX;iBAAM;gBACL,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;aACtC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAjBD,0BAiBC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@osaas/cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Open Source Cloud CLI",
|
|
5
|
+
"author": "Eyevinn Technology <work@eyevinn.se>",
|
|
6
|
+
"homepage": "https://www.osaas.io",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"main": "dist/cli.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"osc": "./dist/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/Eyevinn/osaas-client-ts.git"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.json",
|
|
18
|
+
"lint": "eslint .",
|
|
19
|
+
"pretty": "prettier --check --ignore-unknown .",
|
|
20
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
21
|
+
"test": "jest --pass-with-no-tests"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@osaas/client-core": "^0.4.0",
|
|
25
|
+
"chalk": "4.1.2",
|
|
26
|
+
"commander": "^12.1.0",
|
|
27
|
+
"fast-jwt": "^4.0.1"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"gitHead": "71d6b915ca0ff5bfdcc1a0886ed7c9f816343fa1"
|
|
33
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Command Line Utility for Open Source Cloud
|
|
2
|
+
|
|
3
|
+
CLI for working and scripting with [Open Source Cloud](www.osaas.io)
|
|
4
|
+
|
|
5
|
+
Prerequisites:
|
|
6
|
+
|
|
7
|
+
- Node >18
|
|
8
|
+
- An Open Source Cloud account and a Personal Access Token at hand
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
npm install -g @osaas/cli
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
% osc
|
|
20
|
+
Usage: osc [options] [command]
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
--env <environment> Environment to use
|
|
24
|
+
-h, --help display help for command
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
admin
|
|
28
|
+
list <serviceId> List all my service instances
|
|
29
|
+
create [options] <serviceId> <name> Create a service instance
|
|
30
|
+
remove <serviceId> <name> Remove a service instance
|
|
31
|
+
help [command] display help for command
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
To display help for subcommand `admin` you enter
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
% osc help admin
|
|
38
|
+
Usage: osc admin [options] [command]
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
-h, --help display help for command
|
|
42
|
+
|
|
43
|
+
Commands:
|
|
44
|
+
gen-pat <tenantId> <username> Generate a personal access token
|
|
45
|
+
list-instances <tenantId> <serviceId> List all instances for a service and tenant
|
|
46
|
+
remove-instance <tenantId> <serviceId> <name> Remove an instance
|
|
47
|
+
help [command] display help for command
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Examples
|
|
51
|
+
|
|
52
|
+
### List all my channel-engine instances
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
% export OSC_ACCESS_TOKEN=<pat>
|
|
56
|
+
% osc list channel-engine
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Create a channel from a VOD on loop and insert ad breaks
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
% osc create channel-engine cli -o \
|
|
63
|
+
type=Loop \
|
|
64
|
+
url=https://lab.cdn.eyevinn.technology/stswetvplus-promo-2023-5GBm231Mkz.mov/manifest.m3u8 \
|
|
65
|
+
opts.useDemuxedAudio=false \
|
|
66
|
+
opts.useVttSubtitles=false \
|
|
67
|
+
opts.preroll.url=http://maitv-vod.lab.eyevinn.technology/VINN.mp4/master.m3u8 \
|
|
68
|
+
opts.preroll.duration=10500
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Remove a channel-engine instance with name `clidemo`
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
% osc remove channel-engine clidemo
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### List all channel-engine instance for tenant `eyevinn` as an OSC super admin
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
PAT_SECRET=<pat-secret> osc admin list-instances eyevinn channel-engine
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Remove a channel-engine instance in dev env for tenant `asdasd` as an OSC super admin
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
PAT_SECRET=<pat-secret> osc --env dev admin remove-instance asdasd channel-engine mychannel
|
|
87
|
+
```
|
package/src/admin/cmd.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { generatePat } from './token';
|
|
3
|
+
import { Log } from '@osaas/client-core';
|
|
4
|
+
import { listInstancesForTenant, removeInstanceForTenant } from './instance';
|
|
5
|
+
import { confirm } from '../user/util';
|
|
6
|
+
|
|
7
|
+
export default function cmdAdmin() {
|
|
8
|
+
const admin = new Command('admin');
|
|
9
|
+
admin
|
|
10
|
+
.command('gen-pat')
|
|
11
|
+
.description('Generate a personal access token')
|
|
12
|
+
.argument('<tenantId>', 'The tenant ID')
|
|
13
|
+
.argument('<username>', 'The username')
|
|
14
|
+
.action((tenantId, username) => {
|
|
15
|
+
try {
|
|
16
|
+
const pat = generatePat(tenantId, username);
|
|
17
|
+
console.log(pat);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
console.log((err as Error).message);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
admin
|
|
23
|
+
.command('list-instances')
|
|
24
|
+
.description('List all instances for a service and tenant')
|
|
25
|
+
.argument('<tenantId>', 'The tenant ID')
|
|
26
|
+
.argument('<serviceId>', 'The service ID')
|
|
27
|
+
.action(async (tenantId, serviceId, options, command) => {
|
|
28
|
+
try {
|
|
29
|
+
const globalOpts = command.optsWithGlobals();
|
|
30
|
+
const environment = globalOpts?.env || 'prod';
|
|
31
|
+
Log().info(
|
|
32
|
+
`Listing instance for tenant ${tenantId} and service ${serviceId} in ${environment}`
|
|
33
|
+
);
|
|
34
|
+
const instances = await listInstancesForTenant(
|
|
35
|
+
tenantId,
|
|
36
|
+
serviceId,
|
|
37
|
+
environment
|
|
38
|
+
);
|
|
39
|
+
instances.forEach((instance) => console.log(instance));
|
|
40
|
+
} catch (err) {
|
|
41
|
+
console.log((err as Error).message);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
admin
|
|
45
|
+
.command('remove-instance')
|
|
46
|
+
.description('Remove an instance')
|
|
47
|
+
.argument('<tenantId>', 'The Tenant Id')
|
|
48
|
+
.argument('<serviceId>', 'The Service Id')
|
|
49
|
+
.argument('<name>', 'The instance name')
|
|
50
|
+
.action(async (tenantId, serviceId, name, options, command) => {
|
|
51
|
+
try {
|
|
52
|
+
const globalOpts = command.optsWithGlobals();
|
|
53
|
+
const environment = globalOpts?.env || 'prod';
|
|
54
|
+
Log().info(
|
|
55
|
+
`Removing instance ${name} for tenant ${tenantId} and service ${serviceId} in ${environment}`
|
|
56
|
+
);
|
|
57
|
+
await confirm(
|
|
58
|
+
'Are you sure you want to remove this instance? (yes/no) '
|
|
59
|
+
);
|
|
60
|
+
await removeInstanceForTenant(tenantId, serviceId, name, environment);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.log((err as Error).message);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return admin;
|
|
66
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Context, listInstances, removeInstance } from '@osaas/client-core';
|
|
2
|
+
import { generatePat } from './token';
|
|
3
|
+
|
|
4
|
+
export async function listInstancesForTenant(
|
|
5
|
+
tenantId: string,
|
|
6
|
+
serviceId: string,
|
|
7
|
+
environment: string
|
|
8
|
+
): Promise<string[]> {
|
|
9
|
+
const pat = generatePat(tenantId, 'osc-admin');
|
|
10
|
+
|
|
11
|
+
const ctx = new Context({ personalAccessToken: pat, environment });
|
|
12
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
13
|
+
|
|
14
|
+
const instances = await listInstances(ctx, serviceId, serviceAccessToken);
|
|
15
|
+
return instances.map((instance: { name: string }) => instance.name);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function removeInstanceForTenant(
|
|
19
|
+
tenantId: string,
|
|
20
|
+
serviceId: string,
|
|
21
|
+
name: string,
|
|
22
|
+
environment: string
|
|
23
|
+
) {
|
|
24
|
+
const pat = generatePat(tenantId, 'osc-admin');
|
|
25
|
+
|
|
26
|
+
const ctx = new Context({ personalAccessToken: pat, environment });
|
|
27
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
28
|
+
|
|
29
|
+
await removeInstance(ctx, serviceId, name, serviceAccessToken);
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createSigner } from 'fast-jwt';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
|
|
4
|
+
function readPatSecret(): string {
|
|
5
|
+
if (!process.env.PAT_SECRET) {
|
|
6
|
+
throw new Error('PAT_SECRET must be set');
|
|
7
|
+
}
|
|
8
|
+
return process.env.PAT_SECRET;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function generatePat(
|
|
12
|
+
tenantId: string,
|
|
13
|
+
userId: string,
|
|
14
|
+
serviceLimits?: number
|
|
15
|
+
) {
|
|
16
|
+
const signSync = createSigner({
|
|
17
|
+
key: readPatSecret(),
|
|
18
|
+
iss: 'token.osaas.eyevinn.se'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const iat = Math.round(Date.now() / 1000);
|
|
22
|
+
const patId = randomUUID();
|
|
23
|
+
const jwtClaims = {
|
|
24
|
+
iat,
|
|
25
|
+
tenantId,
|
|
26
|
+
userId,
|
|
27
|
+
patId,
|
|
28
|
+
serviceLimits
|
|
29
|
+
};
|
|
30
|
+
const token = signSync(jwtClaims);
|
|
31
|
+
return token;
|
|
32
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import cmdAdmin from './admin/cmd';
|
|
5
|
+
import * as cmdUser from './user/cmd';
|
|
6
|
+
|
|
7
|
+
const cli = new Command();
|
|
8
|
+
|
|
9
|
+
cli
|
|
10
|
+
.configureHelp({ showGlobalOptions: true })
|
|
11
|
+
.option('--env <environment>', 'Environment to use');
|
|
12
|
+
cli.addCommand(cmdAdmin());
|
|
13
|
+
cli.addCommand(cmdUser.cmdList());
|
|
14
|
+
cli.addCommand(cmdUser.cmdCreate());
|
|
15
|
+
cli.addCommand(cmdUser.cmdRemove());
|
|
16
|
+
cli.parse(process.argv);
|
package/src/user/cmd.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Context,
|
|
3
|
+
createInstance,
|
|
4
|
+
listInstances,
|
|
5
|
+
removeInstance
|
|
6
|
+
} from '@osaas/client-core';
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import { confirm, instanceOptsToPayload } from './util';
|
|
9
|
+
|
|
10
|
+
export function cmdList() {
|
|
11
|
+
const list = new Command('list');
|
|
12
|
+
|
|
13
|
+
list
|
|
14
|
+
.description('List all my service instances')
|
|
15
|
+
.argument('<serviceId>', 'The Service Id')
|
|
16
|
+
.action(async (serviceId, options, command) => {
|
|
17
|
+
try {
|
|
18
|
+
const globalOpts = command.optsWithGlobals();
|
|
19
|
+
const environment = globalOpts?.env || 'prod';
|
|
20
|
+
const ctx = new Context({ environment });
|
|
21
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
22
|
+
|
|
23
|
+
const instances = await listInstances(
|
|
24
|
+
ctx,
|
|
25
|
+
serviceId,
|
|
26
|
+
serviceAccessToken
|
|
27
|
+
);
|
|
28
|
+
return instances.map((instance: { name: string }) =>
|
|
29
|
+
console.log(instance.name)
|
|
30
|
+
);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
console.log((err as Error).message);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return list;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function cmdCreate() {
|
|
39
|
+
const create = new Command('create');
|
|
40
|
+
|
|
41
|
+
create
|
|
42
|
+
.description('Create a service instance')
|
|
43
|
+
.argument('<serviceId>', 'The Service Id')
|
|
44
|
+
.argument('<name>', 'The instance name')
|
|
45
|
+
.option(
|
|
46
|
+
'-o, --instance-options [instanceOptions...]',
|
|
47
|
+
'Instance options as key value pairs (e.g. -o key1=value1 -o key2=value2)'
|
|
48
|
+
)
|
|
49
|
+
.action(async (serviceId, name, options, command) => {
|
|
50
|
+
try {
|
|
51
|
+
const globalOpts = command.optsWithGlobals();
|
|
52
|
+
const payload = instanceOptsToPayload(options.instanceOptions);
|
|
53
|
+
payload['name'] = name;
|
|
54
|
+
const environment = globalOpts?.env || 'prod';
|
|
55
|
+
const ctx = new Context({ environment });
|
|
56
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
57
|
+
|
|
58
|
+
const instance = await createInstance(
|
|
59
|
+
ctx,
|
|
60
|
+
serviceId,
|
|
61
|
+
serviceAccessToken,
|
|
62
|
+
payload
|
|
63
|
+
);
|
|
64
|
+
console.log('Instance created:');
|
|
65
|
+
console.log(instance);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
console.log((err as Error).message);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return create;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function cmdRemove() {
|
|
74
|
+
const remove = new Command('remove');
|
|
75
|
+
|
|
76
|
+
remove
|
|
77
|
+
.description('Remove a service instance')
|
|
78
|
+
.argument('<serviceId>', 'The Service Id')
|
|
79
|
+
.argument('<name>', 'The instance name')
|
|
80
|
+
.action(async (serviceId, name, options, command) => {
|
|
81
|
+
try {
|
|
82
|
+
const globalOpts = command.optsWithGlobals();
|
|
83
|
+
const environment = globalOpts?.env || 'prod';
|
|
84
|
+
const ctx = new Context({ environment });
|
|
85
|
+
const serviceAccessToken = await ctx.getServiceAccessToken(serviceId);
|
|
86
|
+
|
|
87
|
+
await confirm(`Are you sure you want to remove ${name}? (yes/no) `);
|
|
88
|
+
await removeInstance(ctx, serviceId, name, serviceAccessToken);
|
|
89
|
+
console.log('Instance removed');
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.log((err as Error).message);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
return remove;
|
|
95
|
+
}
|
package/src/user/util.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import readline from 'node:readline';
|
|
2
|
+
|
|
3
|
+
export function instanceOptsToPayload(opts: string[] | undefined) {
|
|
4
|
+
const payload: { [key: string]: any } = {};
|
|
5
|
+
if (opts) {
|
|
6
|
+
opts.map((kv: string) => {
|
|
7
|
+
const [key, value] = kv.split('=');
|
|
8
|
+
const subkeys = key.split('.');
|
|
9
|
+
if (subkeys.length > 1) {
|
|
10
|
+
let current = payload;
|
|
11
|
+
subkeys.forEach((subkey, index) => {
|
|
12
|
+
if (index === subkeys.length - 1) {
|
|
13
|
+
current[subkey] = value;
|
|
14
|
+
} else {
|
|
15
|
+
if (!current[subkey]) {
|
|
16
|
+
current[subkey] = {};
|
|
17
|
+
}
|
|
18
|
+
current = current[subkey];
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
} else {
|
|
22
|
+
payload[key] = value;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return payload;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function confirm(message: string | undefined): Promise<void> {
|
|
30
|
+
const rl = readline.createInterface({
|
|
31
|
+
input: process.stdin,
|
|
32
|
+
output: process.stdout
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
rl.question(message || 'Are you sure? (yes/no) ', (answer) => {
|
|
37
|
+
rl.close();
|
|
38
|
+
const cleaned = answer.trim().toLowerCase();
|
|
39
|
+
if (cleaned === 'yes') {
|
|
40
|
+
resolve();
|
|
41
|
+
} else {
|
|
42
|
+
reject(new Error('aborted by user'));
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|