Exemplo n.º 1
0
        public async Task <(bool, string)> GetRuntimeToken(string armId)
        {
            string siteName          = armId.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault();
            var    getAppSettingsUrl = $"{armId}/config/appsettings/list";

            // Dictionary<string, string> is all we need from app settings.
            var maybeAppSettings = await _client.Post <ArmResource <Dictionary <string, string> > >(getAppSettingsUrl, AntaresApiVersion);

            if (!maybeAppSettings.IsSuccessful)
            {
                return(false, await maybeAppSettings.Error.Content.ReadAsStringAsync());
            }
            else
            {
                var appSettings = maybeAppSettings.Result;
                var diagResults = new List <DiagnosticsResult>();
                var machineKey  = appSettings.Properties.FirstOrDefault(k => k.Key.Equals("MACHINEKEY_DecryptionKey", StringComparison.OrdinalIgnoreCase));

                if (string.IsNullOrEmpty(machineKey.Key) || string.IsNullOrEmpty(machineKey.Value))
                {
                    using (var aes = new AesManaged())
                    {
                        aes.GenerateKey();
                        var key = BitConverter.ToString(aes.Key).Replace("-", "");
                        appSettings.Properties.Add("MACHINEKEY_DecryptionKey", key);
                        var setAppSettingsUrl = $"{armId}/config/appsettings";
                        var result            = await _client.Put <ArmResource <Dictionary <string, string> > >(setAppSettingsUrl, AntaresApiVersion, appSettings);

                        if (result.IsSuccessful)
                        {
                            return(true, GetRuntimeToken(siteName, key));
                        }
                        else
                        {
                            return(false, await result.Error.Content.ReadAsStringAsync());
                        }
                    }
                }
                else
                {
                    return(true, GetRuntimeToken(siteName, machineKey.Value));
                }
            }
        }
        /// <summary>
        /// If an app setting goes missing for any reason, make sure to alert the user regarding it.
        /// The method isn't really very smart since every app setting has a different message and a different action, etc.
        /// I didn't wanna complicate the logic too much for 4 app settings.
        /// <param name="functionApp"> function app to check the app settings for. </param>
        /// </summary>
        private async Task <TypedPair <ArmResource <Dictionary <string, string> > > > CheckAppSettings(ArmResource <ArmFunctionApp> functionApp)
        {
            var armId = $"{functionApp.Id}/config/appsettings/list";
            // Dictionary<string, string> is all we need from app settings.
            var maybeAppSettings = await _client.Post <ArmResource <Dictionary <string, string> > >(armId, AntaresApiVersion);

            if (!maybeAppSettings.IsSuccessful)
            {
                return(new TypedPair <ArmResource <Dictionary <string, string> > >(HandleArmResponseError(armId, maybeAppSettings.Error), null));
            }
            else
            {
                var appSettings = maybeAppSettings.Result;
                var diagResults = new List <DiagnosticsResult>();

                if (!appSettings.Properties.Any(k => k.Key.Equals(AzureWebJobsStorageAppSetting, StringComparison.OrdinalIgnoreCase)))
                {
                    diagResults.Add(new DiagnosticsResult
                    {
                        IsDiagnosingSuccessful = true,
                        SuccessResult          = new DiagnoseSuccessResult
                        {
                            IsTerminating = true,
                            Message       = string.Format("'{0}' application setting is missing from your app. This setting contains a connection string for an Azure Storage account that is needed for the functions runtime to handle multiple instances synchronization, log invocation results, and other infrastructure jobs. Your function app will not work correctly without that setting.", AzureWebJobsStorageAppSetting),
                            UserAction    = "Create the app setting with a valid storage connection string.",
                            ActionId      = ActionIds.MissingAzureWebjobsStorageAppSetting
                        }
                    });
                }

                if (!appSettings.Properties.Any(k => k.Key.Equals(FunctionsExtensionVersionAppSetting, StringComparison.OrdinalIgnoreCase)))
                {
                    diagResults.Add(new DiagnosticsResult
                    {
                        IsDiagnosingSuccessful = true,
                        SuccessResult          = new DiagnoseSuccessResult
                        {
                            Message    = string.Format("'{0}' application setting is missing from your app. Without this setting you'll always be running the latest version of the runtime even across major version updates which might contain breaking changes. It's advised to set that value to the current latest major version (~1) and you'll get notified with newer versions for update.", FunctionsExtensionVersionAppSetting),
                            UserAction = string.Format("Create the app setting and add a valid version. Latest current version is {0}", Constants.CurrentLatestRuntimeVersion),
                            ActionId   = ActionIds.MissingFunctionsExtensionVersionAppSetting
                        }
                    });
                }

                if (functionApp.Properties.Sku.Equals("Dynamic", StringComparison.OrdinalIgnoreCase) &&
                    !appSettings.Properties.Any(k => k.Key.Equals(AzureFilesConnectionString, StringComparison.OrdinalIgnoreCase)))
                {
                    diagResults.Add(new DiagnosticsResult
                    {
                        IsDiagnosingSuccessful = true,
                        SuccessResult          = new DiagnoseSuccessResult
                        {
                            IsTerminating = true,
                            Message       = string.Format("'{0}' application setting is missing from your app. This setting contains a connection string for an Azure Storage account that is used to host your functions content. Your app will be completely broken without this setting.", AzureFilesConnectionString),
                            UserAction    = "You may need to delete and recreate this function app if you no longer have access to the value of that application setting.",
                            ActionId      = ActionIds.MissingAzureFilesConnectionString
                        }
                    });
                }

                if (functionApp.Properties.Sku.Equals("Dynamic", StringComparison.OrdinalIgnoreCase) &&
                    !appSettings.Properties.Any(k => k.Key.Equals(AzureFilesContentShare, StringComparison.OrdinalIgnoreCase)))
                {
                    diagResults.Add(new DiagnosticsResult
                    {
                        IsDiagnosingSuccessful = true,
                        SuccessResult          = new DiagnoseSuccessResult
                        {
                            IsTerminating = true,
                            Message       = string.Format("'{0}' application setting is missing from your app. This setting contains a share name where your function content lives. Your app will be completely broken without this setting.", AzureFilesContentShare),
                            UserAction    = "You may need to delete and recreate this function app if you no longer have access to the value of that application setting.",
                            ActionId      = ActionIds.MissingAzureFilesContentShare
                        }
                    });
                }

                return(new TypedPair <ArmResource <Dictionary <string, string> > >(diagResults, appSettings));
            }
        }