Question
· May 11, 2021

Urgent Help - Unable to find/update Ensemble settings using Ens_Config.Item class programmatically for all Business Hosts

I have a requirement to update the Ensemble Host Settings Programmatically.  Mainly the  "AlertOnError,QueueCountAlert,QueueWaitAlert,InactivityTimeout" settings.

I used Ens_Config.Item (persistent) class to get the settings (list object) and then update it. But for some of the Business Host's, I dont see the above settings in the table, but present in Settings of that particular Host in Ensemble Management Portal. So my logic is not working.

Why is that and how to write a code to update the above settings for all the hosts ?

Please let me know the way to achieve my requirement.

My code.

&SQL(SELECT ID INTO :Oid FROM Ens_Config.Item WHERE NAME = :HostName)
Write Oid,!
If ($Get(Oid) '="")
{
Set item=##class(Ens.Config.Item).%OpenId(Oid)

Set tSetting = item.FindSettingByName(SettingName, SettingType) //Write tSetting,!
If (tSetting = "")
{
Write "Unable to find the Setting : """_SettingName_""" for the SettingType : "_SettingType,!
Quit
}

If '$IsObject(tSetting) {
Set tSetting = ##class(Ens.Config.Setting).%New()
Set tSetting.Name = SettingName
Set tSetting.Target = SettingType
Set tStatus = tSetting.ValueSet(SettingValue)
If $$$ISERR(tStatus) Quit tStatus
Set tStatus = item.Settings.Insert(tSetting)
}
Else {
Write "In else",!
Set tStatus = tSetting.ValueSet(SettingValue)
}
Set sts = item.%Save()
Write "Save status : "_sts,!
Write tStatus,!
}
//Update Production after the setting change.
Write ##class(Ens.Director).UpdateProduction(),!

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

Hello T,

Some settings such as AlertOnError aren't in Ens.Config.Item but are stored in the production definition class.

edit: see my comment below, these settings are in the production definition, but you seem to be able to modify them using Ens.Config.Item as well.

Perhaps you could use the System Default Setting?

For something like this, especially with urgency, I'd recommend reaching out to your InterSystems rep or the WRC.

Hi

There are a couple of things to note here:

1) You can programmatically update the Production Item settings as well as the settings of the Adapter bound to the Service or Operation. What you won't see are those modified values on the Production Item Settings TAB though if you do a $$$TRACE in your code you will see that the setting value is the value to assigned to the setting.

2) The Production Item has groups of common attributes such as Information, Connection, Alerting, Development. Most of these are common to almost all production items. 

3) If you want to add a custom setting to the Production Item define it as a property. for example:

Property MaxNumberOfLoops As %Integer [ InitialExpression = 200 ]; 

and then if there isn't already a PARAMETER Settings include the following:

Parameter SETTINGS = "MaxNumberOfLoops:Basic";

This will add a field to the Basic section of the Settings TAB and in the OnProcess(), OnProcessInput() or equivalent methods you can access the property value using  normal object instance syntax:

set maxloops=..MaxNumberOfLoops

4) For a more complex example where you might want to include a drop down list of values derived from a class/table in the database you can do the following:

Property Organization As %String;

Property OrganizationId As %String [ Calculated ];

Parameter SETTINGS = "Organization:Basic:selector?context={Nigel.Production.ContextSearch/Organizations}"';

The code for this ContextSearch is specified in a class method called "Organizations" (the name that follows the ContextSearch/Name} in a class that has the following attributes:

Class Nigel.Production.ContextSearch Extends Ens.ContextSearch
{

ClassMethod Organizations(Output pCaption As %String, Output pTopResults, Output pResults, ByRef pParms As %String, pSearchKey As %String = "") As %Status
{
     set tSC=$$$OK,count=1,pCaption="" kill pResults,pTopResults
     try {
           &sql(declare cursor for SELECT Name into :tName FROM Nigel_Organization.Organization)
           &sql(open x)                                                                                                                                                                             
           for &sql(fetch x)  quit:SQLCODE  set pResults(count)=tName,count=count+1 }

            &sql(close x)
       }
       catch ex {set tSC=ex.AsStatus()}
       quit tSC
    }

}

This will populate the list with the Organization Name and you will want to maintain an array of "Organization Name" back to Organization Internal Id. You can specify the Caption to introduce spaces and other cosmetic features.

There are also some built in functions that you can make use of for the selector such as a Calendar for Dates/Date&Time, A Directory Selector, File selector, basically the standard Zen custom components which canbe handy.

As a matter of interest what production item doesn't have the Alerting section. If it doesn't, and given that apart from the development and testing section if there isn't an Alerting Section then there is probably a very good reason why alerting is just not appropriate for that item. Even Ens.Alert has an Alerting section. LOL

If you wanted to add some additional field to the Alerting section then define the property but link it to:

PARAMETER Settings="myProperty:Alerting;"

on the other hand:

I once designed an architecture where I had a an abstract device class and a whole lot of abstract adapter classes which I inherited into persistent classes and each persisted device had a unique name and in the OnInit method I would get the production item name and if i could find an entry for that name in my device Index global I would use the values from my device table to populate the production item with specific device or adapter setting values. It is a bit complex to explain here so let me know if you want any more information on how I made it work but I think that Ensemble ultimately added that sort of functionality in later releases. I think i developed my own version for Ensemble 2014 or earlier.

Finally if you are not sure if a Production Item Setting exists use the following code:

Set outputContentType=$GET(pInput.Attributes("Content-Type"),"text/xml")

and if apart from the

PARAMETER Adapter ="......";

property Adapter as EnsLib.......;

you can use something like:

set xyz=$property(..Adapter,{Property_Name}) if the property doesn't exist then it will return a <property does not exist> error if it is not a property of the Adapter class and you can check that by using the code:

if ##class(%Dictionary.CompiledProperty).%ExistsId("Classname||PropertyName") is true then the property is a property of the Adapter class 

Nigel

You could also try

quit ##class(Ens.Director).GetCurrProductionSettings(.pSettings)

and then

according to the documentation you should be able to use:

in Ens.Production

classmethod ApplySettings(pProductionName As %String, ByRef pSettings) as %Status

Apply multiple settings to a production pProductionName is the name of the Production to which to apply the settings
pSettings is a local array of settings structured in the following way:
pSettings(<itemName>,<target>,<settingName>)=<settingValue>
Where:
<itemName> is the configuration item name in the production
<target> Is one of:
Item: Means the setting is a property of the item itself, such as PoolSize
Host: Sets a host setting
Adapter: Sets an adapter setting
<settingName> is the setting name
<settingValue> is the desired value of the setting.

and also in Ens.Production to get the production settings use: \

classmethod GetSettingsArray(Output pSettings) as %Status
 

I haven't tried them but thats what the documentation in the class says

Nigel 

Your problem is the FindSettingsByName method, above, does not find settings you see in the production settings tab for some items, right?

They are shown in black (not green from the class definition or blue from System Default Settings)?

If you do: SELECT ID, Production, Name, Settings FROM Ens_Config.Item do you see them in the Settings column? 

Do you see the settings in the production class XData block?

Do you have examples where a given setting shows with one items but not others?

Hi Kevin,
Yes, FindSettingsByName method is giving empty for some items. 
They are showing Green color in the mgmt portal. I also couldnt find them in the Settings value of Ens_Config.Item table.  It gives only few settings values. E.g below

*LoggingTargetHostOPR_LOG_SOCAL_OPR ApplicationNameHostHSC RetryIntervalHost30


It's a custom Operation class (extends EnsLib.HL7.Operation.TCPOperation) in which the Alert properties are overridden.

It's not working for a host which has class name of EnsLib.HL7.Operation.FileOperation , but it works for EnsLib.HL7.Operation.HTTPOperation, since it shows those settings in Ens_Config.Item table.

I need to find out, what are the cases, in which the Alert Settings are not showing in the Ens_Config.Item table.

Appreciate any help. We can connect directly, if you want. Let me know your availability through email.

In the Ens_Config.Item table, For the same underlying custom TCP operation class, I see one entry has these Alert Settings and other doesnt have all of the Alert Settings.
I am not sure, what's the reason behind this .

ReplyCodeActionsHost:~=C #ApplicationNameHost Initiate *LoggingTargetHostOPR_LOG_SOCAL_OPR AlertOnErrorHost1 %AlertRetryGracePeriodHost1200 InactivityTimeoutHost60 QueueCountAlertHost30 ReconnectRetry Adapter5 RetryIntervalHost60

 

 

ApplicationNameHostCAC *LoggingTargetHostOPR_LOG_SOCAL_OPR AlertOnErrorHost1

I could see the reason behind this. 
Whatever setting present in the Production class Xdata block, those only available in the Ens_Config.Item table->Settings column
So the real question now is, How do I Update the settings, which are not present in the Production Class/Ens_Config.Item, but showing as a setting for the Business Host in management Portal through a piece of code.

E.g

Production XData block

 <Item Name="OPR_ALL_SMM_MLA" Category="SMM_ADT,SMM_ORM" ClassName="SJHLIB.Operation.HL7.TCPOperation" PoolSize="1" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
    <Setting Target="Host" Name="LoggingTarget">OPR_LOG_SOCAL_OPR</Setting>
    <Setting Target="Host" Name="ApplicationName">MLA</Setting>
  </Item>
  
  Ens_Config.Item
  
  *LoggingTargetHostOPR_LOG_SOCAL_OPR ApplicationNameHostMLA

Production XData block

<Item Name="test" Category="" ClassName="EnsLib.HL7.Operation.HTTPOperation" PoolSize="1" Enabled="false" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
    <Setting Target="Adapter" Name="HTTPServer">localhost</Setting>
    <Setting Target="Adapter" Name="HTTPPort">30021</Setting>
    <Setting Target="Adapter" Name="Credentials"></Setting>
    <Setting Target="Adapter" Name="URL"></Setting>
    <Setting Target="Host" Name="ArchiveIO">1</Setting>
    <Setting Target="Host" Name="AlertOnError">1</Setting>
    <Setting Target="Host" Name="InactivityTimeout">10</Setting>
    <Setting Target="Host" Name="QueueCountAlert">10</Setting>
    <Setting Target="Host" Name="QueueWaitAlert">10</Setting>
    <Setting Target="Host" Name="AlertRetryGracePeriod">10</Setting>
    <Setting Target="Host" Name="AlertOnErro">0</Setting>
    <Setting Target="Host" Name="PoolSize">1</Setting>
    <Setting Target="Host" Name="PoolSiz">1</Setting>
  </Item>

Ens_Config.Item

"""HTTPServer Adapterlocalhost" HTTPPort Adapter30021 Credentials Adapter URL Adapter ArchiveIOHost1 AlertOnErrorHost0 InactivityTimeoutHost0 QueueCountAlertHost0 QueueWaitAlertHost0 #AlertRetryGracePeriodHost10 AlertOnErroHost0 PoolSizeHost1 PoolSizHost1

Any help is appreciated.

Yes. those that show green or blue will not show with the query since they are stored in System Default Settings or defaults in the class. Only those that are black are the ones in the XData.  You can still create a new Settings entry and save it (they should then show as black, since it will then be a setting in the XData settings.)

If you want to walk through a list of all the configuration settings for an item, not just those that have been set, you can find an example in the GetSettingsSubTree() method of the EnsPortal.DefaultSettings class.

  If $IsObject(pItem) {
       Set tSC = pItem.GetStaticSettings(.pList)
       if $$$ISOK(tSC) {
          Do pItem.PopulateVirtualSettings()
          
Set n0 = $O(pList(""),-1)
          Set n = pItem.VirtualSettings.Count()
          For I = 1:1:n {
             Set pList(n0+i) = pItem.VirtualSettings.GetAt(i)
          }
    
}

Each of the setting items in pList are a $LIST that contains:

Type = $LIST(setting,1)                               // "host"
Name = $LIST(setting,2)                             //"FilePath"
Value = $LIST(setting,3)
Description = $LIST(setting,7)
DataType = $LIST(setting,8)                       // "%Library.String"
LocalizedName = $LIST(setting,15)            // "File Path"
Setting Category = $LIST(setting,16)         // "Basic"
Localized Category = $LIST(setting,17)     // "Basic Setting"
Editor = $LIST(setting,18)                          // "directorySelector"

Thanks for the response Kevin. Using this, I have modified my code to disable all the "Alerting" settings ( even though, they might not be present in the Ens_Config.Item table, but present in the Host class settings in mgmt portal(green color))

OID is , OID of the Ens_Config.Item table.
Here is my code.
Let me know, if I have to change anything.

UpdateSetting(Oid) public
{
Set sts = 0
Set tStatus = 0
If ($Get(Oid) '="")
{
Set item=##class(Ens.Config.Item).%OpenId(Oid) If $IsObject(item)
{
Set tSC = item.GetStaticSettings(.pList)
If $$$ISOK(tSC)
{
         Do item.PopulateVirtualSettings()
           Set n0 = $O(pList(""),-1)
           Set = item.VirtualSettings.Count()
           For = 1:1:
           {
            Set pList(n0+i) = item.VirtualSettings.GetAt(i)             //Check the group of this setting and we need only the Alerting group settings
            If ($LIST(pList(n0+i),16)="Alerting")
            {
             Set SettingName = $LIST(pList(n0+i),2)
             Set SettingType = $LIST(pList(n0+i),1)
             Set SettingDataType = $LIST(pList(n0+i),8)
            Set tSetting = item.FindSettingByName(SettingName, SettingType)
            //Write SettingName,!
            //ZW pList(n0+i)
            
            //If the Setting DataType is String set as empty, otherwise zero
            Set SettingValue = $Select(SettingDataType="%Library.String":"",1:0)
            
            //If the setting is present in Ens_Config.Item table/Production Host class, set the value alone, otherwise Populate the setting into it.
            If '$IsObject(tSetting) {
Set tSetting = ##class(Ens.Config.Setting).%New()
Set tSetting.Name = SettingName
Set tSetting.Target = SettingType
Set tStatus = tSetting.ValueSet(SettingValue)
If $$$ISERR(tStatus) Quit
Set tStatus = item.Settings.Insert(tSetting)
}
Else {
Set tStatus = tSetting.ValueSet(SettingValue)
}
Set sts = item.%Save()
            
       }        
           }     
     }
}
}
Quit (sts&&tStatus)
}