How to make resource in Serverless Framework reusable? - serverless-framework

I am trying to set up my serverless.yml file with only an API Gateway, and there are several resources that I need to reuse throughout the file, and I'd like to not copy and paste the same lines of code per resource like 100 times.
For example, I want to reuse TestId resource below and dynamically pass in the Ref under ParentId so I can reuse the resource for multiple parent resources. How can I do that?
TestResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId:
Fn::GetAtt:
- TestApi
- RootResourceId
PathPart: test
RestApiId:
Ref: TestApi
TestId:
Type: AWS::ApiGateway::Resource
Properties:
ParentId:
Ref: TestResource
PathPart: '{id}'
RestApiId:
Ref: TestApi
Ideally I would want the resuable TestId resource in a separate file and then reference it, and also pass in the dynamic value that I want to insert in. Something like:
TestId: ${file(testid.yml):TestId} somehow override the TestId.Properties.ParentId.Ref: <somevalue>
Does anyone know if this is possible?

In case you are using NodeJs (if not maybe something like this exists in your programming language), I think you should take a look at this plugin : https://www.npmjs.com/package/yamlinc
It allow to compose YAML files using $include tag.
Hope this helps you.

Related

Define variables per folder in dbt

I'm trying to have a structure to run a dbt project, where I have multiple entities (bank, names, cars). I'm going to have exactly the same code for them all.
Based on that, I'm trying to have several folder with the same code, where I can define inside the dbt_project.yamlfile. The idea is something like this:
vars:
db_name: 'db_official'
staging:
bank: 'variable_bank'
car: 'variable_car'
name: 'variable_name'
The variable "db_name" works. So, my the two problems I'm having are:
How to have this structure inside the the yaml file?
How to reference this structure inside each file?
(extra) Any other ideas how to handle this?
Thanks!
vars are basically globals. They can be scoped to your whole project, or to a package within your project, but not more specifically than that (they share a flat namespace). See the docs.
I would pull out the common code into a macro, then call that macro from each model file, passing in the unique values as string literals in the model file:
-- models/staging/bank.sql
{{ my_model_template('variable_bank') }}
-- models/staging/car.sql
{{ my_model_template('variable_car') }}

Use (scalar) variables in jsonschema to dynamically set attribute, e.g. title

I am using Google Cloud deployment manager to manage infrastructure as code (IAC) and they support providing schema files for describing IAC templates. Their support of jsonschema is a bit weird - the documentation is very brief but it suggests that they support the latest version of the schema plus they require title and description to be within an info object.
This is irritating because I use an HTML renderer for my schemas, which implements jsonschema and therefore, it requires title and description to be set as top-level properties.
To satisfy both, I need to duplicate, e.g.:
title: foo
description: bar
info:
title: foo
description: bar
I was hoping to just define title and description values once and then use some $ref: "#/$defs/title" magic but I don't think you can use this to dynamically set values like the title because this functionality is intended for schema parsers to fetch block content from elsewhere.
Is there any way I can avoid duplicating the values - beyond dynamically rendering my schema files which I do not want to do.
As far as I can tell, there is no way to use reference within json schema.
As a crude workaround you can use a script to add/replace placeholders:
#!/bin/bash
sed -i 's/\$title/title: foo/g' file.json
sed -i 's/\$desc/description: bar/g' file.json

Combine properties in serverless.yml

I have a custom section in serverless.common.yml, which is common to all the services. Some services use some additional properties in their serverless.yml appart from the defined in the file mentioned before.
My idea would be to perform something like:
custom:
- ${file(../serverless.common.yml):custom}
- myServiceCustomProperty: 1
But this does not work. Any idea about how can I achieve that behaviour?
Thank you
- ${file(../serverless.common.yml):custom} is going to dump the array from common so that wont merge. With this approach you need to add each property from the common/custom section individually:
custom:
- foo: ${file(../serverless.common.yml):custom.foo}
- myServiceCustomProperty: 1
or
custom: ${file(../serverless.common.yml):custom}
Alternatively if your setup is complex you can write a serverless.js file instead which allows JS processing. I personally use that to programically merge a dozen yml file - for example when I run sls offline I want to add/remove a bunch of stuff so that's a pretty powerful approach.

Using variables in Serverless resource name

In my serverless.yml I have:
public-function:
handler: function.Handler
I want to parametrise the public-function line but I'm not sure how to do this. I know I can add a name: attribute to the function and use the ${} syntax documented at https://www.serverless.com/framework/docs/providers/aws/guide/variables/ but this only half solves my problem as public-function is used by Serverless as a basis for the names of other resources which I also want to have parametrised names.
Is there some way of using variables in the resource name?
The declared function key (i.e. public-function) is only a reference in the stack. There is no reason to change it at build time as the name is arbitrary.
If you want to customise the details of the deployed function, change its configuration.
For example, change the name of the function to something else using environment variables:
functions:
main:
handler: function.Handler
name: ${self:provider.stage}-${env:FUNCTION_NAME}
If you are exporting the resource to another stack, you can define the export name like so:
resources:
Outputs:
MainFunction:
Value:
Fn::GetAtt: [MainLambdaFunction, Arn]
Export:
Name: ${self:provider.stage}-${env:CUSTOM_EXPORT_NAME}
The stage scoping to both of these examples is recommended but not required; you can name your functions, resources, and outputs anything you want.

Declaring resources in multiple files in Serverless framework

Is there any way to split the resource definitions in serverless framework into multiple files? Something like:
resources:
- ${resources/base.yml}
- ${resources/foo.yml}
I have been trying multiple combinations but I keep getting errors about references not being found.
Even though dashmug's answer is correct, I found that the way I was trying to make it work was quite close to a valid solution too. As explained in this github comment it is possible to reference other files in the resources section:
resources:
- ${file(resources/first-cf-resources.yml)}
- ${file(resources/second-cf-resources.yml)}
Provided that each those files defines a "Resources" key of its own, like:
---
Resources:
MyCFResource:
Type:.....
What I didn't manage is to have a mixed approach such as:
resources:
- ${file(resources/first-cf-resources.yml)}
- ${file(resources/second-cf-resources.yml)}
SomeResource:
Type: ...
So I just have a resources/base.yml for that instead.
I can't comment but I'd like to extend Jesuspc's answer.
There is a way to achieve that 'mixed' approach, in serverless.yml:
resources:
- ${file(resources/first-cf-resources.yml)}
- ${file(resources/second-cf-resources.yml)}
- Resources:
SomeResource:
Type: ...
In this case files first-cf-resources.yml and second-cf-resources.yml must have the next structure:
Resources:
SomeResourceA:
...
AnotherResourceB:
...
Take note that the resources property has to be an object containing a Resources property, NOT an array of resources like what you wanted in your code snippet.
So, to use external file references, you can do something like...
resources
Resources:
UsersTable: ${file(../resources/base.yml):UsersTable}
FooTable: ${file(../resources/foo.yml):FooTable}
Reference: Reference variables in other files