Am currently running some Terraform to create resources in Azure. We have a module we have written to create a resource group with a bunch of variables. The provider currently does not allow the creation of budgets and cost alerts but the Powershell modules do. I thought we could then add a Powershell script to carry out the settings. I seem to be hitting a snag where I cannot quite work out how to address the Powershell script. I have the following:
resource "null_resource" "PowerShellScriptRunAlways" {
triggers = {
always_run = "${timestamp()}"
}
provisioner "local-exec" {
command = ".'${path.module}//pwsh//costalert.ps1 -subscriptionID \"${var.azure_subscription_id}\" -tenantID \"${var.azure_tenant_id}\" -clientID \"${var.azure_client_id}\" -clientSecret \"${var.azure_client_secret}\" -budgetAmount \"${var.budgetAmount}\" -rgName \"${azurerm_resource_group.this.name}\" -emailAddresses \"${var.emailAddresses}\"'"
interpreter = ["pwsh", "-Command"]
}
}
using pwsh as this is running on a Linux Jenkins agent. This is part of a module where the ps1 file is under "root module directory/pwsh" but it seems to yield the following:
Error: Error running command '.'.terraform/modules/rg_test\pwsh\costalert.ps1 -subscriptionID "xxxxx" -tenantID "xxxxxxx" -clientID "xxxxxx" -clientSecret "xxxxx" -budgetAmount "1000" -rgName "rg-da_test-sbxeng-001" -emailAddresses "xxxxxx"'': exit status 1. Output: . : The module '.terraform/modules/rg_test' could not be loaded. For more information, run 'Import-Module .terraform/modules/rg_test
+ .'.terraform/modules/rg_test\pwsh\costalert.ps1 -subscriptionID
It seems to be switching the path but cannot seem to make it pick up the script and run it. Does anyone have any suggestions?
Isn't this a quoting issue?
I can successfully execute this pwsh null resource from a terraform module in an Azure DevOps linux agent. Note that only the script path is single quoted, while in your example you've got the whole command single quoted.
resource "null_resource" "create_sql_user" {
provisioner "local-exec" {
command = ".'${path.module}\\scripts\\create-sql-user.ps1' -password \"${random_password.sql_password.result}\" -username \"${var.sql_username}\" -sqlSaConnectionString \"${var.sql_server_connectionstring}\" -databaseName \"${azurerm_sql_database.db.name}\" "
interpreter = ["pwsh", "-Command"]
}
depends_on = [azurerm_sql_database.db]
}
Related
I'm trying to wrap my brain around an issue with either the TF Code, or me. I've got a VM Set that I'm mapping over, and on each one, I have a CustomScriptExtension that should install Docker on the VMs.
When I run the plan, it builds the VMs, and the Custom Script runs, however when I RDP into the machine, and attempt a docker info It's telling me that docker isn't installed.
A quick cursory glance of C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.*\Downloads\ Shows that the installer script is indeed being downloaded, but it doesn't seem to be installing.
Here's the AzureRM Resource (Sanitized):
resource "azurerm_virtual_machine_extension" "bootstrap-scripts" {
for_each = local.XXXXXX
name = "${each.key}-bootstrap"
virtual_machine_id = module.XXXXXXXX[each.key].virtual_machine_id
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.10"
settings = <<SETTINGS
{
"commandToExecute" : "powershell -ExecutionPolicy Unrestricted -File install-docker-ce.ps1",
"fileUris" : ["https://raw.githubusercontent.com/microsoft/Windows-Containers/Main/helpful_tools/Install-DockerCE/install-docker-ce.ps1"]
}
SETTINGS
}
And the output from the log at C:\WindowsAzure\Logs\Plugins\Microsoft.Compute.CustomScriptExtension
[
{
"version":"1",
"timestampUTC":"2022-10-21T20:03:44.6989395Z",
"status":{"name":"powershell -ExecutionPolicy Unrestricted -File install-docker-ce.ps1",
"operation":"Command Execution Finished",
"status":"success",
"code":0,
"formattedMessage":{
"lang":"en-US",
"message":"Command execution finished"
},
"substatus":[
{
"name":"StdOut",
"status":"success",
"code":0,"formattedMessage":{
"lang":"en-US",
"message":"Querying status of Windows feature: Containers...\r\nEnabling feature Containers...\r\nWARNING: You must restart this server to finish the installation process.\r\nRestart is required; restarting now...\r\nCreating scheduled task action (C:\\Packages\\Plugins\\Microsoft.Compute.CustomScriptExtension\\1.10.12\\Downloads\\0\\install-docker-ce.ps1 )...\r\nCreating scheduled task trigger...\r\nRegistering script to re-run at next user logon...\r\n"
}
},
{
"name":"StdErr",
"status":"success",
"code":0,
"formattedMessage":{
"lang":"en-US",
"message":"Register-ScheduledTask : No mapping between account names and security IDs was done.\r\n(12,8):UserId:\r\nAt C:\\Packages\\Plugins\\Microsoft.Compute.CustomScriptExtension\\1.10.12\\Downloads\\0\\install-docker-ce.ps1:150 char:5\r\n+ Register-ScheduledTask -TaskName $global:BootstrapTask -Action $a ...\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n + CategoryInfo : NotSpecified: (PS_ScheduledTask:Root/Microsoft/...S_ScheduledTask) [Register-ScheduledTa \r\n sk], CimException\r\n + FullyQualifiedErrorId : HRESULT 0x80070534,Register-ScheduledTask\r\n \r\n"
}
}
]
}
}
]
from what I'm reading, it seems to set up the scheduled task to reboot the server, but it looks like it never does? However even after a manual restart, it's still not installed.
Can anyone shed some light on this?
EDIT: I forgot to mention that I cannot use anything out of the Azure Public Marketplace, in case someone wanted to mention using a premade image. I am relegated to using images that are stored in our private collection
I have created Azure data migration service and migration project using terraform, so is there any terraform scripts available for creating migration activity in Azure?
Currently its not possible with Terraform as only Database Migration Service and Project are available for now . You can use ARM template for the same .
If you want to use Terraform , then you can use local-exec to use PowerShell or CLI and execute the Az-powershell or Az CLI commands there .
Example of Local-exec :
resource "null_resource" "example" {
provisioner "local-exec" {
command = <<Settings
$ResourceGroupName = "${data.azurerm_resource_group.example.name}"
$FunctionAppName = "${var.function_app}"
$SubscriptionId = "${var.Subscription}"
Get-AzFunctionApp -ResourceGroupName $ResourceGroupName -Name $FunctionAppName -SubscriptionId $SubscriptionId
Settings
interpreter = ["PowerShell", "-Command"]
}
}
I have a powershell task that is used to run a script which involves creating azure resources (Example: Resource group, Azure Key Vault, Function App...). When the pipeline is being run and it arrives to the powershell task in the deploy stage, it shows the following message:
The problem here, it says Finishing:Powershell but it didn't execute the script and did not create any azure resource.
Here is a sample of the powershell script:
$vaultName = "key vault name"
$blobstorageName = "blob storage name"
$Location = "Location Name"
$resourceGroupName = "Resource Group Name"
try {
#Creation of Resource Group
$resourceGroup = Get-AzResourceGroup -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue
if($null -eq $resourceGroup)
{
New-AzResourceGroup -Name $resourceGroupName -Location $Location
}
else
{
Write-Host "The ResourceGroup with the name: $resourceGroupName already exists."
}
# Creation of Storage Account
$checkBlobStorage = (Get-AzStorageAccountNameAvailability -Name $blobstorageName) | Select-Object NameAvailable
if ($checkBlobStorage.NameAvailable)
{
New-AzStorageAccount -ResourceGroupName $resourceGroupName -AccountName $blobstorageName -Location $Location -SkuName Standard_LRS -Kind StorageV2 -AccessTier Hot
}
else
{
Write-Host "The name $blobStorageName is not available. Suggest a new globally unique name!"
}
catch
{
}
Does anyone have a clue what is wrong ? Am I missing something in the powershell script (Maybe I don't have direct access to the azure portal from azure devops) or maybe something is missing in
the Yaml file ?
Two major issues:
you seem to be using the Powershell Task, which is not designed for communication with Azure. You should use the Azure Powershell task for this kind of script, because it already has the right modules loaded and the authentication prepared.
your script is swallowing the error so it is hiding what went wrong. It's usually more useful not to catch exceptions; if your script is erroring then let it error, and let the pipeline show you in its log what has happened.
I have a powershell script present in GitHub and using it in the "Settings" block inside "azurerm_virtual_machine_extension" to configure the Windows Server VM. Below is the code.
resource "azurerm_virtual_machine_extension" "iis-windows-vm" {
depends_on = [azurerm_windows_virtual_machine.web-windows-vm]
name = "win-${random_string.random-win-vm.result}-vm-extn"
virtual_machine_id = azurerm_windows_virtual_machine.web-windows-vm.id
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.9"
settings = <<SETTINGS
{
"commandToExecute": "powershell -ExecutionPolicy Unrestricted -File demo.ps1",
"fileUris": ["https://raw.githubusercontent.com/Configure/app/master/demo.ps1"]
}
SETTINGS
}
And the below are the content of "demo.ps1"
New-LocalUser "ansible" -Password (ConvertTo-SecureString -AsPlainText -Force ) -AccountNeverExpires:$true -PasswordNeverExpires:$true -FullName "ansible" | Add-LocalGroupMember -Group administrators
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
$file = "$env:temp\ConfigureRemotingForAnsible.ps1"
(New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
powershell.exe -ExecutionPolicy ByPass -File $file
Install-WindowsFeature -Name Web-Server -IncludeAllSubFeature -IncludeManagementTools
When I do "terraform apply", below error is displayed.
Error: Future#WaitForCompletion: context has been cancelled: StatusCode=200 -- Original Error: context deadline exceeded
The code was working fine until now. Not able to figure out the problem here. Request you assist me to make this work.
The error Original Error: context deadline exceeded means that we ran into a situation where a given action was not completed in an expected timeframe.
So there can be a handful of reason why you are encountering the execution timeout like Network Latency, Slow I/O, Firewall Rules and many more. One possible reason that I think is the URL is not responding as expected or it's taking to much time to respond.
Before being able to solve the problem, you need to determine what is actually failing. I would suggest to check the detailed terraform log file to find the reason of timeout.
But even after checking you find is good and you are still facing the issue then with v2.0 of the AzureRM Provider it is possible to add custom timeouts using timeouts block as shown in the example snippet below.
resource "azurerm_resource_group" "example" {
name = "example-resource-group"
location = "West Europe"
timeouts {
create = "10m"
delete = "30m"
}
}
For more information check this Custom Timeouts for Resources section of the terraform document.
Terraform doesn't provide options to change the Azure recovery Services Vault to use LocallyRedundant storage replication type. So I decided to use the PowerShell module to set this after the resource is provisioned. The command seems to be correct and works when it's manually invoked but doesn't when it's put in the provisioner. Any thoughts?
Terraform Version : 0.15
Azurerm Version : 2.40.0
resource "azurerm_recovery_services_vault" "RSV"{
name = "RSV"
location = "eastus"
resource_group_name = "RGTEST"
sku = "Standard"
provisioner "local-exec" {
command = "Get-AzRecoveryServicesVault -Name ${azurerm_recovery_services_vault.RSV.name} | Set-AzRecoveryServicesBackupProperty -BackupStorageRedundancy LocallyRedundant"
interpreter = ["powershell", "-Command"]
}
}
The PowerShell scripts rely on the resource "azurerm_recovery_services_vault" that is fully created. In this case, if you include the local-exec Provisioner in a null_resource, run terraform init and terraform apply again, it works.
Note that even though the resource will be fully created when the
provisioner is run, there is no guarantee that it will be in an
operable state
resource "null_resource" "script" {
provisioner "local-exec" {
command = "Get-AzRecoveryServicesVault -Name ${azurerm_recovery_services_vault.RSV.name} | Set-AzRecoveryServicesBackupProperty -BackupStorageRedundancy LocallyRedundant"
interpreter = ["powershell", "-Command"]
}
}