Features block terraform - azure-devops

terraform init successfully initializes but gets stuck on terraform plan.
The error is related to the feature block. I'm unsure where to add the feature block:
Insufficient features blocks (source code not available) At least 1 "features" blocks are required.
My configuration looks like
terraform {
required_version = ">= 0.11"
backend "azurerm" {
features {}
}
}
I tried removing and adding features block as github page

When you run updated version of terraform you need to define another block defined below
provider "azurerm" {
features {}
}

An other reason for the message could be, that a named provider is in use:
provider "azurerm" {
alias = "some_name" # <- here
features {}
}
But not specified on the resource:
resource "azurerm_resource_group" "example" {
# might this block is missing
# -> provider = azurerm.some_name
name = var.rg_name
location = var.region
}
Error message:
terraform plan
╷
│ Error: Insufficient features blocks
│
│ on <empty> line 0:
│ (source code not available)
│
│ At least 1 "features" blocks are required.

In Terraform >= 0.13, here's what a sample versions.tf looks like (note the provider config being in a separate block):
# versions.tf
terraform {
required_providers {
azurerm = {
# ...
}
}
required_version = ">= 0.13"
}
# This block goes outside of the required_providers block!
provider "azurerm" {
features {}
}

Please check if highlighted lines are added to your template

Related

Creating Issue Labels with Terraform using the Github Provider

I'm trying to automate my repository setup with terraform. First thing is creating issue labels for a bunch of repos using the Terraform Guthub provider.
It works when I explicitly state the repo and the labels:
terraform {
required_providers {
github = {
source = "integrations/github"
version = "~> 5.0"
}
}
}
# Use env-var
provider "github" {}
data "github_repository" "trashbox" {
full_name = "sebastian-sommerfeld-io/trashbox"
}
resource "github_issue_label" "bug" {
repository = data.github_repository.trashbox.id
name = "bug"
description = "Something is not working"
color = "B60205"
}
resource "github_issue_label" "security" {
repository = data.github_repository.trashbox.id
name = "security"
description = "CVEs, code scan violations, etc."
color = "cd3ad7"
}
But this would mean that I would have to duplicate everything for another repo. Or at least that I need to update my terraform config manually when I add another repo. I'd prever to have all relevant repos auto-detected.
Auto-detecting works with this snippet ... this returns all repos I want to configure.
data "github_repositories" "repos" {
query = "user:sebastian-sommerfeld-io archived:false"
include_repo_id = true
}
But now I cannot create the labels. When I run terraform apply I always get this error:
Error: POST https://api.github.com/repos/sebastian-sommerfeld-io/sebastian-sommerfeld-io/website-sommerfeld-io/labels: 404 Not Found []
with github_issue_label.bug["sebastian-sommerfeld-io/website-sommerfeld-io"],
on issues.tf line 1, in resource "github_issue_label" "bug":
1: resource "github_issue_label" "bug" {
The odd thing is, that terraform plan does not hint at any error:
# github_issue_label.bug["sebastian-sommerfeld-io/website-sommerfeld-io"] will be created
+ resource "github_issue_label" "bug" {
+ color = "B60205"
+ description = "Something is not working"
+ etag = (known after apply)
+ id = (known after apply)
+ name = "bug"
+ repository = "sebastian-sommerfeld-io/website-sommerfeld-io"
+ url = (known after apply)
}
My complete Terraform config which generates the outputs from terraform plan and terraform apply is this:
terraform {
required_providers {
github = {
source = "integrations/github"
version = "~> 5.0"
}
}
}
# Use env-var
provider "github" {}
data "github_repositories" "repos" {
query = "user:sebastian-sommerfeld-io archived:false"
include_repo_id = true
}
resource "github_issue_label" "bug" {
for_each = toset(data.github_repositories.repos.full_names)
repository = each.value
name = "bug"
description = "Something is not working"
color = "B60205"
}
The repositories are queried correctly. I confirmed this via:
output "affected_repos" {
value = data.github_repositories.repos.full_names
description = "Github Repos"
}
This lists all repos correctly:
affected_repos = tolist([
"sebastian-sommerfeld-io/website-sommerfeld-io",
"sebastian-sommerfeld-io/jarvis",
"sebastian-sommerfeld-io/github-action-generate-docs",
"sebastian-sommerfeld-io/configs",
"sebastian-sommerfeld-io/website-tafelboy-de",
"sebastian-sommerfeld-io/website-numero-uno-de",
"sebastian-sommerfeld-io/website-masterblender-de",
"sebastian-sommerfeld-io/monitoring",
"sebastian-sommerfeld-io/github-action-update-antora-yml",
"sebastian-sommerfeld-io/github-action-generate-readme",
"sebastian-sommerfeld-io/docker-image-tf-graph-beautifier",
"sebastian-sommerfeld-io/docker-image-jq",
"sebastian-sommerfeld-io/docker-image-git",
"sebastian-sommerfeld-io/docker-image-ftp-client",
"sebastian-sommerfeld-io/docker-image-folderslint",
"sebastian-sommerfeld-io/docker-image-adoc-antora",
"sebastian-sommerfeld-io/trashbox",
"sebastian-sommerfeld-io/provinzial",
])
I guess I don't get the for_each stuff right. Can anyone help me? I want to query all my repos taht fit my criteria and add labels to them.
UPDATE: I just detected that with my static approach I pass id, not full_name. I updated my code to this (snippet from above):
resource "github_issue_label" "bug" {
for_each = data.github_repositories.repos.repo_ids
repository = each.value
name = "bug"
description = "Something is not working"
color = "B60205"
}
Now at least the error message is different:
│ Error: Invalid for_each argument
│
│ on issues.tf line 2, in resource "github_issue_label" "bug":
│ 2: for_each = data.github_repositories.repos.repo_ids
│ ├────────────────
│ │ data.github_repositories.repos.repo_ids is list of number with 18 elements
│
│ The given "for_each" argument value is unsuitable: the "for_each" argument
│ must be a map, or set of strings, and you have provided a value of type
│ list of number.

Terraform failed to destroy with kubernetes autoscaler

I have been using following snippet to manage kubernetes auto scaling with terraform
resource "helm_release" "cluster-autoscaler" {
depends_on = [
module.eks
]
name = "cluster-autoscaler"
namespace = local.k8s_service_account_namespace
repository = "https://kubernetes.github.io/autoscaler"
chart = "cluster-autoscaler"
version = "9.10.7"
create_namespace = false
While all of this has been in working state for months (Gitlab CI/CD), it has suddenly stopped working and throwing following error.
module.review_vpc.helm_release.cluster-autoscaler: Refreshing state... [id=cluster-autoscaler]
╷
│ Error: Kubernetes cluster unreachable: exec plugin: invalid apiVersion "client.authentication.k8s.io/v1alpha1"
│
│ with module.review_vpc.helm_release.cluster-autoscaler,
│ on ..\..\modules\aws\eks.tf line 319, in resource "helm_release" "cluster-autoscaler":
│ 319: resource "helm_release" "cluster-autoscaler" {
I am using AWS EKS with kubernetes version 1.21.
The terraform providers are as follows
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
kubectl = {
source = "gavinbunney/kubectl"
version = "1.14.0"
}
}
UPDATE 1
Here is the module for eks
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "17.24.0"
I had to do couple of changes to terraform scripts (not sure whey they were not required earlier).
Added helm to required_providers section
helm = {
source = "hashicorp/helm"
version = "2.3.0"
}
Replaced token generation from
exec {
api_version = "client.authentication.k8s.io/v1alpha1"
args = ["eks", "get-token", "--cluster-name", var.eks_cluster_name]
command = "aws"
}
to
token = data.aws_eks_cluster_auth.cluster.token
Note that I am using hashicorp/terraform:1.0.11 image on Gitlab runner to execute Terraform Code. Hence manually installing kubectl or aws CLI is not applicable in my case.
This looks like a Helm v3.9 version issue.
Check which version you are using, if so, just do the downgrade to v3.8.
Don't forget to confirm that you are also using the version of kubectl v1.21 and aws-cli v2.7

Create Azure AKS with Managed Identity using Terraform gives AutoUpgradePreview not enabled error

I am trying to create an AKS cluster with managed identity using Terraform. This is my code so far, pretty basic and standard from a few documentation and blog posts I found online.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "2.79.1"
}
}
}
provider "azurerm" {
features {}
use_msi = true
}
resource "azurerm_resource_group" "rg" {
name = "prod_test"
location = "northeurope"
}
resource "azurerm_kubernetes_cluster" "cluster" {
name = "prod_test_cluster"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
dns_prefix = "weak"
default_node_pool {
name = "default"
node_count = "4"
vm_size = "standard_ds3_v2"
}
identity {
type = "SystemAssigned"
}
}
And this is the error message that I can't come around to a solution. Any thoughts on it?
Error: creating Managed Kubernetes Cluster "prod_test_cluster" (Resource Group "prod_test"): containerservice.ManagedClustersClient#CreateOrUpdate: Failure sending request: StatusCode=0 -- Original Error: Code="BadRequest" Message="Feature Microsoft.ContainerService/AutoUpgradePreview is not enabled. Please see https://aka.ms/aks/previews for how to enable features."
│
│ with azurerm_kubernetes_cluster.cluster,
│ on main.tf line 19, in resource "azurerm_kubernetes_cluster" "cluster":
│ 19: resource "azurerm_kubernetes_cluster" "cluster" {
│
I tested it on my environment and faced the same issue as you can see below:
So, to give a description on the issue the AutoChannelUpgrade went
to public preview on August 2021. And as per the terraform azurerm provider 2.79.0 , it bydefault passes that value to none in the
backend but as we have not registered for the feature it fails giving
the error Feature Microsoft.ContainerService/AutoUpgradePreview is not enabled.
To confirm you don't have the feature registered you can use the
below command :
az feature show -n AutoUpgradePreview --namespace Microsoft.ContainerService
You will see it not registered as below:
Now to overcome this you can try two solutions as given below:
You can try using terraform azurerm provider 2.78.0 instead of 2.79.1.
Other solution will be to register for the feature and then you can
use the same code that you are using .
You can follow the below steps:
You can use below command to register the feature (it will take around 5
mins to get registered) :
az login --identity
az feature register --namespace Microsoft.ContainerService -n AutoUpgradePreview
After the above is done you can check the registration stauts with below command :
az feature registration show --provider-namespace Microsoft.ContainerService -n AutoUpgradePreview
After the feature status becomes registered you can do a terraform apply to your code .
I tested it using the below code on my VM:
provider "azurerm" {
features {}
subscription_id = "948d4068-xxxxx-xxxxxx-xxxx-e00a844e059b"
tenant_id = "72f988bf-xxxxx-xxxxxx-xxxxx-2d7cd011db47"
use_msi = true
}
resource "azurerm_resource_group" "rg" {
name = "terraformtestansuman"
location = "west us 2"
}
resource "azurerm_kubernetes_cluster" "cluster" {
name = "prod_test_cluster"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
dns_prefix = "weak"
default_node_pool {
name = "default"
node_count = "4"
vm_size = "standard_ds3_v2"
}
identity {
type = "SystemAssigned"
}
}
Outputs:
Reference:
Github Issue
Install Azure CLI if not installed on the VM using Microsoft Installer

Azure app registration creation error through terraform Azure Devops yml pipeline [duplicate]

This question already has answers here:
json.Marshal(): json: error calling MarshalJSON for type msgraph.Application
(2 answers)
Closed 1 year ago.
I have very simple terraform code.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=2.46.0"
}
azuread = {
source = "hashicorp/azuread"
version = "~> 2.0.0"
}
}
}
provider "azurerm" {
features {}
}
provider "azuread" {
tenant_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
terraform {
backend "azurerm" {
resource_group_name = "xxxx"
storage_account_name = "xxxxxxxxx"
container_name = "xxxxxxxxxxxxx"
key = "xxxxxxxxxxxxxxxxx"
}
}
data "azuread_client_config" "current" {}
resource "azurerm_resource_group" "test" {
name = "test-rg-005"
location = "East US"
}
resource "azuread_application" "example" {
display_name = "Example-app"
}
However when i run this through yml pipeline on azure devops, i am getting this error during apply stage.
Plan: 1 to add, 0 to change, 0 to destroy.
azuread_application.example: Creating...
│ Error: Could not create application
│
│ with azuread_application.example,
│ on terraform.tf line 42, in resource "azuread_application" "example":
│ 42: resource "azuread_application" "example" {
│
│ json.Marshal(): json: error calling MarshalJSON for type
│ msgraph.Application: json: error calling MarshalJSON for type
│ *msgraph.Owners: marshaling Owners: encountered DirectoryObject with nil
│ ODataId
##[error]Error: The process '/opt/hostedtoolcache/terraform/1.0.5/x64/terraform' failed with
exit code 1
Any clue will be helpful, not really clear what this error is about?
Thanks.
There is a bug in azure Active directory provider after an MSFT update. This is impacting any azure ad provider usage creating new resources, however it seems to be working on already deployed resources, i.e. changing and upgrading the configurations of already deployed resource within azure ad. Following is the link for the bug updates.
https://github.com/hashicorp/terraform-provider-azuread/issues/588

terraform plan recreates resources on every run with terraform cloud backend

I am running into an issue where terraform plan recreates resources that don't need to be recreated every run. This is an issue because some of the steps depend on those resources being available, and since they are recreated with each run, the script fails to complete.
My setup is Github Actions, Linode LKE, Terraform Cloud.
My main.tf file looks like this:
terraform {
required_providers {
linode = {
source = "linode/linode"
version = "=1.16.0"
}
helm = {
source = "hashicorp/helm"
version = "=2.1.0"
}
}
backend "remote" {
hostname = "app.terraform.io"
organization = "MY-ORG-HERE"
workspaces {
name = "MY-WORKSPACE-HERE"
}
}
}
provider "linode" {
}
provider "helm" {
debug = true
kubernetes {
config_path = "${local_file.kubeconfig.filename}"
}
}
resource "linode_lke_cluster" "lke_cluster" {
label = "MY-LABEL-HERE"
k8s_version = "1.21"
region = "us-central"
pool {
type = "g6-standard-2"
count = 3
}
}
and my outputs.tf file
resource "local_file" "kubeconfig" {
depends_on = [linode_lke_cluster.lke_cluster]
filename = "kube-config"
# filename = "${path.cwd}/kubeconfig"
content = base64decode(linode_lke_cluster.lke_cluster.kubeconfig)
}
resource "helm_release" "ingress-nginx" {
# depends_on = [local_file.kubeconfig]
depends_on = [linode_lke_cluster.lke_cluster, local_file.kubeconfig]
name = "ingress"
repository = "https://kubernetes.github.io/ingress-nginx"
chart = "ingress-nginx"
}
resource "null_resource" "custom" {
depends_on = [helm_release.ingress-nginx]
# change trigger to run every time
triggers = {
build_number = "${timestamp()}"
}
# download kubectl
provisioner "local-exec" {
command = "curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl"
}
# apply changes
provisioner "local-exec" {
command = "./kubectl apply -f ./k8s/ --kubeconfig ${local_file.kubeconfig.filename}"
}
}
In Github Actions, I'm running these steps:
jobs:
init-terraform:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./terraform
steps:
- name: Checkout code
uses: actions/checkout#v2
with:
ref: 'privatebeta-kubes'
- name: Setup Terraform
uses: hashicorp/setup-terraform#v1
with:
cli_config_credentials_token: ${{ secrets.TERRAFORM_API_TOKEN }}
- name: Terraform Init
run: terraform init
- name: Terraform Format Check
run: terraform fmt -check -v
- name: List terraform state
run: terraform state list
- name: Terraform Plan
run: terraform plan
id: plan
env:
LINODE_TOKEN: ${{ secrets.LINODE_TOKEN }}
When I look at the results of terraform state list I can see my resources:
Run terraform state list
terraform state list
shell: /usr/bin/bash -e {0}
env:
TERRAFORM_CLI_PATH: /home/runner/work/_temp/3f9749b8-515b-4cb4-8053-1a6318496321
/home/runner/work/_temp/3f9749b8-515b-4cb4-8053-1a6318496321/terraform-bin state list
helm_release.ingress-nginx
linode_lke_cluster.lke_cluster
local_file.kubeconfig
null_resource.custom
But my terraform plan fails and the issue seems to stem from the fact that those resources try to get recreated.
Run terraform plan
terraform plan
shell: /usr/bin/bash -e {0}
env:
TERRAFORM_CLI_PATH: /home/runner/work/_temp/3f9749b8-515b-4cb4-8053-1a6318496321
LINODE_TOKEN: ***
/home/runner/work/_temp/3f9749b8-515b-4cb4-8053-1a6318496321/terraform-bin plan
Running plan in the remote backend. Output will stream here. Pressing Ctrl-C
will stop streaming the logs, but will not stop the plan running remotely.
Preparing the remote plan...
Waiting for the plan to start...
Terraform v1.0.2
on linux_amd64
Configuring remote state backend...
Initializing Terraform configuration...
linode_lke_cluster.lke_cluster: Refreshing state... [id=31946]
local_file.kubeconfig: Refreshing state... [id=fbb5520298c7c824a8069397ef179e1bc971adde]
helm_release.ingress-nginx: Refreshing state... [id=ingress]
╷
│ Error: Kubernetes cluster unreachable: stat kube-config: no such file or directory
│
│ with helm_release.ingress-nginx,
│ on outputs.tf line 8, in resource "helm_release" "ingress-nginx":
│ 8: resource "helm_release" "ingress-nginx" {
Is there a way to tell terraform it doesn't need to recreate those resources?
Regarding the actual error shown, Error: Kubernetes cluster unreachable: stat kibe-config: no such file or directory... which is referencing your outputs file... I found this which could help with your specific error: https://github.com/hashicorp/terraform-provider-helm/issues/418
1 other thing looks strange to me. Why does your outputs.tf refer to 'resources' & not 'outputs'. Shouldn't your outputs.tf look like this?
output "local_file_kubeconfig" {
value = "reference.to.resource"
}
Also I see your state file / backend config looks like it's properly configured.
I recommend logging into your terraform cloud account to verify that the workspace is indeed there, as expected. It's the state file that tells terraform not to re-create the resources it manages.
If the resources are already there and terraform is trying to re-create them, that could indicate that those resources were created prior to using terraform or possibly within another terraform cloud workspace or plan.
Did you end up renaming your backend workspace at any point with this plan? I'm referring to your main.tf file, this part where it says MY-WORKSPACE-HERE :
terraform {
required_providers {
linode = {
source = "linode/linode"
version = "=1.16.0"
}
helm = {
source = "hashicorp/helm"
version = "=2.1.0"
}
}
backend "remote" {
hostname = "app.terraform.io"
organization = "MY-ORG-HERE"
workspaces {
name = "MY-WORKSPACE-HERE"
}
}
}
Unfortunately I am not a kurbenetes expert, so possibly more help can be used there.