Authors: Sam Habiel
Last updated in December 2018.
While none of the previous sections are required for completing this section, you need to set-up the
OPEN PARAMETERS
of the HFS device entry as KIDS won't work without it. Look in VistA Initialization HFS Device section. Also, you need to know how to get to theEVE
menu. For the purposes of this section, setting your DUZ and runningD ^XUP
works fine.
A VistA system, like a new car, is old by the time you drive it. One of the big challenges for new users for VistA is understanding the large amount of on-going updates. Almost always, without exception, new users of VistA tend to fall behind on patching when first implementing the system. There is no automated system to apply updates (see the last section for discussion); so it takes some discipline to keep up on the VistA updates. I do acknowledge that the situation needs to be improved. The system that is used to update VistA is the Kernel Installation Distribution System (KIDS). KIDS consists of files or mail messages (rare for people outside of the VA) that you load into a VistA system.
There are many concepts that reference each other; and while I try to go in an order that makes sense, it may help to read this twice.
Most of the document discusses how to install a KIDS build. The end of the document discusses how to acquire all the KIDS builds to bring your VistA up to date; you can jump there now if you wish: Patching up an old VistA System.
There is an older link on this website about KIDS: It provides a good introduction if you are a VistA developer.
TL;DR = Internet Slang for Too Long; Didn't Read
If you just want to know how to install a KIDS build, here are the steps:
Outside of VistA:
dos2unix
the file.readlink -f {filename}
; on Windows, typing Win+R to open the run box and dragging the file there will do the trick.Inside of VistA:
Prerequisite: XUPROG
security key.
An even shorter way to install a KIDS build is to run D ^XPDIL,^XPDI
from direct mode (aka programmer mode). This runs steps 5 and 6.
Here's an example starting from after logging in as the system manager with EVE
as the main menu. Responses are in bold.
Core Applications ... Device Management ... Menu Management ... Programmer Options ... Operations Management ... Spool Management ... Information Security Officer Menu ... Taskman Management ... User Management ... Application Utilities ... Capacity Planning ... HL7 Main Menu ... Systems Manager Menu: Programmer Options KIDS Kernel Installation & Distribution System ... PG Programmer mode Delete Unreferenced Options Error Processing ... Global Block Count Routine Tools ... Programmer Options: KIDS Kernel Installation & Distribution System Edits and Distribution ... Utilities ... Installation ... Patch Monitor Main Menu ... Kernel Installation & Distribution System: Installation 1 Load a Distribution 2 Verify Checksums in Transport Global 3 Print Transport Global 4 Compare Transport Global to Current System 5 Backup a Transport Global 6 Install Package(s) Restart Install of Package(s) Unload a Distribution Installation: 1 Load a Distribution Enter a Host File: /tmp/GMRV-5_SEQ-29_PAT-37.kids Released GMRV*5*37 SEQ #29 Comment: Extracted from mail message This Distribution contains Transport Globals for the following Package(s): GMRV*5.0*37 Distribution OK! Want to Continue with Load? Yes// y es Loading Distribution... GMRV*5.0*37 Use INSTALL NAME: GMRV*5.0*37 to install this Distribution. 1 Load a Distribution 2 Verify Checksums in Transport Global 3 Print Transport Global 4 Compare Transport Global to Current System 5 Backup a Transport Global 6 Install Package(s) Restart Install of Package(s) Unload a Distribution Installation: 6 Install Package(s) Select INSTALL NAME: GMRV*5.0*37 Loaded from Distribution 2018-12-22@12 :02:02 => Extracted from mail message ;Created on This Distribution was loaded on 2018-12-22@12:02:02 with header of Extracted from mail message ;Created on It consisted of the following Install(s): GMRV*5.0*37 Checking Install for Package GMRV*5.0*37 Install Questions for GMRV*5.0*37 Want KIDS to INHIBIT LOGONs during the install? No// <enter> Want to DISABLE Scheduled Options, Menu Options, and Protocols? No//<enter> Enter the Device you want to print the Install messages. You can queue the install by enter a 'Q' at the device prompt. Enter a '^' to abort the install. DEVICE: HOME// ;p-other; CONSOLE Install Started for GMRV*5.0*37 : 2018-12-22@12:02:36 Build Distribution Date: 2018-01-10 Installing Routines:.. 2018-12-22@12:02:36 Running Post-Install Routine: EN^GMV37PST. Updating system parameters. Updating Routine file...... Updating KIDS files....... GMRV*5.0*37 Installed. 2018-12-22@12:02:36 Not a VA primary domain NO Install Message sent 1 Load a Distribution 2 Verify Checksums in Transport Global 3 Print Transport Global 4 Compare Transport Global to Current System 5 Backup a Transport Global 6 Install Package(s) Restart Install of Package(s) Unload a Distribution Installation:
KIDS was written by Ron DiMecili at the VA in 1994. It was based on a white paper written by several senior developers, led by Cameron Schlehuber, the Database Administrator. Before KIDS existed, VistA (known in those days as the Decentralized Hospital Computer Program [DHCP]) used a technology called DIFROM to transport routines/data between two systems. DIFROM, as it name indicates, is part of Fileman (DI in the name is the namespace for Fileman). DIFROM transported data as routines, as routines were one of the few early standardized ways to share data between different M systems. The routines were were moved between systems using tapes or floppy disks which were mailed.
By about 1987, VistA systems were all networked to each other via Mailman (i.e. SMTP). Mailman added a format called "Packman" which allowed the transport of DIFROM formatted routines via SMTP, rather than by "snail mail" on tapes or floppy disks.
KIDS came around in the mid 90s; and M systems were by now running on an operating system rather than being the only thing that ran on a machine--so the concept of files on a file system was well-developed by then. The data format that KIDS uses looks like the global output format that is a lowest common denominator standard between M implementations. KIDS can send messages either through email or via files. As stated earlier, in the VA single builds are transported as mail messages; whereas outside of the VA, most builds are transported as files.
Incidentally, the header and footer for the formats for the mail messages vs KIDS file on the file system are slightly different. The mail messages use the same format that Packman used.
KIDS files are easy to identify. The extension is a .kid[s] and the first few lines look like this:
Released GMRV*5*37 SEQ #29
Extracted from mail message
**KIDS**:GMRV*5.0*37^
**INSTALL NAME**
GMRV*5.0*37
"BLD",10542,0)
GMRV*5.0*37^GEN. MED. REC. - VITALS^0^3180110^y
"BLD",10542,1,0)
^^2^2^3180108^
"BLD",10542,1,1,0)
This patch will resolve the following issues in the Vitals Lite DLL
The "patch name" GMRV*5.0*37
consists of three pieces: GMRV
is the package namespace (a package namespace is the place where the package code lives); 5.0
is the package version; and 37
is the patch number. We need to note that patches in VistA are not real patches in the Unix sense: They are whole replacements of parts of a program; not line additions and deletions. Thus the name "patch" for KIDS files is misleading. Originally, there was a difference between a whole version release of a package (where the KIDS file would be known as a package) and a release of a patch to a package (where the KIDS file would be known as a patch). Since most KIDS files are patches; they now tend to be called KIDS patches, even in the rare case when the KIDS file actually transports a package not a patch.
Let's talk about the so-called "Sequence Numbers". The first line contains this information: GMRV*5*37 SEQ #29
. SEQ #29 means that this patch should be applied as the 29th in order for the vitals package. This is because it's possible to release patches where the patch number does not correspond to the order in which the patches should be installed, as patch numbers are assigned when development starts, not when it completes. In other words, patch numbers are assigned when you start working on something; but if you are working on a new feature, it can take much longer to release than a simple bug fix. For examples, if you head over here, you will notice that patch 35 has sequence number 24, whereas patch 27 has sequence number 25. That means, in spite of patch 35 seeming to be later than patch 27, what you really need to do is apply patch 35 first, then patch 27, since it has the earlier sequence number.
Astute observers will note that the 5 contains a .0
in some places and not in others. Different systems may allow or not allow the .0
when there isn't a decimal.
Due to the fact that sequence numbers are what tells people what order to install patches in, when patches are stored in files, file names put the sequence number first so that any computer program can sort the patches in the order that they need to be applied. The file name for patch GMRV*5.0*37
is GMRV-5_SEQ-29_PAT-37.kids
.
Each KIDS patch comes with a text file containing information on what the patch fixes and how to install it. The one for the patch we are looking is named GMRV-5_SEQ-29_PAT-37.txt
; and you can find it here.
There are 4 kinds of files. The first three are variations on each other; the 4th is different.
The last lets you dump a global from one system and load it onto another system.
All VistA software developed in the VA goes through the Patch Module. The patch module is responsible for allocating patch numbers and for storing each version of the KIDS build while it is in development. The Patch Module also distributes "verified" KIDS builds to the end sites via email messages to the VistA sites inside of the VA. The email message contains both the software and the text that accompanies the patch that we saw in section How to Identify KIDS files. The whole message is called a Packman message.
KIDS has been enhanced to be able to send out combined builds and multibuilds; but the Patch Module has not. So when a combined build or multibuild is produced inside the VA; it is distributed outside the Patch Module.
The current location of the FOIA copy of the VA's patch stream is here.
To learn a bit about how VistA is updated, we need to take a look at the so-called "Patch Stream". There are two ways to view it:
In the section How to Identify KIDS files, we looked at the patches for the Vitals Package.
You might want to spend a few minutes exploring the few links above before returning here.
Note the pair-wise correlation between .TXT files and .KID files. The reason for the patch module detour is that .TXT file and .KID file are the two parts of the packman message - the description, as well as the KIDS data itself. Of note, I am told that a trailing lowercase s on the .KID means that the file got redacted. I don't know if that's true as I see a lot of files with .KIDs that don't seem to have been redacted.
The section in the TL;DR gave you a quick overview of how to install KIDS files. We will repeat the discussion here in more detail.
The installation menu resides here: System Manager (EVE) > Programmer Options > KIDS > Installation. When you reach that menu, you get the following menu options:
1 Load a Distribution
2 Verify Checksums in Transport Global
3 Print Transport Global
4 Compare Transport Global to Current System
5 Backup a Transport Global
6 Install Package(s)
Restart Install of Package(s)
Unload a Distribution
The steps are helpfully marked from 1-6 in the order you need to follow them in.
This option loads the KIDS build from the file system. If the KIDS build is a Global Build, then this option also installs the globals.
Before you invoke this option, you should download the KIDS build you want to install, and dos2unix
it. You should typically dos2unix
the KIDS build file first to prevent problems on GTM/YottaDB systems which don't have a way to automatically remove the Carriage Return. After you do that, you should get copy the path to the file.On Linux & Cygwin, you can get the path using readlink -f {filename}
; on Windows, typing Win+R to open the run box and dragging the file there will do the trick. KIDS comes by default with a limit of 75 characters for the path--if you have a long path, you may need to copy the file into another place on the file system to get a short path. (Or you can manually modify XPDIL in order to allow a bigger path length -- the line to change is described here).
What you see next depends on the kind of KIDS build you are loading, whether there is an environment check, and whether there are dependency checks. An environment check is a programmatic check placed by the developer who created the KIDS build to check if it should be allowed on your system. Dependencies are KIDS builds that need to be installed first. All types of KIDS builds allow environment checks; all non-global builds allow dependency checks. If you are loading multi-builds (type 2 or type 3 - see Kinds of KIDS files), you will get environment checks for each one.
I would like to note that a lot of people use spacebar, enter to select the build in subsequent options--but that doesn't work for multi-builds (type 2 or type 3).
Select Installation Option: 1 Load a Distribution Enter a Host File: /tmp/PSJ-5_SEQ-304_PAT-356.kids Released PSJ*5*356 SEQ #304 Comment: Extracted from mail message This Distribution contains Transport Globals for the following Package(s): PSJ*5.0*356 Distribution OK! Want to Continue with Load? YES//<enter> Loading Distribution... PSJ*5.0*356 Use INSTALL NAME: PSJ*5.0*356 to install this Distribution.
Steps 2-5 are optional steps. However, if you are a test system for new KIDS patches; or are developing software, you should follow steps 2-5. Production sites are advised to back up the current copy of their routines using Backup a Transport Global
.
This checks that the routines in the KIDS build have not been altered. Note that non-routine elements (of which there are many) are not checksummed. If they were modified in transit, there is no way to detect that.
Select Installation Option: 2 Verify Checksums in Transport Global Select INSTALL NAME: <spacebar><enter> PSJ*5.0*356 Loaded from Distribution 12/25/18@14:01:15 => Extracted from mail message ;Created on This Distribution was loaded on Dec 25, 2018@14:01:15 with header of Extracted from mail message ;Created on It consisted of the following Install(s): PSJ*5.0*356 Want each Routine Listed with Checksums: Yes// <enter> YES DEVICE: HOME// ;;999 CONSOLE PACKAGE: PSJ*5.0*356 Dec 25, 2018 2:26 pm PAGE 1 ------------------------------------------------------------------------------- PSJPAD70 Calculated 196235756 PSJPAD7I Calculated 94307166 PSJPADIT Calculated 210594395 PSJPADIU Calculated 4945715 4 Routines checked, 0 failed.
This allows you to inspect the contents of the build you just loaded. Here's an example:
Select Installation Option: 3 Print Transport Global Select INSTALL NAME: <spacebar><enter> PSJ*5.0*356 Loaded from Distribution 12/25/18@14: 01:15 => Extracted from mail message ;Created on This Distribution was loaded on Dec 25, 2018@14:01:15 with header of Extracted from mail message ;Created on It consisted of the following Install(s): PSJ*5.0*356 Select one of the following: 1 Print Summary 2 Print Summary and Routines 3 Print Routines What to Print: 1 Print Summary DEVICE: HOME// ;;999 CONSOLE PACKAGE: PSJ*5.0*356 Dec 25, 2018 2:39 pm PAGE 1 ------------------------------------------------------------------------------- TYPE: SINGLE PACKAGE TRACK NATIONALLY: YES NATIONAL PACKAGE: INPATIENT MEDICATIONS ALPHA/BETA TESTING: NO DESCRIPTION: This patch will resolve the following issue. I17870223FY18 - FRAMESTACK error ENVIRONMENT CHECK: DELETE ENV ROUTINE: PRE-INIT ROUTINE: DELETE PRE-INIT ROUTINE: POST-INIT ROUTINE: DELETE POST-INIT ROUTINE: PRE-TRANSPORT RTN: ROUTINE: ACTION: PSJPAD70 SEND TO SITE PSJPAD7I SEND TO SITE PSJPADIT SEND TO SITE PSJPADIU SEND TO SITE INSTALL QUESTIONS: Default INHIBIT LOGONs during the install: NO Default DISABLE Scheduled Options, Menu Options, and Protocols: NO REQUIRED BUILDS: ACTION: PSJ*5.0*317 Don't install, leave global
This option compares the components in the KIDS build to your current system. It does not just do it for routines; it also does it for other components a KIDS build sends out. This is an important step for developers exchanging KIDS builds -- as it lets them see what changes this build is going to make to the system. Here's an example; discussion follows.
Select Installation Option: 4 Compare Transport Global to Curren t System Select INSTALL NAME: <spacebar><enter> PSJ*5.0*356 Loaded from Distribution 12/25/18@14: 01:15 => Extracted from mail message ;Created on This Distribution was loaded on Dec 25, 2018@14:01:15 with header of Extracted from mail message ;Created on It consisted of the following Install(s): PSJ*5.0*356 Select one of the following: 1 Full Comparison 2 Second line of Routines only 3 Routines only 4 Old style Routine compare Type of Compare: 1 Full Comparison DEVICE: HOME// ;;9999 CONSOLE Compare KIDS package PSJ*5.0*356 to current site (Disk) Site: DEMO.OSEHRA.ORG UCI: VAH,ROU Dec 25, 2018@14:54:28 KIDS Disk ------------------------------------------------------------------------------- Routine: PSJPAD70 2{ ;;5.0;INPATIENT MEDICATIONS ;**31} 2{ ;;5.0;INPATIENT MEDICATIONS ;**31} {7,356**;16 DEC 97;Build 7} {7**;16 DEC 97;Build 130} ^ ^ 22{ S PSJPSYS=$$FIND1^DIC(58.601,"","} 22{ S PSJPSYS=$$FIND1^DIC(58.601,"","} {",PSJPSYS) K DIERR Q:'PSJPSYS "" } {",PSJPSYS) Q:'PSJPSYS ""} ^ ^ {;*356} 25{ K DIERR S CABIEN=$$FIND1^DIC(58.6} 25{ S CABIEN=$$FIND1^DIC(58.63,"","",} ^ ^ {3,"","",CABNAME) K DIERR Q:'CABIEN} {CABNAME) Q:'CABIEN ""} { "" ;*356} 27{ K DIERR D GETS^DIQ(58.63,CABIEN_"} 27{ D GETS^DIQ(58.63,CABIEN_",",3,"I"} ^ ^ {,",3,"I","RESULT","ERROR") K DIERR} {,"RESULT","ERROR")} { ;*356} 64{ K DIERR S PSJPSYS=$$FIND1^DIC(58.} 64{ S PSJPSYS=$$FIND1^DIC(58.601,"","} ^ ^ {601,"","",PSJPSYS) K DIERR Q:'PSJP} {",PSJPSYS) Q:'PSJPSYS 0} {SYS 0 ;*356} 67{ K DIERR S PSJCAB=+$$FIND1^DIC(58.} 67{ S PSJCAB=+$$FIND1^DIC(58.63,,,PSJ} ^ ^ {63,,,PSJOMS("CABID")),PSJCAB("FICH} {OMS("CABID")),PSJCAB("FICHK",PSJCA} {K",PSJCAB)=PSJOMS("CABID") K DIERR} {B)=PSJOMS("CABID")} { ;*356} 68{ K DIERR D GETS^DIQ(58.63,PSJCAB,2} 68{ D GETS^DIQ(58.63,PSJCAB,2,"IE","P} ^ ^ {,"IE","PSJDIV") K DIERR ;*356} {SJDIV")} 275{ K DIERR,ERR S TMPADATA("SYS IEN")} 275{ S TMPADATA("SYS IEN")=$$FIND1^DIC} ^ ^ {=$$FIND1^DIC(58.601,"","MX",$G(TMP} {(58.601,"","MX",$G(TMPADATA(1)),,,} {ADATA(1)),,,"ERR") K DIERR ;*356} {"ERR")} 282{ K ERR,DIERR S TMPADATA("DEVICE IE} 282{ S TMPADATA("DEVICE IEN")=$$FIND1^} ^ ^ {N")=$$FIND1^DIC(58.63,,"BX",TMPADA} {DIC(58.63,,"MX",TMPADATA(2),,PSJSC} {TA(2),,PSJSCR,"ERR") K DIERR ;*356} {R,"ERR")} 302{ S TMPADATA("DRUG DEV IEN")=$$FIND} 302{ S TMPADATA("DRUG DEV IEN")=$$FIND} {1^DIC(58.60111,","_DEVIEN_","_SYSI} {1^DIC(58.60111,","_DEVIEN_","_SYSI} {EN_",","MXQ",DRUG,,,"ERR") K DIERR} {EN_",","MXQ",DRUG,,,"ERR")} { ;*356} 307{ K ERR,DIERR S TMPADATA("POCK/SUB } 307{ S TMPADATA("POCK/SUB IEN")=$$FIND} ^ ^ {IEN")=$$FIND1^DIC(58.601122,","_TM} {1^DIC(58.601122,","_TMPADATA("DRAW} {PADATA("DRAWER IEN")_","_TMPADATA(} {ER IEN")_","_TMPADATA("DEVICE IEN"} {"DEVICE IEN")_","_TMPADATA("SYS IE} {)_","_TMPADATA("SYS IEN")_",","MX"} {N")_",","MX",POCKSUB,,,"ERR") K DI} {,POCKSUB,,,"ERR")} {ERR ;*356} Routine: PSJPAD7I 2{ ;;5.0;INPATIENT MEDICATIONS ;**31} 2{ ;;5.0;INPATIENT MEDICATIONS ;**31} {7,356**;16 DEC 97;Build 7} {7**;16 DEC 97;Build 130} ^ ^ 160{ K PSJDIERR,DIERR D UPDATE^DIE(,"F} 160{ K PSJDIERR D UPDATE^DIE(,"FDA",""} ^ ^ {DA","","PSJDIERR") K DIERR ;*356} {,"PSJDIERR")} 193{ K DIERR,PSJERR2 S PSJPSYS=$$FIND1} 193{ S PSJPSYS=$$FIND1^DIC(58.601,,"BX} ^ ^ {^DIC(58.601,,"BX",$G(PSJOMS("DISPS} {",$G(PSJOMS("DISPSYS")),,,"PSJERR2} {YS")),,,"PSJERR2") K DIERR ;*356} {")} 194{ I '$G(PSJERR2("DIERR")) K DIERR,P} 194{ I '$G(PSJERR2("DIERR")) S PADEVIE} ^ ^ {SJERR2 S PADEVIEN=$$FIND1^DIC(58.6} {N=$$FIND1^DIC(58.63,,"BX",$G(PSJOM} {3,,"BX",$G(PSJOMS("CABID")),,,"PSJ} {S("CABID")),,,"PSJERR2")} {ERR2") K DIERR ;*356} 202{ K DIERR S PSJPSYS=$$FIND1^DIC(58.} 202{ S PSJPSYS=$$FIND1^DIC(58.601,"","} ^ ^ {601,"","",PSJPSYS) K DIERR Q:'PSJP} {",PSJPSYS) Q:'PSJPSYS ""} {SYS "" ;*356} 203{ K DIERR S CABIEN=$$FIND1^DIC(58.6} 203{ S CABIEN=$$FIND1^DIC(58.63,,,CABN} ^ ^ {3,,,CABNAME,,,"RESULT") K DIERR Q:} {AME,,,"RESULT") Q:'CABIEN ""} {'CABIEN "" ;*356} 205{ K DIERR D GETS^DIQ(58.63,CABIEN,2} 205{ D GETS^DIQ(58.63,CABIEN,2,"I","RE} ^ ^ {,"I","RESULT") K DIERR ;*356} {SULT")} Routine: PSJPADIT 2{ ;;5.0;INPATIENT MEDICATIONS ;**31} 2{ ;;5.0;INPATIENT MEDICATIONS ;**31} {7,356**;16 DEC 97;Build 7} {7**;16 DEC 97;Build 130} ^ ^ 3{ ;Per VHA Directive 2004-038, this} { routine should not be modified.} 47{ ;S PADATA(4)=$P($G(^PS(58.6,+$G(P} {S586IEN),0)),"^",3) ;UNCOMMENT THI} {S LINE IN TEST SYSTEM ONLY TO MOCK} { TEST CREATING AN INVENTORY UPDATE} { IN FILEMAN} 59{ I '$$FILDEV^PSJPADIU(.PADATA,.ERR} 57{ I '$$FILDEV(.PADATA,.ERR) S ERR="} ^ ^ {) S ERR="PADE DEVICE NOT UPDATED "} {PADE DEVICE NOT UPDATED "_ERR D LO} {_ERR D LOGERR(.ERR) Q} {GERR(.ERR) Q} 110{ K DIERR,ERR S PADATA("SYS IEN")=$} 108{ S PADATA("SYS IEN")=$$FIND1^DIC(5} ^ ^ {$FIND1^DIC(58.601,"","MXQ",$G(PADA} {8.601,"","MXQ",$G(PADATA(1)),,,"ER} {TA(1)),,,"ERR") K DIERR ;*356} {R")} 119{ D FILDEV^PSJPADIU(.PADATA)} 117{ D FILDEV(.PADATA)} ^ ^ 121{ ;} 122{FILDRWR(PADATA,ERRMSG) ; Add PADE } 119{FILDEV(PADATA,ERRMSG) ; File PADE } ^ ^ {Drawer to PADE System's DISPENSING} {DEVICE to PADE INVENTORY file} { DEVICE in PADE INVENTORY file} 120{ N FDA,PSJPSYS,PSJSCR,PSJSCR} 121{ I '($G(PADATA(2))]"") S ERRMSG="M} {ISSING PADE DEVICE" Q 0} 122{ I $G(PSJPSYS),$G(^PS(58.601,+PSJP} {SYS,0))]"" S PADATA("SYS IEN")=PSJ} {PSYS} 123{ S PSJPSYS=PADATA("SYS IEN"),PSJSC} {R="I $S('$G(PSJPSYS):1,1:PSJPSYS=$} {P(^(0),U,2))"} 124{ I ($G(PADATA(1))=""&$G(PSJPSYS)) } {S PADATA(1)=$P(^PS(58.601,PSJPSYS,} {0),"^")} 125{ S PADATA("DEVICE IEN")=$$FIND1^DI} {C(58.63,,"MX",PADATA(2),,PSJSCR,"E} {RR")} 126{ I '$G(PADATA("DEVICE IEN")) D} 127{ .N FDA S FDA(58.63,"?+1,",.01)=PA} {DATA(2)} 128{ .S FDA(58.63,"?+1,",1)=PADATA(1)} 129{ .S FDA(58.63,"?+1,",12)=$$UPPER^P} {SJPDRUT(PADATA(2))} 130{ .D UPDATE^DIE("E","FDA","","ERR")} 131{ .S PADATA("DEVICE IEN")=$$FIND1^D} {IC(58.63,,"MX",PADATA(2),,PSJSCR,"} {ERR")} 123{ I $G(PADATA(3))="" S PADATA(3)="z} 132{ I $G(PADATA("DEVICE IEN")) D} ^ ^ {z"} 133{ .N FDA S FDA(58.6011,"?+1,"_PADAT} {A("SYS IEN")_",",.01)=PADATA(2) D } {UPDATE^DIE("E","FDA","","ERR")} 124{ K ERR,DIERR S PADATA("DRAWER IEN"} 134{ .S PADATA("DEVICE IEN")=$$FIND1^D} ^ ^ {)=$$FIND1^DIC(58.60112,","_PADATA(} {IC(58.6011,","_PADATA("SYS IEN")_"} {"DEVICE IEN")_","_PADATA("SYS IEN"} {,","MX",PADATA(2),,,"ERR")} {)_",","MX",PADATA(3),,,"ERR") K DI} {ERR ;*356} 125{ I '$G(PADATA("DRAWER IEN")) D} 135{ I '$G(PADATA("DEVICE IEN")) S ERR} ^ ^ {MSG="Unable to file PADE Device "_} {PADATA(2) Q 0} 136{ Q 1} 137{ ;} 138{FILDRWR(PADATA,ERRMSG) ; Add PADE } {Drawer to PADE System's DISPENSING} { DEVICE in PADE INVENTORY file} 139{ I $G(PADATA(3))="" S PADATA(3)="z} {z"} 140{ S PADATA("DRAWER IEN")=$$FIND1^DI} {C(58.60112,","_PADATA("DEVICE IEN"} {)_","_PADATA("SYS IEN")_",","MX",P} {ADATA(3),,,"ERR")} 141{ I '$G(PADATA("DRAWER IEN")) D} 126{ .K FDA,ERR,DIERR S FDA(58.60112,"} 142{ .K FDA,ERR S FDA(58.60112,"?+1,"_} ^ ^ {?+1,"_+PADATA("DEVICE IEN")_","_+P} {+PADATA("DEVICE IEN")_","_+PADATA(} {ADATA("SYS IEN")_",",.01)=PADATA(3} {"SYS IEN")_",",.01)=PADATA(3) D UP} {) D UPDATE^DIE("E","FDA","","ERR")} {DATE^DIE("E","FDA","","ERR")} { K DIERR ;*356} 127{ .K ERR,DIERR S PADATA("DRAWER IEN} 143{ .S PADATA("DRAWER IEN")=$$FIND1^D} ^ ^ {")=$$FIND1^DIC(58.60112,","_PADATA} {IC(58.60112,","_PADATA("DEVICE IEN} {("DEVICE IEN")_","_PADATA("SYS IEN} {")_","_PADATA("SYS IEN")_",","MX",} {")_",","MX",PADATA(3),,,"ERR") K D} {PADATA(3),,,"ERR")} {IERR ;*356} 149{ K ERR,DIERR S PADATA("DRUG DEV IE} 165{ S PADATA("DRUG DEV IEN")=$$FIND1^} ^ ^ {N")=$$FIND1^DIC(58.60111,","_DEVIE} {DIC(58.60111,","_DEVIEN_","_SYSIEN} {N_","_SYSIEN_",","MXQ",DRUG,,,"ERR} {_",","MXQ",DRUG,,,"ERR")} {") K DIERR ;*356} 151{ .K ERR,DIERR S FDA(58.60111,"?+1,} 167{ .S FDA(58.60111,"?+1,"_+DEVIEN_",} ^ ^ {"_+DEVIEN_","_+SYSIEN_",",.01)=DRU} {"_+SYSIEN_",",.01)=DRUG D UPDATE^D} {G D UPDATE^DIE("E","FDA","ERR") K } {IE("E","FDA","ERR")} {DIERR ;*356} 152{ .K ERR,DIERR S PADATA("DRUG DEV I} 168{ .S PADATA("DRUG DEV IEN")=$$FIND1} ^ ^ {EN")=$$FIND1^DIC(58.60111,","_DEVI} {^DIC(58.60111,","_DEVIEN_","_SYSIE} {EN_","_SYSIEN_",","MXQ",DRUG,,,"ER} {N_",","MXQ",DRUG,,,"ERR")} {R") K DIERR ;*356} 153{ K ERR,DIERR S PADATA("DRUG DEV IE} 169{ S PADATA("DRUG DEV IEN")=$$FIND1^} ^ ^ {N")=$$FIND1^DIC(58.60111,","_DEVIE} {DIC(58.60111,","_DEVIEN_","_SYSIEN} {N_","_SYSIEN_",","MXQ",DRUG,,,"ERR} {_",","MXQ",DRUG,,,"ERR")} {") K DIERR ;*356} 159{ K ERR,DIERR S PADATA("DRUG IEN")=} 175{ S PADATA("DRUG IEN")=$$FIND1^DIC(} ^ ^ {$$FIND1^DIC(58.601121,","_PADATA("} {58.601121,","_PADATA("DRAWER IEN")} {DRAWER IEN")_","_PADATA("DEVICE IE} {_","_PADATA("DEVICE IEN")_","_PADA} {N")_","_PADATA("SYS IEN")_",","MXQ} {TA("SYS IEN")_",","MXQ",PADATA(4),} {",PADATA(4),,,"ERR") K DIERR ;*35} {,,"ERR")} {6} 161{ .S FDA(58.601121,"?+1,"_PADATA("D} 177{ .S FDA(58.601121,"?+1,"_PADATA("D} {RAWER IEN")_","_PADATA("DEVICE IEN} {RAWER IEN")_","_PADATA("DEVICE IEN} {")_","_PADATA("SYS IEN")_",",.01)=} {")_","_PADATA("SYS IEN")_",",.01)=} {PADATA(4) K ERR,DIERR D UPDATE^DIE} {PADATA(4) D UPDATE^DIE("","FDA",""} ^ ^ {("","FDA","","ERR") K DIERR ;*356} {,"ERR")} 162{ .K DIERR,ERR S PADATA("DRUG IEN")} 178{ .S PADATA("DRUG IEN")=$$FIND1^DIC} ^ ^ {=$$FIND1^DIC(58.601121,","_PADATA(} {(58.601121,","_PADATA("DRAWER IEN"} {"DRAWER IEN")_","_PADATA("DEVICE I} {)_","_PADATA("DEVICE IEN")_","_PAD} {EN")_","_PADATA("SYS IEN")_",","MX} {ATA("SYS IEN")_",","MXQ",PADATA(4)} {Q",PADATA(4),,,"ERR") K DIERR ;*35} {,,,"ERR")} {6} 168{ .K DIERR,ERR D FILE^DIE("","FDA",} 184{ .D FILE^DIE("","FDA","ERR")} ^ ^ {"ERR") K DIERR ;*356} 188{ N TRERR,FDA K DIERR S FDA(58.6011} 204{ N TRERR,FDA S FDA(58.60111,DBALIE} ^ ^ {1,DBALIENS,2)=BALANCE D FILE^DIE("} {NS,2)=BALANCE D FILE^DIE("","FDA",} {","FDA","TRERR") K DIERR ;*356} {"TRERR")} 196{ K DIERR,TRERR D FILE^DIE("","FDA"} 212{ D FILE^DIE("","FDA","TRERR")} ^ ^ {,"TRERR") K DIERR ;*356} 211{ K DIERR,ERR D FILE^DIE("","FDA","} 227{ D FILE^DIE("","FDA","ERR")} ^ ^ {ERR") K DIERR ;*356} 229{ K ERR,DIERR S PADATA("POCK/SUB IE} 245{ S PADATA("POCK/SUB IEN")=$$FIND1^} ^ ^ {N")=$$FIND1^DIC(58.601122,","_PADA} {DIC(58.601122,","_PADATA("DRAWER I} {TA("DRAWER IEN")_","_PADATA("DEVIC} {EN")_","_PADATA("DEVICE IEN")_","_} {E IEN")_","_PADATA("SYS IEN")_",",} {PADATA("SYS IEN")_",","MX",POCKSUB} {"MX",POCKSUB,,,"ERR") K DIERR ;*35} {,,,"ERR")} {6} 239{ .S FDA(58.601122,"?+1,"_PADATA("D} 255{ .S FDA(58.601122,"?+1,"_PADATA("D} {RAWER IEN")_","_PADATA("DEVICE IEN} {RAWER IEN")_","_PADATA("DEVICE IEN} {")_","_PADATA("SYS IEN")_",",.01)=} {")_","_PADATA("SYS IEN")_",",.01)=} {POCKSUB K DIERR,ERR D UPDATE^DIE("} {POCKSUB D UPDATE^DIE("","FDA","","} ^ ^ {","FDA","","ERR") K DIERR ;*356} {ERR")} 240{ .K ERR,DIERR S PADATA("POCK/SUB I} 256{ .S PADATA("POCK/SUB IEN")=$$FIND1} ^ ^ {EN")=$$FIND1^DIC(58.601122,","_PAD} {^DIC(58.601122,","_PADATA("DRAWER } {ATA("DRAWER IEN")_","_PADATA("DEVI} {IEN")_","_PADATA("DEVICE IEN")_","} {CE IEN")_","_PADATA("SYS IEN")_","} {_PADATA("SYS IEN")_",","MX",POCKSU} {,"MX",POCKSUB,,,"ERR") K DIERR ;*3} {B,,,"ERR")} {56} 248{ .K ERR,DIERR D FILE^DIE("","FDA",} 264{ .D FILE^DIE("","FDA","ERR")} ^ ^ {"ERR") K DIERR ;*356} 252{ ..K DIERR,ERR D UPDATE^DIE("","FD} 268{ ..D UPDATE^DIE("","FDA","","ERR")} ^ ^ {A","","ERR") K DIERR ;*356} 253{ .K DIERR,ERR S PSPRVDIE=$$FIND1^D} 269{ .S PSPRVDIE=$$FIND1^DIC(58.601123} ^ ^ {IC(58.601123,","_PADATA("DRAWER IE} {,","_PADATA("DRAWER IEN")_","_PADA} {N")_","_PADATA("DEVICE IEN")_","_P} {TA("DEVICE IEN")_","_PADATA("SYS I} {ADATA("SYS IEN")_",","MX",POCKSUB,} {EN")_",","MX",POCKSUB,,,"ERR")} {,,"ERR") K DIERR ;*356} 257{ ..K DIERR,ERR D FILE^DIE("","FDA"} 273{ ..D FILE^DIE("","FDA","ERR")} ^ ^ {,"ERR") K DIERR ;*356} 285{ K DIERR,ERR D FILE^DIE("","FDA","} 301{ D FILE^DIE("","FDA","ERR")} ^ ^ {ERR") K DIERR ;*356} 294{ K DIERR,ERROR D GETS^DIQ(58.6,PS5} 310{ D GETS^DIQ(58.6,PS586IEN_",","4;1} ^ ^ {86IEN_",","4;15","","RESULT","ERRO} {5","","RESULT","ERROR")} {R") K DIERR ;*356} *ADD* Routine: PSJPADIU
It should be obvious upon quick inspection that the ^ shows where a difference between lines starts. Also, if you see *ADD* or *DELETE*, it means something is new or is being deleted.
This is a colossally misnamed option: This option does not -- as it name suggests -- back up the KIDS build you are currently installing; rather it backs up the current state of the system -- but only the routines -- in order for you to be able to recover your old code in case the code the KIDS build brings in is bad. Note that all the other changes that a KIDS build performs are not reversed, including any data conversion. Some developers write an "undo" utility for big patches that perform data conversion; but that's more of the exception rather than the rule.
Here's an example:
Select Installation Option: 5 Backup a Transport Global Select INSTALL NAME: <spacebar><enter> PSJ*5.0*356 Loaded from Distribution 12/25/18@14: 01:15 => Extracted from mail message ;Created on This Distribution was loaded on Dec 25, 2018@14:01:15 with header of Extracted from mail message ;Created on It consisted of the following Install(s): PSJ*5.0*356 Subject: Backup of PSJ*5.0*356 install on Dec 25, 2018 Replace Loading Routines for PSJ*5.0*356... Routine PSJPADIU is not on the disk.. Send mail to: 사용자,하나// `1 사용자,하나 Select basket to send to: IN//<enter> And Send to:<enter>
This is the option that finally installs the loaded KIDS build into the system. You are typically asked a few questions, most of which you can accept the defaults to. The questions you typically see are as follows:
You should normally say "No", which is the default, for these questions. There are reasons to say yes, but they are rare. Also, the developer will change the default from No to Yes if the question needs to be answered as a yes.
$$ACCESS^XQCHK
.Another question that you may see is an entry of a Mail Group Coordinator for new mail groups. If you are not doing this install at a production site, or don't know your package coordinator, you should put POSTMASTER
.
Developers are free to add their own questions, and you may see them; but these are comparatively rare.
Before the install starts, you will be prompted for DEVICE: HOME//
. Regrettably, KIDS tries to be helpful when you accept the default of "HOME" and paints a user friendly screen showing you an progress indicator. The problem is that this hides any compilation errors or possibly any other errors. Therefore, unless you are just the recipient of a KIDS build that will "just work", you should enter ;P-OTHER;
into that prompt in order to get regular roll & scroll output.
Here's an example install, using the same build we have been using so far in this section:
Select Installation Option: 6 Install Package(s) Select INSTALL NAME: <spacebar><enter> PSJ*5.0*356 Loaded from Distribution 12/25/18@14: 01:15 => Extracted from mail message ;Created on This Distribution was loaded on Dec 25, 2018@14:01:15 with header of Extracted from mail message ;Created on It consisted of the following Install(s): PSJ*5.0*356 Checking Install for Package PSJ*5.0*356 Install Questions for PSJ*5.0*356 Want KIDS to INHIBIT LOGONs during the install? NO//<enter> Want to DISABLE Scheduled Options, Menu Options, and Protocols? NO//<enter> Enter the Device you want to print the Install messages. You can queue the install by enter a 'Q' at the device prompt. Enter a '^' to abort the install. DEVICE: HOME// ;p-other; CONSOLE Install Started for PSJ*5.0*356 : Dec 25, 2018@15:29:50 Build Distribution Date: Mar 22, 2018 Installing Routines:..... Dec 25, 2018@15:29:50 Updating Routine file...... Updating KIDS files....... PSJ*5.0*356 Installed. Dec 25, 2018@15:29:50 Not a VA primary domain NO Install Message sent
And that's it for installation a patch. By the way, in the VA, an email message will be sent to a central system called "FORUM" to indicate that the patch was installed.
Here are some quick tips for dealing with KIDS builds that don't load or didn't fully go in. If a crash happens, you probably need to know some M code in order to be able to diagnose what is happening.
Restart Install of Package(s)
.^XTMP("XPDI",{install #})
.Unload a Distribution
.Utilities > Edit Install Status
.As soon as you install a new VistA system, it starts to become out of date, as new features are always being continuously released. Most of the patches come out of the VA; and so we will focus here on patching up using the VA patch stream. If there are community patches, you need to check with their authors if they may collide with VA patches. Frequently, vendors or vendor like organizations will provide you with an "overlay" patch that undoes all the overwritten changes that were due to installing the VA patch stream. Here are the steps for patching up an old system.
The best way I have found of doing this is printing a listing of KIDS installs from Fileman in reverse chronological order, and figuring which which VA patches got installed. The file where that data resides is (appropriately enough) called INSTALL
. Here's a sample of how I can do that. Note that I am using INSTALL START TIME
as the field to reverse sort (- means reverse sort) in one print but the DISTRIBUTION DATE
in the next print. The field DISTRIBUTION DATE
is far more accurate as it gives you the date the KIDS build was produced in the VA; not the date it was installed on your system.
FOIA201805>S DUZ=1 FOIA201805>D P^DI MSC FileMan 22.1060 Select OPTION: PRINT FILE ENTRIES Output from what File: INSTALL// INSTALL (10451 entries) Sort by: NAME// -INSTALL START TIME Start with INSTALL START TIME: FIRST//<enter> Within INSTALL START TIME, Sort by:<enter> First Print FIELD: NAME Then Print FIELD: INSTALL START TIME Then Print FIELD:<enter> Heading (S/C): INSTALL List//<enter> DEVICE: HOME//<enter>
Here's the output by INSTALL START TIME
, which normally isn't useful.
INSTALL List DEC 25,2018@17:52 PAGE 1
NAME INSTALL START TIME
--------------------------------------------------------------------------------
PSJ*5.0*356 DEC 25,2018@15:29:50
GMRV*5.0*37 DEC 22,2018@12:02:36
XPD*8.0*11310 NOV 7,2018@15:54:10
XOBW*1.0*10001 SEP 25,2018@09:53:32
XT*7.3*101 SEP 10,2018@14:13:42
KMP*4.0*0 JUN 16,2018@10:46:19
XU*8.0*670 JUN 16,2018@10:46:18
VFD*15.0*103 MAY 29,2018@09:26:52
MASH*1.5*0 MAY 14,2018@11:29:19
LBR*2.5*15 APR 3,2018@17:45:36
EC*2.0*141 APR 3,2018@17:44:55
PSO*7.0*513 APR 3,2018@17:43:42
PSX PSO BUNDLE 1.0 APR 3,2018@17:43:41
PSX*2.0*83 APR 3,2018@17:43:41
PSO*7.0*504 APR 3,2018@17:40:02
SD*5.3*680 APR 3,2018@17:39:08
And here's the output by DISTRIBUTION DATE
:
INSTALL List DEC 25,2018@17:53 PAGE 1
DISTRIBUTION
NAME DATE
--------------------------------------------------------------------------------
XOBW*1.0*10001 APR 4,2018
PSJ*5.0*356 MAR 22,2018
XU*8.0*670 MAR 21,2018
KMP*4.0*0 MAR 21,2018
SD*5.3*677 MAR 5,2018
EC*2.0*140 MAR 5,2018
PSO*7.0*504 FEB 26,2018
GMRC*3.0*92 FEB 15,2018
MAG*3.0*196 FEB 12,2018
IB*2.0*597 FEB 9,2018
PSJ*5.0*355 FEB 8,2018
LA*5.2*96 FEB 7,2018
LR*5.2*502 FEB 1,2018
IB*2.0*601 FEB 1,2018
PSO*7.0*515 JAN 31,2018
From the listing in distribution dates, I am probably patched up to April 2018 (patches distributed in March are probably going to be released in April). That gives me an idea of where to start looking.
There are several ways to figure out what patches you need to install. One of the easier ways is that there are spreadsheets of what patches are released in which order, which you can currently find here. Since I am missing patches since April 2018, and I am writing this in December 2018, I would look at the spreadsheet for 2018.
Comparing the patches using the INSTALL START DATE
listing, and comparing it to the Excel Sheet, I can detect that the last patch I installed was LBR*2.5*15
.
That means that there are 484-157 = 327 patches to install. Now you can understand why we need an automated installer--we have to install 327 patches to keep VistA up to date; and that's for less than one year. In reality, the number is slightly smaller, as not all patches are installable, and many patches are either "entered in error" or not releasable to the public.
You can now use the same spreadsheet to figure out which patches you need to install.
The best way to download patches for a specific month is to go to the Releases by Year and Month page. Once you are there, you can download all the patches by a specific month, dos2unix them.
You should probably install a month at a time.
If you are a client of a vendor/organization, you will be given an overlay to apply. If you are doing this on your own, you will need to create the overlay yourself. The overlay will usually contain the following items:
One of the biggest challenges (if not the biggest) for people using VistA is keeping it up to date. With 300-500 KIDS patches per year, it's hard to keep VistA up to date. If you are an organizational client of a VistA distribution (like WorldVistA or vxVistA), you may get Multibuilds of all the patches. This reduces the number of installs you have to do from 400 to about 30 per year. But these organizations that produce the Multibuilds have to go through this process in order to make the Multibuilds.
Besides that, there are two other projects, one of which is in active use.
OSEHRA created an autopatcher, which is a set of python expect scripts that automate all of what we discussed above. It is not designed for production environments. You can find instructions on using it here. OSEHRA has had good results using it, but you need to be aware of the limitations:
You can find this here. It's a promising project, and I think the right direction for VistA, but it was never fully pursued.
Based on what we discussed above, and based on our experience with systems like apt
, dnf
, and pacman
, we want the following features: