AWS SSM - store multiple parameters using terraform and json file - json

We have a couple of legacy applications we're migrating to ec2 and these use a bunch of application configuration parameters. I need to be able to store each config as an individual parameter per application.
I'm trying the following but clearly not doing it right as it appends all values to a single parameter per application:
locals {
application = {
"application1" = { app_shortcode = "app1"},
"application2" = { app_shortcode = "app2"}
}
resource "aws_ssm_parameter" "application_parameters" {
for_each = local.application
name = each.key
value = jsonencode(file("${path.module}/${each.key}/ssm_param.json"))
}
my app1's ssm_param.json is something like
{
"app1_config1": "config_value_1",
"app1_config2": "config_value_2",
"app1_config3": "config_value_3"
}
and app2's ssm_param.jsonis
{
"app2_config_a": "config_value_a",
"app2_config_b": "config_value_b",
"app2_config_c": "config_value_c"
}
The current output is a single parameter like this for each application:
"{\r\n \"app2_config_a\": \"config_value_a\",\r\n \"app2_config_b\": \"config_value_b\"\r\n, \r\n \"app2_config_c\": \"config_value_c\"\r\n}"
Looking for suggestions please.

I solved this by using a slightly different approach (not quite the same as my initial one but this works for me for now):
used a ssm_params.yaml as below (the project team was kind enough to give me the config settings as yaml output)
parameter:
app1:
name: app1_config1
description: "application config test"
type: "String"
value: "some_randoM_value"
app1:
name: app_config2
description: "another test"
type: "SecureString"
value: "some_random123_value###"
app2:
name: app_config_2
description: "config test"
type: "String"
value: "some_randoM_value_2"
locals {
params = yamldecode(file("${path.module}/ssm_params.yaml"))
}
resource "aws_ssm_parameter" "app_params" {
for_each = local.params.parameter
name = each.value.name
type = each.value.type
value = each.value.value
}

Related

Monaco editor default json uri schema

I'm using monaco editor to edit JSON and I would like to set a custom diagnostic option.
I'm trying that https://microsoft.github.io/monaco-editor/playground.html#extending-language-services-configure-json-defaults
// Configures two JSON schemas, with references.
var jsonCode = [
'{',
' "p1": "v3",',
' "p2": false',
"}"
].join('\n');
var modelUri = monaco.Uri.parse("a://b/foo.json"); // a made up unique URI for our model
var model = monaco.editor.createModel(jsonCode, "json", modelUri);
// configure the JSON language support with schemas and schema associations
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
schemas: [{
uri: "http://myserver/foo-schema.json", // id of the first schema
fileMatch: [modelUri.toString()], // associate with our model
schema: {
type: "object",
properties: {
p1: {
enum: ["v1", "v2"]
},
p2: {
$ref: "http://myserver/bar-schema.json" // reference the second schema
}
}
}
}, {
uri: "http://myserver/bar-schema.json", // id of the second schema
schema: {
type: "object",
properties: {
q1: {
enum: ["x1", "x2"]
}
}
}
}]
});
monaco.editor.create(document.getElementById("container"), {
model: model
});
Where does uri: "http://myserver/foo-schema.json" come from ? I just want to use default JSON schema. Not my own.
Setting uri like this works :
uri: "http://localhost:4200/assets/monaco-editor/min/vs/language/json/jsonMode.js",
But is there a clean way to set this value ? Maybe uri value for JSON is available somewhere ? I searched through monaco.languages.json.jsonDefaults but I did not find anything.
"http://myserver/foo-schema.json" is an arbitrary value-- you can make it anything you want. It only matters if you are also using enableSchemaRequest-- in which case it should point to the location that you want the schema to be fetched from-- but you're not doing that, so that doesn't matter. In fact, everything related to this URI is irrelevant to what you are trying to do, if I'm understanding your intent correctly.
When you say "I just want to use default JSON Schema, Not my own", I think what you mean to say is that you just want to ensure that it is valid JSON, right? Because, there is no such thing as "default JSON Schema"-- by definition, it is defined by you-- but there is such a thing as a formal definition of what JSON is (JSON Schema, on the other hand, assumes that you are already starting with valid JSON, and allows you to then define a schema that your (valid) JSON must conform to).
Assuming you just want to ensure it is valid JSON (but you don't care that the json conform to some custom schema), setting the language to 'json' is all you need to do and your code can be as simple as:
var myBadJSONText = '{this is not : "JSON"}'
monaco.editor.create(document.getElementById('container'), {
language: 'json',
value: myBadJSONText
});
which running in the Monaco playground gives you:

Porting a cloudformation template to terraform

I am following a direction on Hashicorp's site regarding wrapping a CF Template in Terraform. There's a fair amount to the whole code, but the CF Template works, so the issue is with the "wrapping"...
Terraform plan gives me this error output:
terraform plan
Error: aws_cloudformation_stack.Momma: "template_body" contains an invalid JSON: invalid character 'A' looking for beginning of object key string
Error: aws_cloudformation_stack.Momma: : invalid or unknown key: source
So it seems that the "AWSTemplateFormatVersion" line is what it does not like. Hence the'A' it is picking up, I guess.
This is the Hashicorp page I am following, I'm wondering if there are any escape characters that are appropriate or, if anyone can see any immediate formatting issues with my JSON?
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudformation_stack
terraform {}
provider "aws" {
version = "= 2.61"
region = "ap-southeast-2"
}
resource "aws_cloudformation_stack" "Momma" {
source = "../../aws_modules/aws-db-event-subscription"
name = "Momma-Stack"
template_body = <<STACK
{
AWSTemplateFormatVersion: 2010-09-09
Description: Team Server
Metadata:
'AWS::CloudFormation::Interface':
ParameterGroups:
- Label:
default: Deployment Options
Parameters:
- Environment
- KeyPairName
- VPCID
- Subnet1ID
- RemoteAccessCIDR
- Owner
ParameterLabels:
KeyPairName:
Default: Key Pair Name
RemoteAccessCIDR:
Default: External Access CIDR
VPCID:
Default: VPC ID
Owner:
Default: MommaTeam....
Thank you for any guidance offered.
There are at least two issues that are apparent:
source = "../../aws_modules/aws-db-event-subscription" is invalid. There is no attribute called source in aws_cloudformation_stack. You can remove it.
Your template_body should not begin with { in:
template_body = <<STACK
{
This is because you are using YAML for your template, not JSON.

How to convert string to number in terraform template file

I have a terraform template file source.tpl - it's a json and it has to be JSON, because it's produced by python json library. This file has the following entry
[
{
"data": {
"address": "${NETWORK}",
"netmask": "${NETMASK}",
}
}
]
In my tf module, I render this template:
data "template_file" "source" {
template = "${file("${path.module}/source.tpl")}"
vars = {
NETWORK = element(split("/", "${var.cidr}"),0)
NETMASK = tonumber(element(split("/", "${var.cidr}"),1))
}
}
where cidr is a string - something like 10.1.1.0/24
In the rendered output I need NETMASK to be a number and NETWORK to be a string. I.e. it has to be something like:
data = {
address = "10.1.1.0"
netmask = 24
}
But I'm getting:
data = {
address = "10.1.1.0"
netmask = "24"
}
I.e. netmask is a string. How can I get rid of those quotes in terraform? Initial source.tpl should still have those quotes, because if I remove them - it becomes invalid JSON.
I understand the problem here, you're generating the template using a JSON library that cannot produce something like the following since it's invalid JSON, though this is what you want for the template to be
[
{
"data": {
"address": "${NETWORK}",
"netmask": ${NETMASK}
}
}
]
Might I recommend a little bit of preprocessing? For example
template = "${replace(file("${path.module}/source.tpl"), "\"$${NETMASK}\"", "$${NETMASK}")}"

Create Terraform resources out of JSON values

I am looking for a way to generate Terraform code based on JSON values.
Imagine I have a JSON file with the following structure:
{
"settings": [
{
"conf": [
{
"setting": "DeploymentPolicy",
"namespace": "aws:elasticbeanstalk:command",
"value": "AllAtOnce"
},
{
"setting": "BatchSize",
"namespace": "aws:elasticbeanstalk:command",
"value": "30"
},
{
"setting": "BatchSizeType",
"namespace": "aws:elasticbeanstalk:command",
"value": "Percentage"
}
]
}
]
}
What I want to do is the following:
Creating a working Terraform resource based on the JSON file values, e.g. a beanstalk environment like this:
resource "aws_elastic_beanstalk_environment" "app_prod" {
name = "${aws_elastic_beanstalk_application_version.app.name}-prod"
application = aws_elastic_beanstalk_application.app.name
solution_stack_name = data.aws_elastic_beanstalk_solution_stack.latest_linux_java.name
wait_for_ready_timeout = "10m"
version_label = aws_elastic_beanstalk_application_version.app.name
# Elastic beanstalk configuration
setting {
name = "DeploymentPolicy"
namespace = "aws:elasticbeanstalk:command"
value = "AllAtOnce"
}
setting {
name = "BatchSize"
namespace = "aws:elasticbeanstalk:command"
value = "30"
}
...
}
Therefore I have to create the settings block in HCL (Terraform configuration) based on the JSON values.
This means the JSON file above should result in:
setting {
name = "DeploymentPolicy"
namespace = "aws:elasticbeanstalk:command"
value = "AllAtOnce"
}
setting {
name = "BatchSize"
namespace = "aws:elasticbeanstalk:command"
value = "30"
}
setting {
name = "BatchSizeType"
namespace = "aws:elasticbeanstalk:command"
value = "Percentage"
}
As you can see, the structure of JSON and HCL is very similar, but not identical. See e.g. settings, conf, or setting instead of name in the JSON.
A possible approach would be to read the JSON values and store them in an array or a map. But I have no idea how I could generate valid HCL and inject it in the desired part of the resource. Furthermore I tried to use a template but Terraform does not support the looping functionality that I need to iterate over the settings.
To sum up:
Input is a JSON file that must be read
JSON contains settings (besides other information)
The number of settings can differ
Somehow I have to generate a settings block
Somehow I have to inject this settings blok in the resource
Does anyone have an idea how to do that? Any other approaches?
Thanks a lot!
Assuming that your JSON object were in a file called settings.json inside your module directory, you could do something like this:
locals {
environment_settings = jsondecode(file("${path.module}/settings.json")).settings[0].conf[0]
}
resource "aws_elastic_beanstalk_environment" "app_prod" {
name = "${aws_elastic_beanstalk_application_version.app.name}-prod"
application = aws_elastic_beanstalk_application.app.name
solution_stack_name = data.aws_elastic_beanstalk_solution_stack.latest_linux_java.name
wait_for_ready_timeout = "10m"
version_label = aws_elastic_beanstalk_application_version.app.name
dynamic "setting" {
for_each = local.environment_settings
content {
namespace = setting.value.namespace
name = setting.value.setting
value = setting.value.value
}
}
}
This special dynamic block is a sort of macro to create repeated setting blocks, each one correlating with one element of the collection given in for_each.
You can do whatever transformations of the input you need using Terraform's expression language in the locals block to ensure that the local.environment_settings value contains one element for each setting block you will generate, and then in the content nested block tell Terraform how to populate the setting arguments based on those element values.

Creating a connection type in AWS AppSync to retrieve data from Aurora Serverless

so I have a Aurora Serverless DB in Amazon RDS. I would like to use this within GraphQL and set up connections between certain types. I.e, a User could have a list of Followers and that's used with a UserFollowerConnection type. What I would like this to do is paginate and only retrieve maybe 10 items at a time, and keep track of the nextToken. I was able to do this successfully with DynamoDB tables but I am trying to replicate the same implementation with RDS.
My schema looks something like this:
type User {
userId: String!
userName: String!
fullName: String!
displayName: String!
email: String!
followers(limit: Int, nextToken: String): UserFollowerConnection
}
type UserFollower {
userId: String!
followerId: String!
dateFollowed: AWSDateTime!
}
type UserFollowerConnection {
items: [UserFollower]
nextToken: String
}
My current resolver implementation for DynamoDB looks something like this:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
## Provide a query expression. **
"expression": "userId = :id",
"expressionValues" : {
":id": {
"S": "$ctx.source.userId"
}
}
},
"limit": #if($context.arguments.limit) $context.arguments.limit #else 10 #end,
"nextToken": #if($context.arguments.nextToken) "$context.arguments.nextToken" #else null #end
}
What would be the best practice for implementing this for AuroraServerless/MySQL? Would I write this code within the resolver on AppSync as shown in the documentation, or should this be a Lambda function that is connected to the resolver?
i hope you fixed your problem.
I`m currently in the same situation.
And there's another obstacle when trying to implement this functionality with mysql: Pagination
https://github.com/aws-amplify/amplify-cli/issues/3111
Would be great if you could post your resolver once you have fixed the problem.