@hiiretail/gcp-infra-cli 0.76.0 → 0.76.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@ const BaseGenerator = require('../../../src/BaseGenerator');
4
4
  const { chain, required } = require('../../../src/validators');
5
5
  const { getGcpProjects, validateGcpProjects } = require('./gcp-projects');
6
6
  const getTribeAndClanName = require('./tribe-clan-repo');
7
+ const validate = require('./validate');
7
8
 
8
9
  module.exports = class extends BaseGenerator {
9
10
  prompting() {
@@ -36,6 +37,12 @@ module.exports = class extends BaseGenerator {
36
37
  message: 'Provide the cost center your tribe belongs to',
37
38
  validate: required,
38
39
  },
40
+ {
41
+ type: 'input',
42
+ name: 'jiraProjectKey',
43
+ message: 'Provide the "jira project key" for your clan (the uppercase prefix in your task names, example: SRT)',
44
+ validate: required && validate.jiraProjectKey,
45
+ },
39
46
  {
40
47
  type: 'input',
41
48
  name: 'repoName',
@@ -12,4 +12,5 @@ locals {
12
12
  ]
13
13
  project_id_slack_token = "tf-admin-90301274"
14
14
  cost_center = "<%-costCenter%>"
15
+ jira_project_key = "<%-jiraProjectKey%>"
15
16
  }
@@ -0,0 +1,8 @@
1
+ const validate = {};
2
+
3
+ validate.jiraProjectKey = (input) => {
4
+ if (!/\s/.test(input) && input === input.toUpperCase()) return true;
5
+ return 'Must be uppercase and not contain any whitepace';
6
+ };
7
+
8
+ module.exports = validate;
@@ -0,0 +1,23 @@
1
+ names:
2
+ - "<%-bucketName%>"
3
+ prefix: "<%-prefix%>"
4
+ storage_class: "STANDARD" <% if (env == 'prod') { %>
5
+ location: "EU" <% } else { %>
6
+ location: "EUROPE-WEST1"<% } %>
7
+ versioning:
8
+ "<%-bucketName%>": <%-versioning%>
9
+ set_viewer_roles: true <% if (lifecycleRules == 'true') { %>
10
+ lifecycle_rules:
11
+ action:
12
+ type: "<%-action%>" <% if (action == 'SetStorageClass') { %>
13
+ storage_class: "<%-storageClass%>" <% } else { %>
14
+ storage_class: null <% } %>
15
+ condition:
16
+ age: <%-age%> <% if (createdBefore != 'null') { %>
17
+ created_before: "<%-createdBefore%>" <% } else { %>
18
+ created_before: null <% } %> <% if (withState != 'null') { %>
19
+ with_state: "<%-withState%>" <% } else { %>
20
+ with_state: null <% } %> <% if (matchesStorageClass != 'null') { %>
21
+ matches_storage_class: "<%-matchesStorageClass%>" <% } else { %>
22
+ matches_storage_class: null <% } %>
23
+ num_newer_versions: <%-numNewerVersions%> <% } %>
@@ -10,14 +10,13 @@ include {
10
10
  }
11
11
 
12
12
  locals {
13
- spec_vars = read_terragrunt_config("${get_terragrunt_dir()}/spec.hcl")
14
13
  project_vars = read_terragrunt_config(find_in_parent_folders("project.hcl"))
15
14
  common_vars = read_terragrunt_config(find_in_parent_folders("common.hcl"))
16
15
  }
17
16
 
18
17
  # These are the variables we have to pass in to use the module specified in the terragrunt configuration above
19
18
  inputs = merge(
20
- local.spec_vars.locals,
19
+ yamldecode(file("${get_terragrunt_dir()}/storage.yaml")),
21
20
  local.project_vars.locals,
22
21
  {
23
22
  project_id = local.project_vars.locals.project_id
@@ -0,0 +1,28 @@
1
+ const ejs = require('ejs');
2
+
3
+ const handleAlerts = (alerts, templates, answers) => {
4
+ const template = templates[`${answers.alertResource}`][`${answers.alert}`];
5
+ const newAlert = JSON.parse(ejs.render(JSON.stringify(template), answers));
6
+
7
+ alerts.push(newAlert);
8
+ return alerts;
9
+ };
10
+
11
+ const handleSlos = (slos, templates, answers) => {
12
+ const template = templates[`${answers.sli}`];
13
+ const newSLO = JSON.parse(ejs.render(JSON.stringify(template), answers));
14
+
15
+ if (answers.burnRateAlert === 'no') newSLO.alert = {};
16
+
17
+ slos.push(newSLO);
18
+ return slos;
19
+ };
20
+
21
+ const handleUptimeChecks = (slos, templates, answers) => {
22
+ const newCheck = JSON.parse(ejs.render(JSON.stringify(templates), answers));
23
+
24
+ slos.push(newCheck);
25
+ return slos;
26
+ };
27
+
28
+ module.exports = { handleAlerts, handleSlos, handleUptimeChecks };
@@ -4,12 +4,12 @@ const fs = require('fs');
4
4
  const yaml = require('js-yaml');
5
5
  const BaseGenerator = require('../../../src/BaseGenerator');
6
6
  const { required } = require('../../../src/validators');
7
- const validator = require('./validate');
8
- const handleSlosFile = require('./handle-slos');
9
- const handleUptimeFile = require('./handle-uptime');
10
- const handleAlerts = require('./handle-alerts');
7
+ const validate = require('./validate');
8
+ const { handleSlos, handleAlerts, handleUptimeChecks } = require('./handle-yaml');
11
9
 
10
+ const uptimeCheckTemplates = yaml.load(fs.readFileSync(`${__dirname}/templates/uptime-checks/uptime-checks.yaml`));
12
11
  const alertTemplates = yaml.load(fs.readFileSync(`${__dirname}/templates/alerts/alerts.yaml`));
12
+ const sloTemplates = yaml.load(fs.readFileSync(`${__dirname}/templates/slos/slos.yaml`));
13
13
 
14
14
  module.exports = class extends BaseGenerator {
15
15
  async prompting() {
@@ -37,7 +37,7 @@ module.exports = class extends BaseGenerator {
37
37
  type: 'input',
38
38
  name: 'systemName',
39
39
  message: 'Please provide three-letter system name as defined in Styra (example: sre, ptf, sda, che, pnp, iam...)',
40
- validate: required && validator.systemName,
40
+ validate: required && validate.systemName,
41
41
  },
42
42
  {
43
43
  when: (response) => ['slos', 'uptime-checks'].includes(response.monitoringResource) || response.alertResource === 'cloud_run',
@@ -51,7 +51,7 @@ module.exports = class extends BaseGenerator {
51
51
  type: 'input',
52
52
  name: 'runbookLink',
53
53
  message: 'Please provide the full URL to your runbook in confluence (Leave empty if none)',
54
- validate: required && validator.url,
54
+ validate: required && validate.url,
55
55
  },
56
56
  {
57
57
  when: (response) => response.alertResource === 'cloud_scheduler',
@@ -65,28 +65,28 @@ module.exports = class extends BaseGenerator {
65
65
  type: 'input',
66
66
  name: 'databaseId',
67
67
  message: 'Please provide the "database id"',
68
- validate: required && validator.databaseId,
68
+ validate: required && validate.databaseId,
69
69
  },
70
70
  {
71
71
  when: (response) => response.alertResource === 'memorystore',
72
72
  type: 'input',
73
73
  name: 'instanceId',
74
74
  message: 'Please provide the "instance id"',
75
- validate: required && validator.instanceID,
75
+ validate: required && validate.instanceID,
76
76
  },
77
77
  {
78
78
  when: (response) => response.alertResource === 'pub_sub',
79
79
  type: 'input',
80
80
  name: 'subscriptionId',
81
81
  message: 'Please provide the "subscription id"',
82
- validate: required && validator.pubSubSubscription,
82
+ validate: required && validate.pubSubSubscription,
83
83
  },
84
84
  {
85
85
  when: (response) => response.monitoringResource === 'uptime-checks',
86
86
  type: 'input',
87
87
  name: 'hostname',
88
88
  message: 'Please provide the base hostname of the service (example: my-service.retailsvc.com)',
89
- validate: required && validator.validHostname,
89
+ validate: required && validate.hostName,
90
90
  },
91
91
  {
92
92
  when: (response) => response.monitoringResource === 'uptime-checks',
@@ -101,132 +101,70 @@ module.exports = class extends BaseGenerator {
101
101
  type: 'list',
102
102
  name: 'sli',
103
103
  message: 'Please select the SLI',
104
- choices: ['availability', 'error-rate', 'latency'],
104
+ choices: Object.keys(sloTemplates),
105
+ },
106
+ {
107
+ when: (response) => response.monitoringResource === 'slos' && response.sli === 'availability',
108
+ type: 'input',
109
+ name: 'uptimeCheckId',
110
+ message: 'Please provide the "Uptime Check ID" (NOTE: The "Uptime check" needs to have been created first in order to fetch the ID)',
111
+ validate: required,
105
112
  },
106
113
  {
107
114
  when: (response) => response.monitoringResource === 'slos',
108
115
  type: 'list',
109
- name: 'burnRateAlerts',
116
+ name: 'burnRateAlert',
110
117
  message: 'Please select yes if you want to have burn-rate alerts included',
111
118
  default: 'yes',
112
119
  choices: ['yes', 'no'],
113
120
  },
114
- {
115
- when: (response) => response.monitoringResource === 'slos' && response.sli === 'availability',
116
- type: 'confirm',
117
- name: 'info',
118
- message: 'WARNING: Make sure an uptime check has been created BEFORE continuing with the creation of this SLO.',
119
- },
120
121
  ]);
121
122
  }
122
123
 
123
124
  async writing() {
124
- const {
125
- monitoringResource,
126
- serviceName,
127
- hostname,
128
- sli,
129
- systemName,
130
- burnRateAlerts,
131
- } = this.answers;
125
+ const { monitoringResource, serviceName } = this.answers;
126
+ const resourceDir = path.join(process.cwd(), 'infra', 'prod', 'monitoring', monitoringResource);
132
127
 
133
- const resourcePath = path.join(process.cwd(), 'infra', 'prod', 'monitoring', monitoringResource);
128
+ const copyTemplate = (resource, resourcePath, yamlPath) => {
129
+ if (!fs.existsSync(resourcePath)) fs.mkdirSync(resourcePath, { recursive: true });
130
+ if (!fs.existsSync(yamlPath)) fs.writeFileSync(yamlPath, '');
131
+ if (!fs.existsSync(`${path}/terragrunt.hcl`)) {
132
+ this.fs.copyTpl(
133
+ this.templatePath(`${resource}/terragrunt.hcl`),
134
+ this.destinationPath(`${resourcePath}/terragrunt.hcl`),
135
+ this.answers,
136
+ );
137
+ }
138
+ };
134
139
 
135
140
  if (monitoringResource === 'uptime-checks') {
136
- if (!fs.existsSync(resourcePath)) {
137
- fs.mkdirSync(resourcePath, { recursive: true });
138
- }
141
+ const yamlPath = `${resourceDir}/uptime-checks.yaml`;
139
142
 
140
- const uptimeYamlFile = `${resourcePath}/uptime-checks.yaml`;
141
- if (!fs.existsSync(uptimeYamlFile)) {
142
- this.copyDir(
143
- 'uptime-checks',
144
- resourcePath,
145
- {
146
- ...this.answers,
147
- serviceName,
148
- hostname,
149
- systemName,
150
- },
151
- );
152
- } else {
153
- await handleUptimeFile(this.answers, uptimeYamlFile);
154
- }
143
+ copyTemplate('uptime-checks', resourceDir, yamlPath);
144
+
145
+ const oldYaml = yaml.load(fs.readFileSync(yamlPath, 'utf8')) || [];
146
+ const newYaml = await handleUptimeChecks(oldYaml, uptimeCheckTemplates, this.answers);
147
+
148
+ fs.writeFileSync(yamlPath, yaml.dump(newYaml));
155
149
  }
156
150
 
157
151
  if (monitoringResource === 'slos') {
158
- const serviceFolderName = serviceName.replace(/ /g, '-').toLowerCase();
159
- const serviceDir = path.join(process.cwd(), 'infra', 'prod', 'monitoring', monitoringResource, serviceFolderName);
160
- const fileContainsFilter = (fileName, str) => {
161
- const contents = fs.readFileSync(fileName, 'utf-8');
162
- const result = contents.includes(str);
163
- return result;
164
- };
165
-
166
- if (!fs.existsSync(serviceDir)) {
167
- fs.mkdirSync(serviceDir, { recursive: true });
168
- }
152
+ const service = serviceName.replace(/ /g, '-').toLowerCase();
153
+ const servicePath = path.join(process.cwd(), 'infra', 'prod', 'monitoring', monitoringResource, service);
154
+ const yamlPath = `${servicePath}/slos.yaml`;
169
155
 
170
- if (fs.existsSync(`${serviceDir}/terragrunt.hcl`)) {
171
- if (fileContainsFilter(`${serviceDir}/terragrunt.hcl`, 'metric_filter') === false) {
172
- this.fs.copyTpl(
173
- this.templatePath('slos/terragrunt.hcl'),
174
- this.destinationPath(`${serviceDir}/terragrunt.hcl`),
175
- {
176
- ...this.answers,
177
- monitoringResource,
178
- serviceName,
179
- systemName,
180
- burnRateAlerts,
181
- },
182
- );
183
- }
184
- } else {
185
- this.fs.copyTpl(
186
- this.templatePath('slos/terragrunt.hcl'),
187
- this.destinationPath(`${serviceDir}/terragrunt.hcl`),
188
- {
189
- ...this.answers,
190
- monitoringResource,
191
- serviceName,
192
- systemName,
193
- burnRateAlerts,
194
- },
195
- );
196
- }
156
+ copyTemplate('slos', servicePath, yamlPath);
197
157
 
198
- const sloYamlFile = `${serviceDir}/slos.yaml`;
199
- if (!fs.existsSync(sloYamlFile)) {
200
- this.fs.copyTpl(
201
- this.templatePath('slos/slos.yaml'),
202
- this.destinationPath(sloYamlFile),
203
- {
204
- ...this.answers,
205
- monitoringResource,
206
- serviceName,
207
- systemName,
208
- sli,
209
- burnRateAlerts,
210
- },
211
- );
212
- } else {
213
- await handleSlosFile(this.answers, sloYamlFile);
214
- }
158
+ const oldYaml = yaml.load(fs.readFileSync(yamlPath, 'utf8')) || [];
159
+ const newYaml = await handleSlos(oldYaml, sloTemplates, this.answers);
160
+
161
+ fs.writeFileSync(yamlPath, yaml.dump(newYaml));
215
162
  }
216
163
 
217
164
  if (monitoringResource === 'alerts') {
218
- const yamlPath = `${resourcePath}/alerts.yaml`;
219
- const terraPath = `${resourcePath}/terragrunt.hcl`;
220
- if (!fs.existsSync(resourcePath)) fs.mkdirSync(resourcePath, { recursive: true });
221
- if (!fs.existsSync(yamlPath)) fs.writeFileSync(yamlPath, '');
165
+ const yamlPath = `${resourceDir}/alerts.yaml`;
222
166
 
223
- if (!fs.existsSync(terraPath)) {
224
- this.fs.copyTpl(
225
- this.templatePath('alerts/terragrunt.hcl'),
226
- this.destinationPath(terraPath),
227
- this.answers,
228
- );
229
- }
167
+ copyTemplate('alerts', resourceDir, yamlPath);
230
168
 
231
169
  const oldYaml = yaml.load(fs.readFileSync(yamlPath, 'utf8')) || [];
232
170
  const newYaml = await handleAlerts(oldYaml, alertTemplates, this.answers);
@@ -23,11 +23,12 @@ locals {
23
23
 
24
24
  # These are the variables we have to pass in to use the module specified in the terragrunt configuration above
25
25
  inputs = {
26
- monitoring_project_id = local.project_vars.locals.monitoring_project_id,
26
+ monitoring_project_id = lookup(local.project_vars.locals, "monitoring_project_id", local.project_vars.locals.tribe_project_id),
27
27
  notification_channels = dependency.notification_channels.outputs.notification_channels,
28
28
  policies = yamldecode(file("${get_terragrunt_dir()}/alerts.yaml")),
29
29
  user_labels = {
30
- cc = local.common_vars.locals.cost_center
31
- clan = local.common_vars.locals.clan_name
30
+ cc = local.common_vars.locals.cost_center
31
+ clan = local.common_vars.locals.clan_name
32
+ jira_project_key = lookup(local.common_vars.locals, "jira_project_key", null)
32
33
  },
33
34
  }
@@ -1,35 +1,41 @@
1
- <% if (sli === 'latency') { %>- display_name: Month - Latency
2
- slo_id: month-latency
3
- goal: 0.95
4
- calendar_period: MONTH
5
- type: request_based_sli
6
- method: distribution_cut
7
- metric_filter: |-
8
- metric.type="knative.dev/serving/revision/request_latencies"
9
- resource.type="knative_revision"
10
- resource.labels.service_name="<%-serviceName%>"
11
- range_min: 0
12
- range_max: 100<% if (burnRateAlerts === 'no') { %>
13
- alert: {}<% } %><% } %><% if (sli === 'availability') { %>- display_name: Month - Availability
1
+ availability:
2
+ display_name: Month - Availability
14
3
  slo_id: month-availability
15
- goal: 0.998
4
+ goal: 0.999
16
5
  calendar_period: MONTH
17
6
  type: windows_based_sli
18
7
  method: boolean_filter
19
- window_period: 60s<% if (burnRateAlerts === 'no') { %>
20
- alert: {}<% } %><% } %><% if (sli === 'error-rate') { %>- display_name: Month - Error rate
8
+ window_period: 60s
9
+ metric_filter: |
10
+ metric.type="monitoring.googleapis.com/uptime_check/check_passed"
11
+ resource.type="uptime_url"
12
+ metric.labels.check_id="<%-uptimeCheckId%>"
13
+ error-rate:
14
+ display_name: Month - Error rate
21
15
  slo_id: month-error-rate
22
16
  goal: 0.999
23
17
  calendar_period: MONTH
24
18
  type: request_based_sli
25
19
  method: good_total_ratio
26
- bad_service_filter: |-
20
+ bad_service_filter: |
27
21
  metric.type="knative.dev/serving/revision/request_count"
28
22
  resource.type="knative_revision"
29
23
  metric.labels.response_code_class="5xx"
30
24
  resource.labels.service_name="<%-serviceName%>"
31
- total_service_filter: |-
25
+ total_service_filter: |
32
26
  metric.type="knative.dev/serving/revision/request_count"
33
27
  resource.type="knative_revision"
34
- resource.labels.service_name="<%-serviceName%>"<% if (burnRateAlerts === 'no') { %>
35
- alert: {}<% } %><% } %>
28
+ resource.labels.service_name="<%-serviceName%>"
29
+ latency:
30
+ display_name: Month - Latency
31
+ slo_id: month-latency
32
+ goal: 0.95
33
+ calendar_period: MONTH
34
+ type: request_based_sli
35
+ method: distribution_cut
36
+ range_min: 0
37
+ range_max: 100
38
+ metric_filter: |
39
+ metric.type="knative.dev/serving/revision/request_latencies"
40
+ resource.type="knative_revision"
41
+ resource.labels.service_name="<%-serviceName%>"
@@ -9,10 +9,10 @@ include {
9
9
  path = find_in_parent_folders("terragrunt_root.hcl")
10
10
  }
11
11
 
12
- dependency "uptimecheck_id" {
13
- config_path = "../../uptime-checks"
12
+ dependency "notification_channels" {
13
+ config_path = "../../notification-channels"
14
14
  mock_outputs = {
15
- uptime_check_ids = ["dummy-id"]
15
+ notification_channels = ["dummy-channel"]
16
16
  }
17
17
  }
18
18
 
@@ -25,13 +25,9 @@ inputs = merge(
25
25
  local.project_vars.locals,
26
26
  {
27
27
  service_name = "<%-systemName%>.<%-serviceName%>"
28
+ monitoring_project_id = lookup(local.project_vars.locals, "monitoring_project_id", local.project_vars.locals.tribe_project_id),
29
+ notification_channels = dependency.notification_channels.outputs.notification_channels,
30
+ telemetry_resource_name = "//container.googleapis.com/projects/${lookup(local.project_vars.locals, "monitoring_project_id", local.project_vars.locals.tribe_project_id)}/locations/europe-west1/clusters/k8s-cluster/k8s/namespaces/<%-serviceName%>"
28
31
  slos = yamldecode(file("${get_terragrunt_dir()}/slos.yaml")),
29
- telemetry_resource_name = "//container.googleapis.com/projects/${local.project_vars.locals.monitoring_project_id}/locations/europe-west1/clusters/k8s-cluster/k8s/namespaces/<%-serviceName%>"
30
- <% if (sli === 'availability') { %>
31
- metric_filter = {
32
- "metric.type" = "monitoring.googleapis.com/uptime_check/check_passed"
33
- "resource.type" = "uptime_url"
34
- "metric.labels.check_id" = dependency.uptimecheck_id.outputs.uptime_check_ids["<%-systemName%>.<%-serviceName%>"]
35
- }<% } %>
36
32
  }
37
33
  )
@@ -26,11 +26,13 @@ inputs = merge(
26
26
  local.project_vars.locals,
27
27
  local.common_vars.locals,
28
28
  {
29
- notification_channels = dependency.notification_channels.outputs.notification_channels
30
- uptime_checks = yamldecode(file("${get_terragrunt_dir()}/uptime-checks.yaml")),
31
- labels = {
32
- clan = local.common_vars.locals.clan_name
33
- cc = local.common_vars.locals.cost_center
29
+ monitoring_project_id = lookup(local.project_vars.locals, "monitoring_project_id", local.project_vars.locals.tribe_project_id),
30
+ notification_channels = dependency.notification_channels.outputs.notification_channels
31
+ uptime_checks = yamldecode(file("${get_terragrunt_dir()}/uptime-checks.yaml")),
32
+ labels = {
33
+ clan = local.common_vars.locals.clan_name
34
+ cc = local.common_vars.locals.cost_center
35
+ jira_project_key = lookup(local.project_vars.locals, "jira_project_key", null)
34
36
  }
35
37
  }
36
38
  )
@@ -1,3 +1,3 @@
1
- - service_name: <%-systemName%>.<%-serviceName%>
2
- hostname: <%-hostname%>
3
- path: <%-path%>
1
+ service_name: <%-systemName%>.<%-serviceName%>
2
+ hostname: <%-hostname%>
3
+ path: <%-path%>
@@ -1,40 +1,38 @@
1
- const validator = {};
1
+ const validate = {};
2
2
 
3
- validator.hostName = (input) => {
3
+ const hasWhitespace = (str) => /\s/.test(str);
4
+
5
+ validate.hostName = (input) => {
4
6
  const regex = new RegExp(/^(?:[a-z-]+\.){1,3}[a-z-]+$/g);
5
- if (input.match(regex)) {
6
- return true;
7
- }
7
+ if (input.match(regex)) return true;
8
8
  return 'Hostname must not include path to the page to run the check against or spaces';
9
9
  };
10
10
 
11
- validator.systemName = (input) => {
12
- if (input.replace(/\s/g, '').length === 3) {
13
- return true;
14
- }
11
+ validate.systemName = (input) => {
12
+ if (input.length === 3 && !hasWhitespace(input)) return true;
15
13
  return 'System name must be 3 characters';
16
14
  };
17
15
 
18
- validator.url = (input) => {
16
+ validate.url = (input) => {
19
17
  // eslint-disable-next-line no-useless-escape
20
18
  const regex = new RegExp(/^https:\/\/[a-zA-Z]*.[a-zA-Z]*.[a-zA-Z]*\/[a-zA-Z\/+_-]*.$/g);
21
- if (regex.test(input) || input === '') return true;
19
+ if ((regex.test(input) && !hasWhitespace(input)) || input === '') return true;
22
20
  return 'You must enter a valid URL';
23
21
  };
24
22
 
25
- validator.instanceID = (input) => {
26
- if (input.split('/').length === 6) return true;
23
+ validate.instanceID = (input) => {
24
+ if (input.split('/').length === 6 && !hasWhitespace(input)) return true;
27
25
  return 'You must enter the full instance path (example: projects/example/locations/europe-west1/instances/instanceID)';
28
26
  };
29
27
 
30
- validator.databaseId = (input) => {
31
- if (input.split(':').length === 2) return true;
28
+ validate.databaseId = (input) => {
29
+ if (input.split(':').length === 2 && !hasWhitespace(input)) return true;
32
30
  return 'You must enter the full database path (example: my-project:databaseID)';
33
31
  };
34
32
 
35
- validator.pubSubSubscription = (input) => {
36
- if (input.split('/').length === 4) return true;
33
+ validate.pubSubSubscription = (input) => {
34
+ if (input.split('/').length === 4 && !hasWhitespace(input)) return true;
37
35
  return 'You must enter the full subscription path (example: projects/example/subscriptions/subscriptionId)';
38
36
  };
39
37
 
40
- module.exports = validator;
38
+ module.exports = validate;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hiiretail/gcp-infra-cli",
3
- "version": "0.76.0",
3
+ "version": "0.76.3",
4
4
  "description": "Infrastructure as code generator for GCP.",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
@@ -1,47 +0,0 @@
1
- locals {
2
- ###################
3
- # REQUIRED INPUTS #
4
- ###################
5
-
6
- names = ["<%-bucketName%>"]
7
- prefix = "<%-prefix%>"
8
-
9
-
10
- ###################
11
- # OPTIONAL INPUTS #
12
- ###################
13
-
14
- # The Storage Class of the new bucket.
15
- # Supported values include: STANDARD, MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, ARCHIVE.
16
- storage_class = "STANDARD"
17
-
18
- # The GCS location - 'EU' for multi-regional buckets.
19
- <% if (env == 'prod') { %>
20
- location = "EU"
21
- <% } else { %>
22
- location = "EUROPE-WEST1"
23
- <% } %>
24
- versioning = {
25
- "<%-bucketName%>" = <%-versioning%>
26
- }
27
- set_viewer_roles = true
28
-
29
- <% if (lifecycleRules == 'true') { %>
30
- lifecycle_rules = [{
31
- action = {
32
- type = "<%-action%>" <% if (action == 'SetStorageClass') { %>
33
- storage_class = "<%-storageClass%>" <% } else { %>
34
- storage_class = null <% } %>
35
- }
36
- condition = {
37
- age = <%-age%> <% if (createdBefore != 'null') { %>
38
- created_before = "<%-createdBefore%>" <% } else { %>
39
- created_before = null <% } %> <% if (withState != 'null') { %>
40
- with_state = "<%-withState%>" <% } else { %>
41
- with_state = null <% } %> <% if (matchesStorageClass != 'null') { %>
42
- matches_storage_class = "<%-matchesStorageClass%>" <% } else { %>
43
- matches_storage_class = null <% } %>
44
- num_newer_versions = <%-numNewerVersions%>
45
- }
46
- }] <% } %>
47
- }
@@ -1,105 +0,0 @@
1
- const fs = require('fs');
2
- const yaml = require('js-yaml');
3
-
4
- const appendIncludeConfigSlo = async (fileContent, originalContentYaml, slosFilePath, inputs) => {
5
- if (fileContent !== null && fileContent !== '') {
6
- const configArray = Object.values(originalContentYaml);
7
- const yamlPullArray = yaml.dump(configArray);
8
- fs.writeFileSync(slosFilePath, `${yamlPullArray}`);
9
- }
10
-
11
- const newPullArray = [];
12
-
13
- const availabilityConf = {
14
- display_name: 'Month - Availability',
15
- slo_id: 'month-availability',
16
- goal: 0.998,
17
- calendar_period: 'MONTH',
18
- type: 'windows_based_sli',
19
- method: 'boolean_filter',
20
- window_period: '60s',
21
- };
22
-
23
- if (inputs.sli === 'availability') {
24
- if (inputs.burnRateAlerts === 'no') {
25
- availabilityConf.alert = {};
26
- }
27
- newPullArray.push(availabilityConf);
28
- }
29
-
30
- const errorRateConf = {
31
- display_name: 'Month - Error rate',
32
- slo_id: 'month-error-rate',
33
- goal: 0.999,
34
- calendar_period: 'MONTH',
35
- type: 'request_based_sli',
36
- method: 'good_total_ratio',
37
- bad_service_filter:
38
- `metric.type="knative.dev/serving/revision/request_count"
39
- resource.type="knative_revision"
40
- metric.labels.response_code_class="5xx"
41
- resource.labels.service_name="${inputs.serviceName}"`,
42
- total_service_filter:
43
- `metric.type="knative.dev/serving/revision/request_count"
44
- resource.type="knative_revision"
45
- resource.labels.service_name=${inputs.serviceName}"`,
46
- };
47
-
48
- if (inputs.sli === 'error-rate') {
49
- if (inputs.burnRateAlerts === 'no') {
50
- errorRateConf.alert = {};
51
- }
52
- newPullArray.push(errorRateConf);
53
- }
54
-
55
- const latencyConf = {
56
- display_name: 'Month - Latency',
57
- slo_id: 'month-latency',
58
- goal: 0.95,
59
- calendar_period: 'MONTH',
60
- type: 'request_based_sli',
61
- method: 'distribution_cut',
62
- metric_filter:
63
- `metric.type="knative.dev/serving/revision/request_latencies"
64
- resource.type="knative_revision"
65
- resource.labels.service_name="${inputs.serviceName}"`,
66
- range_min: 0,
67
- range_max: 100,
68
- };
69
-
70
- if (inputs.sli === 'latency') {
71
- if (inputs.burnRateAlerts === 'no') {
72
- latencyConf.alert = {};
73
- }
74
- newPullArray.push(latencyConf);
75
- }
76
-
77
- const finalYamlPullArray = yaml.dump(newPullArray);
78
- fs.appendFileSync(slosFilePath, finalYamlPullArray);
79
- };
80
-
81
- const appendIncludeConfigUptime = async (fileContent, uptimeContentYml, uptimeFilePath, inputs) => {
82
- if (fileContent !== null && fileContent !== '') {
83
- const configArray = Object.values(uptimeContentYml);
84
- const yamlPullArray = yaml.dump(configArray);
85
- fs.writeFileSync(uptimeFilePath, `${yamlPullArray}`);
86
- }
87
-
88
- const newPullArray = [];
89
-
90
- newPullArray.push(
91
- {
92
- service_name: `${inputs.systemName}.${inputs.serviceName}`,
93
- hostname: inputs.hostname,
94
- path: inputs.path,
95
- },
96
- );
97
-
98
- const finalYamlPullArray = yaml.dump(newPullArray);
99
- fs.appendFileSync(uptimeFilePath, finalYamlPullArray);
100
- };
101
-
102
- module.exports = {
103
- appendIncludeConfigSlo,
104
- appendIncludeConfigUptime,
105
- };
@@ -1,11 +0,0 @@
1
- const ejs = require('ejs');
2
-
3
- const handleAlerts = (alerts, templates, answers) => {
4
- const template = templates[`${answers.alertResource}`][`${answers.alert}`];
5
- const newAlert = ejs.render(JSON.stringify(template), answers);
6
-
7
- alerts.push(JSON.parse(newAlert));
8
- return alerts;
9
- };
10
-
11
- module.exports = handleAlerts;
@@ -1,28 +0,0 @@
1
- const fs = require('fs');
2
- const yaml = require('js-yaml');
3
- const { appendIncludeConfigSlo } = require('./append');
4
-
5
- const handleSlosFile = async (answers, slosFilePath) => {
6
- const {
7
- serviceName,
8
- sli,
9
- systemName,
10
- burnRateAlerts,
11
- } = answers;
12
-
13
- const sloFileContent = fs.readFileSync(slosFilePath, 'utf8');
14
-
15
- const inputs = {
16
- ...this.answers,
17
- serviceName,
18
- sli,
19
- systemName,
20
- burnRateAlerts,
21
- };
22
-
23
- const originalContentYaml = yaml.load(sloFileContent);
24
- const fileContent = sloFileContent;
25
- await appendIncludeConfigSlo(fileContent, originalContentYaml, slosFilePath, inputs);
26
- };
27
-
28
- module.exports = handleSlosFile;
@@ -1,28 +0,0 @@
1
- const fs = require('fs');
2
- const yaml = require('js-yaml');
3
- const { appendIncludeConfigUptime } = require('./append');
4
-
5
- const handleUptimeFile = async (answers, uptimeFilePath) => {
6
- const {
7
- serviceName,
8
- hostname,
9
- path,
10
- systemName,
11
- } = answers;
12
-
13
- const uptimeFileContent = fs.readFileSync(uptimeFilePath, 'utf8');
14
-
15
- const inputs = {
16
- ...this.answers,
17
- serviceName,
18
- hostname,
19
- path,
20
- systemName,
21
- };
22
-
23
- const originalContentYaml = yaml.load(uptimeFileContent);
24
- const fileContent = uptimeFileContent;
25
- await appendIncludeConfigUptime(fileContent, originalContentYaml, uptimeFilePath, inputs);
26
- };
27
-
28
- module.exports = handleUptimeFile;