TN0090

Guidelines for Product Maintainers:
How to Write a Table File for
'Privileged Product' Installations

CD/OSS
Applications Support


If a product has things that must be done as 'root' when it is installed, the following conventions should be followed:

  1. the 'configure' and 'current' (and any other chain-type actions) SHOULD NOT perform the privileged steps. Instead, they should issue messages stating that an additional step is necessary.

  2. The table file should contain
    	action=installAsRoot
    		# privileged stuff here
    
    You can tell users that they should log in as root and issue the command
    	$ ups installAsRoot <product> <version>
    

  3. OR, for more complicated products (like kerberos), the table file could contain
    	action=installAsRoot
    		# just a magic keyword
    
    which is called from separate stanzas (all with different actions):
    	action=doMyThing
    	   exeActionRequired( installAsRoot )
    	   # MyThing goes here
    
    	action=doYourThing
    	   exeActionRequired( installAsRoot )
    	   # YourThing goes here
    
    Then tell users to issue the command
    	$ ups doMyThing <product> <version>
    
    or
    	$ ups doYourThing <product> <version>
    

  4. Be aware that this is (at present) only a convention. You should perform your own tests to make sure the user is able to perform the necessary functions. (Eventually, this intelligence will be added to ups).

    In other words, a non-privileged user who would otherwise be able to install products should ALWAYS be able to:
    $ upd install <product> <version> # or ftp the files and
    # unwind them manually as an unprivileged user
    $ ups declare <product> <version> <-g chain> # this implies 'ups configure' and/or
    # 'ups <chain>' for whatever chain
    # has been requested, e.g.,
    # 'ups current' or 'ups test'
    $ su root
    $ . /usr/local/etc/setups.sh
    # or 'source /usr/local/etc/setups.csh'
    $ ups installAsRoot <product> <version>
    # this step may be done at a later time;
    # (replace /usr/local/etc with the appropriate path
    #    to $SETUPS_DIR on each system);
    # (or a similar type of 'ups install' command)

    Note that the product will probably not function properly until the user has performed the final step as 'root'. In many cases, this step may need to be taken on each node in a cluster; this should be noted in the documentation (INSTALL_NOTE, etc.) as well as in the message issued during product configuration.


    Sample Table File:

    The following sample table file may be used as an example. After the sample table file, each stanza is discussed.

    File=Table
    Product=SampleProduct
    
    Group:
    Flavor=ANY
    Qualifiers=""
    
    Common:
       Action=setup
    	prodDir()
    	setupEnv()
    	pathPrepend(PATH, ${UPS_PROD_DIR}/bin)
    
       Action=configure
    	execute( echo "You must login in as root and issue the command", N0_UPS_ENV )
    	execute( echo "     ups installAsRoot ${UPS_PROD_NAME} ${UPS_PROD_VERSION}", NO_UPS_ENV )
    	execute( echo "on each node of the cluster to finish the installation.", NO_UPS_ENV )
    
       Action=current
    	exeActionRequired( configure )
    
       Action=installAsRoot
    	execute( echo "Now performing privileged tasks...", NO_UPS_ENV )
    	execute( ${UPS_UPS_DIR}/installScript, UPS_ENV )
    End:
    

    Discussion:

    Action=setup:
    This is a typical setup stanza, nothing new. It sets the $SAMPLEPRODUCT_DIR and $SETUP_SAMPLEPRODUCT environmental variables, and adds $SAMPLEPRODUCT_DIR/bin to the front of the user's path.

    Action=configure:
    The configure action issues an informational message to the product installer, informing them that an additional step (ups installAsRoot) must be taken. (Note that 'ups configure' happens automatically the first time a product is declared to a ups database; therefore, this stanza should never contain instructions which should be executed as 'root').

    Action=current:
    The current action calls the 'configure' action; in this way, the product developer needs to maintain the correct message in only one place. The current action does not perform the privileged action. (Note that 'ups current' happens when the product is chained as current; therefore, this stanza should never contain instructions which should be executed as 'root').

    Action=installAsRoot:
    The installAsRoot action is where the privileged instructions take place (in this case, by running the script $SAMPLEPRODUCT_DIR/ups/installScript). This will not happen automatically when the product is declared to a ups database or when the product is chained; the product installer must enter the command manually. Therefore, a non-privileged user (e.g., ~products) may perform the 'upd install -G -c' command without crashing, and perform the subsequent privileged operations as 'root'.


    A More Complicated Table File:

    File=Table
    Product=SomeOptions
    
    Group:
    Flavor=ANY
    Qualifiers=""
    
    Common:
    
       Action=issueMessage
    	execute( echo "", NO_UPS_ENV )
    	execute( echo "You must log in as 'root' and issue", NO_UPS_ENV )
    	execute( echo "one of the following commands in", NO_UPS_ENV )
    	execute( echo "order to finish the installation.", NO_UPS_ENV )
    	execute( echo "Please select the appropriate option", NO_UPS_ENV )
    	execute( echo "for your site:", NO_UPS_ENV )
    	execute( echo "", NO_UPS_ENV )
    	execute( echo "  1) Option 1: description of option 1", NO_UPS_ENV )
    	execute( echo "     goes here.  If you want to install", NO_UPS_ENV )
    	execute( echo "     this option, log in as root and", NO_UPS_ENV )
    	execute( echo "     issue the command", NO_UPS_ENV )
    	execute( echo "        $ ups opt1 ${UPS_PROD_NAME} ${UPS_PROD_VERSION}", NO_UPS_ENV )
    	execute( echo "  2) Option 2: description of option 2", NO_UPS_ENV )
    	execute( echo "     goes here.  If you want to install", NO_UPS_ENV )
    	execute( echo "     this option, log in as root and", NO_UPS_ENV )
    	execute( echo "     issue the command", NO_UPS_ENV )
    	execute( echo "        $ ups opt2 ${UPS_PROD_NAME} ${UPS_PROD_VERSION}", NO_UPS_ENV )
    	execute( echo "", NO_UPS_ENV )
    
       Action=configure
    	exeActionRequired( issueMessage )
    
       Action=current
    	exeActionRequired( issueMessage )
    
       Action=installAsRoot
    	
       Action=opt1
    	exeActionRequired( installAsRoot )
    	execute( echo "Now performing 'ups opt1' actions.", NO_UPS_ENV )
    	execute( "${UPS_UPS_DIR}/installScript opt1", UPS_ENV )
    
       Action=opt2
    	exeActionRequired( installAsRoot )
    	execute( echo "Now performing 'ups opt2' actions.", NO_UPS_ENV )
    	execute( "${UPS_UPS_DIR}/installScript opt2", UPS_ENV )
    
    End:
    

    Discussion:

    Action=configure:, Action=current
    These just call a user-defined action issueMessage, which tells the product installer about all of the installation options.

    Action=opt1, Action=opt2
    These call the installAsRoot action to indicate that the user must be 'root', then go on to perform whatever installation steps are necessary. Note, at the present time the installAsRoot action does not perform any checking to ensure that you actually are 'root'. The installScript should perform checking if necessary.


    Background


    From the FUE meeting, 21 January 2000

    The Problem We Are Trying To Solve:
    How to know ahead of time that you need to be 'root' when you install a product in order for it to be fully functional and/or to not get annoying error messages during installation?

    For OSS and UAS, this is no longer a theoretical problem that can be put off. The success of the ups/upd rewrite and the bootstrap product has meant that many more system utilities (ssh, tcp_wrappers, kerberos, 90?) are installed via upd. (The problem of knowing when to be root and what to do was one of the reasons why system utilities were not generally packaged as ups products before).

    Product installers need to be able to successfully "do the right thing" -- be root when necessary, and not otherwise.

    The BEST solution: (proposed by Eileen Berman and Margaret Votava, (unable to attend the meeting), and aptly defended by Cindy Wike:
    Add a new table file function mustBeUser('root'). We are all in agreement that, given time and resources, this would be the best solution technically and aesthetically.

    The PROBLEM with this solution is:
    Nobody could begin to use the mustBeUser function in a table file until everybody had upgraded to the new [not yet written] version of ups that contains this feature. It is NOT backwards compatible with existing ups installations.

    The COMPROMISE solution:
    Instead of implementing a new table file function, teach ups about one new action: installAsRoot.

    The BENEFIT of this solution is:
    We can implement this now, today, using no new tools. Until ups is taught to recognize the new action it will be only a convention -- but a convention with teeth in it that we all agree is a Good Convention. It is backwards compatible -- you don't get the benefit of "additional intelligence" in ups until you upgrade to the new [not yet written] version of ups that contains this feature -- but you can still install the product. It doesn't break existing systems.


    This document was created in January 2000 by llc.