Either I’m not getting DSC (which is highly likely) or there is a huge floor in attempting to treat servers like cattle as opposed to pets.
I know the role, but not the name of the server until the deployment has reached a certain phase as its name is generated dynamically. Part of the deployment is to configure it with DSC. I can use “localhost” or “inject” the name, but the latter involves re-compiling the configuration in the middle of the deployment.
What is the purpose of Node $AllNodes.where{$_.Role -eq “WebServer”}.NodeName within a configuration? My theory is to be able to do something like:
Configuration DSCTestNodes { Node $AllNodes.where{$_.Role -eq "WebServer"}.NodeName { File TestFile { Ensure = "Present" Type = "File" Contents = "Role: $($node.FileContents)" DestinationPath = "D:\Temp\DsctestNode-WS.txt" } } Node $AllNodes.where{$_.Role -eq "Database"}.NodeName { File TestFile { Ensure = "Present" Type = "File" Contents = "Role: $($node.FileContents)" DestinationPath = "D:\Temp\DsctestNode-DB.txt" } } }
Essentially, one configuration for multiple roles. But this has a potential of make a very long configuration. One of my configurations for a single role is already 500 lines long, and that is using composite resources! Surely it is better to make separate configurations in separate files, keeping them as short as possible? Also, one still needs to know the hostname ahead of compilation.
This moves me on to ConfigurationData. Taking note of a post written by one of the prevalent people on this site, if I were to literally interpret NodeName to mean NodeRole which seems a good idea, I am scuppered because at run time, DSC cannot find any such computer on my network, named WS or DB.
$ConfigurationData = @{ AllNodes = @( @{ NodeName="*" PSDscAllowPlainTextPassword=$true PsDscAllowDomainUser = $true TempDriveLetter = "P" #ADDomain = $CommonParameters.AdDomainName } @{ NodeName="WS" Role = "WebServer" FileContents = "Web server" WindowsFeatures = @( "GPMC" ) } @{ NodeName="DB" Role = "Datasbase" FileContents = "Database server" WindowsFeatures = @( "GPMC" "Windows-Server-Backup" ) } ) }
So here, in the AllNodes array, I define my common-to-all data, then data that is unique to each role. Herein lies the problem. NodeName has to be a valid and unique hostname for an existing server. But I don’t know its hostname!
If I leave out the nodename, compilation fails:
ValidateUpdate-ConfigurationData : all elements of AllNodes need to be hashtable and has a property 'NodeName'.
What about localhost. In this case, I have two roles, therefore I use localhost twice:
$ConfigurationData = @{ AllNodes = @( @{ NodeName="*" PSDscAllowPlainTextPassword=$true PsDscAllowDomainUser = $true TempDriveLetter = "P" #ADDomain = $CommonParameters.AdDomainName } @{ NodeName="localhost" Role = "WebServer" FileContents = "AOS server" WindowsFeatures = @( "GPMC" ) } @{ NodeName="localhost" Role = "AXR3DB" FileContents = "Database server" WindowsFeatures = @( "GPMC" "Windows-Server-Backup" ) } ) }
Fail:
ValidateUpdate-ConfigurationData : There are duplicated NodeNames 'localhost' in the configurationData passed in.
So bring on NonNodeData. I do away with the “named” nodes and move the role-specific data thus:
$ConfigurationData = @{ AllNodes = @( @{ NodeName="*" PSDscAllowPlainTextPassword=$true PsDscAllowDomainUser = $true TempDriveLetter = "P" } ) NonNodeData = @{ Roles = @{ WebServer = @{ FileContents = "This is webserver" WindowsFeatures = @( "GPMC" ) } Database = @{ FileContents = "This is a database" WindowsFeatures = @( "GPMC" "Windows-Server-Backup" ) } } } }
I then need to modify the configuration thus:
Configuration DSCTestNodes { Node localhost { foreach($setting in $ConfigurationData.NonNodeData.Roles) { File TestFileWS { Ensure = "Present" Type = "File" Contents = "Role: $($setting.webserver.FileContents)" DestinationPath = "D:\Temp\DsctestNode-WS.txt" } File TestFileDB { Ensure = "Present" Type = "File" Contents = "Role: $($setting.database.FileContents)" DestinationPath = "D:\Temp\DsctestNode-DB.txt" } } } }
Note, I am using Node localhost and referencing the “contents” for WebServer and database from the NonNodeData hash table. But wait a minute, that creates two files on localhost, aka every computer I run it on, regardless of its intended role. Not what I want. The only way DSC knows which configuration to apply is by manually telling it which MOF file to apply. So we are back to the configuration only applying one role. The ConfigurationData can still contain data for multiple roles.
Configuration DSCTestNodesWS { $WebServerSettings = $ConfigurationData.NonNodeData.Roles.WebServer Node localhost { File TestFileWS { Ensure = "Present" Type = "File" Contents = "Role: $($WebServerSettings.FileContents)" DestinationPath = "D:\Temp\DsctestNode-WS.txt" } } } Configuration DSCTestNodesDB { $databaseSettings = $ConfigurationData.NonNodeData.Roles.database Node localhost { File TestFileDB { Ensure = "Present" Type = "File" Contents = "Role: $($databaseSettings.FileContents)" DestinationPath = "D:\Temp\DsctestNode-DB.txt" } } } $ConfigurationData = @{ AllNodes = @( @{ NodeName="*" PSDscAllowPlainTextPassword=$true PsDscAllowDomainUser = $true TempDriveLetter = "P" } ) NonNodeData = @{ Roles = @{ WebServer = @{ FileContents = "This is webserver" WindowsFeatures = @( "GPMC" ) } Database = @{ FileContents = "This is a database" WindowsFeatures = @( "GPMC" "Windows-Server-Backup" ) } } } } DscTestNodesWS -OutputPath "D:\Configurations\DSCTestNodesWS" -verbose -ConfigurationData $ConfigurationData DscTestNodesDB -OutputPath "D:\Configurations\DSCTestNodesDB" -verbose -ConfigurationData $ConfigurationData
I realise I can parameterise the configuration, but it has the same effect of having to compile mid-deployment, so if I’m going to all that trouble, I might as well add the actual nodename. The best I can come up with is a separation that allows minimal compiling, i.e. using localhost and only compiling when the configuration changes – which during development is every time :-).
So, am I missing a trick, or is this a limitation of DSC in its current form (5.1)?
In my humble opinion, what would resolve much of this is for DSC to take parameters that are resolved at run time. I know MOF is a standard that probably doesn’t take parameters, but when have Microsoft ever adhered to standards!