Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure ARM uniqueString function mimic

I need to deploy Sql Databases into an Azure Sql Server using to ways: the ARM template way, and a more custom way using C# code. There's a ARM template function called uniqueString(string) that generate a pseudo random hash of a given string. It's a deterministic pure function.

I need to find a way to exactly mimic the behaviour of this function from my C# code. ie I need to reproduce this function into my C# code.

Where can i find the algorithm used by the ARM Api ?

MSDN reference for uniqueString()

like image 605
Loul G. Avatar asked Apr 08 '17 15:04

Loul G.


4 Answers

I've been researching this myself on and off for a few years now, and I've finally hit paydirt...

// "zcztcwvu6iyg6"
var unique = ArmUniqueString("tyeth");

My ArmUniqueString function is a wrapper around some dlls that are distributed with the Azure Stack Hub Development Kit which is basically a virtual machine image that contains the Azure server-side platform that you can run locally...

private static string ArmUniqueString(string originalString)
{

    var assembly = Assembly.GetAssembly(
        typeof(Microsoft.WindowsAzure.ResourceStack.Frontdoor.Templates.Engines.TemplateEngine)
    );

    var functions = assembly.GetType(
        "Microsoft.WindowsAzure.ResourceStack.Frontdoor.Templates.Expressions.TemplateExpressionBuiltInFunctions"
    );

    var uniqueString = functions.GetMethod(
        "UniqueString",
        BindingFlags.Static | BindingFlags.NonPublic
    );

    var parameters = new object[] {
        "uniqueString",
        new JToken[] {
            (JToken)originalString
        }
    };

    var result = uniqueString.Invoke(null, parameters).ToString();

    return result;

}

You'll need to download the Azure Stack Hub Development Kit and unpack it to get the dlls:

  • Download the Azure Stack Hub Development Kit - warning: it's about 22Gb!
  • Run the installer to unpack a 55Gb *.vhdx
  • Mount the *.vhdx, or expand / unpack it locally
  • Inside the *.vhdx, find this file and unzip it somewhere:
    • CloudBuilder\CloudDeployment\NuGetStore\Microsoft.AzureStack.Setup.Services.ResourceManager.5.20.1335.300.nupkg
  • The content\Website\bin folder inside the *.nupkg contains the necessary dlls

To use them, add an assembly reference to Microsoft.WindowsAzure.ResourceStack.Frontdoor.Templates.dll (it has some dependencies on other files in the bin folder) and that contains the TemplateExpressionBuiltInFunctions class. The code above just uses reflection to invoke the private UniqueString function from that assembly, with a little bit of work to marshal the parameters into appropriate JToken types.

If you wanted to dig into the implementation details you could probably run a decompiler against the assembly to find out what it's doing under the covers...

Note - credits go to this blog article for pointing me in the right direction:

https://the.agilesql.club/2017/12/azure-arm-template-function-internals/

like image 136
mclayton Avatar answered Oct 19 '22 17:10

mclayton


I found some PowerShell code to do this here: https://blogs.technet.microsoft.com/389thoughts/2017/12/23/get-uniquestring-generate-unique-id-for-azure-deployments/

I converted this code to C#:

public string GetUniqueString(string id, int length = 13)
{
    string result = "";
    var buffer = System.Text.Encoding.UTF8.GetBytes(id);
    var hashArray = new System.Security.Cryptography.SHA512Managed().ComputeHash(buffer);
    for(int i = 1; i <= length; i++)
    {
        var b = hashArray[i];
        var c = Convert.ToChar((b % 26) + (byte)'a');
        result = result + c;
    }

    return result;
}
like image 42
JoshSchlesinger Avatar answered Oct 19 '22 18:10

JoshSchlesinger


This function is released in nuget: https://www.nuget.org/packages/Azure.Deployments.Expression/ The implementation: https://msazure.visualstudio.com/One/_git/AzureUX-Deployments?path=%2Fsrc%2FExpressions%2FExpressions%2FExpressionBuiltInFunctions.cs&version=GBmaster&_a=contents

Example:

using Azure.Deployments.Expression.Expressions;
using Newtonsoft.Json.Linq;

var funcs = ExpressionBuiltInFunctions.Functions;
var jt = new JTokenExpression("test");
var output = funcs.EvaluateFunction("uniqueString", new JToken[] { jt.Value }).ToString();
like image 2
David Zoo Avatar answered Oct 19 '22 18:10

David Zoo


Sam Cogan wrote a blog post on how to do this in C# here: https://samcogan.com/using-bicep-functions-in-c-if-you-really-want-to/

Inspired by Sam, I wrote a PowerShell module (for PowerShell 7) that does the same. You can install the module by running Install-Module -Name AzExpression which will give you command called New-AzUniqueString.

Here is an example on how to use it:
New-AzUniqueString -InputStrings 'test', 'value'
Which will output: bhxq2thzm5dym

like image 1
Simon Wåhlin Avatar answered Oct 19 '22 17:10

Simon Wåhlin