diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..58d3674
--- /dev/null
+++ b/.github/CODE_OF_CONDUCT.md
@@ -0,0 +1,133 @@
+
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+ community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or advances of
+ any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email address,
+ without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+info@lablabs.io.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..5249a56
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,30 @@
+# Contributing
+
+When contributing to this repository, please first create an issue and link the PR with it.
+
+Please note we have a code of conduct, please follow it in all your interactions with the project.
+
+## Pull Request Process
+
+1. Update the README.md with details of changes including example hcl blocks and [example files](./examples) if appropriate.
+2. Run pre-commit hooks `pre-commit run -a`.
+3. Once all outstanding comments and checklist items have been addressed, your contribution will be merged! Merged PRs will be included in the next release. The terraform-aws-vpc maintainers take care of updating the CHANGELOG as they merge.
+
+## Checklists for contributions
+
+- [ ] Add [semantics prefix](#semantic-pull-requests) to your PR or Commits.
+- [ ] CI tests are passing
+- [ ] README.md has been updated after any changes. The variables and outputs in the README.md has been generated (using the `terraform_docs` pre-commit hook).
+- [ ] Run pre-commit hooks `pre-commit run -a`
+
+## Semantic Pull Requests
+
+Pull Requests or Commits must follow conventional specs below:
+
+- `ci:` Changes to our CI configuration files and scripts (example scopes: GitHub Actions)
+- `docs:` Documentation only changes
+- `feat:` A new feature
+- `fix:` A bug fix
+- `refactor:` A code change that neither fixes a bug nor adds a feature
+- `style:` Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
+- `test:` Adding missing tests or correcting existing tests
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..ad2fe05
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,108 @@
+---
+name: Bug report
+description: File a bug report
+title: "bug: "
+labels: bug
+
+body:
+- type: markdown
+ attributes:
+ value: >
+ **Thank you for wanting to report a bug!**
+
+ Verify first that your issue is not [already reported on
+ GitHub][issue search].
+
+ Also test if the latest release is affected too.
+
+- type: textarea
+ attributes:
+ label: Summary
+ description: Explain the problem briefly below.
+ placeholder: >-
+ When I try to do X with teraform module from the main branch on GitHub, Y
+ breaks in a way Z under the env E. Here are all the details I know
+ about this problem...
+ validations:
+ required: true
+
+- type: dropdown
+ attributes:
+ label: Issue Type
+ description: >
+ Please select the single available option in the drop-down.
+
+
+ Why?
+
+
+ We would do it by ourselves but unfortunatelly, the curent
+ edition of GitHub Issue Forms Alpha does not support this yet 🤷
+
+
+ _We will make it easier in the future, once GitHub
+ supports dropdown defaults. Promise!_
+
+
[| no | +| [argo\_kubernetes\_manifest\_computed\_fields](#input\_argo\_kubernetes\_manifest\_computed\_fields) | List of paths of fields to be handled as "computed". The user-configured value for the field will be overridden by any different value returned by the API after apply. | `list(string)` |
{
"name": "terraform",
"value": "true"
}
]
[| no | +| [argo\_kubernetes\_manifest\_field\_manager\_force\_conflicts](#input\_argo\_kubernetes\_manifest\_field\_manager\_force\_conflicts) | Forcibly override any field manager conflicts when applying the kubernetes manifest resource | `bool` | `false` | no | +| [argo\_kubernetes\_manifest\_field\_manager\_name](#input\_argo\_kubernetes\_manifest\_field\_manager\_name) | The name of the field manager to use when applying the kubernetes manifest resource. Defaults to Terraform | `string` | `"Terraform"` | no | +| [argo\_kubernetes\_manifest\_wait\_fields](#input\_argo\_kubernetes\_manifest\_wait\_fields) | A map of fields and a corresponding regular expression with a pattern to wait for. The provider will wait until the field matches the regular expression. Use * for any value. | `map(string)` | `{}` | no | +| [argo\_metadata](#input\_argo\_metadata) | ArgoCD Application metadata configuration. Override or create additional metadata parameters | `map` |
"metadata.labels",
"metadata.annotations"
]
{| no | | [argo\_namespace](#input\_argo\_namespace) | Namespace to deploy ArgoCD application CRD to | `string` | `"argo"` | no | | [argo\_project](#input\_argo\_project) | ArgoCD Application project | `string` | `"default"` | no | +| [argo\_spec](#input\_argo\_spec) | ArgoCD Application spec configuration. Override or create additional spec parameters | `map` | `{}` | no | | [argo\_sync\_policy](#input\_argo\_sync\_policy) | ArgoCD syncPolicy manifest parameter | `map` | `{}` | no | | [enabled](#input\_enabled) | Variable indicating whether deployment is enabled | `bool` | `true` | no | +| [helm\_atomic](#input\_helm\_atomic) | If set, installation process purges chart on fail. The wait flag will be set automatically if atomic is used | `bool` | `false` | no | | [helm\_chart\_name](#input\_helm\_chart\_name) | Helm chart name to be installed | `string` | `"cluster-autoscaler"` | no | -| [helm\_chart\_version](#input\_helm\_chart\_version) | Version of the Helm chart | `string` | `"9.10.3"` | no | +| [helm\_chart\_version](#input\_helm\_chart\_version) | Version of the Helm chart | `string` | `"9.19.1"` | no | +| [helm\_cleanup\_on\_fail](#input\_helm\_cleanup\_on\_fail) | Allow deletion of new resources created in this helm upgrade when upgrade fails | `bool` | `false` | no | | [helm\_create\_namespace](#input\_helm\_create\_namespace) | Create the namespace if it does not yet exist | `bool` | `true` | no | +| [helm\_dependency\_update](#input\_helm\_dependency\_update) | Runs helm dependency update before installing the chart | `bool` | `false` | no | +| [helm\_description](#input\_helm\_description) | Set helm release description attribute (visible in the history) | `string` | `""` | no | +| [helm\_devel](#input\_helm\_devel) | Use helm chart development versions, too. Equivalent to version '>0.0.0-0'. If version is set, this is ignored | `bool` | `false` | no | +| [helm\_disable\_openapi\_validation](#input\_helm\_disable\_openapi\_validation) | If set, the installation process will not validate rendered helm templates against the Kubernetes OpenAPI Schema | `bool` | `false` | no | +| [helm\_disable\_webhooks](#input\_helm\_disable\_webhooks) | Prevent helm chart hooks from running | `bool` | `false` | no | +| [helm\_force\_update](#input\_helm\_force\_update) | Force helm resource update through delete/recreate if needed | `bool` | `false` | no | +| [helm\_keyring](#input\_helm\_keyring) | Location of public keys used for verification. Used only if helm\_package\_verify is true | `string` | `"~/.gnupg/pubring.gpg"` | no | +| [helm\_lint](#input\_helm\_lint) | Run the helm chart linter during the plan | `bool` | `false` | no | +| [helm\_package\_verify](#input\_helm\_package\_verify) | Verify the package before installing it. Helm uses a provenance file to verify the integrity of the chart; this must be hosted alongside the chart | `bool` | `false` | no | +| [helm\_postrender](#input\_helm\_postrender) | Value block with a path to a binary file to run after helm renders the manifest which can alter the manifest contents | `map(any)` | `{}` | no | +| [helm\_recreate\_pods](#input\_helm\_recreate\_pods) | Perform pods restart during helm upgrade/rollback | `bool` | `false` | no | +| [helm\_release\_max\_history](#input\_helm\_release\_max\_history) | Maximum number of release versions stored per release | `number` | `0` | no | | [helm\_release\_name](#input\_helm\_release\_name) | Helm release name | `string` | `"cluster-autoscaler"` | no | +| [helm\_render\_subchart\_notes](#input\_helm\_render\_subchart\_notes) | If set, render helm subchart notes along with the parent | `bool` | `true` | no | +| [helm\_replace](#input\_helm\_replace) | Re-use the given name of helm release, only if that name is a deleted release which remains in the history. This is unsafe in production | `bool` | `false` | no | +| [helm\_repo\_ca\_file](#input\_helm\_repo\_ca\_file) | Helm repositories cert file | `string` | `""` | no | +| [helm\_repo\_cert\_file](#input\_helm\_repo\_cert\_file) | Helm repositories cert file | `string` | `""` | no | +| [helm\_repo\_key\_file](#input\_helm\_repo\_key\_file) | Helm repositories cert key file | `string` | `""` | no | +| [helm\_repo\_password](#input\_helm\_repo\_password) | Password for HTTP basic authentication against the helm repository | `string` | `""` | no | | [helm\_repo\_url](#input\_helm\_repo\_url) | Helm repository | `string` | `"https://kubernetes.github.io/autoscaler"` | no | -| [k8s\_irsa\_role\_create](#input\_k8s\_irsa\_role\_create) | Whether to create IRSA role and annotate service account | `bool` | `true` | no | -| [k8s\_namespace](#input\_k8s\_namespace) | The K8s namespace in which the node-problem-detector service account has been created | `string` | `"cluster-autoscaler"` | no | -| [k8s\_rbac\_create](#input\_k8s\_rbac\_create) | Whether to create and use RBAC resources | `bool` | `true` | no | -| [k8s\_service\_account\_create](#input\_k8s\_service\_account\_create) | Whether to create Service Account | `bool` | `true` | no | -| [k8s\_service\_account\_name](#input\_k8s\_service\_account\_name) | The k8s cluster-autoscaler service account name | `string` | `"cluster-autoscaler"` | no | -| [settings](#input\_settings) | Additional settings which will be passed to the Helm chart values, see https://hub.helm.sh/charts/stable/cluster-autoscaler | `map(any)` | `{}` | no | +| [helm\_repo\_username](#input\_helm\_repo\_username) | Username for HTTP basic authentication against the helm repository | `string` | `""` | no | +| [helm\_reset\_values](#input\_helm\_reset\_values) | When upgrading, reset the values to the ones built into the helm chart | `bool` | `false` | no | +| [helm\_reuse\_values](#input\_helm\_reuse\_values) | When upgrading, reuse the last helm release's values and merge in any overrides. If 'helm\_reset\_values' is specified, this is ignored | `bool` | `false` | no | +| [helm\_set\_sensitive](#input\_helm\_set\_sensitive) | Value block with custom sensitive values to be merged with the values yaml that won't be exposed in the plan's diff | `map(any)` | `{}` | no | +| [helm\_skip\_crds](#input\_helm\_skip\_crds) | If set, no CRDs will be installed before helm release | `bool` | `false` | no | +| [helm\_timeout](#input\_helm\_timeout) | Time in seconds to wait for any individual kubernetes operation (like Jobs for hooks) | `number` | `300` | no | +| [helm\_wait](#input\_helm\_wait) | Will wait until all helm release resources are in a ready state before marking the release as successful. It will wait for as long as timeout | `bool` | `false` | no | +| [helm\_wait\_for\_jobs](#input\_helm\_wait\_for\_jobs) | If wait is enabled, will wait until all helm Jobs have been completed before marking the release as successful. It will wait for as long as timeout | `bool` | `false` | no | +| [irsa\_additional\_policies](#input\_irsa\_additional\_policies) | Map of the additional policies to be attached to default role. Where key is arbitrary id and value is policy arn. | `map(string)` | `{}` | no | +| [irsa\_assume\_role\_arn](#input\_irsa\_assume\_role\_arn) | Assume role arn. Assume role must be enabled. | `string` | `""` | no | +| [irsa\_assume\_role\_enabled](#input\_irsa\_assume\_role\_enabled) | Whether IRSA is allowed to assume role defined by assume\_role\_arn. | `bool` | `false` | no | +| [irsa\_policy\_enabled](#input\_irsa\_policy\_enabled) | Whether to create opinionated policy to allow operations on specified zones in `policy_allowed_zone_ids`. | `bool` | `true` | no | +| [irsa\_role\_create](#input\_irsa\_role\_create) | Whether to create IRSA role and annotate service account | `bool` | `true` | no | +| [irsa\_role\_name\_prefix](#input\_irsa\_role\_name\_prefix) | The IRSA role name prefix for vector | `string` | `"cluster-autoscaler-irsa"` | no | +| [irsa\_tags](#input\_irsa\_tags) | IRSA resources tags | `map(string)` | `{}` | no | +| [namespace](#input\_namespace) | The K8s namespace in which the node-problem-detector service account has been created | `string` | `"cluster-autoscaler"` | no | +| [rbac\_create](#input\_rbac\_create) | Whether to create and use RBAC resources | `bool` | `true` | no | +| [service\_account\_create](#input\_service\_account\_create) | Whether to create Service Account | `bool` | `true` | no | +| [service\_account\_name](#input\_service\_account\_name) | The k8s cluster-autoscaler service account name | `string` | `"cluster-autoscaler"` | no | +| [settings](#input\_settings) | Additional helm sets which will be passed to the Helm chart values, see https://hub.helm.sh/charts/stable/cluster-autoscaler | `map(any)` | `{}` | no | | [values](#input\_values) | Additional yaml encoded values which will be passed to the Helm chart, see https://hub.helm.sh/charts/stable/cluster-autoscaler | `string` | `""` | no | ## Outputs -No outputs. +| Name | Description | +|------|-------------| +| [helm\_release\_application\_metadata](#output\_helm\_release\_application\_metadata) | Argo application helm release attributes | +| [helm\_release\_metadata](#output\_helm\_release\_metadata) | Helm release attributes | +| [iam\_role\_attributes](#output\_iam\_role\_attributes) | Vector IAM role atributes | +| [kubernetes\_application\_attributes](#output\_kubernetes\_application\_attributes) | Argo kubernetes manifest attributes | ## Contributing and reporting issues diff --git a/argo.tf b/argo.tf index c20c4f7..a952837 100644 --- a/argo.tf +++ b/argo.tf @@ -1,4 +1,9 @@ locals { + argo_application_metadata = { + "labels" : try(var.argo_metadata.labels, {}), + "annotations" : try(var.argo_metadata.annotations, {}), + "finalizers" : try(var.argo_metadata.finalizers, []) + } argo_application_values = { "project" : var.argo_project "source" : { @@ -8,48 +13,74 @@ locals { "helm" : { "releaseName" : var.helm_release_name "parameters" : [for k, v in var.settings : tomap({ "forceString" : true, "name" : k, "value" : v })] - "values" : data.utils_deep_merge_yaml.values[0].output + "values" : var.enabled ? data.utils_deep_merge_yaml.values[0].output : "" } } "destination" : { - "server" : var.argo_destionation_server - "namespace" : var.k8s_namespace + "server" : var.argo_destination_server + "namespace" : var.namespace } "syncPolicy" : var.argo_sync_policy "info" : var.argo_info } } -data "utils_deep_merge_yaml" "argo_application_values" { - count = var.enabled && var.argo_application_enabled && var.argo_application_use_helm ? 1 : 0 +data "utils_deep_merge_yaml" "argo_helm_values" { + count = var.enabled && var.argo_enabled && var.argo_helm_enabled ? 1 : 0 input = compact([ - yamlencode(local.argo_application_values), - var.argo_application_values + yamlencode({ + "apiVersion" : var.argo_apiversion + }), + yamlencode({ + "spec" : local.argo_application_values + }), + yamlencode({ + "spec" : var.argo_spec + }), + yamlencode( + local.argo_application_metadata + ) ]) } -resource "helm_release" "argocd_application" { - count = var.enabled && var.argo_application_enabled && var.argo_application_use_helm ? 1 : 0 + +resource "helm_release" "argo_application" { + count = var.enabled && var.argo_enabled && var.argo_helm_enabled ? 1 : 0 chart = "${path.module}/helm/argocd-application" name = var.helm_release_name namespace = var.argo_namespace values = [ - data.utils_deep_merge_yaml.argo_application_values[0].output + data.utils_deep_merge_yaml.argo_helm_values[0].output, + var.argo_helm_values ] } -resource "kubernetes_manifest" "self" { - count = var.enabled && var.argo_application_enabled && !var.argo_application_use_helm ? 1 : 0 +resource "kubernetes_manifest" "this" { + count = var.enabled && var.argo_enabled && !var.argo_helm_enabled ? 1 : 0 manifest = { - "apiVersion" = "argoproj.io/v1alpha1" + "apiVersion" = var.argo_apiversion "kind" = "Application" - "metadata" = { - "name" = var.helm_release_name - "namespace" = var.argo_namespace - } - "spec" = local.argo_application_values + "metadata" = merge( + local.argo_application_metadata, + { "name" = var.helm_release_name }, + { "namespace" = var.argo_namespace }, + ) + "spec" = merge( + local.argo_application_values, + var.argo_spec + ) + } + computed_fields = var.argo_kubernetes_manifest_computed_fields + + field_manager { + name = var.argo_kubernetes_manifest_field_manager_name + force_conflicts = var.argo_kubernetes_manifest_field_manager_force_conflicts + } + + wait { + fields = var.argo_kubernetes_manifest_wait_fields } } diff --git a/examples/basic/README.md b/examples/basic/README.md index 5e415cb..918d18a 100644 --- a/examples/basic/README.md +++ b/examples/basic/README.md @@ -11,7 +11,9 @@ No requirements. | Name | Source | Version | |------|--------|---------| -| [cluster\_autoscaler](#module\_cluster\_autoscaler) | ../../ | n/a | +| [cluster-autoscaler\_argo\_helm](#module\_cluster-autoscaler\_argo\_helm) | ../../ | n/a | +| [cluster-autoscaler\_argo\_manifests](#module\_cluster-autoscaler\_argo\_manifests) | ../../ | n/a | +| [cluster-autoscaler\_helm](#module\_cluster-autoscaler\_helm) | ../../ | n/a | | [eks\_cluster](#module\_eks\_cluster) | cloudposse/eks-cluster/aws | 0.43.2 | | [eks\_node\_group](#module\_eks\_node\_group) | cloudposse/eks-node-group/aws | 0.25.0 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | 3.6.0 | diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 4c8d66a..64c925d 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -32,10 +32,72 @@ module "eks_node_group" { depends_on = [module.eks_cluster.kubernetes_config_map_id] } -module "cluster_autoscaler" { +module "cluster-autoscaler_helm" { source = "../../" + enabled = true + argo_enabled = false + argo_helm_enabled = false + + cluster_name = module.eks_cluster.eks_cluster_id + cluster_identity_oidc_issuer = module.eks_cluster.eks_cluster_identity_oidc_issuer + cluster_identity_oidc_issuer_arn = module.eks_cluster.eks_cluster_identity_oidc_issuer_arn + + values = yamlencode({ + "image" : { + "tag" : "v1.21.2" + } + }) + + argo_sync_policy = { + "automated" : {} + "syncOptions" = ["CreateNamespace=true"] + } +} + +module "cluster-autoscaler_argo_manifests" { + source = "../../" + + enabled = true + argo_enabled = true + argo_helm_enabled = false + + cluster_name = module.eks_cluster.eks_cluster_id + cluster_identity_oidc_issuer = module.eks_cluster.eks_cluster_identity_oidc_issuer + cluster_identity_oidc_issuer_arn = module.eks_cluster.eks_cluster_identity_oidc_issuer_arn + + values = yamlencode({ + "image" : { + "tag" : "v1.21.2" + } + }) + + argo_sync_policy = { + "automated" : {} + "syncOptions" = ["CreateNamespace=true"] + } +} + + +module "cluster-autoscaler_argo_helm" { + source = "../../" + + enabled = true + argo_enabled = true + argo_helm_enabled = true + cluster_name = module.eks_cluster.eks_cluster_id cluster_identity_oidc_issuer = module.eks_cluster.eks_cluster_identity_oidc_issuer cluster_identity_oidc_issuer_arn = module.eks_cluster.eks_cluster_identity_oidc_issuer_arn + + values = yamlencode({ + "image" : { + "tag" : "v1.21.2" + } + }) + + argo_sync_policy = { + "automated" : {} + "syncOptions" = ["CreateNamespace=true"] + } } diff --git a/helm.tf b/helm.tf new file mode 100644 index 0000000..2592884 --- /dev/null +++ b/helm.tf @@ -0,0 +1,63 @@ +resource "helm_release" "this" { + count = var.enabled && !var.argo_enabled ? 1 : 0 + chart = var.helm_chart_name + create_namespace = var.helm_create_namespace + namespace = var.namespace + name = var.helm_release_name + version = var.helm_chart_version + repository = var.helm_repo_url + + repository_key_file = var.helm_repo_key_file + repository_cert_file = var.helm_repo_cert_file + repository_ca_file = var.helm_repo_ca_file + repository_username = var.helm_repo_username + repository_password = var.helm_repo_password + devel = var.helm_devel + verify = var.helm_package_verify + keyring = var.helm_keyring + timeout = var.helm_timeout + disable_webhooks = var.helm_disable_webhooks + reset_values = var.helm_reset_values + reuse_values = var.helm_reuse_values + force_update = var.helm_force_update + recreate_pods = var.helm_recreate_pods + cleanup_on_fail = var.helm_cleanup_on_fail + max_history = var.helm_release_max_history + atomic = var.helm_atomic + wait = var.helm_wait + wait_for_jobs = var.helm_wait_for_jobs + skip_crds = var.helm_skip_crds + render_subchart_notes = var.helm_render_subchart_notes + disable_openapi_validation = var.helm_disable_openapi_validation + dependency_update = var.helm_dependency_update + replace = var.helm_replace + description = var.helm_description + lint = var.helm_lint + + values = [ + data.utils_deep_merge_yaml.values[0].output + ] + + dynamic "set" { + for_each = var.settings + content { + name = set.key + value = set.value + } + } + + dynamic "set_sensitive" { + for_each = var.helm_set_sensitive + content { + name = set_sensitive.key + value = set_sensitive.value + } + } + + dynamic "postrender" { + for_each = var.helm_postrender + content { + binary_path = postrender.value + } + } +} diff --git a/helm/argocd-application/templates/application.yaml b/helm/argocd-application/templates/application.yaml index ec30753..3117c37 100644 --- a/helm/argocd-application/templates/application.yaml +++ b/helm/argocd-application/templates/application.yaml @@ -1,24 +1,19 @@ -apiVersion: argoproj.io/v1alpha1 +apiVersion: {{ .Values.apiVersion }} kind: Application metadata: name: {{ include "argocd_application.fullname" . }} labels: {{- include "argocd_application.labels" . | nindent 4 }} + {{- if .Values.labels }} + {{ toYaml .Values.labels | nindent 4 }} + {{- end }} + annotations: + {{- if .Values.annotations }} + {{ toYaml .Values.annotations | indent 4 }} + {{- end }} + finalizers: + {{- if .Values.finalizers }} + {{ toYaml .Values.finalizers | indent 4 }} + {{- end }} spec: - project: {{ .Values.project }} - {{ with .Values.source }} - source: - {{- toYaml . | nindent 4 }} - {{- end }} - {{ with .Values.destination }} - destination: - {{- toYaml . | nindent 4 }} - {{- end }} - {{ with .Values.syncPolicy }} - syncPolicy: - {{- toYaml . | nindent 4 }} - {{- end }} - {{ with .Values.info }} - info: - {{- toYaml . | nindent 4 }} - {{- end }} + {{ toYaml .Values.spec | nindent 2 }} diff --git a/iam.tf b/iam.tf index e98e571..7a43b71 100644 --- a/iam.tf +++ b/iam.tf @@ -1,5 +1,9 @@ -data "aws_iam_policy_document" "cluster_autoscaler" { - count = local.k8s_irsa_role_create ? 1 : 0 +locals { + irsa_role_create = var.enabled && var.rbac_create && var.service_account_create && var.irsa_role_create +} + +data "aws_iam_policy_document" "this" { + count = local.irsa_role_create && var.irsa_policy_enabled && !var.irsa_assume_role_enabled ? 1 : 0 statement { sid = "Autoscaling" @@ -24,17 +28,34 @@ data "aws_iam_policy_document" "cluster_autoscaler" { } -resource "aws_iam_policy" "cluster_autoscaler" { - count = local.k8s_irsa_role_create ? 1 : 0 - name = "${var.cluster_name}-cluster-autoscaler" +data "aws_iam_policy_document" "this_assume" { + count = local.irsa_role_create && var.irsa_assume_role_enabled ? 1 : 0 + + statement { + sid = "AllowAssumeClusterAutoscalerRole" + effect = "Allow" + actions = [ + "sts:AssumeRole" + ] + resources = [ + var.irsa_assume_role_arn + ] + } +} + +resource "aws_iam_policy" "this" { + count = local.irsa_role_create && (var.irsa_policy_enabled || var.irsa_assume_role_enabled) ? 1 : 0 + + name = "${var.irsa_role_name_prefix}-${var.helm_chart_name}" path = "/" description = "Policy for cluster-autoscaler service" + policy = var.irsa_assume_role_enabled ? data.aws_iam_policy_document.this_assume[0].json : data.aws_iam_policy_document.this[0].json - policy = data.aws_iam_policy_document.cluster_autoscaler[0].json + tags = var.irsa_tags } -data "aws_iam_policy_document" "cluster_autoscaler_assume" { - count = local.k8s_irsa_role_create ? 1 : 0 +data "aws_iam_policy_document" "this_irsa" { + count = local.irsa_role_create ? 1 : 0 statement { actions = ["sts:AssumeRoleWithWebIdentity"] @@ -49,7 +70,7 @@ data "aws_iam_policy_document" "cluster_autoscaler_assume" { variable = "${replace(var.cluster_identity_oidc_issuer, "https://", "")}:sub" values = [ - "system:serviceaccount:${var.k8s_namespace}:${var.k8s_service_account_name}", + "system:serviceaccount:${var.namespace}:${var.service_account_name}", ] } @@ -57,14 +78,22 @@ data "aws_iam_policy_document" "cluster_autoscaler_assume" { } } -resource "aws_iam_role" "cluster_autoscaler" { - count = local.k8s_irsa_role_create ? 1 : 0 - name = "${var.cluster_name}-cluster-autoscaler" - assume_role_policy = data.aws_iam_policy_document.cluster_autoscaler_assume[0].json +resource "aws_iam_role" "this" { + count = local.irsa_role_create ? 1 : 0 + name = "${var.irsa_role_name_prefix}-${var.helm_chart_name}" + assume_role_policy = data.aws_iam_policy_document.this_irsa[0].json + tags = var.irsa_tags +} + +resource "aws_iam_role_policy_attachment" "this" { + count = local.irsa_role_create ? 1 : 0 + role = aws_iam_role.this[0].name + policy_arn = aws_iam_policy.this[0].arn } -resource "aws_iam_role_policy_attachment" "cluster_autoscaler" { - count = local.k8s_irsa_role_create ? 1 : 0 - role = aws_iam_role.cluster_autoscaler[0].name - policy_arn = aws_iam_policy.cluster_autoscaler[0].arn +resource "aws_iam_role_policy_attachment" "this_additional" { + for_each = local.irsa_role_create ? var.irsa_additional_policies : {} + + role = aws_iam_role.this[0].name + policy_arn = each.value } diff --git a/main.tf b/main.tf deleted file mode 100644 index 94418d4..0000000 --- a/main.tf +++ /dev/null @@ -1,52 +0,0 @@ -locals { - k8s_irsa_role_create = var.enabled && var.k8s_rbac_create && var.k8s_service_account_create && var.k8s_irsa_role_create - - values = yamlencode({ - "awsRegion" : data.aws_region.current.name, - "autoDiscovery" : { - "clusterName" : var.cluster_name - }, - "rbac" : { - "create" : var.k8s_rbac_create, - "serviceAccount" : { - "create" : var.k8s_service_account_create, - "name" : var.k8s_service_account_name - "annotations" : { - "eks.amazonaws.com/role-arn" : local.k8s_irsa_role_create ? aws_iam_role.cluster_autoscaler[0].arn : "" - } - } - } - }) -} - -data "aws_region" "current" {} - -data "utils_deep_merge_yaml" "values" { - count = var.enabled ? 1 : 0 - input = compact([ - local.values, - var.values - ]) -} - -resource "helm_release" "cluster_autoscaler" { - count = var.enabled && !var.argo_application_enabled ? 1 : 0 - chart = var.helm_chart_name - create_namespace = var.helm_create_namespace - namespace = var.k8s_namespace - name = var.helm_release_name - version = var.helm_chart_version - repository = var.helm_repo_url - - values = [ - data.utils_deep_merge_yaml.values[0].output - ] - - dynamic "set" { - for_each = var.settings - content { - name = set.key - value = set.value - } - } -} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..39b56a3 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,19 @@ +output "helm_release_metadata" { + description = "Helm release attributes" + value = try(helm_release.this[0].metadata, {}) +} + +output "helm_release_application_metadata" { + description = "Argo application helm release attributes" + value = try(helm_release.argo_application[0].metadata, {}) +} + +output "kubernetes_application_attributes" { + description = "Argo kubernetes manifest attributes" + value = try(kubernetes_manifest.this, {}) +} + +output "iam_role_attributes" { + description = "Vector IAM role atributes" + value = try(aws_iam_role.this[0], {}) +} diff --git a/values.tf b/values.tf new file mode 100644 index 0000000..0b5f4e5 --- /dev/null +++ b/values.tf @@ -0,0 +1,28 @@ +data "aws_region" "current" {} + +locals { + values_default = yamlencode({ + "awsRegion" : data.aws_region.current.name, + "autoDiscovery" : { + "clusterName" : var.cluster_name + }, + "rbac" : { + "create" : var.rbac_create, + "serviceAccount" : { + "create" : var.service_account_create, + "name" : var.service_account_name + "annotations" : { + "eks.amazonaws.com/role-arn" : local.irsa_role_create ? aws_iam_role.this[0].arn : "" + } + } + } + }) +} + +data "utils_deep_merge_yaml" "values" { + count = var.enabled ? 1 : 0 + input = compact([ + local.values_default, + var.values + ]) +} diff --git a/variables.tf b/variables.tf index c2fc340..e74b3a7 100644 --- a/variables.tf +++ b/variables.tf @@ -27,7 +27,7 @@ variable "helm_chart_name" { variable "helm_chart_version" { type = string - default = "9.10.3" + default = "9.19.1" description = "Version of the Helm chart" } @@ -48,31 +48,60 @@ variable "helm_create_namespace" { description = "Create the namespace if it does not yet exist" } -variable "k8s_namespace" { +variable "namespace" { type = string default = "cluster-autoscaler" description = "The K8s namespace in which the node-problem-detector service account has been created" } -variable "k8s_rbac_create" { +variable "rbac_create" { type = bool default = true description = "Whether to create and use RBAC resources" } -variable "k8s_service_account_create" { +variable "service_account_create" { type = bool default = true description = "Whether to create Service Account" } -variable "k8s_irsa_role_create" { +variable "irsa_role_create" { type = bool default = true description = "Whether to create IRSA role and annotate service account" } -variable "k8s_service_account_name" { +variable "irsa_policy_enabled" { + type = bool + default = true + description = "Whether to create opinionated policy to allow operations on specified zones in `policy_allowed_zone_ids`." +} + +variable "irsa_assume_role_enabled" { + type = bool + default = false + description = "Whether IRSA is allowed to assume role defined by assume_role_arn." +} + +variable "irsa_assume_role_arn" { + default = "" + description = "Assume role arn. Assume role must be enabled." +} + +variable "irsa_additional_policies" { + type = map(string) + default = {} + description = "Map of the additional policies to be attached to default role. Where key is arbitrary id and value is policy arn." +} + +variable "irsa_role_name_prefix" { + type = string + default = "cluster-autoscaler-irsa" + description = "The IRSA role name prefix for vector" +} + +variable "service_account_name" { default = "cluster-autoscaler" description = "The k8s cluster-autoscaler service account name" } @@ -80,7 +109,19 @@ variable "k8s_service_account_name" { variable "settings" { type = map(any) default = {} - description = "Additional settings which will be passed to the Helm chart values, see https://hub.helm.sh/charts/stable/cluster-autoscaler" + description = "Additional helm sets which will be passed to the Helm chart values, see https://hub.helm.sh/charts/stable/cluster-autoscaler" +} + +variable "helm_set_sensitive" { + type = map(any) + default = {} + description = "Value block with custom sensitive values to be merged with the values yaml that won't be exposed in the plan's diff" +} + +variable "helm_postrender" { + type = map(any) + default = {} + description = "Value block with a path to a binary file to run after helm renders the manifest which can alter the manifest contents" } variable "values" { @@ -95,24 +136,19 @@ variable "argo_namespace" { description = "Namespace to deploy ArgoCD application CRD to" } -variable "argo_application_enabled" { +variable "argo_enabled" { type = bool default = false description = "If set to true, the module will be deployed as ArgoCD application, otherwise it will be deployed as a Helm release" } -variable "argo_application_use_helm" { +variable "argo_helm_enabled" { type = bool default = false description = "If set to true, the ArgoCD Application manifest will be deployed using Kubernetes provider as a Helm release. Otherwise it'll be deployed as a Kubernetes manifest. See Readme for more info" } -variable "argo_application_values" { - default = "" - description = "Value overrides to use when deploying argo application object with helm" -} - -variable "argo_destionation_server" { +variable "argo_destination_server" { type = string default = "https://kubernetes.default.svc" description = "Destination server for ArgoCD Application" @@ -136,3 +172,213 @@ variable "argo_sync_policy" { description = "ArgoCD syncPolicy manifest parameter" default = {} } + +variable "helm_repo_key_file" { + type = string + default = "" + description = "Helm repositories cert key file" +} + +variable "helm_repo_cert_file" { + type = string + default = "" + description = "Helm repositories cert file" +} + +variable "helm_repo_ca_file" { + type = string + default = "" + description = "Helm repositories cert file" +} + +variable "helm_repo_username" { + type = string + default = "" + description = "Username for HTTP basic authentication against the helm repository" +} + +variable "helm_repo_password" { + type = string + default = "" + description = "Password for HTTP basic authentication against the helm repository" +} + +variable "helm_devel" { + type = bool + default = false + description = "Use helm chart development versions, too. Equivalent to version '>0.0.0-0'. If version is set, this is ignored" +} + +variable "helm_package_verify" { + type = bool + default = false + description = "Verify the package before installing it. Helm uses a provenance file to verify the integrity of the chart; this must be hosted alongside the chart" +} + +variable "helm_keyring" { + type = string + default = "~/.gnupg/pubring.gpg" + description = "Location of public keys used for verification. Used only if helm_package_verify is true" +} + +variable "helm_timeout" { + type = number + default = 300 + description = "Time in seconds to wait for any individual kubernetes operation (like Jobs for hooks)" +} + +variable "helm_disable_webhooks" { + type = bool + default = false + description = "Prevent helm chart hooks from running" +} + +variable "helm_reset_values" { + type = bool + default = false + description = "When upgrading, reset the values to the ones built into the helm chart" +} + +variable "helm_reuse_values" { + type = bool + default = false + description = "When upgrading, reuse the last helm release's values and merge in any overrides. If 'helm_reset_values' is specified, this is ignored" +} + +variable "helm_force_update" { + type = bool + default = false + description = "Force helm resource update through delete/recreate if needed" +} + +variable "helm_recreate_pods" { + type = bool + default = false + description = "Perform pods restart during helm upgrade/rollback" +} + +variable "helm_cleanup_on_fail" { + type = bool + default = false + description = "Allow deletion of new resources created in this helm upgrade when upgrade fails" +} + +variable "helm_release_max_history" { + type = number + default = 0 + description = "Maximum number of release versions stored per release" +} + +variable "helm_atomic" { + type = bool + default = false + description = "If set, installation process purges chart on fail. The wait flag will be set automatically if atomic is used" +} + +variable "helm_wait" { + type = bool + default = false + description = "Will wait until all helm release resources are in a ready state before marking the release as successful. It will wait for as long as timeout" +} + +variable "helm_wait_for_jobs" { + type = bool + default = false + description = "If wait is enabled, will wait until all helm Jobs have been completed before marking the release as successful. It will wait for as long as timeout" +} + +variable "helm_skip_crds" { + type = bool + default = false + description = "If set, no CRDs will be installed before helm release" +} + +variable "helm_render_subchart_notes" { + type = bool + default = true + description = "If set, render helm subchart notes along with the parent" +} + +variable "helm_disable_openapi_validation" { + type = bool + default = false + description = "If set, the installation process will not validate rendered helm templates against the Kubernetes OpenAPI Schema" +} + +variable "helm_dependency_update" { + type = bool + default = false + description = "Runs helm dependency update before installing the chart" +} + +variable "helm_replace" { + type = bool + default = false + description = "Re-use the given name of helm release, only if that name is a deleted release which remains in the history. This is unsafe in production" +} + +variable "helm_description" { + type = string + default = "" + description = "Set helm release description attribute (visible in the history)" +} + +variable "helm_lint" { + type = bool + default = false + description = "Run the helm chart linter during the plan" +} + +variable "argo_metadata" { + default = { + "finalizers" : [ + "resources-finalizer.argocd.argoproj.io" + ] + } + description = "ArgoCD Application metadata configuration. Override or create additional metadata parameters" +} + +variable "argo_apiversion" { + default = "argoproj.io/v1alpha1" + description = "ArgoCD Appliction apiVersion" +} + +variable "argo_spec" { + default = {} + description = "ArgoCD Application spec configuration. Override or create additional spec parameters" +} + +variable "argo_helm_values" { + type = string + default = "" + description = "Value overrides to use when deploying argo application object with helm" +} + +variable "argo_kubernetes_manifest_computed_fields" { + type = list(string) + default = ["metadata.labels", "metadata.annotations"] + description = "List of paths of fields to be handled as \"computed\". The user-configured value for the field will be overridden by any different value returned by the API after apply." +} + +variable "argo_kubernetes_manifest_field_manager_name" { + default = "Terraform" + description = "The name of the field manager to use when applying the kubernetes manifest resource. Defaults to Terraform" +} + +variable "argo_kubernetes_manifest_field_manager_force_conflicts" { + type = bool + default = false + description = "Forcibly override any field manager conflicts when applying the kubernetes manifest resource" +} + +variable "argo_kubernetes_manifest_wait_fields" { + type = map(string) + default = {} + description = "A map of fields and a corresponding regular expression with a pattern to wait for. The provider will wait until the field matches the regular expression. Use * for any value." +} + +variable "irsa_tags" { + type = map(string) + default = {} + description = "IRSA resources tags" +} diff --git a/versions.tf b/versions.tf index 603dee4..ea8c3a1 100644 --- a/versions.tf +++ b/versions.tf @@ -1,18 +1,22 @@ terraform { - required_version = ">= 0.13" + required_version = ">= 1.0" required_providers { aws = { source = "hashicorp/aws" - version = ">= 2.0" + version = ">= 4.19.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.11.0" } helm = { source = "hashicorp/helm" - version = ">= 1.0" + version = ">= 2.6.0" } utils = { source = "cloudposse/utils" - version = ">= 0.12.0" + version = ">= 0.17.0" } } }
"finalizers": [
"resources-finalizer.argocd.argoproj.io"
]
}