Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4ad5eef
Delete automation doc
devpro Jul 13, 2025
bc06bc0
Cosmetic code changes to Docker sample
devpro Jul 13, 2025
aaeb1c6
Dump version to 1.1.0
devpro Jul 13, 2025
72a175c
Use SUSE Base container images
devpro Jul 13, 2025
8502f54
Improve README and update action version in GitLab Actions
devpro Jul 13, 2025
ba881a9
Update max CVE to 0 in container scan
devpro Jul 13, 2025
c459bd9
Update packages
devpro Jul 13, 2025
8b4cef7
Use ThrowIfNull in RawRequestBodyFormatter CanRead method
devpro Jul 13, 2025
22fafe4
Add CI/CD pipelines section in CONTRIBUTING
devpro Jul 13, 2025
b8e7319
Update Sonar key in badge
devpro Jul 13, 2025
232c956
Fix Sonar warning about Dockerfile
devpro Jul 13, 2025
deeba66
Code improvements following update to .NET 8
devpro Jul 13, 2025
0db3475
Use file scoped namespace
devpro Jul 13, 2025
11ed03a
Add HealthCheckResource_Create_ReturnsOk integration test
devpro Jul 13, 2025
1e53810
Add HealthCheckResource_Create_ReturnsOk integration test
devpro Jul 13, 2025
144c0e2
Improve BehaviorServiceCollectionExtensions
devpro Jul 14, 2025
1d12e04
Add HealthCheckResource_GetNotExisting_ReturnsOk test
devpro Jul 14, 2025
544c2ab
Add integration tests and start implementing state lock
devpro Jul 14, 2025
494448e
Add terraform-local-exec
devpro Jul 14, 2025
c510166
Finalize tests
devpro Jul 14, 2025
6dcf7d8
Improve test and doc
devpro Jul 14, 2025
5f1286a
Small changes
devpro Jul 16, 2025
9db6ff0
Use StateModel for tests
devpro Jul 16, 2025
3261f1d
Add tenant
devpro Jul 16, 2025
97919f2
Update samples
devpro Jul 16, 2025
206342a
Add test on InvalidModelStateBehavior
devpro Jul 16, 2025
1f1bf4a
Add user repository in db with password encryption and check
devpro Jul 16, 2025
ee75f19
Add db scripts in CI
devpro Jul 16, 2025
ceb5a78
Make script executable
devpro Jul 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,24 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkout workflow parts
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: devpro/github-workflow-parts
ref: feature/sonar-login-deprecation
path: workflow-parts
- name: Start MongoDB
uses: ./workflow-parts/mongodb/start
- name: Initialize database
run: |
mongosh mongodb://localhost:27017/terraform_backend_dev scripts/mongo-create-index.js
sudo apt-get -y install apache2-utils
./scripts/mongo-create-user.sh admin admin123 dummy
mongosh mongodb://localhost:27017/terraform_backend_dev scripts/add-user.js
shell: bash
- name: Build, lint & test
uses: ./workflow-parts/dotnet/build-lint-test
with:
Expand All @@ -61,10 +68,10 @@ jobs:
uses: ./workflow-parts/docker/build-scan
with:
docker_file: 'src/WebApi/Dockerfile'
image_tag: 1.0.${{ github.run_id }}
image_tag: 1.1.${{ github.run_id }}
image_path: 'docker.io/devprofr'
image_name: terraform-backend-mongodb
max_high_cves: 16
max_medium_cves: 11
max_high_cves: 0
max_medium_cves: 0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6 changes: 3 additions & 3 deletions .github/workflows/pkg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Checkout workflow parts
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: devpro/github-workflow-parts
ref: main
Expand All @@ -29,7 +29,7 @@ jobs:
container_username: ${{ secrets.DOCKERHUB_USERNAME }}
container_password: ${{ secrets.DOCKERHUB_TOKEN }}
docker_file: 'src/WebApi/Dockerfile'
image_tag: 1.0.${{ github.run_id }}
image_tag: 1.1.${{ github.run_id }}
image_path: 'docker.io/devprofr'
image_name: terraform-backend-mongodb
create_latest: ${{ github.ref_name == 'main' }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,6 @@ appsettings.Development.json
.terraform/
.terraform.lock.hcl
errored.tfstate

# temp script files
scripts/add-user.js
89 changes: 89 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Project development guide

## Design

The application is entirely based on open-source, cross-platform (Linux/Windows), highly performant, free, object-oriented technologies: .NET / C#.

### Projects

Project name | Technology | Project type
---------------------------|------------|---------------------------
`Common.AspNetCore` | .NET 8 | Library
`Common.AspNetCore.WebApi` | .NET 8 | Library
`Common.MongoDb` | .NET 8 | Library
`Domain` | .NET 8 | Library
`Infrastructure.MongoDb` | .NET 8 | Library
`WebApi` | ASP.NET 8 | Web application (REST API)

### Packages (NuGet)

Name | Description
-------------------------|-----------------------------
`MongoDB.Bson` | MongoDB BSON
`MongoDB.Driver` | MongoDB .NET Driver
`Swashbuckle.AspNetCore` | OpenAPI / Swagger generation
`System.Text.Json` | JSON support

### Documentation

* [OpenTofu](https://opentofu.org/)
* [MongoDB](https://www.mongodb.com/)
* [Terraform](https://www.terraform.io)
* [HTTP backend](https://developer.hashicorp.com/terraform/language/backend/http)
* [Remote state backend](https://github.com/hashicorp/terraform/tree/main/internal/backend/remote-state).

### References of other implementations

* [GitLab](https://gitlab.com/gitlab-org/manage/import/gitlab/-/blob/master/doc/user/infrastructure/terraform_state.md)
* [lib/api/terraform/state.rb](https://gitlab.com/gitlab-org/manage/import/gitlab/-/blob/master/lib/api/terraform/state.rb)
* HTTP
* [akshay/terraform-http-backend-pass](https://git.coop/akshay/terraform-http-backend-pass)
* [bhoriuchi/terraform-backend-http](https://github.com/bhoriuchi/terraform-backend-http)
* git
* [plumber-cd/terraform-backend-git](https://github.com/plumber-cd/terraform-backend-git)

## Automation

### Build (CI/CD pipelines)

GitHub Actions are triggered to automate the integration and delivery of the application:

- [CI](.github/workflows/ci.yaml)
- [PKG](.github/workflows/pkg.yaml)

GitHub project has been configured, in **General** / **Security** / **Secrets and Variables** / **Actions**:

- DOCKERHUB_TOKEN
- DOCKERHUB_USERNAME
- SONAR_HOST_URL
- SONAR_ORG
- SONAR_PROJECT_KEY
- SONAR_TOKEN

## Procedures

### Run locally the application

Create/have a MongoDB database (example with a local container but you can provision a cluster in MongoDB Atlas):

```bash
# creates a container
docker run --name mongodb -d -p 27017:27017 mongo:8.0
# (optional) adds indexes for optimal performances
docker run --rm --link mongodb \
-v "$(pwd)/scripts":/home/scripts mongo:8.0 \
bash -c "mongosh mongodb://mongodb:27017/terraform_backend_dev /home/scripts/mongo-create-index.js"
# creates one user
./scripts/mongo-create-user.sh admin admin123 dummy
docker run --rm --link mongodb \
-v "$(pwd)/scripts":/home/scripts mongo:8.0 \
bash -c "mongosh mongodb://mongodb:27017/terraform_backend_dev /home/scripts/add-user.js"
```

Run the web API (example with the command line but an IDE like Visual Studio or Rider would be nice to be able to debug):

```bash
dotnet run --project src/WebApi
```

Open Swagger in a browser: [localhost:5293/swagger](http://localhost:5293/swagger).
40 changes: 22 additions & 18 deletions Devpro.TerraformBackend.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0 - Solution Items", "0 - S
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
.gitlab-ci.yml = .gitlab-ci.yml
compose.yaml = compose.yaml
CONTRIBUTING.md = CONTRIBUTING.md
Directory.Build.props = Directory.Build.props
README.md = README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2 - Applications", "2 - Applications", "{6D13F54F-4547-49C7-8136-01BFB4BBEE1E}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3 - Applications", "3 - Applications", "{6D13F54F-4547-49C7-8136-01BFB4BBEE1E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1 - Libraries", "1 - Libraries", "{E9839BEC-B050-43E9-8EFD-34659CC92D93}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2 - Business", "2 - Business", "{E9839BEC-B050-43E9-8EFD-34659CC92D93}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApi", "src\WebApi\WebApi.csproj", "{5CD7A689-5ADB-4207-972E-6FA881AF1B1C}"
EndProject
Expand All @@ -29,29 +29,33 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{3C2E
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.AspNetCore", "src\Common.AspNetCore\Common.AspNetCore.csproj", "{F23098F5-355B-46F0-BABE-3D6E23D8EED7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "terraform-docker", "terraform-docker", "{001CB9EB-2F7E-4288-BA9B-1E01ED43B8FF}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker-nginx", "docker-nginx", "{001CB9EB-2F7E-4288-BA9B-1E01ED43B8FF}"
ProjectSection(SolutionItems) = preProject
samples\terraform-docker\main.tf = samples\terraform-docker\main.tf
samples\terraform-docker\outputs.tf = samples\terraform-docker\outputs.tf
samples\terraform-docker\providers.tf = samples\terraform-docker\providers.tf
samples\terraform-docker\README.md = samples\terraform-docker\README.md
samples\terraform-docker\variables.tf = samples\terraform-docker\variables.tf
samples\docker-nginx\main.tf = samples\docker-nginx\main.tf
samples\docker-nginx\outputs.tf = samples\docker-nginx\outputs.tf
samples\docker-nginx\providers.tf = samples\docker-nginx\providers.tf
samples\docker-nginx\README.md = samples\docker-nginx\README.md
samples\docker-nginx\variables.tf = samples\docker-nginx\variables.tf
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{7F01D180-1A34-4377-B4E5-C852D8302CE7}"
ProjectSection(SolutionItems) = preProject
scripts\mongo-create-index.js = scripts\mongo-create-index.js
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{4EC46C35-77AA-4C4E-AEAC-63A2D44C9CA6}"
ProjectSection(SolutionItems) = preProject
docs\automation.md = docs\automation.md
scripts\mongo-create-user.sh = scripts\mongo-create-user.sh
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApi.IntegrationTests", "test\WebApi.IntegrationTests\WebApi.IntegrationTests.csproj", "{B055FFAF-8261-43B1-866A-12E289D5D7DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.AspNetCore.WebApi", "src\Common.AspNetCore.WebApi\Common.AspNetCore.WebApi.csproj", "{19336002-C959-4E76-B112-861F93CF6423}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1 - Framework", "1 - Framework", "{0C1E6968-B289-4378-84CF-B64E05E643A5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "local-files", "local-files", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
ProjectSection(SolutionItems) = preProject
samples\local-files\main.tf = samples\local-files\main.tf
samples\local-files\README.md = samples\local-files\README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -94,14 +98,14 @@ Global
{5CD7A689-5ADB-4207-972E-6FA881AF1B1C} = {6D13F54F-4547-49C7-8136-01BFB4BBEE1E}
{A5CAD112-C1E6-442B-BE0E-37C697030636} = {E9839BEC-B050-43E9-8EFD-34659CC92D93}
{0429A41A-2D3A-42D4-8736-5FC0F6F0FF0C} = {E9839BEC-B050-43E9-8EFD-34659CC92D93}
{49BF313A-4ED3-4BD2-9AEE-E44A5ED19C0C} = {E9839BEC-B050-43E9-8EFD-34659CC92D93}
{49BF313A-4ED3-4BD2-9AEE-E44A5ED19C0C} = {0C1E6968-B289-4378-84CF-B64E05E643A5}
{3C2E7F7E-1F8E-49D1-AD56-EC60BEB5299D} = {7B3738E0-6F86-4358-B55C-5AAD42B24F81}
{F23098F5-355B-46F0-BABE-3D6E23D8EED7} = {E9839BEC-B050-43E9-8EFD-34659CC92D93}
{F23098F5-355B-46F0-BABE-3D6E23D8EED7} = {0C1E6968-B289-4378-84CF-B64E05E643A5}
{001CB9EB-2F7E-4288-BA9B-1E01ED43B8FF} = {3C2E7F7E-1F8E-49D1-AD56-EC60BEB5299D}
{7F01D180-1A34-4377-B4E5-C852D8302CE7} = {7B3738E0-6F86-4358-B55C-5AAD42B24F81}
{4EC46C35-77AA-4C4E-AEAC-63A2D44C9CA6} = {7B3738E0-6F86-4358-B55C-5AAD42B24F81}
{B055FFAF-8261-43B1-866A-12E289D5D7DC} = {6D13F54F-4547-49C7-8136-01BFB4BBEE1E}
{19336002-C959-4E76-B112-861F93CF6423} = {E9839BEC-B050-43E9-8EFD-34659CC92D93}
{19336002-C959-4E76-B112-861F93CF6423} = {0C1E6968-B289-4378-84CF-B64E05E643A5}
{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {3C2E7F7E-1F8E-49D1-AD56-EC60BEB5299D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC545534-6A10-475B-A0DA-3374CC025D82}
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<PropertyGroup>
<!-- edit this value to change the current MAJOR.MINOR.PATCH version -->
<VersionPrefix>1.0.2</VersionPrefix>
<VersionPrefix>1.1.0</VersionPrefix>
</PropertyGroup>

<Choose>
Expand Down
80 changes: 17 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
# Terraform backend management in MongoDB
# MongoDB HTTP backend for Terraform/OpenTofu state

[![CI](https://github.com/devpro/terraform-backend-mongodb/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/devpro/terraform-backend-mongodb/actions/workflows/ci.yaml)
[![PKG](https://github.com/devpro/terraform-backend-mongodb/actions/workflows/pkg.yaml/badge.svg?branch=main)](https://github.com/devpro/terraform-backend-mongodb/actions/workflows/pkg.yaml)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=devpro.terraform-backend-mongodb&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=devpro.terraform-backend-mongodb)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=devpro_terraform-backend-mongodb&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=devpro_terraform-backend-mongodb)
[![Docker Image Version](https://img.shields.io/docker/v/devprofr/terraform-backend-mongodb?label=Image&logo=docker)](https://hub.docker.com/r/devprofr/terraform-backend-mongodb)

Store [Terraform](https://www.terraform.io) state in [MongoDB](https://www.mongodb.com/), using
[HTTP](https://www.terraform.io/language/settings/backends/http) [backend](https://github.com/hashicorp/terraform/tree/main/internal/backend/remote-state).
Manage Terraform/OpenTofu state through a secured REST API and take advatange of MongoDB greatness!

## How to use
The [project development guide](CONTRIBUTING.md) provides the implementation details.

* Create a MongoDB database (you can provision a cluster in MongoDB Atlas)
## Quick start

```bash
# example on a MongoDB container running locally
docker run --name mongodb -d -p 27017:27017 mongo:5.0
```
1. Make sure a you have access to a MongoDB database

2. Configure the application with the MongoDB database connection information

* Run the web API
2. Run the web API

* Update the Terraform file
3. Update the Terraform file

```tf
terraform {
backend "http" {
address = "<webapi_url>/state/<project_name>"
lock_address = "<webapi_url>/state/<project_name>/lock"
unlock_address = "<webapi_url>/state/<project_name>/lock"
address = "<webapi_url>/<tenant>/state/<project_name>"
lock_address = "<webapi_url>/<tenant>/state/<project_name>/lock"
unlock_address = "<webapi_url>/<tenant>/state/<project_name>/lock"
lock_method = "POST"
unlock_method = "DELETE"
username = "<api_username>"
Expand All @@ -37,53 +35,9 @@ terraform {
}
```

* Execute usual Terraform command lines

* (Optional) Add MongoDB indexes for optimal performances

```bash
# example on a MongoDB container running locally
docker run --rm --link mongodb \
-v "$(pwd)/scripts":/home/scripts mongo:5.0 \
bash -c "mongo mongodb://mongodb:27017/terraform_backend_dev /home/scripts/mongo-create-index.js"
```

## How to demonstrate

* Run the [terraform-docker sample](samples/terraform-docker/README.md)

## How to contribute

This is a .NET 8 / C# codebase (open-source, cross-platform, free, object-oriented technologies)

### Project structure

Project name | Technology | Project type
------------------------ | ---------- | --------------------------
`Common.AspNetCore` | .NET 8 | Library
`Common.MongoDb` | .NET 8 | Library
`Common.Runtime` | .NET 8 | Library
`Domain` | .NET 8 | Library
`Infrastructure.MongoDb` | .NET 8 | Library
`WebApi` | ASP.NET 8 | Web application (REST API)

### Packages (NuGet)

Name | Description
------------------------ | ----------------------------
`MongoDB.Bson` | MongoDB BSON
`MongoDB.Driver` | MongoDB .NET Driver
`Swashbuckle.AspNetCore` | OpenAPI / Swagger generation
`System.Text.Json` | JSON support

## How to compare
4. Execute usual Terraform command lines

### Samples with other solutions
## Samples

* [GitLab](https://gitlab.com/gitlab-org/manage/import/gitlab/-/blob/master/doc/user/infrastructure/terraform_state.md)
* [lib/api/terraform/state.rb](https://gitlab.com/gitlab-org/manage/import/gitlab/-/blob/master/lib/api/terraform/state.rb)
* HTTP
* [akshay/terraform-http-backend-pass](https://git.coop/akshay/terraform-http-backend-pass)
* [bhoriuchi/terraform-backend-http](https://github.com/bhoriuchi/terraform-backend-http)
* git
* [plumber-cd/terraform-backend-git](https://github.com/plumber-cd/terraform-backend-git)
* [Make local actions on files](samples/local-files/README.md)
* [Run NGINX container with Docker](samples/docker-nginx/README.md)
2 changes: 1 addition & 1 deletion compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ services:
depends_on:
- mongodb
mongodb:
image: mongo:6.0
image: mongo:8.0
ports:
- "27017:27017"
Empty file added docs/.gitkeep
Empty file.
19 changes: 0 additions & 19 deletions docs/automation.md

This file was deleted.

Loading