private async Task <R> HttpPost <R, T>(string path, T content = default(T), string queryString = "", string apiVersion = GeoMasterConstants.August2016Version, CancellationToken cancellationToken = default(CancellationToken)) { var query = SitePathUtility.CsmAnnotateQueryString(queryString, apiVersion); var response = new HttpResponseMessage(); try { var uri = path + query; var body = JsonConvert.SerializeObject(content); response = await _geoMasterClient.Client.PostAsync(uri, new StringContent(body, Encoding.UTF8, "application/json"), cancellationToken); response.EnsureSuccessStatusCode(); } catch (TaskCanceledException) { if (cancellationToken != default(CancellationToken)) { throw new DataSourceCancelledException(); } //if any task cancelled without provided cancellation token - we want capture exception in datasourcemanager throw; } if (typeof(R) == typeof(string)) { return((await response.Content.ReadAsStringAsync()).CastTo <R>()); } string responseContent = await response.Content.ReadAsStringAsync(); R value = JsonConvert.DeserializeObject <R>(responseContent); return(value); }
/// <summary> /// Gets the container logs for a site as a string /// </summary> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">Name of the resource</param> /// <param name="slotName">slot name (if querying for a slot, defaults to production slot)</param> /// /// <example> /// The below example shows how you call <see cref="GetLinuxContainerLogs"/> to get container logs for this app. /// <code> /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// var subId = cxt.Resource.SubscriptionId; /// var rg = cxt.Resource.ResourceGroup; /// var name = cxt.Resource.Name; /// var slot = cxt.Resource.Slot; /// /// string containerLogs = await dp.GeoMaster.GetLinuxContainerLogs(subId, rg, name,slot); /// /// // do any processing on the string variable containerLogs /// } /// </code> /// </example> /// <returns></returns> public async Task <string> GetLinuxContainerLogs(string subscriptionId, string resourceGroupName, string name, string slotName) { string path = $"{SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name, slotName)}/containerlogs"; var geoMasterResponse = await HttpPost <string, string>(path); return(geoMasterResponse); }
private async Task <R> PerformHttpRequest <R>(HttpMethod method, string path, string queryString, string content, string apiVersion, CancellationToken cancellationToken) { var query = SitePathUtility.CsmAnnotateQueryString(queryString, apiVersion); var uri = new Uri(_geoMasterClient.BaseUri, path + query); HttpResponseMessage response = null; try { using (var request = new HttpRequestMessage(method, uri)) { try { if (method == HttpMethod.Post || method == HttpMethod.Put) { request.Content = new StringContent(content, Encoding.UTF8, "application/json"); } var token = _geoMasterClient.AuthenticationToken; if (!string.IsNullOrWhiteSpace(token)) { request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); } response = await _geoMasterClient.Client.SendAsync(request, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); } catch (TaskCanceledException) { if (cancellationToken != default(CancellationToken)) { throw new DataSourceCancelledException(); } //if any task cancelled without provided cancellation token - we want capture exception in datasourcemanager throw; } } R value; if (typeof(R) == typeof(string)) { value = (await response.Content.ReadAsStringAsync().ConfigureAwait(false)).CastTo <R>(); } else { string responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); value = JsonConvert.DeserializeObject <R>(responseContent); } return(value); } finally { if (response != null) { response.Dispose(); } } }
/// <summary> /// Using this method you can invoke any API on a SiteExtension that is installed on the Web App /// </summary> /// <typeparam name="T"></typeparam> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">The resource name</param> /// <param name="slotName">slot name (if querying for a slot, defaults to production slot)</param> /// <param name="extension">Full path to the SiteExtension and any api under that extension</param> /// <param name="apiVersion">(Optional Parameter) Pass an API version if required, 2016-08-01 is the default value</param> /// <param name="cancellationToken">(Optional Parameter) Cancellation token </param> /// <example> /// This sample shows how to call the <see cref="InvokeSiteExtension"/> method in a detector /// <code> /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// var resp = await dp.GeoMaster.InvokeSiteExtension<![CDATA[<dynamic>]]>(cxt.Resource.SubscriptionId, /// cxt.Resource.ResourceGroup, /// cxt.Resource.Name, /// "loganalyzer/log/eventlogs"); /// /// // do something with the response object /// var responseFromSiteExtension = resp.ToString(); /// return res; /// } /// </code> /// </example> /// <returns></returns> private Task <T> InvokeSiteExtension <T>(string subscriptionId, string resourceGroupName, string name, string slotName, string extension, string apiVersion = GeoMasterConstants.August2016Version, CancellationToken cancellationToken = default(CancellationToken)) { if (string.IsNullOrWhiteSpace(extension)) { throw new ArgumentNullException(nameof(extension)); } string path = SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name, slotName) + SiteExtensionResource.Replace("{*extensionApiMethod}", extension, StringComparison.CurrentCultureIgnoreCase); return(HttpGet <T>(path, string.Empty, apiVersion, cancellationToken)); }
/// <summary> /// Using this method you can invoke any API on a SiteExtension that is installed on the Web App /// </summary> /// <typeparam name="T"></typeparam> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">The resource name</param> /// <param name="slotName">slot name (if querying for a slot, defaults to production slot)</param> /// <param name="extension">Full path to the SiteExtension and any api under that extension</param> /// <param name="apiVersion">(Optional Parameter) Pass an API version if required, 2016-08-01 is the default value</param> /// <param name="cancellationToken">(Optional Parameter) Cancellation token </param> /// <example> /// This sample shows how to call the <see cref="InvokeSiteExtension"/> method in a detector /// <code> /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// var resp = await dp.GeoMaster.InvokeSiteExtension<![CDATA[<dynamic>]]>(cxt.Resource.SubscriptionId, /// cxt.Resource.ResourceGroup, /// cxt.Resource.Name, /// "loganalyzer/log/eventlogs"); /// /// // do something with the response object /// var responseFromSiteExtension = resp.ToString(); /// return res; /// } /// </code> /// </example> /// <returns></returns> private async Task <T> InvokeSiteExtension <T>(string subscriptionId, string resourceGroupName, string name, string slotName, string extension, string apiVersion = GeoMasterConstants.August2016Version, CancellationToken cancellationToken = default(CancellationToken)) { if (string.IsNullOrWhiteSpace(extension)) { throw new ArgumentNullException("extension"); } string path = SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name, slotName) + SiteExtensionResource.Replace("{*extensionApiMethod}", extension); var result = await HttpGet <T>(path, string.Empty, apiVersion, cancellationToken); return(result); }
/// <summary> /// Gets a dictionary of all the deployments that were triggered for this Web App. The key of this dictionary /// is the DeploymentId /// </summary> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">Name of the resource</param> /// <param name="slotName">slot name (if querying for a slot, defaults to production slot)</param> /// <returns></returns> /// <example> /// The below example shows how you call <see cref="GetAppDeployments"/> to find out details about the deployments that were triggered for this App. /// <code> /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// var subId = cxt.Resource.SubscriptionId; /// var rg = cxt.Resource.ResourceGroup; /// var name = cxt.Resource.Name; /// var slot = cxt.Resource.Slot; /// /// var deployments = await dp.GeoMaster.GetAppDeployments(subId, rg, name, slot); /// foreach(var deployment in deployments) /// { /// string deploymentId = deployment["id"].ToString(); /// var message = "DeploymentId = " + deploymentId; /// /// // get a specific property like this (Hint - View all properties /// // at https://resources.azure.com) /// string deployer = deployment["deployer"].ToString(); /// /// // or just loop through all the keys /// foreach(string key in deployment.Keys) /// { /// var deploymentinfo = $" {key} = {deployment[key]}"; /// } /// } /// } /// </code> /// </example> public async Task <List <IDictionary <string, dynamic> > > GetAppDeployments(string subscriptionId, string resourceGroupName, string name, string slotName) { string path = $"{SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name, slotName)}/deployments"; GeoMasterResponseArray geoMasterResponse = null; geoMasterResponse = await HttpGet <GeoMasterResponseArray>(path); var deployments = new List <IDictionary <string, dynamic> > (); foreach (var deployment in geoMasterResponse.Value) { deployments.Add(deployment.Properties); } return(deployments); }
/// <summary> /// All the ARM or GeoMaster operations that are allowed over HTTP GET can be called via this method by passing the path. To get a list of all the HTTP GET based ARM operations, check out a WebApp on https://resources.azure.com . /// <para>It should be noted that the response of the ARM operation is of 3 types:</para> /// <para>1) Response contains a Properties{} object.</para> /// <para>2) Reponse contains a Value[] array which has a properties object.</para> /// <para>3) Response contains a Value[] array that has no properties object. </para> /// /// To invoke the right route, pass the right class to the method call i.e. GeoMasterResponse or GeoMasterResponseArray or GeoMasterResponseDynamicArray /// </summary> /// <typeparam name="T"></typeparam> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">Name of the resource</param> /// <param name="slotName">slot name (if querying for a slot, defaults to production slot)</param> /// <param name="path">The path to the API route (for e.g. usages, recommendations)</param> /// <example> /// The below shows how to make this method call to invoke the different types of operations /// <code> /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// /// var subId = cxt.Resource.SubscriptionId; /// var rg = cxt.Resource.ResourceGroup; /// var name = cxt.Resource.Name; /// var slot = cxt.Resource.Slot; /// /// var resp = await dp.GeoMaster.MakeHttpGetRequest<![CDATA[<GeoMasterResponse>]]>(subId, /// rg, /// name, /// slot, /// "sourcecontrols/web"); /// /// var repoUrl = resp.Properties["repoUrl"]; /// var branch = resp.Properties["branch"]; /// var provisioningState = resp.Properties["provisioningState"]; /// /// var respVal = await dp.GeoMaster.MakeHttpGetRequest<![CDATA[<GeoMasterResponseDynamicArray>]]>(subId, /// rg, /// name, /// "usages"); /// /// foreach(var val in respVal.Value) /// { /// var unit = val.unit; /// var name = val.name.value; /// var localizedValue = val.name.localizedValue; /// var currentValue = val.currentValue; /// } /// /// // To get properties on the site root path, just call the method like this /// var siteProperties = await dp.GeoMaster.MakeHttpGetRequest<![CDATA[<GeoMasterResponse>]]>(subId, /// rg, /// name, /// slot); /// foreach(var item in siteProperties.Properties) /// { /// string str = item.Key + " " + item.Value; /// } /// } /// </code> /// </example> public Task <T> MakeHttpGetRequest <T>(string subscriptionId, string resourceGroupName, string name, string slotName, string path = "") { if (!string.IsNullOrWhiteSpace(path)) { path = path.StartsWith("/") ? path.Substring(1) : path; } if (string.IsNullOrWhiteSpace(path)) { path = $"{SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name)}"; } else { path = $"{SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name)}/{path}"; } return(HttpGet <T>(path)); }
/// <summary> /// Using this method you can invoke an API on the DaaS SiteExtension that is installed on the Web App /// </summary> /// <typeparam name="T"></typeparam> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">The resource name</param> /// <param name="slotName">slot name (if querying for a slot, defaults to production slot)</param> /// <param name="daasApiPath">Full path to the DAAS API </param> /// <param name="apiVersion">(Optional Parameter) Pass an API version if required, 2016-08-01 is the default value</param> /// <param name="cancellationToken">(Optional Parameter) Cancellation token </param> /// <example> /// This sample shows how to call the <see cref="InvokeDaasExtension"/> method in a detector /// <code> /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// var resp = await dp.GeoMaster.InvokeDaasExtension<![CDATA[<dynamic>]]>(cxt.Resource.SubscriptionId, /// cxt.Resource.ResourceGroup, /// cxt.Resource.Name, /// cxt.Resource.Slot, /// "api/diagnosers"); /// /// // do something with the response object /// var responseFromDaaS = resp.ToString(); /// return res; /// } /// </code> /// </example> /// <returns></returns> public Task <T> InvokeDaasExtension <T>(string subscriptionId, string resourceGroupName, string name, string slotName, string daasApiPath, string apiVersion = GeoMasterConstants.August2016Version, CancellationToken cancellationToken = default(CancellationToken)) { if (string.IsNullOrWhiteSpace(daasApiPath)) { throw new ArgumentNullException("daasApiPath"); } if (daasApiPath.StartsWith("api/databasetest", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("Accessing DatabaseTestController under DAAS is not allowed as it contains PII"); } string extensionPath = $"daas/{daasApiPath}"; string path = SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name, slotName) + SiteExtensionResource.Replace("{*extensionApiMethod}", extensionPath); return(HttpGet <T>(path, string.Empty, apiVersion, cancellationToken)); }
/// <summary> /// All the ARM or GeoMaster operations that are allowed over HTTP GET can be called via this method by passing the path. /// To get a list of all the HTTP GET based ARM operations, check out a WebApp on https://resources.azure.com /// It should be noted that the response of the ARM operation is of 3 types /// 1) Response contains a Properties{} object. /// 2) Reponse contains a Value[] array which has a properties object. /// 3) Response contains a Value[] array that has no properties object. /// /// To invoke the right route, pass the right class to the method call i.e. GeoMasterResponse or GeoMasterResponseArray or GeoMasterResponseDynamicArray /// </summary> /// <typeparam name="T"></typeparam> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">Name of the resource</param> /// <param name="path">The path to the API route (for e.g. usages, recommendations)</param> /// <example> /// The below shows how to make this method call to invoke the different types of operations /// <code> /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext cxt, Response res) /// { /// /// var subId = cxt.Resource.SubscriptionId; /// var rg = cxt.Resource.ResourceGroup; /// var name = cxt.Resource.Name; /// /// var resp = await dp.GeoMaster.MakeHttpGetRequest<![CDATA[<GeoMasterResponse>]]>(subId, /// rg, /// name, /// "sourcecontrols/web"); /// /// var repoUrl = resp.Properties["repoUrl"]; /// var branch = resp.Properties["branch"]; /// var provisioningState = resp.Properties["provisioningState"]; /// /// var respVal = await dp.GeoMaster.MakeHttpGetRequest<![CDATA[<GeoMasterResponseDynamicArray>]]>(subId, /// rg, /// name, /// "usages"); /// /// foreach(var val in respVal.Value) /// { /// var unit = val.unit; /// var name = val.name.value; /// var localizedValue = val.name.localizedValue; /// var currentValue = val.currentValue; /// } /// /// // To get properties on the site root path, just call the method like this /// var siteProperties = await dp.GeoMaster.MakeHttpGetRequest<![CDATA[<GeoMasterResponse>]]>(subId, /// rg, /// name); /// foreach(var item in siteProperties.Properties) /// { /// string str = item.Key + " " + item.Value; /// } /// } /// </code> /// </example> public async Task <T> MakeHttpGetRequest <T>(string subscriptionId, string resourceGroupName, string name, string path = "") { if (!string.IsNullOrWhiteSpace(path)) { path = path.StartsWith("/") ? path.Substring(1) : path; } if (string.IsNullOrWhiteSpace(path)) { path = $"{SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name)}"; } else { path = $"{SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name)}/{path}"; } var geoMasterResponse = await HttpGet <T>(path); return(geoMasterResponse); }
/// <summary> /// Gets all the APP SETTINGS for the Web App that start with WEBSITE_ filtering out /// the sensitive settings like connectionstrings, tokens, secrets, keys, content shares etc. /// </summary> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">Name of the resource</param> /// <param name="slotName">slot name (if querying for a slot, defaults to production slot)</param> /// <returns>A dictionary of AppSetting Keys and values</returns> /// <example> /// <code> /// This sample shows how to call the <see cref="GetAppSettings"/> method in a detector /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// var subId = cxt.Resource.SubscriptionId; /// var rg = cxt.Resource.ResourceGroup; /// var name = cxt.Resource.Name; /// var slot = cxt.Resource.Slot; /// /// var appSettings = await dp.GeoMaster.GetAppSettings(subId, rg, name, slot); /// foreach(var key in appSettings.Keys) /// { /// // do something with the appSettingValue /// string appSettingValue = appSettings[key]; /// } /// } /// </code> /// </example> public async Task <IDictionary <string, string> > GetAppSettings(string subscriptionId, string resourceGroupName, string name, string slotName) { string path = $"{SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name, slotName)}/config/appsettings/list"; var geoMasterResponse = await HttpPost <GeoMasterResponse, string>(path); var properties = geoMasterResponse.Properties; Dictionary <string, string> appSettings = new Dictionary <string, string>(); foreach (var item in properties) { if (item.Key.StartsWith("WEBSITE_")) { if (!SensitiveAppSettingsEndingWith.Any(x => item.Key.EndsWith(x))) { appSettings.Add(item.Key, item.Value); } } } return(appSettings); }
/// <summary> /// Gets all App Settings that are marked sticky to the slot for this site\slot /// </summary> /// <param name="subscriptionId"></param> /// <param name="resourceGroupName"></param> /// <param name="name"></param> /// <returns>A dictionary of Settings that are marked sticky to the slot</returns> /// <example> /// This sample shows how to call the <see cref="GetStickySlotSettingNames"/> method in a detector /// <code> /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// var subId = cxt.Resource.SubscriptionId; /// var rg = cxt.Resource.ResourceGroup; /// var name = cxt.Resource.Name; /// /// var stickySettings = await dp.GeoMaster.GetStickySlotSettingNames(subId, rg, name); /// foreach(var key in stickySettings.Keys) /// { /// // do something with the stickyslot value /// string[] settings = stickySettings[key]; /// } /// } /// </code> /// </example> public async Task <IDictionary <string, string[]> > GetStickySlotSettingNames(string subscriptionId, string resourceGroupName, string name) { string path = SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name); path = path + "/config/slotConfigNames"; GeoMasterResponse geoMasterResponse = null; geoMasterResponse = await HttpGet <GeoMasterResponse>(path); Dictionary <string, string[]> stickyToSlotSettings = new Dictionary <string, string[]>(); foreach (var item in geoMasterResponse.Properties) { var val = new string[0]; if (item.Value != null && item.Value is Newtonsoft.Json.Linq.JArray) { var jArray = (Newtonsoft.Json.Linq.JArray)item.Value; val = jArray.ToObject <string[]>(); } stickyToSlotSettings.Add(item.Key, val); } return(stickyToSlotSettings); }
/// <summary> /// Gets all the APP SETTINGS for the Web App that start with prefixes like WEBSITE_, FUNCTION_ etc, filtering out /// the sensitive settings like connectionstrings, tokens, secrets, keys, content shares etc. /// </summary> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">Name of the resource</param> /// <param name="slotName">slot name (if querying for a slot, defaults to production slot)</param> /// <returns>A dictionary of AppSetting Keys and values</returns> /// <example> /// <code> /// This sample shows how to call the <see cref="GetAppSettings"/> method in a detector /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// var subId = cxt.Resource.SubscriptionId; /// var rg = cxt.Resource.ResourceGroup; /// var name = cxt.Resource.Name; /// var slot = cxt.Resource.Slot; /// /// var appSettings = await dp.GeoMaster.GetAppSettings(subId, rg, name, slot); /// foreach(var key in appSettings.Keys) /// { /// // do something with the appSettingValue /// string appSettingValue = appSettings[key]; /// } /// } /// </code> /// </example> public async Task <IDictionary <string, string> > GetAppSettings(string subscriptionId, string resourceGroupName, string name, string slotName) { string path = $"{SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name, slotName)}/config/appsettings/list"; var geoMasterResponse = await HttpPost <GeoMasterResponse, string>(path); var properties = geoMasterResponse.Properties; Dictionary <string, string> appSettings = new Dictionary <string, string>(); foreach (var item in properties) { if (AllowedlistAppSettingsStartingWith.Any(x => item.Key.StartsWith(x)) && !SensitiveAppSettingsEndingWith.Any(x => item.Key.EndsWith(x)) || RegexMatchingPatterns.Any(x => (Regex.Match(item.Key, x).Success))) { string value = RemovePIIFromSettings(item.Value); appSettings.Add(item.Key, value); } else { appSettings.Add(item.Key, "******"); } } return(appSettings); }
/// <summary> /// Gets the container logs for a site as a string /// </summary> /// <param name="subscriptionId">Subscription Id for the resource</param> /// <param name="resourceGroupName">The resource group that the resource is part of </param> /// <param name="name">Name of the resource</param> /// <param name="slotName">slot name (if querying for a slot, defaults to production slot)</param> /// /// <example> /// The below example shows how you call <see cref="GetLinuxContainerLogs"/> to get container logs for this app. /// <code> /// public async static Task<![CDATA[<Response>]]> Run(DataProviders dp, OperationContext<![CDATA[<App>]]> cxt, Response res) /// { /// var subId = cxt.Resource.SubscriptionId; /// var rg = cxt.Resource.ResourceGroup; /// var name = cxt.Resource.Name; /// var slot = cxt.Resource.Slot; /// /// string containerLogs = await dp.GeoMaster.GetLinuxContainerLogs(subId, rg, name,slot); /// /// // do any processing on the string variable containerLogs /// } /// </code> /// </example> /// <returns></returns> public Task <string> GetLinuxContainerLogs(string subscriptionId, string resourceGroupName, string name, string slotName) { string path = $"{SitePathUtility.GetSitePath(subscriptionId, resourceGroupName, name, slotName)}/containerlogs"; return(HttpPost <string, string>(path)); }