@contrail/cli 2.0.7 → 2.0.9
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/README.md +10 -9
- package/dist/api/users.d.ts +2 -0
- package/dist/api/users.js +16 -0
- package/dist/commands/groups/export.d.ts +1 -1
- package/dist/commands/groups/export.js +9 -10
- package/dist/commands/groups/upload.js +49 -72
- package/dist/commands/instance/export.js +2 -0
- package/dist/commands/instance/import.js +6 -2
- package/dist/commands/types/getAll.d.ts +1 -1
- package/dist/commands/types/getAll.js +35 -5
- package/dist/commands/types/loadAll.d.ts +1 -1
- package/dist/commands/types/loadAll.js +4 -2
- package/dist/commands/types/uploadTypePropertyPolicies.js +37 -6
- package/dist/commands/users/export.d.ts +1 -1
- package/dist/commands/users/export.js +4 -6
- package/dist/helpers/file-helpers.js +1 -1
- package/oclif.manifest.json +8 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ $ npm install -g @contrail/cli
|
|
|
15
15
|
$ contrail COMMAND
|
|
16
16
|
running command...
|
|
17
17
|
$ contrail (--version)
|
|
18
|
-
@contrail/cli/2.0.
|
|
18
|
+
@contrail/cli/2.0.9 darwin-arm64 node-v18.13.0
|
|
19
19
|
$ contrail --help [COMMAND]
|
|
20
20
|
USAGE
|
|
21
21
|
$ contrail COMMAND
|
|
@@ -331,11 +331,11 @@ Export all groups in the org.
|
|
|
331
331
|
|
|
332
332
|
```
|
|
333
333
|
USAGE
|
|
334
|
-
$ contrail groups export [-
|
|
334
|
+
$ contrail groups export [-f <value>] [--overwrite]
|
|
335
335
|
|
|
336
336
|
FLAGS
|
|
337
|
-
-
|
|
338
|
-
--overwrite
|
|
337
|
+
-f, --outFile=<value> [default: groups.yml] The location for the file to be saved
|
|
338
|
+
--overwrite Replaces existing files if they exist
|
|
339
339
|
|
|
340
340
|
DESCRIPTION
|
|
341
341
|
Export all groups in the org.
|
|
@@ -408,10 +408,11 @@ Import the data to an instance, including types and users
|
|
|
408
408
|
|
|
409
409
|
```
|
|
410
410
|
USAGE
|
|
411
|
-
$ contrail instance import [
|
|
411
|
+
$ contrail instance import [-d <value>]
|
|
412
412
|
|
|
413
413
|
FLAGS
|
|
414
|
-
--dir=<value> [default: .] The directory from which to export the instance data. Defaults to the current
|
|
414
|
+
-d, --dir=<value> [default: .] The directory from which to export the instance data. Defaults to the current
|
|
415
|
+
directory
|
|
415
416
|
|
|
416
417
|
DESCRIPTION
|
|
417
418
|
Import the data to an instance, including types and users
|
|
@@ -1089,11 +1090,11 @@ Export all users in the org.
|
|
|
1089
1090
|
|
|
1090
1091
|
```
|
|
1091
1092
|
USAGE
|
|
1092
|
-
$ contrail users export [-
|
|
1093
|
+
$ contrail users export [-f <value>] [--overwrite]
|
|
1093
1094
|
|
|
1094
1095
|
FLAGS
|
|
1095
|
-
-
|
|
1096
|
-
--overwrite
|
|
1096
|
+
-f, --outFile=<value> [default: users.yml] The location for the file to be saved
|
|
1097
|
+
--overwrite Replaces existing files if they exist
|
|
1097
1098
|
|
|
1098
1099
|
DESCRIPTION
|
|
1099
1100
|
Export all users in the org.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getGroups = exports.getUserOrgs = void 0;
|
|
4
|
+
const sdk_1 = require("@contrail/sdk");
|
|
5
|
+
async function getUserOrgs(options) {
|
|
6
|
+
return new sdk_1.Entities().get({
|
|
7
|
+
entityName: 'user-org', ...options
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
exports.getUserOrgs = getUserOrgs;
|
|
11
|
+
async function getGroups(options) {
|
|
12
|
+
return new sdk_1.Entities().get({
|
|
13
|
+
entityName: 'group', ...options
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
exports.getGroups = getGroups;
|
|
@@ -4,7 +4,7 @@ export default class ExportGroups extends Command {
|
|
|
4
4
|
static description: string;
|
|
5
5
|
static examples: string[];
|
|
6
6
|
static flags: {
|
|
7
|
-
|
|
7
|
+
outFile: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
8
8
|
overwrite: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
9
|
};
|
|
10
10
|
run(): Promise<void>;
|
|
@@ -3,13 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.exportGroups = exports.DEFAULT_FILE_LOCATION = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const path = tslib_1.__importStar(require("path"));
|
|
6
|
-
const sdk_1 = require("@contrail/sdk");
|
|
7
6
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
8
7
|
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
9
8
|
const login_1 = require("../../auth/login");
|
|
10
9
|
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
|
|
11
10
|
const core_1 = require("@oclif/core");
|
|
12
11
|
const file_helpers_1 = require("../../helpers/file-helpers");
|
|
12
|
+
const users_1 = require("../../api/users");
|
|
13
13
|
exports.DEFAULT_FILE_LOCATION = 'groups.yml';
|
|
14
14
|
class ExportGroups extends core_1.Command {
|
|
15
15
|
async run() {
|
|
@@ -18,7 +18,7 @@ class ExportGroups extends core_1.Command {
|
|
|
18
18
|
try {
|
|
19
19
|
await (0, login_1.authUser)();
|
|
20
20
|
this.log('%s Getting Groups.', chalk_1.default.blue.bold('START'));
|
|
21
|
-
await exportGroups((_a = flags.
|
|
21
|
+
await exportGroups((_a = flags.outFile) !== null && _a !== void 0 ? _a : exports.DEFAULT_FILE_LOCATION, flags.overwrite);
|
|
22
22
|
this.log('%s Done', chalk_1.default.yellow.bold('GROUPS'));
|
|
23
23
|
}
|
|
24
24
|
catch (e) {
|
|
@@ -35,16 +35,12 @@ ExportGroups.examples = [
|
|
|
35
35
|
`,
|
|
36
36
|
];
|
|
37
37
|
ExportGroups.flags = {
|
|
38
|
-
|
|
38
|
+
outFile: core_1.Flags.string({ char: 'f', description: 'The location for the file to be saved', required: false, default: exports.DEFAULT_FILE_LOCATION }),
|
|
39
39
|
overwrite: core_1.Flags.boolean({ description: 'Replaces existing files if they exist', required: false, default: false })
|
|
40
40
|
};
|
|
41
41
|
async function exportGroups(fileLocation, overwrite) {
|
|
42
|
-
const allGroups = await
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
const allUsersInOrg = await new sdk_1.Entities().get({
|
|
46
|
-
entityName: 'user-org',
|
|
47
|
-
});
|
|
42
|
+
const allGroups = await (0, users_1.getGroups)({ relations: ['groupPrincipals'] });
|
|
43
|
+
const allUsersInOrg = await (0, users_1.getUserOrgs)();
|
|
48
44
|
const groups = [];
|
|
49
45
|
for (const group of allGroups) {
|
|
50
46
|
const groupPrincipals = getGroupPrincipals(group, allGroups, allUsersInOrg);
|
|
@@ -59,13 +55,16 @@ exports.exportGroups = exportGroups;
|
|
|
59
55
|
async function saveData(data, fileLocation, overwrite) {
|
|
60
56
|
const yamlStr = js_yaml_1.default.dump(data);
|
|
61
57
|
const CURRENT_DIR = process.cwd();
|
|
62
|
-
const pathToWrite = path.
|
|
58
|
+
const pathToWrite = path.join(CURRENT_DIR, fileLocation);
|
|
63
59
|
if (fs_1.default.existsSync(pathToWrite)) {
|
|
64
60
|
await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
|
|
65
61
|
}
|
|
66
62
|
fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
|
|
67
63
|
}
|
|
68
64
|
function getGroupPrincipals(group, allGroups, orgUsers) {
|
|
65
|
+
if (!(group === null || group === void 0 ? void 0 : group.groupPrincipals)) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
69
68
|
const principals = [];
|
|
70
69
|
for (const principal of group.groupPrincipals) {
|
|
71
70
|
const [type, id] = principal.principalReference.split(':');
|
|
@@ -56,12 +56,12 @@ async function uploadGroups(fileLocation) {
|
|
|
56
56
|
});
|
|
57
57
|
const toDelete = existingGroups.filter(x => !groupsToImport.map(y => y.name).includes(x.name));
|
|
58
58
|
const toCreate = groupsToImport.filter(x => !existingGroups.map(y => y.name).includes(x.name));
|
|
59
|
-
const toUpdate =
|
|
59
|
+
const toUpdate = groupsToImport.filter(x => existingGroups.map(y => y.name).includes(x.name));
|
|
60
60
|
const createdGroups = [];
|
|
61
61
|
// it's important to create all the groups first, to resolve any downstream principal dependencies
|
|
62
62
|
for (const group of toCreate) {
|
|
63
63
|
if (!group.groupPrincipals || !group.name) {
|
|
64
|
-
console.log('skipping invalid group');
|
|
64
|
+
console.log('skipping create of invalid group');
|
|
65
65
|
}
|
|
66
66
|
createdGroups.push(await new sdk_1.Entities().create({
|
|
67
67
|
entityName: 'group', object: { name: group.name }
|
|
@@ -77,90 +77,67 @@ async function uploadGroups(fileLocation) {
|
|
|
77
77
|
}
|
|
78
78
|
for (const group of toUpdate) {
|
|
79
79
|
if (!group.groupPrincipals || !group.name) {
|
|
80
|
-
console.log('skipping invalid group');
|
|
80
|
+
console.log('skipping update invalid group');
|
|
81
81
|
}
|
|
82
|
-
|
|
82
|
+
const existingGroup = existingGroups.find(x => x.name === group.name);
|
|
83
|
+
await updateGroup(group.groupPrincipals, orgUsers, existingGroup, allGroupsAfterCreate);
|
|
83
84
|
}
|
|
84
85
|
for (const group of toDelete) {
|
|
85
86
|
if (!group.groupPrincipals || !group.name) {
|
|
86
|
-
console.log('skipping invalid group');
|
|
87
|
+
console.log('skipping delete of invalid group');
|
|
87
88
|
}
|
|
88
89
|
await new sdk_1.Entities().delete({ entityName: 'group', id: group.id });
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
exports.uploadGroups = uploadGroups;
|
|
92
93
|
async function updateGroup(principals, orgUsers, existingGroup, allGroupsAfterCreate) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
await new sdk_1.Entities().update({
|
|
105
|
-
entityName: 'group-principal', object: {
|
|
106
|
-
principalReference: `user:${user.id}`,
|
|
107
|
-
groupId: existingGroup.id
|
|
108
|
-
}
|
|
109
|
-
});
|
|
94
|
+
var _a;
|
|
95
|
+
const principalsToUpdate = principals
|
|
96
|
+
.map(x => groupPrincipalNameToId(x, allGroupsAfterCreate, orgUsers))
|
|
97
|
+
.filter(x => !!x)
|
|
98
|
+
.map(x => { return { principalReference: `${x.type}:${x.identifier}`, groupId: existingGroup.id }; });
|
|
99
|
+
await new sdk_1.Entities().batchCreate({
|
|
100
|
+
entityName: 'group-principal', objects: {
|
|
101
|
+
principalReferences: principalsToUpdate.map(x => x.principalReference),
|
|
102
|
+
groupIds: [existingGroup.id]
|
|
110
103
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
groupId: existingGroup.id
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
104
|
+
});
|
|
105
|
+
// remove principals
|
|
106
|
+
const principalsToKeep = principalsToUpdate.map(principal => `${principal.type}:${principal.identifier}`);
|
|
107
|
+
const principalsToDelete = ((_a = existingGroup === null || existingGroup === void 0 ? void 0 : existingGroup.groupPrincipals) !== null && _a !== void 0 ? _a : [])
|
|
108
|
+
.map(x => groupPrincipalNameToId(x, allGroupsAfterCreate, orgUsers))
|
|
109
|
+
.filter(x => !!x)
|
|
110
|
+
.filter(x => !principalsToKeep.includes(`${x.type}:${x.identifier}`));
|
|
111
|
+
await principalsToDelete.forEach(async (principal) => {
|
|
112
|
+
await new sdk_1.Entities().delete({
|
|
113
|
+
entityName: 'group-principal', id: principal.cloudId
|
|
114
|
+
});
|
|
115
|
+
});
|
|
128
116
|
}
|
|
129
117
|
async function createGroupPrincipals(group, principals, orgUsers, allGroupsAfterCreate) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
catch (e) {
|
|
145
|
-
console.log('could not create group principal');
|
|
146
|
-
}
|
|
118
|
+
const principalsToCreate = principals
|
|
119
|
+
.map(x => groupPrincipalNameToId(x, allGroupsAfterCreate, orgUsers))
|
|
120
|
+
.filter(x => !!x)
|
|
121
|
+
.map(x => { return { principalReference: `${x.type}:${x.identifier}`, groupId: group.id }; });
|
|
122
|
+
await new sdk_1.Entities().batchCreate({
|
|
123
|
+
entityName: 'group-principal', objects: principalsToCreate
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function groupPrincipalNameToId(principal, groups, orgUsers) {
|
|
127
|
+
if (principal.type === 'user') {
|
|
128
|
+
const user = orgUsers.map(x => x.user).find(x => x.email === (principal === null || principal === void 0 ? void 0 : principal.email));
|
|
129
|
+
if (!user) {
|
|
130
|
+
console.log(`user ${principal.email} is not in this org's user list`);
|
|
131
|
+
return undefined;
|
|
147
132
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
entityName: 'group-principal', object: {
|
|
156
|
-
principalReference: `group:${nestedGroup.id}`,
|
|
157
|
-
groupId: group.id
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
catch (e) {
|
|
162
|
-
console.log('could not create nested group');
|
|
163
|
-
}
|
|
133
|
+
return { type: 'user', identifier: user.id, cloudId: principal.id };
|
|
134
|
+
}
|
|
135
|
+
else if (principal.type === 'group') {
|
|
136
|
+
const group = groups.find(x => x.name === principal.name);
|
|
137
|
+
if (!group) {
|
|
138
|
+
console.log(`group ${principal.name} is not in this org's group list`);
|
|
139
|
+
return undefined;
|
|
164
140
|
}
|
|
141
|
+
return { type: 'group', identifier: group.id, cloudId: principal.id };
|
|
165
142
|
}
|
|
166
143
|
}
|
|
@@ -5,11 +5,13 @@ const path = tslib_1.__importStar(require("path"));
|
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
6
|
const getAll_1 = require("../types/getAll");
|
|
7
7
|
const export_1 = require("../users/export");
|
|
8
|
+
const export_2 = require("../groups/export");
|
|
8
9
|
class ExportInstance extends core_1.Command {
|
|
9
10
|
async run() {
|
|
10
11
|
const { flags } = await this.parse(ExportInstance);
|
|
11
12
|
await (0, getAll_1.getAll)(flags.outDir, flags.overwrite);
|
|
12
13
|
await (0, export_1.exportUsers)(path.join(flags.outDir, 'users.yml'), flags.overwrite);
|
|
14
|
+
await (0, export_2.exportGroups)(path.join(flags.outDir, 'groups.yml'), flags.overwrite);
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
exports.default = ExportInstance;
|
|
@@ -5,11 +5,15 @@ const path = tslib_1.__importStar(require("path"));
|
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
6
|
const loadAll_1 = require("../types/loadAll");
|
|
7
7
|
const upload_1 = require("../users/upload");
|
|
8
|
+
const upload_2 = require("../groups/upload");
|
|
9
|
+
const uploadTypePropertyPolicies_1 = require("../types/uploadTypePropertyPolicies");
|
|
8
10
|
class ImportInstance extends core_1.Command {
|
|
9
11
|
async run() {
|
|
10
12
|
const { flags } = await this.parse(ImportInstance);
|
|
11
|
-
await (0, loadAll_1.loadAll)(flags.dir);
|
|
13
|
+
await (0, loadAll_1.loadAll)(flags.dir, true);
|
|
12
14
|
await (0, upload_1.uploadUsers)(path.join(flags.dir, 'users.yml'));
|
|
15
|
+
await (0, upload_2.uploadGroups)(path.join(flags.dir, 'groups.yml'));
|
|
16
|
+
await (0, uploadTypePropertyPolicies_1.uploadTypePropertyPolicies)(flags.dir);
|
|
13
17
|
}
|
|
14
18
|
}
|
|
15
19
|
exports.default = ImportInstance;
|
|
@@ -19,5 +23,5 @@ ImportInstance.examples = [
|
|
|
19
23
|
`,
|
|
20
24
|
];
|
|
21
25
|
ImportInstance.flags = {
|
|
22
|
-
dir: core_1.Flags.string({ description: 'The directory from which to export the instance data. Defaults to the current directory', required: false, default: '.' }),
|
|
26
|
+
dir: core_1.Flags.string({ char: 'd', description: 'The directory from which to export the instance data. Defaults to the current directory', required: false, default: '.' }),
|
|
23
27
|
};
|
|
@@ -30,4 +30,4 @@ export default class GetAllTypes extends Command {
|
|
|
30
30
|
}
|
|
31
31
|
export declare function getAll(outDir: string, overwrite: boolean): Promise<void>;
|
|
32
32
|
export declare function reduceTypes(dataHolder: DataHolder): any[];
|
|
33
|
-
export declare function reduceData(data: DataHolder): ReducedDataHolder
|
|
33
|
+
export declare function reduceData(data: DataHolder): Promise<ReducedDataHolder>;
|
|
@@ -10,6 +10,7 @@ const path = tslib_1.__importStar(require("path"));
|
|
|
10
10
|
const type_extractor_1 = require("../../helpers/types/type-extractor");
|
|
11
11
|
const types_1 = require("../../api/types");
|
|
12
12
|
const file_helpers_1 = require("../../helpers/file-helpers");
|
|
13
|
+
const users_1 = require("../../api/users");
|
|
13
14
|
const yaml = require('js-yaml');
|
|
14
15
|
class GetAllTypes extends core_1.Command {
|
|
15
16
|
async run() {
|
|
@@ -45,7 +46,7 @@ async function getAll(outDir, overwrite) {
|
|
|
45
46
|
typePropertyPolicies: await (0, types_1.getTypePropertyPolicies)(),
|
|
46
47
|
typePropertyPolicyLinks: await (0, types_1.getTypePropertyPolicyLinks)(),
|
|
47
48
|
};
|
|
48
|
-
const reducedData = reduceData(data);
|
|
49
|
+
const reducedData = await reduceData(data);
|
|
49
50
|
await saveData(reducedData, outDir, overwrite);
|
|
50
51
|
console.log('%s Retrieved', chalk_1.default.yellow.bold('TYPES'));
|
|
51
52
|
}
|
|
@@ -56,14 +57,43 @@ async function getAll(outDir, overwrite) {
|
|
|
56
57
|
console.log('%s Types Retrieval Complete.', chalk_1.default.green.bold('COMPLETE'));
|
|
57
58
|
}
|
|
58
59
|
exports.getAll = getAll;
|
|
59
|
-
function reduceTypePropertyPolicies(data) {
|
|
60
|
+
async function reduceTypePropertyPolicies(data) {
|
|
60
61
|
var _a;
|
|
62
|
+
const orgUsers = await (0, users_1.getUserOrgs)();
|
|
63
|
+
const groups = await (0, users_1.getGroups)();
|
|
64
|
+
function reducePrincipal(statement) {
|
|
65
|
+
var _a, _b;
|
|
66
|
+
if (!(statement === null || statement === void 0 ? void 0 : statement.principal)) {
|
|
67
|
+
return statement;
|
|
68
|
+
}
|
|
69
|
+
const [type, id] = statement.principal.split(':');
|
|
70
|
+
if (!type || !id) {
|
|
71
|
+
return statement;
|
|
72
|
+
}
|
|
73
|
+
if (type === 'group') {
|
|
74
|
+
const groupName = (_a = groups.find(x => x.id === id)) === null || _a === void 0 ? void 0 : _a.name;
|
|
75
|
+
if (!groupName) {
|
|
76
|
+
console.log(`Could not find group for statement. skipping invalid policy conversion ${id}`);
|
|
77
|
+
return statement;
|
|
78
|
+
}
|
|
79
|
+
statement.principal = `group:${groupName}`;
|
|
80
|
+
}
|
|
81
|
+
else if (type === 'user') {
|
|
82
|
+
const userEmail = (_b = orgUsers.find(x => x.user.id === id)) === null || _b === void 0 ? void 0 : _b.email;
|
|
83
|
+
if (!userEmail) {
|
|
84
|
+
console.log(`Could not find group for statement. skipping invalid policy conversion ${id}`);
|
|
85
|
+
return statement;
|
|
86
|
+
}
|
|
87
|
+
statement.principal = `user:${userEmail}`;
|
|
88
|
+
}
|
|
89
|
+
return statement;
|
|
90
|
+
}
|
|
61
91
|
return (_a = data === null || data === void 0 ? void 0 : data.typePropertyPolicies) === null || _a === void 0 ? void 0 : _a.map(x => {
|
|
62
92
|
return {
|
|
63
93
|
label: x.label,
|
|
64
94
|
policy: {
|
|
65
95
|
version: x.policy.version,
|
|
66
|
-
statements: x.policy.statements,
|
|
96
|
+
statements: x.policy.statements.map(x => reducePrincipal(x)),
|
|
67
97
|
}
|
|
68
98
|
};
|
|
69
99
|
});
|
|
@@ -195,7 +225,7 @@ function reduceTypes(dataHolder) {
|
|
|
195
225
|
return reducedTypes;
|
|
196
226
|
}
|
|
197
227
|
exports.reduceTypes = reduceTypes;
|
|
198
|
-
function reduceData(data) {
|
|
228
|
+
async function reduceData(data) {
|
|
199
229
|
return {
|
|
200
230
|
reducedTypes: reduceTypes(data),
|
|
201
231
|
reducedOptionSets: reduceOptionSets(data),
|
|
@@ -203,7 +233,7 @@ function reduceData(data) {
|
|
|
203
233
|
reducedRuleSets: reduceRuleSets(data),
|
|
204
234
|
reducedRuleSetLinks: reduceRuleSetLinks(data),
|
|
205
235
|
reducedUsageInfo: reduceUsageInfo(data),
|
|
206
|
-
reducedTypePropertyPolicies: reduceTypePropertyPolicies(data),
|
|
236
|
+
reducedTypePropertyPolicies: await reduceTypePropertyPolicies(data),
|
|
207
237
|
reducedTypePropertyPolicyLinks: reduceTypePropertyPolicyLinks(data),
|
|
208
238
|
};
|
|
209
239
|
}
|
|
@@ -26,7 +26,7 @@ LoadAllTypes.examples = [
|
|
|
26
26
|
LoadAllTypes.flags = {
|
|
27
27
|
dir: core_1.Flags.string({ char: 'd', description: 'The directory from which to load the types data. Defaults to the current directory.', required: false, default: '.' }),
|
|
28
28
|
};
|
|
29
|
-
async function loadAll(dir) {
|
|
29
|
+
async function loadAll(dir, skipPolicies = false) {
|
|
30
30
|
try {
|
|
31
31
|
await (0, login_1.authUser)();
|
|
32
32
|
await (0, uploadOptionSets_1.uploadOptionSets)(dir);
|
|
@@ -34,7 +34,9 @@ async function loadAll(dir) {
|
|
|
34
34
|
await (0, type_uploader_1.uploadTypes)(dir);
|
|
35
35
|
await (0, uploadUsageInfo_1.uploadUsageInfo)(dir);
|
|
36
36
|
await (0, uploadRuleSets_1.uploadRuleSets)(dir);
|
|
37
|
-
|
|
37
|
+
if (!skipPolicies) {
|
|
38
|
+
await (0, uploadTypePropertyPolicies_1.uploadTypePropertyPolicies)(dir);
|
|
39
|
+
}
|
|
38
40
|
}
|
|
39
41
|
catch (e) {
|
|
40
42
|
console.log(`%s Types Upload Failed. ${e}`, chalk_1.default.red.bold('FAIL'));
|
|
@@ -9,6 +9,7 @@ const login_1 = require("../../auth/login");
|
|
|
9
9
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
10
10
|
const core_1 = require("@oclif/core");
|
|
11
11
|
const type_extractor_1 = require("../../helpers/types/type-extractor");
|
|
12
|
+
const users_1 = require("../../api/users");
|
|
12
13
|
const yaml = require('js-yaml');
|
|
13
14
|
class UploadTypePropertyPolicies extends core_1.Command {
|
|
14
15
|
async run() {
|
|
@@ -58,6 +59,42 @@ function loadTPPolicies(fromDir) {
|
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
async function uploadTPPolicyObjects(reducedTypePropertyPolicies) {
|
|
62
|
+
const orgUsers = await (0, users_1.getUserOrgs)();
|
|
63
|
+
const groups = await (0, users_1.getGroups)();
|
|
64
|
+
function fillPrincipal(statement) {
|
|
65
|
+
const principal = statement === null || statement === void 0 ? void 0 : statement.principal;
|
|
66
|
+
if (!principal) {
|
|
67
|
+
console.warn(`skipping bad statement principal ${statement === null || statement === void 0 ? void 0 : statement.principal}`);
|
|
68
|
+
return statement;
|
|
69
|
+
}
|
|
70
|
+
const [type, identifier] = principal.split(':');
|
|
71
|
+
if (!type || !identifier) {
|
|
72
|
+
console.warn(`skipping bad statement principal ${statement === null || statement === void 0 ? void 0 : statement.principal}`);
|
|
73
|
+
return statement;
|
|
74
|
+
}
|
|
75
|
+
if (type === 'group') {
|
|
76
|
+
const group = groups.find(x => x.name === identifier);
|
|
77
|
+
if (!group) {
|
|
78
|
+
console.log(`Could not find group ${identifier}`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
statement.principal = `group:${group.id}`;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if (type === 'user') {
|
|
85
|
+
const orgUser = orgUsers.find(x => x.user.email === identifier);
|
|
86
|
+
if (!orgUser) {
|
|
87
|
+
console.log(`Could not find user ${identifier}`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
statement.principal = `user:${orgUser.user.id}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return statement;
|
|
94
|
+
}
|
|
95
|
+
reducedTypePropertyPolicies.forEach(policy => {
|
|
96
|
+
policy.policy.statements = policy.policy.statements.map(x => fillPrincipal(x));
|
|
97
|
+
});
|
|
61
98
|
const currentTPPolicies = await new sdk_1.Entities().get({
|
|
62
99
|
entityName: 'type-property-policy',
|
|
63
100
|
});
|
|
@@ -69,8 +106,6 @@ async function uploadTPPolicyObjects(reducedTypePropertyPolicies) {
|
|
|
69
106
|
for (const loadedTPP of reducedTypePropertyPolicies) {
|
|
70
107
|
loadedTPPByName[loadedTPP.label] = loadedTPP;
|
|
71
108
|
}
|
|
72
|
-
// console.debug('current tp policy:', currentTPPolicies);
|
|
73
|
-
// console.debug('reduced tp policy:', reducedTypePropertyPolicies);
|
|
74
109
|
for (const [label, loadedTPP] of Object.entries(loadedTPPByName)) {
|
|
75
110
|
try {
|
|
76
111
|
const found = currentTPPByLabel[label];
|
|
@@ -137,8 +172,6 @@ async function uploadTypePropertyPolicyLinks(reducedTypePropertyPolicyLinks) {
|
|
|
137
172
|
const hash = `${loadedLink.typePropertySlug}|${loadedLink.typePropertyPolicyLabel}`;
|
|
138
173
|
reducedLinksByHashes[hash] = loadedLink;
|
|
139
174
|
}
|
|
140
|
-
console.debug('current type property policy links:', currentLinksHashes);
|
|
141
|
-
console.debug('reduced type property policy links:', reducedLinksByHashes);
|
|
142
175
|
for (const loadedTPPLink of reducedTypePropertyPolicyLinks) {
|
|
143
176
|
try {
|
|
144
177
|
const found = currentLinksHashes[`${loadedTPPLink.typePropertySlug}|${loadedTPPLink.typePropertyPolicyLabel}`];
|
|
@@ -146,7 +179,6 @@ async function uploadTypePropertyPolicyLinks(reducedTypePropertyPolicyLinks) {
|
|
|
146
179
|
if (!transformReducedLink(loadedTPPLink, typeProperties, currentTPPs)) {
|
|
147
180
|
continue;
|
|
148
181
|
}
|
|
149
|
-
console.log('Creating: ', loadedTPPLink);
|
|
150
182
|
await new sdk_1.Entities().create({
|
|
151
183
|
entityName: 'type-property-policy-link',
|
|
152
184
|
object: {
|
|
@@ -159,7 +191,6 @@ async function uploadTypePropertyPolicyLinks(reducedTypePropertyPolicyLinks) {
|
|
|
159
191
|
if (!transformReducedLink(loadedTPPLink, typeProperties, currentTPPs)) {
|
|
160
192
|
continue;
|
|
161
193
|
}
|
|
162
|
-
console.log('skipping existing link: ', loadedTPPLink);
|
|
163
194
|
}
|
|
164
195
|
}
|
|
165
196
|
catch (err) {
|
|
@@ -4,7 +4,7 @@ export default class ExportUsers extends Command {
|
|
|
4
4
|
static description: string;
|
|
5
5
|
static examples: string[];
|
|
6
6
|
static flags: {
|
|
7
|
-
|
|
7
|
+
outFile: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
8
8
|
overwrite: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
9
|
};
|
|
10
10
|
run(): Promise<void>;
|
|
@@ -3,13 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.exportUsers = exports.DEFAULT_FILE_LOCATION = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const path = tslib_1.__importStar(require("path"));
|
|
6
|
-
const sdk_1 = require("@contrail/sdk");
|
|
7
6
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
8
7
|
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
9
8
|
const login_1 = require("../../auth/login");
|
|
10
9
|
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
|
|
11
10
|
const core_1 = require("@oclif/core");
|
|
12
11
|
const file_helpers_1 = require("../../helpers/file-helpers");
|
|
12
|
+
const users_1 = require("../../api/users");
|
|
13
13
|
exports.DEFAULT_FILE_LOCATION = 'users.yml';
|
|
14
14
|
class ExportUsers extends core_1.Command {
|
|
15
15
|
async run() {
|
|
@@ -18,7 +18,7 @@ class ExportUsers extends core_1.Command {
|
|
|
18
18
|
try {
|
|
19
19
|
await (0, login_1.authUser)();
|
|
20
20
|
this.log('%s Getting Users.', chalk_1.default.blue.bold('START'));
|
|
21
|
-
await exportUsers((_a = flags.
|
|
21
|
+
await exportUsers((_a = flags.outFile) !== null && _a !== void 0 ? _a : exports.DEFAULT_FILE_LOCATION, flags.overwrite);
|
|
22
22
|
this.log('%s Done', chalk_1.default.yellow.bold('USERS'));
|
|
23
23
|
}
|
|
24
24
|
catch (e) {
|
|
@@ -35,13 +35,11 @@ ExportUsers.examples = [
|
|
|
35
35
|
`,
|
|
36
36
|
];
|
|
37
37
|
ExportUsers.flags = {
|
|
38
|
-
|
|
38
|
+
outFile: core_1.Flags.string({ char: 'f', description: 'The location for the file to be saved', required: false, default: exports.DEFAULT_FILE_LOCATION }),
|
|
39
39
|
overwrite: core_1.Flags.boolean({ description: 'Replaces existing files if they exist', required: false, default: false })
|
|
40
40
|
};
|
|
41
41
|
async function exportUsers(fileLocation, overwrite) {
|
|
42
|
-
const allUsersInOrg = await
|
|
43
|
-
entityName: 'user-org',
|
|
44
|
-
});
|
|
42
|
+
const allUsersInOrg = await (0, users_1.getUserOrgs)();
|
|
45
43
|
const users = [];
|
|
46
44
|
for (const userInOrg of allUsersInOrg) {
|
|
47
45
|
delete userInOrg.user.id;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.safeFileOverwrite = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
|
|
6
|
-
const PASS_FORCE_TO_OVERWRITE = 'Pass --
|
|
6
|
+
const PASS_FORCE_TO_OVERWRITE = 'Pass --overwrite to overwrite without prompting';
|
|
7
7
|
//throws an error if the user declines to overwrite the file
|
|
8
8
|
async function safeFileOverwrite(fileLocation, overwrite) {
|
|
9
9
|
if (overwrite) {
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.0.
|
|
2
|
+
"version": "2.0.9",
|
|
3
3
|
"commands": {
|
|
4
4
|
"app:create": {
|
|
5
5
|
"id": "app:create",
|
|
@@ -307,10 +307,10 @@
|
|
|
307
307
|
"$ contrail groups export\n"
|
|
308
308
|
],
|
|
309
309
|
"flags": {
|
|
310
|
-
"
|
|
311
|
-
"name": "
|
|
310
|
+
"outFile": {
|
|
311
|
+
"name": "outFile",
|
|
312
312
|
"type": "option",
|
|
313
|
-
"char": "
|
|
313
|
+
"char": "f",
|
|
314
314
|
"description": "The location for the file to be saved",
|
|
315
315
|
"required": false,
|
|
316
316
|
"multiple": false,
|
|
@@ -393,6 +393,7 @@
|
|
|
393
393
|
"dir": {
|
|
394
394
|
"name": "dir",
|
|
395
395
|
"type": "option",
|
|
396
|
+
"char": "d",
|
|
396
397
|
"description": "The directory from which to export the instance data. Defaults to the current directory",
|
|
397
398
|
"required": false,
|
|
398
399
|
"multiple": false,
|
|
@@ -932,10 +933,10 @@
|
|
|
932
933
|
"$ contrail users export\n"
|
|
933
934
|
],
|
|
934
935
|
"flags": {
|
|
935
|
-
"
|
|
936
|
-
"name": "
|
|
936
|
+
"outFile": {
|
|
937
|
+
"name": "outFile",
|
|
937
938
|
"type": "option",
|
|
938
|
-
"char": "
|
|
939
|
+
"char": "f",
|
|
939
940
|
"description": "The location for the file to be saved",
|
|
940
941
|
"required": false,
|
|
941
942
|
"multiple": false,
|