· Oct 12, 2017

Unable to use variable in <Role> tag in Installer manifest?

I'm trying to write an installer manifest that can create a namespace, resources (%DB_namespace) and a role (with the resource, above), based on the namespace.  So you could pass in "ABC", or "XYZ", and it would create the %DB_ABC resource and the ABC role with %DB_ABC:RW permissions; or it will create the %DB_XYZ resource and the XYZ role with %DB_XYZ:RW permissions, accordingly.

I have a variable set up for the name of the namespace (in my code it's called PMGNAMESPACE), and I create a variable for the resource name, called PMGDbResource ( this == %DB_ABC)

The installer manifest is not evaluating the variable PMGDbResource int he <Role> tag, and I get this error:

017-10-12 08:56:57 0 RHS.Installer: ERROR #892: Resource ${PMGDbResource} does not exist.
2017-10-12 08:56:57 0 RHS.Installer: Installation failed at 2017-10-12 08:56:57

Is this typical or is there any work around?  If I can't evaluate the variable for the %DB_namespace resource name, then I can't add the Role for a different namespace.  I'm stuck with one name.

<Log Level="2" Text="Setting up PMGDbResource" />
<Var Name="PMGDbResource" Value="%DB_${PMGNAMESPACE}"/> <!-- %DB_PMG -->

Description="Namespace Resource for ${PMGNAMESPACE}"
Type="Application" />

<Log Level="2" Text="Creating ${PMGNAMESPACE} Role" />
<!-- Attempting to use PMGDbResource variable here -->
Description="Works User Role for ${PMGNAMESPACE} Namespace"
Resources="${PMGDbResource}:RW,PMG:RWU"                                              <-- I'd like to use ${PMGNAMESPACE} here too, but                                                                                                                                          variables aren't evaluated in this part of the Role tag :( -->
 RolesGranted="" />

Discussion (2)0
Log in or sign up to continue

Resources property is not evaluated. You can see that in %Installer.Role class, %OnGenerateCode method.

/// Generate code for this document.
Method %OnGenerateCode(pTargetClass As %Dictionary.CompiledClass, pCode As %Stream.TmpCharacter, pDocument As %Installer.Manifest) As %Status [ Internal ]
Do pCode.WriteLine(..%Indent()_"Do tInstaller.CreateRole($$$EVAL("_..Target_"),$$$EVAL("_..Description_"),"""_..Resources_""","""_..RolesGranted_""")")
Quit $$$OK

You can get around that with this hacky solution:

Description="Works User Role for ${PMGNAMESPACE} Namespace"
Resources='"_tInstaller.Evaluate("${PMGDbResource}:RW,PMG:RWU")_"' RolesGranted="" />

Which would be compiled into the following code:

 Do tInstaller.CreateRole(tInstaller.Evaluate("${PMGNAMESPACE}"),tInstaller.Evaluate("Works User Role for ${PMGNAMESPACE} Namespace"),""_tInstaller.Evaluate("${PMGDbResource}:RW,PMG:RWU")_"","")

I guess if you need to do that once, it's okay. But if it's a regular occurrence writing a method and calling it from installer might be a better solution.

Here's an article on %Installer usage.

Hi Eduard,

Interesting hack, and a good point.  There's enough going back and forth between namespaces, importing new code, and running new methods in the newly created namespace already, so I'd prefer to keep my manifest simple.  If I find that it needs to be done in, say, 5 places, I'll just say it needs to be the one value ("ABC") and I can create a copy of the installer if it needs to be a new value ("XYZ").  If it needs to be a new value, then we're probably moving toward replacing the old value anyway.