public async createSimulation()

in source/packages/services/simulation-manager/src/simulations/simulations.service.ts [47:150]


    public async createSimulation(request: CreateSimulationRequest): Promise<string> {
        logger.debug(`simulations.service createSimulation: request:${JSON.stringify(request)}`);

        // validation
        ow(request, ow.object.nonEmpty);
        const { simulation, taskOverrides } = request;
        ow(simulation, ow.object.nonEmpty);
        ow(simulation.name, ow.string.nonEmpty);
        ow(simulation.deviceCount, ow.number.greaterThan(0));

        if (taskOverrides?.taskRoleArn) {
            // eslint-disable-next-line no-unsafe-optional-chaining
            const [_, roleName] = taskOverrides?.taskRoleArn.split('/');
            ow(roleName, ow.string.startsWith('cdf-simulation-launcher'));
        }

        simulation.id = generate();
        simulation.status = SimulationStatus.preparing;
        await this._dao.save(simulation);

        // TODO: run any configured setup tasks

        // launch any configured provisioning task asynchronously
        const task = simulation.tasks.provisioning;
        if (task) {
            const threadsPerInstance = Number(process.env.RUNNERS_THREADS);
            const numInstances = Math.ceil(task.threads.total / threadsPerInstance);
            const devicesPerInstance = Math.ceil(simulation.deviceCount / numInstances);
            const s3RootKey = `${this._s3Prefix}${simulation.id}/provisioning/`;
            const simulationPlanKey = `${s3RootKey}plan.jmx`;

            logger.debug(`simulations.service s3RootKey:${s3RootKey}`);
            logger.debug(`simulations.service simulationPlanKey:${simulationPlanKey}`);
            logger.debug(`simulations.service copySource:/${this._s3Bucket}/${task.plan}`);
            logger.debug(`simulations.service numInstances:${numInstances}`);
            logger.debug(`simulations.service devicesPerInstance:${devicesPerInstance}`);

            // copy the test plan

            await this._s3
                .copyObject({
                    CopySource: `/${this._s3Bucket}/${task.plan}`,
                    Bucket: this._s3Bucket,
                    Key: simulationPlanKey,
                })
                .promise();

            // prepare the config for each instance
            const properties: TemplateProperties = {
                config: {
                    aws: {
                        iot: {
                            host: process.env.AWS_IOT_HOST,
                        },
                        region: process.env.AWS_REGION,
                        s3: {
                            bucket: process.env.AWS_S3_BUCKET,
                            prefix: process.env.AWS_S3_PREFIX,
                        },
                    },
                    cdf: {
                        assetlibrary: {
                            mimetype: process.env.ASSETLIBRARY_MIMETYPE,
                            apiFunctionName: process.env.ASSETLIBRARY_API_FUNCTION_NAME,
                        },
                    },
                    runners: {
                        dataDir: process.env.RUNNERS_DATADIR,
                    },
                },
                simulation: simulation,
                instance: {
                    id: 0,
                    devices: devicesPerInstance,
                    threads: threadsPerInstance,
                },
            };

            const template = fs.readFileSync(process.env.TEMPLATES_PROVISIONING, 'utf8');
            const compiledTemplate = handlebars.compile(template);

            for (let instanceId = 1; instanceId <= numInstances; instanceId++) {
                properties.instance.id = instanceId;
                const propertyFile = compiledTemplate(properties);

                const s3Key = `${s3RootKey}instances/${instanceId}/properties`;
                await this._s3
                    .putObject({
                        Bucket: this._s3Bucket,
                        Key: s3Key,
                        Body: propertyFile,
                    })
                    .promise();
            }

            // Launch provisioning tasks
            await this.launchRunner(simulation.id, numInstances, s3RootKey, taskOverrides);
            simulation.status = SimulationStatus.provisioning;
            await this._dao.save(simulation);
        }

        logger.debug(`simulations.service create: exit:${simulation.id}`);
        return simulation.id;
    }