How to configure azure storage lifecycle with terraform? - azure

So I'm using terraform for azure provider in order to deploy my infrastructure. I just can't seem to be able to define the storage lifecycle. I'd like to add something like this, which i have found, but is not available as is.
So i've tried this https://github.com/terraform-providers/terraform-provider-azurerm/issues/3316, and i've look all over. I'm certain there's a way of telling azure to enable the lifecycle tiertoarchive and tiertodelete… Just can't seem to figure it out.
Thanks
What i'm looking for:
*the resource azurerm_storage_management_policy is a made up resource.
resource "azurerm_storage_account" "example" {
name = "myaccount"
resource_group_name = "myresourcegroup"
location = "westeurope"
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_storage_management_policy" "example" {
storage_account_name ="${azurerm_storage_account.example.name}"
rule {
name = "rule1"
enabled = true
type = "Lifecycle"
definition {
filters {
prefix_match = ["container1/wibble"]
blob_types = ["blockBlob"]
}
actions = {
base_blob {
tier_to_cool {
days_after_modification_greater_than = 30
}
tier_to_archive {
days_after_modification_greater_than = 90
}
delete {
days_after_modification_greater_than = 2555
}
snapshot {
delete {
days_after_creation_greater_than = 90
}
}
}
}
}
}
https://github.com/terraform-providers/terraform-provider-azurerm/issues/3316

I see in your comment, you ask for powershell to do that. Then yes, it's possible via powershell as per this doc.
The sample code from the doc(you can modify it to meet your need) works for me, and note that you should install azure powershell az module before run the script:
#Initialize the following with your resource group and storage account names
$rgname = ""
$accountName = ""
#Create a new action object
$action = Add-AzStorageAccountManagementPolicyAction -BaseBlobAction Delete -daysAfterModificationGreaterThan 2555
$action = Add-AzStorageAccountManagementPolicyAction -InputObject $action -BaseBlobAction TierToArchive -daysAfterModificationGreaterThan 90
$action = Add-AzStorageAccountManagementPolicyAction -InputObject $action -BaseBlobAction TierToCool -daysAfterModificationGreaterThan 30
$action = Add-AzStorageAccountManagementPolicyAction -InputObject $action -SnapshotAction Delete -daysAfterCreationGreaterThan 90
# Create a new filter object
# PowerShell automatically sets BlobType as “blockblob” because it is the only available option currently
$filter = New-AzStorageAccountManagementPolicyFilter -PrefixMatch ab,cd
#Create a new rule object
#PowerShell automatically sets Type as “Lifecycle” because it is the only available option currently
$rule1 = New-AzStorageAccountManagementPolicyRule -Name Test -Action $action -Filter $filter
#Set the policy
$policy = Set-AzStorageAccountManagementPolicy -ResourceGroupName $rgname -StorageAccountName $accountName -Rule $rule1
Please let me know if you issues when write / execute the code above.

Related

Local-exec using powershell throws Cannot index into a null array

Had some help in getting PowerShell command to run in Terraform local-exec See here for code. Just hit the next hurdle as that I can now run various 'get-az' commands with parameters but if I want to run
Update-AzFunctionAppSetting -ResourceGroupName "MyResourceGroup" -Name "MyFunctionApp" -SubscriptionId "MySubscriptionId" -AppSetting #{"testmw" = "2"}
it throws an error:
Update-AzFunctionAppSetting : Cannot index into a null array.
Please use the below code as per your requirement :
provider "azurerm" {
features{}
}
data "azurerm_resource_group" "example"{
name = "ansumantest"
}
variable "function_apps" {
default = ["ansumanfunc1","ansumanfunc2"]
}
variable "Subscription" {
default = "SubID"
}
resource "null_resource" "example2" {
count = length(var.function_apps)
provisioner "local-exec" {
command = <<Settings
$ResourceGroupName = "${data.azurerm_resource_group.example.name}"
$FunctionAppName = "${var.function_apps[count.index]}"
$SubscriptionId = "${var.Subscription}"
Get-AzFunctionApp -ResourceGroupName $ResourceGroupName -Name $FunctionAppName -SubscriptionId $SubscriptionId
Update-AzFunctionAppSetting -ResourceGroupName $ResourceGroupName -Name $FunctionAppName -SubscriptionId $SubscriptionID -AppSetting #{"testmw" = "2"}
Settings
interpreter = ["PowerShell", "-Command"]
}
}
Output:

Azure deployment slots - Adding it to a virtual network using powershell

I'm trying to add an azure deployment slot to a virtual network. Below is the powershell script I'm currently using for adding the webapp to the Vnet, which is working fine:
#Property array with the SubnetID
$properties = #{
subnetResourceId = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/resourceGroupName/providers/Microsoft.Network/virtualNetworks/vnetName/subnets/subnetName"
}
#Creation of the VNet integration
$vnetParams = #{
ResourceName = "WebappName/VirtualNetwork"
Location = "South Central US"
ResourceGroupName = "resourceGroupName"
ResourceType = "Microsoft.Web/sites/networkConfig"
PropertyObject = $properties
}
New-AzResource #vnetParams -Force
How do I change the above script to work with the deployment slot of the same webapp?
Thanks in advance.
You could change your code like this. Note the change of ResourceName and ResourceType.
#Property array with the SubnetID
$properties = #{
subnetResourceId = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/resourceGroupName/providers/Microsoft.Network/virtualNetworks/vnetName/subnets/subnetName"
}
#Creation of the VNet integration
$vnetParams = #{
ResourceName = "WebappName/slot/VirtualNetwork"
Location = "South Central US"
ResourceGroupName = "resourceGroupName"
ResourceType = "Microsoft.Web/sites/slots/networkConfig"
PropertyObject = $properties
}
New-AzResource #vnetParams -Force

How to assign content trust policy to container registry resource azure powershell

I have created container registry as below through powershell.
$prop = #{
Location = "..."
ResourceName = "Resource1"
ResourceType = "Microsoft.ContainerRegistry/registries"
ResourceGroupName = "ResourceGroup.."
Force = $true
Sku = #{"Name"="Premium"}
}
$registry = New-AzResource #prop"
It gets created successfully, but the content trust policy set for this is "disabled"
How can i make it enabled during creation through powershell
The content trust policy for the ACR is in its properties, so you need to set it in the commands. Finally, the commands will like this:
$prop = #{
Location ="location"
ResourceName ="resourceName"
ResourceType ="Microsoft.ContainerRegistry/registries"
ResourceGroupName ="groupName"
Sku =#{"Name"="Premium"}
Properties =#{"Policies"=#{"TrustPolicy"=#{"Type"="Notary";"Status"="enabled"}}}
}
$registry = New-AzResource #prop

Azure Powershell Tagging VM's from CSV file

I'm quite new to Powershell scripting. I'm trying to generate tags for azure vm's from a CSV file.
Inside the CSV I have the following column headings:
VMName
Application
SubCat
Environment
AppOwner
Location
I've got a test CSV which literally has the following data in it:
MattTestVM, TestApp, TestSubapp, Dev, Matt, UK South
I'm not sure what i've put wrong in my code to get it to add the tags.
Code
#Set Credentials
$cred = Get-credential
# Sign-in with Azure account credentials
add-azurermaccount -credential $cred
# Select Azure Subscription
$subscriptionId = (Get-AzureRmSubscription | Out-GridView -Title "Select an Azure Subscription ..." -PassThru).SubscriptionId
#Select specified subscription ID
Select-AzureRmSubscription -SubscriptionId $subscriptionId
$InputCSVFilePath = "C:\test\Tagging1.csv"
#Start loop
foreach ($eachRecord in $InputCSVFilePath)
{
$VMName = $eachrecord.VMName
$Application = $eachrecord.Application
$SubCat = $eachrecord.SubCat
$Environment = $eachrecord.Environment
$AppOwner = $eachrecord.AppOwner
$Location = $eachrecord.Location
$r = Get-AzureRmResource -ResourceId $ResourceId -ErrorAction Continue
if($r -ne $null)
{
if($r.tags)
{
# Tag - Application
if($r.Tags.ContainsKey("Application"))
{
$r.Tags["Application"] = $Application
}
else
{
$r.Tags.Add("Application", $Application)
}
# Tag - SubCat
if($r.Tags.ContainsKey("subCat"))
{
$r.Tags["subCat"] = $subCat
}
else
{
$r.Tags.Add("subCat", $subCat)
}
# Tag - Environment
if($r.Tags.ContainsKey("Environment"))
{
$r.Tags["Environment"] = $Environment
}
else
{
$r.Tags.Add("Environment", $Environment)
}
# Tag - AppOwner
if($r.Tags.ContainsKey("AppOwner"))
{
$r.Tags["AppOwner"] = $AppOwner
}
else
{
$r.Tags.Add("AppOwner", $AppOwner)
}
# Tag - Location
if($r.Tags.ContainsKey("Location"))
{
$r.Tags["Location"] = $Location
}
else
{
$r.Tags.Add("Location", $Location)
}
#Setting the tags on the resource
Set-AzureRmResource -Tag $r.Tags -ResourceId $r.ResourceId -Force
}
else
{
#Setting the tags on a resource which doesn't have tags
Set-AzureRmResource -Tag #{ Application=$Application; subCat=$subCat; Environment=$Environment; AppOwner=$AppOwner; Location=$Location } -ResourceId $r.ResourceId -Force
}
}
else
{
Write-Host "Resource Not Found with Resource Id: " + $ResourceId
}
}
Error message
Get-AzureRmResource : Cannot validate argument on parameter 'ResourceId'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:10 char:43
+ $r = Get-AzureRmResource -ResourceId $ResourceId -ErrorAction Co ...
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-AzureRmResource], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.GetAzureResourceCmdlet
OK, first thing's first: You can't do this without the ResourceGroupName, and the best way to add it in your case is as a column in your csv.
Secondly, everybody starts somewhere so never apologize. :) I commented about most of the issues I fixed in the code below. Your biggest problems were a) you didn't actually load the data from the CSV (you only created a variable with the file path in it), and b) you were attempting to use $ResourceID without ever populating it.
I cleaned things up a bit and it works now, and will throw an error if it can't find the VM. Here are the contents of my test.csv, with one good VM and one that doesn't exist.
VMName,ResourceGroup,Application,SubCat,Environment,AppOwner,Location
test-rm-01,test-rg,Thing,Subs,Dev,Nick,Europe
clambake,mygroup,,,,,
And here's the re-worked script.
# Set Credentials (Fixed this up)
$context = Get-AzureRmContext
if ($context.Account -eq $null) {
Login-AzureRmAccount
}
# Select Azure Subscription
$subscriptionId = (Get-AzureRmSubscription | Out-GridView -Title "Select an Azure Subscription ..." -PassThru).SubscriptionId
#Select specified subscription ID
Select-AzureRmSubscription -SubscriptionId $subscriptionId
$InputCSVFilePath = "C:\Users\Nick\Desktop\test.csv"
################
#
# Here you were missing loading the actual data. Also renamed the items in the loop, nitpicking. :)
#
################
$csvItems = Import-Csv $InputCSVFilePath
################
#Start loop
foreach ($item in $csvItems)
{
################
#
# Change here, you need ResourceGroupName
# Also cleared r because if you don't, it will still have a value if no matching VM is found, which would re-tag the previous item from the loop, instead of throwing an error that the VM was not found
#
################
Clear-Variable r
$r = Get-AzureRmResource -ResourceGroupName $item.ResourceGroup -Name $item.VMName -ErrorAction Continue
################
if ($r -ne $null)
{
if ($r.Tags)
{
# Tag - Application
if ($r.Tags.ContainsKey("Application"))
{
$r.Tags["Application"] = $item.Application
}
else
{
$r.Tags.Add("Application", $item.Application)
}
# Tag - SubCat
if ($r.Tags.ContainsKey("subCat"))
{
$r.Tags["subCat"] = $item.subCat
}
else
{
$r.Tags.Add("subCat", $item.subCat)
}
# Tag - Environment
if ($r.Tags.ContainsKey("Environment"))
{
$r.Tags["Environment"] = $item.Environment
}
else
{
$r.Tags.Add("Environment", $item.Environment)
}
# Tag - AppOwner
if ($r.Tags.ContainsKey("AppOwner"))
{
$r.Tags["AppOwner"] = $item.AppOwner
}
else
{
$r.Tags.Add("AppOwner", $item.AppOwner)
}
# Tag - Location
if ($r.Tags.ContainsKey("Location"))
{
$r.Tags["Location"] = $item.Location
}
else
{
$r.Tags.Add("Location", $item.Location)
}
#Setting the tags on the resource
Set-AzureRmResource -Tag $r.Tags -ResourceId $r.ResourceId -Force
}
else
{
#Setting the tags on a resource which doesn't have tags
Set-AzureRmResource -Tag #{ Application = $Application; subCat = $subCat; Environment = $Environment; AppOwner = $AppOwner; Location = $Location } -ResourceId $r.ResourceId -Force
}
}
else
{
Write-Host "No VM found named $($item.VMName) in ResourceGroup $($item.ResourceGroup)!"
}
}

Passing multiple Parameters in single Azure Storage Script for various environments

I have a powershell script that creates the storage and blob account for a given subscription that works fine . Subscription Name, resource group keeps changing for different environments like DEV,UAT,PROD
STRUCTURE OF MY TEMPLATE / CODE :
param(
[string] $subscriptionName ="ABC",
[string] $resourceGroupName = "XYZ",
[string] $resourceGroupLocation ="westus",
[string] $templateFilePath = "template.json",
[string] $parametersFilePath = "parameters.json"
)
Function RegisterRP {
Param(
[string]$ResourceProviderNamespace
)
Write-Host "Registering resource provider '$ResourceProviderNamespace'";
Register-AzureRmResourceProvider -ProviderNamespace $ResourceProviderNamespace;
}
$ErrorActionPreference = "Stop"
$confirmExecution = Read-Host -Prompt "Hit Enter to continue."
if($confirmExecution -ne '') {
Write-Host "Script was stopped by user." -ForegroundColor Yellow
exit
}
# sign in
Write-Host "Logging in...";
Login-AzureRmAccount;
# select subscription
Write-Host "Selecting subscription '$subscriptionName'";
Select-AzureRmSubscription -SubscriptionName $subscriptionName;
# Register RPs
$resourceProviders = #("microsoft.storage");
if($resourceProviders.length) {
Write-Host "Registering resource providers"
foreach($resourceProvider in $resourceProviders) {
RegisterRP($resourceProvider);
}
}
#Create or check for existing resource group
$resourceGroup = Get-AzureRmResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue
if(!$resourceGroup)
{
Write-Host "Resource group '$resourceGroupName' does not exist. To create a new resource group, please enter a location.";
if(!$resourceGroupLocation) {
$resourceGroupLocation = Read-Host "resourceGroupLocation";
}
Write-Host "Creating resource group '$resourceGroupName' in location '$resourceGroupLocation'";
New-AzureRmResourceGroup -Name $resourceGroupName -Location $resourceGroupLocation
}
else{
Write-Host "Using existing resource group '$resourceGroupName'";
}
# Start the deployment
Write-Host "Starting deployment...";
if(Test-Path $parametersFilePath) {
New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -Name $deploymentName -TemplateFile $templateFilePath -TemplateParameterFile $parametersFilePath -storageAccounts_name $storageAccountName
} else {
New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -Name $deploymentName -TemplateFile $templateFilePath; -storageAccounts_name $storageAccountName
}
Approach 1 :
Created multiple powershell scripts for each denvironment
Created 1 Menu Based powershell script that calls the other script and executes like : Select 1 for Dev , 2 for UAt , 3 for PROD , this approach works but is not effective .
Approach 2 :
I would like to combine all scripts and just have one script for all environments and based on select should allow me to create the storage accounts. Only Subscription and resource group change rest all structure of the powershell remains same .
I tried using GET function commandlets and it selects but still throws the error
[string] $subscriptionName = Get-AzureSubscription,
[string] $resourceGroupName = Get-AzureRmLocation,
If i try to use it using an array based approach like passing the values as below im unable to understand how do i pass these array based values to the code and get it to work .
$environment=#('DEV','TEST','QA','PROD')
$resourcegroupname = #('test','test1','test2','test3')
$subscriptionName = #('devsub1','devsub2','test3','prod4')
I'm trying to call the functions using :
$environment[0]
$subscriptionName[0]
It returns the value as below if i execute it seperately but how do i pass these values to my script to create storage account ?
DEV
devsub1
Requesting expert help if anyone has come across such scenarios earlier and if you can help in changing the above code and provide a tested code that would be of great help.
APPROACH 3:
$subscription = #(Get-AzureRmSubscription)
$resourcegroup = #(Get-AzureRmResourceGroup)
$Environment = #('DEV','TEST','QA','PROD')
$resourceGroupName = $resourcegroup | Out-GridView -PassThru -Title 'Pick the environment'
$subscriptionName = $subscription | Out-GridView -PassThru -Title 'Pick the subscription'
Write-Host "Subscription:" $subscriptionName
Write-Host "ResourceGroup:" $resourcegroup
OUTPUT :
If you look at resource group it fails to give the selection option for resource group .
Subscription: < it returns the subscription name >
ResourceGroup: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResourceGroup Microsoft.Azure.Commands.ResourceManager.Cmd
lets.SdkModels.PSResourceGroup Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResourceGroup Microsoft.Azure.Commands.Res
ourceManager.Cmdlets.SdkModels.PSResourceGroup
What you are proposing is an interesting approach. I would likely an input parameter that defines which environment the work will be done in, and then have a conditional block that sets the dynamic variables for that environment. There would be some duplication of initialization code for each environment, but the main code block would still be unified.

Resources