Exemplo n.º 1
0
        public async Task <IActionResult> MarkStart([Required] string service, [Required] string id)
        {
            _logger.LogInformation("Recording start of deployment of '{service}' with id '{id}'", service, id);
            NewGrafanaAnnotationRequest content = new NewGrafanaAnnotationRequest
            {
                Text = $"Deployment of {service}",
                Tags = new[] { "deploy", $"deploy-{service}", service },
                Time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
            };

            NewGrafanaAnnotationResponse annotation;

            using (var client = new HttpClient(new HttpClientHandler()
            {
                CheckCertificateRevocationList = true
            }))
            {
                annotation = await _retry.RetryAsync(async() =>
                {
                    GrafanaOptions grafanaOptions = _grafanaOptions.CurrentValue;
                    _logger.LogInformation("Creating annotation to {url}", grafanaOptions.BaseUrl);
                    using (var request = new HttpRequestMessage(HttpMethod.Post,
                                                                $"{grafanaOptions.BaseUrl}/api/annotations"))
                    {
                        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                        request.Headers.Authorization =
                            new AuthenticationHeaderValue("Bearer", grafanaOptions.ApiToken);
                        request.Content = CreateObjectContent(content);

                        using (HttpResponseMessage response = await client.SendAsync(request, CancellationToken.None))
                        {
                            _logger.LogTrace("Response from grafana {responseCode} {reason}", response.StatusCode, response.ReasonPhrase);
                            response.EnsureSuccessStatusCode();
                            return(await ReadObjectContent <NewGrafanaAnnotationResponse>(response.Content));
                        }
                    }
                },
                                                     e => _logger.LogWarning(e, "Failed to send new annotation"),
                                                     e => true
                                                     );
            }
            _logger.LogInformation("Created annotation {annotationId}, inserting into table", annotation.Id);

            CloudTable table = await GetCloudTable();

            await table.ExecuteAsync(
                TableOperation.InsertOrReplace(
                    new AnnotationEntity(service, id, annotation.Id)
            {
                ETag = "*"
            }
                    )
                );

            return(NoContent());
        }
        public async Task <string> GetTokenForInstallation(long installationId)
        {
            if (TryGetCachedToken(installationId, out AccessToken cachedToken))
            {
                _logger.LogInformation($"Cached token obtained for GitHub installation {installationId}. Expires at {cachedToken.ExpiresAt}.");
                return(cachedToken.Token);
            }

            return(await ExponentialRetry.RetryAsync(
                       async() =>
            {
                string jwt = GetAppToken();
                var product = new ProductHeaderValue(Options.ApplicationName, Options.ApplicationVersion);
                var appClient = new Octokit.GitHubClient(product)
                {
                    Credentials = new Credentials(jwt, AuthenticationType.Bearer)
                };
                AccessToken token = await appClient.GitHubApps.CreateInstallationToken(installationId);
                _logger.LogInformation($"New token obtained for GitHub installation {installationId}. Expires at {token.ExpiresAt}.");
                UpdateTokenCache(installationId, token);
                return token.Token;
            },
                       ex => _logger.LogError(ex, $"Failed to get a github token for installation id {installationId}, retrying"),
                       ex => ex is ApiException && ((ApiException)ex).StatusCode == HttpStatusCode.InternalServerError));
        }
        public async Task UpdateStatusAsync(string serviceName, string instance, string subStatusName, HealthStatus status, string message)
        {
            if (!TryGetUrlParts(out string baseUrl, out string sasQuery))
            {
                return;
            }

            string partitionKey = EscapeKeyField(serviceName);
            string rowKey       = GetRowKey(instance, subStatusName);

            async Task Attempt()
            {
                HttpContent content = new ByteArrayContent(JsonSerializer.SerializeToUtf8Bytes(
                                                               new Entity {
                    Status = status, Message = message
                },
                                                               s_jsonSerializerOptions
                                                               ));

                content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");

                string requestUri =
                    $"{baseUrl}(PartitionKey='{Uri.EscapeDataString(partitionKey)}',RowKey='{Uri.EscapeDataString(rowKey)}'){sasQuery}";

                using HttpResponseMessage response = await _client.PutAsync(requestUri, content).ConfigureAwait(false);

                response.EnsureSuccessStatusCode();
            }

            try
            {
                await _retry.RetryAsync(
                    Attempt,
                    e => _logger.LogWarning("Failed to update status for {service}/{subStatus}, retrying",
                                            serviceName,
                                            subStatusName),
                    e => true
                    ).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                // Crashing out a service trying to report health isn't useful, log that we failed and move on
                _logger.LogError(e, "Unable to update health status for {service}/{subStatus}", serviceName, subStatusName);
            }
        }
Exemplo n.º 4
0
        public async Task <IActionResult> MarkEnd([Required] string service, [Required] string id)
        {
            _logger.LogInformation("Recording end of deployment of '{service}' with id '{id}'", service, id);
            CloudTable table = await GetCloudTable();

            _logger.LogInformation("Looking for existing deployment");
            var tableResult = await table.ExecuteAsync(TableOperation.Retrieve <AnnotationEntity>(service, id));

            _logger.LogTrace("Table response code {responseCode}", tableResult.HttpStatusCode);
            if (!(tableResult.Result is AnnotationEntity annotation))
            {
                return(NotFound());
            }

            _logger.LogTrace("Updating end time of deployment...");
            annotation.Ended = DateTimeOffset.UtcNow;
            tableResult      = await table.ExecuteAsync(TableOperation.Replace(annotation));

            _logger.LogInformation("Update response code {responseCode}", tableResult.HttpStatusCode);

            var content = new NewGrafanaAnnotationRequest
            {
                TimeEnd = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
            };

            using (var client = new HttpClient())
            {
                await ExponentialRetry.RetryAsync(async() =>
                {
                    GrafanaOptions grafanaOptions = _grafanaOptions.CurrentValue;
                    _logger.LogInformation("Updating annotation {annotationId} to {url}", annotation.GrafanaAnnotationId, grafanaOptions.BaseUrl);
                    using (var request = new HttpRequestMessage(HttpMethod.Patch,
                                                                $"{grafanaOptions.BaseUrl}/api/annotations/{annotation.GrafanaAnnotationId}"))
                    {
                        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                        request.Headers.Authorization =
                            new AuthenticationHeaderValue("Bearer", grafanaOptions.ApiToken);
                        request.Content =
                            new ObjectContent <NewGrafanaAnnotationRequest>(content, s_grafanaFormatter);
                        using (HttpResponseMessage response = await client.SendAsync(request, CancellationToken.None))
                        {
                            _logger.LogTrace("Response from grafana {responseCode} {reason}", response.StatusCode, response.ReasonPhrase);
                            response.EnsureSuccessStatusCode();
                        }
                    }
                },
                                                  e => _logger.LogWarning(e, "Failed to send new annotation"),
                                                  e => true
                                                  );
            }

            return(NoContent());
        }
Exemplo n.º 5
0
        public async Task <IRemote> GetRemoteAsync(string repoUrl, ILogger logger)
        {
            using (logger.BeginScope($"Getting remote for repo {repoUrl}."))
            {
                // Normalize the url with the AzDO client prior to attempting to
                // get a token. When we do coherency updates we build a repo graph and
                // may end up traversing links to classic azdo uris.
                string normalizedUrl     = AzureDevOpsClient.NormalizeUrl(repoUrl);
                Uri    normalizedRepoUri = new Uri(normalizedUrl);
                // Look up the setting for where the repo root should be held.  Default to empty,
                // which will use the temp directory.
                string temporaryRepositoryRoot = Configuration.GetValue <string>("DarcTemporaryRepoRoot", null);
                if (string.IsNullOrEmpty(temporaryRepositoryRoot))
                {
                    temporaryRepositoryRoot = _tempFiles.GetFilePath("repos");
                }
                IGitRepo gitClient;

                long installationId = await Context.GetInstallationId(normalizedUrl);

                await ExponentialRetry.RetryAsync(
                    async() => await EnsureLocalGit(logger),
                    ex => logger.LogError(ex, $"Failed to install git to local temporary directory."),
                    ex => true);

                switch (normalizedRepoUri.Host)
                {
                case "github.com":
                    if (installationId == default)
                    {
                        throw new GithubApplicationInstallationException($"No installation is avaliable for repository '{normalizedUrl}'");
                    }

                    gitClient = new GitHubClient(_gitExecutable, await GitHubTokenProvider.GetTokenForInstallationAsync(installationId),
                                                 logger, temporaryRepositoryRoot, Cache.Cache);
                    break;

                case "dev.azure.com":
                    gitClient = new AzureDevOpsClient(_gitExecutable, await AzureDevOpsTokenProvider.GetTokenForRepository(normalizedUrl),
                                                      logger, temporaryRepositoryRoot);
                    break;

                default:
                    throw new NotImplementedException($"Unknown repo url type {normalizedUrl}");
                }
                ;

                return(new Remote(gitClient, new MaestroBarClient(Context), logger));
            }
        }
 public async Task <string> GetTokenForInstallation(long installationId)
 {
     return(await ExponentialRetry.RetryAsync(
                async() =>
     {
         string jwt = GetAppToken();
         var product = new ProductHeaderValue(Options.ApplicationName, Options.ApplicationVersion);
         var appClient = new Octokit.GitHubClient(product)
         {
             Credentials = new Credentials(jwt, AuthenticationType.Bearer)
         };
         AccessToken token = await appClient.GitHubApps.CreateInstallationToken(installationId);
         return token.Token;
     },
                ex => _logger.LogError(ex, $"Failed to get a github token for installation id {installationId}, retrying"),
                ex => ex is ApiException && ((ApiException)ex).StatusCode == HttpStatusCode.InternalServerError));
 }