Skip to content

Commit

Permalink
feat(TPLAT-339): moved module here
Browse files Browse the repository at this point in the history
Signed-off-by: tom-hauschke <[email protected]>
  • Loading branch information
tom-hauschke committed Sep 12, 2023
1 parent 92bab09 commit ea2e29c
Show file tree
Hide file tree
Showing 7 changed files with 372 additions and 37 deletions.
19 changes: 19 additions & 0 deletions .terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 66 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,73 @@
# terraform-module-template

A template repository to provide a basic setup for Terraform modules.

## Module structure

The module structure is based on the [Terraform module documentation](https://www.terraform.io/docs/modules/index.html#standard-module-structure). The following tree shows the structure of the module.

```txt
├── .gitignore
├── LICENSE
├── README.md
├── docs
│ └── README.md
├── examples
│ ├── complete
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── minimal
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
├── main.tf
├── outputs.tf
├── variables.tf
└── versions.tf
# ArgoCD Application Set

This module creates an applicationSet in an ArgoCD instance.

## Config schema for ApplicationSet

Required fields:

```yaml
values: |
# Here you can define the values for the chart
```
## Working with this template
Optional fields:
```yaml
namespace_overwrite: <namespace> # e.g. default (default: generated based on the project name + git folder name). Must be set if more than one environment is deployed in the same cluster.
chart:
repo: <chart_repo_url> # e.g. registry.hub.docker.com/tagesspiegel
name: <chart_name> # e.g. background
version: <chart_version> # e.g. 1.0.0
release_name: <chart_release_name> # e.g. background-develop
```
## Cluster selection
The cluster selection is based on the ``
<!-- BEGIN_TF_DOCS -->
## Requirements
| Name | Version |
|------|---------|
| <a name="requirement_argocd"></a> [argocd](#requirement\_argocd) | 6.0.1 |
## Providers
| Name | Version |
|------|---------|
| <a name="provider_argocd"></a> [argocd](#provider\_argocd) | 6.0.1 |
## Modules
No modules.
## Resources
| Name | Type |
|------|------|
| [argocd_application_set.this](https://registry.terraform.io/providers/oboukili/argocd/6.0.1/docs/resources/application_set) | resource |
In order to use this template, you can use the GitHub template feature. This will create a new repository based on this template. After that, you can clone the repository and start working on it.
## Inputs
### Creating a new repository based on this template
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_annotations"></a> [annotations](#input\_annotations) | Annotations to apply to the application set | `map(string)` | `{}` | no |
| <a name="input_generator"></a> [generator](#input\_generator) | The generator configuration. Only one generator can be used at a time. | <pre>object({<br> git = optional(object({<br> repo_url = string<br> revision = string<br> files = optional(list(string))<br> directories = optional(list(object({<br> path = string<br> exclude = bool<br> })))<br> }))<br> pull_request = optional(list(object({<br> requeue_after_seconds = number<br> repo = string<br> labels = list(string)<br> })))<br> })</pre> | n/a | yes |
| <a name="input_generator_segment_index_overwrite"></a> [generator\_segment\_index\_overwrite](#input\_generator\_segment\_index\_overwrite) | Optional generator setting to override the index path segment during path selection. This option should only be set if generator.git.directories is used. Otherwise it should be left empty as it may affect the behavior. If this option is set in combination with generator.git.directories and your repository contains the cluster folder name in its root directory, this option should be set to 0. In all other cases, this option should reflect the index segment level to the directory corresponding to the cluster name. | `number` | `null` | no |
| <a name="input_labels"></a> [labels](#input\_labels) | Labels to apply to the application set | `map(string)` | `{}` | no |
| <a name="input_manifest_source"></a> [manifest\_source](#input\_manifest\_source) | n/a | <pre>object({<br> helm = optional(object({<br> chart = string<br> repo_url = string<br> target_revision = string<br> release_name = string<br> }))<br> directory = optional(object({<br> repo = object({<br> url = string<br> revision = string<br> path = string<br> })<br> glob_path = optional(string)<br> }))<br> })</pre> | n/a | yes |
| <a name="input_name"></a> [name](#input\_name) | The name of the application set | `string` | n/a | yes |
| <a name="input_namespace_annotations"></a> [namespace\_annotations](#input\_namespace\_annotations) | Annotations to apply to the namespace. Only used if create\_namespace is set to true. | `map(string)` | `{}` | no |
| <a name="input_namespace_labels"></a> [namespace\_labels](#input\_namespace\_labels) | Labels to apply to the namespace. Only used if sync\_options.* CreateNamespace=true is set. | `map(string)` | `{}` | no |
| <a name="input_project_name"></a> [project\_name](#input\_project\_name) | The name of the ArgoCD project to use for this application set. If not set, this application set is special. Special application sets are managed by the platform team and therefore the ArgoCD project reference is handled differently to normal application sets. A major difference is that the ArgoCD project is not statically defined as reference but dynamically via the config directory name. | `string` | n/a | yes |
| <a name="input_sync_options"></a> [sync\_options](#input\_sync\_options) | The sync options to use | `list(string)` | <pre>[<br> "Validate=false",<br> "ApplyOutOfSyncOnly=true",<br> "CreateNamespace=true"<br>]</pre> | no |
| <a name="input_sync_retries"></a> [sync\_retries](#input\_sync\_retries) | The retry configuration for the sync policy | <pre>object({<br> duration = string<br> max_duration = string<br> factor = number<br> limit = number<br> })</pre> | <pre>{<br> "duration": "30s",<br> "factor": 2,<br> "limit": 5,<br> "max_duration": "2m"<br>}</pre> | no |
| <a name="input_target_namespace_overwrite"></a> [target\_namespace\_overwrite](#input\_target\_namespace\_overwrite) | The target namespace to use. If not set, the namespace is derived from the application set and git folder name. | `string` | `""` | no |

To get started with this template, you have to navigate https://github.com/new and select the Tagesspiegel organization. After that, you can select the `terraform-module-template` repository, enter a name for your new repository and click on `Create repository`. Please note that you have to define a name for your new repository that is not already taken and follows the naming conventions (`terraform-<provider>-<name>`).
## Outputs

![Create GitHub repository based on template](docs/github_create_repository.png)
No outputs.
<!-- END_TF_DOCS -->

If everything worked as expected, you should now have a new repository based on this template. You can now clone the repository and start working on it.
Binary file removed docs/github_create_repository.png
Binary file not shown.
148 changes: 148 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
locals {
generator_selector = var.generator_segment_index_overwrite == null ? ".path.basenameNormalized" : "(index .path.segments ${var.generator_segment_index_overwrite})"
}

resource "argocd_application_set" "this" {
metadata {
name = "${var.project_name}-${var.name}"
namespace = "argo-system"
}

spec {
go_template = true

generator {
// if the git block is not null, then we want to add it to the generator
dynamic "git" {
for_each = var.generator.git != null ? [var.generator.git] : []
content {
repo_url = var.generator.git.repo_url
revision = var.generator.git.revision
dynamic "file" {
for_each = var.generator.git.files != null ? var.generator.git.files : []
content {
path = file.value
}
}
dynamic "directory" {
for_each = var.generator.git.directories != null ? var.generator.git.directories : []
content {
path = directory.value.path
exclude = directory.value.exclude
}
}
}
}

// if the github block is not null, then we want to add it to the generator
dynamic "pull_request" {
for_each = var.generator.pull_request != null ? var.generator.pull_request : []
content {
requeue_after_seconds = pull_request.value.requeue_after_seconds
github {
owner = "urbanmedia"
repo = pull_request.value.repo
labels = pull_request.value.labels
}
}
}
}

template {
metadata {
// application names are in the format: <name>-<cluster>
// e.g. prometheus-staging
name = "${var.name}-{{ ${local.generator_selector} }}"
annotations = merge(
var.annotations,
{
"managed-by" = "argo-cd",
"application-set" = var.name
},
)
labels = merge(
var.labels,
{
"managed-by" = "argo-cd",
"application-set" = var.name
},
)
}

spec {
project = var.project_name

// TODO(@tagesspiegel/platform-engineers): We want to add the sync block here so we can support progressive syncs
// See: https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Progressive-Syncs/

dynamic "source" {
for_each = var.manifest_source.helm != null ? ["abc"] : []
content {
chart = "{{ default \"${var.manifest_source.helm.chart}\" .chart.name }}"
repo_url = "{{ default \"${var.manifest_source.helm.repo_url}\" .chart.repo }}"
target_revision = "{{ default \"${var.manifest_source.helm.target_revision}\" .chart.version }}"
helm {
release_name = "{{ default \"${var.manifest_source.helm.release_name}\" .chart.release_name }}"
values = "{{ .values }}"
}
}
}
dynamic "source" {
for_each = var.manifest_source.directory != null ? ["abc"] : []
content {
repo_url = var.manifest_source.directory.repo.url
target_revision = var.manifest_source.directory.repo.revision
path = var.manifest_source.directory.repo.path
directory {
include = var.manifest_source.directory.glob_path
recurse = true
}
}
}

destination {
name = "{{ if (eq ${local.generator_selector} \"general-purpose\") }}in-cluster{{ else }}{{ ${local.generator_selector} }}{{ end }}"
// if the target_namespace_overwrite is not empty, then we want to use it as the namespace
// (e.g. ingress-controllers (assuming "ingress-controllers" is the target_namespace_overwrite))
// otherwise we check if the configuration provided by the developer has a namespace_overwrite
// if the namespace_overwrite is not set, then we use the namespace based on the project name and git folder name
// (e.g. background-staging (assuming "background" is the project and "staging" the folder name))
// otherwise we use the namespace_overwrite provided by the developer
// (e.g. background-staging-v2 (assuming "background" is the project and "staging-v2" the namespace_overwrite))
namespace = var.target_namespace_overwrite != "" ? var.target_namespace_overwrite : "{{ if not .namespace_overwrite }}${var.project_name}-{{ ${local.generator_selector} }}{{ else }}${var.project_name}-{{ .namespace_overwrite }}{{ end }}"
}
sync_policy {
automated {
prune = true
self_heal = true
allow_empty = true
}
managed_namespace_metadata {
annotations = merge(
var.namespace_annotations,
{
"managed-by" = "argo-cd"
},
)
labels = merge(
var.namespace_labels,
{
"managed-by" = "argo-cd"
},
)
}
# Only available from ArgoCD 1.5.0 onwards
sync_options = var.sync_options
retry {
limit = var.sync_retries.limit
backoff {
duration = var.sync_retries.duration
max_duration = var.sync_retries.max_duration
factor = var.sync_retries.factor
}
}
}
}
}
}
}
Empty file removed outputs.tf
Empty file.
Loading

0 comments on commit ea2e29c

Please sign in to comment.