Skip to content
This repository was archived by the owner on Apr 13, 2020. It is now read-only.

Commit 8e49f8c

Browse files
authored
HCL file generation for spk infra scaffold (#83)
* generates `input` block for variables in Terragrunt HCL file.
1 parent c7ecb5f commit 8e49f8c

File tree

6 files changed

+315
-9
lines changed

6 files changed

+315
-9
lines changed

docs/cloud-infra-management.md

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ spk infra scaffold|s [options]
7676
> `spk infra scaffold --name discovery-service --source https://github.com/microsoft/bedrock --version "0.0.1" --template /microsoft/bedrock/cluster/environments/azure-simple`
7777
7878
Options:
79+
--hcl Generate HCL definition file (terragrunt.hcl)
7980
-n, --name <name> Cluster name for scaffolding
8081
-s, --source <cluster definition github repo> Source URL for the repository containing the terraform deployment
8182
-v, --version <repository version> Version or tag for the repository so a fixed version is referenced
@@ -91,11 +92,13 @@ spk infra scaffold --name discovery-service --source https://github.com/microsof
9192

9293
Output:
9394

94-
```
95+
definition.json
96+
97+
```json
9598
{
9699
"name": "discovery-service",
97100
"source": "https://github.com/microsoft/bedrock",
98-
"template": "bedrock/cluster/environments/azure-simple",
101+
"template": "bedrock/cluster/environments/azure-simple",
99102
"version": "0.0.1",
100103
"variables": {
101104
"agent_vm_count": "3",
@@ -127,3 +130,36 @@ Output:
127130
}
128131
}
129132
```
133+
134+
terrgrunt.hcl
135+
136+
```
137+
inputs = {
138+
agent_vm_count = "3"
139+
agent_vm_size = "Standard_D2s_v3"
140+
acr_enabled = "true"
141+
gc_enabled = "true"
142+
cluster_name = ""
143+
dns_prefix = ""
144+
flux_recreate = ""
145+
kubeconfig_recreate = ""
146+
gitops_ssh_url = ""
147+
gitops_ssh_key = ""
148+
gitops_path = ""
149+
gitops_url_branch = "master"
150+
resource_group_name = ""
151+
ssh_public_key = ""
152+
service_principal_id = ""
153+
service_principal_secret = ""
154+
gitops_poll_interval = "5m"
155+
vnet_name = ""
156+
service_cidr = "10.0.0.0/16"
157+
dns_ip = "10.0.0.10"
158+
docker_cidr = "172.17.0.1/16"
159+
address_space = "10.10.0.0/16"
160+
subnet_prefix = "10.10.1.0/24"
161+
network_plugin = "azure"
162+
network_policy = "azure"
163+
oms_agent_enabled = "false"
164+
}
165+
```

src/commands/infra/scaffold.test.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import {
33
enableVerboseLogging,
44
logger
55
} from "../../logger";
6-
import { generateClusterDefinition, parseVariablesTf } from "./scaffold";
6+
import {
7+
generateClusterDefinition,
8+
parseVariablesTf,
9+
scaffoldHcl
10+
} from "./scaffold";
711

812
beforeAll(() => {
913
enableVerboseLogging();
@@ -32,7 +36,7 @@ describe("Validate parsing of sample variables.tf file", () => {
3236
sampleVarTf
3337
);
3438
expect(Object.keys(fields).length).toBe(3);
35-
expect(fields.resource_group_name).toBe(null);
39+
expect(fields.resource_group_name).toBe("");
3640
expect(fields.gitops_poll_interval).toBe("5m");
3741
});
3842
});
@@ -63,3 +67,21 @@ describe("Validate generation of sample scaffold definition", () => {
6367
expect(def.variables.resource_group_name).toBe("<insert value>");
6468
});
6569
});
70+
71+
describe("Validate generation of a valid cluster HCL file", () => {
72+
test("Validate that a variables.tf sample can be parsed and translated to an HCL file", async () => {
73+
const mockFileName = "src/commands/mocks/azure-simple";
74+
const sampleVarTf = "src/commands/mocks/azure-simple/variables.tf";
75+
const value = await scaffoldHcl(mockFileName, sampleVarTf);
76+
expect(value).toBe(true);
77+
});
78+
});
79+
80+
describe("Failure testing for generation of a valid cluster HCL file", () => {
81+
test("Mocked a failed scenario of HCL generation", async () => {
82+
const mockFileName = "src/commands/mocks/azure-simple";
83+
const sampleVarTf = "src/commands/mocks/azure-simple";
84+
const value = await scaffoldHcl(mockFileName, sampleVarTf);
85+
expect(value).toBe(false);
86+
});
87+
});

src/commands/infra/scaffold.ts

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ 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")
3031
.action(async opts => {
3132
try {
3233
if (opts.name && opts.source && opts.version && opts.template) {
@@ -36,11 +37,23 @@ export const scaffoldCommandDecorator = (command: commander.Command): void => {
3637
"You must specify each of the variables 'name', 'source', 'version', 'template' in order to scaffold out a deployment."
3738
);
3839
}
39-
4040
await copyTfTemplate(opts.template, opts.name);
4141
await validateVariablesTf(path.join(opts.template, "variables.tf"));
4242
await renameTfvars(opts.name);
43-
await scaffoldInit(opts.name, opts.source, opts.version, opts.template);
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+
}
4457
} catch (err) {
4558
logger.error("Error occurred while generating scaffold");
4659
logger.error(err);
@@ -141,7 +154,7 @@ export const parseVariablesTf = (data: string) => {
141154
const blocks = data.split(splitRegex);
142155
// iterate through each 'block' and extract the variable name and any possible
143156
// default value. if no default value found, null is used in it's place
144-
const fields: { [name: string]: string | null } = {};
157+
const fields: { [name: string]: string | "" } = {};
145158
const fieldSplitRegex = /\"\s{0,}\{/;
146159
const defaultRegex = /default\s{0,}=\s{0,}(.*)/;
147160
blocks.forEach((b, idx) => {
@@ -160,7 +173,7 @@ export const parseVariablesTf = (data: string) => {
160173
}
161174
fields[elt[0]] = value;
162175
} else {
163-
fields[elt[0]] = null;
176+
fields[elt[0]] = "";
164177
}
165178
}
166179
});
@@ -200,7 +213,7 @@ export const generateClusterDefinition = (
200213
* @param bedrockVersion The version of the repo used
201214
* @param tfVariableFile Path to the variable file to parse
202215
*/
203-
export const scaffoldInit = async (
216+
export const scaffoldJson = async (
204217
name: string,
205218
bedrockSource: string,
206219
bedrockVersion: string,
@@ -244,3 +257,46 @@ export const scaffoldInit = async (
244257
}
245258
return false;
246259
};
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);
296+
} catch (err) {
297+
logger.error("Failed to create HCL file.");
298+
logger.error(err);
299+
return false;
300+
}
301+
return true;
302+
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
module "provider" {
2+
source = "github.com/microsoft/bedrock?ref=master//cluster/azure/provider"
3+
}
4+
5+
data "azurerm_resource_group" "cluster_rg" {
6+
name = "${var.resource_group_name}"
7+
}
8+
9+
module "vnet" {
10+
source = "github.com/microsoft/bedrock?ref=master//cluster/azure/vnet"
11+
12+
vnet_name = "${var.vnet_name}"
13+
address_space = "${var.address_space}"
14+
resource_group_name = "${data.azurerm_resource_group.cluster_rg.name}"
15+
subnet_names = ["${var.cluster_name}-aks-subnet"]
16+
subnet_prefixes = ["${var.subnet_prefix}"]
17+
18+
tags = {
19+
environment = "azure-simple"
20+
}
21+
}
22+
23+
module "aks-gitops" {
24+
source = "github.com/microsoft/bedrock?ref=master//cluster/azure/aks-gitops"
25+
26+
acr_enabled = "${var.acr_enabled}"
27+
agent_vm_count = "${var.agent_vm_count}"
28+
agent_vm_size = "${var.agent_vm_size}"
29+
cluster_name = "${var.cluster_name}"
30+
dns_prefix = "${var.dns_prefix}"
31+
flux_recreate = "${var.flux_recreate}"
32+
kubeconfig_recreate = "${var.kubeconfig_recreate}"
33+
gc_enabled = "${var.gc_enabled}"
34+
gitops_ssh_url = "${var.gitops_ssh_url}"
35+
gitops_ssh_key = "${var.gitops_ssh_key}"
36+
gitops_path = "${var.gitops_path}"
37+
gitops_poll_interval = "${var.gitops_poll_interval}"
38+
gitops_url_branch = "${var.gitops_url_branch}"
39+
ssh_public_key = "${var.ssh_public_key}"
40+
resource_group_name = "${data.azurerm_resource_group.cluster_rg.name}"
41+
service_principal_id = "${var.service_principal_id}"
42+
service_principal_secret = "${var.service_principal_secret}"
43+
vnet_subnet_id = "${tostring(element(module.vnet.vnet_subnet_ids, 0))}"
44+
service_cidr = "${var.service_cidr}"
45+
dns_ip = "${var.dns_ip}"
46+
docker_cidr = "${var.docker_cidr}"
47+
network_plugin = "${var.network_plugin}"
48+
network_policy = "${var.network_policy}"
49+
oms_agent_enabled = "${var.oms_agent_enabled}"
50+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
resource_group_name = "resource-group-name"
2+
cluster_name = "cluster-name"
3+
agent_vm_count = "3"
4+
dns_prefix = "dns-prefix"
5+
service_principal_id = "client-id"
6+
service_principal_secret = "client-secret"
7+
ssh_public_key = "public-key"
8+
gitops_ssh_url = "git@github.com:timfpark/fabrikate-cloud-native-manifests.git"
9+
gitops_ssh_key = "<path to private gitops repo key>"
10+
vnet_name = "<vnet name>"
11+
12+
#--------------------------------------------------------------
13+
# Optional variables - Uncomment to use
14+
#--------------------------------------------------------------
15+
# gitops_url_branch = "release-123"
16+
# gitops_poll_interval = "30s"
17+
# gitops_path = "prod"
18+
# network_policy = "calico"
19+
# oms_agent_enabled = "false"

0 commit comments

Comments
 (0)