UNPKG

@c8y/toolkit

Version:

Toolkit for Cumulocity applications, allows to e.g. deploy an application to an instance of Cumulocity.

142 lines 7.15 kB
"use strict"; 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