private async Task PostAsync(IMonitoringAccount monitoringAccount, string url) { Validate(monitoringAccount); var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }; var serializedMonitoringAccount = JsonConvert.SerializeObject( monitoringAccount, Formatting.Indented, settings); try { await HttpClientHelper.GetResponse( new Uri(url), HttpMethod.Post, this.httpClient, monitoringAccount.Name, this.operation, serializedContent : serializedMonitoringAccount).ConfigureAwait(false); } catch (MetricsClientException mce) { ThrowSpecificExceptionIfPossible(mce, monitoringAccount.Name); throw; } }
/// <inheritdoc /> public async Task <IReadOnlyList <ConfigurationUpdateResultList> > SyncConfigurationAsync( IMonitoringAccount monitoringAccount, bool skipVersionCheck = false, bool validate = true) { if (monitoringAccount == null) { throw new ArgumentNullException(nameof(monitoringAccount)); } var namespaces = await this.metricReader.GetNamespacesAsync(monitoringAccount.Name).ConfigureAwait(false); List <ConfigurationUpdateResultList> results = new List <ConfigurationUpdateResultList>(); foreach (var ns in namespaces) { var namespaceResults = await this.SyncConfigurationAsync( monitoringAccount, ns, skipVersionCheck, validate).ConfigureAwait(false); // For QOS namespace or other internal namespace, there is no configuration to // replicate and thus the namespace results is an empty list. if (namespaceResults.Count > 0) { results.AddRange(namespaceResults); } } return(results); }
/// <summary> /// Save the monitoring account configuration provided. /// </summary> /// <param name="monitoringAccount">The monitoring account configuration to save.</param> /// <param name="skipVersionCheck">Flag indicating whether or not the version flag should be honored.</param> /// <returns>A task the caller can wait on.</returns> public async Task SaveAsync(IMonitoringAccount monitoringAccount, bool skipVersionCheck = false) { var path = $"{this.monitoringAccountUrlPrefix}/{monitoringAccount.Name}/skipVersionCheck/{skipVersionCheck}"; var uriBuilder = new UriBuilder(this.connectionInfo.GetEndpoint(monitoringAccount.Name)) { Path = path }; var url = uriBuilder.Uri.ToString(); await this.PostAsync(monitoringAccount, url).ConfigureAwait(false); }
/// <inheritdoc /> public async Task <IReadOnlyList <ConfigurationUpdateResultList> > SyncConfigurationAsync( IMonitoringAccount monitoringAccount, string metricNamespace, bool skipVersionCheck = false, bool validate = true) { if (monitoringAccount == null) { throw new ArgumentNullException(nameof(monitoringAccount)); } if (string.IsNullOrEmpty(metricNamespace)) { throw new ArgumentNullException(nameof(metricNamespace)); } var metricNames = await this.metricReader.GetMetricNamesAsync( monitoringAccount.Name, metricNamespace).ConfigureAwait(false); var taskList = new List <Task <ConfigurationUpdateResultList> >(this.MaxParallelRunningTasks); List <ConfigurationUpdateResultList> results = new List <ConfigurationUpdateResultList>(); foreach (var metricName in metricNames) { if (taskList.Count == this.MaxParallelRunningTasks) { await this.WaitForSync(taskList, results).ConfigureAwait(false); taskList.Clear(); } else { taskList.Add(this.SyncConfigurationAsync(monitoringAccount, metricNamespace, metricName, skipVersionCheck, validate)); } } if (taskList.Count > 0) { await this.WaitForSync(taskList, results).ConfigureAwait(false); taskList.Clear(); } return(results); }
/// <summary> /// Validates that the monitoring account provided can be sent to the server to be saved. /// </summary> /// <param name="monitoringAccount">The monitoring account configuration being saved.</param> private static void Validate(IMonitoringAccount monitoringAccount) { if (monitoringAccount == null) { throw new ArgumentNullException(nameof(monitoringAccount)); } if (string.IsNullOrWhiteSpace(monitoringAccount.Name)) { throw new ArgumentException("Monitoring account name cannot be null or empty."); } if (monitoringAccount.Permissions == null || !monitoringAccount.Permissions.Any()) { throw new ArgumentException("One or more permissions must be specified for this account. These can include users, security groups, or certificates."); } }
/// <inheritdoc /> public async Task <IReadOnlyList <ConfigurationUpdateResult> > SyncMonitoringAccountConfigurationAsync( IMonitoringAccount monitoringAccount, bool skipVersionCheck = false) { if (monitoringAccount == null) { throw new ArgumentNullException(nameof(monitoringAccount)); } var mirrorOperation = $"{this.monitoringAccountUrlPrefix}replicateConfigurationToMirrorAccounts"; var path = $"{this.monitoringAccountUrlPrefix}{monitoringAccount.Name}/replicateConfigurationToMirrorAccounts/skipVersionCheck/{skipVersionCheck}"; var uriBuilder = new UriBuilder(this.connectionInfo.GetGlobalEndpoint()) { Path = path }; try { var response = await HttpClientHelper.GetResponse( uriBuilder.Uri, HttpMethod.Post, this.httpClient, monitoringAccount.Name, mirrorOperation).ConfigureAwait(false); return(JsonConvert.DeserializeObject <ConfigurationUpdateResult[]>( response.Item1, this.serializerSettings)); } catch (MetricsClientException mce) { if (mce.ResponseStatusCode == HttpStatusCode.Unauthorized) { var exMsg = $"Unable to sync configuration for monitoring account:{monitoringAccount.Name} as " + $"user doesn't have permission to update configurations. Response:{mce.Message}"; throw new ConfigurationValidationException(exMsg, ValidationType.ServerSide, mce); } throw; } }
/// <summary> /// Creates a monitoring account with provided configuration. /// </summary> /// <param name="monitoringAccount">The monitoring account configuration.</param> /// <param name="stampHostName">The stamp name such as prod3.metrics.nsatc.net as documented @ https://aka.ms/mdm-endpoints.</param> /// <returns>A task the caller can wait on.</returns> public async Task CreateAsync(IMonitoringAccount monitoringAccount, string stampHostName) { if (string.IsNullOrWhiteSpace(stampHostName)) { throw new ArgumentException("value is null or empty", nameof(stampHostName)); } if (this.connectionInfo.Endpoint != null) { throw new ArgumentException("'Endpoint' must not be specified in the constructor for ConnectionInfo to create monitoring accounts."); } // Check if the client has service admin permission in the global stamp; if not, try to create the account in the target stamp directly. var globalStampEndpoint = ConnectionInfo.ResolveGlobalEnvironments()[(int)this.connectionInfo.MdmEnvironment]; bool hasAccountCreationPermissionInGlobalStamp = await this.HasAccountCreationPermission(globalStampEndpoint).ConfigureAwait(false); var endpoint = hasAccountCreationPermissionInGlobalStamp ? globalStampEndpoint : $"https://{stampHostName}/"; var url = $"{endpoint}{this.monitoringAccountUrlPrefix}{monitoringAccount.Name}/stamp/{stampHostName}"; await this.PostAsync(monitoringAccount, url).ConfigureAwait(false); }
/// <inheritdoc /> public async Task <ConfigurationUpdateResultList> SyncConfigurationAsync( IMonitoringAccount monitoringAccount, string metricNamespace, string metricName, bool skipVersionCheck = false, bool validate = true) { if (monitoringAccount == null) { throw new ArgumentNullException(nameof(monitoringAccount)); } if (metricNamespace == null) { throw new ArgumentNullException(nameof(metricNamespace)); } if (metricName == null) { throw new ArgumentNullException(nameof(metricName)); } var operation = $"{this.metricUrlPrefix}/replicateMonitorConfigurations"; var path = $"{operation}/monitoringAccount/{monitoringAccount.Name}/metricNamespace/{metricNamespace}/metricName/{metricName}/skipVersionCheck/{skipVersionCheck}/operation/Replace"; var uriBuilder = new UriBuilder(this.connectionInfo.GetGlobalEndpoint()) { Path = path, Query = $"validate={validate}" }; var result = new ConfigurationUpdateResultList { MonitoringAccount = monitoringAccount.Name, MetricNamespace = metricNamespace, MetricName = metricName }; try { if (monitoringAccount.MirrorMonitoringAccountList == null || !monitoringAccount.MirrorMonitoringAccountList.Any()) { throw new Exception("MirrorAccountsList can't be null or empty while replicating monitors."); } var serializedTargetAccounts = JsonConvert.SerializeObject(monitoringAccount.MirrorMonitoringAccountList.ToList(), Formatting.Indented, this.serializerSettings); var response = await HttpClientHelper.GetResponse( uriBuilder.Uri, HttpMethod.Post, this.httpClient, monitoringAccount.Name, operation, serializedContent : serializedTargetAccounts).ConfigureAwait(false); result.ConfigurationUpdateResults = JsonConvert.DeserializeObject <ConfigurationUpdateResult[]>( response.Item1, this.serializerSettings); foreach (var updateResult in result.ConfigurationUpdateResults) { if (!updateResult.Success) { result.Success = false; result.ExceptionMessage = updateResult.Message; return(result); } } result.Success = true; return(result); } catch (MetricsClientException mce) { result.Success = false; if (mce.ResponseStatusCode == HttpStatusCode.Unauthorized || mce.ResponseStatusCode == HttpStatusCode.Forbidden) { var exMsg = $"Unable to sync configuration for monitoringAccount:{monitoringAccount.Name}, metricNamespace:{metricNamespace}, metricName:{metricName}" + $"doesn't have permission to update configurations in mirror accounts. Response:{mce.Message}"; throw new ConfigurationValidationException(exMsg, ValidationType.ServerSide, mce); } result.ExceptionMessage = mce.Message; return(result); } }