@c8y/toolkit
Version:
Toolkit for Cumulocity applications, allows to e.g. deploy an application to an instance of Cumulocity.
142 lines • 7.15 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTenant = createTenant;
const client_1 = require("@c8y/client");
const client_2 = require("./client");
const chalk_1 = __importDefault(require("chalk"));
const lodash_1 = require("lodash");
async function createTenant(options) {
const { user, password, url, tenant } = options;
const client = await (0, client_2.createClient)({ user, password, url, tenant });
console.log(chalk_1.default.green('Provided credentials are valid.'));
if (!options.domainNamePrefix) {
options.domainNamePrefix = crypto.randomUUID();
}
const matches = url.match(/\.([a-zA-Z0-9\.\-_]*)/);
if (!matches || matches.length < 1) {
throw new Error('Invalid URL format.');
}
const baseDomain = matches[1];
const adminName = options.tenantUser || user;
const adminPass = options.tenantPassword || password;
for (let i = 0; i < (options.tenantsNumber || 1); i++) {
const newDomain = `${options.domainNamePrefix}${options.noTenantSuffix === false ? i + 1 : ''}.${baseDomain}`;
let { data: tenant } = await client.tenant.create({
company: options.companyName,
contactName: options.contactName,
contactPhone: options.contactPhone,
adminName,
adminPass,
adminEmail: 'e2edocker@cumulocity.com',
domain: newDomain
});
console.log(chalk_1.default.green(`Tenant ${tenant.domain} (${tenant.id}) created successfully.`));
if (options.allowCreateTenants) {
tenant = await makeItAnEnterpriseTenant(client, tenant);
}
await subscribeMicroservices(client, tenant, options.applicationsToBeSubscribed.split(','));
const subtenantClientInstance = await client_1.Client.authenticate({
user: adminName,
password: adminPass,
tenant: tenant.id
}, url);
await addPermissionsToAdminRole(subtenantClientInstance);
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function makeItAnEnterpriseTenant(client, tenant) {
const { data: updatedTenant } = await client.tenant.update({
id: tenant.id,
allowCreateTenants: true,
customProperties: {
gainsightEnabled: true
}
});
console.log(`Tenant ${updatedTenant.domain} (${updatedTenant.id}) is now allowed to create subtenants.`);
return updatedTenant;
}
async function subscribeMicroservices(client, tenant, applicationsToBeSubscribed) {
const { data: applications } = await client.application.listByOwner('management', {
pageSize: 2000
});
applicationsToBeSubscribed = applicationsToBeSubscribed
.map(appName => appName.trim())
.filter(appName => appName.length > 0);
const applicationsToSubscribe = applications.filter(app => app.name && applicationsToBeSubscribed.includes(app.name));
if (applicationsToSubscribe.length < applicationsToBeSubscribed.length) {
const missingApps = applicationsToBeSubscribed.filter(appName => !applicationsToSubscribe.some(app => app.name === appName));
console.warn(chalk_1.default.yellow(`The following applications were not found: ${missingApps.join(', ')} and will not be subscribed.`));
}
if (applicationsToSubscribe.length === 0) {
console.log(chalk_1.default.green('No applications to subscribe.'));
return;
}
for (const app of applicationsToSubscribe) {
if (tenant.applications?.references.some(ref => ref.application.id === app.id)) {
console.log(`Tenant ${tenant.domain} is already subscribed to application ${app.name} (${app.id}).`);
continue;
}
await client.tenant.subscribeApplication(tenant, app);
console.log(chalk_1.default.green(`Subscribed tenant ${tenant.domain} to application ${app.name} (${app.id}).`));
}
}
async function getPermissionsOfTenant(client) {
const { data: permissions } = await client.userRole.list({ pageSize: 2000 });
const permissionIds = permissions.map(permission => permission.id);
return { permissions, permissionIds };
}
/**
* Ensures that all permissions of all applications are available in the tenant.
* This is necessary because the permissions are not available immediately after creating a tenant and subscribing applications.
* Permissions of applications might be created asynchronously.
*/
async function ensureAllPermissionsOfAppsAreAvailable(client) {
const { data: apps } = await client.application.list({ pageSize: 2000 });
const permissionsOfApps = (0, lodash_1.uniq)(apps.map(app => app.roles || []).flat());
let permissions = [];
let permissionIds = [];
const maxIterations = 20;
let currentIteration = 1;
while (true) {
const { permissions: permissionsOfTenant, permissionIds: permissionIdsOfTenant } = await getPermissionsOfTenant(client);
const missingPermissions = permissionsOfApps.filter(permission => !permissionIdsOfTenant.includes(permission));
if (missingPermissions.length === 0) {
permissions = permissionsOfTenant;
permissionIds = permissionIdsOfTenant;
break;
}
console.log(chalk_1.default.yellow(`Not all permissions of all applications are yet available.`));
console.log(chalk_1.default.yellow(`The following permissions are missing: ${missingPermissions.join(', ')}`));
if (currentIteration >= maxIterations) {
throw new Error(`Permissions of applications are not yet available. The follwing permissions are missing: ${missingPermissions.join(', ')}`);
}
console.log(chalk_1.default.yellow(`Waiting for one second before retrying...`));
await sleep(1000);
currentIteration++;
}
return { permissions, permissionIds };
}
async function addPermissionsToAdminRole(client) {
const { permissions, permissionIds } = await ensureAllPermissionsOfAppsAreAvailable(client);
const { data: allUserGroups } = await client.userGroup.list({ pagePize: 2000 });
const adminUserGroup = allUserGroups.find(group => group.name === 'admins');
if (!adminUserGroup) {
throw new Error('Admin user group not found');
}
const alreadyAssignedPermissions = adminUserGroup.roles?.references.map(role => role.role.id) || [];
const permissionsToAdd = permissionIds.filter(permission => !alreadyAssignedPermissions.includes(permission));
if (permissionsToAdd.length === 0) {
console.log(chalk_1.default.green('No new permissions to add to admin user group.'));
return;
}
for (const permission of permissionsToAdd) {
await client.userGroup.addRoleToGroup(adminUserGroup, permissions.find(p => p.id === permission));
console.log(chalk_1.default.green(`Permission ${permission} added to admin user group.`));
}
}
//# sourceMappingURL=create-tenant.js.map