private static void LogBeginRequest(HttpContext httpContext) { if (whiteListedPaths.FindIndex(x => x.Contains(httpContext.Request.Path.ToString(), StringComparison.OrdinalIgnoreCase)) != -1) { return; } OperationManager.SafeExecute(() => { var request = httpContext.Request; var requestId = request.GetRequestId() ?? Guid.NewGuid().ToString(); httpContext.Items[Constants.RequestIdHeader] = requestId; httpContext.Items[Constants.RequestDateTimeUtc] = DateTime.UtcNow; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "OnBeginRequest", GetRawUrl(request), request.Method, requestId, 0, 0, request.GetUserAgent()); }); }
private async Task Assign(HostAssignmentContext assignmentContext) { try { // first make all environment and file system changes required for // the host to be specialized assignmentContext.ApplyAppSettings(); KuduEventGenerator.Log(null).LogMessage(EventLevel.Informational, assignmentContext.SiteName, $"Mounting file share at {DateTime.UtcNow}", string.Empty); // Limit the amount of time time we allow for mounting to complete var mounted = await MountFileShareWithin(TimeSpan.FromSeconds(30)); KuduEventGenerator.Log(null).LogMessage(EventLevel.Informational, assignmentContext.SiteName, $"Mount file share result: {mounted} at {DateTime.UtcNow}", string.Empty); } catch (Exception) { throw; } finally { // all assignment settings/files have been applied so we can flip // the switch now on specialization // even if there are failures applying context above, we want to // leave placeholder mode _linuxConsumptionEnv.FlagAsSpecializedAndReady(); _linuxConsumptionEnv.ResumeRequests(); } }
private async Task <string> MountKuduFileShare(string siteName, string connectionString) { try { var fileShareName = string.Format(FileShareFormat, Constants.KuduFileSharePrefix, ServerConfiguration.GetApplicationName().ToLowerInvariant()); await _storageClient.CreateFileShare(siteName, connectionString, fileShareName); KuduEventGenerator.Log(_environment).LogMessage(EventLevel.Informational, siteName, $"Mounting Kudu mount file share {fileShareName} at {Constants.KuduFileShareMountPath}", string.Empty); await _meshServiceClient.MountCifs(connectionString, fileShareName, Constants.KuduFileShareMountPath); return(string.Empty); } catch (Exception e) { var message = e.ToString(); KuduEventGenerator.Log(_environment) .LogMessage(EventLevel.Warning, siteName, nameof(MountKuduFileShare), message); return(message); } }
private static void LogEndRequest(HttpContext httpContext) { if (whiteListedPaths.FindIndex(x => x.Contains(httpContext.Request.Path.ToString(), StringComparison.OrdinalIgnoreCase)) != -1) { return; } OperationManager.SafeExecute(() => { var request = httpContext.Request; var response = httpContext.Response; var requestId = (string)httpContext.Items[Constants.RequestIdHeader]; var requestTime = (DateTime)httpContext.Items[Constants.RequestDateTimeUtc]; var latencyInMilliseconds = (long)(DateTime.UtcNow - requestTime).TotalMilliseconds; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "OnEndRequest", GetRawUrl(request), request.Method, requestId, response.StatusCode, latencyInMilliseconds, request.GetUserAgent()); }); }
public void ReturnsLinuxEventGenerator() { var environment = new TestSystemEnvironment(); environment.SetEnvironmentVariable(Constants.ContainerName, "container-name"); var eventGenerator = KuduEventGenerator.Log(environment); Assert.True(eventGenerator is LinuxContainerEventGenerator); }
private static async Task PrintRequirementsTxtDependenciesAsync(string builtFolder) { string filename = "requirements.txt"; string requirementsTxtPath = Path.Combine(builtFolder, filename); if (File.Exists(requirementsTxtPath)) { string[] lines = await File.ReadAllLinesAsync(requirementsTxtPath); foreach (string line in lines) { int separatorIndex; if (line.IndexOf("==") >= 0) { separatorIndex = line.IndexOf("=="); } else if (line.IndexOf(">=") >= 0) { separatorIndex = line.IndexOf(">="); } else if (line.IndexOf("<=") >= 0) { separatorIndex = line.IndexOf("<="); } else if (line.IndexOf(">") >= 0) { separatorIndex = line.IndexOf(">"); } else if (line.IndexOf("<") >= 0) { separatorIndex = line.IndexOf("<"); } else { separatorIndex = line.Length; } string package = line.Substring(0, separatorIndex).Trim(); string version = line.Substring(separatorIndex).Trim(); KuduEventGenerator.Log().GenericEvent( ServerConfiguration.GetApplicationName(), $"dependencies,python,{filename},{package},{version}", Guid.Empty.ToString(), string.Empty, string.Empty, string.Empty); } } }
private async Task <HttpResponseMessage> SendAsync(IEnumerable <KeyValuePair <string, string> > formData) { var operationName = formData.FirstOrDefault(f => string.Equals(f.Key, Operation)).Value; var meshUri = _environment.GetEnvironmentVariable(Constants.MeshInitURI); KuduEventGenerator.Log(_environment).GenericEvent(ServerConfiguration.GetApplicationName(), $"Sending mesh request {operationName} to {meshUri}", string.Empty, string.Empty, string.Empty, string.Empty); var res = await _client.PostAsync(meshUri, new FormUrlEncodedContent(formData)); KuduEventGenerator.Log(_environment).GenericEvent(ServerConfiguration.GetApplicationName(), $"Mesh response {res.StatusCode}", string.Empty, string.Empty, string.Empty, string.Empty); return(res); }
private bool EnsureMountedDeploymentsPath(string path) { try { FileSystemHelpers.EnsureDirectory(path); return(true); } catch (Exception e) { KuduEventGenerator.Log().LogMessage(EventLevel.Informational, ServerConfiguration.GetApplicationName(), $"{nameof(EnsureMountedDeploymentsPath)} Failed. Path = {path}", e.ToString()); return(false); } }
private static ITracer TraceStartup(HttpContext httpContext) { ITracer tracer = null; // 0 means this is the very first request starting up Kudu if (0 == Interlocked.Exchange(ref _traceStartup, 1)) { tracer = TraceServices.CreateRequestTracer(httpContext); if (tracer != null && tracer.TraceLevel > TraceLevel.Off) { var attribs = GetTraceAttributes(httpContext); // force always trace attribs[TraceExtensions.AlwaysTrace] = "1"; // Dump environment variables foreach (DictionaryEntry entry in System.Environment.GetEnvironmentVariables()) { var key = (string)entry.Key; if (key.StartsWith("SCM", StringComparison.OrdinalIgnoreCase)) { attribs[key] = (string)entry.Value; } } tracer.Trace(XmlTracer.StartupRequestTrace, attribs); } OperationManager.SafeExecute(() => { var requestId = (string)httpContext.Items[Constants.RequestIdHeader]; var assembly = Assembly.GetExecutingAssembly(); var fvi = FileVersionInfo.GetVersionInfo(assembly.Location); KuduEventGenerator.Log().GenericEvent( ServerConfiguration.GetApplicationName(), string.Format("StartupRequest pid:{0}, domain:{1}", Process.GetCurrentProcess().Id, AppDomain.CurrentDomain.Id), requestId, System.Environment.GetEnvironmentVariable(SettingsKeys.ScmType), System.Environment.GetEnvironmentVariable(SettingsKeys.WebSiteSku), fvi.FileVersion); }); } return(tracer); }
/// <summary> /// Mounts file share /// </summary> /// <returns></returns> public async Task <bool> MountFileShare() { var siteName = ServerConfiguration.GetApplicationName(); if (IsKuduShareMounted()) { const string message = "Kudu file share mounted already"; UpdateStatus(true, message); KuduEventGenerator.Log(_environment).LogMessage(EventLevel.Warning, siteName, nameof(MountFileShare), message); return(true); } if (!_environment.IsOnLinuxConsumption()) { const string message = "Mounting kudu file share is only supported on Linux consumption environment"; UpdateStatus(false, message); KuduEventGenerator.Log(_environment).LogMessage(EventLevel.Warning, siteName, nameof(MountFileShare), message); return(false); } if (!IsPersistentStorageEnabled()) { const string message = "Kudu file share was not mounted since persistent storage is disabled"; UpdateStatus(false, message); KuduEventGenerator.Log(_environment).LogMessage(EventLevel.Warning, siteName, nameof(MountFileShare), message); return(false); } if (!TryGetStorageConnectionString(out var connectionString)) { var message = $"Kudu file share was not mounted since {Constants.AzureWebJobsStorage} is empty"; UpdateStatus(false, message); KuduEventGenerator.Log(_environment).LogMessage(EventLevel.Warning, siteName, nameof(MountFileShare), message); return(false); } var errorMessage = await MountKuduFileShare(siteName, connectionString); var mountResult = string.IsNullOrEmpty(errorMessage); UpdateStatus(mountResult, errorMessage); KuduEventGenerator.Log(_environment).LogMessage(EventLevel.Informational, siteName, $"Mounting Kudu file share result: {mountResult}", string.Empty); return(mountResult); }
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args) { if (_logger != null && eventType <= TraceEventType.Information) { _logger.Log(format, args); KuduEventGenerator.Log().GenericEvent( ServerConfiguration.GetApplicationName(), string.Format(format, args), System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty, string.Empty, string.Empty, string.Empty); } _tracer.Trace(format, args); }
private static async Task LogDependenciesFile(string builtFolder) { try { await PrintRequirementsTxtDependenciesAsync(builtFolder); await PrintPackageJsonDependenciesAsync(builtFolder); PrintCsprojDependenciesAsync(builtFolder); } catch (Exception) { KuduEventGenerator.Log().GenericEvent( ServerConfiguration.GetApplicationName(), $"dependencies,failed to parse function app dependencies", Guid.Empty.ToString(), string.Empty, string.Empty, string.Empty); } }
private static void LogBeginRequest(HttpContext httpContext) { OperationManager.SafeExecute(() => { var request = httpContext.Request; var requestId = request.GetRequestId() ?? Guid.NewGuid().ToString(); httpContext.Items[Constants.RequestIdHeader] = requestId; httpContext.Items[Constants.RequestDateTimeUtc] = DateTime.UtcNow; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "OnBeginRequest", GetRawUrl(request), request.Method, requestId, 0, 0, request.GetUserAgent()); }); }
private static void LogEndRequest(HttpContext httpContext) { OperationManager.SafeExecute(() => { var request = httpContext.Request; var response = httpContext.Response; var requestId = (string)httpContext.Items[Constants.RequestIdHeader]; var requestTime = (DateTime)httpContext.Items[Constants.RequestDateTimeUtc]; var latencyInMilliseconds = (long)(DateTime.UtcNow - requestTime).TotalMilliseconds; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "OnEndRequest", GetRawUrl(request), request.Method, requestId, response.StatusCode, latencyInMilliseconds, request.GetUserAgent()); }); }
private static async Task PrintPackageJsonDependenciesAsync(string builtFolder) { string filename = "package.json"; string packageJsonPath = Path.Combine(builtFolder, filename); if (File.Exists(packageJsonPath)) { string content = await File.ReadAllTextAsync(packageJsonPath); JObject jobj = JObject.Parse(content); if (jobj.ContainsKey("devDependencies")) { Dictionary <string, string> dictObj = jobj["devDependencies"].ToObject <Dictionary <string, string> >(); foreach (string key in dictObj.Keys) { KuduEventGenerator.Log().GenericEvent( ServerConfiguration.GetApplicationName(), $"dependencies,node,{filename},{key},{dictObj[key]},devDependencies", Guid.Empty.ToString(), string.Empty, string.Empty, string.Empty); } } if (jobj.ContainsKey("dependencies")) { Dictionary <string, string> dictObj = jobj["dependencies"].ToObject <Dictionary <string, string> >(); foreach (string key in dictObj.Keys) { KuduEventGenerator.Log().GenericEvent( ServerConfiguration.GetApplicationName(), $"dependencies,node,{filename},{key},{dictObj[key]},dependencies", Guid.Empty.ToString(), string.Empty, string.Empty, string.Empty); } } } }
private async Task <bool> MountFileShareWithin(TimeSpan timeLimit) { var startTime = DateTime.UtcNow; try { return(await OperationManager.ExecuteWithTimeout(MountFileShare(), timeLimit)); } catch (Exception e) { KuduEventGenerator.Log(null).LogMessage(EventLevel.Warning, ServerConfiguration.GetApplicationName(), nameof(MountFileShareWithin), e.ToString()); return(false); } finally { KuduEventGenerator.Log(null).LogMessage(EventLevel.Informational, ServerConfiguration.GetApplicationName(), $"Time taken to mount = {(DateTime.UtcNow - startTime).TotalMilliseconds}", string.Empty); } }
public async Task CreateFileShare(string siteName, string connectionString, string fileShareName) { try { var storageAccount = CloudStorageAccount.Parse(connectionString); var fileClient = storageAccount.CreateCloudFileClient(); // Get a reference to the file share we created previously. CloudFileShare share = fileClient.GetShareReference(fileShareName); KuduEventGenerator.Log(_environment).LogMessage(EventLevel.Informational, siteName, $"Creating Kudu mount file share {fileShareName}", string.Empty); await share.CreateIfNotExistsAsync(new FileRequestOptions(), new OperationContext()); } catch (Exception e) { KuduEventGenerator.Log(_environment) .LogMessage(EventLevel.Warning, siteName, nameof(CreateFileShare), e.ToString()); throw; } }
private static void TraceHeartbeat() { var now = DateTime.UtcNow; if (_nextHeartbeatDateTime >= now) { return; } _nextHeartbeatDateTime = now.AddHours(1); OperationManager.SafeExecute(() => { KuduEventGenerator.Log().GenericEvent( ServerConfiguration.GetApplicationName(), string.Format("Heartbeat pid:{0}, domain:{1}", Process.GetCurrentProcess().Id, AppDomain.CurrentDomain.Id), string.Empty, System.Environment.GetEnvironmentVariable(SettingsKeys.ScmType), System.Environment.GetEnvironmentVariable(SettingsKeys.WebSiteSku), KuduVersion.Value); }); }
private static void PrintCsprojDependenciesAsync(string builtFolder) { foreach (string csprojPath in Directory.GetFiles(builtFolder, "*.csproj", SearchOption.TopDirectoryOnly)) { string filename = Path.GetFileName(csprojPath); XElement purchaseOrder = XElement.Load(csprojPath); foreach (var itemGroup in purchaseOrder.Elements("ItemGroup")) { foreach (var packageReference in itemGroup.Elements("PackageReference")) { string include = packageReference.Attribute("Include").Value; string version = packageReference.Attribute("Version").Value; KuduEventGenerator.Log().GenericEvent( ServerConfiguration.GetApplicationName(), $"dependencies,dotnet,{filename},{include},{version}", Guid.Empty.ToString(), string.Empty, string.Empty, string.Empty); } } } }
/// <summary> /// Detect if a route matches any of whitelisted prefixes /// </summary> /// <param name="context">Http request context</param> /// <param name="authorizationService">Authorization service for each request</param> /// <returns>Response be set to 404 if the route is not whitelisted</returns> public async Task Invoke(HttpContext context, IAuthorizationService authorizationService = null) { DateTime requestTime = DateTime.UtcNow; // Step 1: if disguise host exists, replace the request header HOST to DISGUISED-HOST // if disguist host does not exist, check and replace ~1 with regex if (context.Request.Headers.TryGetValue(DisguisedHostHeader, out StringValues value)) { context.Request.Headers[HostHeader] = value; } else { context.Request.Host = new HostString(SanitizeScmUrl( context.Request.Headers[HostHeader].FirstOrDefault())); } if (context.Request.Headers.TryGetValue(ForwardedProtocolHeader, out value)) { context.Request.Scheme = value; } // Step 2: check if the request endpoint is enabled in Linux Consumption if (!IsRouteAllowed(context.Request.Path)) { context.Response.StatusCode = 404; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "BlacklistedLinuxConsumptionEndpoint", context.Request.GetEncodedPathAndQuery(), context.Request.Method, System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty, context.Response.StatusCode, (DateTime.UtcNow - requestTime).Milliseconds, context.Request.GetUserAgent()); return; } // Step 3: check if the request matches authorization policy // If the home page is requested without authentication (e.g. ControllerPing), return 200 with hint. // If the home page is requested with authentication (e.g. Customer Browser Access), return 200 with homepage content. AuthenticateResult authenticationResult = await context.AuthenticateAsync(ArmAuthenticationDefaults.AuthenticationScheme); if (IsHomePageWithoutAuthentication(authenticationResult, context.Request.Path)) { byte[] data = Encoding.UTF8.GetBytes("Please use /basicAuth endpoint or AAD to authenticate SCM site"); context.Response.StatusCode = 200; context.Response.ContentType = "text/plain; charset=UTF-8"; await context.Response.Body.WriteAsync(data, 0, data.Length); KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "AccessLinuxConsumptionHomePageWithoutAuthentication", context.Request.GetEncodedPathAndQuery(), context.Request.Method, System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty, context.Response.StatusCode, (DateTime.UtcNow - requestTime).Milliseconds, context.Request.GetUserAgent()); return; } else if (!authenticationResult.Succeeded) { context.Response.StatusCode = 401; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "UnauthenticatedLinuxConsumptionEndpoint", context.Request.GetEncodedPathAndQuery(), context.Request.Method, System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty, context.Response.StatusCode, (DateTime.UtcNow - requestTime).Milliseconds, context.Request.GetUserAgent()); return; } if (authorizationService != null) { AuthorizationResult endpointAuthorization = await authorizationService.AuthorizeAsync(authenticationResult.Principal, AuthorizationPolicy); if (!endpointAuthorization.Succeeded) { context.Response.StatusCode = 401; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "UnauthorizedLinuxConsumptionEndpoint", context.Request.GetEncodedPathAndQuery(), context.Request.Method, System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty, context.Response.StatusCode, (DateTime.UtcNow - requestTime).Milliseconds, context.Request.GetUserAgent()); return; } } await _next.Invoke(context); }
/// <summary> /// Detect if a route matches any of whitelisted prefixes /// </summary> /// <param name="context">Http request context</param> /// <param name="authorizationService">Authorization service for each request</param> /// <returns>Response be set to 404 if the route is not whitelisted</returns> public async Task Invoke(HttpContext context, IAuthorizationService authorizationService = null) { DateTime requestTime = DateTime.UtcNow; // Step 1: if disguise host exists, replace the request header HOST to DISGUISED-HOST // if disguist host does not exist, check and replace ~1 with regex if (context.Request.Headers.TryGetValue(DisguisedHostHeader, out StringValues value)) { context.Request.Headers[HostHeader] = value; } else { context.Request.Host = new HostString(SanitizeScmUrl( context.Request.Headers[HostHeader].FirstOrDefault())); } if (context.Request.Headers.TryGetValue(ForwardedProtocolHeader, out value)) { context.Request.Scheme = value; } // Step 2: check if it is homepage route or favicon route, always return 200 if (IsHomePageRoute(context.Request.Path) || IsFavIconRoute(context.Request.Path)) { context.Response.StatusCode = 200; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "LinuxConsumptionEndpoint", context.Request.GetEncodedPathAndQuery(), context.Request.Method, System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty, context.Response.StatusCode, (DateTime.UtcNow - requestTime).Milliseconds, context.Request.GetUserAgent()); return; } // Step 3: check if the request endpoint is enabled in Linux Consumption if (!IsRouteWhitelisted(context.Request.Path)) { context.Response.StatusCode = 404; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "BlacklistedLinuxConsumptionEndpoint", context.Request.GetEncodedPathAndQuery(), context.Request.Method, System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty, context.Response.StatusCode, (DateTime.UtcNow - requestTime).Milliseconds, context.Request.GetUserAgent()); return; } // Step 4: check if the request matches authorization policy AuthenticateResult authenticationResult = await context.AuthenticateAsync(ArmAuthenticationDefaults.AuthenticationScheme); if (!authenticationResult.Succeeded) { context.Response.StatusCode = 401; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "UnauthenticatedLinuxConsumptionEndpoint", context.Request.GetEncodedPathAndQuery(), context.Request.Method, System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty, context.Response.StatusCode, (DateTime.UtcNow - requestTime).Milliseconds, context.Request.GetUserAgent()); return; } if (authorizationService != null) { AuthorizationResult endpointAuthorization = await authorizationService.AuthorizeAsync(authenticationResult.Principal, AuthorizationPolicy); if (!endpointAuthorization.Succeeded) { context.Response.StatusCode = 401; KuduEventGenerator.Log().ApiEvent( ServerConfiguration.GetApplicationName(), "UnauthorizedLinuxConsumptionEndpoint", context.Request.GetEncodedPathAndQuery(), context.Request.Method, System.Environment.GetEnvironmentVariable("x-ms-request-id") ?? string.Empty, context.Response.StatusCode, (DateTime.UtcNow - requestTime).Milliseconds, context.Request.GetUserAgent()); return; } } await _next.Invoke(context); }