device-simulation-dotnet/Services/Simulations.cs

775 строки
31 KiB
C#
Исходник Обычный вид История

// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Exceptions;
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.IotHub;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Runtime;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Statistics;
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Storage;
2017-09-23 04:34:25 +03:00
using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.StorageAdapter;
using Newtonsoft.Json;
namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services
{
public interface ISimulations
{
2018-10-01 20:08:31 +03:00
// Get list of simulations.
// This will have better perf than GetListWithStatisticsAsync.
Task<IList<Models.Simulation>> GetListAsync();
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
// Get list of simulations with statistics.
Task<IList<Models.Simulation>> GetListWithStatisticsAsync();
2018-10-01 20:08:31 +03:00
// Get a simulation.
// This will have better perf than GetWithStatisticsAsync.
Task<Models.Simulation> GetAsync(string id);
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
// Get a simulation with statistics.
Task<Models.Simulation> GetWithStatisticsAsync(string id);
2018-10-01 20:08:31 +03:00
// Create a simulation.
Task<Models.Simulation> InsertAsync(Models.Simulation simulation, string template = "");
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
2018-10-01 20:08:31 +03:00
// Create or Replace a simulation.
Task<Models.Simulation> UpsertAsync(Models.Simulation simulation, bool validateHubCredentials);
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
2018-10-01 20:08:31 +03:00
// Modify a simulation.
Task<Models.Simulation> MergeAsync(SimulationPatch patch);
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
2018-10-01 20:08:31 +03:00
// Add a device to simulation
Task AddDeviceAsync(string id);
// Delete a simulation and its statistics (not the devices).
Task DeleteAsync(string id);
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
// Seed default simulations
Task TrySeedAsync();
2018-10-01 20:08:31 +03:00
// Try to start a job to create all the devices
Task<bool> TryToStartDevicesCreationAsync(string simulationId, IDevices devices);
// Change the simulation, setting the device creation complete
Task<bool> TryToSetDeviceCreationCompleteAsync(string simulationId);
// Create a job to delete all the devices (used by web service on user request)
Task<(bool jobCreated, string jobId)> DeleteAllDevicesAsync(string simulationId, IDevices devices);
// Try to start a job to delete all the devices (used by simulation agent when a simulation ends)
Task<bool> TryToStartDevicesDeletionAsync(string simulationId, IDevices devices);
// Change the simulation, setting the device deletion complete
Task<bool> TryToSetDeviceDeletionCompleteAsync(string simulationId);
2018-10-01 20:08:31 +03:00
// Get the ID of the devices in a simulation.
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
IEnumerable<string> GetDeviceIds(Models.Simulation simulation);
// Get the ID of the devices in a simulation, grouped by device model ID.
Dictionary<string, List<string>> GetDeviceIdsByModel(Models.Simulation simulation);
// Generate a device Id
string GenerateId(string simulationId, string deviceModelId, int position);
}
public class Simulations : ISimulations
{
private const string DEFAULT_SIMULATION_ID = "1";
private const string DEFAULT_TEMPLATE_NAME = "default";
private const string DEVICES_COLLECTION = "SimulatedDevices";
private const string SEED_STATUS_KEY = "SeedCompleted";
Methods and docs (#40) This PR provides method support for chillers in the default simulation: reboot, firmware update, increase pressure, and decrease pressure. It also keeps reported properties in sync with desired properties (by polling for value changes). * DeviceMethod implmentation class * First round of methods, added: 1) infra for registering methods for devices, 2) walking avail. methods for each device. Main functionality missing is allowing specifation and then running the method script. * remove todo from actor * nits to code style * Move methods ownership from devicebootstrap to deviceclient. * error handling and todos. * retry method registration, minor fixes. * nits, logging, removed exception handling for registering methods (it's handled by the parent method) * bumped version * code style nits * Methods use scripts. Desired properties are polled in UpdateDeviceState and delta is copied into Reported property values. Telemetry is not sent if the device is marked other than online == "True" * code style/cleanup changes. change get query for simulations to linq query rather than iterating the list. * update version * Exception handling for updatedevicestate nit for rename method execution endpoint to include Async suffix. * nit fix comment code style * Inject scriptinterpreter. refactoring. * nits * state update bug * no need for scriptengine null check * Bootstrap individual methods, implement decreasepressure aka EMergencyValveRelease * remove connection string :( * fixed threading problem w/ methods, implemented & tested first four methods * Implement switch to turn random telemetry off; e.g. when increasepressure is called, wait until decreasepressure is called to turn it back on. * remove clearing of DeviceMethodStatus * Code style changes + fix some jslint errors * Fix js methods files * DeviceMethods code style changes * Devices.cs code style * JavascriptInterpreter.cs code style * script changes for messages, docs * Cleanup up Javascript functions, create Issue to track implementing functions not yet done. * Halve the amount of telemetry sent * Address PR comments. * issue for script interpreter todo * todos, nits, pr feedback
2017-09-08 01:08:26 +03:00
private const int DEVICES_PER_MODEL_IN_DEFAULT_TEMPLATE = 1;
private readonly IServicesConfig config;
private readonly IDeviceModels deviceModels;
private readonly IStorageAdapterClient storageAdapterClient;
private readonly IEngine mainStorage;
private readonly IEngine simulationsStorage;
private readonly IConnectionStrings connectionStrings;
private readonly ISimulationStatistics simulationStatistics;
private readonly IFileSystem fileSystem;
private readonly ILogger log;
private readonly IDiagnosticsLogger diagnosticsLogger;
public Simulations(
IServicesConfig config,
IDeviceModels deviceModels,
IEngines engines,
IStorageAdapterClient storageAdapterClient,
IConnectionStrings connectionStrings,
IFileSystem fileSystem,
ILogger logger,
IDiagnosticsLogger diagnosticsLogger,
ISimulationStatistics simulationStatistics)
{
this.config = config;
this.deviceModels = deviceModels;
this.storageAdapterClient = storageAdapterClient;
this.mainStorage = engines.Build(config.MainStorage);
this.simulationsStorage = engines.Build(config.SimulationsStorage);
this.connectionStrings = connectionStrings;
this.fileSystem = fileSystem;
this.log = logger;
this.diagnosticsLogger = diagnosticsLogger;
this.simulationStatistics = simulationStatistics;
}
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
/// <summary>
/// Get list of simulations.
/// </summary>
public async Task<IList<Models.Simulation>> GetListAsync()
{
var items = await this.simulationsStorage.GetAllAsync();
var result = new List<Models.Simulation>();
foreach (var item in items)
{
var simulation = JsonConvert.DeserializeObject<Models.Simulation>(item.GetData());
simulation.ETag = item.GetETag();
simulation.Id = item.GetId();
result.Add(simulation);
}
// TODO: This will need changes to support pagination. Also order should be by simulation Id.
return result.OrderByDescending(s => s.Created).ToList();
}
/// <summary>
/// Get list of simulations with statistics.
/// </summary>
public async Task<IList<Models.Simulation>> GetListWithStatisticsAsync()
{
var items = await this.GetListAsync();
foreach (var item in items)
{
item.Statistics = await this.simulationStatistics.GetSimulationStatisticsAsync(item.Id);
}
return items;
}
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
/// <summary>
/// Get a simulation.
/// </summary>
public async Task<Models.Simulation> GetAsync(string id)
{
var item = await this.simulationsStorage.GetAsync(id);
if (item == null) return null;
var simulation = JsonConvert.DeserializeObject<Models.Simulation>(item.GetData());
simulation.ETag = item.GetETag();
simulation.Id = item.GetId();
return simulation;
}
public async Task<Models.Simulation> GetWithStatisticsAsync(string id)
{
var simulation = await this.GetAsync(id);
if (simulation == null) return null;
simulation.Statistics = await this.simulationStatistics.GetSimulationStatisticsAsync(id);
return simulation;
}
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
/// <summary>
/// Create a simulation.
/// </summary>
public async Task<Models.Simulation> InsertAsync(Models.Simulation simulation, string template = "")
{
var usingDefaultTemplate = !string.IsNullOrEmpty(template) && template.ToLowerInvariant() == DEFAULT_TEMPLATE_NAME;
if (!string.IsNullOrEmpty(template) && template.ToLowerInvariant() != DEFAULT_TEMPLATE_NAME)
{
this.log.Warn("Unknown template name", () => new { template });
throw new InvalidInputException("Unknown template name. Try 'default'.");
}
if (!usingDefaultTemplate && string.IsNullOrEmpty(simulation.Name))
{
this.log.Warn("Missing simulation name", () => new { });
throw new InvalidInputException("Simulation name is required.");
}
// Note: forcing the ID because only one simulation can be created
simulation.Id = usingDefaultTemplate ? DEFAULT_SIMULATION_ID : Guid.NewGuid().ToString();
simulation.Created = DateTimeOffset.UtcNow;
// Create default simulation
if (usingDefaultTemplate)
{
simulation.Name = "Default Simulation";
var types = await this.deviceModels.GetListAsync();
simulation.DeviceModels = new List<Models.Simulation.DeviceModelRef>();
foreach (var type in types)
{
simulation.DeviceModels.Add(new Models.Simulation.DeviceModelRef
{
Id = type.Id,
Methods and docs (#40) This PR provides method support for chillers in the default simulation: reboot, firmware update, increase pressure, and decrease pressure. It also keeps reported properties in sync with desired properties (by polling for value changes). * DeviceMethod implmentation class * First round of methods, added: 1) infra for registering methods for devices, 2) walking avail. methods for each device. Main functionality missing is allowing specifation and then running the method script. * remove todo from actor * nits to code style * Move methods ownership from devicebootstrap to deviceclient. * error handling and todos. * retry method registration, minor fixes. * nits, logging, removed exception handling for registering methods (it's handled by the parent method) * bumped version * code style nits * Methods use scripts. Desired properties are polled in UpdateDeviceState and delta is copied into Reported property values. Telemetry is not sent if the device is marked other than online == "True" * code style/cleanup changes. change get query for simulations to linq query rather than iterating the list. * update version * Exception handling for updatedevicestate nit for rename method execution endpoint to include Async suffix. * nit fix comment code style * Inject scriptinterpreter. refactoring. * nits * state update bug * no need for scriptengine null check * Bootstrap individual methods, implement decreasepressure aka EMergencyValveRelease * remove connection string :( * fixed threading problem w/ methods, implemented & tested first four methods * Implement switch to turn random telemetry off; e.g. when increasepressure is called, wait until decreasepressure is called to turn it back on. * remove clearing of DeviceMethodStatus * Code style changes + fix some jslint errors * Fix js methods files * DeviceMethods code style changes * Devices.cs code style * JavascriptInterpreter.cs code style * script changes for messages, docs * Cleanup up Javascript functions, create Issue to track implementing functions not yet done. * Halve the amount of telemetry sent * Address PR comments. * issue for script interpreter todo * todos, nits, pr feedback
2017-09-08 01:08:26 +03:00
Count = DEVICES_PER_MODEL_IN_DEFAULT_TEMPLATE
});
}
simulation.IotHubConnectionStrings = new List<string> { ServicesConfig.USE_DEFAULT_IOTHUB };
}
2018-09-21 20:23:51 +03:00
for (var index = 0; index < simulation.IotHubConnectionStrings.Count; index++)
{
var connString = await this.connectionStrings.SaveAsync(simulation.IotHubConnectionStrings[index], true);
2018-09-21 20:23:51 +03:00
if (!simulation.IotHubConnectionStrings.Contains(connString))
{
simulation.IotHubConnectionStrings[index] = connString;
}
}
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
// This value cannot be set by the user, we set it here and make sure it's "false"
simulation.PartitioningComplete = false;
return await this.SaveAsync(simulation, "*");
}
/// <summary>
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
/// Create or Replace a simulation.
/// The logic works under the assumption that there is only one simulation with id "1".
/// </summary>
public async Task<Models.Simulation> UpsertAsync(Models.Simulation simulation, bool validateHubCredentials)
{
if (string.IsNullOrEmpty(simulation.Id))
{
throw new InvalidInputException("Simulation ID is not specified.");
}
2018-09-21 20:23:51 +03:00
Models.Simulation existingSimulation = null;
try
{
existingSimulation = await this.GetAsync(simulation.Id);
}
catch (ResourceNotFoundException)
{
// Do nothing - this mean simulation does not exist in storage
// Therefore allow to create a new simulation
this.log.Info("Simulation not found in storage, hence proceeding to create new simulation");
}
var simulationIsRestarting = false;
var simulationIsStopping = false;
if (existingSimulation != null)
{
this.log.Info("Modifying simulation");
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
if (simulation.ETag == "*")
{
simulation.ETag = existingSimulation.ETag;
this.log.Warn("The client used ETag='*' choosing to overwrite the current simulation");
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
}
if (simulation.ETag != existingSimulation.ETag)
{
this.log.Error("Invalid simulation ETag",
() => new { simulation.Id, ETagInStorage = existingSimulation.ETag, ETagInRequest = simulation.ETag });
this.diagnosticsLogger.LogServiceError($"Invalid simulation ETag", new { simulation.Id, simulation.Name });
throw new ResourceOutOfDateException($"Invalid ETag. The simulation ETag is '{existingSimulation.ETag}'");
}
// Define the user intent looking at the simulation status and the patch content
simulationIsRestarting = !existingSimulation.Enabled && simulation.Enabled;
simulationIsStopping = existingSimulation.Enabled && !simulation.Enabled;
simulation.Created = existingSimulation.Created;
}
else
{
this.log.Info("Creating new simulation");
simulation.Created = DateTimeOffset.UtcNow;
// This value cannot be set by the user, we set it here and make sure it's "false"
simulation.PartitioningComplete = false;
}
for (var index = 0; index < simulation.IotHubConnectionStrings.Count; index++)
{
var connString = await this.connectionStrings.SaveAsync(simulation.IotHubConnectionStrings[index], validateHubCredentials);
2018-09-21 20:23:51 +03:00
if (!simulation.IotHubConnectionStrings.Contains(connString))
{
simulation.IotHubConnectionStrings[index] = connString;
}
}
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
// Note: this code is also in MergeAsync
// (consider refactoring it out unless the code becomes harder to follow)
if (simulationIsRestarting)
{
simulation = await this.ResetSimulationStatisticsAsync(simulation);
}
else if (simulationIsStopping)
{
simulation.StoppedTime = DateTimeOffset.UtcNow;
// When a simulation is disabled, its partitions are deleted.
// This boolean triggers the deletion of partitions from the storage
// in the partitioning agent.
simulation.PartitioningComplete = false;
}
return await this.SaveAsync(simulation, simulation.ETag);
}
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
/// <summary>
/// Modify some simulation details
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
/// </summary>
public async Task<Models.Simulation> MergeAsync(SimulationPatch patch)
{
if (string.IsNullOrEmpty(patch.Id))
{
this.log.Warn("Invalid simulation ID.", () => new { patch.Id });
throw new InvalidInputException("Invalid simulation ID.");
}
var item = await this.simulationsStorage.GetAsync(patch.Id);
var simulation = JsonConvert.DeserializeObject<Models.Simulation>(item.GetData());
simulation.ETag = item.GetETag();
simulation.Id = item.GetId();
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
// Even when there's nothing to do, verify the ETag mismatch
if (patch.ETag != simulation.ETag)
{
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
this.log.Warn("ETag mismatch",
() => new { Current = simulation.ETag, Provided = patch.ETag });
throw new ConflictingResourceException(
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
$"The ETag provided doesn't match the current resource ETag ({simulation.ETag}).");
}
// Define the user intent looking at the simulation status and the patch content
var simulationIsRestarting = !simulation.Enabled && patch.Enabled.HasValue && patch.Enabled.Value;
var simulationIsStopping = simulation.Enabled && patch.Enabled.HasValue && !patch.Enabled.Value;
// Note: this code is also in UpsertAsync
// (consider refactoring it out unless the code becomes harder to follow)
if (simulationIsRestarting)
{
simulation = await this.ResetSimulationStatisticsAsync(simulation);
}
else if (simulationIsStopping)
{
simulation.StoppedTime = DateTimeOffset.UtcNow;
// When a simulation is disabled, its partitions are deleted.
// This boolean triggers the deletion of partitions from the storage
// in the partitioning agent.
simulation.PartitioningComplete = false;
// Reset active device count to 0
await this.ResetActiveDevicesStatistics(simulation);
}
// The Enabled field is optional, e.g. in case PATCH is extended to
// modify other fields, so we need to check for null
if (patch.Enabled != null) simulation.Enabled = patch.Enabled.Value;
if (patch.DeleteDevicesOnce.HasValue)
{
simulation.DeleteDevicesOnce = patch.DeleteDevicesOnce.Value;
}
// TODO: can we use this.SaveAsync() here too and avoid the duplication?
var record = this.simulationsStorage.BuildRecord(simulation.Id, JsonConvert.SerializeObject(simulation));
item = await this.simulationsStorage.UpsertAsync(record, patch.ETag);
simulation.ETag = item.GetETag();
return simulation;
}
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
/// <summary>
/// Delete a simulation and its statistics (not the devices).
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
/// </summary>
public async Task DeleteAsync(string id)
{
await this.simulationStatistics.DeleteSimulationStatisticsAsync(id);
await this.simulationsStorage.DeleteAsync(id);
}
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
public async Task TrySeedAsync()
{
try
{
var templateName = this.config.SeedTemplate;
if (string.IsNullOrEmpty(templateName)) return;
// Skips if the seeding has already been complete
if (!await this.mainStorage.ExistsAsync(SEED_STATUS_KEY))
{
await this.SeedSimulationsAsync(templateName);
var record = this.mainStorage.BuildRecord(SEED_STATUS_KEY, "Seed Completed");
await this.mainStorage.CreateAsync(record);
}
else
{
this.log.Info("Seeding skipped.");
}
}
catch (Exception e)
{
var msg = "Failed to seed default simulations." + e;
this.log.Error(msg);
this.diagnosticsLogger.LogServiceError(msg);
}
}
2018-10-01 20:08:31 +03:00
public async Task<bool> TryToStartDevicesCreationAsync(string simulationId, IDevices devices)
{
// Fetch latest record
var simulation = await this.GetAsync(simulationId);
// Edit the record only if required
if (!simulation.DevicesCreationStarted)
{
try
{
Dictionary<string, List<string>> deviceList = this.GetDeviceIdsByModel(simulation);
var deviceIds = deviceList.SelectMany(x => x.Value);
this.log.Info("Creating devices...", () => new { simulationId });
simulation.DeviceCreationJobId = await devices.CreateListUsingJobsAsync(deviceIds);
simulation.DevicesCreationStarted = true;
this.log.Info("Import job created for bulk device creation", () => new { simulationId, simulation.DeviceCreationJobId });
await this.SaveAsync(simulation, simulation.ETag);
}
catch (Exception e)
{
this.log.Error("Failed to create bulk-device-creation job", e);
return false;
}
}
return true;
}
/// <summary>
/// Try to create a job to delete all the devices in a simulation.
/// Throw exception in case of errors.
///
/// This operation is not meant to modify the simulation object, so if the simulation
/// is still running it will cause errors due to the missing devices. The simulation
/// might as well recreate the devices if it is running, that is not a problem.
///
/// This method is invoked by the web service, exceptions are thrown to tell the user
/// what happened. At this point the UI doesn't consume this logic, which is used only
/// for maintenance.
/// </summary>
public async Task<(bool jobCreated, string jobId)> DeleteAllDevicesAsync(string simulationId, IDevices devices)
{
try
{
var (simulation, jobCreated, jobId) = await this.CreateJobToDeleteDevices(simulationId, devices);
return (jobCreated, jobId);
}
catch (Exception e)
{
this.log.Error("Failed to start bulk device deletion", e);
throw new ExternalDependencyException("Failed to start bulk device deletion", e);
}
}
/// <summary>
/// Try to create a job to delete all the devices in a simulation.
/// This method is used by the simulation agent when a simulation ends.
/// In case of errors the method returns 'false' and the caller is expected to retry.
/// </summary>
public async Task<bool> TryToStartDevicesDeletionAsync(string simulationId, IDevices devices)
{
try
{
var (simulation, jobCreated, jobId) = await this.CreateJobToDeleteDevices(simulationId, devices);
if (!jobCreated) return true;
simulation.DeviceDeletionJobId = jobId;
simulation.DevicesDeletionStarted = true;
2018-10-01 20:08:31 +03:00
await this.SaveAsync(simulation, simulation.ETag);
return true;
}
catch (Exception e)
{
this.log.Error("Failed to start bulk device deletion", e);
return false;
2018-10-01 20:08:31 +03:00
}
}
public async Task<bool> TryToSetDeviceCreationCompleteAsync(string simulationId)
{
var simulation = await this.GetAsync(simulationId);
// Edit the record only if required
if (simulation.DevicesCreationComplete) return true;
simulation.DevicesCreationComplete = true;
// Reset device deletion state
simulation.DevicesDeletionComplete = false;
simulation.DeviceDeletionJobId = null;
simulation.DevicesDeletionStarted = false;
return await this.TryToUpdateSimulationAsync(simulation);
}
public async Task<bool> TryToSetDeviceDeletionCompleteAsync(string simulationId)
{
var simulation = await this.GetAsync(simulationId);
// Edit the record only if required
if (simulation.DevicesDeletionComplete) return true;
simulation.DevicesDeletionComplete = true;
// Reset device creation state
simulation.DevicesCreationComplete = false;
simulation.DeviceCreationJobId = null;
simulation.DevicesCreationStarted = false;
simulation.DeleteDevicesOnce = false;
return await this.TryToUpdateSimulationAsync(simulation);
2018-10-01 20:08:31 +03:00
}
public async Task AddDeviceAsync(string id)
{
await this.storageAdapterClient.CreateAsync(DEVICES_COLLECTION, id, id);
}
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
/// <summary>
/// Get the ID of the devices in a simulation.
/// </summary>
public IEnumerable<string> GetDeviceIds(Models.Simulation simulation)
{
var deviceIds = new List<string>();
// Calculate the device IDs used in the simulation
var models = (from model in simulation.DeviceModels where model.Count > 0 select model).ToList();
foreach (var model in models)
{
for (var i = 0; i < model.Count; i++)
{
deviceIds.Add(this.GenerateId(simulation.Id, model.Id, i));
Merge azure-iot-pcs-simulation into master (#197) * Rewrite to use fewer threads and increase throughput * Expose simulation metrics in the status endpoint * When available, return a URL to the Azure Portal metrics of the pre-provisioned IoT Hub * Allow to run a simulation against a custom IoT Hub, passing the connection string * Allow to schedule a simulation, defining start and end time * Improve security by running the service as a non-root user * Support multiple behavior scripts in a device model * Support custom device with custom sensors, behavior and frequency * Allow to override the initial device state when creating a simulation * When a simulation starts, create all the devices in batches * When a simulation is deleted, delete also the devices * Refactor timers to start sending telemetry as soon as possible * Refactor and improve how simulation scripts access state and properties * Change stock models to use AMQP (#189) * Overall improvements to exceptions handling * Disable SDK retry, and change timeout from default (4 minutes) to 10 seconds * Do not retry sending telemetry on failure, skip message * Use IoT Hub S2 SKU limits by default * Upgrade to .NET Core 2.0.3 * Upgrade Azure IoT SDK: Devices 1.4.1 to 1.6.0, Devices Client 1.5.2 to 1.7.0 * Run simulation engine in the same process used for the web service * Move docs, move wiki, new API specs, fix scripts for Windows Bash * Fix the spelling of “ETag” and allow ETag=* * Add internal scripts for increasing/decreasing/random telemetry * Add env vars documentation ENVIRONMENT_VARIABLES.md * Add more optional logging by device and by actor * Use logging level and other logging settings from configuration * Adjust unit test precision to mitigate flaky test * Add system properties to telemetry messages * Removing the squash flag from Docker scripts * Use env vars in launchSettings.json
2018-04-13 03:42:46 +03:00
}
}
return deviceIds;
}
public Dictionary<string, List<string>> GetDeviceIdsByModel(Models.Simulation simulation)
{
var result = new Dictionary<string, List<string>>();
var deviceCount = 0;
// Load the simulation models with at least 1 device to simulate (ignoring the custom device ID for now)
List<Models.Simulation.DeviceModelRef> models = (from model in simulation.DeviceModels where model.Count > 0 select model).ToList();
// Generate ID, e.g. "1.chiller-01.1", "1.chiller-01.2", etc
foreach (var model in models)
{
var deviceIds = new List<string>();
for (var i = 1; i <= model.Count; i++)
{
deviceIds.Add(this.GenerateId(simulation.Id, model.Id, i));
deviceCount++;
}
result.Add(model.Id, deviceIds);
}
// Add custom device IDs
foreach (var device in simulation.CustomDevices)
{
if (!result.ContainsKey(device.DeviceModel.Id))
{
result.Add(device.DeviceModel.Id, new List<string>());
}
result[device.DeviceModel.Id].Add(device.DeviceId);
deviceCount++;
}
this.log.Debug("Device IDs loaded", () => new { Simulation = simulation.Id, deviceCount });
return result;
}
/// <summary>
/// Generate a device Id. The method is here to avoid the need to call Dispose
/// on the registry used by the Devices class.
/// </summary>
public string GenerateId(string simulationId, string deviceModelId, int position)
{
return simulationId + "." + deviceModelId + "." + position;
}
private async Task<(Models.Simulation simulation, bool jobCreated, string jobId)> CreateJobToDeleteDevices(string simulationId, IDevices devices)
{
// Fetch latest record, so that updates have the latest ETag if needed
var simulation = await this.GetAsync(simulationId);
// If deletion already happened there's nothing to do, return an empty Job ID
if (simulation.DevicesDeletionStarted || simulation.DevicesDeletionComplete)
{
this.log.Info("Bulk device deletion not needed, devices have already been deleted", () => new { simulation.Id });
return (simulation, false, null);
}
Dictionary<string, List<string>> deviceList = this.GetDeviceIdsByModel(simulation);
var deviceIds = deviceList.SelectMany(x => x.Value).ToList();
string jobId = await devices.DeleteListUsingJobsAsync(deviceIds);
this.log.Info("Bulk device deletion started", () => new { simulation.Id, jobId, deviceIds.Count });
return (simulation, true, jobId);
}
private async Task<bool> TryToUpdateSimulationAsync(Models.Simulation simulation)
{
try
{
await this.SaveAsync(simulation, simulation.ETag);
}
catch (ConflictingResourceException e)
{
this.log.Warn("Update failed, another client modified the simulation record", e);
return false;
}
return true;
}
private async Task<Models.Simulation> SaveAsync(Models.Simulation simulation, string eTag)
{
simulation.Modified = DateTimeOffset.UtcNow;
// When a simulation is disabled, its partitions are deleted - this triggers the deletion
if (!simulation.Enabled)
{
simulation.PartitioningComplete = false;
}
IDataRecord record = this.simulationsStorage.BuildRecord(simulation.Id, JsonConvert.SerializeObject(simulation));
IDataRecord result = await this.simulationsStorage.UpsertAsync(record, eTag);
// Use the new ETag provided by the storage
simulation.ETag = result.GetETag();
simulation.Id = result.GetId();
this.log.Info("Simulation written to storage",
() => new
{
simulation.Id,
simulation.Enabled,
simulation.PartitioningComplete
});
return simulation;
}
// This creates sample simulations that will be shown on simulation dashboard by default
private async Task SeedSimulationsAsync(string templateName)
{
string content;
var fileName = templateName + ".json";
var filePath = Path.Combine(this.config.SeedTemplateFolder, fileName);
if (this.fileSystem.Exists(filePath))
{
content = this.fileSystem.ReadAllText(filePath);
}
else
{
this.log.Debug("Template not found for setting sample simulations.");
return;
}
Models.Simulation simulation = null;
try
{
var simulationList = JsonConvert.DeserializeObject<List<Models.Simulation>>(content);
if (simulationList == null || simulationList.Count == 0) return;
for (int index = 0; index < simulationList.Count; index++)
{
// We need to start creating simulations starting with id 1 as it is treated as default simulation
// and is referenced in Welcome page on UI
simulation = simulationList[index];
var simulationId = index + 1;
simulation.Id = simulationId.ToString();
try
{
// Check if there is an existing simulation with the given id
// if it exists then skip creating a new simulation
await this.GetAsync(simulation.Id);
}
catch (ResourceNotFoundException)
{
// create a simulation if no sample simulation exists with provided id.
simulation.StartTime = DateTimeOffset.UtcNow;
await this.UpsertAsync(simulation, false);
}
}
}
catch (Exception ex)
{
var message = "Failed to create sample simulation. " + " template: " + JsonConvert.SerializeObject(simulation);
this.log.Error(message, ex);
}
}
private async Task<Models.Simulation> ResetSimulationStatisticsAsync(Models.Simulation simulation)
{
// Reset ActualStartTime, which is used to calculate statistics
// from the moment when the simulation starts connecting devices and sending telemetry,
// i.e. after the devices have been created.
simulation.ActualStartTime = null;
// Delete statistics records on simulation start
await this.simulationStatistics.DeleteSimulationStatisticsAsync(simulation.Id);
return simulation;
}
private async Task ResetActiveDevicesStatistics(Models.Simulation simulation)
{
try
{
var currentStats = await this.simulationStatistics.GetSimulationStatisticsAsync(simulation.Id);
if (currentStats != null)
{
var simulationModel = new SimulationStatisticsModel
{
ActiveDevices = 0, // Reset active devices to 0
TotalMessagesSent = currentStats.TotalMessagesSent,
FailedMessages = currentStats.FailedMessages,
FailedDeviceConnections = currentStats.FailedDeviceConnections,
FailedDevicePropertiesUpdates = currentStats.FailedDevicePropertiesUpdates,
};
await this.simulationStatistics.UpdateAsync(simulation.Id, simulationModel);
}
}
catch (Exception e)
{
this.log.Error("Error updating active device count statistics.", () => new { simulation.Id, e });
}
}
}
}