示例#1
0
 public Task PingAsync(CancellationToken token) =>
 Profiler.Run(
     () => this.iotHub.InvokeMethodAsync(
         this.deviceId,
         $"${this.Id}",
         new CloudToDeviceMethod("ping"),
         token),
     "Pinged module '{Module}' from the cloud",
     this.Id);
示例#2
0
        public Task WaitForStatusAsync(EdgeDaemonStatus desired, CancellationToken token)
        {
            var sc = new ServiceController("iotedge");

            return(Profiler.Run(
                       () => this.WaitForStatusAsync(sc, (ServiceControllerStatus)desired, token),
                       "Edge daemon entered the '{Desired}' state",
                       desired.ToString().ToLower()));
        }
示例#3
0
        public static Task WaitForStatusAsync(IEnumerable <EdgeModule> modules, EdgeModuleStatus desired, CancellationToken token)
        {
            string[] moduleIds = modules.Select(m => m.Id).Distinct().ToArray();

            string FormatModulesList() => moduleIds.Length == 1 ? "Module '{0}'" : "Modules ({0})";

            async Task WaitForStatusAsync()
            {
                await Retry.Do(
                    async() =>
                {
                    string[] output = await Process.RunAsync("iotedge", "list", token);

                    Log.Verbose(string.Join("\n", output));

                    return(output
                           .Where(
                               ln =>
                    {
                        var columns = ln.Split(null as char[], StringSplitOptions.RemoveEmptyEntries);
                        foreach (var moduleId in moduleIds)
                        {
                            // each line is "name status"
                            if (columns[0] == moduleId &&
                                columns[1].Equals(desired.ToString(), StringComparison.OrdinalIgnoreCase))
                            {
                                return true;
                            }
                        }

                        return false;
                    }).ToArray());
                },
                    a => a.Length == moduleIds.Length,
                    e =>
                {
                    // Retry if iotedged's management endpoint is still starting up,
                    // and therefore isn't responding to `iotedge list` yet
                    bool DaemonNotReady(string details) =>
                    details.Contains("Could not list modules", StringComparison.OrdinalIgnoreCase) ||
                    details.Contains("Socket file could not be found", StringComparison.OrdinalIgnoreCase);

                    return(DaemonNotReady(e.ToString()));
                },
                    TimeSpan.FromSeconds(5),
                    token);
            }

            return(Profiler.Run(
                       WaitForStatusAsync,
                       string.Format(FormatModulesList(), "{Modules}") + " entered the '{Desired}' state",
                       string.Join(", ", moduleIds),
                       desired.ToString().ToLower()));
        }
示例#4
0
        public Task UninstallAsync(CancellationToken token)
        {
            var commands = new[]
            {
                "$ProgressPreference='SilentlyContinue'",
                $". {this.scriptDir}\\IotEdgeSecurityDaemon.ps1",
                "Uninstall-IoTEdge -Force"
            };

            return(Profiler.Run(
                       "Uninstalling edge daemon",
                       () => Process.RunAsync("powershell", string.Join(";", commands), token)));
        }
示例#5
0
 public static Task <EdgeDevice> CreateIdentityAsync(
     string deviceId,
     IotHub iotHub,
     CancellationToken token)
 {
     return(Profiler.Run(
                $"Creating edge device '{deviceId}' on hub '{iotHub.Hostname}'",
                async() =>
     {
         Device device = await iotHub.CreateEdgeDeviceIdentityAsync(deviceId, token);
         return new EdgeDevice(device, true, iotHub);
     }));
 }
示例#6
0
        public Task StartAsync(CancellationToken token)
        {
            var sc = new ServiceController("iotedge");

            return(Profiler.Run(
                       async() =>
            {
                if (sc.Status != ServiceControllerStatus.Running)
                {
                    sc.Start();
                    await this.WaitForStatusAsync(sc, ServiceControllerStatus.Running, token);
                }
            },
                       "Started edge daemon"));
        }
示例#7
0
        public Task StopAsync(CancellationToken token)
        {
            var sc = new ServiceController("iotedge");

            return(Profiler.Run(
                       "Stopping edge daemon",
                       async() =>
            {
                if (sc.Status != ServiceControllerStatus.Stopped)
                {
                    sc.Stop();
                    await this.WaitForStatusAsync(sc, ServiceControllerStatus.Stopped, token);
                }
            }));
        }
示例#8
0
        public Task WaitForEventsReceivedAsync(CancellationToken token)
        {
            return(Profiler.Run(
                       $"Receiving events from device '{this.deviceId}' on Event Hub '{this.iotHub.EntityPath}'",
                       () => this.iotHub.ReceiveEventsAsync(
                           this.deviceId,
                           data =>
            {
                data.SystemProperties.TryGetValue("iothub-connection-device-id", out object devId);
                data.SystemProperties.TryGetValue("iothub-connection-module-id", out object modId);

                return devId != null && devId.ToString().Equals(this.deviceId) &&
                modId != null && modId.ToString().Equals(this.Id);
            },
                           token)));
        }
示例#9
0
 public Task PingAsync(CancellationToken token)
 {
     return(Profiler.Run(
                "Pinging module 'edgeAgent' from the cloud",
                () =>
     {
         return Retry.Do(
             () => this.iotHub.InvokeMethodAsync(
                 this.deviceId,
                 "$edgeAgent",
                 new CloudToDeviceMethod("ping"),
                 token),
             result => result.Status == 200,
             e => true,
             TimeSpan.FromSeconds(5),
             token);
     }));
 }
示例#10
0
        public Task UninstallAsync(CancellationToken token)
        {
            var commands = new[]
            {
                "$ProgressPreference='SilentlyContinue'",
                $". {this.scriptDir}\\IotEdgeSecurityDaemon.ps1",
                "Uninstall-IoTEdge -Force"
            };

            return(Profiler.Run(
                       async() =>
            {
                string[] output =
                    await Process.RunAsync("powershell", string.Join(";", commands), token);
                Log.Verbose(string.Join("\n", output));
            },
                       "Uninstalled edge daemon"));
        }
示例#11
0
 public Task PingAsync(CancellationToken token)
 {
     return(Profiler.Run(
                () =>
     {
         return Retry.Do(
             () => this.iotHub.InvokeMethodAsync(
                 this.deviceId,
                 $"${this.Id}",
                 new CloudToDeviceMethod("ping"),
                 token),
             result => result.Status == 200,
             e => true,
             TimeSpan.FromSeconds(5),
             token);
     },
                "Pinged module '{Module}' from the cloud",
                this.Id));
 }
示例#12
0
        public Task InstallAsync(
            string deviceConnectionString,
            Option <string> packagesPath,
            Option <Uri> proxy,
            CancellationToken token)
        {
            string installCommand = "Install-IoTEdge -Manual -ContainerOs Windows " +
                                    $"-DeviceConnectionString '{deviceConnectionString}'";

            packagesPath.ForEach(p => installCommand += $" -OfflineInstallationPath '{p}'");
            proxy.ForEach(
                p => installCommand += $" -InvokeWebRequestParameters @{{ '-Proxy' = '{p}' }}");

            var commands = new[]
            {
                "$ProgressPreference='SilentlyContinue'",
                $". {this.scriptDir}\\IotEdgeSecurityDaemon.ps1",
                installCommand
            };

            string message    = "Installed edge daemon";
            var    properties = new object[] { };

            packagesPath.ForEach(p =>
            {
                message   += " from packages in '{InstallPackagePath}'";
                properties = new object[] { p };
            });

            return(Profiler.Run(
                       async() =>
            {
                string[] output =
                    await Process.RunAsync("powershell", string.Join(";", commands), token);
                Log.Verbose(string.Join("\n", output));
            },
                       message,
                       properties));
        }
示例#13
0
        public static Task <EdgeDevice> CreateIdentityAsync(
            string deviceId,
            IotHub iotHub,
            AuthenticationType authType,
            X509Thumbprint x509Thumbprint,
            CancellationToken token)
        {
            if (authType == AuthenticationType.SelfSigned && x509Thumbprint == null)
            {
                throw new ArgumentException("A device created with self-signed mechanism must provide an x509 thumbprint.");
            }

            return(Profiler.Run(
                       async() =>
            {
                Device device = await iotHub.CreateEdgeDeviceIdentityAsync(deviceId, authType, x509Thumbprint, token);
                return new EdgeDevice(device, true, iotHub);
            },
                       "Created edge device '{Device}' on hub '{IotHub}'",
                       deviceId,
                       iotHub.Hostname));
        }
示例#14
0
 public Task WaitForReportedConfigurationAsync(object expected, CancellationToken token) => Profiler.Run(
     () => this.WaitForReportedPropertyUpdatesInternalAsync(expected, token),
     "Edge Agent confirmed deployment");
示例#15
0
        public static Task <LeafDevice> CreateAsync(
            string leafDeviceId,
            Protocol protocol,
            AuthenticationType auth,
            Option <string> parentId,
            bool useSecondaryCertificate,
            CertificateAuthority ca,
            IotHub iotHub,
            CancellationToken token)
        {
            return(Profiler.Run(
                       async() =>
            {
                ITransportSettings transport = protocol.ToTransportSettings();
                OsPlatform.Current.InstallEdgeCertificates(ca.Certificates.TrustedCertificates, transport);

                string edgeHostname = Dns.GetHostName().ToLower();

                switch (auth)
                {
                case AuthenticationType.Sas:
                    return await CreateWithSasAsync(
                        leafDeviceId,
                        parentId,
                        iotHub,
                        transport,
                        edgeHostname,
                        token);

                case AuthenticationType.CertificateAuthority:
                    {
                        string p = parentId.Expect(() => new ArgumentException());
                        return await CreateWithCaCertAsync(
                            leafDeviceId,
                            p,
                            ca,
                            iotHub,
                            transport,
                            edgeHostname,
                            token);
                    }

                case AuthenticationType.SelfSigned:
                    {
                        string p = parentId.Expect(() => new ArgumentException());
                        return await CreateWithSelfSignedCertAsync(
                            leafDeviceId,
                            p,
                            useSecondaryCertificate,
                            ca,
                            iotHub,
                            transport,
                            edgeHostname,
                            token);
                    }

                default:
                    throw new InvalidEnumArgumentException();
                }
            },
                       "Created leaf device '{Device}' on hub '{IotHub}'",
                       leafDeviceId,
                       iotHub.Hostname));
        }
示例#16
0
 public Task DeleteIdentityAsync(CancellationToken token)
 {
     return(Profiler.Run(
                $"Deleting device '{this.Id}'",
                () => this.iotHub.DeleteDeviceIdentityAsync(this.device, token)));
 }
示例#17
0
        public static Task WaitForStatusAsync(EdgeModule[] modules, EdgeModuleStatus desired, CancellationToken token)
        {
            string FormatModulesList() => modules.Length == 1
                ? $"module '{modules.First().Id}'"
                : $"modules ({string.Join(", ", modules.Select(module => module.Id))})";

            async Task WaitForStatusAsync()
            {
                try
                {
                    await Retry.Do(
                        async() =>
                    {
                        string[] result = await Process.RunAsync("iotedge", "list", token);

                        return(result
                               .Where(
                                   ln =>
                        {
                            var columns = ln.Split(null as char[], StringSplitOptions.RemoveEmptyEntries);
                            foreach (var module in modules)
                            {
                                // each line is "name status"
                                if (columns[0] == module.Id &&
                                    columns[1].Equals(desired.ToString(), StringComparison.OrdinalIgnoreCase))
                                {
                                    return true;
                                }
                            }

                            return false;
                        }).ToArray());
                    },
                        a => a.Length == modules.Length,
                        e =>
                    {
                        // Retry if iotedged's management endpoint is still starting up,
                        // and therefore isn't responding to `iotedge list` yet
                        bool DaemonNotReady(string details) =>
                        details.Contains("Could not list modules", StringComparison.OrdinalIgnoreCase) ||
                        details.Contains("Socket file could not be found", StringComparison.OrdinalIgnoreCase);

                        return(DaemonNotReady(e.ToString()));
                    },
                        TimeSpan.FromSeconds(5),
                        token);
                }
                catch (OperationCanceledException)
                {
                    throw new Exception($"Error: timed out waiting for {FormatModulesList()} to start");
                }
                catch (Exception e)
                {
                    throw new Exception($"Error searching for {FormatModulesList()}: {e}");
                }
            }

            return(Profiler.Run(
                       $"Waiting for {FormatModulesList()} to enter the '{desired.ToString().ToLower()}' state",
                       WaitForStatusAsync));
        }
示例#18
0
        public static Task <LeafDevice> CreateAsync(
            string leafDeviceId,
            Protocol protocol,
            AuthenticationType auth,
            Option <string> parentId,
            bool useSecondaryCertificate,
            CertificateAuthority ca,
            IotHub iotHub,
            string edgeHostname,
            CancellationToken token,
            Option <string> modelId,
            bool nestedEdge)
        {
            ClientOptions options = new ClientOptions();

            modelId.ForEach(m => options.ModelId = m);
            return(Profiler.Run(
                       async() =>
            {
                ITransportSettings transport = protocol.ToTransportSettings();
                OsPlatform.Current.InstallCaCertificates(ca.EdgeCertificates.TrustedCertificates, transport);

                switch (auth)
                {
                case AuthenticationType.Sas:
                    return await CreateWithSasAsync(
                        leafDeviceId,
                        parentId,
                        iotHub,
                        transport,
                        edgeHostname,
                        token,
                        options,
                        nestedEdge);

                case AuthenticationType.CertificateAuthority:
                    {
                        string p = parentId.Expect(() => new ArgumentException("Missing parent ID"));
                        return await CreateWithCaCertAsync(
                            leafDeviceId,
                            p,
                            ca,
                            iotHub,
                            transport,
                            edgeHostname,
                            token,
                            options);
                    }

                case AuthenticationType.SelfSigned:
                    {
                        string p = parentId.Expect(() => new ArgumentException("Missing parent ID"));
                        return await CreateWithSelfSignedCertAsync(
                            leafDeviceId,
                            p,
                            useSecondaryCertificate,
                            ca,
                            iotHub,
                            transport,
                            edgeHostname,
                            token,
                            options);
                    }

                default:
                    throw new InvalidEnumArgumentException();
                }
            },
                       "Created leaf device '{Device}' on hub '{IotHub}'",
                       leafDeviceId,
                       iotHub.Hostname));
        }
示例#19
0
        public static Task WaitForStatusAsync(EdgeModule[] modules, EdgeModuleStatus desired, CancellationToken token)
        {
            (string template, string[] args) FormatModulesList() => modules.Length == 1
                ? ("module '{0}'", new[] { modules.First().Id })
                : ("modules ({0})", modules.Select(module => module.Id).ToArray());

            string SentenceCase(string input) =>
            $"{input.First().ToString().ToUpper()}{input.Substring(1)}";

            async Task WaitForStatusAsync()
            {
                try
                {
                    await Retry.Do(
                        async() =>
                    {
                        string[] output = await Process.RunAsync("iotedge", "list", token);

                        Log.Verbose(string.Join("\n", output));

                        return(output
                               .Where(
                                   ln =>
                        {
                            var columns = ln.Split(null as char[], StringSplitOptions.RemoveEmptyEntries);
                            foreach (var module in modules)
                            {
                                // each line is "name status"
                                if (columns[0] == module.Id &&
                                    columns[1].Equals(desired.ToString(), StringComparison.OrdinalIgnoreCase))
                                {
                                    return true;
                                }
                            }

                            return false;
                        }).ToArray());
                    },
                        a => a.Length == modules.Length,
                        e =>
                    {
                        // Retry if iotedged's management endpoint is still starting up,
                        // and therefore isn't responding to `iotedge list` yet
                        bool DaemonNotReady(string details) =>
                        details.Contains("Could not list modules", StringComparison.OrdinalIgnoreCase) ||
                        details.Contains("Socket file could not be found", StringComparison.OrdinalIgnoreCase);

                        return(DaemonNotReady(e.ToString()));
                    },
                        TimeSpan.FromSeconds(5),
                        token);
                }
                catch (OperationCanceledException)
                {
                    (string t, string[] a) = FormatModulesList();
                    throw new Exception(string.Format($"Error: timed out waiting for {t} to start", a));
                }
                catch (Exception e)
                {
                    (string t, string[] a) = FormatModulesList();
                    throw new Exception(string.Format($"Error searching for {t}: {e}", a));
                }
            }

            (string template, string[] args) = FormatModulesList();
            return(Profiler.Run(
                       WaitForStatusAsync,
                       string.Format(SentenceCase(template), "{Modules}") + " entered the '{Desired}' state",
                       string.Join(", ", args),
                       desired.ToString().ToLower()));
        }
示例#20
0
 public Task DeleteIdentityAsync(CancellationToken token) =>
 Profiler.Run(
     () => this.iotHub.DeleteDeviceIdentityAsync(this.device, token),
     "Deleted edge device '{Device}'",
     this.Id);
示例#21
0
 public Task UpdateDesiredPropertiesAsync(object patch, CancellationToken token)
 {
     return(Profiler.Run(
                $"Updating twin for module '{this.moduleId}'",
                () => this.iotHub.UpdateTwinAsync(this.deviceId, this.moduleId, patch, token)));
 }