예제 #1
0
        /// <summary>
        /// Writes the module blocks for any modules this module refers to.
        /// </summary>
        /// <returns>Task to await.</returns>
        public async Task WriteModuleBlocksAsync()
        {
            var modulesFile = Path.Combine(this.ModuleDirectory, TerraformExporterConstants.ModulesFile);

            if (File.Exists(modulesFile))
            {
                // In case we removed all pre-existing submodule references
                File.Delete(modulesFile);
            }

            if (!this.NestedModules.Any())
            {
                return;
            }

            using (var fs = AsyncFileHelpers.OpenWriteAsync(modulesFile))
                using (var writer = new StreamWriter(fs, AsyncFileHelpers.DefaultEncoding))
                {
                    foreach (var module in this.NestedModules)
                    {
                        var sb = new StringBuilder().AppendLine($"module \"{module.Name}\" {{").AppendLine(
                            $"  source = \"./{module.Settings.ModuleDirectory.Replace('\\', '/')}\"");

                        if (module.IsImported)
                        {
                            // We can only emit module arguments once the module has been imported and
                            // corresponding "variable" declarations are visible to Terraform command.
                            foreach (var input in module.Inputs.Where(i => !(i.IsDataSource || i is PseudoParameterInput)))
                            {
                                sb.AppendLine($"  {input.GenerateVariableAssignment()}");
                            }
                        }

                        sb.AppendLine("}");

                        await writer.WriteLineAsync(sb.ToString());
                    }
                }
        }
예제 #2
0
        /// <summary>
        /// Processes the stack asynchronous.
        /// </summary>
        /// <returns>Module describing entire tree of nested stacks.</returns>
        public async Task <ModuleInfo> ProcessStackAsync()
        {
            if (this.settings.ExportNestedStacks)
            {
                return(await ProcessChildModule(this.settings, this.warnings));
            }

            this.settings.Logger.LogInformation($"Processing stack {this.settings.StackName}...");

            using (var fs = AsyncFileHelpers.OpenAppendAsync(TerraformExporterConstants.MainScriptFile))
                using (var writer = new StreamWriter(fs, AsyncFileHelpers.DefaultEncoding))
                {
                    var module = new ModuleInfo(
                        this.settings,
                        null,
                        new InputVariableProcessor(this.settings, this.warnings).ProcessInputs(),
                        null);

                    await module.ProcessResources(writer, this.warnings);

                    return(module);
                }
        }
예제 #3
0
        /// <summary>
        /// Performs Terraform export.
        /// </summary>
        /// <returns><c>true</c> if resources were imported; else <c>false</c></returns>
        public async Task <bool> Export()
        {
            this.settings.Logger.LogInformation("\nInitializing inputs and resources...");

            using (new WorkingDirectoryContext(this.settings.WorkspaceDirectory))
            {
                var configurationBlocks = new ConfigurationBlockBuilder().WithRegion(this.settings.AwsRegion)
                                          .WithDefaultTag(this.settings.AddDefaultTag ? this.settings.StackName : null).WithZipper(
                    this.settings.Template.Resources.Any(
                        r => r.Type == TerraformExporterConstants.AwsLambdaFunction &&
                        r.GetResourcePropertyValue(TerraformExporterConstants.LambdaZipFile) != null)).Build();


                // Write out terraform and provider blocks.
                using (var writer = new StreamWriter(TerraformExporterConstants.MainScriptFile))
                {
                    await writer.WriteLineAsync(configurationBlocks);
                }

                // Gather and write out initial stack resources
                var mapper     = new ResourceMapper(this.settings, this.warnings);
                var rootModule = await mapper.ProcessStackAsync();

                var allModules = rootModule?.DescendentsAndThis().ToList();

                if (rootModule == null || !allModules.Any())
                {
                    this.settings.Logger.LogWarning("No resources were found that could be imported.");
                    return(false);
                }

                var terraformExecutionErrorCount = 0;
                var warningCount = 0;

                try
                {
                    this.InitializeWorkspace();

                    foreach (var module in allModules)
                    {
                        var importedResources = await module.ImportResources(this.warnings, this.errors);

                        if (!this.settings.ExportNestedStacks)
                        {
                            // If leaving nested stacks as aws_cloudformation_stack, then fix up S3 locations of these.
                            await this.FixCloudFormationStacksAsync(importedResources);
                        }

                        var stateFile = JsonConvert.DeserializeObject <StateFile>(
                            await AsyncFileHelpers.ReadAllTextAsync(this.stateFilePath));

                        var writer = new HclWriter(module, this.warnings, this.errors);

                        warningCount += await writer.Serialize(stateFile);

                        this.settings.Logger.LogInformation(
                            $"\nExport of stack \"{module.Settings.StackName}\" to terraform complete!");
                    }
                }
                catch (TerraformRunnerException e)
                {
                    // Errors already reported by output of terraform
                    terraformExecutionErrorCount += e.Errors;
                    warningCount += e.Warnings;
                    throw;
                }
                catch (HclSerializerException e)
                {
                    this.errors.Add(e.Message);
                    throw;
                }
                catch (Exception e)
                {
                    this.errors.Add($"ERROR: Internal error: {e.Message}");
                    throw;
                }
                finally
                {
                    this.WriteSummary(terraformExecutionErrorCount, warningCount);
                }
            }

            return(true);
        }
예제 #4
0
        /// <summary>
        /// Recursively process nested stacks.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="warnings">The warnings.</param>
        /// <returns>Module being processed.</returns>
        private static async Task <ModuleInfo> ProcessChildModule(
            ITerraformExportSettings settings,
            IList <string> warnings)
        {
            var childModules = new List <ModuleInfo>();

            foreach (var child in settings.Resources.Where(
                         r => r.ResourceType == TerraformExporterConstants.AwsCloudFormationStack))
            {
                var logicalId = child.LogicalResourceId;
                var stackName = GetStackName(child.StackResource.PhysicalResourceId);
                var stackData = await StackHelper.ReadStackAsync(
                    settings.CloudFormationClient,
                    stackName,
                    new Dictionary <string, object>());

                var childModuleSettings = settings.CopyWith(
                    stackData.Template,
                    stackData.Resources,
                    stackData.Outputs,
                    stackName,
                    Path.Combine("modules", stackName),
                    logicalId);

                childModules.Add(await ProcessChildModule(childModuleSettings, warnings));
            }

            var workingDirectory = Path.Combine(settings.WorkspaceDirectory, settings.ModuleDirectory);

            if (!Directory.Exists(workingDirectory))
            {
                Directory.CreateDirectory(workingDirectory);
            }

            settings.Logger.LogInformation($"Processing stack {settings.StackName}...");
            var scriptFile = Path.Combine(workingDirectory, TerraformExporterConstants.MainScriptFile);

            ModuleInfo module;

            using (var fs = settings.IsRootModule ? AsyncFileHelpers.OpenAppendAsync(scriptFile) : AsyncFileHelpers.OpenWriteAsync(scriptFile))
                using (var writer = new StreamWriter(fs, AsyncFileHelpers.DefaultEncoding))
                {
                    var thisModuleSettings = settings.CopyWith(
                        settings.Template,
                        settings.Resources.Where(r => r.ResourceType != TerraformExporterConstants.AwsCloudFormationStack),
                        null,
                        settings.StackName,
                        settings.IsRootModule ? "." : settings.ModuleDirectory,
                        settings.LogicalId);

                    module = new ModuleInfo(
                        thisModuleSettings,
                        childModules,
                        new InputVariableProcessor(thisModuleSettings, warnings).ProcessInputs(),
                        thisModuleSettings.CloudFormationOutputs);

                    await module.ProcessResources(writer, warnings);
                }

            await module.WriteModuleBlocksAsync();

            return(module);
        }