internal static WebHostSettings CreateDefault(ScriptSettingsManager settingsManager)
        {
            WebHostSettings settings = new WebHostSettings
            {
                IsSelfHost = !settingsManager.IsAppServiceEnvironment && !settingsManager.IsLinuxContainerEnvironment
            };

            if (settingsManager.IsAppServiceEnvironment)
            {
                // Running in App Service
                string home = settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteHomePath);
                settings.ScriptPath   = Path.Combine(home, "site", "wwwroot");
                settings.LogPath      = Path.Combine(home, "LogFiles", "Application", "Functions");
                settings.SecretsPath  = Path.Combine(home, "data", "Functions", "secrets");
                settings.TestDataPath = Path.Combine(home, "data", "Functions", "sampledata");
            }
            else
            {
                // Local hosting or Linux container scenarios
                settings.ScriptPath   = settingsManager.GetSetting(EnvironmentSettingNames.AzureWebJobsScriptRoot);
                settings.LogPath      = Path.Combine(Path.GetTempPath(), @"Functions");
                settings.TestDataPath = Path.Combine(Path.GetTempPath(), @"FunctionsData");

                // TODO: Revisit. We'll likely have to take an instance of an IHostingEnvironment here
                settings.SecretsPath = Path.Combine(AppContext.BaseDirectory, "Secrets");
            }

            if (string.IsNullOrEmpty(settings.ScriptPath))
            {
                throw new InvalidOperationException("Unable to determine function script root directory.");
            }

            return(settings);
        }
Example #2
0
        internal static WebHostSettings CreateDefault(ScriptSettingsManager settingsManager)
        {
            WebHostSettings settings = new WebHostSettings
            {
                IsSelfHost = !settingsManager.IsAzureEnvironment
            };

            if (settingsManager.IsAzureEnvironment)
            {
                string home = settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteHomePath);
                settings.ScriptPath  = Path.Combine(home, @"site\wwwroot");
                settings.LogPath     = Path.Combine(home, @"LogFiles\Application\Functions");
                settings.SecretsPath = Path.Combine(home, @"data\Functions\secrets");
            }
            else
            {
                settings.ScriptPath  = settingsManager.GetSetting(EnvironmentSettingNames.AzureWebJobsScriptRoot);
                settings.LogPath     = Path.Combine(Path.GetTempPath(), @"Functions");
                settings.SecretsPath = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/Secrets");
            }

            if (string.IsNullOrEmpty(settings.ScriptPath))
            {
                throw new InvalidOperationException("Unable to determine function script root directory.");
            }

            return(settings);
        }
Example #3
0
        private static WebHostSettings GetDefaultSettings(ScriptSettingsManager settingsManager)
        {
            WebHostSettings settings = new WebHostSettings();

            string home    = settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteHomePath);
            bool   isLocal = string.IsNullOrEmpty(home);

            if (isLocal)
            {
                settings.ScriptPath  = settingsManager.GetSetting(EnvironmentSettingNames.AzureWebJobsScriptRoot);
                settings.LogPath     = Path.Combine(Path.GetTempPath(), @"Functions");
                settings.SecretsPath = HttpContext.Current.Server.MapPath("~/App_Data/Secrets");
            }
            else
            {
                // we're running in Azure
                settings.ScriptPath  = Path.Combine(home, @"site\wwwroot");
                settings.LogPath     = Path.Combine(home, @"LogFiles\Application\Functions");
                settings.SecretsPath = Path.Combine(home, @"data\Functions\secrets");
            }

            if (string.IsNullOrEmpty(settings.ScriptPath))
            {
                throw new InvalidOperationException("Unable to determine function script root directory.");
            }

            return(settings);
        }
            public TestEnvironment()
            {
                _settingsManager     = ScriptSettingsManager.Instance;
                _prevHome            = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteHomePath);
                _prevPlaceholderMode = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsitePlaceholderMode);
                _prevInstanceId      = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteInstanceId);

                _home = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(_home);
                _settingsManager.SetSetting(EnvironmentSettingNames.AzureWebsiteHomePath, _home);

                Reset();
            }
        private static ScriptHostConfiguration GetScriptHostConfiguration(string scriptPath, string logPath)
        {
            string home = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteHomePath);

            if (!string.IsNullOrEmpty(home))
            {
                // Create the tools folder if it doesn't exist
                string toolsPath = Path.Combine(home, @"site\tools");
                Directory.CreateDirectory(toolsPath);
            }

            Directory.CreateDirectory(scriptPath);

            // Delete hostingstart.html if any. Azure creates that in all sites by default
            string hostingStart = Path.Combine(scriptPath, "hostingstart.html");

            if (File.Exists(hostingStart))
            {
                File.Delete(hostingStart);
            }

            var scriptHostConfig = new ScriptHostConfiguration()
            {
                RootScriptPath  = scriptPath,
                RootLogPath     = logPath,
                FileLoggingMode = FileLoggingMode.DebugOnly
            };

            // If running on Azure Web App, derive the host ID from the site name
            string hostId = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteName);

            if (!String.IsNullOrEmpty(hostId))
            {
                // Truncate to the max host name length if needed
                const int MaximumHostIdLength = 32;
                if (hostId.Length > MaximumHostIdLength)
                {
                    hostId = hostId.Substring(0, MaximumHostIdLength);
                }

                // Trim any trailing - as they can cause problems with queue names
                hostId = hostId.TrimEnd('-');

                scriptHostConfig.HostConfig.HostId = hostId.ToLowerInvariant();
            }

            return(scriptHostConfig);
        }
        private static void PrependFoldersToEnvironmentPath(ScriptSettingsManager settingsManager)
        {
            // Only do this when %HOME% is defined (normally on Azure)
            string home = settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteHomePath);

            if (!string.IsNullOrEmpty(home))
            {
                // Create the tools folder if it doesn't exist
                string toolsPath = Path.Combine(home, @"site\tools");
                Directory.CreateDirectory(toolsPath);

                var folders = new List <string>();
                folders.Add(Path.Combine(home, @"site\tools"));

                string path            = Environment.GetEnvironmentVariable("PATH");
                string additionalPaths = String.Join(";", folders);

                // Make sure we haven't already added them. This can happen if the appdomain restart (since it's still same process)
                if (!path.Contains(additionalPaths))
                {
                    path = additionalPaths + ";" + path;

                    Environment.SetEnvironmentVariable("PATH", path);
                }
            }
        }
 public SystemTraceWriter(IEventGenerator eventGenerator, ScriptSettingsManager settingsManager, TraceLevel level) : base(level)
 {
     _settingsManager = settingsManager;
     _appName         = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteName);
     _subscriptionId  = Utility.GetSubscriptionId();
     _eventGenerator  = eventGenerator;
 }
        internal ApplicationPerformanceCounters GetPerformanceCounters()
        {
            string json = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteAppCountersName);

            if (!string.IsNullOrEmpty(json))
            {
                try
                {
                    // TEMP: need to parse this specially to work around bug where
                    // sometimes an extra garbage character occurs after the terminal
                    // brace
                    int idx = json.LastIndexOf('}');
                    if (idx > 0)
                    {
                        json = json.Substring(0, idx + 1);
                    }

                    return(JsonConvert.DeserializeObject <ApplicationPerformanceCounters>(json));
                }
                catch (JsonReaderException ex)
                {
                    _traceWriter.Error($"Failed to deserialize application performance counters. JSON Content: \"{json}\"", ex);
                }
            }

            return(null);
        }
Example #9
0
        public IActionResult Assign([FromBody] EncryptedHostAssignmentContext encryptedAssignmentContext)
        {
            var containerKey      = _settingsManager.GetSetting(EnvironmentSettingNames.ContainerEncryptionKey);
            var assignmentContext = encryptedAssignmentContext.Decrypt(containerKey);

            return(_instanceManager.StartAssignment(assignmentContext)
                ? Accepted()
                : StatusCode(StatusCodes.Status409Conflict, "Instance already assigned"));
        }
Example #10
0
        private void SetVariables()
        {
            foreach (var item in _variables)
            {
                _existingVariables.Add(item.Key, _settingsManager.GetSetting(item.Key));

                _settingsManager.SetSetting(item.Key, item.Value);
            }
        }
Example #11
0
        private static bool IsEncryptionSupported()
        {
            if (_settingsManager.IsLinuxContainerEnvironment)
            {
                // TEMP: https://github.com/Azure/azure-functions-host/issues/3035
                return(false);
            }

            return(_settingsManager.IsAppServiceEnvironment || _settingsManager.GetSetting(AzureWebsiteLocalEncryptionKey) != null);
        }
Example #12
0
        private async Task ApplyContextIfPresent()
        {
            var startContext = _settingsManager.GetSetting(EnvironmentSettingNames.ContainerStartContext);

            // Container start context is not available directly
            if (string.IsNullOrEmpty(startContext))
            {
                // Check if the context is available in blob
                var sasUri = _settingsManager.GetSetting(EnvironmentSettingNames.ContainerStartContextSasUri);

                if (!string.IsNullOrEmpty(sasUri))
                {
                    _logger.LogInformation("Host context specified via CONTAINER_START_CONTEXT_SAS_URI");
                    startContext = await GetAssignmentContextFromSasUri(sasUri);
                }
            }
            else
            {
                _logger.LogInformation("Host context specified via CONTAINER_START_CONTEXT");
            }

            if (!string.IsNullOrEmpty(startContext))
            {
                _logger.LogInformation("Applying host context");

                var encryptedAssignmentContext = JsonConvert.DeserializeObject <EncryptedHostAssignmentContext>(startContext);
                var containerKey      = _settingsManager.GetSetting(EnvironmentSettingNames.ContainerEncryptionKey);
                var assignmentContext = encryptedAssignmentContext.Decrypt(containerKey);
                if (_instanceManager.StartAssignment(assignmentContext))
                {
                    _logger.LogInformation("Start assign HostAssignmentContext success");
                }
                else
                {
                    _logger.LogError("Start assign HostAssignmentContext failed");
                }
            }
            else
            {
                _logger.LogInformation("No host context specified. Waiting for host assignment");
            }
        }
Example #13
0
        public MetricsEventManager(ScriptSettingsManager settingsManager, IEventGenerator generator, int functionActivityFlushIntervalSeconds, int metricsFlushIntervalMS = DefaultFlushIntervalMS)
        {
            // we read these in the ctor (not static ctor) since it can change on the fly
            appName        = GetNormalizedString(settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteName)) ?? string.Empty;
            subscriptionId = Utility.GetSubscriptionId() ?? string.Empty;

            _eventGenerator = generator;
            _functionActivityFlushIntervalSeconds = functionActivityFlushIntervalSeconds;
            QueuedEvents = new ConcurrentDictionary <string, SystemMetricEvent>(StringComparer.OrdinalIgnoreCase);

            // Initialize the periodic log flush timer
            _metricsFlushTimer = new Timer(TimerFlush, null, metricsFlushIntervalMS, metricsFlushIntervalMS);
        }
        private static bool IsDisabled(JToken isDisabledValue)
        {
            if (isDisabledValue != null)
            {
                if (isDisabledValue.Type == JTokenType.Boolean && (bool)isDisabledValue)
                {
                    return(true);
                }
                else
                {
                    string settingName = (string)isDisabledValue;
                    string value       = _settingsManager.GetSetting(settingName);
                    if (!string.IsNullOrEmpty(value) &&
                        (string.Compare(value, "1", StringComparison.OrdinalIgnoreCase) == 0 ||
                         string.Compare(value, "true", StringComparison.OrdinalIgnoreCase) == 0))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        public ISecretsRepository Create(ScriptSettingsManager settingsManager, WebHostSettings webHostSettings, ScriptHostConfiguration config, ILogger logger)
        {
            string secretStorageType = settingsManager.GetSetting(EnvironmentSettingNames.AzureWebJobsSecretStorageType);
            string storageString     = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);

            if (secretStorageType != null && secretStorageType.Equals("Blob", StringComparison.OrdinalIgnoreCase) && storageString != null)
            {
                string siteSlotName = settingsManager.AzureWebsiteUniqueSlotName ?? config.HostConfig.HostId;
                return(new BlobStorageSecretsMigrationRepository(Path.Combine(webHostSettings.SecretsPath, "Sentinels"), storageString, siteSlotName, logger));
            }
            else
            {
                return(new FileSystemSecretsRepository(webHostSettings.SecretsPath));
            }
        }
Example #16
0
        private string GetJobBasePath()
        {
            string home     = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteHomePath);
            string basePath = null;

            if (!string.IsNullOrEmpty(home))
            {
                basePath = Path.Combine(home, "data", "Functions", "extensions");
            }
            else
            {
                basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".azurefunctions", "extensions");
            }
            return(basePath);
        }
        private void OnHostInitializing(object sender, EventArgs e)
        {
            // by the time this event is raised, loggers for the host
            // have been initialized
            var    host             = (ScriptHost)sender;
            string extensionVersion = _settingsManager.GetSetting(EnvironmentSettingNames.FunctionsExtensionVersion);
            string hostId           = host.ScriptConfig.HostConfig.HostId;
            string message          = $"Starting Host (HostId={hostId}, InstanceId={host.InstanceId}, Version={ScriptHost.Version}, ProcessId={Process.GetCurrentProcess().Id}, AppDomainId={AppDomain.CurrentDomain.Id}, Debug={host.InDebugMode}, ConsecutiveErrors={_consecutiveErrorCount}, StartupCount={_hostStartCount}, FunctionsExtensionVersion={extensionVersion})";

            host.Logger.LogInformation(message);

            // we check host health before starting to avoid starting
            // the host when connection or other issues exist
            IsHostHealthy(throwWhenUnhealthy: true);
        }
        public static string GetSubscriptionId(ScriptSettingsManager settingsManager)
        {
            string ownerName = settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteOwnerName) ?? string.Empty;

            if (!string.IsNullOrEmpty(ownerName))
            {
                int idx = ownerName.IndexOf('+');
                if (idx > 0)
                {
                    return(ownerName.Substring(0, idx));
                }
            }

            return(null);
        }
        public PackageAssemblyResolverTests()
        {
            _settingsManager        = ScriptSettingsManager.Instance;
            _runPath                = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
            _lockFilePath           = Path.Combine(_runPath, DotNetConstants.ProjectLockFileName);
            _oldHomeEnv             = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteHomePath);
            _targetAssemblyPath     = Path.Combine(_runPath, "data\\Functions\\packages\\nuget\\Test.Package\\1.0.0\\lib\\net45");
            _targetAssemblyFilePath = Path.Combine(_targetAssemblyPath, Path.GetFileName(this.GetType().Assembly.Location));
            Directory.CreateDirectory(_targetAssemblyPath);

            // Copy current assembly to target package reference location
            File.Copy(this.GetType().Assembly.Location, _targetAssemblyFilePath);

            // Create our Lock file using the current assembly as the target
            File.WriteAllText(_lockFilePath, string.Format(Resources.ProjectLockFileFormatString, Path.GetFileName(this.GetType().Assembly.Location)));

            _settingsManager.SetSetting(EnvironmentSettingNames.AzureWebsiteHomePath, _runPath);
        }
        protected async Task ApiHubTest()
        {
            // ApiHub for dropbox is enabled if the AzureWebJobsDropBox environment variable is set.
            // The format should be: Endpoint={endpoint};Scheme={scheme};AccessToken={accesstoken}
            // or to use the local file system the format should be: UseLocalFileSystem=true;Path={path}
            string apiHubConnectionString = SettingsManager.GetSetting("AzureWebJobsDropBox");

            if (string.IsNullOrEmpty(apiHubConnectionString))
            {
                throw new ApplicationException("Missing AzureWebJobsDropBox environment variable.");
            }

            string testBlob   = "teste2e";
            string apiHubFile = "teste2e/test.txt";
            var    resultBlob = Fixture.TestOutputContainer.GetBlockBlobReference(testBlob);

            resultBlob.DeleteIfExists();

            var root = ItemFactory.Parse(apiHubConnectionString);

            if (await root.FileExistsAsync(apiHubFile))
            {
                var file = root.GetFileReference(apiHubFile);
                await file.DeleteAsync();
            }

            // Test both writing and reading from ApiHubFile.
            // First, manually invoke a function that has an output binding to write to Dropbox.
            string testData = Guid.NewGuid().ToString();

            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "input", testData },
            };
            await Fixture.Host.CallAsync("ApiHubFileSender", arguments);

            // Second, there's an ApiHubFile trigger which will write a blob.
            // Once the blob is written, we know both sender & listener are working.
            // TODO: removing the BOM character from result.
            string result = (await TestHelpers.WaitForBlobAndGetStringAsync(resultBlob)).Remove(0, 1);

            Assert.Equal(testData, result);
        }
Example #21
0
        public async Task <IActionResult> Assign([FromBody] EncryptedHostAssignmentContext encryptedAssignmentContext)
        {
            var containerKey      = _settingsManager.GetSetting(EnvironmentSettingNames.ContainerEncryptionKey);
            var assignmentContext = encryptedAssignmentContext.Decrypt(containerKey);

            // before starting the assignment we want to perform as much
            // up front validation on the context as possible
            string error = await _instanceManager.ValidateContext(assignmentContext);

            if (error != null)
            {
                return(StatusCode(StatusCodes.Status400BadRequest, error));
            }

            var result = _instanceManager.StartAssignment(assignmentContext);

            return(result
                ? Accepted()
                : StatusCode(StatusCodes.Status409Conflict, "Instance already assigned"));
        }
        internal ApplicationPerformanceCounters GetPerformanceCounters()
        {
            string json = _settingsManager.GetSetting(EnvironmentSettingNames.AzureWebsiteAppCountersName);

            if (!string.IsNullOrEmpty(json))
            {
                // TEMP: need to parse this specially to work around bug where
                // sometimes an extra garbage character occurs after the terminal
                // brace
                int idx = json.LastIndexOf('}');
                if (idx > 0)
                {
                    json = json.Substring(0, idx + 1);
                }

                return(JsonConvert.DeserializeObject <ApplicationPerformanceCounters>(json));
            }

            return(null);
        }
 private static bool IsEncryptionSupported() => _settingsManager.IsAzureEnvironment || _settingsManager.GetSetting(AzureWebsiteLocalEncryptionKey) != null;
        public void RunAndBlock(CancellationToken cancellationToken = default(CancellationToken))
        {
            int consecutiveErrorCount = 0;

            do
            {
                ScriptHost newInstance = null;

                try
                {
                    // if we were in an error state retain that,
                    // otherwise move to default
                    if (State != ScriptHostState.Error)
                    {
                        State = ScriptHostState.Default;
                    }

                    OnCreatingHost();

                    // Create a new host config, but keep the host id from existing one
                    _config.HostConfig = new JobHostConfiguration(_settingsManager.Configuration)
                    {
                        HostId = _config.HostConfig.HostId
                    };
                    OnInitializeConfig(_config);
                    newInstance = _scriptHostFactory.Create(_environment, EventManager, _settingsManager, _config, _loggerFactoryBuilder);
                    newInstance.HostInitialized += OnHostInitialized;
                    newInstance.HostStarted     += OnHostStarted;
                    _traceWriter = newInstance.TraceWriter;
                    _logger      = newInstance.Logger;

                    _currentInstance = newInstance;
                    lock (_liveInstances)
                    {
                        _liveInstances.Add(newInstance);
                        _hostStartCount++;
                    }

                    string extensionVersion = _settingsManager.GetSetting(EnvironmentSettingNames.FunctionsExtensionVersion);
                    string hostId           = newInstance.ScriptConfig.HostConfig.HostId;
                    string message          = $"Starting Host (HostId={hostId}, Version={ScriptHost.Version}, ProcessId={Process.GetCurrentProcess().Id}, Debug={newInstance.InDebugMode}, ConsecutiveErrors={consecutiveErrorCount}, StartupCount={_hostStartCount}, FunctionsExtensionVersion={extensionVersion})";
                    _traceWriter?.Info(message);
                    _logger?.LogInformation(message);

                    newInstance.StartAsync(cancellationToken).GetAwaiter().GetResult();

                    // log any function initialization errors
                    LogErrors(newInstance);

                    LastError                = null;
                    consecutiveErrorCount    = 0;
                    _restartDelayTokenSource = null;

                    // Wait for a restart signal. This event will automatically reset.
                    // While we're restarting, it is possible for another restart to be
                    // signaled. That is fine - the restart will be processed immediately
                    // once we get to this line again. The important thing is that these
                    // restarts are only happening on a single thread.
                    WaitHandle.WaitAny(new WaitHandle[]
                    {
                        cancellationToken.WaitHandle,
                        _restartHostEvent,
                        _stopEvent
                    });

                    // Orphan the current host instance. We're stopping it, so it won't listen for any new functions
                    // it will finish any currently executing functions and then clean itself up.
                    // Spin around and create a new host instance.
                    Task.Run(() => Orphan(newInstance)
                             .ContinueWith(t =>
                    {
                        if (t.IsFaulted)
                        {
                            t.Exception.Handle(e => true);
                        }
                    }, TaskContinuationOptions.ExecuteSynchronously));
                }
                catch (Exception ex)
                {
                    State     = ScriptHostState.Error;
                    LastError = ex;
                    consecutiveErrorCount++;

                    // We need to keep the host running, so we catch and log any errors
                    // then restart the host
                    string message = "A ScriptHost error has occurred";
                    _traceWriter?.Error(message, ex);
                    _logger?.LogError(0, ex, message);

                    // If a ScriptHost instance was created before the exception was thrown
                    // Orphan and cleanup that instance.
                    if (newInstance != null)
                    {
                        Task.Run(() => Orphan(newInstance, forceStop: true)
                                 .ContinueWith(t =>
                        {
                            if (t.IsFaulted)
                            {
                                t.Exception.Handle(e => true);
                            }
                        }, TaskContinuationOptions.ExecuteSynchronously));
                    }

                    // attempt restarts using an exponential backoff strategy
                    CreateRestartBackoffDelay(consecutiveErrorCount).GetAwaiter().GetResult();
                }
            }while (!_stopped && !cancellationToken.IsCancellationRequested);
        }