diff --git a/Services/IStatusService.cs b/Services/IStatusService.cs new file mode 100644 index 00000000..4362b5c2 --- /dev/null +++ b/Services/IStatusService.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models; +using System.Threading.Tasks; + +namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services +{ + public interface IStatusService + { + Task GetStatusAsync(); + } +} diff --git a/Services/Models/StatusResultServiceModel.cs b/Services/Models/StatusResultServiceModel.cs new file mode 100644 index 00000000..945354fa --- /dev/null +++ b/Services/Models/StatusResultServiceModel.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Newtonsoft.Json; + +namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models +{ + public class StatusResultServiceModel + { + [JsonProperty(PropertyName = "IsHealthy")] + public bool IsHealthy { get; set; } + + [JsonProperty(PropertyName = "Message")] + public string Message { get; set; } + + [JsonConstructor] + public StatusResultServiceModel(bool isHealthy, string message) + { + IsHealthy = isHealthy; + Message = message; + } + } +} diff --git a/Services/Models/StatusServiceModel.cs b/Services/Models/StatusServiceModel.cs new file mode 100644 index 00000000..07b2300b --- /dev/null +++ b/Services/Models/StatusServiceModel.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models +{ + public class StatusServiceModel + { + [JsonProperty(PropertyName = "Status")] + public StatusResultServiceModel Status { get; set; } + + [JsonProperty(PropertyName = "Properties")] + public Dictionary Properties { get; set; } + + [JsonProperty(PropertyName = "Dependencies")] + public Dictionary Dependencies { get; set; } + + public StatusServiceModel(bool isHealthy, string message) + { + this.Status = new StatusResultServiceModel(isHealthy, message); + this.Dependencies = new Dictionary(); + this.Properties = new Dictionary(); + } + } +} diff --git a/Services/PreprovisionedIotHub.cs b/Services/PreprovisionedIotHub.cs index 8da1b4e4..9d2e2fbc 100644 --- a/Services/PreprovisionedIotHub.cs +++ b/Services/PreprovisionedIotHub.cs @@ -13,7 +13,7 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services public interface IPreprovisionedIotHub { // Ping the registry to see if the connection is healthy - Task> PingRegistryAsync(); + Task PingRegistryAsync(); } public class PreprovisionedIotHub : IPreprovisionedIotHub @@ -37,21 +37,23 @@ public PreprovisionedIotHub( } // Ping the registry to see if the connection is healthy - public async Task> PingRegistryAsync() + public async Task PingRegistryAsync() { - if (this.registry == null) await this.InitAsync(); - + var result = new StatusResultServiceModel(false, "IoTHub check failed"); + try { await this.InitAsync(); await this.registry.GetDeviceAsync("healthcheck"); - return new Tuple(true, "OK"); + result.IsHealthy = true; + result.Message = "Alive and Well!"; } catch (Exception e) { this.log.Error("Device registry test failed", e); - return new Tuple(false, e.Message); } + + return result; } // This call can throw an exception, which is fine when the exception happens during diff --git a/Services/StatusService.cs b/Services/StatusService.cs new file mode 100644 index 00000000..2f99c280 --- /dev/null +++ b/Services/StatusService.cs @@ -0,0 +1,198 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics; +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Http; +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models; +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Runtime; +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.StorageAdapter; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services +{ + class StatusService : IStatusService + { + private const string JSON_TRUE = "true"; + private const string JSON_FALSE = "false"; + + private const string SIMULATION_RUNNING_KEY = "SimulationRunning"; + private const string PREPROVISIONED_IOTHUB_KEY = "PreprovisionedIoTHub"; + + private const bool ALLOW_INSECURE_SSL_SERVER = true; + private readonly int timeoutMS = 10000; + + private readonly IPreprovisionedIotHub preprovisionedIotHub; + private readonly ISimulations simulations; + private readonly IHttpClient httpClient; + private readonly ILogger log; + private readonly IServicesConfig servicesConfig; + + public StatusService( + ILogger logger, + IPreprovisionedIotHub preprovisionedIotHub, + ISimulations simulations, + IHttpClient httpClient, + IServicesConfig servicesConfig + ) + { + this.log = logger; + this.preprovisionedIotHub = preprovisionedIotHub; + this.simulations = simulations; + this.httpClient = httpClient; + this.servicesConfig = servicesConfig; + } + + public async Task GetStatusAsync() + { + var result = new StatusServiceModel(true, "Alive and well!"); + var errors = new List(); + + string storageAdapterName = "StorageAdapter"; + string diagnosticsName = "Diagnostics"; + + // Simulation status + var simulationIsRunning = await this.CheckIsSimulationRunningAsync(errors); + var isRunning = simulationIsRunning.HasValue && simulationIsRunning.Value; + + // Check access to StorageAdapter + var storageAdapterResult = await this.PingServiceAsync( + storageAdapterName, + this.servicesConfig.StorageAdapterApiUrl); + SetServiceStatus(storageAdapterName, storageAdapterResult, result, errors); + + // Check access to Diagnostics + var diagnosticsResult = await this.PingServiceAsync( + diagnosticsName, + this.servicesConfig.DiagnosticsEndpointUrl); + // Note: Overall simulation service status is independent of diagnostics service + // Hence not using SetServiceStatus on diagnosticsResult + result.Dependencies.Add(diagnosticsName, diagnosticsResult); + + // Preprovisioned IoT hub status + var isHubPreprovisioned = this.IsHubConnectionStringConfigured(); + + if (isHubPreprovisioned) + { + var preprovisionedHubResult = await this.preprovisionedIotHub.PingRegistryAsync(); + SetServiceStatus("IoTHub", preprovisionedHubResult, result, errors); + } + + result.Properties.Add(SIMULATION_RUNNING_KEY, + simulationIsRunning.HasValue + ? (isRunning ? JSON_TRUE : JSON_FALSE) + : "unknown"); + result.Properties.Add(PREPROVISIONED_IOTHUB_KEY, + isHubPreprovisioned + ? JSON_TRUE + : JSON_FALSE); + + if (errors.Count > 0) + { + result.Status.Message = string.Join("; ", errors); + } + + result.Properties.Add("DiagnosticsEndpointUrl", this.servicesConfig?.DiagnosticsEndpointUrl); + result.Properties.Add("StorageAdapterApiUrl", this.servicesConfig?.StorageAdapterApiUrl); + this.log.Info( + "Service status request", + () => new + { + Healthy = result.Status.IsHealthy, + result.Status.Message + }); + return result; + } + + private void SetServiceStatus( + string dependencyName, + StatusResultServiceModel serviceResult, + StatusServiceModel result, + List errors + ) + { + if (!serviceResult.IsHealthy) + { + errors.Add(dependencyName + " check failed"); + result.Status.IsHealthy = false; + } + result.Dependencies.Add(dependencyName, serviceResult); + } + + // Check whether the simulation is running, and populate errors if any + private async Task CheckIsSimulationRunningAsync(List errors) + { + bool? simulationRunning = null; + try + { + var simulationList = await this.simulations.GetListAsync(); + var runningSimulation = simulationList.FirstOrDefault(s => s.ShouldBeRunning); + simulationRunning = (runningSimulation != null); + } + catch (Exception e) + { + var msg = "Unable to fetch simulation status"; + errors.Add(msg); + this.log.Error(msg, e); + } + + return simulationRunning; + } + + // Check whether the configuration contains a connection string + private bool IsHubConnectionStringConfigured() + { + var cs = this.servicesConfig?.IoTHubConnString?.ToLowerInvariant().Trim(); + return (!string.IsNullOrEmpty(cs) + && cs.Contains("hostname=") + && cs.Contains("sharedaccesskeyname=") + && cs.Contains("sharedaccesskey=")); + } + + private async Task PingServiceAsync(string serviceName, string serviceURL) + { + var result = new StatusResultServiceModel(false, $"{serviceName} check failed"); + try + { + var response = await this.httpClient.GetAsync(this.PrepareRequest($"{serviceURL}/status")); + if (response.IsError) + { + result.Message = $"Status code: {response.StatusCode}; Response: {response.Content}"; + } + else + { + var data = JsonConvert.DeserializeObject(response.Content); + result = data.Status; + } + } + catch (Exception e) + { + this.log.Error(result.Message, () => new { e }); + } + + return result; + } + + private HttpRequest PrepareRequest(string path) + { + var request = new HttpRequest(); + request.AddHeader(HttpRequestHeader.Accept.ToString(), "application/json"); + request.AddHeader(HttpRequestHeader.CacheControl.ToString(), "no-cache"); + request.AddHeader(HttpRequestHeader.Referer.ToString(), "ASA Manager " + this.GetType().FullName); + request.SetUriFromString(path); + request.Options.EnsureSuccess = false; + request.Options.Timeout = this.timeoutMS; + if (path.ToLowerInvariant().StartsWith("https:")) + { + request.Options.AllowInsecureSSLServer = ALLOW_INSECURE_SSL_SERVER; + } + + this.log.Debug("Prepare Request", () => new { request }); + + return request; + } + } +} diff --git a/Services/StorageAdapter/StorageAdapterClient.cs b/Services/StorageAdapter/StorageAdapterClient.cs index eaf29209..1cd1dea3 100644 --- a/Services/StorageAdapter/StorageAdapterClient.cs +++ b/Services/StorageAdapter/StorageAdapterClient.cs @@ -8,6 +8,7 @@ using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics; using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Exceptions; using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Http; +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models; using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Runtime; using Newtonsoft.Json; @@ -15,7 +16,6 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.StorageAdapter { public interface IStorageAdapterClient { - Task> PingAsync(); Task GetAllAsync(string collectionId); Task GetAsync(string collectionId, string key); Task CreateAsync(string collectionId, string value); @@ -50,36 +50,6 @@ public StorageAdapterClient( this.diagnosticsLogger = diagnosticsLogger; } - public async Task> PingAsync() - { - var status = false; - var message = ""; - - try - { - var response = await this.httpClient.GetAsync(this.PrepareRequest($"status")); - if (response.IsError) - { - message = "Status code: " + response.StatusCode; - } - else - { - var data = JsonConvert.DeserializeObject>(response.Content); - message = data["Status"].ToString(); - status = data["Status"].ToString().StartsWith("OK:"); - } - } - catch (Exception e) - { - const string MSG = "Storage adapter check failed"; - this.log.Error(MSG, e); - this.diagnosticsLogger.LogServiceError(MSG, e.Message); - message = e.Message; - } - - return new Tuple(status, message); - } - public async Task GetAllAsync(string collectionId) { var response = await this.httpClient.GetAsync( diff --git a/WebService.Test/v1/Controllers/StatusControllerTest.cs b/WebService.Test/v1/Controllers/StatusControllerTest.cs index 4a2fddaf..62c07fe0 100644 --- a/WebService.Test/v1/Controllers/StatusControllerTest.cs +++ b/WebService.Test/v1/Controllers/StatusControllerTest.cs @@ -1,20 +1,13 @@ // Copyright (c) Microsoft. All rights reserved. -using System; -using System.Collections.Generic; using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services; -using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Concurrency; -using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics; -using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.IotHub; -using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Runtime; -using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.StorageAdapter; -using Microsoft.Azure.IoTSolutions.DeviceSimulation.SimulationAgent; +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models; +using Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.Runtime; using Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.v1.Controllers; using Moq; using WebService.Test.helpers; using Xunit; using Xunit.Abstractions; -using SimulationModel = Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models.Simulation; namespace WebService.Test.v1.Controllers { @@ -22,89 +15,30 @@ public class StatusControllerTest { private const string SIMULATION_ID = "1"; - private readonly Mock preprovisionedIotHub; - private readonly Mock storage; - private readonly Mock simulations; - private readonly Mock logger; - private readonly Mock servicesConfig; - private readonly Mock rateReporter; + private readonly Mock statusService; + private readonly Mock config; private readonly StatusController target; public StatusControllerTest(ITestOutputHelper log) { - this.preprovisionedIotHub = new Mock(); - this.storage = new Mock(); - this.simulations = new Mock(); - this.logger = new Mock(); - this.servicesConfig = new Mock(); - this.rateReporter = new Mock(); - - this.target = new StatusController( - this.preprovisionedIotHub.Object, - this.storage.Object, - this.simulations.Object, - this.logger.Object, - this.servicesConfig.Object); - } - - [Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)] - public void ItReturnsTheStatusOfRunningSimulation() - { - // Arrange - this.SetupSimulationForRunner(); - - // Act - var result = this.target.GetAsync().CompleteOrTimeout().Result; - - // Assert - Assert.Equal("true", result.Properties["SimulationRunning"]); + this.statusService = new Mock(); + this.config = new Mock(); + this.target = new StatusController(this.config.Object, this.statusService.Object); } [Fact, Trait(Constants.TYPE, Constants.UNIT_TEST)] - public void ItReturnsTheStatusOfPreprovisionedIoTHub() + public void ItReturnsHealthOfSimulationService() { - // Arrange - this.SetupSimulationForRunner(); - this.SetupPreprovisionedIoTHub(); + //Arrange + this.statusService + .Setup(x => x.GetStatusAsync()) + .ReturnsAsync(new StatusServiceModel(true, "Alive and well!")); // Act var result = this.target.GetAsync().CompleteOrTimeout().Result; // Assert - Assert.Equal("true", result.Properties["PreprovisionedIoTHub"]); - } - - private void SetupSimulationForRunner() - { - var simulation = new SimulationModel - { - Id = SIMULATION_ID, - Name = "Test Simulation", - Created = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(10)), - Modified = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(10)), - ETag = "ETag0", - Enabled = true, - PartitioningComplete = true, - DevicesCreationComplete = true - }; - - var simulations = new List { simulation }; - - this.simulations - .Setup(x => x.GetListAsync()) - .ReturnsAsync(simulations); - } - - private void SetupPreprovisionedIoTHub() - { - const string FAKE_KEY = "fakekey"; - const string FAKE_HOST = "hub-1"; - const string IOTHUB_CONNECTION_STRING = - "hostname=" + FAKE_HOST + ";sharedaccesskeyname=hubowner;sharedaccesskey=" + FAKE_KEY; - - this.servicesConfig - .Setup(x => x.IoTHubConnString) - .Returns(IOTHUB_CONNECTION_STRING); + Assert.True(result.Status.IsHealthy); } } } diff --git a/WebService/v1/Controllers/StatusController.cs b/WebService/v1/Controllers/StatusController.cs index a0c77c06..6f4ec30d 100644 --- a/WebService/v1/Controllers/StatusController.cs +++ b/WebService/v1/Controllers/StatusController.cs @@ -1,14 +1,9 @@ // Copyright (c) Microsoft. All rights reserved. -using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services; -using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Diagnostics; -using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Runtime; -using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.StorageAdapter; +using Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.Runtime; using Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.v1.Filters; using Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.v1.Models; @@ -17,163 +12,23 @@ namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.v1.Controller [Route(Version.PATH + "/[controller]"), ExceptionsFilter] public sealed class StatusController : Controller { - private const string SERVICE_IS_HEALTHY = "Alive and well"; + private readonly IConfig config; + private readonly IStatusService statusService; - private const string JSON_TRUE = "true"; - private const string JSON_FALSE = "false"; - - private const string SIMULATION_RUNNING_KEY = "SimulationRunning"; - private const string PREPROVISIONED_IOTHUB_KEY = "PreprovisionedIoTHub"; - - private readonly IPreprovisionedIotHub preprovisionedIotHub; - private readonly IStorageAdapterClient storage; - private readonly ISimulations simulations; - private readonly ILogger log; - private readonly IServicesConfig servicesConfig; - - public StatusController( - IPreprovisionedIotHub preprovisionedIotHub, - IStorageAdapterClient storage, - ISimulations simulations, - ILogger logger, - IServicesConfig servicesConfig) + public StatusController(IConfig config, IStatusService statusService) { - this.preprovisionedIotHub = preprovisionedIotHub; - this.storage = storage; - this.simulations = simulations; - this.log = logger; - this.servicesConfig = servicesConfig; + this.statusService = statusService; + this.config = config; } // TODO: reduce method complexity, refactor out some logic [HttpGet] public async Task GetAsync() { - var result = new StatusApiModel(); - var statusMsg = SERVICE_IS_HEALTHY; - var errors = new List(); - - // Simulation status - var simulationIsRunning = await this.CheckIsSimulationRunningAsync(errors); - var isRunning = simulationIsRunning.HasValue && simulationIsRunning.Value; - result.Properties.Add(SIMULATION_RUNNING_KEY, - simulationIsRunning.HasValue - ? (isRunning ? JSON_TRUE : JSON_FALSE) - : "unknown"); - - // Storage status - var storageStatus = await this.CheckStorageStatusAsync(errors); - result.Dependencies.Add("Storage", storageStatus?.Item2); - var statusIsOk = storageStatus.Item1; - - // Preprovisioned IoT hub status - var isHubPreprovisioned = this.IsHubConnectionStringConfigured(); - result.Properties.Add(PREPROVISIONED_IOTHUB_KEY, - isHubPreprovisioned - ? JSON_TRUE - : JSON_FALSE); - if (isHubPreprovisioned) - { - var preprovisionedHubStatus = await this.CheckAzureIoTHubStatusAsync(errors); - statusIsOk = statusIsOk && preprovisionedHubStatus.Item1; - - result.Dependencies.Add(PREPROVISIONED_IOTHUB_KEY, preprovisionedHubStatus?.Item2); - } - - // Prepare status message and response - if (!statusIsOk) - { - statusMsg = string.Join(";", errors); - } - - result.SetStatus(statusIsOk, statusMsg); - - this.log.Info("Service status request", () => new - { - Healthy = statusIsOk, - statusMsg - }); + var result = new StatusApiModel(await this.statusService.GetStatusAsync()); + result.Properties.Add("Port", this.config.Port.ToString()); return result; } - - // Check whether the simulation is running, and populate errors if any - private async Task CheckIsSimulationRunningAsync(List errors) - { - bool? simulationRunning = null; - try - { - var simulationList = await this.simulations.GetListAsync(); - var runningSimulation = simulationList.FirstOrDefault(s => s.ShouldBeRunning); - simulationRunning = (runningSimulation != null); - } - catch (Exception e) - { - var msg = "Unable to fetch simulation status"; - errors.Add(msg); - this.log.Error(msg, e); - } - - return simulationRunning; - } - - // Check the storage dependency status - private async Task> CheckStorageStatusAsync(ICollection errors) - { - Tuple result; - try - { - result = await this.storage.PingAsync(); - if (!result.Item1) - { - errors.Add("Unable to use Storage"); - } - } - catch (Exception e) - { - result = new Tuple(false, "Storage check failed"); - this.log.Error("Storage ping failed", e); - } - - return result; - } - - // Check IoT Hub dependency status - private async Task> CheckAzureIoTHubStatusAsync(ICollection errors) - { - Tuple result; - try - { - if (this.IsHubConnectionStringConfigured()) - { - result = await this.preprovisionedIotHub.PingRegistryAsync(); - if (!result.Item1) - { - errors.Add("Unable to use Azure IoT Hub service"); - } - } - else - { - result = new Tuple(true, "IoTHub connection string not configured"); - } - } - catch (Exception e) - { - result = new Tuple(false, "IoTHub check failed"); - this.log.Error("IoT Hub ping failed", e); - } - - return result; - } - - // Check whether the configuration contains a connection string - private bool IsHubConnectionStringConfigured() - { - var cs = this.servicesConfig?.IoTHubConnString?.ToLowerInvariant().Trim(); - return (!string.IsNullOrEmpty(cs) - && cs.Contains("hostname=") - && cs.Contains("sharedaccesskeyname=") - && cs.Contains("sharedaccesskey=")); - } } } diff --git a/WebService/v1/Models/StatusApiModel.cs b/WebService/v1/Models/StatusApiModel.cs index b3bbb370..e43fba37 100644 --- a/WebService/v1/Models/StatusApiModel.cs +++ b/WebService/v1/Models/StatusApiModel.cs @@ -2,10 +2,10 @@ using System; using System.Collections.Generic; +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models; using Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.Runtime; using Newtonsoft.Json; -// TODO: complete - https://github.com/Azure/device-simulation-dotnet/issues/82 namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.v1.Models { public sealed class StatusApiModel @@ -16,7 +16,7 @@ public sealed class StatusApiModel public string Name => "DeviceSimulation"; [JsonProperty(PropertyName = "Status", Order = 20)] - public string Status { get; set; } + public StatusResultApiModel Status { get; set; } [JsonProperty(PropertyName = "CurrentTime", Order = 30)] public string CurrentTime => DateTimeOffset.UtcNow.ToString(DATE_FORMAT); @@ -37,26 +37,28 @@ public sealed class StatusApiModel /// A property bag with details about the service [JsonProperty(PropertyName = "Properties", Order = 70)] - public Dictionary Properties = new Dictionary(); + public Dictionary Properties { get; set; } /// A property bag with details about the internal dependencies [JsonProperty(PropertyName = "Dependencies", Order = 80)] - public Dictionary Dependencies = new Dictionary(); + public Dictionary Dependencies { get; set; } [JsonProperty(PropertyName = "$metadata", Order = 1000)] - public Dictionary Metadata = new Dictionary + public Dictionary Metadata => new Dictionary { { "$type", "Status;" + Version.NUMBER }, { "$uri", "/" + Version.PATH + "/status" } }; - public void SetStatus(bool isOk, string msg) + public StatusApiModel(StatusServiceModel model) { - this.Status = isOk ? "OK" : "ERROR"; - if (!string.IsNullOrEmpty(msg)) + this.Status = new StatusResultApiModel(model.Status); + this.Dependencies = new Dictionary(); + foreach (KeyValuePair pair in model.Dependencies) { - this.Status += ":" + msg; + this.Dependencies.Add(pair.Key, new StatusResultApiModel(pair.Value)); } + this.Properties = model.Properties; } } } diff --git a/WebService/v1/Models/StatusResultApiModel.cs b/WebService/v1/Models/StatusResultApiModel.cs new file mode 100644 index 00000000..b0a1674f --- /dev/null +++ b/WebService/v1/Models/StatusResultApiModel.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Microsoft.Azure.IoTSolutions.DeviceSimulation.Services.Models; +using Newtonsoft.Json; +using System; + +namespace Microsoft.Azure.IoTSolutions.DeviceSimulation.WebService.v1.Models +{ + public class StatusResultApiModel + { + [JsonProperty(PropertyName = "IsHealthy", Order = 10)] + public bool IsHealthy { get; set; } + + [JsonProperty(PropertyName = "Message", Order = 20)] + public string Message { get; set; } + + public StatusResultApiModel(StatusResultServiceModel servicemodel) + { + this.IsHealthy = servicemodel.IsHealthy; + this.Message = servicemodel.Message; + } + } +}