@@ -27,7 +27,6 @@ export const scaffoldCommandDecorator = (command: commander.Command): void => {
2727 "-t, --template <path to variables.tf> " ,
2828 "Location of the variables.tf for the terraform deployment"
2929 )
30- . option ( "--hcl" , "Generates cluster definition HCL file" )
3130 . action ( async opts => {
3231 try {
3332 if ( opts . name && opts . source && opts . version && opts . template ) {
@@ -39,21 +38,8 @@ export const scaffoldCommandDecorator = (command: commander.Command): void => {
3938 }
4039 await copyTfTemplate ( opts . template , opts . name ) ;
4140 await validateVariablesTf ( path . join ( opts . template , "variables.tf" ) ) ;
41+ await scaffold ( opts . name , opts . source , opts . version , opts . template ) ;
4242 await renameTfvars ( opts . name ) ;
43- if ( opts . hcl ) {
44- logger . info ( "Generating HCL cluster definition file." ) ;
45- await scaffoldHcl (
46- opts . name ,
47- path . join ( opts . template , "variables.tf" )
48- ) ;
49- } else {
50- await scaffoldJson (
51- opts . name ,
52- opts . source ,
53- opts . version ,
54- opts . template
55- ) ;
56- }
5743 } catch ( err ) {
5844 logger . error ( "Error occurred while generating scaffold" ) ;
5945 logger . error ( err ) ;
@@ -64,7 +50,7 @@ export const scaffoldCommandDecorator = (command: commander.Command): void => {
6450/**
6551 * Checks if working variables.tf is present
6652 *
67- * @param templatePath Path the variables.tf file
53+ * @param templatePath Path to the variables.tf file
6854 */
6955export const validateVariablesTf = async (
7056 templatePath : string
@@ -77,7 +63,7 @@ export const validateVariablesTf = async (
7763 return false ;
7864 }
7965 logger . info (
80- `Terraform variables.tf file found. Attempting to generate definition JSON/HCL file.. .`
66+ `Terraform variables.tf file found. Attempting to generate definition.json file.`
8167 ) ;
8268 } catch ( _ ) {
8369 logger . error ( `Unable to validate Terraform variables.tf.` ) ;
@@ -87,15 +73,32 @@ export const validateVariablesTf = async (
8773} ;
8874
8975/**
90- * Rename any .tfvars file by appending ".backup"
76+ * Checks if backend.tfvars is present
77+ *
78+ * @param dir Path to the backend.tfvars file
79+ */
80+ export const validateBackendTfvars = async ( name : string ) : Promise < boolean > => {
81+ const backendConfig = path . join ( name , "backend.tfvars" ) ;
82+ logger . info ( backendConfig ) ;
83+ if ( fs . existsSync ( backendConfig ) ) {
84+ logger . info ( `A remote backend configuration was found : ${ backendConfig } ` ) ;
85+ return true ;
86+ } else {
87+ logger . info ( `No remote backend configuration was found.` ) ;
88+ return false ;
89+ }
90+ } ;
91+
92+ /**
93+ * Renames any .tfvars file by appending ".backup"
9194 *
9295 * @param dir path to template directory
9396 */
9497export const renameTfvars = async ( dir : string ) : Promise < void > => {
9598 try {
9699 const tfFiles = fs . readdirSync ( dir ) ;
97100 tfFiles . forEach ( file => {
98- if ( file . indexOf ( ".tfvars ") !== - 1 ) {
101+ if ( file . substr ( file . lastIndexOf ( ". ") + 1 ) === "tfvars" ) {
99102 fs . renameSync ( path . join ( dir , file ) , path . join ( dir , file + ".backup" ) ) ;
100103 }
101104 } ) ;
@@ -157,7 +160,7 @@ export const parseVariablesTf = (data: string) => {
157160 const fields : { [ name : string ] : string | "" } = { } ;
158161 const fieldSplitRegex = / \" \s { 0 , } \{ / ;
159162 const defaultRegex = / d e f a u l t \s { 0 , } = \s { 0 , } ( .* ) / ;
160- blocks . forEach ( ( b , idx ) => {
163+ blocks . forEach ( b => {
161164 b = b . trim ( ) ;
162165 const elt = b . split ( fieldSplitRegex ) ;
163166 elt [ 0 ] = elt [ 0 ] . trim ( ) . replace ( '"' , "" ) ;
@@ -180,11 +183,39 @@ export const parseVariablesTf = (data: string) => {
180183 return fields ;
181184} ;
182185
183- export const generateClusterDefinition = (
186+ /**
187+ * Parses and reformats the backend.tfvars
188+ *
189+ * @param backendTfvarData path to the directory of backend.tfvars
190+ */
191+ export const parseBackendTfvars = ( backendData : string ) => {
192+ const backend : { [ name : string ] : string | "" } = { } ;
193+ const block = backendData . replace ( / \= / g, ":" ) . split ( "\n" ) ;
194+ block . forEach ( b => {
195+ const elt = b . split ( ":" ) ;
196+ if ( elt [ 0 ] . length > 0 ) {
197+ backend [ elt [ 0 ] ] = elt [ 1 ] . replace ( / \" / g, "" ) ;
198+ }
199+ } ) ;
200+ return backend ;
201+ } ;
202+
203+ /**
204+ * Generates cluster definition as definition.json
205+ *
206+ * @param name name of destination directory
207+ * @param source git url of source repo
208+ * @param template name of Terraform environment
209+ * @param version a tag/branch/release of source repo
210+ * @param backendTfvars path to directory that contains backend.tfvars
211+ * @param vartfData path to the variables.tf file
212+ */
213+ export const generateClusterDefinition = async (
184214 name : string ,
185215 source : string ,
186216 template : string ,
187217 version : string ,
218+ backendData : string ,
188219 vartfData : string
189220) => {
190221 const fields : { [ name : string ] : string | null } = parseVariablesTf ( vartfData ) ;
@@ -194,6 +225,10 @@ export const generateClusterDefinition = (
194225 template,
195226 version
196227 } ;
228+ if ( backendData !== "" ) {
229+ const backend = parseBackendTfvars ( backendData ) ;
230+ def . backend = backend ;
231+ }
197232 if ( Object . keys ( fields ) . length > 0 ) {
198233 const fieldDict : { [ name : string ] : string | null } = { } ;
199234 Object . keys ( fields ) . forEach ( key => {
@@ -213,26 +248,33 @@ export const generateClusterDefinition = (
213248 * @param bedrockVersion The version of the repo used
214249 * @param tfVariableFile Path to the variable file to parse
215250 */
216- export const scaffoldJson = async (
251+ export const scaffold = async (
217252 name : string ,
218253 bedrockSource : string ,
219254 bedrockVersion : string ,
220255 template : string
221256) : Promise < boolean > => {
222257 try {
223258 const tfVariableFile = path . join ( name , "variables.tf" ) ;
259+ const backendTfvarsFile = path . join ( name , "backend.tfvars" ) ;
260+ const backendBool = await validateBackendTfvars ( name ) ;
261+ let backendData = "" ;
262+ if ( backendBool === true ) {
263+ backendData = fs . readFileSync ( backendTfvarsFile , "utf8" ) ;
264+ }
224265 // Identify which environment the user selected
225266 if ( fs . existsSync ( tfVariableFile ) ) {
226- logger . info ( `variables.tf file found : ${ tfVariableFile } ` ) ;
267+ logger . info ( `A variables.tf file found : ${ tfVariableFile } ` ) ;
227268 const data : string = fs . readFileSync ( tfVariableFile , "utf8" ) ;
228269 if ( data ) {
229270 const baseDef : {
230271 [ name : string ] : string | null | any ;
231- } = generateClusterDefinition (
272+ } = await generateClusterDefinition (
232273 name ,
233274 bedrockSource ,
234275 template ,
235276 bedrockVersion ,
277+ backendData ,
236278 data
237279 ) ;
238280 if ( baseDef ) {
@@ -252,51 +294,9 @@ export const scaffoldJson = async (
252294 logger . error ( `Unable to read variable file: ${ tfVariableFile } .` ) ;
253295 }
254296 }
255- } catch ( _ ) {
256- logger . warn ( "Unable to create scaffold" ) ;
257- }
258- return false ;
259- } ;
260-
261- export const generateHclClusterDefinition = ( vartfData : string ) => {
262- const data : string = fs . readFileSync ( vartfData , "utf8" ) ;
263- const fields : { [ name : string ] : string | "" | any } = parseVariablesTf ( data ) ;
264- const def : { [ name : string ] : string | "" | any } = { } ;
265- def . inputs = fields ;
266- return def ;
267- } ;
268-
269- /**
270- * This function creates a primary base Terragrunt HCL definition for
271- * generating cluster definitions from.
272- *
273- * @param name Name of the cluster definition
274- * @param vartfData Path to the variable.tf file to parse
275- */
276- export const scaffoldHcl = async (
277- dirName : string ,
278- vartfData : string
279- ) : Promise < boolean > => {
280- try {
281- const def = generateHclClusterDefinition ( vartfData ) ;
282- const confPath : string = path . format ( {
283- base : "terragrunt.hcl" ,
284- dir : dirName ,
285- root : "/ignored"
286- } ) ;
287- const hcl = JSON . stringify ( def , null , 2 )
288- . replace ( / \" ( [ ^ ( \" ) " ] + ) \" : / g, "$1:" )
289- . replace ( new RegExp ( ":" , "g" ) , " =" )
290- . replace ( new RegExp ( "," , "g" ) , " " )
291- . replace ( "{" , "" )
292- . replace ( / \} ( [ ^ } ] * ) $ / , "$1" )
293- . replace ( / ( ^ [ \t ] * \n ) / gm, "" )
294- . trim ( ) ;
295- fs . writeFileSync ( confPath , hcl ) ;
296297 } catch ( err ) {
297- logger . error ( "Failed to create HCL file. ") ;
298+ logger . warn ( "Unable to create scaffold ") ;
298299 logger . error ( err ) ;
299- return false ;
300300 }
301- return true ;
301+ return false ;
302302} ;
0 commit comments