@contrail/cli 2.0.7 → 2.0.8

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 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.7 darwin-arm64 node-v18.13.0
18
+ @contrail/cli/2.0.8 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 [-d <value>] [--overwrite]
334
+ $ contrail groups export [-f <value>] [--overwrite]
335
335
 
336
336
  FLAGS
337
- -d, --outDir=<value> [default: groups.yml] The location for the file to be saved
338
- --overwrite Replaces existing files if they exist
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 [--dir <value>]
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 directory
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 [-d <value>] [--overwrite]
1093
+ $ contrail users export [-f <value>] [--overwrite]
1093
1094
 
1094
1095
  FLAGS
1095
- -d, --outDir=<value> [default: users.yml] The location for the file to be saved
1096
- --overwrite Replaces existing files if they exist
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,2 @@
1
+ export declare function getUserOrgs(options?: any): Promise<any[]>;
2
+ export declare function getGroups(options?: any): Promise<any[]>;
@@ -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
- outDir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
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.outDir) !== null && _a !== void 0 ? _a : exports.DEFAULT_FILE_LOCATION, flags.overwrite);
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
- outDir: core_1.Flags.string({ char: 'd', description: 'The location for the file to be saved', required: false, default: exports.DEFAULT_FILE_LOCATION }),
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 new sdk_1.Entities().get({
43
- entityName: 'group', relations: ['groupPrincipals']
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);
@@ -53,19 +49,26 @@ async function exportGroups(fileLocation, overwrite) {
53
49
  groupPrincipals,
54
50
  });
55
51
  }
52
+ console.log("saving groups:", JSON.stringify(groups));
56
53
  await saveData(groups, fileLocation, overwrite);
57
54
  }
58
55
  exports.exportGroups = exportGroups;
59
56
  async function saveData(data, fileLocation, overwrite) {
60
57
  const yamlStr = js_yaml_1.default.dump(data);
58
+ console.log("file location:", fileLocation);
59
+ console.log("final yml string:", yamlStr);
61
60
  const CURRENT_DIR = process.cwd();
62
- const pathToWrite = path.resolve(path.join(CURRENT_DIR, fileLocation));
61
+ const pathToWrite = path.join(CURRENT_DIR, fileLocation);
63
62
  if (fs_1.default.existsSync(pathToWrite)) {
64
63
  await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
65
64
  }
66
65
  fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
67
66
  }
68
67
  function getGroupPrincipals(group, allGroups, orgUsers) {
68
+ if (!(group === null || group === void 0 ? void 0 : group.groupPrincipals)) {
69
+ return [];
70
+ }
71
+ console.log("all groups:", allGroups.map(x => x.id));
69
72
  const principals = [];
70
73
  for (const principal of group.groupPrincipals) {
71
74
  const [type, id] = principal.principalReference.split(':');
@@ -83,6 +86,7 @@ function getGroupPrincipals(group, allGroups, orgUsers) {
83
86
  }
84
87
  else if (type === 'group') {
85
88
  const nestedGroup = allGroups.find(x => x.id === id);
89
+ console.log("looking for group", id);
86
90
  principals.push({
87
91
  type: 'group',
88
92
  name: nestedGroup.name
@@ -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 = existingGroups.filter(x => groupsToImport.map(y => y.name).includes(x.name));
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
- await updateGroup(group.groupPrincipals, orgUsers, group, allGroupsAfterCreate);
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
- const existingPrincipals = existingGroup.groupPrincipals;
94
- for (const principal of principals) {
95
- if (principal.type === 'user') {
96
- const user = orgUsers.map(x => x.user).find(x => x.email === (principal === null || principal === void 0 ? void 0 : principal.email));
97
- if (!user) {
98
- console.log(`user ${principal.email} is not in this org's user list`);
99
- }
100
- const principalId = `user:${user.id}`;
101
- if (existingPrincipals.map(x => x.principalReference).includes(principalId)) {
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
- else if (principal.type === 'group') {
112
- const group = allGroupsAfterCreate.find(x => x.name === principal.name);
113
- if (!group) {
114
- console.log(`group ${principal.name} is not in this org's group list`);
115
- }
116
- const principalId = `group:${principal.name}`;
117
- if (existingPrincipals.map(x => x.principalReference).includes(principalId)) {
118
- continue;
119
- }
120
- await new sdk_1.Entities().update({
121
- entityName: 'group-principal', object: {
122
- principalReference: `group:${group.id}`,
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
- for (const principal of principals) {
131
- if (principal.type === 'user') {
132
- try {
133
- const user = orgUsers.map(x => x.user).find(x => x.email === (principal === null || principal === void 0 ? void 0 : principal.email));
134
- if (!user) {
135
- console.log(`user ${principal.email} is not in this org's user list`);
136
- }
137
- await new sdk_1.Entities().create({
138
- entityName: 'group-principal', object: {
139
- principalReference: `user:${user.id}`,
140
- groupId: group.id
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
- else if (principal.type === 'group') {
149
- try {
150
- const nestedGroup = allGroupsAfterCreate.find(x => x.name === principal.name);
151
- if (!nestedGroup) {
152
- console.log(`group ${principal.name} is not in this org's group list`);
153
- }
154
- await new sdk_1.Entities().create({
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
  }
@@ -7,4 +7,4 @@ export default class LoadAllTypes extends Command {
7
7
  };
8
8
  run(): Promise<void>;
9
9
  }
10
- export declare function loadAll(dir: string): Promise<void>;
10
+ export declare function loadAll(dir: string, skipPolicies?: boolean): Promise<void>;
@@ -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
- await (0, uploadTypePropertyPolicies_1.uploadTypePropertyPolicies)(dir);
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
- outDir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
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.outDir) !== null && _a !== void 0 ? _a : exports.DEFAULT_FILE_LOCATION, flags.overwrite);
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
- outDir: core_1.Flags.string({ char: 'd', description: 'The location for the file to be saved', required: false, default: exports.DEFAULT_FILE_LOCATION }),
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 new sdk_1.Entities().get({
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 --force to overwrite without prompting';
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) {
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.0.7",
2
+ "version": "2.0.8",
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
- "outDir": {
311
- "name": "outDir",
310
+ "outFile": {
311
+ "name": "outFile",
312
312
  "type": "option",
313
- "char": "d",
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
- "outDir": {
936
- "name": "outDir",
936
+ "outFile": {
937
+ "name": "outFile",
937
938
  "type": "option",
938
- "char": "d",
939
+ "char": "f",
939
940
  "description": "The location for the file to be saved",
940
941
  "required": false,
941
942
  "multiple": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "2.0.7",
3
+ "version": "2.0.8",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",