Why are the resource\key combination required to be unique

This topic contains 9 replies, has 5 voices, and was last updated by Profile photo of Jason Boyd Jason Boyd 2 years ago.

  • Author
    Posts
  • #19098
    Profile photo of Jason Boyd
    Jason Boyd
    Participant

    This has bitten me several times and I am wondering what the reason is for this requirement? Is it part of the .MOF specification, a technical issue with the DSC implementation or an arbitrary decision by the DSC team? If it was an arbitrary decision can we petition the team to remove this requirement?

    The problems this restriction can cause range from kind of annoying: http://stackoverflow.com/questions/23177212/using-the-file-provider-in-dsc-ensure-destination-only-contains-files-from-sou

    to truly troublesome: it breaks the composability of configuration files.

    For example, a recent issue I just ran into is that two different configuration resources had a need to append a path to the 'Path' environment variable. This resulted in the following error: The key properties combination 'Path' is duplicated for keys 'Name' of resource 'Environment' in node 'localhost'.

    The only real solution to this is to make sure all of the configuration resources are disjoint sets of resource\key pairs. That is not a viable solution for anything but the most trivial of server configurations. This would require that every configuration resource be aware of every other configuration resource, what they are configuring and how they are configuring it. Dependencies would get baked into configuration resources and decisions would have to be made about which configuration resource would be the one responsible for configuring concerns that cut across multiple configuration resources. Reusablity goes out the window because I cannot simply copy a configuration resource from one server to another unless I identify and bring along every configuration resource it is dependent on and their dependencies etc. What is to say I want all the baggage on the new server that those dependencies bring along or that they will not introduce conflicts on the new server. At that point it is not really a composite resource composed of independent configuration resources, it is a monolithic resource split into separate files. That does not have any value. I might as well just combine everything back into a single configuration resource. At least then I would be able to identify all of the conflicts and dependencies more easily.

  • #19100
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    I can't really speak for Microsoft reasoning here, but I assume that they're trying to avoid having to do any sort of conflict resolution within a configuration. For example, if you had two File resources with the same DestinationPath, but different values for SourcePath or Contents, how would the LCM know what the correct state of that file is? If it just applies everything in the file as-is (in order), you'd wind up changing the file twice each time the configuration was applied.

    For situations where this behavior isn't desirable, I'd probably recommend writing a new version of the resource where the "Key" property is just some bogus random value. Then your configuration could be something like this:

    configuration SomeConfig
    {
        node SomeNode
        {
            cAppendToEnvironmentVariable addWhatever
            {
                KeyProperty = 'Because DSC says I have to have one.'  # this is a [key] in the schema.
                Name = 'Path'  # This will be tagged as [required] instead of [key] in the schema
                ValueToAppend = 'C:\Program Files\Whatever\'   # [required] here as well.
                Ensure = 'Present'
            }
        }
    }
    
  • #19101
    Profile photo of Don Jones
    Don Jones
    Keymaster

    In large part to make DependsOn work, I suspect. But in any system, elements need a unique key.

    But there's ample evidence that you're wrong about that limiting configurations to trivial ones. I've done incredibly complex composite configurations – and keep in mind that the unique is per config, not globally. Breaking into sub Configs often makes it easier.

    You should also look at the v5 partial configurations.

    But – Id argue you're making a broad overstatement. Perhaps the current system doesn't work the way you'd prefer, but I've seen enough production deployments to believe it's completely viabLe if you adopt the right approach.

  • #19110
    Profile photo of Jason Boyd
    Jason Boyd
    Participant

    Okay, to say it only works for 'trivial server configuration' may have been an overstatement. I will give you that. But I think the issue I raise is valid. Requiring unique resource\key pairs does tightly couple separate configuration resources that are combined into a composite resource inasmuch as each configuration must be aware of the other configurations and what they are doing.

    You could argue, as Dave Wyatt does, that requiring they be unique will prevent users from inadvertently creating conflicting configurations but I do not buy that because it is still possible to shoot yourself in the foot; you could create your own DSC resource to get around the limitation as Dave Wyatt recommends or you could just use the 'Script' resource.

    Regarding your, "In large part to make DependsOn work, I suspect. But in any system, elements need a unique key.", now we are talking about two separate things. 'DependsOn' uses the reseource\resourcename pair, which must also be unique, but 'DependsOn' has nothing to do with the resource\key pair. For instance, I have these two 'configuration items' for lack of a better word that are in two different configuration resources:

    Environment SysinternalsSuitePath {
            Ensure = "Present"
            Path = $true
            Name = "Path"
            Value = "D:\Applications\SysinternalsSuite"
            DependsOn = "[Package]SysinternalsSuite"
        }
    
    Environment GitPath {
                Ensure = "Present"
                Path = $true
                Name = "Path"
                Value = "C:\Program Files (x86)\Git\bin"
                DependsOn = "[Package]Git"
            }
    

    They both use the 'Environment' resource and they both use the same key, 'Path' in this case, because 'Name' is the key for the 'Environment' resource. If I try to combine these two different configuration resources into one composite resource it will fail when I call the composite configuration.

    Don, when you say break it into sub configs are you talking about individual config files (not combined into a composite resource)? In that scenario would I just loop over each configuration file calling the configuration and then calling the Start-DscConfiguration on the resulting directory, rinse and repeat?

  • #19113
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    I haven't been using the Environment resource for anything yet. I've just looked through the code, and I have to agree with your take on it. It looks like it was intended to be used in such a way that you could call this resource multiple times for the same variable, if you also set the Path parameter to $true. As you've pointed out, this isn't allowed.

    I think there's probably still some value in preventing people from accidentally defining two different configurations for the same item (at least by default), but it would also be nice to allow that to happen in some specific cases, perhaps defined somehow in the schema.mof file. In the short term, I would recommend only using Environment with Path = $false, and writing another resource to cover the multi-valued Path-style environment variable in such a way that DSC will allow the configuration to be used.

  • #19124
    Profile photo of Michael Greene
    Michael Greene
    Participant

    I really wanted to know the technical answer to this thread title. So I looked it up. 🙂

    From the Common Information Model (CIM) Metamodel spec DSP0004. Page 23. Section 5.6.7. Document lines 754..755.
    http://www.dmtf.org/sites/default/files/standards/documents/DSP0004_3.0.pdf

    The class name and the name value pairs of all key properties in an instance shall uniquely identify that instance in the scope in which it is instantiated.

    I don't think unique key names are your pain though. The issue is specific to the resource. You are having trouble because you want to update the same thing twice within the same configuration. Example:

    configuration Name
    {
        node ('Node1','Node2','Node3')
        {
            # An env var is set
            Environment Test1
            {
               Ensure = 'Present'
               Name = 'Test'
               Value = 'Foo'
            }
    
            # Some other things happen
            
            # The same variable needs to be changed or updated (and the value could not be known previously)
            Environment Test2
            {
               Ensure = 'Present'
               Name = 'Test'
               Value = 'Bar'
            }
        }
    }
    

    I haven't seen too many cases where a declared configuration needs to change as it is being applied. In a perfect world the environment variable would be a known entity and so it should always be set a specific way. It would literally be declared that it should always be that way (make it so).

    So in your example, you know up front that you want both Sysinternals and Git to be part of the path. You could declare that variable one time with both values, probably towards the end of your configuration.

    I don't want to pick on one example though. It could be that you have found a case where combining settings is not the best approach? Can you provide a couple scenario examples where it is set and then set again within the same configuration? You could experiment with modifying the resource (as a "c" resource) and introducing some artificial string property to use as the Key if you have a reason to do it that way.

  • #19136
    Profile photo of Jason Boyd
    Jason Boyd
    Participant

    Micheal, that is awesome that you took the time to find that! Thanks. That puts my original question to rest.

    I think you are correct, the unique resource\key requirement is not the real issue. I have been considering this problem and I think the real issue is that some of the built in resources have poorly defined keys.

    In the case of the 'Path' variable for the 'Environment' resource I can see the dilemma the DSC team was in. On the one hand 'Path' is an environment variable and so it is easy for one to come to the seemingly logical conclusion that it should be handled by the 'Environment' resource. On the other hand, the 'Path' environment variable is nothing like the other environment variables. In practice it is not a single value, rather, it is a list of values. The fact that that list happens to be stored as a semi-colon separated string is irrelevant. You are not setting the state of a string you are setting the state of individual values in a list (whether they are present or absent). The DSC team chose to include management of the 'Path' variable in the 'Environment' resource which is why they had to tack on the odd 'Path' property which, I have to admit, felt like a hack when I first saw it. I think that was the wrong approach. Dave Wyatt's conclusion that a different resource is needed to manage the 'Path' environment variable is correct. The key for the new resource would be the path that is being appended to the variable or removed from the variable. That is what I plan on implementing on my own server.

    You are right that I could simply set the state of the 'Path' variable once at the end of the configuration but that flies in the face of what I am trying to accomplish. I am trying to create a set of composable and reusable configurations that can be combined into one composite configuration as described in this blog post by the DSC team:

    http://blogs.msdn.com/b/powershell/archive/2014/02/25/reusing-existing-configuration-scripts-in-powershell-desired-state-configuration.aspx

    I want to create a composite configuration that is composed of individual configurations each of which has a single responsibility. For example, one configuration's sole job is to configure the server as a master Git repository. One of the things that configuration needs to do is include the path to the Git directory in the 'Path' environment variable. However, because of the way the 'Environment' resource works, the act of doing that now precludes any other configurations from being able to modify that variable. That does not sound very composable. Again, based on how the 'Environment' resource works, the solution is that I would have to go through each configuration and identify everywhere the path variable is updated and pull them all out, combine them into one operation and place them in a different configuration file. Now I have lost reusablity because I cannot simply take my Git configuration to another server unless I bring along this other configuration file that it is dependent on which now includes a bunch of other stuff that I may not want on the other server.

    In my original post I had argued that the unique resource\key requirement broke this composability. I have come to the conclusion that the requirement in and of itself does not break composability but that poorly chosen resource keys can break composability.

    As far as other examples go, the only other resource I have encountered so far that can be problematic is the 'File' resource. Consider the following (contrived) example that fails:

    File CopyNotepadPlusPlusArchive {
    	Ensure          = "Present"
    	SourcePath      = $NotepadPlusPlusPath
    	DestinationPath = $DestinationPath
    }
    
    File CopySysinternalsSuiteArchive {
    	Ensure          = "Present"
    	SourcePath      = $SysinternalsSuiteSourcePath
    	DestinationPath = $DestinationPath
    }
    

    This fails because the key for the 'File' resource is just the 'DestinationPath'. On the face of it this seems like another example of a poorly chosen key. It seems to me that the correct key for this resource is the combination of the SourcePath and DestinationPath.

  • #19137
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Those are great ideas!

  • #20965
    Profile photo of Jason Capriotti
    Jason Capriotti
    Participant

    @JasonBoyd – did you happen to create a DSC resource to append values to an existing environment variable? I was needing the same thing was thinking about writing one and adding to the community resources. I was hoping this might already be floating around somewhere.

  • #20976
    Profile photo of Jason Boyd
    Jason Boyd
    Participant

    @JasonCapriotti – I did create a DSC resource but at the moment it is specific to the Path environment variable. I needed something quick to solve my immediate problem when I wrote it. That being said, I think what I have is organized fairly well and could be used as a jumping off point. It would be fantastic if it was generalized to any delimited environment variable. It would be even better if somebody else took the time to do it 😉 I have posted the work I did to GitHub. Feel free to take it and do whatever you want with it. https://github.com/johnnymumbles/ASI_cEnvironment.git

You must be logged in to reply to this topic.