public async Task TestStatus() { // Arrange var client = _factory.CreateClient(); // Act var response = await client.GetAsync(VersionInfo.PATH + "/status"); // Assert response.EnsureSuccessStatusCode(); Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString()); var result = await response.Content.ReadAsStringAsync(); var status = JsonConvertEx.DeserializeObject <StatusResponseApiModel>(result); Assert.Equal("OK:Alive and well", status.Status); }
protected void TestDeploymentManifestAndJsonTwin() { var deployment1 = new EdgeDeploymentBase() .WithModule("twin", "marcschier/azure-iiot-opc-twin-module", new CreateContainerParameters { HostConfig = new HostConfig { Privileged = true } }); var json1 = deployment1.ToString(); var deployment2 = new EdgeDeploymentBase( JsonConvertEx.DeserializeObject <ConfigurationContentModel>(json1)); var config1 = JsonConvertEx.DeserializeObject <ConfigurationContentModel>( json1); var config2 = JsonConvertEx.DeserializeObject <ConfigurationContentModel>( deployment2.ToString()); Assert.True(JToken.DeepEquals(JToken.FromObject(config1), JToken.FromObject(config2))); }
public void TestTest1InvocationNonChunked() { var router = GetRouter(); var buffer = new byte[1049]; r.NextBytes(buffer); var expected = new TestModel { Test = buffer }; var response = router.InvokeMethodAsync(new MethodRequest( "Test1_V1", Encoding.UTF8.GetBytes( JsonConvertEx.SerializeObject(expected)))).Result; var returned = JsonConvertEx.DeserializeObject <TestModel>( response.ResultAsJson); Assert.Equal(expected.Test, returned.Test); }
public void TestTest3InvocationV2NonChunked() { var router = GetRouter(); var buffer = new byte[1049]; r.NextBytes(buffer); var expected = 3254; var response = router.InvokeMethodAsync(new MethodRequest( "Test3_v2", Encoding.UTF8.GetBytes( JsonConvertEx.SerializeObject(new { request = buffer, Value = expected })))).Result; var returned = JsonConvertEx.DeserializeObject <int>( response.ResultAsJson); Assert.Equal(expected, returned); }
public async Task TestTest2Invocation() { var harness = new ModuleHostHarness(); await harness.RunTestAsync(GetControllers(), async (device, module, services) => { var hub = services.Resolve <IIoTHubTwinServices>(); var buffer = new byte[1049]; r.NextBytes(buffer); var response = await hub.CallMethodAsync(device, module, new MethodParameterModel { Name = "Test2_V1", JsonPayload = JsonConvertEx.SerializeObject(buffer) }); var returned = JsonConvertEx.DeserializeObject <byte[]>(response.JsonPayload); Assert.True(buffer.SequenceEqual(returned)); Assert.Equal(200, response.Status); }); }
/// <summary> /// Helper to convert a typed response to buffer or throw appropriate /// exception as continuation. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="task"></param> /// <returns></returns> public Task <byte[]> MethodResultConverterContinuation <T>(Task <T> task) { return(task.ContinueWith(tr => { if (tr.IsFaulted || tr.IsCanceled) { var ex = tr.Exception?.Flatten().InnerExceptions.FirstOrDefault(); if (ex == null) { ex = new TaskCanceledException(); } _logger.Verbose($"Method call error", ex); ex = _ef.Filter(ex, out var status); throw new MethodCallStatusException(ex != null ? Encoding.UTF8.GetBytes(JsonConvertEx.SerializeObject(ex)) : null, status); } return Encoding.UTF8.GetBytes( JsonConvertEx.SerializeObject(tr.Result)); })); }
/// <inheritdoc/> public async Task <List <DiscoveredModuleModel> > GetModulesAsync( string deviceId, CancellationToken ct) { if (!string.IsNullOrEmpty(_workloaduri)) { try { var uri = _workloaduri + "/modules?api-version=" + _apiVersion; _logger.Debug("Calling GET on {uri} uri...", uri); var request = _client.NewRequest(uri); var result = await Retry.WithExponentialBackoff(_logger, ct, async() => { var response = await _client.GetAsync(request, ct); var payload = response.GetContentAsString(); if (response.StatusCode == System.Net.HttpStatusCode.OK) { _logger.Debug("... returned {statusCode}.", response.StatusCode); _logger.Verbose("payload: {payload}.", payload); } else { _logger.Warning("... resulted in {statusCode} with error: {payload}.", response.StatusCode, payload); } response.Validate(); return(JsonConvertEx.DeserializeObject <EdgeletModules>(payload)); }, kMaxRetryCount); return(result.Modules?.Select(m => new DiscoveredModuleModel { Id = m.Name, ImageName = m.Config?.Settings?.Image, ImageHash = m.Config?.Settings?.ImageHash, Version = GetVersionFromImageName(m.Config?.Settings?.Image), Status = m.Status?.RuntimeStatus?.Status }).ToList()); } catch (Exception ex) { _logger.Error(ex, "Error during GetModulesAsync"); } return(new List <DiscoveredModuleModel>()); } _logger.Warning("Not running in iotedge context - no modules in scope."); return(new List <DiscoveredModuleModel>()); }
/// <summary> /// Return module content /// </summary> /// <typeparam name="T"></typeparam> /// <param name="config"></param> /// <param name="name"></param> /// <returns></returns> public static T GetModulesContent <T>(this ConfigurationContentModel config, string name) { if (config?.ModulesContent == null) { throw new ArgumentNullException(nameof(config)); } if (!config.ModulesContent.TryGetValue(name, out var prop)) { throw new ArgumentException($"config does not contain {name} section", nameof(config)); } if (!prop.TryGetValue("properties.desired", out var module)) { throw new ArgumentException($"{name} does not properties.desired section", nameof(config)); } return(JsonConvertEx.DeserializeObject <T>(JsonConvertEx.SerializeObject( module))); }
/// <summary> /// Publish test messages /// </summary> /// <param name="ct"></param> /// <returns></returns> private async Task PublishAsync(CancellationToken ct) { _logger.Information("Starting to publish..."); for (var index = 0; !ct.IsCancellationRequested; index++) { var message = JsonConvertEx.SerializeObjectPretty(new { GeneratedAt = DateTime.UtcNow, Index = index }); _logger.Information("Publishing test message {Index}", index); await _events.SendAsync(Encoding.UTF8.GetBytes(message), ContentEncodings.MimeTypeJson); if (Interval != TimeSpan.Zero) { await Task.Delay(Interval, ct); } } _logger.Information("Publishing complete."); }
public async Task TestTest3InvocationWithLargeBufferUsingMethodClient() { var harness = new ModuleHostHarness(); await harness.RunTestAsync(GetControllers(), async (device, module, services) => { var hub = services.Resolve <IMethodClient>(); var buffer = new byte[300809]; r.NextBytes(buffer); var response = await hub.CallMethodAsync(device, module, "Test3_V1", JsonConvertEx.SerializeObject(new { request = buffer, value = 55 }) ); var returned = JsonConvertEx.DeserializeObject <byte[]>(response); Assert.True(buffer.SequenceEqual(returned)); }); }
/// <summary> /// Ping continously /// </summary> private static async Task PingAsync(IIoTHubConfig config, ILogger logger, string deviceId, string moduleId, CancellationToken ct) { var client = new IoTHubTwinMethodClient(CreateClient(config, logger), logger); logger.Information("Starting echo thread"); var found = false; for (var index = 0; !ct.IsCancellationRequested; index++) { try { var message = JsonConvertEx.SerializeObjectPretty(new { Index = index, Started = DateTime.UtcNow }); logger.Debug("Sending ECHO {Index}... ", index); var result = await client.CallMethodAsync(deviceId, moduleId, "Echo_V1", message, null, ct); found = true; try { var returned = (dynamic)JToken.Parse(result); logger.Debug("... received back ECHO {Index} - took {Passed}.", returned.Index, DateTime.UtcNow - ((DateTime)returned.Started)); } catch (Exception e) { logger.Error(e, "Bad result for ECHO {Index}: {result} ", index, result); } } catch (Exception ex) { if (!found && (ex is ResourceNotFoundException)) { logger.Debug("Waiting for module to connect..."); continue; // Initial startup ... } logger.Information(ex, "Failed to send ECHO {Index}.", index); } } logger.Information("Echo thread completed"); }
/// <inheritdoc/> public Task <byte[]> InvokeAsync(byte[] payload, string contentType) { object task; try { object[] inputs; if (_methodParams.Length == 0) { inputs = new object[0]; } else if (_methodParams.Length == 1) { var data = JsonConvertEx.DeserializeObject( Encoding.UTF8.GetString(payload), _methodParams[0].ParameterType); inputs = new[] { data }; } else { var data = (JObject)JToken.Parse(Encoding.UTF8.GetString(payload)); inputs = _methodParams.Select(param => { if (data.TryGetValue(param.Name, StringComparison.InvariantCultureIgnoreCase, out var value)) { return(value.ToObject(param.ParameterType)); } return(param.HasDefaultValue ? param.DefaultValue : null); }).ToArray(); } task = _controllerMethod.Invoke(_controller, inputs); } catch (Exception e) { task = Task.FromException(e); } if (_methodTaskContinuation == null) { return(VoidContinuation((Task)task)); } return((Task <byte[]>)_methodTaskContinuation.Invoke(this, new[] { task })); }
public void TestTest1InvocationChunked() { var router = GetRouter(); var client = new ChunkMethodClient(new TestMethodClient(router), new ConsoleLogger()); var buffer = new byte[300809]; r.NextBytes(buffer); var expected = new TestModel { Test = buffer }; var response = client.CallMethodAsync("test", "test", "Test1_V1", Encoding.UTF8.GetBytes(JsonConvertEx.SerializeObject(expected)), null, null).Result; var returned = JsonConvertEx.DeserializeObject <TestModel>( Encoding.UTF8.GetString(response)); Assert.Equal(expected.Test, returned.Test); }
/// <inheritdoc/> public async Task HandleAsync(string deviceId, string moduleId, byte[] payload, IDictionary <string, string> properties, Func <Task> checkpoint) { var json = Encoding.UTF8.GetString(payload); DiscoveryProgressModel discovery; try { discovery = JsonConvertEx.DeserializeObject <DiscoveryProgressModel>(json); } catch (Exception ex) { _logger.Error(ex, "Failed to convert discovery message {json}", json); return; } try { await Task.WhenAll(_handlers.Select(h => h.OnDiscoveryProgressAsync(discovery))); } catch (Exception ex) { _logger.Error(ex, "Publishing discovery message failed with exception - skip"); } }
/// <summary> /// Helper to read white list /// </summary> /// <returns></returns> private CorsWhitelistModel ReadWhiteList() { try { var model = JsonConvertEx.DeserializeObject <CorsWhitelistModel>( _config.CorsWhitelist); if (model == null) { _log.Error("Invalid CORS whitelist. Ignored", () => new { _config.CorsWhitelist }); } return(model); } catch (Exception ex) { _log.Error("Invalid CORS whitelist. Ignored", () => new { _config.CorsWhitelist, ex.Message }); return(null); } }
/// <inheritdoc/> public void Apply(OpenApiParameter parameter, ParameterFilterContext context) { // // fix current bug where properties are not added correctly // Lookup property schema in schema repo // if (context.PropertyInfo != null) { // Query was passed a parameter with properties var propertySchema = context.SchemaRepository.Schemas .Where(p => p.Key.EqualsIgnoreCase(context.ParameterInfo.ParameterType.Name)) .SelectMany(p => p.Value.Properties) .Where(p => p.Key.EqualsIgnoreCase(context.PropertyInfo.Name)) .FirstOrDefault(); if (propertySchema.Value != null) { propertySchema.Value.Description = propertySchema.Value.Description.SingleSpacesNoLineBreak(); // Replace parameter definition with property schema parameter.Name = propertySchema.Key; // Quick and dirty clone of the schema for the parameter parameter.Schema = JsonConvertEx.DeserializeObject <OpenApiSchema>( JsonConvertEx.SerializeObject(propertySchema.Value)); } parameter.Required = context.PropertyInfo .GetCustomAttributes(typeof(RequiredAttribute), true) .Any(); AdjustSchema(context.PropertyInfo.PropertyType, parameter.Schema); } else if (context.ParameterInfo != null) { // Query was passed a parameter with properties AdjustSchema(context.ParameterInfo.ParameterType, parameter.Schema); } if (parameter.Schema != null) { parameter.Schema.Description = parameter.Schema.Description.SingleSpacesNoLineBreak(); } parameter.Description = parameter.Description.SingleSpacesNoLineBreak(); }
public async Task TestTest1Invocation() { var harness = new ModuleHostHarness(); await harness.RunTestAsync(GetControllers(), async (device, module, services) => { var hub = services.Resolve <IIoTHubTwinServices>(); var buffer = new byte[1049]; kRand.NextBytes(buffer); var expected = new TestModel { Test = buffer }; var response = await hub.CallMethodAsync(device, module, new MethodParameterModel { Name = "Test1_V1", JsonPayload = JsonConvertEx.SerializeObject(expected) }); var returned = JsonConvertEx.DeserializeObject <TestModel>(response.JsonPayload); Assert.Equal(expected.Test, returned.Test); Assert.Equal(200, response.Status); }); }
/// <inheritdoc/> public async Task <(ServiceResultModel, string)> CallMethodAsync( string method, string request, DiagnosticsModel diagnostics) { try { _logger.Verbose("Calling publisher method {method} with {request}", method, request); var response = await _client.CallMethodAsync( _deviceId ?? _identity?.DeviceId, _moduleId ?? "publisher", method, request); _logger.Verbose("Calling publisher method {method} returned {response}", method, response); return(null, response); } catch (Exception ex) { return(new ServiceResultModel { ErrorMessage = ex.Message, Diagnostics = JToken.FromObject(ex, JsonSerializer.Create(JsonConvertEx.GetSettings())) }, null); } }
/// <inheritdoc/> public async Task <BrowseResponseApiModel> NodeBrowseFirstAsync(EndpointApiModel endpoint, BrowseRequestApiModel request, CancellationToken ct) { if (endpoint == null) { throw new ArgumentNullException(nameof(endpoint)); } if (string.IsNullOrEmpty(endpoint.Url)) { throw new ArgumentNullException(nameof(endpoint.Url)); } if (request == null) { throw new ArgumentNullException(nameof(request)); } var response = await _methodClient.CallMethodAsync(_deviceId, _moduleId, "Browse_V2", JsonConvertEx.SerializeObject(new { endpoint, request }), null, ct); return(JsonConvertEx.DeserializeObject <BrowseResponseApiModel>(response)); }
public async Task TestTest3InvocationV2() { var harness = new ModuleHostHarness(); await harness.RunTestAsync(GetControllers(), async (device, module, services) => { var hub = services.Resolve <IIoTHubTwinServices>(); var buffer = new byte[1049]; r.NextBytes(buffer); var expected = 3254; var response = await hub.CallMethodAsync(device, module, new MethodParameterModel { Name = "Test3_v2", JsonPayload = JsonConvertEx.SerializeObject(new { request = buffer, value = expected }) }); var returned = JsonConvertEx.DeserializeObject <int>(response.JsonPayload); Assert.Equal(expected, returned); Assert.Equal(200, response.Status); }); }
/// <inheritdoc/> public async Task HandleAsync(string deviceId, string moduleId, byte[] payload, Func <Task> checkpoint) { var json = Encoding.UTF8.GetString(payload); DiscoveryEventModel discovery; try { discovery = JsonConvertEx.DeserializeObject <DiscoveryEventModel>(json); } catch (Exception ex) { _logger.Error(ex, "Failed to convert discovery {json}", json); return; } try { var supervisorId = SupervisorModelEx.CreateSupervisorId( deviceId, moduleId?.ToString()); await ProcessServerEndpointDiscoveryAsync(supervisorId, discovery, checkpoint); } catch (Exception ex) { _logger.Error(ex, "Handling discovery event failed with exception - skip"); } }
/// <inheritdoc/> public Task <byte[]> InvokeAsync(byte[] payload, string contentType) { // Handle response from device method var result = Encoding.UTF8.GetString(payload); var response = JsonConvertEx.DeserializeObject <HttpTunnelResponseModel>(result); if (_outstanding.TryRemove(response.RequestId, out var tcs)) { var httpResponse = new HttpResponseMessage((HttpStatusCode)response.Status) { Content = response.Payload == null ? null : new ByteArrayContent(response.Payload) }; if (response.Headers != null) { foreach (var header in response.Headers) { httpResponse.Headers.TryAddWithoutValidation(header.Key, header.Value); } } tcs.TrySetResult(httpResponse); } return(Task.FromResult(new byte[0])); }
/// <summary> /// Get ua settings /// </summary> /// <param name="context"></param> /// <returns></returns> internal static JsonSerializerSettings GetSettings(ServiceMessageContext context) { return(JsonConvertEx.GetSettings().AddUaConverters(context)); }
/// <summary> /// Set docker creation options /// </summary> /// <param name="model"></param> /// <param name="createOptions"></param> public static void SetCreateOptions(this EdgeAgentModuleSettingsModel model, CreateContainerParameters createOptions) { model.CreateOptions = JsonConvertEx.SerializeObject(createOptions); }
/// <summary> /// List nodes on endpoint /// </summary> private static async Task ListNodesAsync(IIoTHubConfig config, ILogger logger, string deviceId, string moduleId, string endpointUrl, CancellationToken ct) { if (string.IsNullOrEmpty(endpointUrl)) { throw new ArgumentNullException(nameof(endpointUrl)); } var client = new IoTHubTwinMethodClient(CreateClient(config, logger), logger); while (!ct.IsCancellationRequested) { await Task.Delay(TimeSpan.FromSeconds(5), ct); try { var content = new GetNodesRequestModel { EndpointUrl = endpointUrl }; var result = await client.CallMethodAsync(deviceId, moduleId, "GetConfiguredNodesOnEndpoint", JsonConvertEx.SerializeObject(content), null, ct); var response = JsonConvertEx.DeserializeObject <GetNodesResponseModel>(result); logger.Information("Published nodes: {@response}", response); } catch (Exception ex) { logger.Verbose(ex, "Failed to list published nodes."); } } }
/// <summary> /// Get base edge configuration /// </summary> /// <param name="isLinux"></param> /// <returns></returns> private IDictionary <string, IDictionary <string, object> > CreateLayeredDeployment( bool isLinux) { var registryCredentials = ""; if (!string.IsNullOrEmpty(_config.DockerServer) && _config.DockerServer != "mcr.microsoft.com") { var registryId = _config.DockerServer.Split('.')[0]; registryCredentials = @" ""properties.desired.runtime.settings.registryCredentials." + registryId + @""": { ""address"": """ + _config.DockerServer + @""", ""password"": """ + _config.DockerPassword + @""", ""username"": """ + _config.DockerUser + @""" }, "; } // Configure create options per os specified string createOptions; if (isLinux) { // Linux createOptions = @" { ""NetworkingConfig"":{ ""EndpointsConfig"": { ""host"": { } } }, ""HostConfig"": { ""NetworkMode"": ""host"", ""CapAdd"": [ ""NET_ADMIN"" ] } }"; } else { // Windows createOptions = @" { ""HostConfig"": { ""CapAdd"": [ ""NET_ADMIN"" ] } }"; } createOptions = JObject.Parse(createOptions).ToString(Formatting.None).Replace("\"", "\\\""); var server = string.IsNullOrEmpty(_config.DockerServer) ? "mcr.microsoft.com" : _config.DockerServer; var ns = string.IsNullOrEmpty(_config.ImagesNamespace) ? "" : _config.ImagesNamespace.TrimEnd('/') + "/"; var version = _config.ImagesTag ?? "latest"; var image = $"{server}/{ns}iotedge/discovery:{version}"; _logger.Information("Updating discoverer module deployment with image {image}", image); // Return deployment modules object var content = @" { ""$edgeAgent"": { " + registryCredentials + @" ""properties.desired.modules.discoverer"": { ""settings"": { ""image"": """ + image + @""", ""createOptions"": """ + createOptions + @""" }, ""type"": ""docker"", ""status"": ""running"", ""restartPolicy"": ""always"", ""version"": """ + (version == "latest" ? "1.0" : version) + @""" } }, ""$edgeHub"": { ""properties.desired.routes.upstream"": ""FROM /messages/* INTO $upstream"" } }"; return(JsonConvertEx.DeserializeObject <IDictionary <string, IDictionary <string, object> > >(content)); }
/// <summary> /// Create deployment for a single device. /// </summary> /// <param name="factory"></param> /// <param name="deviceId"></param> /// <param name="deploymentJson"></param> /// <returns></returns> public static IEdgeDeployment CreateFromDeploymentJson( this IEdgeDeploymentFactory factory, string deviceId, string deploymentJson) => factory.Create(deviceId, JsonConvertEx.DeserializeObject <ConfigurationContentModel>( deploymentJson));
/// <summary> /// Create deployment for a fleet of devices identified by /// the target condition and given the desired name. /// </summary> /// <param name="factory"></param> /// <param name="name"></param> /// <param name="condition"></param> /// <param name="priority"></param> /// <param name="deploymentJson"></param> /// <returns></returns> public static IEdgeDeployment CreateFromDeploymentJson( this IEdgeDeploymentFactory factory, string name, string condition, int priority, string deploymentJson) => factory.Create(name, condition, priority, JsonConvertEx.DeserializeObject <ConfigurationContentModel>(deploymentJson));
/// <summary> /// Convert from to /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model"></param> /// <returns></returns> private static T Map <T>(object model) { return(JsonConvertEx.DeserializeObject <T>( JsonConvertEx.SerializeObject(model))); }
/// <summary> /// Apply manifest from stream /// </summary> /// <param name="deployment"></param> /// <param name="manifestJson"></param> /// <returns></returns> public static IEdgeDeployment WithManifest(this IEdgeDeployment deployment, string manifestJson) { return(deployment.WithManifest( JsonConvertEx.DeserializeObject <EdgeDeploymentManifestModel>(manifestJson))); }