private void Awake() { if (instance == null) { instance = this; } }
public async Task ListAsync(Settings settings) { if (!await PopulateDeploymentTierSettingsAsync(settings, requireBucketName: false, requireCoreServices: false, requireVersionCheck: false)) { return; } // gather module details var tierManager = new TierManager(settings); var moduleDetails = await tierManager.GetModuleDetailsAsync(); // sort and format output if (moduleDetails.Any()) { Console.WriteLine(); Console.WriteLine($"Found {moduleDetails.Count():N0} modules for deployment tier {Settings.InfoColor}{tierManager.TierName}{Settings.ResetColor}"); Console.WriteLine(); tierManager.ShowModuleDetails( moduleDetails.OrderBy(module => module.DeploymentDate), (ColumnTitle: "NAME", GetColumnValue: module => module.ModuleDeploymentName), (ColumnTitle: "MODULE", GetColumnValue: module => module.ModuleReference), (ColumnTitle: "STATUS", GetColumnValue: module => module.StackStatus), (ColumnTitle: "DATE", GetColumnValue: module => module.DeploymentDate.ToString("yyyy-MM-dd HH:mm:ss")) ); } else { Console.WriteLine(); Console.WriteLine($"Found no modules for deployment tier {Settings.InfoColor}{tierManager.TierName}{Settings.ResetColor}"); } }
private void ShowModuleDetails(TierManager tierManager, IEnumerable <TierModuleDetails> moduleDetails) { tierManager.ShowModuleDetails( moduleDetails.OrderBy(module => module.ModuleDeploymentName), (ColumnTitle: "NAME", GetColumnValue: module => module.ModuleDeploymentName), (ColumnTitle: "MODULE", GetColumnValue: module => module.ModuleReference), (ColumnTitle: "STATUS", GetColumnValue: module => module.StackStatus), (ColumnTitle: "CORE-SERVICES", GetColumnValue: module => module.CoreServices?.ToUpperInvariant() ?? "N/A") ); }
void OnInitialize(EventArgs e) { #region Config string path = Path.Combine(TShock.SavePath, "CTRSystem", "CTRS-Config.json"); Config = Configuration.ConfigFile.Read(path); Formatter = new TextFormatter(this, Config); #endregion #region Commands Commands = new CommandManager(this); Action <Command> Add = c => { TShockAPI.Commands.ChatCommands.RemoveAll(c2 => c2.Names.Exists(s => c.Names.Contains(s))); TShockAPI.Commands.ChatCommands.Add(c); }; Add(new Command(Permissions.Admin, Commands.CAdmin, "cadmin") { HelpText = "Perform administrative actions across the Contributions Track & Reward System." }); Add(new Command(Permissions.Commands, Commands.Contributions, new List <string>(Config.AdditionalCommandAliases) { "ctrs" }.ToArray()) { HelpText = "Manages contributor settings. You must have contributed at least once before using this command." }); Add(new Command(Permissions.Auth, Commands.Authenticate, "auth", "authenticate") { DoLog = false, HelpText = "Connects your Xenforo account to your TShock account. Enter your forum credentials OR generate an auth code first by visiting your user control panel." }); #endregion _tierUpdateTimer = new Timer(Config.TierRefreshMinutes * 60 * 1000); _tierUpdateTimer.Elapsed += UpdateTiers; _tierUpdateTimer.Start(); Contributors = new ContributorManager(this); CredentialHelper = new LoginManager(this); Rests = new RestManager(this); Tiers = new TierManager(this); XenforoUsers = new XenforoManager(this); }
public MenuItemMasterViewModel() { TableDropDown tdd = new TableDropDown(); LocationList = tdd.SetLocationDropDown(); StoreList = tdd.SetStoreDropDown(); MenuItemMasterList = new List <MenuItem>(); MenuRecipeList = new List <MenuRecipe>(); TierList = TierManager.SetTierList(); TradingAreaList = tdd.SetTradingAreaList(); CategoryList = tdd.SetCategoryList(); MIMFGCList = tdd.SetPMGList("PMGFGC"); MIMHPTList = tdd.SetPMGList("PMGHPT"); MIMWGRList = tdd.SetPMGList("PMGWGR"); GroupList = tdd.SetGroupList(); MasterList = new List <MenuItemMasterViewModel>(); }
public async Task List(Settings settings) { if (!await PopulateDeploymentTierSettingsAsync(settings, requireBucketName: false, requireCoreServices: false, requireVersionCheck: false)) { return; } // gather module details var tierManager = new TierManager(settings); var moduleDetails = await tierManager.GetModuleDetailsAsync(); // sort and format output tierManager.ShowModuleDetails( moduleDetails.OrderBy(module => module.DeploymentDate), (ColumnTitle: "NAME", GetColumnValue: module => module.ModuleDeploymentName), (ColumnTitle: "MODULE", GetColumnValue: module => module.ModuleReference), (ColumnTitle: "STATUS", GetColumnValue: module => module.StackStatus), (ColumnTitle: "DATE", GetColumnValue: module => module.DeploymentDate.ToString("yyyy-MM-dd HH:mm:ss")) ); }
//--- Methods --- public void Register(CommandLineApplication app) { app.Command("tier", cmd => { cmd.HelpOption(); cmd.Description = "Tier utility commands"; // function sub-command cmd.Command("coreservices", subCmd => { subCmd.HelpOption(); subCmd.Description = "Enable/disable LambdaSharp.Core services for all modules in tier"; // command options var enabledOption = subCmd.Option("--enabled", "(optional) Enable LambdaSharp.Core services for all modules", CommandOptionType.NoValue); var disabledOption = subCmd.Option("--disabled", "(optional) Disable LambdaSharp.Core services for all modules", CommandOptionType.NoValue); var initSettingsCallback = CreateSettingsInitializer(subCmd); AddStandardCommandOptions(subCmd); subCmd.OnExecute(async() => { ExecuteCommandActions(subCmd); var settings = await initSettingsCallback(); if (settings == null) { return; } if (enabledOption.HasValue() && disabledOption.HasValue()) { LogError("--enabled and --disabled options are mutually exclusive"); return; } bool?enabled = null; if (enabledOption.HasValue()) { enabled = true; } else if (disabledOption.HasValue()) { enabled = false; } await UpdateCoreServicesAsync(settings, enabled, showModules: true); }); }); // check tier version cmd.Command("version", subCmd => { subCmd.HelpOption(); subCmd.Description = "Check Tier Version"; var minVersionOption = subCmd.Option("--min-version", "(optional) Minimum expected version", CommandOptionType.SingleValue); var initSettingsCallback = CreateSettingsInitializer(subCmd); AddStandardCommandOptions(subCmd); // run command subCmd.OnExecute(async() => { ExecuteCommandActions(subCmd); var settings = await initSettingsCallback(); if (settings == null) { return(-1); } // fetch tier information if (!await PopulateDeploymentTierSettingsAsync(settings, optional: true)) { if (!Program.Quiet) { Console.WriteLine(); Console.WriteLine($"No deployment tier found {Settings.OutputColor}[ExitCode: 2]{Settings.ResetColor}"); } return(2); } // validate options if (minVersionOption.Value() == null) { Console.WriteLine(); Console.WriteLine($"Deployment tier version: {Settings.InfoColor}{settings.TierVersion}{Settings.ResetColor}"); return(0); } else { if (!VersionInfo.TryParse(minVersionOption.Value(), out var minVersion)) { LogError("invalid value for --min-version option"); return(-1); } // compare version numbers var exitCode = settings.TierVersion.IsGreaterOrEqualThanVersion(minVersion) ? 0 : 1; if (!Program.Quiet) { Console.WriteLine(); Console.WriteLine($"Deployment tier version: {Settings.InfoColor}{settings.TierVersion} {Settings.OutputColor}[ExitCode: {exitCode}]{Settings.ResetColor}"); } return(exitCode); } }); }); // check tier version cmd.Command("list", subCmd => { subCmd.HelpOption(); subCmd.Description = "List all available deployment tiers"; // command options var initSettingsCallback = CreateSettingsInitializer(subCmd); AddStandardCommandOptions(subCmd); subCmd.OnExecute(async() => { ExecuteCommandActions(subCmd); var settings = await initSettingsCallback(); if (settings == null) { return; } // gather module details var tierManager = new TierManager(settings); var tierDetails = await tierManager.GetDeploymentTierDetailsAsync(); if (tierDetails.Any()) { Console.WriteLine(); Console.WriteLine($"Found {tierDetails.Count():N0} deployment tiers"); Console.WriteLine(); tierManager.ShowModuleDetails( tierDetails.OrderBy(module => module.DeploymentTierName), (ColumnTitle: "TIER", GetColumnValue: module => module.DeploymentTierName), (ColumnTitle: "VERSION", GetColumnValue: module => ModuleInfo.TryParse(module.ModuleReference, out var moduleInfo) ? moduleInfo.Version.ToString() : module.ModuleReference), (ColumnTitle: "STATUS", GetColumnValue: module => module.StackStatus), (ColumnTitle: "CORE-SERVICES", GetColumnValue: module => module.CoreServices?.ToUpperInvariant() ?? "N/A") ); }
public async Task UpdateCoreServicesAsync(Settings settings, bool?enabled, bool showModules) { if (!await PopulateDeploymentTierSettingsAsync(settings, requireBucketName: false, requireCoreServices: false, requireVersionCheck: false)) { return; } // gather module details var tierManager = new TierManager(settings); var moduleDetails = (await tierManager.GetModuleDetailsAsync()) .OrderBy(details => details.ModuleDeploymentName) .ToList(); if (showModules) { ShowModuleDetails(tierManager, moduleDetails); } // check if tier has any stacks if (!moduleDetails.Any()) { return; } // validate that all modules in tier can enable/disable core services if (enabled.HasValue) { foreach (var details in moduleDetails) { if (details.CoreServices == null) { LogError($"${details.ModuleDeploymentName} does not support enabling/disabling LambdaSharp.Core services"); } else if (!enabled.Value && details.HasDefaultSecretKeyParameter) { LogError($"${details.ModuleDeploymentName} cannot disable LambdaSharp.Core services, because it depends on DefaultSecretKey"); } } } if (!enabled.HasValue || HasErrors) { return; } // update core services for each affected root module var coreServicesParameter = enabled.Value ? "Enabled" : "Disabled"; var modulesToUpdate = moduleDetails .Where(module => module.CoreServices != coreServicesParameter) .Where(module => module.IsRoot) .ToList(); if (!modulesToUpdate.Any()) { return; } Console.WriteLine($"=> {(enabled.Value ? "Enabling" : "Disabling")} modules in deployment tier '{settings.TierName}'"); var parameters = new Dictionary <string, string> { ["LambdaSharpCoreServices"] = coreServicesParameter }; foreach (var module in modulesToUpdate) { await UpdateStackParameters(settings, module, parameters); } Console.WriteLine(); // show updated state if (showModules) { ShowModuleDetails(tierManager, await tierManager.GetModuleDetailsAsync()); } }
public async Task NukeAsync(Settings settings, bool dryRun, bool confirmed) { if (!await PopulateDeploymentTierSettingsAsync(settings, requireBucketName: false, requireCoreServices: false, requireVersionCheck: false)) { return; } // gather module details Console.WriteLine($"=> Inspecting deployment tier {Settings.InfoColor}{settings.TierName}{Settings.ResetColor}"); var tierManager = new TierManager(settings); // enumerate all non-nested (root) stack that in a completed update state var moduleDetails = (await tierManager.GetModuleDetailsAsync(includeCoreModule: true)) .Where(module => module.StackStatus.EndsWith("_COMPLETE") && (module.StackStatus != "DELETE_COMPLETE")) .ToList(); if (!moduleDetails.Any()) { Console.WriteLine($"=> Found no modules to delete"); return; } var count = moduleDetails.Count(module => module.IsRoot); if (count == 1) { Console.WriteLine($"=> Found 1 CloudFormation stack to delete"); } else { Console.WriteLine($"=> Found {count:N0} CloudFormation stacks to delete"); } // confirm action with user if not already confirmed and this is not a dry run if (!confirmed && !dryRun) { // list what is about to be deleted Console.WriteLine(); foreach (var module in moduleDetails .Where(module => module.IsRoot) .OrderBy(module => module.ModuleDeploymentName) ) { Console.WriteLine($" {Settings.InfoColor}{module.ModuleDeploymentName}{Settings.ResetColor}"); } // confirm deployment tier name Console.WriteLine(); if (settings.PromptString("Confirm the deployment tier name to delete") != settings.TierName) { LogError("deployment tier name does not match"); return; } // confirm action one more time if (!settings.PromptYesNo($"Proceed with deleting deployment tier '{settings.TierName}'", defaultAnswer: false)) { Console.WriteLine("=> Canceling deletion of deployment tier"); return; } Console.WriteLine(); } // discover all dependencies var dependencies = new Dictionary <string, HashSet <string> >(); foreach (var module in moduleDetails) { var dependents = new HashSet <string>(); dependencies.Add(module.StackName, dependents); // enumerate each exported value foreach (var output in module.Stack.Outputs.Where(output => output.ExportName != null)) { // discover which stacks are importing it try { var imports = await settings.CfnClient.ListImportsAsync(new ListImportsRequest { ExportName = output.ExportName }); foreach (var import in imports.Imports) { dependents.Add(import); } } catch (AmazonCloudFormationException e) when(e.Message == $"Export '{output.ExportName}' is not imported by any stack.") { // nothing to do } } } // iteratively delete the stacks var bucketsToDelete = new List <string>(); for (var i = 0; moduleDetails.Any() && (i < MAX_ITERATIONS); ++i) { foreach (var module in moduleDetails.Where(module => module.IsRoot).ToList()) { var stackName = module.StackName; // skip stacks that still have dependents if (dependencies[stackName].Any()) { Settings.LogInfoVerbose($"... skipping due to active dependencies: {stackName}"); continue; } if ((module.DeploymentBucketArn != null) && (moduleDetails.Count > 1)) { // don't delete the LambdaSharp.Core stack until all other modules have been deleted continue; } // show progress Console.WriteLine($"=> Deleting {Settings.InfoColor}{stackName}{Settings.ResetColor}"); if (!dryRun) { // check if this is the LambdaSharp.Core stack if (module.DeploymentBucketArn != null) { var resources = await settings.CfnClient.GetStackResourcesAsync(module.StackName); // check if this stack created its own deployment bucket var deploymentBucketName = resources.FirstOrDefault(resource => resource.LogicalResourceId == "DeploymentBucketResource")?.PhysicalResourceId; if (deploymentBucketName != null) { await DeleteBucketContentsAsync(settings, "deployment bucket", deploymentBucketName); bucketsToDelete.Add(deploymentBucketName); } // check if this stack created its own logging bucket var loggingBucketName = resources.FirstOrDefault(resource => resource.LogicalResourceId == "LoggingBucketResource")?.PhysicalResourceId; if (loggingBucketName != null) { await DeleteBucketContentsAsync(settings, "logging bucket", loggingBucketName); bucketsToDelete.Add(loggingBucketName); } } // delete stack var mostRecentStackEventId = await settings.CfnClient.GetMostRecentStackEventIdAsync(stackName); var oldNameMappings = await new ModelManifestLoader(settings, "source").GetNameMappingsFromCloudFormationStackAsync(stackName); await settings.CfnClient.DeleteStackAsync(new DeleteStackRequest { StackName = stackName }); var outcome = await settings.CfnClient.TrackStackUpdateAsync( stackName, module.Stack.StackId, mostRecentStackEventId, nameMappings : null, oldNameMappings, LogError ); // confirm that stack is deleted var stackEventsResponse = await settings.CfnClient.DescribeStackEventsAsync(new DescribeStackEventsRequest { StackName = module.Stack.StackId }); var success = (stackEventsResponse.StackEvents.First().ResourceStatus == ResourceStatus.DELETE_COMPLETE); if (!success) { Console.WriteLine("=> Stack delete FAILED"); LogError($"unable to delete {stackName}"); return; } Console.WriteLine("=> Stack delete finished"); } // remove this stack and its children from the list of stacks to delete RecursiveRemoveFromModuleDetails(module); } } // delete any left over buckets, such as the logging bucket which has 'Retain' as deletion policy if (bucketsToDelete.Any()) { Console.WriteLine(); foreach (var bucketName in bucketsToDelete) { if (await settings.S3Client.DoesS3BucketExistAsync(bucketName)) { try { Console.WriteLine($"=> Deleting S3 Bucket {Settings.InfoColor}{bucketName}{Settings.ResetColor}"); await settings.S3Client.DeleteBucketAsync(bucketName); } catch { LogWarn($"unable to delete S3 bucket: {bucketName}"); } } } } // local functions void RecursiveRemoveFromModuleDetails(TierModuleDetails moduleToRemove) { // remove this stack as a dependent from all dependencies foreach (var dependency in dependencies) { dependency.Value.Remove(moduleToRemove.StackName); } // find all child modules of the module to remove foreach (var childModule in moduleDetails.Where(module => module.Stack.RootId == moduleToRemove.Stack.StackId).ToList()) { RecursiveRemoveFromModuleDetails(childModule); } // remove module from list moduleDetails.RemoveAll(moduleDetail => moduleDetail.StackName == moduleToRemove.StackName); } }