Skip to end of metadata
Go to start of metadata

Grouper 2.5.0 will require running in the InCommon Trusted Access Platform (ITAP) container in Feb 2020.

  • The intent is to make sure everyone has a consistent directory structure, the correct version of libraries, successful and correct upgrades
  • The intent is not to make sure everyone runs the ideal container deployment with orchestration etc.
    • However, we do want people to do this, but its not required for use of the container
  • Institutions running Grouper will install/deploy/upgrade with the ITAP container, not from the installer.  Patches do not exist anymore for 2.5
    • The installer will have a command to get started with the container
  • No more tarballs for Grouper
    • Jars for Grouper are in Maven.  The same jars in the container are in Maven.  The container is built from jars in Maven.

Child pages:

Container

The ITAP container for 2.5 will have some changes compared to 2.4.  The version will be 2.5.X (X is a number.  not patch level for API/UI/etc.

Everything in Grouper is in one directory.  The daemon runs from the webapp.  You should run either UI or WS or daemon or GSH or SCIM, but you can run more than one or all at once if you like

packagingContainerStructure

Container maturity level 0

If an institution does not have experience with running containers, Grouper can easily be run without orchestration or other best practices of using containers.  The institution can run the Grouper container before developing their container standards and practices

Note, in production they would run this setup (or multiple) for the UI, run another instance (or multiple) for WS.  This is an example webapp

packagingContainerMaturity0



This is an example daemon maturity level 0.  In each maturity level, the daemon is the same as the webapp (ui or ws), just doesnt need web requests.  Note there is no HTTP here, though you could use it with the status servlet if you like....

packagingContainerDaemonMaturity0

Getting started with Grouper, use the installer:

  1. Walks through setting up the database
  2. Sets up config files on server
  3. Configures logging on server
  4. Verifies and advises on installing docker / podman
  5. Creates a start script
  6. Ensures there is a service script so Grouper starts on server startup
  7. Helps with networking and ports
  8. Documentation on how to SSH into container
  9. Advises about containers for WS/UI/daemon/GSH

Container maturity level 1

Keep your configs in source control, have an institution Dockerfile and sub-container

packagingContainerMaturity1

Container maturity level 2

Make the container not dependent on server that runs it.  In this case we need a solution for passwords and logs

packagingContainerMaturity2

Container maturity level 3

Use container orchestration

packagingContainerMaturity4


Design

Design goals

  • Support various levels of maturity for containers (including institutions with no experience)
  • Give guidance on how to evolve containerization so best practices are followed
  • Support a quick start
  • Share experience / configuration with various
    • Add deployment recipes for various public cloud infra
  • Provide a very easy path to go from tomcat or tomcat/apache to ITAP container

Suggested changes

  • Only support containerized deployments
  • Grouper in 2.5 will live in one directory in one container: /opt/grouper/grouperWebapp
    • In Grouper 2.4 there were 4 directories: ws, ui, daemon, scim
    • All code and libraries for all features of grouper will be in this one place
  • A switch by command line or grouper-hibernate.properties will tell the container if it is a UI/WS/daemon/GSH, or it can be multiple
    • You can fire up GSH from any container
  • The grouper hibernate and morph params can be passed from env variable or params to container
    • db url, db user, db pass, morph pass
    • the passes can be paths of external files
    • the db pass can be encrypted
    • the entire "conf" directory can be mounted externally
    • the log directory can me mounted outside the container
    • any overlay can be attached to the webapp from /opt/optOverlay
      • for instance, to overlay the grouper.properties, put a file in /opt/containerRootOverlay/opt/grouper/grouperWebapp/WEB-INF/classes/grouper.properties
  • So... to convert from tomcat to container:
    • Install docker
    • Run the ITAP base container with no changes and no dockerfile
    • Pass in if WS/UI/daemon
    • Either put configs in the database or external mount the conf dir
    • Configure logging to log to mounted external file.  Do this by mounting the conf dir, and configure the log4j.properties to log to external
    • For the bootstrap (DB config), pass in or keep in mounted external files the db and morph creds (passwords should be in files)
    • Map the ports so everything works
      • Could be the apache port or tomcat port
  • After that, the institution can at their own pace
    • Use a password manager
    • Put logs somewhere else besides host server
    • Github/gitlab
    • Continuous integration
    • Use orchestration
    • Run in cloud
    • Whatever else we recommend

Tasks

  1. Proof of concept running daemon/ui/ws in one directory
    1. Build the Grouper webapp with WS and UI in one webapp. 
    2. Put all libs in there, all configs, and merge the web.xml's
    3. Run the UI and WS 
    4. Run the daemon, it should work, but just make sure
    5. Add the scim stuff to that one directory.  Can tomcat read it for WS/UI/daemon, and tomee read it for SCIM?  Maybe need dynamic web.xml (only loads scim servlet if env var is set or something)?
    6. Remove web.xml, do basic auth in filter, look at kerberos WsGrouperKerberosAuthentication
  2. Simplify builds of projects
    1. No more tarballs
    2. Remove jar only of installer (will be tarball)
      1. Merge installer with client?
      2. Disable installer if in container for security reasons?
    3. Each project in git should have all dependent jars and a simple (similar) pom.xml to build the project and optionally the tarball
      1. Maven will be used to build jars and publish to maven
      2. Remove extraneous stuff (almost all stuff) from build.xml
    4. Installer when installing should not need to run any builds from maven, it should just download files from maven and copy files around
  3. UI and WS should have dynamic web.xml configuration
    1. put a config item in grouper hibernate properties (since its not in database), with three switches
      1. grouper.is.ui = true|false
      2. grouper.is.ui.basicAuthn = true|false
      3. grouper.is.ws = true|false
      4. grouper.is.ws.basicAuthn = true|false
      5. grouper.is.scim = true|false
      6. grouper.is.scim.basicAuthn = true|false
      7. grouper.is.daemon = true|false
    2. Blank out the web.xml in UI and WS except for the listener or whatever minimal is required.  Both should be the exact same
      1. https://javadeveloperszone.wordpress.com/tag/programmatically-adding-servlet-and-filter/
    3. Based on that config in grouper hibernate properties, can the web.xml be dynamically configured to add the servlets and filters and security constraints based on config? 
      1. The basic auth security constraint can be added from grouper-ui.properties or grouper-ws.properties, and be selective for if ui or ws
      2. Make sure Grouper fails in any UI call (in existing filter?) if grouper.is.ui is false
      3. Make sure Grouper fails in any WS call (in existing filter?) if grouper.is.ws is false
      4. Have the daemon fail (in startup method) if grouper.is.daemon is false
    4. Have a grouper.properties switch that defaults to true (throw exceptions), that says "fail if servlet class not found", dont load classes (try/catch)
  4. The UI/WS/scim should check the url to make sure its ok (based on configuration which defaults to be strict)
    1. configuration to see if this feature is on, default to true
    2. e.g. /grouper/servicesRest and /grouper/v2 and /grouper/services should be an error (/grouper is configurable in the grouper-ui config)
    3. e.g. /grouper-ws/grouperUi and /grouper-ws/v2 should be an error (/grouperWs is configurable in the grouper-ws config)
    4. e.g. /grouper-ws-scim/grouperUi and /grouper-ws-scim/services and /grouper-ws-scim/servicesRest should be an error (/grouper-ws-scim is configurable in the grouper-ws config)

      Apache will do this and invalid requests wont be forwarded

      ReverseProxy   443   /grouper/grouperUi -> 8080 /grouper/grouperUi
      ReverseProxy   443   /grouper/status -> 8080 /grouper/status
      ReverseProxy   443   /grouper-ws/status -> 8080 /grouper/status
      ReverseProxy   443   /grouper-ws/servicesRest -> 8080 /grouper/servicesRest
      ReverseProxy   443   /grouper-ws/services -> 8080 /grouper/services
      ReverseProxy   443   /grouper-ws-scim/v2 -> 8080 /grouper/v2
      ReverseProxy   443   /grouper-ws-scim/status -> 8080 /grouper/status


      TODO (after 2.5), allow daemon nodes to have HTTP status servlet

  5. The daemon (if the daemon switch is on), should run inside of tomee, not only from: gsh.sh -loader
    1. Note, the loader should still be able to be kicked off from gsh.sh -loader, though we wont do that in the container
    2. In the J2EE config, see if hibernate properties is loader, and if so, run GrouperLoader.main(new String[]{}), in a new thread
  6. Update the installer (discuss with Chris first) to build container (grouper devs or chris hubing)
    1. It should ask similar questions, but without redundancies (few questions)
    2. Assume everything is checked out from git
    3. Find version in local filesystem (figure that out)
    4. Download grouper and 3rd party jars from maven (use ant-maven plugin or maven command line to get maven jars from an ant script)
    5. Build these uber webapp
  7. Container changes
    1. Remove the morph config file, and read morph secret from grouper hibernate properties instead.  Note it can also be in the grouper.client.properties (as it is now).  Cant be in multiple places if same (Hyzer)
      1. The grouper hibernate properties is the one file not in the database, and has everything needed to start grouper (Hyzer)
    2. Be able to run the container by mounting the conf directory from a mounted external directory (Hubing)
      1. This is a directory on the server outside of the container (Hubing)
    3. The default container should have configs that will work without mounting externally (Hubing)
      1. Should have 8 variables for morph secret, database user/url/pass, and if ui/ws/daemon, log directory base (can be mounted outside)
        1. https://stackoverflow.com/questions/2975289/log4j-relative-file-path
      2. The container should take empty directory /slashRoot and copy the contents onto "/", and the slashRoot should be able to be mounted externally (Hubing)
    4. Maturity level 0 is just start container with some switches (NA)
    5. Level 1 is mount external conf/ dir and go from there (log4j should be able to log to externally mounted directory) (Hyzer)
    6. Do a POC on RHEL 8 with podman: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/building_running_and_managing_containers/index#running-containers-without-docker_building-running-and-managing-containers (Later)
  8. Installer mode for installing container
    1. Ask questions similar to current install. Mode is installContainer just like buildContainer in GrouperInstaller.java.
    2. Suggest latest container. Get the version out of META-INF and if not from there, get it from the property file.
    3. Detect if docker installed and if yes, just print out that docker is installed and if not, print the instructions to setup docker. they are at: Install the Grouper 2.4 container with maturity level 0#Installdocker
      1. ask user to hit enter when done. On enter, confirm that docker is installed. 
      2. If RHEL 8 (or whatever), use "podman" as a substitute (Later)
      3. For the following, print the first three commands and users should run them if docker not already installed and running. To see if it's running, run `/sbin/service docker status`. try/catch everything and keep going. For the fourth command, grouperInstaller should just run it. throw exception if failed but keep going. 
      4. [root @ip - 172 - 30 - 0 - 157   ~]# /sbin/service docker start
        Redirecting to /bin/systemctl start docker.service
        [root @ip - 172 - 30 - 0 - 157   ~]# systemctl enable docker
        [root @ip - 172 - 30 - 0 - 157   ~]# docker pull tier/grouper: 2.5.x

    4. Ask user where the external mounted directory is and the default should be /opt/grouperMount
    5. Ask about database
      1. Make a grouper.hibernate.properties in the path of wherever the external mounted directory is </opt/grouperMount>/conf/grouper.hibernate.properties

        ########################################
        ## DB settings
        ########################################
        
        # e.g. mysql:           jdbc:mysql://localhost:3306/grouper?useSSL=false
        # e.g. p6spy (log sql): [use the URL that your DB requires]
        # e.g. oracle:          jdbc:oracle:thin:@server.school.edu:1521:sid
        # e.g. hsqldb (a):      jdbc:hsqldb:dist/run/grouper;create=true
        # e.g. hsqldb (b):      jdbc:hsqldb:hsql://localhost:9001/grouper
        # e.g. postgres:        jdbc:postgresql://localhost:5432/database
        # e.g. mssql:           jdbc:sqlserver://localhost:3280;databaseName=grouper
        hibernate.connection.url = jdbc:hsqldb:hsql://localhost:9001/grouper
        
        hibernate.connection.username         = sa
        # If you are using an empty password, depending upon your version of
        # Java and Ant you may need to specify a password of "".
        # Note: you can keep passwords external and encrypted: https://bugs.internet2.edu/jira/browse/GRP-122
        hibernate.connection.password         = <MORPH_ENCRYPTED_PASSWORD>
        
        #######################################
        grouper.is.ui=${java.lang.System.getenv().get('GROUPER_UI')}
        grouper.is.ws=${java.lang.System.getenv().get('GROUPER_WS')}
        grouper.is.scim==${java.lang.System.getenv().get('GROUPER_SCIM')}
        grouper.is.daemon==${java.lang.System.getenv().get('GROUPER_DAEMON')}
        grouper.is.ui.basicAuthn=true
        grouper.is.ws.basicAuthn=true
        grouper.is.scim.basicAuthn=true
        
        
    6. Ask for a morphString password and make a morphString.properties: </opt/grouperMount>/conf/morphString.properties
    7. Ask about initting it (do you want to init it?)   (add this in the README.txt), installer doing this on the user's behalf)

      docker run --detach \
         --mount type=bind,src=</opt/grouperMount>/conf,dst=/opt/grouper/conf \
         --mount type=bind,src=</opt/grouperMount>/logs,dst=/opt/grouper/logs \
         --mount type=bind,src=</opt/grouperMount>/slashRoot=/opt/grouper/slashRoot \
         --name gsh \
         --entrypoint /opt/grouper/grouperWebapp/WEB-INF/bin/gsh \
         tier/grouper:2.5.x \
         -registry -check -runscript -noprompt
    8. Ask about GrouperSystem password and then save it in the grouper_password table via that Authentication class we wrote. Refer to 

      addGrouperSystemWsGroup in GrouperInstaller.java. Make gsh script file which is inside the container in /opt/grouperMount/slashRoot/opt/grouper/grouperWebapp/WEB-INF/bin/createGrouperSystemPassword.gsh. 

      docker run --detach \
         --mount type=bind,src=</opt/grouperMount>/conf,dst=/opt/grouper/conf \
         --mount type=bind,src=</opt/grouperMount>/logs,dst=/opt/grouper/logs \
         --mount type=bind,src=</opt/grouperMount>/slashRoot=/opt/grouper/slashRoot \
         --name gsh \
         --entrypoint /opt/grouper/grouperWebapp/WEB-INF/bin/gsh \
         tier/grouper:2.5.x \
         /opt/grouper/grouperWebapp/WEB-INF/bin/createGrouperSystemPassword.gsh



    9. Ask about external apache (Later)
    10. Ask if want Dockerfile changes (maturity level 2?) (Later)
    11. There are a few arguments you can pass to the container, and env vars...   Note the command if specified (optional) will set env vars before the env vars.  So you could call the container with "ui" but then specify that -e RUN_SHIB_SP='false'   (e.g. if you run CAS)

      ArgumentDescription
      ui

      will set env vars: 
      GROUPER_UI='true'
      RUN_APACHE='true'
      RUN_SHIB_SP='true'
      RUN_TOMEE='true'

      wswill set env vars:
      GROUPER_WS='true'
      RUN_APACHE='true'
      RUN_TOMEE='true'
      scimwill set env vars:
      GROUPER_SCIM='true'
      RUN_APACHE='true'
      RUN_TOMEE='true'
      daemonwill set env vars:
      GROUPER_DAEMON='true'
      RUN_TOMEE='true'
      bin/gshwill just run gsh commands from docker command line
      ui-wswill set env vars:
      GROUPER_UI='true'
      GROUPER_WS='true'
      RUN_APACHE='true'
      RUN_SHIB_SP='true'
      RUN_TOMEE='true'
      <no command>run loader?  maybe do nothing instead, so GSH can be used in bash in container
      -e GROUPER_UI=trueenv var will tell grouper to allow ui calls via grouper.hibernate.base.properties
      grouper.is.ui.elConfig = ${java.lang.System.getenv().get('GROUPER_UI')}
      -e GROUPER_WS=trueenv var will tell grouper to allow ws calls via grouper.hibernate.base.properties
      grouper.is.ws.elConfig = ${java.lang.System.getenv().get('GROUPER_WS')}
      -e GROUPER_SCIM=trueenv var will tell grouper to allow ws calls via grouper.hibernate.base.properties
      grouper.is.scim.elConfig = ${java.lang.System.getenv().get('GROUPER_SCIM')}
      -e GROUPER_DAEMON=trueenv var will tell grouper to kick of daemon thread in tomee
      grouper.is.daemon.elConfig = ${java.lang.System.getenv().get('GROUPER_DAEMON')}
      -e RUN_APACHE=true

      env var will tell supervisor to kick off apache in container.  Note, apache is not needed

      for Grouper.  You could hook up an external web server to tomee or run from tomee itself (not recommended)

      -e RUN_SHIB_SP=true

      env var will tell supervisor to kick off shib sp in container.  Note if you dont use shib this is not needed.

      Note: you can also run shib outside the grouper container (e.g. in another container or from reverse proxy)

      -e RUN_TOMEE=true

      env var will tell supervisor to kick off tomee.  Note you must have this to true if you are doing anything 

      but a GSH env.  The WS/UI/scim/daemon must run tomee in container.

    12. Start the container

      docker run --detach --publish 443:443 \
         --mount type=bind,src=</opt/grouperMount>/conf,dst=/opt/grouper/conf \
         --mount type=bind,src=</opt/grouperMount>/logs,dst=/opt/grouper/logs \
         --mount type=bind,src=</opt/grouperMount>/slashRoot=/opt/grouper/slashRoot \
         --restart always --name grouper \
         tier/grouper:2.5.x \
         -e GROUPER_UI='true' -e GROUPER_WS='true' -e GROUPER_DAEMON='true' -e GROUPER_SCIM='true' \
         -e RUN_APACHE='true' -e RUN_SHIB_SP='false' -e RUN_TOMEE='true'
      
      
    13. Make a README.txt with some commands for and put it in /opt/grouperMount. Refer here: Install the Grouper 2.4 container with maturity level 0#Installdocker
      1. Starting container

      2. Stopping container
      3. SSH'ing into it
      4. Where the ports/conf/logs are
      5. How to upgrade (i.e. go to site that lists TAP containers, update the command based on version, follow upgrade steps to go up major version)
  9. Chad to make maven jar versions of build number: grouper-2.5.8.jar
  10. After build of uber webapp, we should keep lists of files and filesizes so we can know what overlays are there...  keep in a properties file in /WEB-INF/classes
    1. Add a UI screen for disagnostics that reports on file overlays...
    2. Remove the GrouperCheckConfig checking of jars


Tarballs

We wont have tarballs anymore, just building the TAP image in ant. 

The downloads site will need some logic to coordinate the latest version of the client/installer.  I think this can be done with a cron and a script to discover the latest version from maven and update a symlink


Proposed Workflow including CI

Build

  1. edit grouper.version (a.b.c)
  2. edit changelog
  3. commit
  4. add tag (GROUPER_RELEASE_a.b.c) and push

CI (travis)

  1. tag triggers a build
  2. download that zip archive from github (github makes archives available for any tag)
  3. unpack archive
  4. Parse the tag to convert GROUPER_RELEASE_a.b.c to a.b.c
  5. abort if the version from the tag doesn't match version in grouper.version
  6. update maven versions to the new version (`mvn versions:set -DnewVersion=a.b.c`)
  7. build and deploy to staging
  8. Mail committer that either the staged jars in Maven Central are ready to release, or any errors

INSTALL

  1. input parameter is grouper version
  2. download that zip archive from github (github makes archives available for any tag)
  3. download the jar plus dependencies from maven
  4. assemble the container



Notes

Try to get tomee and tomcat to have only one copy of jar
1. If the SCIM switch is passed in, can the container copy the files from one place to another on startup?
2. Tomcat looks like it will allow symlinks with "allowLinking=true", we could link the jars so they arent copies
3. Keep it with copies
4. Only run tomee and not tomcat (I havent gotten this to work but we could try again).  I dont really want to do this though tomee does run tomcat under the covers...
5. We could try to have the scim jar webapp colated with the ui/ws/daemon, where the jar just wont be loaded in the tomcat case, but yes in the scim case


  • No labels