dsccommunity / StorageDsc

DSC resource module is used to manage storage on Windows Servers.
https://dsccommunity.org
MIT License
69 stars 51 forks source link

MountImage: Get error when try to dismount after mounting iso #226

Open NemoDima opened 4 years ago

NemoDima commented 4 years ago

Details of the scenario you tried and the problem that is occurring

Get error when try to dismount after mounting iso.

Verbose logs showing the problem

Test-ConflictingResources : A conflict was detected between resources '[MountImage]MountMSSQL2016 (::8::10::MountImage)' and '[MountI
mage]DismountMSSQL2016 (::23::9::MountImage)' in node 'localhost'. Resources have identical key properties but there are differences 
in the following non-key properties: 'Ensure'. Values 'NULL' don't match values 'Absent'. Please update these property values so that
 they are identical in both cases.
At line:289 char:9
+         Test-ConflictingResources $keywordName $canonicalizedValue $k ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Write-Error], InvalidOperationException
    + FullyQualifiedErrorId : ConflictingDuplicateResource,Test-ConflictingResources
Compilation errors occurred while processing configuration 'Basic_settings'. Please review the errors reported in error stream and mo
dify your configuration code appropriately.
At C:\Windows\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psm1:3917 char:5
+     throw $ErrorRecord
+     ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (Basic_settings:String) [], InvalidOperationException
    + FullyQualifiedErrorId : FailToProcessConfiguration

Suggested solution to the issue

N/A

The DSC configuration that is used to reproduce the issue (as detailed as possible)

Configuration Basic_settings
{
    Import-DSCResource -ModuleName StorageDsc #For ISO-mounting

    Node "localhost"
    {

         MountImage MountMSSQL2016
        {
            ImagePath   = 'C:\Install\Software\Microsoft SQL Server 2016 RTM with SP2 (MSDN)\en_sql_server_2016_enterprise_core_with_service_pack_2_x64_dvd_12124052.iso'
            DriveLetter = 'S'
            #Ensure = 'Present'
        }

        WaitForVolume WaitForISO
        {
            DriveLetter      = 'S'
            RetryIntervalSec = 5
            RetryCount       = 10
            DependsOn = '[MountImage]MountMSSQL2016'
        }

        MountImage DismountMSSQL2016
        {
            ImagePath   = 'C:\Install\Software\Microsoft SQL Server 2016 RTM with SP2 (MSDN)\en_sql_server_2016_enterprise_core_with_service_pack_2_x64_dvd_12124052.iso'
            DriveLetter = 'S'
            Ensure = 'Absent'
            DependsOn = '[WaitForVolume]WaitForISO'
        }
    }
}

$configData = @{
    AllNodes = @(
        @{
            NodeName = '*'
            PSDscAllowPlainTextPassword = $True
            PsDscAllowDomainUser = $true   
        }
        @{
            NodeName = 'localhost'
            PSDscAllowPlainTextPassword = $True
            PsDscAllowDomainUser = $true   
        }
    )
}

Basic_settings -OutputPath "C:\DSC\Configurations" -ConfigurationData $configData

The operating system the target node is running

OsName               : Microsoft Windows Server 2016 Datacenter
OsOperatingSystemSKU : DatacenterServerEdition
OsArchitecture       : 64-bit
WindowsBuildLabEx    : 14393.1794.amd64fre.rs1_release.171008-1615
OsLanguage           : en-US
OsMuiLanguages       : {en-US}

Version and build of PowerShell the target node is running

PSVersion                      5.1.14393.1884                                                                                        
PSEdition                      Desktop                                                                                               
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                               
BuildVersion                   10.0.14393.1884                                                                                       
CLRVersion                     4.0.30319.42000                                                                                       
WSManStackVersion              3.0                                                                                                   
PSRemotingProtocolVersion      2.3                                                                                                   
SerializationVersion           1.1.0.1

Version of the DSC module that was used ('dev' if using current dev branch)

current

PlagueHO commented 4 years ago

Hi @NemoDima , sorry for the delay in getting back to you.

This is by design and is how DSC should be used. This was discussed in https://github.com/dsccommunity/StorageDsc/issues/154.

I do understand the requirement though. In general, I'd recommend just leaving the ISO mounted permanently. @johlju - any thoughts you can share here? E.g. what do other users of SqlServerDsc tend to do? Do they just leave the ISO mounted?

The gist is that DSC is designed to define a desired state. So creating a configuration that has two different states for a resource defined is considered illegal - e.g. in this case, having an ISO both mounted and unmounted is a conflict.

NemoDima commented 4 years ago

@PlagueHO thank you for the answer and explanation.

Now I understand DSC logic quite better. I'm not sure, but maybe it has the sense to add some remarks to readme about MountImage and row execution.

For my purpose, I'll try to look on Script(https://docs.microsoft.com/en-us/powershell/scripting/dsc/reference/resources/windows/scriptresource) or xScript from xPSDesiredStateConfiguration (https://github.com/dsccommunity/xPSDesiredStateConfiguration). Or https://github.com/PowerShell/PSDscResources#script would be better than https://github.com/dsccommunity/xPSDesiredStateConfiguration :)

Thanks again

johlju commented 4 years ago

any thoughts you can share here? E.g. what do other users of SqlServerDsc tend to do? Do they just leave the ISO mounted?

@PlagueHO normally I would say you don’t mount an ISO. I would say that the normal production scenario is instead to extracted the ISO into an UNC path and the SourcePath parameter of SqlSetup resource is pointed to that UNC path. Mounting an ISO is probably best used in lab environments where you change SQL Edition very often and don’t want to change the configuration for whatever reason.

Although it seems for whatever reason the normal scenario is mounting an iso. Not sure if that is by old habit from click-install processes.

@NemoDima is there a reason you mount the image instead of using an UNC share. Interested if the normal scenario I describe above is not as normal as I expect. 😊

bozho commented 4 years ago

@johlju We have a scenario where we host clients on bare metal machines which only have Windows Server installed and we need to install everything else, most notably SQL Server.

Our ideal workflow would be: download ISO file, mount, run SQL Server setup, unmount image, delete file. I'm aware it's much more imperative than declarative :-)

@NemoDima, the way we work around this is that we have a set of partial DSC configurations used for "initial configuration" - these involve bootstrapping our custom DSC resources module, setting up some very basic prerequisites (e.g. setting timezone, machine name, etc). That configuration set also contains a "one-off" partial configuration which sets up our SQL Server: downloads SQL Server ISO file, mounts it and runs SQL Server setup. For SQL Server 2017 and later, it also downloads and installs SSRS. That configuration set is run only once, against a brand-new machine.

After that, we have another set of partial configurations, which is a superset of the "initial configuration" partial configurations, with the one-off partial configuration removed.

@johlju, our approach does hit a snag at the moment, though. Our regular configuration unmounts the SQL Server ISO file and deletes it (no need to keep a few GB permanently mounted). Unfortunately, Get-TargetResource for MountImage throws an error if the target image file is not present on the system (Get-DiskImage throws), preventing our configuration from being re-runnable.

I think the simplest solution would be for MountImage to treat the mount as Absent if the target image is not present on the system instead of throwing an exception.

kewalaka commented 4 years ago

Another approach i've used in the past is to use a Script resource to install SQL based on a configuration file - see the example here: https://colinsalmcorner.com/install-and-configure-sql-server-using-powershell-dsc/

You do lose visibility within DSC with this approach, it used to be my go-to method when the install resource was less mature.

Now, the approach i typically take is to create a template that includes the SQL media already in situ, which could be kept up to date using something like packer (or a script).

Understand this means you've got ISOs copied everywhere, but in this age of de-duplicated storage and other wizardry it wasn't a worry for us.

johlju commented 4 years ago

@johlju, our approach does hit a snag at the moment, though. Our regular configuration unmounts the SQL Server ISO file and deletes it (no need to keep a few GB permanently mounted). Unfortunately, Get-TargetResource for MountImage throws an error if the target image file is not present on the system (Get-DiskImage throws), preventing our configuration from being re-runnable.

I think you will also hit a problem in SqlSetup if it is used since Get-TargetResource expects the setup.exe to be available to determine SQL major version. Major version is needed to determine the correct paths (e.g. registry) in a scenario where multiple instances is installed with different major versions.