@contrail/cli 2.0.3 → 2.0.5
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 +330 -187
- package/dist/api/apps.d.ts +1 -1
- package/dist/api/apps.js +2 -1
- package/dist/commands/app/install.d.ts +1 -0
- package/dist/commands/app/install.js +3 -2
- package/dist/commands/groups/export.d.ts +12 -0
- package/dist/commands/groups/export.js +93 -0
- package/dist/commands/groups/upload.d.ts +10 -0
- package/dist/commands/groups/upload.js +166 -0
- package/dist/commands/instance/export.d.ts +10 -0
- package/dist/commands/instance/export.js +24 -0
- package/dist/commands/instance/import.d.ts +9 -0
- package/dist/commands/instance/import.js +23 -0
- package/dist/commands/types/getAll.d.ts +5 -1
- package/dist/commands/types/getAll.js +31 -11
- package/dist/commands/types/loadAll.d.ts +5 -2
- package/dist/commands/types/loadAll.js +17 -13
- package/dist/commands/types/uploadOptionSetHierarchies.d.ts +4 -1
- package/dist/commands/types/uploadOptionSetHierarchies.js +13 -9
- package/dist/commands/types/uploadOptionSets.d.ts +4 -1
- package/dist/commands/types/uploadOptionSets.js +13 -9
- package/dist/commands/types/uploadRuleSets.d.ts +4 -1
- package/dist/commands/types/uploadRuleSets.js +12 -8
- package/dist/commands/types/uploadTypePropertyPolicies.d.ts +4 -1
- package/dist/commands/types/uploadTypePropertyPolicies.js +12 -8
- package/dist/commands/types/uploadUsageInfo.d.ts +4 -1
- package/dist/commands/types/uploadUsageInfo.js +9 -6
- package/dist/commands/users/export.d.ts +4 -1
- package/dist/commands/users/export.js +16 -7
- package/dist/commands/users/upload.d.ts +1 -0
- package/dist/commands/users/upload.js +5 -4
- package/dist/helpers/app/app-deployer.js +2 -0
- package/dist/helpers/file-helpers.d.ts +1 -0
- package/dist/helpers/file-helpers.js +23 -0
- package/dist/helpers/types/type-uploader.d.ts +1 -1
- package/dist/helpers/types/type-uploader.js +8 -8
- package/dist/interfaces.d.ts +1 -0
- package/dist/templates/typescript/app.yml +1 -0
- package/dist/templates/typescript/src/actions/logItem.ts +3 -8
- package/dist/templates/typescript/src/framework/app-config.ts +1 -4
- package/oclif.manifest.json +212 -15
- package/package.json +8 -3
package/dist/api/apps.d.ts
CHANGED
|
@@ -10,4 +10,4 @@ export declare function upgradeAppVersion(appOrg: any, appVersionId: any): Promi
|
|
|
10
10
|
export declare function deleteAppOrg(appOrgId: string): Promise<AppOrg>;
|
|
11
11
|
export declare function getInstalledApps(): Promise<AppOrg[]>;
|
|
12
12
|
export declare function installAppToOrg(app: any, configProperties: any): Promise<AppOrg>;
|
|
13
|
-
export declare function getAvailableApps(): Promise<App[]>;
|
|
13
|
+
export declare function getAvailableApps(options?: any): Promise<App[]>;
|
package/dist/api/apps.js
CHANGED
|
@@ -74,7 +74,7 @@ async function installAppToOrg(app, configProperties) {
|
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
exports.installAppToOrg = installAppToOrg;
|
|
77
|
-
async function getAvailableApps() {
|
|
77
|
+
async function getAvailableApps(options) {
|
|
78
78
|
const orgId = auth_1.Auth.config.orgId;
|
|
79
79
|
const apps = [];
|
|
80
80
|
apps.push(...await new sdk_1.Entities().get({
|
|
@@ -89,6 +89,7 @@ async function getAvailableApps() {
|
|
|
89
89
|
criteria: {
|
|
90
90
|
orgId,
|
|
91
91
|
private: false,
|
|
92
|
+
...options
|
|
92
93
|
},
|
|
93
94
|
}));
|
|
94
95
|
return apps;
|
|
@@ -6,6 +6,7 @@ export default class InstallApp extends Command {
|
|
|
6
6
|
static flags: {
|
|
7
7
|
appIdentifier: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
8
8
|
installWorkflowTemplates: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
showHidden: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
10
|
};
|
|
10
11
|
run(): Promise<void>;
|
|
11
12
|
}
|
|
@@ -10,9 +10,9 @@ const apps_1 = require("../../api/apps");
|
|
|
10
10
|
const workflow_template_definition_deployer_1 = require("../../helpers/workflow-template-definitions/workflow-template-definition-deployer");
|
|
11
11
|
class InstallApp extends core_1.Command {
|
|
12
12
|
async run() {
|
|
13
|
-
const {
|
|
13
|
+
const { flags } = await this.parse(InstallApp);
|
|
14
14
|
await (0, login_1.authUser)();
|
|
15
|
-
const apps = await (0, apps_1.getAvailableApps)();
|
|
15
|
+
const apps = await (0, apps_1.getAvailableApps)({ hidden: flags.showHidden });
|
|
16
16
|
if (!apps.length) {
|
|
17
17
|
throw new Error('No apps are available to install...');
|
|
18
18
|
}
|
|
@@ -94,6 +94,7 @@ InstallApp.strict = true;
|
|
|
94
94
|
InstallApp.flags = {
|
|
95
95
|
appIdentifier: core_1.Flags.string({ char: 'i', description: 'The identifier of the app to install', required: false }),
|
|
96
96
|
installWorkflowTemplates: core_1.Flags.boolean({ char: 'w', description: 'Install the app\'s accompanying workflows', required: false }),
|
|
97
|
+
showHidden: core_1.Flags.boolean({ char: 'h', description: 'Show the option to install public but hidden apps', required: false }),
|
|
97
98
|
};
|
|
98
99
|
async function getConfigProperties(app) {
|
|
99
100
|
const config = {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export declare const DEFAULT_FILE_LOCATION = "groups.yml";
|
|
3
|
+
export default class ExportGroups extends Command {
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static flags: {
|
|
7
|
+
outDir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
8
|
+
overwrite: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare function exportGroups(fileLocation: string, overwrite: boolean): Promise<void>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.exportGroups = exports.DEFAULT_FILE_LOCATION = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const path = tslib_1.__importStar(require("path"));
|
|
6
|
+
const sdk_1 = require("@contrail/sdk");
|
|
7
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
8
|
+
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
9
|
+
const login_1 = require("../../auth/login");
|
|
10
|
+
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
|
|
11
|
+
const core_1 = require("@oclif/core");
|
|
12
|
+
const file_helpers_1 = require("../../helpers/file-helpers");
|
|
13
|
+
exports.DEFAULT_FILE_LOCATION = 'groups.yml';
|
|
14
|
+
class ExportGroups extends core_1.Command {
|
|
15
|
+
async run() {
|
|
16
|
+
var _a;
|
|
17
|
+
const { flags } = await this.parse(ExportGroups);
|
|
18
|
+
try {
|
|
19
|
+
await (0, login_1.authUser)();
|
|
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);
|
|
22
|
+
this.log('%s Done', chalk_1.default.yellow.bold('GROUPS'));
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
this.log(`%s Groups download Failed. ${e}`, chalk_1.default.red.bold('FAIL'));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
this.log('%s Groups download Complete.', chalk_1.default.green.bold('COMPLETE'));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.default = ExportGroups;
|
|
32
|
+
ExportGroups.description = 'Export all groups in the org.';
|
|
33
|
+
ExportGroups.examples = [
|
|
34
|
+
`$ contrail groups export
|
|
35
|
+
`,
|
|
36
|
+
];
|
|
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 }),
|
|
39
|
+
overwrite: core_1.Flags.boolean({ description: 'Replaces existing files if they exist', required: false, default: false })
|
|
40
|
+
};
|
|
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
|
+
});
|
|
48
|
+
const groups = [];
|
|
49
|
+
for (const group of allGroups) {
|
|
50
|
+
const groupPrincipals = getGroupPrincipals(group, allGroups, allUsersInOrg);
|
|
51
|
+
groups.push({
|
|
52
|
+
name: group.name,
|
|
53
|
+
groupPrincipals,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
await saveData(groups, fileLocation, overwrite);
|
|
57
|
+
}
|
|
58
|
+
exports.exportGroups = exportGroups;
|
|
59
|
+
async function saveData(data, fileLocation, overwrite) {
|
|
60
|
+
const yamlStr = js_yaml_1.default.dump(data);
|
|
61
|
+
const CURRENT_DIR = process.cwd();
|
|
62
|
+
const pathToWrite = path.resolve(path.join(CURRENT_DIR, fileLocation));
|
|
63
|
+
if (fs_1.default.existsSync(pathToWrite)) {
|
|
64
|
+
await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
|
|
65
|
+
}
|
|
66
|
+
fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
|
|
67
|
+
}
|
|
68
|
+
function getGroupPrincipals(group, allGroups, orgUsers) {
|
|
69
|
+
const principals = [];
|
|
70
|
+
for (const principal of group.groupPrincipals) {
|
|
71
|
+
const [type, id] = principal.principalReference.split(':');
|
|
72
|
+
if (type === 'user') {
|
|
73
|
+
const user = orgUsers.find(x => x.user.id === id);
|
|
74
|
+
if (user) {
|
|
75
|
+
principals.push({
|
|
76
|
+
type,
|
|
77
|
+
email: user.user.email
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.log('couldn\'t find user', id);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if (type === 'group') {
|
|
85
|
+
const nestedGroup = allGroups.find(x => x.id === id);
|
|
86
|
+
principals.push({
|
|
87
|
+
type: 'group',
|
|
88
|
+
name: nestedGroup.name
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return principals;
|
|
93
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ImportGroups extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
groupsFile: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare function uploadGroups(fileLocation: string): Promise<void>;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uploadGroups = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const path = tslib_1.__importStar(require("path"));
|
|
6
|
+
const sdk_1 = require("@contrail/sdk");
|
|
7
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
8
|
+
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
9
|
+
const login_1 = require("../../auth/login");
|
|
10
|
+
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
|
|
11
|
+
const core_1 = require("@oclif/core");
|
|
12
|
+
class ImportGroups extends core_1.Command {
|
|
13
|
+
async run() {
|
|
14
|
+
const { args } = await this.parse(ImportGroups);
|
|
15
|
+
try {
|
|
16
|
+
await (0, login_1.authUser)();
|
|
17
|
+
this.log('%s Uploading Groups.', chalk_1.default.blue.bold('START'));
|
|
18
|
+
this.log('%s Uploading', chalk_1.default.yellow.bold('GROUP'));
|
|
19
|
+
await uploadGroups(args.groupsFile);
|
|
20
|
+
this.log('%s Uploaded', chalk_1.default.yellow.bold('GROUP'));
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
this.log(`%s Group Upload Failed. ${e}`, chalk_1.default.red.bold('FAIL'));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.log('%s Group Upload Complete.', chalk_1.default.green.bold('COMPLETE'));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.default = ImportGroups;
|
|
30
|
+
ImportGroups.description = 'Import all groups in the groups.yml file';
|
|
31
|
+
ImportGroups.examples = [
|
|
32
|
+
`$ contrail groups import <GROUPS_FILE>
|
|
33
|
+
`,
|
|
34
|
+
];
|
|
35
|
+
ImportGroups.args = {
|
|
36
|
+
groupsFile: core_1.Args.string({ description: 'The .yml file containing the groups', required: true }),
|
|
37
|
+
};
|
|
38
|
+
function getGroupsFile(fileLocation) {
|
|
39
|
+
const CURRENT_DIR = process.cwd();
|
|
40
|
+
try {
|
|
41
|
+
const fullPath = path.join(CURRENT_DIR, fileLocation);
|
|
42
|
+
const doc = js_yaml_1.default.load(fs_1.default.readFileSync(fullPath, 'utf8'));
|
|
43
|
+
return doc;
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
throw new Error(`ERROR PARSING YAML: ${e}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function uploadGroups(fileLocation) {
|
|
50
|
+
const existingGroups = await new sdk_1.Entities().get({
|
|
51
|
+
entityName: 'group', relations: ['groupPrincipals']
|
|
52
|
+
});
|
|
53
|
+
const groupsToImport = getGroupsFile(fileLocation);
|
|
54
|
+
const orgUsers = await new sdk_1.Entities().get({
|
|
55
|
+
entityName: 'user-org',
|
|
56
|
+
});
|
|
57
|
+
const toDelete = existingGroups.filter(x => !groupsToImport.map(y => y.name).includes(x.name));
|
|
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));
|
|
60
|
+
const createdGroups = [];
|
|
61
|
+
// it's important to create all the groups first, to resolve any downstream principal dependencies
|
|
62
|
+
for (const group of toCreate) {
|
|
63
|
+
if (!group.groupPrincipals || !group.name) {
|
|
64
|
+
console.log('skipping invalid group');
|
|
65
|
+
}
|
|
66
|
+
createdGroups.push(await new sdk_1.Entities().create({
|
|
67
|
+
entityName: 'group', object: { name: group.name }
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
const allGroupsAfterCreate = existingGroups.concat(createdGroups);
|
|
71
|
+
for (const group of toCreate) {
|
|
72
|
+
const createdGroup = createdGroups.find(x => x.name === group.name);
|
|
73
|
+
if (!createdGroup) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
await createGroupPrincipals(createdGroup, group.groupPrincipals, orgUsers, allGroupsAfterCreate);
|
|
77
|
+
}
|
|
78
|
+
for (const group of toUpdate) {
|
|
79
|
+
if (!group.groupPrincipals || !group.name) {
|
|
80
|
+
console.log('skipping invalid group');
|
|
81
|
+
}
|
|
82
|
+
await updateGroup(group.groupPrincipals, orgUsers, group, allGroupsAfterCreate);
|
|
83
|
+
}
|
|
84
|
+
for (const group of toDelete) {
|
|
85
|
+
if (!group.groupPrincipals || !group.name) {
|
|
86
|
+
console.log('skipping invalid group');
|
|
87
|
+
}
|
|
88
|
+
await new sdk_1.Entities().delete({ entityName: 'group', id: group.id });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.uploadGroups = uploadGroups;
|
|
92
|
+
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
|
+
});
|
|
110
|
+
}
|
|
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
|
+
}
|
|
128
|
+
}
|
|
129
|
+
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
|
+
}
|
|
147
|
+
}
|
|
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
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ExportInstance extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
outDir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
7
|
+
overwrite: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const path = tslib_1.__importStar(require("path"));
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
6
|
+
const getAll_1 = require("../types/getAll");
|
|
7
|
+
const export_1 = require("../users/export");
|
|
8
|
+
class ExportInstance extends core_1.Command {
|
|
9
|
+
async run() {
|
|
10
|
+
const { flags } = await this.parse(ExportInstance);
|
|
11
|
+
await (0, getAll_1.getAll)(flags.outDir, flags.overwrite);
|
|
12
|
+
await (0, export_1.exportUsers)(path.join(flags.outDir, 'users.yml'), flags.overwrite);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.default = ExportInstance;
|
|
16
|
+
ExportInstance.description = 'Exports an data of an instance including types and users';
|
|
17
|
+
ExportInstance.examples = [
|
|
18
|
+
`$ contrail instance export
|
|
19
|
+
`,
|
|
20
|
+
];
|
|
21
|
+
ExportInstance.flags = {
|
|
22
|
+
outDir: core_1.Flags.string({ description: 'The directory to which to export the instance data. Defaults to the current directory', required: false, default: '.' }),
|
|
23
|
+
overwrite: core_1.Flags.boolean({ description: 'Replaces any existing export files in outDir', required: false, default: false })
|
|
24
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ImportInstance extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
dir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const path = tslib_1.__importStar(require("path"));
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
6
|
+
const loadAll_1 = require("../types/loadAll");
|
|
7
|
+
const upload_1 = require("../users/upload");
|
|
8
|
+
class ImportInstance extends core_1.Command {
|
|
9
|
+
async run() {
|
|
10
|
+
const { flags } = await this.parse(ImportInstance);
|
|
11
|
+
await (0, loadAll_1.loadAll)(flags.dir);
|
|
12
|
+
await (0, upload_1.uploadUsers)(path.join(flags.dir, 'users.yml'));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.default = ImportInstance;
|
|
16
|
+
ImportInstance.description = 'Import the data to an instance, including types and users';
|
|
17
|
+
ImportInstance.examples = [
|
|
18
|
+
`$ contrail instance import
|
|
19
|
+
`,
|
|
20
|
+
];
|
|
21
|
+
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: '.' }),
|
|
23
|
+
};
|
|
@@ -22,8 +22,12 @@ export interface ReducedDataHolder {
|
|
|
22
22
|
export default class GetAllTypes extends Command {
|
|
23
23
|
static description: string;
|
|
24
24
|
static examples: string[];
|
|
25
|
+
static flags: {
|
|
26
|
+
outDir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
27
|
+
overwrite: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
};
|
|
25
29
|
run(): Promise<void>;
|
|
26
30
|
}
|
|
27
|
-
export declare function getAll(): Promise<void>;
|
|
31
|
+
export declare function getAll(outDir: string, overwrite: boolean): Promise<void>;
|
|
28
32
|
export declare function reduceTypes(dataHolder: DataHolder): any[];
|
|
29
33
|
export declare function reduceData(data: DataHolder): ReducedDataHolder;
|
|
@@ -9,10 +9,12 @@ const login_1 = require("../../auth/login");
|
|
|
9
9
|
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
|
+
const file_helpers_1 = require("../../helpers/file-helpers");
|
|
12
13
|
const yaml = require('js-yaml');
|
|
13
14
|
class GetAllTypes extends core_1.Command {
|
|
14
15
|
async run() {
|
|
15
|
-
await
|
|
16
|
+
const { flags } = await this.parse(GetAllTypes);
|
|
17
|
+
await getAll(flags.outDir, flags.overwrite);
|
|
16
18
|
}
|
|
17
19
|
}
|
|
18
20
|
exports.default = GetAllTypes;
|
|
@@ -21,13 +23,18 @@ GetAllTypes.examples = [
|
|
|
21
23
|
`$ contrail types getAll
|
|
22
24
|
`,
|
|
23
25
|
];
|
|
24
|
-
|
|
26
|
+
GetAllTypes.flags = {
|
|
27
|
+
outDir: core_1.Flags.string({ char: 'd', description: 'The directory to which to export the type data. Defaults to the current directory', required: false, default: '.' }),
|
|
28
|
+
overwrite: core_1.Flags.boolean({ description: 'Replaces any existing export files in outDir', required: false, default: false })
|
|
29
|
+
};
|
|
30
|
+
async function getAll(outDir, overwrite) {
|
|
25
31
|
try {
|
|
26
32
|
const userConfig = await (0, login_1.authUser)();
|
|
27
33
|
console.log(`%s Getting all types for orgId: ${userConfig.orgId}`, chalk_1.default.blue.bold('START'));
|
|
28
34
|
// make directory to house exports
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
if (!fs_1.default.existsSync(path.resolve(outDir))) {
|
|
36
|
+
fs_1.default.mkdirSync(path.resolve(outDir));
|
|
37
|
+
}
|
|
31
38
|
const data = {
|
|
32
39
|
types: await (0, type_extractor_1.getTypes)(),
|
|
33
40
|
optionSets: await (0, types_1.getOptionSets)(),
|
|
@@ -39,7 +46,7 @@ async function getAll() {
|
|
|
39
46
|
typePropertyPolicyLinks: await (0, types_1.getTypePropertyPolicyLinks)(),
|
|
40
47
|
};
|
|
41
48
|
const reducedData = reduceData(data);
|
|
42
|
-
saveData(reducedData,
|
|
49
|
+
await saveData(reducedData, outDir, overwrite);
|
|
43
50
|
console.log('%s Retrieved', chalk_1.default.yellow.bold('TYPES'));
|
|
44
51
|
}
|
|
45
52
|
catch (e) {
|
|
@@ -196,7 +203,7 @@ function reduceData(data) {
|
|
|
196
203
|
};
|
|
197
204
|
}
|
|
198
205
|
exports.reduceData = reduceData;
|
|
199
|
-
const saveTypesFunction =
|
|
206
|
+
const saveTypesFunction = async (data, dir, overwrite) => {
|
|
200
207
|
const roots = {};
|
|
201
208
|
for (const type of data.reducedTypes) {
|
|
202
209
|
const typePathParts = type.typePath.split(':');
|
|
@@ -222,10 +229,14 @@ const saveTypesFunction = function (data, dir) {
|
|
|
222
229
|
if (!fileLabel) {
|
|
223
230
|
console.warn('skipping bad type root:', root);
|
|
224
231
|
}
|
|
225
|
-
|
|
232
|
+
const pathToWrite = path.join(subDir, `${removeSlash(fileLabel)}.yml`);
|
|
233
|
+
if (fs_1.default.existsSync(pathToWrite)) {
|
|
234
|
+
await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
|
|
235
|
+
}
|
|
236
|
+
fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
|
|
226
237
|
}
|
|
227
238
|
};
|
|
228
|
-
function saveData(reducedData, dir) {
|
|
239
|
+
async function saveData(reducedData, dir, overwrite) {
|
|
229
240
|
const propertyToFolderMap = {
|
|
230
241
|
reducedTypes: { filename: 'types', split: false, fileLabel: 'slug', saveFunction: saveTypesFunction },
|
|
231
242
|
reducedOptionSets: { filename: 'option-sets', split: true, fileLabel: 'name' },
|
|
@@ -239,7 +250,7 @@ function saveData(reducedData, dir) {
|
|
|
239
250
|
for (const [key, folder] of Object.entries(propertyToFolderMap)) {
|
|
240
251
|
const CURRENT_DIR = process.cwd();
|
|
241
252
|
if (folder['saveFunction']) {
|
|
242
|
-
folder['saveFunction'](reducedData, dir);
|
|
253
|
+
await folder['saveFunction'](reducedData, dir, overwrite);
|
|
243
254
|
}
|
|
244
255
|
else if (folder.split) {
|
|
245
256
|
const subDir = path.join(CURRENT_DIR, dir, folder.filename);
|
|
@@ -251,13 +262,22 @@ function saveData(reducedData, dir) {
|
|
|
251
262
|
const fileLabel = item[folder.fileLabel];
|
|
252
263
|
if (!fileLabel) {
|
|
253
264
|
console.warn('skipping bad data:', item);
|
|
265
|
+
continue;
|
|
254
266
|
}
|
|
255
|
-
|
|
267
|
+
const pathToWrite = path.join(subDir, `${removeSlash(fileLabel)}.yml`);
|
|
268
|
+
if (fs_1.default.existsSync(pathToWrite)) {
|
|
269
|
+
await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
|
|
270
|
+
}
|
|
271
|
+
fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
|
|
256
272
|
}
|
|
257
273
|
}
|
|
258
274
|
else {
|
|
259
275
|
const yamlStr = yaml.dump(reducedData[key]);
|
|
260
|
-
|
|
276
|
+
const pathToWrite = path.join(CURRENT_DIR, dir, `${folder.filename}.yml`);
|
|
277
|
+
if (fs_1.default.existsSync(pathToWrite)) {
|
|
278
|
+
await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
|
|
279
|
+
}
|
|
280
|
+
fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
|
|
261
281
|
}
|
|
262
282
|
}
|
|
263
283
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
export default class
|
|
2
|
+
export default class LoadAllTypes extends Command {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
dir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
7
|
+
};
|
|
5
8
|
run(): Promise<void>;
|
|
6
9
|
}
|
|
7
|
-
export declare function loadAll(): Promise<void>;
|
|
10
|
+
export declare function loadAll(dir: string): Promise<void>;
|
|
@@ -11,26 +11,30 @@ const uploadUsageInfo_1 = require("./uploadUsageInfo");
|
|
|
11
11
|
const uploadRuleSets_1 = require("./uploadRuleSets");
|
|
12
12
|
const uploadTypePropertyPolicies_1 = require("./uploadTypePropertyPolicies");
|
|
13
13
|
const type_uploader_1 = require("../../helpers/types/type-uploader");
|
|
14
|
-
class
|
|
14
|
+
class LoadAllTypes extends core_1.Command {
|
|
15
15
|
async run() {
|
|
16
|
-
await
|
|
16
|
+
const { flags } = await this.parse(LoadAllTypes);
|
|
17
|
+
await loadAll(flags.dir);
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
|
-
exports.default =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`$ contrail types
|
|
20
|
+
exports.default = LoadAllTypes;
|
|
21
|
+
LoadAllTypes.description = 'loads all the type data that has been exported by getAll';
|
|
22
|
+
LoadAllTypes.examples = [
|
|
23
|
+
`$ contrail types loadAll
|
|
23
24
|
`,
|
|
24
25
|
];
|
|
25
|
-
|
|
26
|
+
LoadAllTypes.flags = {
|
|
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
|
+
};
|
|
29
|
+
async function loadAll(dir) {
|
|
26
30
|
try {
|
|
27
31
|
await (0, login_1.authUser)();
|
|
28
|
-
await (0, uploadOptionSets_1.uploadOptionSets)();
|
|
29
|
-
await (0, uploadOptionSetHierarchies_1.uploadOptionSetHierarchies)();
|
|
30
|
-
await (0, type_uploader_1.uploadTypes)();
|
|
31
|
-
await (0, uploadUsageInfo_1.uploadUsageInfo)();
|
|
32
|
-
await (0, uploadRuleSets_1.uploadRuleSets)();
|
|
33
|
-
await (0, uploadTypePropertyPolicies_1.uploadTypePropertyPolicies)();
|
|
32
|
+
await (0, uploadOptionSets_1.uploadOptionSets)(dir);
|
|
33
|
+
await (0, uploadOptionSetHierarchies_1.uploadOptionSetHierarchies)(dir);
|
|
34
|
+
await (0, type_uploader_1.uploadTypes)(dir);
|
|
35
|
+
await (0, uploadUsageInfo_1.uploadUsageInfo)(dir);
|
|
36
|
+
await (0, uploadRuleSets_1.uploadRuleSets)(dir);
|
|
37
|
+
await (0, uploadTypePropertyPolicies_1.uploadTypePropertyPolicies)(dir);
|
|
34
38
|
}
|
|
35
39
|
catch (e) {
|
|
36
40
|
console.log(`%s Types Upload Failed. ${e}`, chalk_1.default.red.bold('FAIL'));
|
|
@@ -2,6 +2,9 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
export default class UploadOptionSetHierarchies extends Command {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
dir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
7
|
+
};
|
|
5
8
|
run(): Promise<void>;
|
|
6
9
|
}
|
|
7
|
-
export declare function uploadOptionSetHierarchies(): Promise<void>;
|
|
10
|
+
export declare function uploadOptionSetHierarchies(dir: string): Promise<void>;
|
|
@@ -11,20 +11,24 @@ const core_1 = require("@oclif/core");
|
|
|
11
11
|
const yaml = require('js-yaml');
|
|
12
12
|
class UploadOptionSetHierarchies extends core_1.Command {
|
|
13
13
|
async run() {
|
|
14
|
-
|
|
14
|
+
const { flags } = await this.parse(UploadOptionSetHierarchies);
|
|
15
|
+
return await uploadOptionSetHierarchies(flags.dir);
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
exports.default = UploadOptionSetHierarchies;
|
|
18
|
-
UploadOptionSetHierarchies.description = 'Upload
|
|
19
|
+
UploadOptionSetHierarchies.description = 'Upload Option Set Hierarchies for your Org. Option set hierarchies are loaded from .yml files in the option-set-hierarchies directory.';
|
|
19
20
|
UploadOptionSetHierarchies.examples = [
|
|
20
21
|
`$ contrail types uploadOptionSetHierarchies
|
|
21
22
|
`,
|
|
22
23
|
];
|
|
23
|
-
|
|
24
|
+
UploadOptionSetHierarchies.flags = {
|
|
25
|
+
dir: core_1.Flags.string({ char: 'd', description: 'The directory from which to export the option set hierarchies data. Defaults to the current directory. The option set data will be loaded from $dir/option-set-hierarchies', required: false, default: '.' }),
|
|
26
|
+
};
|
|
27
|
+
async function uploadOptionSetHierarchies(dir) {
|
|
24
28
|
try {
|
|
25
29
|
await (0, login_1.authUser)();
|
|
26
30
|
console.log('%s Uploading', chalk_1.default.yellow.bold('OPTION SET HIERARCHIES'));
|
|
27
|
-
const optionSetHierarchies = await loadOptionSetHierarchies();
|
|
31
|
+
const optionSetHierarchies = await loadOptionSetHierarchies(dir);
|
|
28
32
|
await uploadOSH(optionSetHierarchies);
|
|
29
33
|
console.log('%s Uploaded', chalk_1.default.yellow.bold('OPTION SET HIERARCHIES'));
|
|
30
34
|
}
|
|
@@ -35,13 +39,13 @@ async function uploadOptionSetHierarchies() {
|
|
|
35
39
|
console.log('%s Option set hierarchy Upload Complete.', chalk_1.default.green.bold('COMPLETE'));
|
|
36
40
|
}
|
|
37
41
|
exports.uploadOptionSetHierarchies = uploadOptionSetHierarchies;
|
|
38
|
-
function loadOptionSetHierarchies() {
|
|
39
|
-
const TARGET_DIR = process.cwd();
|
|
42
|
+
function loadOptionSetHierarchies(fromDir) {
|
|
40
43
|
try {
|
|
41
|
-
const
|
|
44
|
+
const dir = path.resolve(path.join(fromDir, 'option-set-hierarchies'));
|
|
45
|
+
const files = fs_1.default.readdirSync(dir);
|
|
42
46
|
const OSHs = [];
|
|
43
47
|
for (const file of files) {
|
|
44
|
-
OSHs.push(yaml.load(fs_1.default.readFileSync(path.join(
|
|
48
|
+
OSHs.push(yaml.load(fs_1.default.readFileSync(path.join(dir, file), 'utf8')));
|
|
45
49
|
}
|
|
46
50
|
return OSHs;
|
|
47
51
|
}
|
|
@@ -117,7 +121,7 @@ async function uploadOSH(loadedOSHs) {
|
|
|
117
121
|
}
|
|
118
122
|
// transforms the passed hierarchy from names to ids, and returns true if operation succeeded.
|
|
119
123
|
function transformOSHNameToID(hierarchy, optionSets) {
|
|
120
|
-
console.log('passed
|
|
124
|
+
console.log('passed hierarchy:', hierarchy);
|
|
121
125
|
for (let i = 0; i < hierarchy.length; i++) {
|
|
122
126
|
const os = optionSets.find(os => os.name === hierarchy[i]);
|
|
123
127
|
if (!os) {
|