Example #1
0
        public void ClientConfig_ClientInit_FromFile()
        {
            const string filename = "ClientConfig_NewAzure.xml";

            var client = new ClientBuilder()
                         .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(ISimpleGrain).Assembly))
                         .LoadConfiguration(filename)
                         .Build();

            try
            {
                ClientConfiguration config = client.Configuration();

                output.WriteLine(config);

                Assert.NotNull(config);                                      // Client.CurrentConfig

                Assert.Equal(filename, Path.GetFileName(config.SourceFile)); // ClientConfig.SourceFile

                // GatewayProviderType
                Assert.Equal(ClientConfiguration.GatewayProviderType.AzureTable, config.GatewayProvider);
            }
            finally
            {
                client.Dispose();
            }
        }
Example #2
0
        private static async Task <IClusterClient> InitialiseClient(IConfigurationRoot configuration)
        {
            IClusterClient client = null;

            int tryTimes = 10;

            while (tryTimes > 0)
            {
                try
                {
                    client = new ClientBuilder()
                             .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IHelloGrain).Assembly))
                             .Configure <ClusterOptions>(options =>
                    {
                        options.ClusterId = configuration.GetSection("ClusterId").Value;
                        options.ServiceId = configuration.GetSection("ServiceId").Value;
                    })
                             .UseAdoNetClustering(options =>
                    {
                        options.Invariant        = "System.Data.SqlClient";
                        options.ConnectionString = configuration.GetSection("ConnectionString").Value;
                    })
                             .Build();

                    await client.Connect();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    await Task.Delay(TimeSpan.FromSeconds(5));

                    if (client != null && !client.IsInitialized)
                    {
                        client.Dispose();
                        client = null;
                    }
                }
                tryTimes--;
            }

            return(client);
        }
Example #3
0
        public async Task LocalhostClusterTest()
        {
            using var portAllocator            = new TestClusterPortAllocator();
            var(baseSiloPort, baseGatewayPort) = portAllocator.AllocateConsecutivePortPairs(2);
            var silo1 = new HostBuilder().UseOrleans(siloBuilder =>
            {
                siloBuilder
                .AddMemoryGrainStorage("MemoryStore")
                .UseLocalhostClustering(baseSiloPort, baseGatewayPort);
            }).Build();

            var silo2 = new HostBuilder().UseOrleans(siloBuilder =>
            {
                siloBuilder
                .AddMemoryGrainStorage("MemoryStore")
                .UseLocalhostClustering(baseSiloPort + 1, baseGatewayPort + 1, new IPEndPoint(IPAddress.Loopback, baseSiloPort));
            }).Build();

            var client = new ClientBuilder()
                         .UseLocalhostClustering(new[] { baseGatewayPort, baseGatewayPort + 1 })
                         .Build();

            try
            {
                await Task.WhenAll(silo1.StartAsync(), silo2.StartAsync());

                await client.Connect();

                var grain  = client.GetGrain <IEchoGrain>(Guid.NewGuid());
                var result = await grain.Echo("test");

                Assert.Equal("test", result);
            }
            finally
            {
                var cancelled = new CancellationTokenSource();
                cancelled.Cancel();
                Utils.SafeExecute(() => silo1.StopAsync(cancelled.Token));
                Utils.SafeExecute(() => silo2.StopAsync(cancelled.Token));
                Utils.SafeExecute(() => silo1.Dispose());
                Utils.SafeExecute(() => silo2.Dispose());
                Utils.SafeExecute(() => client.Close());
                Utils.SafeExecute(() => client.Dispose());
            }
        }
        public async Task LocalhostClusterTest()
        {
            var silo1 = new SiloHostBuilder()
                        .AddMemoryGrainStorage("MemoryStore")
                        .UseLocalhostClustering(12111, 30001)
                        .Build();

            var silo2 = new SiloHostBuilder()
                        .AddMemoryGrainStorage("MemoryStore")
                        .UseLocalhostClustering(12112, 30002, new IPEndPoint(IPAddress.Loopback, 12111))
                        .Build();

            var client = new ClientBuilder()
                         .UseLocalhostClustering(new[] { 30001, 30002 })
                         .Build();

            try
            {
                await Task.WhenAll(silo1.StartAsync(), silo2.StartAsync());

                await client.Connect();

                var grain  = client.GetGrain <IEchoGrain>(Guid.NewGuid());
                var result = await grain.Echo("test");

                Assert.Equal("test", result);
            }
            finally
            {
                var cancelled = new CancellationTokenSource();
                cancelled.Cancel();
                Utils.SafeExecute(() => silo1.StopAsync(cancelled.Token));
                Utils.SafeExecute(() => silo2.StopAsync(cancelled.Token));
                Utils.SafeExecute(() => silo1.Dispose());
                Utils.SafeExecute(() => silo2.Dispose());
                Utils.SafeExecute(() => client.Close());
                Utils.SafeExecute(() => client.Dispose());
            }
        }
Example #5
0
        static void Main(string[] args)
        {
            var config = ClientConfiguration.LocalhostSilo();
            var client = new ClientBuilder()
                         .LoadConfiguration("../../ClientConfiguration.xml")
                         .Build();

            client.Connect().Wait();
            Console.WriteLine("Press number or x [Enter] to terminate...");

            string nextCommand = "";

            while (!(nextCommand.ToUpperInvariant() == "X"))
            {
                nextCommand = Console.ReadLine();
                var grain = client.GetGrain <ITalkativeGrain>("Grain-" + nextCommand);
                grain.Talk("Grain-" + nextCommand);
            }

            client.Close();
            client.Dispose();
        }
Example #6
0
        public static async Task Main(string[] args)
        {
            var environment   = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development";
            var isDevelopment = "Development".Equals(environment, StringComparison.OrdinalIgnoreCase);

            var config = new ConfigurationBuilder()
                         .SetBasePath(Directory.GetCurrentDirectory())
                         .AddInMemoryCollection(new Dictionary <string, string> // add default settings, that will be overridden by commandline
            {
                { "Id", "Webapp" },
                { "Version", "1.0.0" },
                { "ClusterId", "rrod-cluster" },
                { "ServiceId", "rrod" }
            })
                         .AddCommandLine(args)
                         .AddJsonFile("Webapp.settings.json", optional: true, reloadOnChange: true)
                         .AddJsonFile($"Webapp.settings.{environment}.json", optional: true, reloadOnChange: true)
                         .AddJsonFile("/run/config/Webapp.settings.json", optional: true, reloadOnChange: true)
                         .AddDockerSecrets("/run/secrets", optional: true)
                         .AddUserSecrets <Program>(optional: true)
                         .AddEnvironmentVariables("RROD_")
                         .Build();

            var loggerFactory = new LoggerFactory()
                                .AddConsole(config.GetSection("Logging"))
                                .AddDebug();
            var logger = loggerFactory.CreateLogger <Program>();

            logger.LogWarning($"Starting Webapp in {environment} environment...");

            foreach (var provider in config.Providers)
            {
                logger.LogInformation($"Config Provider {provider.GetType().Name}: {provider.GetChildKeys(Enumerable.Empty<string>(), null).Count()} settings");
            }

            // ServicePointManager.CheckCertificateRevocationList = false;
            ServicePointManager.SecurityProtocol       = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
            ServicePointManager.DefaultConnectionLimit = 20;

            int            attempt = 0;
            int            initializeAttemptsBeforeFailing = 7;
            IClusterClient clusterClient = null;

            while (true)
            {
                // Initialize orleans client
                clusterClient = new ClientBuilder()
                                .ConfigureServices((context, services) =>
                {
                    // services.AddOptions();
                    services.AddSingleton <ILoggerFactory>(loggerFactory);
                    // services.AddSingleton<IConfiguration>(config);
                    services.Configure <ClusterOptions>(config);
                })
                                .AddAzureQueueStreams <AzureQueueDataAdapterV2>("Default", builder => builder.Configure(options => options.ConnectionString = config.GetConnectionString("DataConnectionString")))
                                .ConfigureApplicationParts(parts =>
                {
                    parts.AddApplicationPart(typeof(ICounterGrain).Assembly).WithReferences();
                    parts.AddApplicationPart(typeof(AzureQueueDataAdapterV2).Assembly).WithReferences();
                })
                                .UseAzureStorageClustering(options => options.ConnectionString = config.GetConnectionString("DataConnectionString"))
                                .Build();

                try
                {
                    await clusterClient.Connect().ConfigureAwait(false);

                    logger.LogInformation("Client successfully connected to silo host");
                    break;
                }
                catch (OrleansException)
                {
                    attempt++;
                    logger.LogWarning($"Attempt {attempt} of {initializeAttemptsBeforeFailing} failed to initialize the Orleans client.");

                    if (clusterClient != null)
                    {
                        clusterClient.Dispose();
                        clusterClient = null;
                    }

                    if (attempt > initializeAttemptsBeforeFailing)
                    {
                        throw;
                    }

                    // Wait 4 seconds before retrying
                    await Task.Delay(TimeSpan.FromSeconds(4));
                }
            }

            var endpoints = config.GetSection("Http:Endpoints")
                            .GetChildren()
                            .ToDictionary(section => section.Key, section =>
            {
                var endpoint = new EndpointConfiguration();
                section.Bind(endpoint);
                return(endpoint);
            });

            // if so, start a listener to respond to Acme (Let's Encrypt) requests, using a response received via an Orleans Cache Grain
            var hasHttps   = endpoints.Any(endpoint => endpoint.Value.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase));
            var needPort80 = endpoints.Any(endpoint => (endpoint.Value.Port ?? (endpoint.Value.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase) ? 443 : 80)) == 80);
            var certs      = new Dictionary <string, X509Certificate2>();

            var acmeOptions = new AcmeOptions
            {
                AcmeSettings         = config.GetSection(nameof(AcmeSettings)).Get <AcmeSettings>(),
                GetChallengeResponse = async(challenge) =>
                {
                    var cacheGrain = clusterClient.GetGrain <ICacheGrain <string> >(challenge);
                    var response   = await cacheGrain.Get();

                    return(response.Value);
                },
                SetChallengeResponse = async(challenge, response) =>
                {
                    var cacheGrain = clusterClient.GetGrain <ICacheGrain <string> >(challenge);
                    await cacheGrain.Set(new Immutable <string>(response), TimeSpan.FromHours(2));
                },
                StoreCertificate = async(string domainName, byte[] certData) =>
                {
                    var certGrain = clusterClient.GetGrain <ICertGrain>(domainName);
                    await certGrain.UpdateCertificate(certData);
                },
                RetrieveCertificate = async(domainName) =>
                {
                    var certGrain = clusterClient.GetGrain <ICertGrain>(domainName);
                    var certData  = await certGrain.GetCertificate();

                    return(certData.Value);
                }
            };

            if (hasHttps)
            {
                logger.LogWarning($"At least one https endpoint is present. Initialize Acme endpoint.");

                var acmeHost = new WebHostBuilder()
                               .UseEnvironment(environment)
                               .UseConfiguration(config)
                               .ConfigureServices(services =>
                {
                    services.AddSingleton <IClusterClient>(clusterClient);
                    services.AddSingleton <ILoggerFactory>(loggerFactory);
                    services.Configure <AcmeSettings>(config.GetSection(nameof(AcmeSettings)));

                    // Register a certitificate manager, supplying methods to store and retreive certificates and acme challenge responses
                    services.AddAcmeCertificateManager(acmeOptions);
                })
                               // .UseUrls("http://*:80")
                               .PreferHostingUrls(false)
                               .UseKestrel(options => {
                    options.Listen(IPAddress.Any, 80);
                })
                               .Configure(app =>
                {
                    app.UseAcmeResponse();
                })
                               .Build();

                try
                {
                    await acmeHost.StartAsync().ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    logger.LogError("Error: can't start web listener for acme certificate renewal, probably the web address is in use by another process. Exception message is: " + e.Message);
                    logger.LogError("Ignoring noncritical error (stop W3SVC or Skype to fix this), continuing...");
                }

                var certificateManager = acmeHost.Services.GetRequiredService <ICertificateManager>();
                // var certificateManager = new AcmeCertificateManager(Options.Create(acmeOptions));
                foreach (var endpoint in endpoints)
                {
                    var  endpointConfig  = endpoint.Value;
                    bool isHttpsEndpoint = endpointConfig.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase);
                    var  port            = endpointConfig.Port ?? (isHttpsEndpoint ? 443 : 80);

                    X509Certificate2 certificate = null;
                    if (isHttpsEndpoint)
                    {
                        try
                        {
                            var domains = new List <string> {
                                endpointConfig.Domain
                            }
                            .Concat(endpointConfig.Domains)
                            .Where(ep => !string.IsNullOrEmpty(ep))
                            .Distinct()
                            .ToArray();

                            logger.LogInformation($"Getting certificate for domain {domains.First()} on port {port}");

                            // Request a new certificate with Let's Encrypt and store it for next time
                            try
                            {
                                certificate = await certificateManager.GetCertificate(domains);
                            }
                            catch (Exception e)
                            {
                                logger.LogCritical(e, $"Exception getting certificate for domain {domains.First()}. PfxPassword configured incorrectly?");
                            }
                            if (certificate == null)
                            {
                                // It didn't work - create a temporary certificate so that we can still start with an untrusted certificate
                                logger.LogCritical($"Error getting certificate for domain {domains.First()} (endpoint '{endpoint.Key}'). Creating self-signed temporary certificate...");
                                certificate = CertHelper.BuildTlsSelfSignedServer(domains);
                            }
                            certs.Add(domains.First(), certificate);
                            logger.LogInformation($"Certificate for domain {domains.First()}: {certificate != null}");
                        }
                        catch (Exception e)
                        {
                            logger.LogCritical($"Kestrel startup: Exception getting certificate. {e.Message}");
                        }
                    }
                }
                if (needPort80)
                {
                    await acmeHost.StopAsync();
                }
            }

            var webHost = new WebHostBuilder()
                          .UseEnvironment(environment)
                          .UseConfiguration(config)
                          .ConfigureServices(services =>
            {
                // services.AddSingleton<IConfiguration>(config);
                services.AddSingleton <IClusterClient>(clusterClient);
                services.AddSingleton <ILoggerFactory>(loggerFactory);
                services.Configure <AcmeSettings>(config.GetSection(nameof(AcmeSettings)));
                services.AddAcmeCertificateManager(acmeOptions);
            })
                          .UseContentRoot(Directory.GetCurrentDirectory())
                          // .UseUrls(listenUrls.ToArray())
                          .PreferHostingUrls(false)
                          .Configure(app =>
            {
                app.UseAcmeResponse();
            })
                          .UseStartup <Startup>()
                          .UseKestrel(options =>
            {
                foreach (var endpoint in endpoints)
                {
                    var endpointConfig   = endpoint.Value;
                    bool isHttpsEndpoint = endpointConfig.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase);
                    var port             = endpointConfig.Port ?? (isHttpsEndpoint ? 443 : 80);

                    var ipAddresses = new List <IPAddress>();
                    var hosts       = new List <string> {
                        endpointConfig.Host
                    }
                    .Concat(endpointConfig.Hosts)
                    .Where(ep => !string.IsNullOrEmpty(ep))
                    .Distinct();

                    foreach (var host in hosts)
                    {
                        if (host == "localhost")
                        {
                            ipAddresses.Add(IPAddress.IPv6Loopback);
                            ipAddresses.Add(IPAddress.Loopback);
                        }
                        else if (IPAddress.TryParse(host, out var address))
                        {
                            ipAddresses.Add(address);
                        }
                        else
                        {
                            logger.LogError($"Error parsing endpoint host: {host}");
                        }
                    }

                    foreach (var address in ipAddresses)
                    {
                        options.Listen(address, port, listenOptions =>
                        {
                            if (isHttpsEndpoint)
                            {
                                var domains = new List <string> {
                                    endpointConfig.Domain
                                }
                                .Concat(endpointConfig.Domains)
                                .Where(ep => !string.IsNullOrEmpty(ep))
                                .Distinct()
                                .ToArray();

                                if (certs.TryGetValue(domains.First(), out var certificate))
                                {
                                    logger.LogInformation($"Kestrel config: Listen on address {address.ToString()}:{port}, certificate {(certificate == null ? "NULL" : certificate.Subject.ToString())}");
                                    listenOptions.UseHttps(certificate);
                                    listenOptions.NoDelay = false;
                                    // listenOptions.UseConnectionLogging();
                                }
                                else
                                {
                                    logger.LogError($"No certificate for domain: {domains.First()}");
                                }
                            }
                        });
                    }
                }
            })
                          .Build();

            await webHost.RunAsync();
        }
Example #7
0
        public static void Main(string[] args)
        {
            string environment   = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development";
            bool   isDevelopment = "Development".Equals(environment, StringComparison.OrdinalIgnoreCase);

            var builder = new ConfigurationBuilder()
                          .SetBasePath(Directory.GetCurrentDirectory())
                          .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                          .AddJsonFile($"appsettings.{environment}.json", optional: true)
                          .AddEnvironmentVariables();

            if (builder.GetFileProvider().GetFileInfo("Webapp.csproj").Exists)
            {
                builder.AddUserSecrets <Program>();
            }

            Configuration = builder.Build();

            // Initialize the connection to the OrleansHost process
            var orleansClientConfig = ClientConfiguration.LocalhostSilo();

            orleansClientConfig.DeploymentId         = Configuration["DeploymentId"];
            orleansClientConfig.DataConnectionString = Configuration.GetConnectionString("DataConnectionString");
            orleansClientConfig.AddSimpleMessageStreamProvider("Default");
            orleansClientConfig.DefaultTraceLevel = Severity.Warning;
            orleansClientConfig.TraceFileName     = "";

            IClusterClient orleansClient;

            do
            {
                orleansClient = new ClientBuilder().UseConfiguration(orleansClientConfig).Build();
                try
                {
                    orleansClient.Connect().Wait();
                    // GrainClient.Initialize(orleansClientConfig);
                }
                catch (Exception ex) when(ex is OrleansException || ex is SiloUnavailableException || (ex is AggregateException && ex.InnerException is SiloUnavailableException))
                {
                    orleansClient.Dispose();
                    // Wait for the Host to start
                    Thread.Sleep(3000);
                }
            }while (!orleansClient.IsInitialized);

            // we use a single settings file, that also contains the hosting settings
            var urls = (Configuration[WebHostDefaults.ServerUrlsKey] ?? "http://localhost:5000")
                       .Split(new[] { ',', ';' })
                       .Select(url => url.Trim())
                       .ToArray();

            // find out if we run any secure urls
            var secureUrls = urls
                             .Distinct()
                             .Select(url => new Uri(url))
                             .Where(uri => uri.Scheme == "https")
                             .ToArray();


            // It is possible to request Acme certificates with subject alternative names, but this is not yet implemented.
            // Usually we'll need only a single address, so I'm taking the first one
            // string firstSecureHost = secureUrls.Any() ? secureUrls.First().Host : null;
            var listenUrls = urls
                             .Distinct()
                             .Where(url => url.StartsWith("http://"));

            // if so, start a listener to respond to Acme (Let's Encrypt) requests, using a response received via an Orleans Cache Grain
            string[]    httpsDomains;
            IWebHost    acmeHost;
            AcmeOptions acmeOptions;

            if (!secureUrls.Any())
            {
                httpsDomains = new string[] { };
                acmeOptions  = null;
                acmeHost     = null;
            }
            else
            {
                // Kestrel can only listen once to any given port, so we make sure multiple https addresses get only one listener
                var httpsListen = secureUrls.GroupBy(url => url.Port).Select(url => url.First()).Select(url => "https://*:" + url.Port);
                listenUrls   = listenUrls.Union(httpsListen);
                httpsDomains = secureUrls.Select(url => url.Host).Distinct().ToArray();

                acmeOptions = new AcmeOptions
                {
                    DomainNames          = httpsDomains,
                    GetChallengeResponse = async(challenge) =>
                    {
                        var cacheGrain = orleansClient.GetGrain <ICacheGrain <string> >(challenge);
                        var response   = await cacheGrain.Get();

                        return(response.Value);
                    },
                    SetChallengeResponse = async(challenge, response) =>
                    {
                        var cacheGrain = orleansClient.GetGrain <ICacheGrain <string> >(challenge);
                        await cacheGrain.Set(new Immutable <string>(response), TimeSpan.FromHours(2));
                    },
                    StoreCertificate = async(string domainName, byte[] certData) =>
                    {
                        var certGrain = orleansClient.GetGrain <ICertGrain>(domainName);
                        await certGrain.UpdateCertificate(certData);
                    },
                    RetrieveCertificate = async(domainName) =>
                    {
                        var certGrain = orleansClient.GetGrain <ICertGrain>(domainName);
                        var certData  = await certGrain.GetCertificate();

                        return(certData.Value);
                    }
                };

                acmeHost = new WebHostBuilder()
                           .UseConfiguration(Configuration)
                           .ConfigureLogging((context, factory) =>
                {
                    factory.AddConfiguration(context.Configuration.GetSection("Logging"));
                    factory.AddConsole();
                    factory.AddDebug();
                })
                           .UseEnvironment(environment)
                           .ConfigureServices(services => {
                    services.AddSingleton <IClusterClient>(orleansClient);
                    services.Configure <AcmeSettings>(Configuration.GetSection(nameof(AcmeSettings)));

                    // Register a certitificate manager, supplying methods to store and retreive certificates and acme challenge responses
                    services.AddAcmeCertificateManager(acmeOptions);
                })
                           .UseUrls("http://*:80/.well-known/acme-challenge/")
                           .UseKestrel()
                           // .UseLoggerFactory(loggerFactory)
                           .Configure(app => {
                    app.UseAcmeResponse();
                })
                           .Build();


                try
                {
                    acmeHost.Start();
                }
                catch (Exception e)
                {
                    var logger = acmeHost.Services.GetService <ILogger <Program> >();
                    // var logger = loggerFactory.CreateLogger<Program>();
                    logger.LogError("Error: can't start web listener for acme certificate renewal, probably the web address is in use by another process. Exception message is: " + e.Message);
                    logger.LogError("Ignoring noncritical error (stop W3SVC or Skype to fix this), continuing...");
                }
            }

            var host = new WebHostBuilder()
                       .UseConfiguration(Configuration)
                       .ConfigureLogging((context, factory) =>
            {
                factory.AddConfiguration(context.Configuration.GetSection("Logging"));
                factory.AddConsole();
                factory.AddDebug();
            })
                       .ConfigureServices(services => {
                services.AddSingleton <IClusterClient>(orleansClient);
                if (secureUrls.Any())
                {
                    services.AddAcmeCertificateManager(acmeOptions);
                }
            })
                       .UseContentRoot(Directory.GetCurrentDirectory())
                       .UseEnvironment(environment)
                       .UseUrls(listenUrls.ToArray())
                       .UseSetting("baseUrl", urls.First())
                       .UseStartup <Startup>()
                       .UseKestrel(async options =>
            {
                // TODO: Make this into a nice Kestrel.Https.Acme nuget package
                if (secureUrls.Any())
                {
                    // Request a new certificate with Let's Encrypt and store it for next time
                    var certificateManager = options.ApplicationServices.GetService <ICertificateManager>();
                    var certificate        = await certificateManager.GetCertificate(httpsDomains);
                    if (certificate != null)
                    {
                        options.Listen(IPAddress.Loopback, 443, listenOptions =>
                        {
                            listenOptions.UseHttps(certificate);
                        });
                    }
                }
            })
                       .Build();

            host.Run();
        }