Even more with Management Packs   Leave a comment

Last post, I went through the process of exporting management packs, so we can see what they do and what they define.  In this post, I’ll discuss importing management packs.  In order to get any benefit from a Management Pack (MP), it needs to be added to the Service Manager platform.  The process of adding an MP to the system is called "Importing".   For this example, we’ll use just a very simple management pack (the contents aren’t really interesting, but to go through the exercise we need one of these).

<ManagementPack ContentReadable="true" SchemaVersion="1.1" 
           xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
           xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <Manifest>
    <Identity>
      <ID>Simple.ManagementPack</ID>
      <Version>7.0.5622.0</Version>
    </Identity>
    <Name>A Simple ManagementPack</Name>
    <References>
      <Reference Alias="System">
        <ID>System.Library</ID>
        <Version>7.0.5622.0</Version>
        <PublicKeyToken>9396306c2be7fcc4</PublicKeyToken>
      </Reference>
    </References>
  </Manifest>
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="Simple.Class" Accessibility="Public" Abstract="false"  
                       Base="System!System.Entity" Hosted="false"  
                       Singleton="false" Extension="false">
          <Property ID="Id"     Type="guid"   Key="true"  Required="true"  />
          <Property ID="Name"   Type="string" Key="false" Required="false" 
                       CaseSensitive="false" MaxLength="256" MinLength="0" />
          <Property ID="Value1" Type="string" Key="false" Required="false"  
                       CaseSensitive="false" MaxLength="256" MinLength="0" />
          <Property ID="Value2" Type="string" Key="false" Required="false"  
                       CaseSensitive="false" MaxLength="256" MinLength="0" />
        </ClassType>
      </ClassTypes>
    </EntityTypes>
  </TypeDefinitions>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Simple.Class">
          <Name>Simple Class</Name>
          <Description>A simple class declaration</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPack>

The Service Manager console has a way to import this, of course, here’s what it looks like:

But you can also do this from PowerShell with a few of simple lines of script

# the two .NET types, we'll need to create
$EMGTYPE = "Microsoft.EnterpriseManagement.EnterpriseManagementGroup"
$MPTYPE  = "Microsoft.EnterpriseManagement.Configuration.ManagementPack"
# Create a connection to the Data Access Service
$EMG = new-object ${EMGTYPE} localhost
# Create a management pack object based on the management pack file and 
# connection to the Data Access Service
$MP = new-object ${MPTYPE} c:\temp\Simple.ManagementPack.xml,$EMG
# Call the import method on the ManagementPacks interface - all done!
$EMG.ManagementPacks.ImportManagementPack($MP)

As you can see, it’s pretty straightforward.  However, this isn’t the whole story.  If you notice in the XML above, there’s a section for "References", this section of the MP allows you to declare that your MP relies on other MPs for class definitions, etc.  This means that if those references aren’t installed, you’re MP isn’t going to work.  We go along way to keep bad data out of the system, so if you try to import an MP which references an MP which isn’t present on the system, then that import will fail.  When you’re considering a single MP, working out these references may not be to bad, but if you have a number of MPs that you want to import and some of them depend on other new imported MPs, you’ve got to get the order correct, or you won’t be able to import.  Most of the time, you’ll wind up inspecting those sections of the MPs, create your order, and finally import the MPs.  (I’ve seen a number of batch files that do this very thing, so I know that this happens).  That’s no good as it’s an awful waste of time and error prone as well.  I’ve created a script to go through any number of MPs and figure out what order they should be installed, and then install them!  The script is built so you can pipe the output of get-childitem to it. 

From a pseudo-code perspective, here’s what we need to do

Find out what MPs are already installed
and then
FOREACH of MPs to install
   retrieve the references
   FOREACH reference
         check to see if the referenced MPs is not already installed (or will be installed)
         IF the needed MP is not installed, skip for now
         IF all the references are
             installed and 
             the version is compatible and 
             the referenced MP is sealed and 
             the keytoken matches
         THEN
             add this MP to the list of MPs to which we'll be able to install
             remove this MP from the list of MPs that we want to install
             add it to the list of MPs that are already installed (since it will be)
             since the list of MPs to install has now changed, restart the main loop

If there are any MPs left in the list to install, it means that we weren’t able to resolve the references, so we won’t be able to install that MP.  Note that the failure can be for any reason, it could rely on an unsealed MP (I don’t want to discuss sealing here, suffice it to say that sealing an MP makes it immutable, this way we know the things that we rely on won’t change), the reference could be missing, it could require the wrong version, or it could have an incorrect KeyToken.   There really isn’t much automatic remediation that we can do, but we can report what went wrong.

So, now that we have a mechanism to put MPs in order, let’s see how it looks.


For our simple test, we’ll create 6 MPs, each one of them dependent on the next MP (from an alphabetical point of view). 

  1. SimpleMP.A depends on SimpleMP.B
  2. SimpleMP.B depends on SimpleMP.C
  3. SimpleMP.C depends on SimpleMP.D
  4. SimpleMP.D depends on SimpleMP.L
  5. SimpleMP.L depends on SimpleMP.M
  6. SimpleMP.M depends on System.Library

this means that the need to be installed in the opposite order, M installed before L, etc. 

First we’ll start by importing the XML file, since XML files can’t be sealed, we should get an error for every MP except the only one that can be installed (SimpleMP.M, since it relies on System.Library).

Now we can see where we have problems, and which MPs we can install.  Because I’m importing unsealed MPs, the references that I had can’t be satisfied.  Only SimpleMP.M can be installed, since it has only one reference to a sealed MP (System.Library).  Note also, that SimpleMP.L can’t be installed because it references SimpleMP.M which is unsealed.  The other MPs can’t be installed because their references aren’t there.  Now, let’s try this again with sealed MPs.

PS> Get-ChildItem *.mp


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---          4/2/2009  12:49 PM       4608 SimpleMP.A.mp
-a---          4/2/2009  12:49 PM       4608 SimpleMP.B.mp
-a---          4/2/2009  12:49 PM       4608 SimpleMP.C.mp
-a---          4/2/2009  12:49 PM       4608 SimpleMP.D.mp
-a---          4/2/2009  12:49 PM       4608 SimpleMP.L.mp
-a---          4/2/2009  12:49 PM       4608 SimpleMP.M.mp

If we tried to import these MPs in alphabetical order, only the last one would succeed, so we could import them by creating a script which does the import explicitly, one at a time, but we can use our script to do it in one fell swoop.  This means that we don’t really have to work out the dependencies manually – automation – that’s the key!

PS> get-childitem *.mp|./Import-ManagementPack -whatif 
WhatIf: Importing Management Pack SimpleMP.M
WhatIf: Importing Management Pack SimpleMP.L
WhatIf: Importing Management Pack SimpleMP.D
WhatIf: Importing Management Pack SimpleMP.C
WhatIf: Importing Management Pack SimpleMP.B
WhatIf: Importing Management Pack SimpleMP.A

Wahoo!  Even though the MPs have dependencies in reverse to the order returned by get-childitem, they’ll be installed in the correct order.  Granted, this example is pretty simple and the dependencies are straightforward, however, this script should handle pretty complicated sets of dependencies.

When actually coding this script, I decided that I wanted to make sure that I could be a bit more flexible than what was strictly possible from within Service Manager.  So I added options to avoid checking for the correct version, whether the MP in the reference is sealed and if the KeyToken is correct.    You still won’t be able to actually import if some of these things are wrong, but you’ll see the order if everything was correct and proper.  I also added -Verbose and -Debug parameters as well as a -WhatIf parameter which allows you to not actually Import the MPs, but will tell you what order they would be installed.  The script it a little on the larger size (about 200 lines), so I’m not going to walk through the script in this blog, but the code is fairly well commented. 

Here’s a link to the script:

http://cid-7143da6e51a2628d.skydrive.live.com/embedrowdetail.aspx/PowerShellFiles/Import-ManagementPack.ps1

Advertisements

Posted June 1, 2009 by jtruher3 in ServiceManager

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: