protected Task ConfigureBootstrapper() { Console.WriteLine("Configuring bootstrapper."); DeviceProvisioningMethod method = this.dpsAttestation.Match( dps => { return(new DeviceProvisioningMethod(dps)); }, () => { IotHubConnectionStringBuilder builder = IotHubConnectionStringBuilder.Create(this.context.IotHubConnectionString); Device device = this.context.Device.Expect(() => new InvalidOperationException("Expected a valid device instance")); string connectionString = $"HostName={builder.HostName};" + $"DeviceId={device.Id};" + $"SharedAccessKey={device.Authentication.SymmetricKey.PrimaryKey}"; return(new DeviceProvisioningMethod(connectionString)); }); Option <string> agentImage = Option.None <string>(); if (this.initializeWithAgentArtifact) { agentImage = Option.Some <string>(this.EdgeAgentImage()); } return(this.bootstrapper.Configure(method, agentImage, this.hostname, this.parentHostname, this.deviceCaCert, this.deviceCaPk, this.deviceCaCerts, this.runtimeLogLevel)); }
public async Task Configure(DeviceProvisioningMethod method, string image, string hostname, string deviceCaCert, string deviceCaPk, string deviceCaCerts, LogLevel runtimeLogLevel) { Console.WriteLine($"Setting up iotedgectl with agent image '{image}'"); string connectionString = method.ManualConnectionString.Expect(() => new ArgumentException("The iotedgectl utility only supports device connection string to bootstrap Edge")); string registryArgs = this.credentials.Match( c => $"--docker-registries {c.Address} {c.User} {c.Password}", () => string.Empty); await Process.RunAsync( "iotedgectl", $"setup --connection-string \"{connectionString}\" --nopass {registryArgs} --image {image} --edge-hostname {hostname}", 120); }
protected Task ConfigureBootstrapper() { Console.WriteLine("Configuring bootstrapper."); DeviceProvisioningMethod method = this.dpsAttestation.Match( dps => { return(new DeviceProvisioningMethod(dps)); }, () => { IotHubConnectionStringBuilder builder = IotHubConnectionStringBuilder.Create(this.context.IotHubConnectionString); string connectionString = $"HostName={builder.HostName};" + $"DeviceId={this.context.Device.Id};" + $"SharedAccessKey={this.context.Device.Authentication.SymmetricKey.PrimaryKey}"; return(new DeviceProvisioningMethod(connectionString)); }); return(this.bootstrapper.Configure(method, this.EdgeAgentImage(), this.hostname, this.deviceCaCert, this.deviceCaPk, this.deviceCaCerts, this.runtimeLogLevel)); }
public async Task Configure( DeviceProvisioningMethod method, Option <string> agentImage, string hostname, Option <string> parentHostname, string deviceCaCert, string deviceCaPk, string deviceCaCerts, LogLevel runtimeLogLevel) { agentImage.ForEach( image => { Console.WriteLine($"Setting up aziot-edged with agent image {image}"); }, () => { Console.WriteLine("Setting up aziot-edged with agent image 1.0"); }); const string KEYD = "/etc/aziot/keyd/config.toml"; const string CERTD = "/etc/aziot/certd/config.toml"; const string IDENTITYD = "/etc/aziot/identityd/config.toml"; const string EDGED = "/etc/aziot/edged/config.yaml"; // Initialize each service's config file. // The mapped values are: // - Path to the config file (/etc/aziot/[service_name]/config.[toml | yaml]) // - User owning the config file // - Template used to generate the config file. Dictionary <string, (string owner, IConfigDocument document)> config = new Dictionary <string, (string, IConfigDocument)>(); config.Add(KEYD, ("aziotks", InitDocument(KEYD + ".default", true))); config.Add(CERTD, ("aziotcs", InitDocument(CERTD + ".default", true))); config.Add(IDENTITYD, ("aziotid", InitDocument(IDENTITYD + ".default", true))); config.Add(EDGED, ("iotedge", InitDocument(EDGED + ".template", false))); // Directory for storing keys; create it if it doesn't exist. string keyDir = "/var/secrets/aziot/keyd/"; Directory.CreateDirectory(keyDir); SetOwner(keyDir, config[KEYD].owner, "700"); // Need to always reprovision so previous test runs don't affect this one. config[IDENTITYD].document.RemoveIfExists("provisioning"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.always_reprovision_on_startup", true); method.ManualConnectionString.Match( cs => { string keyPath = Path.Combine(keyDir, "device-id"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.source", "manual"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.authentication.method", "sas"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.authentication.device_id_pk", "device-id"); config[KEYD].document.ReplaceOrAdd("preloaded_keys.device-id", $"file://{keyPath}"); string[] segments = cs.Split(";"); foreach (string s in segments) { string[] param = s.Split("=", 2); switch (param[0]) { case "HostName": // replace IoTHub hostname with parent hostname for nested edge config[IDENTITYD].document.ReplaceOrAdd("provisioning.iothub_hostname", parentHostname.GetOrElse(param[1])); break; case "SharedAccessKey": File.WriteAllBytes(keyPath, Convert.FromBase64String(param[1])); SetOwner(keyPath, config[KEYD].owner, "600"); break; case "DeviceId": config[IDENTITYD].document.ReplaceOrAdd("provisioning.device_id", param[1]); break; default: break; } } return(string.Empty); }, () => { config[IDENTITYD].document.RemoveIfExists("provisioning"); return(string.Empty); }); method.Dps.ForEach( dps => { config[IDENTITYD].document.ReplaceOrAdd("provisioning.source", "dps"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.global_endpoint", dps.EndPoint); config[IDENTITYD].document.ReplaceOrAdd("provisioning.scope_id", dps.ScopeId); switch (dps.AttestationType) { case DPSAttestationType.SymmetricKey: string dpsKeyPath = Path.Combine(keyDir, "device-id"); string dpsKey = dps.SymmetricKey.Expect(() => new ArgumentException("Expected symmetric key")); File.WriteAllBytes(dpsKeyPath, Convert.FromBase64String(dpsKey)); SetOwner(dpsKeyPath, config[KEYD].owner, "600"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.method", "symmetric_key"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.symmetric_key", "device-id"); break; case DPSAttestationType.X509: string certPath = dps.DeviceIdentityCertificate.Expect(() => new ArgumentException("Expected path to identity certificate")); string keyPath = dps.DeviceIdentityPrivateKey.Expect(() => new ArgumentException("Expected path to identity private key")); SetOwner(certPath, config[CERTD].owner, "444"); SetOwner(keyPath, config[KEYD].owner, "400"); config[CERTD].document.ReplaceOrAdd("preloaded_certs.device-id", new Uri(certPath).AbsoluteUri); config[KEYD].document.ReplaceOrAdd("preloaded_keys.device-id", new Uri(keyPath).AbsoluteUri); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.method", "x509"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.identity_cert", "device-id"); config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.identity_pk", "device-id"); break; default: break; } dps.RegistrationId.ForEach(id => { config[IDENTITYD].document.ReplaceOrAdd("provisioning.attestation.registration_id", id); }); }); agentImage.ForEach(image => { config[EDGED].document.ReplaceOrAdd("agent.config.image", image); }); config[EDGED].document.ReplaceOrAdd("hostname", hostname); config[IDENTITYD].document.ReplaceOrAdd("hostname", hostname); parentHostname.ForEach(v => config[EDGED].document.ReplaceOrAdd("parent_hostname", v)); foreach (RegistryCredentials c in this.credentials) { config[EDGED].document.ReplaceOrAdd("agent.config.auth.serveraddress", c.Address); config[EDGED].document.ReplaceOrAdd("agent.config.auth.username", c.User); config[EDGED].document.ReplaceOrAdd("agent.config.auth.password", c.Password); } config[EDGED].document.ReplaceOrAdd("agent.env.RuntimeLogLevel", runtimeLogLevel.ToString()); if (this.httpUris.HasValue) { HttpUris uris = this.httpUris.OrDefault(); config[EDGED].document.ReplaceOrAdd("connect.management_uri", uris.ConnectManagement); config[EDGED].document.ReplaceOrAdd("connect.workload_uri", uris.ConnectWorkload); config[EDGED].document.ReplaceOrAdd("listen.management_uri", uris.ListenManagement); config[EDGED].document.ReplaceOrAdd("listen.workload_uri", uris.ListenWorkload); } else { UriSocks socks = this.uriSocks; config[EDGED].document.ReplaceOrAdd("connect.management_uri", socks.ConnectManagement); config[EDGED].document.ReplaceOrAdd("connect.workload_uri", socks.ConnectWorkload); config[EDGED].document.ReplaceOrAdd("listen.management_uri", socks.ListenManagement); config[EDGED].document.ReplaceOrAdd("listen.workload_uri", socks.ListenWorkload); } // Clear any existing Identity Service principals. string principalsPath = "/etc/aziot/identityd/config.d"; config[IDENTITYD].document.RemoveIfExists("principal"); if (Directory.Exists(principalsPath)) { Directory.Delete(principalsPath, true); } Directory.CreateDirectory(principalsPath); SetOwner(principalsPath, "aziotid", "755"); // Add the principal entry for aziot-edge to Identity Service. // This is required so aziot-edge can communicate with Identity Service. uint iotedgeUid = await GetIotedgeUid(); AddPrincipal("aziot-edge", iotedgeUid); foreach (string file in new string[] { deviceCaCert, deviceCaPk, deviceCaCerts }) { if (string.IsNullOrEmpty(file)) { throw new ArgumentException("device_ca_cert, device_ca_pk, and trusted_ca_certs must all be provided."); } if (!File.Exists(file)) { throw new ArgumentException($"{file} does not exist."); } } // Files must be readable by KS and CS users. SetOwner(deviceCaCerts, config[CERTD].owner, "444"); SetOwner(deviceCaCert, config[CERTD].owner, "444"); SetOwner(deviceCaPk, config[KEYD].owner, "400"); config[CERTD].document.ReplaceOrAdd("preloaded_certs.aziot-edged-trust-bundle", new Uri(deviceCaCerts).AbsoluteUri); config[CERTD].document.ReplaceOrAdd("preloaded_certs.aziot-edged-ca", new Uri(deviceCaCert).AbsoluteUri); config[KEYD].document.ReplaceOrAdd("preloaded_keys.aziot-edged-ca", new Uri(deviceCaPk).AbsoluteUri); this.proxy.ForEach(proxy => config[EDGED].document.ReplaceOrAdd("agent.env.https_proxy", proxy)); this.upstreamProtocol.ForEach(upstreamProtocol => config[EDGED].document.ReplaceOrAdd("agent.env.UpstreamProtocol", upstreamProtocol.ToString())); foreach (KeyValuePair <string, (string owner, IConfigDocument document)> service in config) { string path = service.Key; string text = service.Value.document.ToString(); await File.WriteAllTextAsync(path, text); SetOwner(path, service.Value.owner, "644"); Console.WriteLine($"Created config {path}"); } }
public async Task Configure(DeviceProvisioningMethod method, Option <string> agentImage, string hostname, Option <string> parentHostname, string deviceCaCert, string deviceCaPk, string deviceCaCerts, LogLevel runtimeLogLevel) { // IMPORTANT: Parent hostname is not going to handled in Windows since Windows is not going to support for 1.1.0. const string HidePowerShellProgressBar = "$ProgressPreference='SilentlyContinue'"; agentImage.ForEach( image => { Console.WriteLine($"Setting up iotedged with agent image {image}"); }, () => { Console.WriteLine("Setting up iotedged with agent image 1.0"); }); using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5))) { if (!string.IsNullOrEmpty(this.offlineInstallationPath)) { this.scriptDir = File.GetAttributes(this.offlineInstallationPath).HasFlag(FileAttributes.Directory) ? this.offlineInstallationPath : new FileInfo(this.offlineInstallationPath).DirectoryName; } else { this.scriptDir = Path.GetTempPath(); await Process.RunAsync( "powershell", $"{HidePowerShellProgressBar}; Invoke-WebRequest -UseBasicParsing -OutFile '{this.scriptDir}\\IotEdgeSecurityDaemon.ps1' aka.ms/iotedge-win", cts.Token); } string args; if (this.requireEdgeInstallation) { Console.WriteLine("Installing iotedge..."); args = $". {this.scriptDir}\\IotEdgeSecurityDaemon.ps1; Install-SecurityDaemon " + $"-ContainerOs Windows"; this.proxy.ForEach(proxy => { args += $" -Proxy '{proxy}'"; }); if (!string.IsNullOrEmpty(this.offlineInstallationPath)) { args += $" -OfflineInstallationPath '{this.offlineInstallationPath}'"; } } else { Console.WriteLine("Initializing iotedge..."); args = $". {this.scriptDir}\\IotEdgeSecurityDaemon.ps1; Initialize-IoTEdge " + $"-ContainerOs Windows"; } agentImage.ForEach(image => { args += $" -AgentImage '{image}'"; foreach (RegistryCredentials c in this.credentials) { args += $" -Username '{c.User}' -Password (ConvertTo-SecureString '{c.Password}' -AsPlainText -Force)"; } }); args += method.Dps.Map( dps => { string dpsArgs = string.Empty; dpsArgs += $" -Dps -ScopeId '{dps.ScopeId}'"; dps.RegistrationId.ForEach(id => { dpsArgs += $" -RegistrationId '{id}'"; }); dps.DeviceIdentityCertificate.ForEach(certPath => { dpsArgs += $" -X509IdentityCertificate '{certPath}'"; }); dps.DeviceIdentityPrivateKey.ForEach(pkPath => { dpsArgs += $" -X509IdentityPrivateKey '{pkPath}'"; }); dps.SymmetricKey.ForEach(symmKey => { dpsArgs += $" -SymmetricKey '{symmKey}'"; }); return(dpsArgs); }).GetOrElse(string.Empty); // *************************************************************** // IMPORTANT: All secret/sensitive argument should be place below. // *************************************************************** Console.WriteLine($"Run command arguments to configure: {args}"); args += method.ManualConnectionString.Map( cs => { return($" -Manual -DeviceConnectionString '{cs}'"); }).GetOrElse(string.Empty); // note: ignore hostname for now string[] result = await Process.RunAsync("powershell", $"{HidePowerShellProgressBar}; {args}", cts.Token); WriteToConsole("Output from Configure iotedge windows service", result); // Stop service and update config file await Task.Delay(TimeSpan.FromSeconds(5)); await this.Stop(); this.UpdateConfigYamlFile(deviceCaCert, deviceCaPk, deviceCaCerts, runtimeLogLevel); // Explicitly set IOTEDGE_HOST environment variable to current process this.SetEnvironmentVariable(); } }
public async Task Configure(DeviceProvisioningMethod method, Option <string> agentImage, string hostname, string deviceCaCert, string deviceCaPk, string deviceCaCerts, LogLevel runtimeLogLevel) { agentImage.ForEach( image => { Console.WriteLine($"Setting up iotedged with agent image {image}"); }, () => { Console.WriteLine("Setting up iotedged with agent image 1.0"); }); const string YamlPath = "/etc/iotedge/config.yaml"; Task <string> text = File.ReadAllTextAsync(YamlPath); var doc = new YamlDocument(await text); method.ManualConnectionString.Match( cs => { doc.ReplaceOrAdd("provisioning.device_connection_string", cs); return(string.Empty); }, () => { doc.Remove("provisioning.device_connection_string"); return(string.Empty); }); method.Dps.ForEach( dps => { doc.ReplaceOrAdd("provisioning.source", "dps"); doc.ReplaceOrAdd("provisioning.global_endpoint", dps.EndPoint); doc.ReplaceOrAdd("provisioning.scope_id", dps.ScopeId); switch (dps.AttestationType) { case DPSAttestationType.SymmetricKey: doc.ReplaceOrAdd("provisioning.attestation.method", "symmetric_key"); doc.ReplaceOrAdd("provisioning.attestation.symmetric_key", dps.SymmetricKey.Expect(() => new ArgumentException("Expected symmetric key"))); break; case DPSAttestationType.X509: var certUri = new Uri(dps.DeviceIdentityCertificate.Expect(() => new ArgumentException("Expected path to identity certificate"))); var keyUri = new Uri(dps.DeviceIdentityPrivateKey.Expect(() => new ArgumentException("Expected path to identity private key"))); doc.ReplaceOrAdd("provisioning.attestation.method", "x509"); doc.ReplaceOrAdd("provisioning.attestation.identity_cert", certUri.AbsoluteUri); doc.ReplaceOrAdd("provisioning.attestation.identity_pk", keyUri.AbsoluteUri); break; default: doc.ReplaceOrAdd("provisioning.attestation.method", "tpm"); break; } dps.RegistrationId.ForEach(id => { doc.ReplaceOrAdd("provisioning.attestation.registration_id", id); }); }); agentImage.ForEach(image => { doc.ReplaceOrAdd("agent.config.image", image); }); doc.ReplaceOrAdd("hostname", hostname); foreach (RegistryCredentials c in this.credentials) { doc.ReplaceOrAdd("agent.config.auth.serveraddress", c.Address); doc.ReplaceOrAdd("agent.config.auth.username", c.User); doc.ReplaceOrAdd("agent.config.auth.password", c.Password); } doc.ReplaceOrAdd("agent.env.RuntimeLogLevel", runtimeLogLevel.ToString()); if (this.httpUris.HasValue) { HttpUris uris = this.httpUris.OrDefault(); doc.ReplaceOrAdd("connect.management_uri", uris.ConnectManagement); doc.ReplaceOrAdd("connect.workload_uri", uris.ConnectWorkload); doc.ReplaceOrAdd("listen.management_uri", uris.ListenManagement); doc.ReplaceOrAdd("listen.workload_uri", uris.ListenWorkload); } else { doc.ReplaceOrAdd("connect.management_uri", "unix:///var/run/iotedge/mgmt.sock"); doc.ReplaceOrAdd("connect.workload_uri", "unix:///var/run/iotedge/workload.sock"); doc.ReplaceOrAdd("listen.management_uri", "fd://iotedge.mgmt.socket"); doc.ReplaceOrAdd("listen.workload_uri", "fd://iotedge.socket"); } if (!string.IsNullOrEmpty(deviceCaCert) && !string.IsNullOrEmpty(deviceCaPk) && !string.IsNullOrEmpty(deviceCaCerts)) { doc.ReplaceOrAdd("certificates.device_ca_cert", deviceCaCert); doc.ReplaceOrAdd("certificates.device_ca_pk", deviceCaPk); doc.ReplaceOrAdd("certificates.trusted_ca_certs", deviceCaCerts); } this.proxy.ForEach(proxy => doc.ReplaceOrAdd("agent.env.https_proxy", proxy)); this.upstreamProtocol.ForEach(upstreamProtocol => doc.ReplaceOrAdd("agent.env.UpstreamProtocol", upstreamProtocol.ToString())); string result = doc.ToString(); FileAttributes attr = 0; if (File.Exists(YamlPath)) { attr = File.GetAttributes(YamlPath); File.SetAttributes(YamlPath, attr & ~FileAttributes.ReadOnly); } await File.WriteAllTextAsync(YamlPath, result); if (attr != 0) { File.SetAttributes(YamlPath, attr); } }
public async Task Configure( DeviceProvisioningMethod method, Option <string> agentImage, string hostname, Option <string> parentHostname, string deviceCaCert, string deviceCaPk, string deviceCaCerts, LogLevel runtimeLogLevel) { agentImage.ForEach( image => { Console.WriteLine($"Setting up aziot-edged with agent image {image}"); }, () => { Console.WriteLine("Setting up aziot-edged with agent image 1.0"); }); // Initialize each service's config file. Dictionary <string, Config> config = new Dictionary <string, Config>(); config.Add(KEYD, await InitConfig(KEYD + ".default", "aziotks")); config.Add(CERTD, await InitConfig(CERTD + ".default", "aziotcs")); config.Add(IDENTITYD, await InitConfig(IDENTITYD + ".default", "aziotid")); config.Add(EDGED, await InitConfig(EDGED + ".default", "iotedge")); // Directory for storing keys; create it if it doesn't exist. string keyDir = "/var/secrets/aziot/keyd/"; Directory.CreateDirectory(keyDir); SetOwner(keyDir, config[KEYD].Owner, "700"); // Need to always reprovision so previous test runs don't affect this one. config[EDGED].Document.ReplaceOrAdd("auto_reprovisioning_mode", "AlwaysOnStartup"); config[IDENTITYD].Document.RemoveIfExists("provisioning"); parentHostname.ForEach( parent_hostame => config[IDENTITYD].Document.ReplaceOrAdd("provisioning.local_gateway_hostname", parent_hostame)); method.ManualConnectionString.Match( cs => { string keyPath = Path.Combine(keyDir, "device-id"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.source", "manual"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.authentication.method", "sas"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.authentication.device_id_pk", "device-id"); config[KEYD].Document.ReplaceOrAdd("preloaded_keys.device-id", $"file://{keyPath}"); string[] segments = cs.Split(";"); foreach (string s in segments) { string[] param = s.Split("=", 2); switch (param[0]) { case "HostName": // replace IoTHub hostname with parent hostname for nested edge config[IDENTITYD].Document.ReplaceOrAdd("provisioning.iothub_hostname", param[1]); break; case "SharedAccessKey": File.WriteAllBytes(keyPath, Convert.FromBase64String(param[1])); SetOwner(keyPath, config[KEYD].Owner, "600"); break; case "DeviceId": config[IDENTITYD].Document.ReplaceOrAdd("provisioning.device_id", param[1]); break; default: break; } } this.SetAuth("device-id", config); return(string.Empty); }, () => { config[IDENTITYD].Document.RemoveIfExists("provisioning"); return(string.Empty); }); method.Dps.ForEach( dps => { config[IDENTITYD].Document.ReplaceOrAdd("provisioning.source", "dps"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.global_endpoint", dps.EndPoint); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.scope_id", dps.ScopeId); switch (dps.AttestationType) { case DPSAttestationType.SymmetricKey: string dpsKeyPath = Path.Combine(keyDir, "device-id"); string dpsKey = dps.SymmetricKey.Expect(() => new ArgumentException("Expected symmetric key")); File.WriteAllBytes(dpsKeyPath, Convert.FromBase64String(dpsKey)); SetOwner(dpsKeyPath, config[KEYD].Owner, "600"); config[KEYD].Document.ReplaceOrAdd("preloaded_keys.device-id", new Uri(dpsKeyPath).AbsoluteUri); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.method", "symmetric_key"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.symmetric_key", "device-id"); this.SetAuth("device-id", config); break; case DPSAttestationType.X509: string certPath = dps.DeviceIdentityCertificate.Expect(() => new ArgumentException("Expected path to identity certificate")); string keyPath = dps.DeviceIdentityPrivateKey.Expect(() => new ArgumentException("Expected path to identity private key")); SetOwner(certPath, config[CERTD].Owner, "444"); SetOwner(keyPath, config[KEYD].Owner, "400"); config[CERTD].Document.ReplaceOrAdd("preloaded_certs.device-id", new Uri(certPath).AbsoluteUri); config[KEYD].Document.ReplaceOrAdd("preloaded_keys.device-id", new Uri(keyPath).AbsoluteUri); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.method", "x509"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.identity_cert", "device-id"); config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.identity_pk", "device-id"); this.SetAuth("device-id", config); break; default: break; } dps.RegistrationId.ForEach(id => { config[IDENTITYD].Document.ReplaceOrAdd("provisioning.attestation.registration_id", id); }); }); agentImage.ForEach(image => { config[EDGED].Document.ReplaceOrAdd("agent.config.image", image); }); config[EDGED].Document.ReplaceOrAdd("hostname", hostname); config[IDENTITYD].Document.ReplaceOrAdd("hostname", hostname); parentHostname.ForEach(v => config[EDGED].Document.ReplaceOrAdd("parent_hostname", v)); foreach (RegistryCredentials c in this.credentials) { config[EDGED].Document.ReplaceOrAdd("agent.config.auth.serveraddress", c.Address); config[EDGED].Document.ReplaceOrAdd("agent.config.auth.username", c.User); config[EDGED].Document.ReplaceOrAdd("agent.config.auth.password", c.Password); } config[EDGED].Document.ReplaceOrAdd("agent.env.RuntimeLogLevel", runtimeLogLevel.ToString()); if (this.httpUris.HasValue) { HttpUris uris = this.httpUris.OrDefault(); config[EDGED].Document.ReplaceOrAdd("connect.management_uri", uris.ConnectManagement); config[EDGED].Document.ReplaceOrAdd("connect.workload_uri", uris.ConnectWorkload); config[EDGED].Document.ReplaceOrAdd("listen.management_uri", uris.ListenManagement); config[EDGED].Document.ReplaceOrAdd("listen.workload_uri", uris.ListenWorkload); } else { UriSocks socks = this.uriSocks; config[EDGED].Document.ReplaceOrAdd("connect.management_uri", socks.ConnectManagement); config[EDGED].Document.ReplaceOrAdd("connect.workload_uri", socks.ConnectWorkload); config[EDGED].Document.ReplaceOrAdd("listen.management_uri", socks.ListenManagement); config[EDGED].Document.ReplaceOrAdd("listen.workload_uri", socks.ListenWorkload); } foreach (string file in new string[] { deviceCaCert, deviceCaPk, deviceCaCerts }) { if (string.IsNullOrEmpty(file)) { throw new ArgumentException("device_ca_cert, device_ca_pk, and trusted_ca_certs must all be provided."); } if (!File.Exists(file)) { throw new ArgumentException($"{file} does not exist."); } } // Files must be readable by KS and CS users. SetOwner(deviceCaCerts, config[CERTD].Owner, "444"); SetOwner(deviceCaCert, config[CERTD].Owner, "444"); SetOwner(deviceCaPk, config[KEYD].Owner, "400"); config[CERTD].Document.ReplaceOrAdd("preloaded_certs.aziot-edged-trust-bundle", new Uri(deviceCaCerts).AbsoluteUri); config[CERTD].Document.ReplaceOrAdd("preloaded_certs.aziot-edged-ca", new Uri(deviceCaCert).AbsoluteUri); config[KEYD].Document.ReplaceOrAdd("preloaded_keys.aziot-edged-ca", new Uri(deviceCaPk).AbsoluteUri); this.proxy.ForEach(proxy => config[EDGED].Document.ReplaceOrAdd("agent.env.https_proxy", proxy)); this.upstreamProtocol.ForEach(upstreamProtocol => config[EDGED].Document.ReplaceOrAdd("agent.env.UpstreamProtocol", upstreamProtocol.ToString())); foreach (KeyValuePair <string, Config> service in config) { string path = service.Key; string text = service.Value.Document.ToString(); await File.WriteAllTextAsync(path, text); SetOwner(path, service.Value.Owner, "644"); Console.WriteLine($"Created config {path}"); } using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2))) { Console.WriteLine($"Calling iotedge system set-log-level {runtimeLogLevel.ToString().ToLower()}"); string[] output = await Process.RunAsync("iotedge", $"system set-log-level {runtimeLogLevel.ToString().ToLower()}", cts.Token); Console.WriteLine($"{output.ToString()}"); } }