@hiiretail/gcp-infra-cli 0.83.3 → 0.84.0

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.
@@ -5,12 +5,14 @@ exports[`googlecloud It renders YAML with comments 1`] = `
5
5
  # - bigtable.googleapis.com # Cloud Bigtable
6
6
  # - bigquery.googleapis.com # Cloud BigQuery
7
7
  - cloudapis.googleapis.com # Google Cloud APIs
8
+ - clouddeploy.googleapis.com # Cloud Deploy API
8
9
  # - cloudfunctions.googleapis.com # Cloud Functions API
9
10
  - cloudresourcemanager.googleapis.com # Cloud Resource Manager API
10
11
  # - compute.googleapis.com # Compute Engine API
11
12
  - container.googleapis.com # Kubernetes
12
13
  - containerregistry.googleapis.com # Container Registry
13
14
  # - dataflow.googleapis.com # Dataflow API
15
+ - dns.googleapis.com # Cloud DNS API
14
16
  # - firestore.googleapis.com # Cloud Firestore
15
17
  - monitoring.googleapis.com # Stackdriver Monitoring API
16
18
  # - pubsub.googleapis.com # Cloud Pub/Sub API
@@ -20,5 +22,6 @@ exports[`googlecloud It renders YAML with comments 1`] = `
20
22
  # - spanner.googleapis.com # Cloud Spanner API
21
23
  # - storage-api.googleapis.com # Cloud Storage
22
24
  # - sqladmin.googleapis.com # Cloud SQL
23
- - servicenetworking.googleapis.com # Service Networking API"
25
+ - servicenetworking.googleapis.com # Service Networking API
26
+ - vpcaccess.googleapis.com # Serverless VPC Access API"
24
27
  `;
@@ -18,6 +18,11 @@ const availableApis = [
18
18
  name: 'Google Cloud APIs',
19
19
  enabled: true,
20
20
  },
21
+ {
22
+ value: 'clouddeploy.googleapis.com',
23
+ name: 'Cloud Deploy API',
24
+ enabled: true,
25
+ },
21
26
  {
22
27
  value: 'cloudfunctions.googleapis.com',
23
28
  name: 'Cloud Functions API',
@@ -45,6 +50,11 @@ const availableApis = [
45
50
  value: 'dataflow.googleapis.com',
46
51
  name: 'Dataflow API',
47
52
  },
53
+ {
54
+ value: 'dns.googleapis.com',
55
+ name: 'Cloud DNS API',
56
+ enabled: true,
57
+ },
48
58
  {
49
59
  value: 'firestore.googleapis.com',
50
60
  name: 'Cloud Firestore',
@@ -89,6 +99,11 @@ const availableApis = [
89
99
  name: 'Service Networking API',
90
100
  enabled: true,
91
101
  },
102
+ {
103
+ value: 'vpcaccess.googleapis.com',
104
+ name: 'Serverless VPC Access API',
105
+ enabled: true,
106
+ },
92
107
  ];
93
108
 
94
109
  const apisYaml = (resources = []) => availableApis.map((entry) => ({
@@ -41,7 +41,7 @@ module.exports = class extends BaseGenerator {
41
41
  const specStageFile = path.join('infra', 'staging', 'elastic');
42
42
  const specProdFile = path.join('infra', 'prod', 'elastic');
43
43
  this.log(`
44
- ${chalk.green(`Your Elastic Cloud deployemnts have now been created. To finalize your configuration, please continue
44
+ ${chalk.green(`Your Elastic Cloud deployments have now been created. To finalize your configuration, please continue
45
45
  with manual editing of the generated files.`)}
46
46
  ${chalk.green('1.')} Review Elastic configuration
47
47
  \u2192 ${chalk.cyan(path.join(specStageFile, 'spec.hcl'))}
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "Elastic Lifecycle policy",
3
+ "description": "Create an Elastic Cloud Lifecycle policy resource"
4
+ }
@@ -0,0 +1,76 @@
1
+ const fs = require('fs');
2
+ const yaml = require('js-yaml');
3
+
4
+ /* eslint-disable no-param-reassign */
5
+ const handleHotPhase = (answers, phaseData) => {
6
+ if (answers.hotReadonly === 'true') {
7
+ phaseData.readonly = { enabled: true };
8
+ }
9
+
10
+ if (answers.hotPriority) {
11
+ phaseData.set_priority = { priority: answers.hotPriority };
12
+ }
13
+ };
14
+
15
+ const handleColdPhase = (answers, phaseData) => {
16
+ if (answers.coldReadonly === 'true') {
17
+ phaseData.readonly = { enabled: true };
18
+ }
19
+
20
+ if (answers.coldPriority) {
21
+ phaseData.set_priority = { priority: answers.coldPriority };
22
+ }
23
+
24
+ if (answers.coldFreeze === 'true') {
25
+ phaseData.freeze = { enabled: true };
26
+ }
27
+ };
28
+
29
+ const handleWarmPhase = (answers, phaseData) => {
30
+ if (answers.warmReadonly === 'true') {
31
+ phaseData.readonly = { enabled: true };
32
+ }
33
+
34
+ if (answers.warmPriority) {
35
+ phaseData.set_priority = { priority: answers.warmPriority };
36
+ }
37
+
38
+ if (answers.warmMigrate === 'true') {
39
+ phaseData.migrate = { enabled: true };
40
+ }
41
+ };
42
+ /* eslint-enable no-param-reassign */
43
+
44
+ const handlePolicies = async (answers, yamlPath) => {
45
+ const existingData = yaml.load(fs.readFileSync(yamlPath, 'utf8')) || { policies: [] };
46
+
47
+ const policy = {
48
+ name: answers.policyName,
49
+ };
50
+
51
+ answers.phase.forEach((phase) => {
52
+ const phaseData = {
53
+ min_age: answers[`${phase}MinAge`],
54
+ };
55
+
56
+ if (phase === 'hot') {
57
+ handleHotPhase(answers, phaseData);
58
+ }
59
+
60
+ if (phase === 'cold') {
61
+ handleColdPhase(answers, phaseData);
62
+ }
63
+
64
+ if (phase === 'warm') {
65
+ handleWarmPhase(answers, phaseData);
66
+ }
67
+
68
+ policy[phase] = phaseData;
69
+ });
70
+
71
+ existingData.policies.push(policy);
72
+
73
+ fs.writeFileSync(yamlPath, yaml.dump(existingData));
74
+ };
75
+
76
+ module.exports = handlePolicies;
@@ -0,0 +1,210 @@
1
+ const path = require('path');
2
+ const chalk = require('chalk');
3
+ const fs = require('fs');
4
+ const BaseGenerator = require('../../../src/BaseGenerator');
5
+ const { required } = require('../../../src/validators');
6
+ const handlePolicies = require('./handle-yaml');
7
+
8
+ module.exports = class extends BaseGenerator {
9
+ prompting() {
10
+ const prompts = [
11
+ {
12
+ type: 'input',
13
+ name: 'policyName',
14
+ message: 'Please provide the name of the lifecycle policy',
15
+ validate: required,
16
+ },
17
+ {
18
+ type: 'checkbox',
19
+ name: 'phase',
20
+ message: 'Please select lifecycle phases to be used within the policy',
21
+ choices: [{
22
+ name: 'The index is actively being updated and queried - hot',
23
+ value: 'hot',
24
+ },
25
+ {
26
+ name: 'The index is no longer being updated but is still being queried - warm',
27
+ value: 'warm',
28
+ },
29
+ {
30
+ name: 'The index is no longer being updated and is queried infrequently - cold',
31
+ value: 'cold',
32
+ },
33
+ {
34
+ name: 'The index is no longer being updated and is queried rarely - frozen',
35
+ value: 'frozen',
36
+ },
37
+ {
38
+ name: 'The index is no longer needed and can safely be removed - delete',
39
+ value: 'delete',
40
+ }],
41
+ },
42
+ ];
43
+
44
+ return this.prompt(prompts).then((props) => {
45
+ this.answers = props;
46
+
47
+ const additionalPrompts = [];
48
+
49
+ if (this.answers.phase.includes('hot')) {
50
+ additionalPrompts.push({
51
+ type: 'input',
52
+ name: 'hotMinAge',
53
+ message: 'Please provide a minimum age for the hot phase to control the timing of the transition. Format: 10s, 10h, 10d',
54
+ validate: required,
55
+ });
56
+
57
+ additionalPrompts.push({
58
+ type: 'list',
59
+ name: 'hotReadonly',
60
+ message: 'Please select true to make the index read-only',
61
+ choices: ['true', 'false'],
62
+ });
63
+
64
+ additionalPrompts.push({
65
+ type: 'input',
66
+ name: 'hotPriority',
67
+ message: 'Please provide the priority for the index. Must be 0 or greater (leave empty to add later)',
68
+ });
69
+ }
70
+
71
+ if (this.answers.phase.includes('cold')) {
72
+ additionalPrompts.push({
73
+ type: 'input',
74
+ name: 'coldMinAge',
75
+ message: 'Please provide a minimum age for the cold phase to control the timing of the transition. Format: 10s, 10h, 10d',
76
+ validate: required,
77
+ });
78
+
79
+ additionalPrompts.push({
80
+ type: 'list',
81
+ name: 'coldReadonly',
82
+ message: 'Please select true to make the index read-only',
83
+ choices: ['true', 'false'],
84
+ });
85
+
86
+ additionalPrompts.push({
87
+ type: 'input',
88
+ name: 'coldPriority',
89
+ message: 'Please provide the priority for the index. Must be 0 or greater (leave empty to add later)',
90
+ });
91
+
92
+ additionalPrompts.push({
93
+ type: 'list',
94
+ name: 'coldFreeze',
95
+ message: 'Please select true if you want to freeze the index to minimize its memory footprint',
96
+ choices: ['true', 'false'],
97
+ });
98
+ }
99
+
100
+ if (this.answers.phase.includes('warm')) {
101
+ additionalPrompts.push({
102
+ type: 'input',
103
+ name: 'warmMinAge',
104
+ message: 'Please provide a minimum age for the warm phase to control the timing of the transition. Format: 10s, 10h, 10d',
105
+ validate: required,
106
+ });
107
+
108
+ additionalPrompts.push({
109
+ type: 'list',
110
+ name: 'warmReadonly',
111
+ message: 'Please select true to make the index read-only',
112
+ choices: ['true', 'false'],
113
+ });
114
+
115
+ additionalPrompts.push({
116
+ type: 'input',
117
+ name: 'warmPriority',
118
+ message: 'Please provide the priority for the index. Must be 0 or greater (leave empty to add later)',
119
+ });
120
+
121
+ additionalPrompts.push({
122
+ type: 'list',
123
+ name: 'warmMigrate',
124
+ message: 'Please select true if you want to move the index to the data tier that corresponds to the current phase',
125
+ choices: ['true', 'false'],
126
+ });
127
+ }
128
+
129
+ if (this.answers.phase.includes('frozen')) {
130
+ additionalPrompts.push({
131
+ type: 'input',
132
+ name: 'frozenMinAge',
133
+ message: 'Please provide a minimum age for the frozen phase to control the timing of the transition. Format: 10s, 10h, 10d',
134
+ validate: required,
135
+ });
136
+ }
137
+
138
+ if (this.answers.phase.includes('delete')) {
139
+ additionalPrompts.push({
140
+ type: 'input',
141
+ name: 'deleteMinAge',
142
+ message: 'Please provide a minimum age for the delete phase to control the timing of the transition. Format: 10s, 10h, 10d',
143
+ validate: required,
144
+ });
145
+ }
146
+
147
+ return this.prompt(additionalPrompts).then((promptProps) => {
148
+ this.answers = {
149
+ ...this.answers,
150
+ ...promptProps,
151
+ };
152
+ });
153
+ });
154
+ }
155
+
156
+ writing() {
157
+ const {
158
+ policyName,
159
+ phase,
160
+ } = this.answers;
161
+
162
+ return Promise.all(['prod', 'staging'].map(async (env) => {
163
+ const resourceDir = path.join(process.cwd(), 'infra', env, 'elastic-index-policy');
164
+ this.fs.copyTpl(
165
+ this.templatePath('policy/terragrunt.hcl'),
166
+ this.destinationPath(`${resourceDir}/terragrunt.hcl`),
167
+ {
168
+ ...this.answers,
169
+ env,
170
+ policyName,
171
+ phase,
172
+ },
173
+ );
174
+
175
+ const yamlPath = `${resourceDir}/policy.yaml`;
176
+ if (!fs.existsSync(resourceDir)) {
177
+ fs.mkdirSync(resourceDir, { recursive: true });
178
+ }
179
+
180
+ if (!fs.existsSync(yamlPath)) {
181
+ fs.writeFileSync(yamlPath, '');
182
+ this.fs.copyTpl(
183
+ this.templatePath('policy/policy.yaml'),
184
+ this.destinationPath(yamlPath),
185
+ {
186
+ ...this.answers,
187
+ env,
188
+ policyName,
189
+ phase,
190
+ },
191
+ );
192
+ } else {
193
+ await handlePolicies(this.answers, yamlPath);
194
+ }
195
+ }));
196
+ }
197
+
198
+ end() {
199
+ const specStageFile = path.join('infra', 'staging', 'elastic-index-policy');
200
+ const specProdFile = path.join('infra', 'prod', 'elastic-index-policy');
201
+ this.log(`
202
+ ${chalk.green(`Your Elastic Lifecycle policy configurations have now been created. To finalize your configuration, please continue
203
+ with manual editing of the generated files. Check tf-module-gcp-elastic/policy module for more options you can add to the policy.`)}
204
+ ${chalk.green('1.')} Review policy configuration
205
+ \u2192 ${chalk.cyan(path.join(specStageFile, 'policy.yaml'))}
206
+ \u2192 ${chalk.cyan(path.join(specProdFile, 'policy.yaml'))}
207
+ ${chalk.green('2.')} Push this change in a feature branch and open a pull request.
208
+ `);
209
+ }
210
+ };
@@ -0,0 +1,28 @@
1
+ policies:
2
+ - name: "<%-policyName%>" <% phase.forEach(function(item) { %><% if (item === 'hot') { %>
3
+ <%- item %>: <% if (hotMinAge != '') { %>
4
+ min_age: "<%-hotMinAge%>" <% } %> <% if (hotReadonly === 'true') { %>
5
+ readonly:
6
+ enabled: true <% } %> <% if (hotPriority != '') { %>
7
+ set_priority:
8
+ priority: "<%-hotPriority%>" <% } %> <% } %> <% if (item === 'cold') { %>
9
+ <%- item %>: <% if (coldMinAge != '') { %>
10
+ min_age: "<%-coldMinAge%>" <% } %> <% if (coldReadonly === 'true') { %>
11
+ readonly:
12
+ enabled: true <% } %> <% if (coldPriority != '') { %>
13
+ set_priority:
14
+ priority: "<%-coldPriority%>" <% } %> <% if (coldFreeze === 'true') { %>
15
+ freeze:
16
+ enabled: true <% } %> <% } %> <% if (item === 'warm') { %>
17
+ <%- item %>: <% if (warmMinAge != '') { %>
18
+ min_age: "<%-warmMinAge%>" <% } %> <% if (warmReadonly === 'true') { %>
19
+ readonly:
20
+ enabled: true <% } %> <% if (warmPriority != '') { %>
21
+ set_priority:
22
+ priority: "<%-warmPriority%>" <% } %> <% if (warmMigrate === 'true') { %>
23
+ migrate:
24
+ enabled: true <% } %> <% } %> <% if (item === 'frozen') { %>
25
+ <%- item %>: <% if (frozenMinAge != '') { %>
26
+ min_age: "<%-frozenMinAge%>" <% } %> <% } %> <% if (item === 'delete') { %>
27
+ <%- item %>: <% if (deleteMinAge != '') { %>
28
+ min_age: "<%-deleteMinAge%>" <% } %> <% } %> <% }) %>
@@ -0,0 +1,25 @@
1
+ # Terragrunt will copy the Terraform configurations specified by the source parameter, along with any files in the
2
+ # working directory, into a temporary folder, and execute your Terraform commands in that folder.
3
+ terraform {
4
+ source = "git::https://github.com/extenda/tf-module-gcp-elastic//policy?ref=v0.1.5"
5
+ }
6
+
7
+ # Include all settings from the root terragrunt.hcl file
8
+ include {
9
+ path = find_in_parent_folders("terragrunt_root.hcl")
10
+ }
11
+
12
+ locals {
13
+ project_vars = read_terragrunt_config(find_in_parent_folders("project.hcl"))
14
+ common_vars = read_terragrunt_config(find_in_parent_folders("common.hcl"))
15
+ }
16
+
17
+ # These are the variables we have to pass in to use the module specified in the terragrunt configuration above
18
+ inputs = merge(
19
+ yamldecode(file("${get_terragrunt_dir()}/policy.yaml")),
20
+ local.project_vars.locals,
21
+ {
22
+ project_id = local.project_vars.locals.project_id
23
+ create_policy = true
24
+ }
25
+ )
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "Elastic Index",
3
+ "description": "Create an Elastic Cloud Index resource"
4
+ }
@@ -0,0 +1,84 @@
1
+ const path = require('path');
2
+ const chalk = require('chalk');
3
+ const BaseGenerator = require('../../../src/BaseGenerator');
4
+ const { required } = require('../../../src/validators');
5
+
6
+ module.exports = class extends BaseGenerator {
7
+ prompting() {
8
+ const prompts = [
9
+ {
10
+ type: 'input',
11
+ name: 'indexName',
12
+ message: 'Please provide the name of the index',
13
+ validate: required,
14
+ },
15
+ {
16
+ type: 'input',
17
+ name: 'numberOfShards',
18
+ message: 'Please provide the number of shards for the index',
19
+ validate: required,
20
+ },
21
+ {
22
+ type: 'input',
23
+ name: 'numberOfReplicas',
24
+ message: 'Please provide the number of shard replicas',
25
+ validate: required,
26
+ },
27
+ {
28
+ type: 'input',
29
+ name: 'aliasName',
30
+ message: 'Please provide the alias name of the index or leave empty',
31
+ },
32
+ {
33
+ type: 'list',
34
+ name: 'isWriteIndex',
35
+ message: 'Please select true if the index is the write index for the alias. If previous step is empty this one will be considered empty as well',
36
+ choices: ['true', 'false'],
37
+ },
38
+ {
39
+ type: 'input',
40
+ name: 'policyName',
41
+ message: 'Please provide the lifecycle policy name for the index that has been previously created or leave empty to add later',
42
+ },
43
+ ];
44
+
45
+ return this.prompt(prompts).then((props) => {
46
+ this.answers = props;
47
+ });
48
+ }
49
+
50
+ writing() {
51
+ const {
52
+ indexName,
53
+ } = this.answers;
54
+
55
+ ['prod', 'staging'].forEach((env) => {
56
+ this.copyDir(
57
+ 'elastic-template',
58
+ path.join('infra', env, 'elastic-template', indexName),
59
+ {
60
+ ...this.answers,
61
+ env,
62
+ indexName,
63
+ },
64
+ );
65
+ });
66
+ }
67
+
68
+ end() {
69
+ const {
70
+ indexName,
71
+ } = this.answers;
72
+
73
+ const specStageFile = path.join('infra', 'staging', 'elastic-template', indexName);
74
+ const specProdFile = path.join('infra', 'prod', 'elastic-template', indexName);
75
+ this.log(`
76
+ ${chalk.green(`Your Elastic Cloud index configurations have now been created. To finalize your configuration, please continue
77
+ with manual editing of the generated files.`)}
78
+ ${chalk.green('1.')} Review Mappings configuration
79
+ \u2192 ${chalk.cyan(path.join(specStageFile, 'mappings.json'))}
80
+ \u2192 ${chalk.cyan(path.join(specProdFile, 'mappings.json'))}
81
+ ${chalk.green('2.')} Push this change in a feature branch and open a pull request.
82
+ `);
83
+ }
84
+ };
@@ -0,0 +1,35 @@
1
+ # Terragrunt will copy the Terraform configurations specified by the source parameter, along with any files in the
2
+ # working directory, into a temporary folder, and execute your Terraform commands in that folder.
3
+ terraform {
4
+ source = "git::https://github.com/extenda/tf-module-gcp-elastic//index?ref=v0.1.5"
5
+ }
6
+
7
+ # Include all settings from the root terragrunt.hcl file
8
+ include {
9
+ path = find_in_parent_folders("terragrunt_root.hcl")
10
+ }
11
+
12
+ locals {
13
+ project_vars = read_terragrunt_config(find_in_parent_folders("project.hcl"))
14
+ common_vars = read_terragrunt_config(find_in_parent_folders("common.hcl"))
15
+ }
16
+
17
+ # These are the variables we have to pass in to use the module specified in the terragrunt configuration above
18
+ inputs = merge(
19
+ local.project_vars.locals,
20
+ {
21
+ index_name = "<%-indexName%>"
22
+ project_id = local.project_vars.locals.project_id
23
+ mappings = jsondecode(file("${get_terragrunt_dir()}/mappings.json"))
24
+ number_of_shards = "<%-numberOfShards%>"
25
+ number_of_replicas = "<%-numberOfReplicas%>" <% if (policyName != '') { %>
26
+ lifecycle_policy = "<%-policyName%>" <% } %>
27
+ <% if (aliasName != '') { %>
28
+ alias = [
29
+ {
30
+ name = "<%-aliasName%>"
31
+ is_write_index = <%-isWriteIndex%>
32
+ }
33
+ ] <% } %>
34
+ }
35
+ )
@@ -170,7 +170,7 @@ module.exports = class extends BaseGenerator {
170
170
  externalSub,
171
171
  } = this.answers;
172
172
 
173
- const dlqTopicName = `dlq.${getProjectId('prod').split('-')[0]}.common`;
173
+ const dlqTopicName = `dlq.${getProjectId('prod').split('-prod')[0]}.common`;
174
174
  let dlqTopic = `projects/${getProjectId('prod')}/topics/${dlqTopicName}`;
175
175
 
176
176
  const dlqTopicDirPath = path.join(process.cwd(), 'infra', 'prod', 'pubsub', dlqTopicName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hiiretail/gcp-infra-cli",
3
- "version": "0.83.3",
3
+ "version": "0.84.0",
4
4
  "description": "Infrastructure as code generator for GCP.",
5
5
  "main": "src/cli.js",
6
6
  "bin": {