Example #1
0
        /// <summary>
        /// Removes a Docker volume.
        /// </summary>
        /// <param name="nameOrId">The volume name or ID.</param>
        /// <param name="cancellationToken">Optional cancellation token.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        public async Task VolumeRemove(string nameOrId, CancellationToken cancellationToken = default)
        {
            await SyncContext.ClearAsync;

            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(nameOrId), nameof(nameOrId));

            await JsonClient.DeleteAsync(GetUri("volumes", nameOrId), cancellationToken : cancellationToken);
        }
        public async Task DeletetAsync()
        {
            // Ensure that DELETE returning an explict type works.

            using (new MockHttpServer(baseUri,
                                      async context =>
            {
                var request = context.Request;
                var response = context.Response;

                if (request.Method != "DELETE")
                {
                    response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                    return;
                }

                if (request.Path.ToString() != "/info")
                {
                    response.StatusCode = (int)HttpStatusCode.NotFound;
                    return;
                }

                var output = new ReplyDoc()
                {
                    Value1 = "Hello World!"
                };

                response.ContentType = "application/json";

                await response.WriteAsync(NeonHelper.JsonSerialize(output));
            }))
            {
                using (var jsonClient = new JsonClient())
                {
                    var reply = (await jsonClient.DeleteAsync(baseUri + "info")).As <ReplyDoc>();

                    Assert.Equal("Hello World!", reply.Value1);

                    reply = await jsonClient.DeleteAsync <ReplyDoc>(baseUri + "info");

                    Assert.Equal("Hello World!", reply.Value1);
                }
            }
        }
        public async Task DeleteAsync_Headers()
        {
            // Ensure that DELETE with headers work.

            using (new MockHttpServer(baseUri,
                                      async context =>
            {
                var request = context.Request;
                var response = context.Response;

                if (request.Method != "DELETE")
                {
                    response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                    return;
                }

                if (request.Path.ToString() != "/info")
                {
                    response.StatusCode = (int)HttpStatusCode.NotFound;
                    return;
                }

                var output = new ReplyDoc()
                {
                    Value1 = request.Headers["arg1"],
                    Value2 = request.Headers["arg2"]
                };

                response.ContentType = "application/json";

                await response.WriteAsync(NeonHelper.JsonSerialize(output));
            }))
            {
                using (var jsonClient = new JsonClient())
                {
                    var headers = new ArgDictionary()
                    {
                        { "arg1", "test1" },
                        { "arg2", "test2" }
                    };

                    var reply = (await jsonClient.DeleteAsync(baseUri + "info", headers: headers)).As <ReplyDoc>();

                    Assert.Equal("test1", reply.Value1);
                    Assert.Equal("test2", reply.Value2);
                }
            }
        }
Example #4
0
        public async Task DeleteAsync_Error()
        {
            // Ensure that DELETE returning a hard error works.

            using (new MockHttpServer(baseUri,
                                      context =>
            {
                var response = context.Response;

                response.StatusCode = (int)HttpStatusCode.NotFound;
            }))
            {
                using (var jsonClient = new JsonClient())
                {
                    await Assert.ThrowsAsync <HttpException>(async() => await jsonClient.DeleteAsync(baseUri + "info"));
                }
            }
        }
Example #5
0
        public async Task DeleteAsync_Args()
        {
            // Ensure that DELETE with query arguments work.

            using (new MockHttpServer(baseUri,
                                      context =>
            {
                var request = context.Request;
                var response = context.Response;

                if (request.Method != "DELETE")
                {
                    response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                    return;
                }

                if (request.Path.ToString() != "/info")
                {
                    response.StatusCode = (int)HttpStatusCode.NotFound;
                    return;
                }

                var output = new ReplyDoc()
                {
                    Value1 = request.QueryGet("arg1"),
                    Value2 = request.QueryGet("arg2")
                };

                response.ContentType = "application/json";

                response.Write(NeonHelper.JsonSerialize(output));
            }))
            {
                using (var jsonClient = new JsonClient())
                {
                    var reply = (await jsonClient.DeleteAsync(baseUri + "info?arg1=test1&arg2=test2")).As <ReplyDoc>();

                    Assert.Equal("test1", reply.Value1);
                    Assert.Equal("test2", reply.Value2);
                }
            }
        }
        public async Task DeleteAsync_Dynamic_NotJson()
        {
            // Ensure that DELETE returning non-JSON returns a NULL dynamic document.

            using (new MockHttpServer(baseUri,
                                      async context =>
            {
                var request = context.Request;
                var response = context.Response;

                if (request.Method != "DELETE")
                {
                    response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                    return;
                }

                if (request.Path.ToString() != "/info")
                {
                    response.StatusCode = (int)HttpStatusCode.NotFound;
                    return;
                }

                var output = new ReplyDoc()
                {
                    Value1 = "Hello World!"
                };

                response.ContentType = "application/not-json";

                await response.WriteAsync(NeonHelper.JsonSerialize(output));
            }))
            {
                using (var jsonClient = new JsonClient())
                {
                    var reply = (await jsonClient.DeleteAsync(baseUri + "info")).AsDynamic();

                    Assert.Null(reply);
                }
            }
        }
        public async Task DeleteAsync_Retry()
        {
            // Ensure that DELETE will retry after soft errors.

            var attemptCount = 0;

            using (new MockHttpServer(baseUri,
                                      async context =>
            {
                var request = context.Request;
                var response = context.Response;

                if (attemptCount++ == 0)
                {
                    response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;

                    return;
                }

                var output = new ReplyDoc()
                {
                    Value1 = "Hello World!"
                };

                response.ContentType = "application/json";

                await response.WriteAsync(NeonHelper.JsonSerialize(output));
            }))
            {
                using (var jsonClient = new JsonClient())
                {
                    var reply = (await jsonClient.DeleteAsync(baseUri + "info")).AsDynamic();

                    Assert.Equal(2, attemptCount);
                    Assert.Equal("Hello World!", (string)reply.Value1);
                }
            }
        }
        public async Task DeleteAsync_NoRetryExplicit()
        {
            // Ensure that DELETE won't retry if [retryPolicy=NoRetryPolicy]

            var attemptCount = 0;

            using (new MockHttpServer(baseUri,
                                      async context =>
            {
                var request = context.Request;
                var response = context.Response;

                if (attemptCount++ == 0)
                {
                    response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;

                    return;
                }

                var output = new ReplyDoc()
                {
                    Value1 = "Hello World!"
                };

                response.ContentType = "application/json";

                await response.WriteAsync(NeonHelper.JsonSerialize(output));
            }))
            {
                using (var jsonClient = new JsonClient())
                {
                    await Assert.ThrowsAsync <HttpException>(async() => await jsonClient.DeleteAsync(NoRetryPolicy.Instance, baseUri + "info"));

                    Assert.Equal(1, attemptCount);
                }
            }
        }
Example #9
0
        /// <summary>
        /// Handles purging of old <b>logstash</b> and <b>metricbeat</b> Elasticsearch indexes.
        /// </summary>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        public async Task LogPurgerAsync(TimeSpan logPurgerInterval, int retentionDays)
        {
            using (var jsonClient = new JsonClient())
            {
                jsonClient.BaseAddress = KubernetesClientConfiguration.IsInCluster()
                    ? this.ServiceMap[NeonServices.Elasticsearch].Endpoints.Default.Uri
                    : new Uri($"http://localhost:{this.ServiceMap[NeonServices.Elasticsearch].Endpoints.Default.Port}");

                var periodicTask =
                    new AsyncPeriodicTask(
                        logPurgerInterval,
                        onTaskAsync:
                        async() =>
                {
                    // We're going to list the indexes and look for [logstash]
                    // and [metricbeat] indexes that encode the index date like:
                    //
                    //      logstash-2018.06.06
                    //      metricbeat-6.1.1-2018.06.06
                    //
                    // The date is simply encodes the day covered by the index.

                    var utcNow           = DateTime.UtcNow;
                    var deleteBeforeDate = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day) - TimeSpan.FromDays(retentionDays);

                    var indexList = await jsonClient.GetAsync <JObject>("_aliases");

                    foreach (var indexProperty in indexList.Properties())
                    {
                        var indexName = indexProperty.Name;

                        // We're only purging [logstash] and [metricbeat] indexes.

                        if (!indexName.StartsWith("logstash-") && !indexName.StartsWith("metricbeat-"))
                        {
                            continue;
                        }


                        // Extract the date from the index name.

                        var pos = indexName.LastIndexOf('-');

                        if (pos == -1)
                        {
                            Log.LogWarn(() => $"LOG-PURGER: Cannot extract date from index named [{indexName}].");
                            continue;
                        }

                        var date      = indexName.Substring(pos + 1);
                        var fields    = date.Split('.');
                        var indexDate = default(DateTime);

                        try
                        {
                            indexDate = new DateTime(int.Parse(fields[0]), int.Parse(fields[1]), int.Parse(fields[2]));
                        }
                        catch
                        {
                            Log.LogWarn(() => $"LOG-PURGER: Cannot extract date from index named [{indexName}].");
                            continue;
                        }

                        if (indexDate < deleteBeforeDate)
                        {
                            Log.LogInfo(() => $"LOG-PURGER: Deleting index [{indexName}].");
                            await jsonClient.DeleteAsync <JObject>(indexName);
                            Log.LogInfo(() => $"LOG-PURGER: [{indexName}] was deleted.");
                        }
                    }

                    Log.LogDebug("LOG-PURGER: Scan finished.");
                    return(await Task.FromResult(false));
                },
                        onExceptionAsync:
                        async e =>
                {
                    Log.LogError("LOG-PURGER", e);
                    return(await Task.FromResult(false));
                },
                        onTerminateAsync:
                        async() =>
                {
                    Log.LogInfo(() => "LOG-PURGER: Terminating");
                    await Task.CompletedTask;
                });

                await periodicTask.Run();
            }
        }
Example #10
0
        /// <summary>
        /// Handles purging of old <b>logstash</b> and <b>metricbeat</b> Elasticsearch indexes.
        /// </summary>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        private static async Task LogPurgerAsync()
        {
            using (var jsonClient = new JsonClient())
            {
                var periodicTask =
                    new AsyncPeriodicTask(
                        logPurgerInterval,
                        onTaskAsync:
                        async() =>
                {
                    if (IsSetupPending)
                    {
                        log.LogInfo(() => "LOG-PURGER: Delaying because hive setup is still in progress.");
                        return(false);
                    }

                    var manager = hive.GetReachableManager();

                    log.LogDebug(() => "LOG-PURGER: Scanning for old Elasticsearch indexes ready for removal.");

                    // We're going to list the indexes and look for [logstash]
                    // and [metricbeat] indexes that encode the index date like:
                    //
                    //      logstash-2018.06.06
                    //      metricbeat-6.1.1-2018.06.06
                    //
                    // The date is simply encodes the day covered by the index.

                    if (!hive.Globals.TryGetInt(HiveGlobals.UserLogRetentionDays, out var retentionDays))
                    {
                        retentionDays = 14;
                    }

                    var utcNow           = DateTime.UtcNow;
                    var deleteBeforeDate = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day) - TimeSpan.FromDays(retentionDays);

                    var indexList = await jsonClient.GetAsync <JObject>($"http://{manager.PrivateAddress}:{HiveHostPorts.ProxyPrivateHttpLogEsData}/_aliases");

                    foreach (var indexProperty in indexList.Properties())
                    {
                        var indexName = indexProperty.Name;

                        // We're only purging [logstash] and [metricbeat] indexes.

                        if (!indexName.StartsWith("logstash-") && !indexName.StartsWith("metricbeat-"))
                        {
                            continue;
                        }

                        // Extract the date from the index name.

                        var pos = indexName.LastIndexOf('-');

                        if (pos == -1)
                        {
                            log.LogWarn(() => $"LOG-PURGER: Cannot extract date from index named [{indexName}].");
                            continue;
                        }

                        var date      = indexName.Substring(pos + 1);
                        var fields    = date.Split('.');
                        var indexDate = default(DateTime);

                        try
                        {
                            indexDate = new DateTime(int.Parse(fields[0]), int.Parse(fields[1]), int.Parse(fields[2]));
                        }
                        catch
                        {
                            log.LogWarn(() => $"LOG-PURGER: Cannot extract date from index named [{indexName}].");
                            continue;
                        }

                        if (indexDate < deleteBeforeDate)
                        {
                            log.LogInfo(() => $"LOG-PURGER: Deleting index [{indexName}].");
                            await jsonClient.DeleteAsync <JObject>($"http://{manager.PrivateAddress}:{HiveHostPorts.ProxyPrivateHttpLogEsData}/{indexName}");
                            log.LogInfo(() => $"LOG-PURGER: [{indexName}] was deleted.");
                        }
                    }

                    log.LogDebug("LOG-PURGER: Scan finished.");
                    return(await Task.FromResult(false));
                },
Example #11
0
        /// <summary>
        /// Removes a Docker network.
        /// </summary>
        /// <param name="nameOrId">The network name or ID.</param>
        /// <param name="cancellationToken">Optional cancellation token.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        public async Task NetworkRemove(string nameOrId, CancellationToken cancellationToken = default)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(nameOrId));

            await JsonClient.DeleteAsync(GetUri("networks", nameOrId), cancellationToken : cancellationToken);
        }