Exemplo n.º 1
0
        protected override Assembly Load(AssemblyName assemblyName)
        {
            // If the assembly being requested matches a runtime assembly,
            // we'll use the runtime assembly instead of loading it in this context:
            if (TryLoadRuntimeAssembly(assemblyName, out Assembly assembly))
            {
                return(assembly);
            }

            if (IsRuntimeAssembly(assemblyName))
            {
                // If there was a failure loading a runtime assembly, ensure we gracefuly unify to
                // the runtime version of the assembly if the version falls within a safe range.
                if (TryLoadRuntimeAssembly(new AssemblyName(assemblyName.Name), out assembly))
                {
                    AssemblyName runtimeAssemblyName = AssemblyNameCache.GetName(assembly);

                    if (runtimeAssemblyName.Version.Major == assemblyName.Version.Major &&
                        runtimeAssemblyName.Version.Minor == assemblyName.Version.Minor)
                    {
                        return(assembly);
                    }
                }

                return(null);
            }

            return(LoadInternal(assemblyName));
        }
Exemplo n.º 2
0
        /// <summary>
        /// A load policy evaluator that verifies if the runtime package is the same major and
        /// newer minor version.
        /// </summary>
        /// <param name="requestedAssembly">The name of the requested assembly.</param>
        /// <param name="runtimeAssembly">The runtime assembly.</param>
        /// <returns>True if the evaluation succeeds.</returns>
        private static bool IsMinorMatchOrLowerPolicyEvaluator(AssemblyName requestedAssembly, Assembly runtimeAssembly)
        {
            AssemblyName runtimeAssemblyName = AssemblyNameCache.GetName(runtimeAssembly);

            return(requestedAssembly.Version.Major == runtimeAssemblyName.Version.Major &&
                   requestedAssembly.Version.Minor <= runtimeAssemblyName.Version.Minor);
        }
Exemplo n.º 3
0
        public bool TryResolveAssembly(string assemblyName, AssemblyLoadContext targetContext, out Assembly assembly)
        {
            if (string.Compare(AssemblyNameCache.GetName(_assembly).Name, assemblyName, StringComparison.OrdinalIgnoreCase) == 0)
            {
                assembly = _assembly;
                return(true);
            }

            assembly = null;
            return(false);
        }
Exemplo n.º 4
0
        private static bool TryResolveExtensionAssembly(ScriptBindingProvider bindingProvider, string assemblyName, out Assembly assembly)
        {
            assembly = null;
            Assembly providerAssembly = bindingProvider.GetType().Assembly;

            if (string.Compare(assemblyName, AssemblyNameCache.GetName(providerAssembly).Name) == 0)
            {
                assembly = providerAssembly;
            }

            return(assembly != null);
        }
        public bool TryResolveAssembly(string assemblyName, AssemblyLoadContext targetContext, ILogger logger, out Assembly assembly)
        {
            if (string.Compare(AssemblyNameCache.GetName(_assembly).Name, assemblyName, StringComparison.OrdinalIgnoreCase) == 0)
            {
                logger.LogInformation($"{nameof(DirectSharedAssemblyProvider)} resolved shared assembly '{assemblyName}'");

                assembly = _assembly;
                return(true);
            }

            assembly = null;
            return(false);
        }
Exemplo n.º 6
0
        public static bool TryMatchAssembly(string assemblyName, Type type, out Assembly matchedAssembly)
        {
            matchedAssembly = null;

            var candidateAssembly = type.Assembly;

            if (string.Compare(assemblyName, AssemblyNameCache.GetName(candidateAssembly).Name, StringComparison.OrdinalIgnoreCase) == 0)
            {
                matchedAssembly = candidateAssembly;
                return(true);
            }

            return(false);
        }
        // Do the full runtime intitialization. This includes static initialization.
        // This mainly means:
        // - indexing the functions
        // - spinning up the listeners (so connecting to the services)
        public static async Task <JobHostContext> CreateJobHostContextAsync(
            this JobHostConfiguration config,
            ServiceProviderWrapper services, // Results from first phase
            JobHost host,
            CancellationToken shutdownToken,
            CancellationToken cancellationToken)
        {
            FunctionExecutor                           functionExecutor       = services.GetService <FunctionExecutor>();
            IFunctionIndexProvider                     functionIndexProvider  = services.GetService <IFunctionIndexProvider>();
            ITriggerBindingProvider                    triggerBindingProvider = services.GetService <ITriggerBindingProvider>();
            IBindingProvider                           bindingProvider        = services.GetService <IBindingProvider>();
            SingletonManager                           singletonManager       = services.GetService <SingletonManager>();
            IJobActivator                              activator              = services.GetService <IJobActivator>();
            IHostIdProvider                            hostIdProvider         = services.GetService <IHostIdProvider>();
            INameResolver                              nameResolver           = services.GetService <INameResolver>();
            IExtensionRegistry                         extensions             = services.GetExtensions();
            IStorageAccountProvider                    storageAccountProvider = services.GetService <IStorageAccountProvider>();
            ILoggerFactory                             loggerFactory          = services.GetService <ILoggerFactory>();
            IFunctionResultAggregatorFactory           aggregatorFactory      = services.GetService <IFunctionResultAggregatorFactory>();
            IAsyncCollector <FunctionInstanceLogEntry> functionEventCollector = null;

            // Create the aggregator if all the pieces are configured
            IAsyncCollector <FunctionInstanceLogEntry> aggregator = null;

            if (loggerFactory != null && aggregatorFactory != null && config.Aggregator.IsEnabled)
            {
                aggregator = aggregatorFactory.Create(config.Aggregator.BatchSize, config.Aggregator.FlushTimeout, loggerFactory);
            }

            IQueueConfiguration queueConfiguration = services.GetService <IQueueConfiguration>();
            var blobsConfiguration = config.Blobs;

            TraceWriter trace = services.GetService <TraceWriter>();
            IAsyncCollector <FunctionInstanceLogEntry> registeredFunctionEventCollector = services.GetService <IAsyncCollector <FunctionInstanceLogEntry> >();

            if (registeredFunctionEventCollector != null && aggregator != null)
            {
                // If there are both an aggregator and a registered FunctionEventCollector, wrap them in a composite
                functionEventCollector = new CompositeFunctionEventCollector(new[] { registeredFunctionEventCollector, aggregator });
            }
            else
            {
                // Otherwise, take whichever one is null (or use null if both are)
                functionEventCollector = aggregator ?? registeredFunctionEventCollector;
            }

            IWebJobsExceptionHandler exceptionHandler = services.GetService <IWebJobsExceptionHandler>();

            if (exceptionHandler != null)
            {
                exceptionHandler.Initialize(host);
            }

            bool hasFastTableHook   = services.GetService <IAsyncCollector <FunctionInstanceLogEntry> >() != null;
            bool noDashboardStorage = config.DashboardConnectionString == null;

            // Only testing will override these interfaces.
            IHostInstanceLoggerProvider     hostInstanceLoggerProvider     = services.GetService <IHostInstanceLoggerProvider>();
            IFunctionInstanceLoggerProvider functionInstanceLoggerProvider = services.GetService <IFunctionInstanceLoggerProvider>();
            IFunctionOutputLoggerProvider   functionOutputLoggerProvider   = services.GetService <IFunctionOutputLoggerProvider>();

            if (hostInstanceLoggerProvider == null && functionInstanceLoggerProvider == null && functionOutputLoggerProvider == null)
            {
                if (hasFastTableHook && noDashboardStorage)
                {
                    var loggerProvider = new FastTableLoggerProvider(trace);
                    hostInstanceLoggerProvider     = loggerProvider;
                    functionInstanceLoggerProvider = loggerProvider;
                    functionOutputLoggerProvider   = loggerProvider;
                }
                else
                {
                    var loggerProvider = new DefaultLoggerProvider(storageAccountProvider, trace);
                    hostInstanceLoggerProvider     = loggerProvider;
                    functionInstanceLoggerProvider = loggerProvider;
                    functionOutputLoggerProvider   = loggerProvider;
                }
            }

            using (CancellationTokenSource combinedCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, shutdownToken))
            {
                CancellationToken combinedCancellationToken = combinedCancellationSource.Token;

                await WriteSiteExtensionManifestAsync(combinedCancellationToken);

                IStorageAccount dashboardAccount = await storageAccountProvider.GetDashboardAccountAsync(combinedCancellationToken);

                IHostInstanceLogger hostInstanceLogger = await hostInstanceLoggerProvider.GetAsync(combinedCancellationToken);

                IFunctionInstanceLogger functionInstanceLogger = await functionInstanceLoggerProvider.GetAsync(combinedCancellationToken);

                IFunctionOutputLogger functionOutputLogger = await functionOutputLoggerProvider.GetAsync(combinedCancellationToken);

                if (functionExecutor == null)
                {
                    var extensionRegistry     = config.GetService <IExtensionRegistry>();
                    var globalFunctionFilters = extensionRegistry.GetFunctionFilters();

                    functionExecutor = new FunctionExecutor(functionInstanceLogger, functionOutputLogger, exceptionHandler, trace, functionEventCollector, loggerFactory, globalFunctionFilters);
                    services.AddService(functionExecutor);
                }

                if (functionIndexProvider == null)
                {
                    functionIndexProvider = new FunctionIndexProvider(
                        services.GetService <ITypeLocator>(),
                        triggerBindingProvider,
                        bindingProvider,
                        activator,
                        functionExecutor,
                        extensions,
                        singletonManager,
                        trace,
                        loggerFactory);

                    // Important to set this so that the func we passed to DynamicHostIdProvider can pick it up.
                    services.AddService <IFunctionIndexProvider>(functionIndexProvider);
                }

                IFunctionIndex functions = await functionIndexProvider.GetAsync(combinedCancellationToken);

                IListenerFactory functionsListenerFactory = new HostListenerFactory(functions.ReadAll(), singletonManager, activator, nameResolver, trace, loggerFactory);

                IFunctionExecutor hostCallExecutor;
                IListener         listener;
                HostOutputMessage hostOutputMessage;

                string hostId = await hostIdProvider.GetHostIdAsync(cancellationToken);

                if (string.Compare(config.HostId, hostId, StringComparison.OrdinalIgnoreCase) != 0)
                {
                    // if this isn't a static host ID, provide the HostId on the config
                    // so it is accessible
                    config.HostId = hostId;
                }

                if (dashboardAccount == null)
                {
                    hostCallExecutor = new ShutdownFunctionExecutor(shutdownToken, functionExecutor);

                    IListener factoryListener  = new ListenerFactoryListener(functionsListenerFactory);
                    IListener shutdownListener = new ShutdownListener(shutdownToken, factoryListener);
                    listener = shutdownListener;

                    hostOutputMessage = new DataOnlyHostOutputMessage();
                }
                else
                {
                    string sharedQueueName = HostQueueNames.GetHostQueueName(hostId);
                    IStorageQueueClient dashboardQueueClient       = dashboardAccount.CreateQueueClient();
                    IStorageQueue       sharedQueue                = dashboardQueueClient.GetQueueReference(sharedQueueName);
                    IListenerFactory    sharedQueueListenerFactory = new HostMessageListenerFactory(sharedQueue,
                                                                                                    queueConfiguration, exceptionHandler, trace, loggerFactory, functions,
                                                                                                    functionInstanceLogger, functionExecutor);

                    Guid             hostInstanceId               = Guid.NewGuid();
                    string           instanceQueueName            = HostQueueNames.GetHostQueueName(hostInstanceId.ToString("N"));
                    IStorageQueue    instanceQueue                = dashboardQueueClient.GetQueueReference(instanceQueueName);
                    IListenerFactory instanceQueueListenerFactory = new HostMessageListenerFactory(instanceQueue,
                                                                                                   queueConfiguration, exceptionHandler, trace, loggerFactory, functions,
                                                                                                   functionInstanceLogger, functionExecutor);

                    HeartbeatDescriptor heartbeatDescriptor = new HeartbeatDescriptor
                    {
                        SharedContainerName = HostContainerNames.Hosts,
                        SharedDirectoryName = HostDirectoryNames.Heartbeats + "/" + hostId,
                        InstanceBlobName    = hostInstanceId.ToString("N"),
                        ExpirationInSeconds = (int)HeartbeatIntervals.ExpirationInterval.TotalSeconds
                    };

                    IStorageBlockBlob blob = dashboardAccount.CreateBlobClient()
                                             .GetContainerReference(heartbeatDescriptor.SharedContainerName)
                                             .GetBlockBlobReference(heartbeatDescriptor.SharedDirectoryName + "/" + heartbeatDescriptor.InstanceBlobName);
                    IRecurrentCommand heartbeatCommand = new UpdateHostHeartbeatCommand(new HeartbeatCommand(blob));

                    IEnumerable <MethodInfo> indexedMethods = functions.ReadAllMethods();
                    Assembly hostAssembly = GetHostAssembly(indexedMethods);
                    string   displayName  = hostAssembly != null?AssemblyNameCache.GetName(hostAssembly).Name : "Unknown";

                    hostOutputMessage = new DataOnlyHostOutputMessage
                    {
                        HostInstanceId      = hostInstanceId,
                        HostDisplayName     = displayName,
                        SharedQueueName     = sharedQueueName,
                        InstanceQueueName   = instanceQueueName,
                        Heartbeat           = heartbeatDescriptor,
                        WebJobRunIdentifier = WebJobRunIdentifier.Current
                    };

                    hostCallExecutor = CreateHostCallExecutor(instanceQueueListenerFactory, heartbeatCommand,
                                                              exceptionHandler, shutdownToken, functionExecutor);
                    IListenerFactory hostListenerFactory = new CompositeListenerFactory(functionsListenerFactory,
                                                                                        sharedQueueListenerFactory, instanceQueueListenerFactory);
                    listener = CreateHostListener(hostListenerFactory, heartbeatCommand, exceptionHandler, shutdownToken);

                    // Publish this to Azure logging account so that a web dashboard can see it.
                    await LogHostStartedAsync(functions, hostOutputMessage, hostInstanceLogger, combinedCancellationToken);
                }

                functionExecutor.HostOutputMessage = hostOutputMessage;

                IEnumerable <FunctionDescriptor> descriptors = functions.ReadAllDescriptors();
                int descriptorsCount = descriptors.Count();

                ILogger startupLogger = loggerFactory?.CreateLogger(LogCategories.Startup);

                if (config.UsingDevelopmentSettings)
                {
                    string msg = "Development settings applied";
                    trace.Verbose(msg);
                    startupLogger?.LogDebug(msg);
                }

                if (descriptorsCount == 0)
                {
                    string msg = string.Format("No job functions found. Try making your job classes and methods public. {0}",
                                               Constants.ExtensionInitializationMessage);

                    trace.Warning(msg, Host.TraceSource.Indexing);
                    startupLogger?.LogWarning(msg);
                }
                else
                {
                    StringBuilder functionsTrace = new StringBuilder();
                    functionsTrace.AppendLine("Found the following functions:");

                    foreach (FunctionDescriptor descriptor in descriptors)
                    {
                        functionsTrace.AppendLine(descriptor.FullName);
                    }
                    string msg = functionsTrace.ToString();
                    trace.Info(msg, Host.TraceSource.Indexing);
                    startupLogger?.LogInformation(msg);
                }

                return(new JobHostContext(
                           functions,
                           hostCallExecutor,
                           listener,
                           trace,
                           functionEventCollector,
                           loggerFactory));
            }
        }
        public bool Setup(
            IFunctionIndex functions,
            IListenerFactory functionsListenerFactory,
            out IFunctionExecutor hostCallExecutor,
            out IListener listener,
            out HostOutputMessage hostOutputMessage,
            string hostId,
            CancellationToken shutdownToken)
        {
            string sharedQueueName = HostQueueNames.GetHostQueueName(hostId);
            var    sharedQueue     = sharedQueueName;

            IListenerFactory sharedQueueListenerFactory = new HostMessageListenerFactory(_storageServices, sharedQueue,
                                                                                         _exceptionHandler, _loggerFactory, functions,
                                                                                         _functionInstanceLogger, _functionExecutor);

            Guid             hostInstanceId               = Guid.NewGuid();
            string           instanceQueueName            = HostQueueNames.GetHostQueueName(hostInstanceId.ToString("N"));
            var              instanceQueue                = instanceQueueName;
            IListenerFactory instanceQueueListenerFactory = new HostMessageListenerFactory(_storageServices, instanceQueue,
                                                                                           _exceptionHandler, _loggerFactory, functions,
                                                                                           _functionInstanceLogger, _functionExecutor);

            HeartbeatDescriptor heartbeatDescriptor = new HeartbeatDescriptor
            {
                SharedContainerName = HostContainerNames.Hosts,
                SharedDirectoryName = HostDirectoryNames.Heartbeats + "/" + hostId,
                InstanceBlobName    = hostInstanceId.ToString("N"),
                ExpirationInSeconds = (int)HeartbeatIntervals.ExpirationInterval.TotalSeconds
            };

            var dashboardAccount = _storageAccountOptions.GetDashboardStorageAccount();

            var blob = dashboardAccount.CreateCloudBlobClient()
                       .GetContainerReference(heartbeatDescriptor.SharedContainerName)
                       .GetBlockBlobReference(heartbeatDescriptor.SharedDirectoryName + "/" + heartbeatDescriptor.InstanceBlobName);
            IRecurrentCommand heartbeatCommand = new UpdateHostHeartbeatCommand(new HeartbeatCommand(blob));

            IEnumerable <MethodInfo> indexedMethods = functions.ReadAllMethods();
            Assembly hostAssembly = JobHostContextFactory.GetHostAssembly(indexedMethods);
            string   displayName  = hostAssembly != null?AssemblyNameCache.GetName(hostAssembly).Name : "Unknown";

            hostOutputMessage = new JobHostContextFactory.DataOnlyHostOutputMessage
            {
                HostInstanceId      = hostInstanceId,
                HostDisplayName     = displayName,
                SharedQueueName     = sharedQueueName,
                InstanceQueueName   = instanceQueueName,
                Heartbeat           = heartbeatDescriptor,
                WebJobRunIdentifier = WebJobRunIdentifier.Current
            };

            hostCallExecutor = JobHostContextFactory.CreateHostCallExecutor(instanceQueueListenerFactory, heartbeatCommand,
                                                                            _exceptionHandler, shutdownToken, _functionExecutor);
            IListenerFactory hostListenerFactory = new CompositeListenerFactory(functionsListenerFactory,
                                                                                sharedQueueListenerFactory, instanceQueueListenerFactory);

            listener = JobHostContextFactory.CreateHostListener(hostListenerFactory, _sharedQueueHandler, heartbeatCommand, _exceptionHandler, shutdownToken);

            return(true);
        }
Exemplo n.º 9
0
        // Helper to filter out assemblies that don't reference the SDK or
        // binding extension assemblies (i.e. possible sources of binding attributes, etc.)
        private static bool AssemblyReferencesSdkOrExtension(Assembly assembly, IEnumerable <Assembly> extensionAssemblies)
        {
            // Don't index methods in our assemblies.
            if (typeof(DefaultTypeLocator).Assembly == assembly)
            {
                return(false);
            }

            AssemblyName[] referencedAssemblyNames = assembly.GetReferencedAssemblies();
            foreach (var referencedAssemblyName in referencedAssemblyNames)
            {
                if (String.Equals(referencedAssemblyName.Name, WebJobsAssemblyName, StringComparison.OrdinalIgnoreCase))
                {
                    // the assembly references our core SDK assembly
                    // containing our built in attribute types
                    return(true);
                }

                if (extensionAssemblies.Any(p => string.Equals(referencedAssemblyName.Name, AssemblyNameCache.GetName(p).Name, StringComparison.OrdinalIgnoreCase)))
                {
                    // the assembly references an extension assembly that may
                    // contain extension attributes
                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 10
0
        protected override Assembly Load(AssemblyName assemblyName)
        {
            bool isNameAdjusted = TryAdjustRuntimeAssemblyFromDepsFile(assemblyName, out assemblyName);

            // Try to load from deps references, if available
            if (TryLoadDepsDependency(assemblyName, out Assembly assembly))
            {
                return(assembly);
            }

            // If this is a runtime restricted assembly, load it based on unification rules
            if (TryGetRuntimeAssembly(assemblyName, out ScriptRuntimeAssembly scriptRuntimeAssembly))
            {
                // There are several possible scenarios:
                //  1. The assembly was found and the policy evaluator succeeded.
                //     - Return the assembly.
                //
                //  2. The assembly was not found (meaning the policy evaluator wasn't able to run).
                //     - Return null as there's not much else we can do. This will fail and come back to this context
                //       through the fallback logic for another attempt. This is likely an error case so let it fail.
                //
                //  3. The assembly was found but the policy evaluator failed.
                //     a. We did not adjust the requested assembly name via the deps file.
                //        - This means that the DefaultLoadContext is looking for the correct version. Return null and let
                //          it handle the load attempt.
                //     b. We adjusted the requested assembly name via the deps file. If we return null the DefaultLoadContext would attempt to
                //        load the original assembly version, which may be incorrect if we had to adjust it forward past the runtime's version.
                //        i.  The adjusted assembly name is higher than the runtime's version.
                //            - Do not trust the DefaultLoadContext to handle this as it may resolve to the runtime's assembly. Instead,
                //              call LoadCore() to ensure the adjusted assembly is loaded.
                //        ii. The adjusted assembly name is still lower than or equal to the runtime's version (this likely means
                //            a lower major version).
                //            - Return null and let the DefaultLoadContext handle it. It may come back here due to fallback logic, but
                //              ultimately it will unify on the runtime version.

                if (TryLoadRuntimeAssembly(assemblyName, scriptRuntimeAssembly, out assembly))
                {
                    // Scenarios 1 and 2(a).
                    return(assembly);
                }
                else
                {
                    if (assembly == null || !isNameAdjusted)
                    {
                        // Scenario 2 and 3(a).
                        return(null);
                    }

                    AssemblyName runtimeAssemblyName = AssemblyNameCache.GetName(assembly);
                    if (assemblyName.Version > runtimeAssemblyName.Version)
                    {
                        // Scenario 3(b)(i).
                        return(LoadCore(assemblyName));
                    }

                    // Scenario 3(b)(ii).
                    return(null);
                }
            }

            // If the assembly being requested matches a host assembly, we'll use
            // the host assembly instead of loading it in this context:
            if (TryLoadHostEnvironmentAssembly(assemblyName, out assembly))
            {
                return(assembly);
            }

            return(LoadCore(assemblyName));
        }