Azure IoT Edge 以编程方式停止模块

Azure IoT Edge stop a module programmatically

我正在尝试以编程方式更改 IoT Edge 模块的“状态”(运行 或已停止)和“restartPolicy”,以便停止模块而无需为设备。

我看到 Edge Agent 的双胞胎在他的 desiredProperties 中有模块的部署信息,我尝试使用以下代码(使用 Microsoft.Azure.Devices NuGet 包)对其进行修补

   public async Task ShutdownModule(string deviceId, string moduleId)
    {
        var twinEdgeAgent = await _registryManager.GetTwinAsync(deviceId, "$edgeAgent");

        var patchJson = $"{{\"properties\":{{\"desired\":{{\"modules\":{{\"{moduleId}\":{{\"status\": \"stopped\", \"restartPolicy\": \"never\"}}}}}}}}}}";
        await _registryManager.UpdateTwinAsync(deviceId, "$edgeAgent", patchJson, twinEdgeAgent.ETag);
    } 

不幸的是,这不起作用,我收到 UnauthorizedException 消息“ErrorCode:SystemModuleModifyUnauthorizedAccess;Unauthorized to modify reserved module.”。看来我无法更改 Edge Agent 模块的所需属性。

有没有办法改变这个 属性 而不必重新创建整个部署 JSON,或者至少有办法获得这个部署 JSON 这样我就可以修改我需要更改的属性?

我设法通过部署 API 做到了,方法是首先通过 EdgeAgent、EdgeHub 和所有模块孪生重建现有部署。

这是我最终写的方法的简历:

var modulesContent = new Dictionary<string, IDictionary<string, object>>();

var twinEdgeAgent = await _registryManager.GetTwinAsync(deviceId, "$edgeAgent");
var agentModules = twinEdgeAgent.Properties.Desired[ModulesJsonPropertyName];

agentModules[myModuleId]["status"] = "stopped";
agentModules[myModuleId]["restartPolicy"] = "never";

var desiredProperties = twinEdgeAgent.GetDesiredPropertiesDictionary();

modulesContent.Add("$edgeAgent", edgeHubDesiredProperties);

var twinEdgeHub = await _registryManager.GetTwinAsync(deviceId, "$edgeHub");
var edgeHubDesiredProperties = twinEdgeHub.GetDesiredPropertiesDictionary();
modulesContent.Add("$edgeHub", edgeHubDesiredProperties);

// foreach modules contained in agentModules also add 
// the module's twin desired properties in the dictionary (not shown for brevity)

await _registryManager.ApplyConfigurationContentOnDeviceAsync(
            deviceId,
            new ConfigurationContent { ModulesContent = modulesContent });

internal static class TwinExtensions
{
    private const string DesiredPropertiesAttribute = "properties.desired";

    public static IDictionary<string, object> GetDesiredPropertiesDictionary(this Twin twin)
    {
        if (twin == null)
        {
            throw new ArgumentNullException(nameof(twin));
        }

        var twinDesiredProperties = twin.Properties.Desired;
        twinDesiredProperties.ClearMetadata();

        var twinDesiredPropertiesDictionary =
            JsonConvert.DeserializeObject<Dictionary<string, object>>(twinDesiredProperties.ToJson());

        return new Dictionary<string, object> {{DesiredPropertiesAttribute, twinDesiredPropertiesDictionary}};
    }
}

也许有更好/更简单的解决方案,但我们正在使用类似的方法来自动升级模块的运行时映像和其他一些东西,所以我能够在同一代码中重新组合所有这些更改。

如果有一种方法可以直接获取部署JSON,但我没有找到任何方法,那就大大简化了。