There is a huge benefit from two perspectives:

- If you need to refresh data in your Dev or Test environment, you can just grab the globals DB from Live and drop it in and not worry about overwriting any code in Dev or Test

- If you choose to deploy your code via a DB drop, you can drop in a new DB to replace the existing routines DB

NOTE - for either of these to work, you may need to map configuration into the routines DB (so you don't bring back Live config into Dev for instance)

HTH!

Ben

FYI ... we will have several sessions covering this topic at the Global Summit - attend if you can, otherwise check out the material afterwards!

For internal application development within InterSystems we use a variety of approaches, but the most common is as follows:

1) We use an internally developed issue tracking system, but we plan to eventually migrate to JIRA

2) We use Perforce for all of our source control 

3) We have BASE, TEST and LIVE environments for every application, typically BASE and TEST being cloned from VM snapshots of LIVE.  In addition to the Shared BASE VM, for those applications which are undergoing the highest rate of change, developers will create a local copy of the application to do their development work.  Some apps have all changes being developed on Shared BASE and the changes are progressed (via our Change Control tool) to TEST and the LIVE.  For applications where developers use Private BASEs, they commit there and then push the changes to Shared BASE and then to TEST and LIVE.

Feel free to ask questions (here or at Global Summit)!

Thanks for asking.

Sven,

I know that customers have set this up before.  Here are some old notes that I found which may point you in the right direction.  NOTE - I have never done this myself so I con't be of much help beyond pointing out this starting point:

Implementation Outline:
1. Configure CSP to accept IIS's authentication headers and pass them to Caché

2. Set up delegated authentication to use existing security model to assign $username and $roles 
based on the user's domain accountname and/or domain groups. (Implement ZAUTHENTICATE.MAC)

3. Enable delegated authentication for any desired services and CSP applications -- in this case 
the system management portal.
·  Configuration (e.g. CSP application definition)
·  Login Page Logic decides based on Gateway Service User, whether to trust REMOTE_USER HTTP 
header, or to prompt for username/password (other fields such as PIN are also an option).

HTH,

Ben

Steve,

Here is some sample code that should help get you going in the right direction.  NOTE - the byRef LD argument is a handle for the connection to the LDAP server and it needs to be cleaned up when you're done if you're going to fetch any attributes.  

(sorry for the messed up indentation)

 /// Authenticates against the configured domain, with username/password, passing a resulting a status ByRef and a returning success/failure value
ClassMethod Authenticate(username As %String, password As %String, ByRef Status As %Status, ByRef LD As %Integer) As %Boolean
{
Set Status=$$$OK, ret=0
If ('$data(username))||('$data(password)) 
    Set Status=$$$ERROR($$$GeneralError,"Both fields are required") 
    Quit 0
}

Set sc=$$$OK
Try {
//Connect to the LDAP server
Set LDAPServer="myldapserver.mydomain.com"
Set sc=$$$OK
Set LD=##class(%SYS.LDAP).Init(LDAPServer)
If LD=0 {
        Set LDAPStatus=##class(%SYS.LDAP).GetLastError()
        Set sc=$$$ERROR($$$GeneralError,"LDAP Init Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
Else {
    //Authenticate the passed in user by using the Binds command 
    Set Domain=..GetDomain()
    If ($$$isWINDOWS) {
        Set LDAPStatus=##Class(%SYS.LDAP).StartTLSs(LD)
        If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP StartTLSs Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    Else {
        Set LDAPStatus=##Class(%SYS.LDAP).Binds(LD,"",$lb(username,Domain,password),$$$LDAPAUTHNEGOTIATE)
        If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP Binds Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    } 
}
ElseIf ($$$isUNIX) {
    Set cert = ..GetCert()
    Set LDAPStatus=##Class(%SYS.LDAP).SetOption(LD,$$$LDAPOPTXTLSCACERTFILE,cert)
    If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP SetOption Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
        Do ..RotateOnFailure(sc)
Else {
        Set LDAPStatus=##Class(%SYS.LDAP).StartTLSs(LD)
        If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP StartTLSs Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    }
}
If LDAPStatus=$$$LDAPSUCCESS {
    Set LDAPStatus=##Class(%SYS.LDAP).SimpleBinds(LD,username_"@"_Domain,password)
    If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP SimpleBinds Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    }
}
Else {
    Set LDAPStatus=$$$LDAPAUTHMETHODNOTSUPPORTED
}
If (LDAPStatus'=$$$LDAPSUCCESS)&&($$$ISOK(sc)) {
    Set sc=$$$ERROR($$$GeneralError,"LDAP API Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
}
} 
Catch err {
    Set sc = $$$ERROR($$$GeneralError,err.Data) 
}
If $$$ISOK(sc) {
     Set ret = 1
Else {
    Set Status = sc 
}

Quit ret
}

Personally, I would do this via Source Control and not via Studio.  The approach to this will depend on your source control structures, etc, but the easiest way to handle this for me would be:

1) Make sure that everything in my package was checked into my branch, e.g. /MyApp/cls/MyFirstPackage/...

2) Since my source tree is structured according to package names, I would copy /MyApp/cls/MyFirstPackage/... to /MyApp/cls/MySecondPackage/... 

3) Check in /MyApp/cls/MySecondPackage/... into source control

4) Check out /MyApp/cls/MySecondPackage/... 

5) Do a Find & Replace in /MyApp/cls/MySecondPackage/... to replace all instances of "MyFirstPackage" with "MySecondPackage"

6) Diff /MyApp/cls/MySecondPackage/...  and make sure all replacements are desired

7) Check in /MyApp/cls/MySecondPackage/... 

8) Run my build routine to pull all of /MyApp/cls/MySecondPackage/...  into my namespace and Compile it (or just use $system.OBJ.LoadDir() if you don't already have a build routine)

Voila!  Package is duplicated and all checked into source control ready for further changes :) The above process should only take a couple of minutes.

Scott,

See the Documatic for the following methods in %Studio.SourceControl.ISC:

classmethod Lock(Admin As %Boolean = 0) as %Status

Lock the source control hooks for this instance.

The default setting will be "Locked". Passing a '1' for the Admin parameter will set the instance to AdminLocked.

See Locked for more details.

classmethod Locked() as %String

Returns value that shows whether or not this instance is "Locked"

Return values are:

  • "": Instance has never been Locked or Unlocked (default)
  • 0: Instance is Unlocked
  • 1: Instance is Locked
  • 2: Instance is AdminLocked

When the instance is Locked or AdminLocked, no changes can be made via Studio. It is possible to change from Locked to NotLocked via different UIs. When an instance is AdminLocked it should only be possible to unlock it via the Unlock method.

classmethod Unlock() as %Status

Unlock the source control hooks for this instance.

This is not a Caché utility - it must be supplied by your application partner.  Also, the AP must be storing their own users at the application level because if they were using Caché users there would be no way to create a utility that shows Caché users' passwords (see Patrick's answer below).

I suggest you reach out to your application partner with this question (or if it is an inhouse development, speak with the development team)

Paul,

Have you looked at the details in the Caché SQL manual about optimizing performance:

http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...

Play particular attention to the section about using TuneTable to properly set the meta-data around table extent size, selectivity, etc.  Lot of people miss this and it's very important because the query plans rely on this metadata to optimize performance.  

Playing around with it a little bit, I came to the following conclusions:

- *some* pages rely on the $Namespace url parameter in order to initialize what namespace it is pulling data from

- this doesn't appear to be stored in the session (and therefore it isn't shared between tab); I think it is only effective in the url

- there are some pages which don't honor the $Namespace url parameter (e.g. they still show %SYS even if $Namespace is defined to a different value); this is probably because those pages don't act on any namespace-specific data (or they act on data which lives ONLY in %SYS)

It sounds like if you want to keep your tabs in sync, you should put something in the session, and switch namespaces in your page logic.  Probably in OnPreHttp (although you'd need to test to make sure that the namespace sticks for the OnPage method as well)