Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • Setting gsh.useLegacy = true in grouper.properties.
  • Using a command line argument  (gsh.sh -forceLegacyGsh)

Escape

Escape things in groovysh with single backslash.  e.g.

Code Block
attributeValueDelegate.assignValue(RuleUtils.ruleIfConditionElName(), "\${subject.sourceId != 'g:gsa'}");


API Compability

gsh is now a core part of the Grouper API and so is always compatible with the current release.

...

Code Block
export GSH_JVMARGS="-Dlibrary.jansi.path=/some/other/temp/path/with/exec"

Supported Commands

Grouper API methods

Any Grouper API method can be directly invoked just by referencing it, inclusive of the class in which it is defined. Methods return a java object which can be stored in a variable. For example, the following gsh session determines all of the groups to which a given subject belongs:

Environment variables that affect GSH startup:

  • GROUPER_HOME: if set to a valid Grouper directory, it will use this directory. Otherwise, it will determine it based on the path to gsh
  • GROUPER_CONF: if set to a valid conf directory, it will use this directory. Otherwise it will determine it based on GROUPER_HOME
  • MEM_START: Override the default -Xms Java parameter (initial Java heap size)
  • MEM_MAX: Override the default -Xmx Java parameter (maximum Java heap size)
  • CLASSPATH: Will prepend to the constructed classpath
  • GSH_JVMARGS: Additional arguments to pass to Java
  • GSH_CYGWIN: (since 2.4.0 api patch 3) if set and not blank, the script will convert paths and the classpath to Windows-style, for use with Windows Java under Cygwin
  • GSH_QUIET: (since 2.4.0 api patch 3) if set and not blank, will not output preliminary diagnostic information before starting Java, other than errors

Command line arg in script

Code Block
./gsh -runarg 'userToFind="user1"\n:load "/opt/grouper/scripts/myGSHScript.gsh"'


Supported Commands

Grouper API methods

Any Grouper API method can be directly invoked just by referencing it, inclusive of the class in which it is defined. Methods return a java object which can be stored in a variable. For example, the following gsh session determines all of the groups to which a given subject belongs:

No Format
gsh 0% GrouperSession.startRootSession();
gsh 0% subj = findSubject("SD00125")
subject
No Format
gsh 0% GrouperSession.startRootSession();
gsh 0% subj = findSubject("SD00125")
subject: id='SD00125' type='person' source='kitn-person' name='Barton, Tom'
gsh 1% sess = GrouperSession.start(subj)
edu.internet2.middleware.grouper.GrouperSession: 29c40f97-9fb0-4e45-88bc-a14877a6c9b5,'SD00125','person'
gsh 2% member = MemberFinder.findBySubject(sess, subj)
member: id='SD00125' type='person' source='kitn-person' uuid='d0fa765e-1439-name='Barton, Tom'
gsh 1% sess = GrouperSession.start(subj)
edu.internet2.middleware.grouper.GrouperSession: 29c40f97-9fb0-4e45-88bc-a14877a6c9b5,'SD00125','person'
gsh 2% member = MemberFinder.findBySubject(sess, subj)
member: id='SD00125' type='person' source='kitn-person' uuid='d0fa765e-1439-4701-89b1-9b08b4ce9daa'
gsh 3% member.getGroups()
group: name='etc:sysadmingroup' displayName='Grouper Administration:SysAdmin Group' uuid='6f77fb36-b466-481a-84a7-7af609f1ad09'

...

Command

Description

addComposite(group name, composite type, left group name, right group name)

Add composite membership.  e.g. CompositeType.UNION

addMember(group name, subject id)

Add member to the members list for the group.

addMember(group name, subject id, field)

Add member to the specified list for the group.

delComposite(group name)

Delete composite membership from group

delMember(group name, subject id)

Delete member from the members list for the group

delMember(group name, subject id, field)

Delete member from the specified list for the group

getMembers(group name)

Get members of group

hasMember(group name, subject id)

Check whether subject is member of the members list

hasMember(group name, subject id, field)

Check whether subject is member of the specified list

Privileges

GrouperSession grouperSession = GrouperSession.startRootSession();
Group group = GroupFinder.findByName(grouperSession, "a:b:c", true);
group.addMember(SubjectFinder.findByIdAndSource("someId", "sourceId", true), false);
Add member with subjectId and sourceId
GrouperSession grouperSession = GrouperSession.startRootSession();
Group group = GroupFinder.findByName(grouperSession, "a:b:c", true);
group.addMember(SubjectFinder.findByIdentifierAndSource("someIdentifier", "sourceId", true), false);
Add member with subjectIdentifier and sourceId

Privileges

Command

Description

grantPriv

Command

Description

grantPriv(group name, subject id, privilege)

Grant privilege on group. privilege must be an AccessPrivilege (e.g. AccessPrivilege.ADMIN)

grantPriv(stem name, subject id, privilege)

Grant privilege on stem. privilege must be a NamingPrivilege (e.g. NamingPrivilege.STEM)

hasPriv(group name, subject id, privilege)

Check whether subject has Grant privilege on group. privilege must be an AccessPrivilege (e.g. AccessPrivilege.ADMIN)

grantPriv(stem name, subject id, privilege)

Grant privilege on stem. privilege must be a NamingPrivilege (e.g. NamingPrivilege.STEM)

hasPriv(group name, subject id, privilege)

Check whether subject has privilege on group. privilege must be an AccessPrivilege (e.g. AccessPrivilege.ADMIN)

hasPriv(stem name, subject id, privilege)

Check whether subject has privilege on strem. privilege must be a NamingPrivilege (e.g. NamingPrivilege.STEM)

revokePriv(group name, subject id, privilege)

Revoke privilege on group. privilege must be an AccessPrivilege (e.g. AccessPrivilege.ADMIN)

revokePriv(stem name, subject id, privilege)

Revoke privilege on stem. privilege must be a NamingPrivilege (e.g. NamingPrivilege.STEM)

...

Delete stem and subcontents

Command

Description

addRootStem(extension, displayExtension)

Add top-level stem to the registry

addStem(parent stem name, extension, displayExtension)

Add stem to registry

delStem(stem name)

Delete stem from registry

obliterateStem(stem name, testOnlyBoolean, deleteFromPointInTimeBoolean)    (Grouper v2.0.2+)

Delete stem, and subobjects.

If testonly (true|false), then only
print a report.  This is not supported when deleteFromPointInTime is true.

If deleteFromPointInTime (true|false), then delete from point in time as well.  Otherwise, point in time records are not deleted.

Note that point in time data can only be deleted after the actual objects have been deleted and those deletions have been processed by the changeLogTempToChangeLog job, which runs once a minute by default with the Grouper Daemon.  So when you call obliterateStem(name, false, true), it will first obliterate the actual stem, then sleep and keep checking if the changeLogTempToChangeLog job has completed.  When it completes, it will obliterate from the point in time data.

GrouperSession must be open before calling...

getStemAttr(stem name, attr)

Get value of stem attribute

getStems(name)

Find all stems with a matching naming attribute value, returns a Set of stems

setStemAttr(stem name, attr, value)

Set value of stem attribute

StemFinder.findByName(grouperSession, name)

Find one stem by name

StemFinder.findByUuid(grouperSession, uuid)

Find one stem by uuid

Delete stem and subcontents


Code Block
grouperSession = GrouperSession.startRootSession();
stem = StemFinder.findByName(grouperSession, "a");
for(child : stem.getChildGroups(Stem.Scope.SUB)) { System.out.println("deleting: " + child.getName()); child.delete();  }
stemList = new ArrayList(stem.getChildStems(Stem.Scope.SUB));
Collections.sort(stemList);
Collections.reverse(stemList);
for(childStem : stemList) { System.out.println("deleting: " + childStem.getName()); childStem.delete(); }
stem.delete();


Subjects

Command

Description

addSubject(id, type, name)

Add local subject to registry. You need the jdbc source for this to work. The type parameter describes the type of subject (e.g. "people"), and is required non-null even though there are few useful api methods to query it.

In 2.4.0.api.41+ patch, this will also create the id, name, description, and loginid attribute (unless grouper.properties create.attributes.when.creating.registry.subjects is false)

RegistrySubject.addOrUpdate(grouperSession, id, type, name, nameAttributeValue, loginid, description, email)In 2.4.0.api.41+ patch, add a registry subject like addSubject, but specify the attribute values of name, loginid, etc
e.g. RegistrySubject.addOrUpdate(grouperSession, "someTestSubject", "person", "Some Testsubject", "Name Some Test Subject", "stsub", "Some Testsubject - employee - also alumni", "some@test.subject");
RegistrySubject.find(id, errorOnNotFound)In 2.4.0.api.41+ patch, get a registry subject
e.g. registrySubject = RegistrySubject.find("someTestSubject", false);
registrySubject.delete(grouperSession)In 2.4.0.api.41+ patch, delete a registry subject
e.g. registrySubject.delete(grouperSession);
RegistrySubjectAttribute.addOrUpdate(subjectId, attributeName, attributeValue)In 2.4.0.api.41+ patch, add or update a registry subject attribute
registrySubjectAttribute.delete()In 2.4.0.api.41+ patch, delete an attribute value

findSubject(ididOrIdentifier)

Find a subject by id or identifier

findSubject(ididOrIdentifier, type)

Find a subject by id or identifier; type is a deprecated parameter that is ignored

findSubject(idOrIdentifier, typefindSubject(id, type, source)

Find a subject by id or identifier for a specific subject source; type is a deprecated parameter that is ignored

getSources()

Find all Subject sources

grouperSession = GrouperSession.startRootSession();
SubjectFinder.findAll(searchString, source);

Find all subjects in a source by search string

grouperSession = GrouperSession.startRootSession();
SubjectFinder.findByIdAndSource(id, source, exceptionIfNull);
SubjectFinder.findByIdAndSource("12345", "jdbc", true);

Find a subject by id in a certain source

grouperSession = GrouperSession.startRootSession();
SubjectFinder.findByIdentifierAndSource(identifier, source, exceptionIfNull);
SubjectFinder.findByIdentifierAndSource("jsmith", "jdbc", true);

Find a subject by identifier in a certain source

grouperSession = GrouperSession.startRootSession();
SubjectFinder.findByIdOrIdentifierAndSource(idOrIdentifier, source, exceptionIfNull);
SubjectFinder.findByIdOrIdentifierAndSource("jsmith", "jdbc", true);

Find a subject by id or identifier in a certain source

add test subjects to registry (e.g. test.subject.0 through 9)

grouperSession = GrouperSession.startRootSession();
new RegistryReset()._addSubjects();

Edit subject (in this case name)

RegistrySubject registrySubject = GrouperDAOFactory.getFactory().getRegistrySubject().find("user1a", "person", true);
registrySubject.setName("New name");
HibernateSession.byObjectStatic().update(registrySubject);

add a subject application principal with attributes (GSH)


Code Block
String principal = "someApp";
String email = null;

GrouperSession grouperSession = GrouperSession.startRootSession();


addSubject(principal, "application", principal);
HibernateSession.bySqlStatic().executeSql("insert into subjectattribute (subjectId, name, value, searchValue) values (?, ?, ?, ?)", GrouperUtil.toListObject(new Object[]{principal, "description", principal, principal.toLowerCase()}));
if (email != null){ HibernateSession.bySqlStatic().executeSql("insert into subjectattribute (subjectId, name, value, searchValue) values (?, ?, ?, ?)", GrouperUtil.toListObject(new Object[]{principal, "email", email, email.toLowerCase()}));}
HibernateSession.bySqlStatic().executeSql("insert into subjectattribute (subjectId, name, value, searchValue) values (?, ?, ?, ?)", GrouperUtil.toListObject(new Object[]{principal, "loginid", principal, principal}));
HibernateSession.bySqlStatic().executeSql("insert into subjectattribute (subjectId, name, value, searchValue) values (?, ?, ?, ?)", GrouperUtil.toListObject(new Object[]{principal, "name", principal, principal}));



remove a subject with attributes (GSH)


Code Block
String principal = "someApp";
String email = null;

GrouperSession grouperSession = GrouperSession.startRootSession();

HibernateSession.bySqlStatic().executeSql("delete from subjectattribute where subjectId = ?", GrouperUtil.toListObject(new Object[]{principal}));
HibernateSession.bySqlStatic().executeSql("delete from subject where subjectId = ?", GrouperUtil.toListObject(new Object[]{principal}));

System

...

Command

...

Description

...

sqlRun(file)

...

Execute each line of a sql file, just like ant would.  This can run the files generated by registryInitializeSchema()

...

sqlRun(string)

...

Executes a single sql statement

...

:exit

...

Terminate shell

...

help()

...

Display usage information

...

p(command)

...

Pretty print results.

...

:quit

...

Terminate shell

...

version()

...

Return version information


subject api diagnostics

grouper.properties (temporarily)

Code Block
gsh.exitOnSubjectCheckConfigProblem = false

gsh

Code Block
GrouperSession.startRootSession();
new edu.internet2.middleware.grouper.grouperUi.serviceLogic.SubjectSourceDiagnostics().assignSourceId("SMUPerson_DEV").assignSubjectId("empl1").assignSubjectIdentifier("netid@school.edu").assignSearchString("em").subjectSourceDiagnosticsFromGsh()
===>
SUCCESS: Found subject by id in 37ms: 'empl1'
         with SubjectFinder.findByIdAndSource("empl1", "SMUPerson_DEV", false)
SUCCESS: Subject id in returned subject matches the subject id searched for: 'empl1'
WARNING: No subject found by identifier in 14ms: 'netid@school.edu'
         with SubjectFinder.findByIdentifierAndSource("netid@school.edu", "SMUPerson_DEV", false)


System

Command

Description

sqlRun(file)

Execute each line of a sql file, just like ant would.  This can run the files generated by registryInitializeSchema()

sqlRun(string)

Executes a single sql statement

:exit

Terminate shell

help()

Display usage information

p(command)

Pretty print results.

:quit

Terminate shell

version()

Return version information

Unresolvable subject deletion utility (USDU)

usdu finds which memberships are with subjects which cannot be found in a subject source, and prints them on the screen
- if the usdu.DELETE option is passed in, then the memberships will be deleted
- a grouper session must be open when this command is run.

 For more information, see Unresolvable Subject Deletion Utility (USDU)

Command

Description

GrouperSession.startRootSession();
 usdu()

Sample call to find all unresolvable subjects in the registry and print details to the screen

usdu(usdu.DELETE)

Pass in that you want to delete memberships in the usdu call

usduBySource("schoolperson")

Work only in a specific subject source, pass in the sourceId from sources.xml

usduBySource("schoolperson", usdu.DELETE)

Work in a specific source and delete membeships

subject=SubjectFinder.findById("GrouperSystem")
 session=GrouperSession.start(subject)"
 memberSubject=SubjectFinder.findById("1234567")
 member=MemberFinder.findBySubject(session,memberSubject)
 usduByMember(member)

Work only with a specific member

usduByMember(member, usdu.DELETE)

usdu by member, and delete memberships

Find bad memberships

 This command will find membership records in the database which are invalid, and prints them on the screen, along with a GSH script that will fix the memberships.

 For more information, see Bad Membership Finder Utility

Command

Description

findBadMemberships()

complete findBadMemberships run


XML legacy

Command

Description

xmlFromFile(filename)

Load registry from XML in file

xmlFromString(xml)

Load registry from XML in string

xmlFromURL(url)

Load registry from XML at URL

xmlToFile(filename)

Exports registry to file

xmlToString()

Exports registry to string.

xmlUpdateFromFile(filename)

Update registry from XML in file

xmlUpdateFromString(xml)

Update registry from XML in string

xmlUpdateFromURL(url)

Update registry from XML at URL

XML export legacy

There is an object: XmlExport which has various chaining methods, which should be ended with an exportTo() method.  You can export to file or string.

For more information, see Import-Export

Command

Description

XmlExport xmlExport.stem(stem)

The stem to export. Defaults to the ROOT stem.

XmlExport xmlExport.group(group)

The group to export

XmlExport xmlExport.relative(boolean)

If group or stem specified do not export parent Stems.

XmlExport xmlExport.includeParent(boolean)

If group specified, export from the parent stem

XmlExport xmlExport.childrenOnly(boolean)

If stem specified, export child stems and groups only - not the specified stem

XmlExport xmlExport.userProperties(file)

Properties file for extra settings for import

XmlExport xmlExport.grouperSession(grouperSession)

Operate within a certain grouper session (defaults to root session)

void xmlExport.exportToFile(file)

Export to an XML file

void xmlExport.exportToString(string)

Export to an XML string

 Examples:

No Format
gsh 1% new XmlExport()

Unresolvable subject deletion utility (USDU)

usdu finds which memberships are with subjects which cannot be found in a subject source, and prints them on the screen
- if the usdu.DELETE option is passed in, then the memberships will be deleted
- a grouper session must be open when this command is run.

 For more information, see Unresolvable Subject Deletion Utility (USDU)

...

Command

...

Description

...

GrouperSession.startRootSession();
 usdu()

...

Sample call to find all unresolvable subjects in the registry and print details to the screen

...

usdu(usdu.DELETE)

...

Pass in that you want to delete memberships in the usdu call

...

usduBySource("schoolperson")

...

Work only in a specific subject source, pass in the sourceId from sources.xml

...

usduBySource("schoolperson", usdu.DELETE)

...

Work in a specific source and delete membeships

...

subject=SubjectFinder.findById("GrouperSystem")
 session=GrouperSession.start(subject)"
 memberSubject=SubjectFinder.findById("1234567")
 member=MemberFinder.findBySubject(session,memberSubject)
 usduByMember(member)

...

Work only with a specific member

...

usduByMember(member, usdu.DELETE)

...

usdu by member, and delete memberships

Find bad memberships

 This command will find membership records in the database which are invalid, and prints them on the screen, along with a GSH script that will fix the memberships.

 For more information, see Bad Membership Finder Utility

...

Command

...

Description

...

findBadMemberships()

...

complete findBadMemberships run

XML legacy

Command

Description

xmlFromFile(filename)

Load registry from XML in file

xmlFromString(xml)

Load registry from XML in string

xmlFromURL(url)

Load registry from XML at URL

xmlToFile(filename)

Exports registry to file

xmlToString()

Exports registry to string.

xmlUpdateFromFile(filename)

Update registry from XML in file

xmlUpdateFromString(xml)

Update registry from XML in string

xmlUpdateFromURL(url)

Update registry from XML at URL

XML export legacy

There is an object: XmlExport which has various chaining methods, which should be ended with an exportTo() method.  You can export to file or string.

For more information, see Import-Export

...

Command

...

Description

...

XmlExport xmlExport.stem(stem)

...

The stem to export. Defaults to the ROOT stem.

...

XmlExport xmlExport.group(group)

...

The group to export

...

XmlExport xmlExport.relative(boolean)

...

If group or stem specified do not export parent Stems.

...

XmlExport xmlExport.includeParent(boolean)

...

If group specified, export from the parent stem

...

XmlExport xmlExport.childrenOnly(boolean)

...

If stem specified, export child stems and groups only - not the specified stem

...

XmlExport xmlExport.userProperties(file)

...

Properties file for extra settings for import

...

XmlExport xmlExport.grouperSession(grouperSession)

...

Operate within a certain grouper session (defaults to root session)

...

void xmlExport.exportToFile(file)

...

Export to an XML file

...

void xmlExport.exportToString(string)

...

Export to an XML string

 Examples:

No Format
gsh 1% new XmlExport().exportToFile(new File("c:/temp/export.xml"))
No Format
gsh 1% grouperSession = GrouperSession.start(SubjectFinder.findById("mchyzer"));
gsh 2% stem = StemFinder.findByName(grouperSession, "aStem");
gsh 3% new XmlExport().stem(stem).relative(true).userProperties(new File("C:/temp/some.props")).grouperSession(grouperSession).exportToFile(new File("c:/temp/export.xml"));

 -or- (without chaining)

No Format
gsh 3% xmlExport = new XmlExport();
gsh 4% xmlExport.stem(stem);
gsh 5% xmlExport.grouperSession(grouperSession);
gsh 6% xmlExport.exportToFile(new File("c:/temp/export.xml"))

XML import legacy

There is an object: XmlImport which has various chaining methods, which should be ended with an importFrom() method.  You can import from file, string, or url.

For more information, see Import-Export

Command

Description

XmlImport xmlImport.stem(stem)

The Stem into which data will be imported. Defaults to the ROOT stem.

XmlImport xmlImport.updateList(boolean)

XML contains a flat list of Stems or Groups which may be updated.
Missing Stems and Groups are not created.

XmlImport xmlImport.userProperties(file)

Properties file for extra settings for import

XmlImport xmlImport.grouperSession(grouperSession)

Operate within a certain grouper session (defaults to root session)

XmlImport xmlImport.ignoreInternal(boolean)

Ignore internal attributes, including group and stem uuids.

void xmlImport.importFromFile(file)

Import from an XML file

void xmlImport.importFromString(string)

Import from an XML string

void xmlImport.importFromUrl(url)

Import XML from a URL

 Examples:


No Format
gsh 1% grouperSession = GrouperSession.start(SubjectFinder.findById("mchyzer"));
gsh 2% stem = StemFinder.findByName(grouperSession, "aStem");
gsh 3% new XmlExport().stem(stem).relative(true).userProperties(new File("C:/temp/some.props")).grouperSession(grouperSession).exportToFile(new 
No Format
gsh 1% new XmlImport().importFromFile(new File("c:/temp/export.xml"));

 -or- (without chaining)

No Format
gsh 1%3% grouperSessionxmlExport = new GrouperSession.start(SubjectFinder.findById("mchyzer")XmlExport();
gsh 2%4% xmlExport.stem(stem);
gsh =5% StemFinderxmlExport.findByNamegrouperSession(grouperSession, "aStem");
gsh 3% new XmlImport().stem(stem).updateList(true).userProperties6% xmlExport.exportToFile(new File("Cc:/temp/someexport.propsxml")).grouperSession(grouperSession).importFromUrl(new URL("http://whatever.xml"));

 -or- (without chaining)

No Format
gsh 3% xmlImport = new XmlImport();
gsh 4% xmlImport.stem(stem);
gsh 5% xmlImport.grouperSession(grouperSession);
gsh 6% xmlImport.importFromFile(new File("c:/temp/export.xml"))

Transactions

Transactions facilitate all commands succeeding or failing together, and perhaps some level of repeatable reads of the DB (depending on the DB).  If there is an open transaction and an exception is thrown in a command, GSH will shut down so that subsequent commands will not execute outside of a transaction.

Command

Description

help("transaction")

print help information

transactionStatus()

print the list of nested transactions

transactionStart("<GrouperTransactionType>")

start a transaction, or make sure one is already started
   Can use: "READONLY_OR_USE_EXISTING", "NONE", "READONLY_NEW",
"READ_WRITE_OR_USE_EXISTING", "READ_WRITE_NEW"

transactionCommit("<GrouperCommitType>")

commit a transaction
   Can use: "COMMIT_NOW", "COMMIT_IF_NEW_TRANSACTION

transactionRollback("<GrouperRollbackType>")

rollback a transaction
    Can use: "ROLLBACK_NOW", "ROLLBACK_IF_NEW_TRANSACTION

transactionEnd()

end a transaction
    Note if it was read/write, and not committed or rolled back, this will commit and end

Loader

Above, it describes how you can kick off the loader in daemon mode.  You can also execute one job with:

...

Command

...

Description

...

grouperSession = GrouperSession.startRootSession();
loaderGroup = GroupFinder.findByName(grouperSession, "stem:group");
loaderRunOneJob(loaderGroup);

...

Kick off the loader for one group (configured by group attributes)

...

loaderRunOneJob("MAINTENANCE_cleanLogs");

...

Kick off the loader by job name

...

loaderRunOneJob("CHANGE_LOG_changeLogTempToChangeLog");

...

Move change log entries from the temp table to the real table

...

loaderRunOneJob("CHANGE_LOG_consumer_grouperRules");
loaderRunOneJob("MAINTENANCE__rules");

...

Run the Grouper Rules daemon (the changelog or full version)

...

loaderRunOneJob("CHANGE_LOG_consumer_test");

...

Run a change log consumer

This query (in Oracle) will find jobs with no success in the last day and make a gsh script:

Code Block
select distinct 'loaderRunOneJob("' || job_name || '");' as script 
from grouper_loader_log gll where started_time > sysdate-1 and status != 'SUCCESS'
and gll.job_name not like 'subjobFor%'
and not exists (select 1 from grouper_loader_log gll2 where gll2.started_time > sysdate-1
 and gll2.status = 'SUCCESS' and gll2.job_name = gll.job_name)
Code Block
languagesql
titleHSQLDB (similar example)
select distinct job_name from grouper_loader_log gll where started_time > CURRENT_DATE - 1 DAY and status != 'SUCCESS' and gll.job_name not like 'subjobFor%' 
AND NOT EXISTS (select job_name from grouper_loader_log gll2 where gll2.started_time > CURRENT_DATE - 1 DAY and gll2.status = 'SUCCESS' and gll2.job_name = gll.job_name)

v1.6+ loader

...

Command

...

Description

...

loaderRunOneJobAttr(attirbuteDef)

...

Run an attribute definition loader job

You can run the loader as a linux service

GrouperShell Variables (BeanShell only)

gsh has several variables that can be set to modify runtime behavior

...

Variable

...

Description

...

GSH_DEBUG

...

Stack traces will be printed upon failure if true

...

GSH_DEVEL

...

Summaries of returned objects are not automatically printed if true

...

GSH_TIMER

...

Prints time spent evaluating each command if true


XML import legacy

There is an object: XmlImport which has various chaining methods, which should be ended with an importFrom() method.  You can import from file, string, or url.

For more information, see Import-Export

Command

Description

XmlImport xmlImport.stem(stem)

The Stem into which data will be imported. Defaults to the ROOT stem.

XmlImport xmlImport.updateList(boolean)

XML contains a flat list of Stems or Groups which may be updated.
Missing Stems and Groups are not created.

XmlImport xmlImport.userProperties(file)

Properties file for extra settings for import

XmlImport xmlImport.grouperSession(grouperSession)

Operate within a certain grouper session (defaults to root session)

XmlImport xmlImport.ignoreInternal(boolean)

Ignore internal attributes, including group and stem uuids.

void xmlImport.importFromFile(file)

Import from an XML file

void xmlImport.importFromString(string)

Import from an XML string

void xmlImport.importFromUrl(url)

Import XML from a URL

 Examples:

No Format
gsh 1% new XmlImport().importFromFile(new File("c:/temp/export.xml"))


No Format
gsh 1% grouperSession = GrouperSession.start(SubjectFinder.findById("mchyzer"));
gsh 2% stem = StemFinder.findByName(grouperSession, "aStem");
gsh 3% new XmlImport().stem(stem).updateList(true).userProperties(new File("C:/temp/some.props")).grouperSession(grouperSession).importFromUrl(new URL("http://whatever.xml"));

 -or- (without chaining)

No Format
gsh 3% xmlImport = new XmlImport();
gsh 4% xmlImport.stem(stem);
gsh 5% xmlImport.grouperSession(grouperSession);
gsh 6% xmlImport.importFromFile(new File("c:/temp/export.xml"))

Transactions

Transactions facilitate all commands succeeding or failing together, and perhaps some level of repeatable reads of the DB (depending on the DB).  If there is an open transaction and an exception is thrown in a command, GSH will shut down so that subsequent commands will not execute outside of a transaction.

Command

Description

help("transaction")

print help information

transactionStatus()

print the list of nested transactions

transactionStart("<GrouperTransactionType>")

start a transaction, or make sure one is already started
   Can use: "READONLY_OR_USE_EXISTING", "NONE", "READONLY_NEW",
"READ_WRITE_OR_USE_EXISTING", "READ_WRITE_NEW"

transactionCommit("<GrouperCommitType>")

commit a transaction
   Can use: "COMMIT_NOW", "COMMIT_IF_NEW_TRANSACTION

transactionRollback("<GrouperRollbackType>")

rollback a transaction
    Can use: "ROLLBACK_NOW", "ROLLBACK_IF_NEW_TRANSACTION

transactionEnd()

end a transaction
    Note if it was read/write, and not committed or rolled back, this will commit and end

Daemon

You can schedule daemon jobs (and in UI) in v2.5.23+

Code Block
GrouperSession.startRootSession();
edu.internet2.middleware.grouper.app.loader.GrouperLoader.scheduleJobs();


Loader

Above, it describes how you can kick off the loader in daemon mode.  You can also execute one job with:

Command

Description

grouperSession = GrouperSession.startRootSession();
loaderGroup = GroupFinder.findByName(grouperSession, "stem:group");
loaderRunOneJob(loaderGroup);

Kick off the loader for one group (configured by group attributes)

loaderRunOneJob("MAINTENANCE_cleanLogs");

Kick off the loader by job name

loaderRunOneJob("CHANGE_LOG_changeLogTempToChangeLog");

Move change log entries from the temp table to the real table

loaderRunOneJob("CHANGE_LOG_consumer_grouperRules");
loaderRunOneJob("MAINTENANCE__rules");

Run the Grouper Rules daemon (the changelog or full version)

loaderRunOneJob("CHANGE_LOG_consumer_test");

Run a change log consumer

GrouperLoaderType.validateAndScheduleSqlLoad(group, null, false)Schedule SQL job
GrouperLoaderType.validateAndScheduleLdapLoad(attributeAssign, null, false)Schedule LDAP job
GrouperLoaderType.scheduleAttributeLoads();Schedule all attribute loader jobs

This query (in Oracle) will find jobs with no success in the last day and make a gsh script:

Code Block
select distinct 'loaderRunOneJob("' || job_name || '");' as script 
from grouper_loader_log gll where started_time > sysdate-1 and status != 'SUCCESS'
and gll.job_name not like 'subjobFor%'
and not exists (select 1 from grouper_loader_log gll2 where gll2.started_time > sysdate-1
 and gll2.status = 'SUCCESS' and gll2.job_name = gll.job_name)


Code Block
languagesql
titleHSQLDB (similar example)
select distinct job_name from grouper_loader_log gll where started_time > CURRENT_DATE - 1 DAY and status != 'SUCCESS' and gll.job_name not like 'subjobFor%' 
AND NOT EXISTS (select job_name from grouper_loader_log gll2 where gll2.started_time > CURRENT_DATE - 1 DAY and gll2.status = 'SUCCESS' and gll2.job_name = gll.job_name)


v1.6+ loader

Command

Description

loaderRunOneJobAttr(attirbuteDef)

Run an attribute definition loader job

You can run the loader as a linux service

Jobs not firing in daemon

  1. Stop all daemons
  2. Run these sqls from a file: fixLoaderScheduler.sql

    Code Block
    UPDATE GROUPER_QZ_TRIGGERS SET TRIGGER_STATE = 'WAITING';
    DELETE FROM GROUPER_QZ_FIRED_TRIGGERS;
    commit;



    Code Block
    gsh.sh -registry -runsqlfile fixLoaderScheduler.sql



  3. Restart daemons


It took a couple of hours to catch up on a few days of changes, but it seems to be back to normal. Thanks again, guys!

GrouperShell Variables (BeanShell only)

gsh has several variables that can be set to modify runtime behavior

Variable

Description

GSH_DEBUG

Stack traces will be printed upon failure if true

GSH_DEVEL

Summaries of returned objects are not automatically printed if true

GSH_TIMER

Prints time spent evaluating each command if true

    Example:

No Format
gsh 4% GSH_DEVEL = true
gsh 5% subj = findSubject("SD00125")
gsh 6% sess = GrouperSession.start(subj)
gsh 7% member = MemberFinder.findBySubject(sess, subj)
gsh 8% p(member.getGroups())
group: name='etc:sysadmingroup' displayName='Grouper Administration:SysAdmin Group' uuid='6f77fb36-b466-481a-84a7-7af609f1ad09'

Membership scripts

Code Block
# (1) Print tab-separated summary of all group members, and flags for direct, indirect, or both
# Depending on the results, you could use the data to create a scrutinized list of Ids to delete, then import it and delete in a loop

me = SubjectFinder.findByIdentifierAndSource("my-username", "pid", true);
session = GrouperSession.start(me);
// OR: session = GrouperSession.startRootSession(True)

group = GroupFinder.findByName(session, "tmp:my:group", true);

effectiveMembers = group.getEffectiveMembers();
immediateMembers = group.getImmediateMembers();

System.out.println(String.join("\t", "id", "name", "Effective", "Immediate"));

for (Member m: group.getMembers()) {
    System.out.print(m.getSubject().getId() + "\t" + m.getSubject().getName() + "\t");
    System.out.print(effectiveMembers.contains(m).toString() + "\t");
    System.out.println(immediateMembers.contains(m).toString() + "\t");
}



# (2) Get the immediate and effective members for a specific source ("pid" in this example), intersect them to find the redundant ones
# This has a dryRun flag, so you can test first

sources = new HashSet<Source>()
sources.add(SourceManager.getInstance().getSource("pid"))

effectiveUsers = group.getEffectiveMembers(Group.getDefaultList(), sources, null)
immediateUsers = group.getImmediateMembers(Group.getDefaultList(), sources, null)

# use retainAll() to find the intersection; i.e., users both as effective and immediate member
immediateUsers.retainAll(effectiveUsers)

System.out.println("There are " + immediateUsers.size() + " users having both direct + indirect memberships");

dryRun = true

for (Member m: immediateUsers) {
    if (dryRun) {
        System.out.println("Ok to delete 

    Example:

No Format
gsh 4% GSH_DEVEL = true
gsh 5% subj = findSubject("SD00125")
gsh 6% sess = GrouperSession.start(subj)
gsh 7% member = MemberFinder.findBySubject(sess, subj)
gsh 8% p(member.getGroups())
group: name='etc:sysadmingroup' displayName='Grouper Administration:SysAdmin Group' uuid='6f77fb36-b466-481a-84a7-7af609f1ad09'

Membership scripts

Code Block
# (1) Print tab-separated summary of all group members, and flags for direct, indirect, or both
# Depending on the results, you could use the data to create a scrutinized list of Ids to delete, then import it and delete in a loop

me = SubjectFinder.findByIdentifierAndSource("my-username", "pid", true);
session = GrouperSession.start(me);
// OR: session = GrouperSession.startRootSession(True)

group = GroupFinder.findByName(session, "tmp:my:group", true);

effectiveMembers = group.getEffectiveMembers();
immediateMembers = group.getImmediateMembers();

System.out.println(String.join("\t", "id", "name", "Effective", "Immediate"));

for (Member m: group.getMembers()) {
    System.out.print(m.getSubject().getId() + "\t" + m.getSubject().getNamegetId()) + "\t");
;
    } else {
        System.out.print(effectiveMembers.contains(m).toString() + "\t");
println("Deleting " + m.getSubject().getId());
        System.out.println(immediateMembers.contains(m).toString() + "\t");
}

group.deleteMember(m, false);
    }
}

# (23) Get the immediate and effective members for a specific source ("pid" in the groups this example),subject intersectis thema tomember findof. theNote redundantthat ones
#a Thisgroup hasis a kind dryRunof flagsubject, soand youhas cana test first

sources = new HashSet<Source>()
sources.add(SourceManager.getInstance().getSource("pid"))

effectiveUsers = group.getEffectiveMembers(Group.getDefaultList(), sources, null)
immediateUsers = group.getImmediateMembers(Group.getDefaultList(), sources, null)

# use retainAll() to find the intersection; i.e., users both as effective and immediate member
immediateUsers.retainAll(effectiveUsers)

System.out.println("There are " + immediateUsers.size() + " users having both direct + indirect memberships");

dryRun = true

for (Member m: immediateUsers) {
    if (dryRun) {
        System.out.println("Ok to delete " + m.getSubject().getId());
    } else {
        System.out.println("Deleting " + m.getSubject().getId());
        group.deleteMember(m, false);
    }
}

# (3) Get the groups this subject is a member of. Note that a group is a kind of subject, and has a toSubject() method to convert it.

import edu.internet2.middleware.grouper.membership.MembershipSubjectContainer

GrouperSession grouperSession = GrouperSession.startRootSession();

Group group = GroupFinder.findByName(grouperSession, "test:testGroup", true);
Subject subject = g.toSubject();

Set<MembershipSubjectContainer> msc = new MembershipFinder().addSubject(subject).findMembershipResult().getMembershipSubjectContainers();

for (MembershipSubjectContainer membershipSubjectContainer : msc) { println(membershipSubjectContainer.getGroupOwner().getName());}

//Note there are a few other options for the search. Add these to the MembershipFinder method chain before calling findMembershipResult():
//  - search immediate, effective, etc. (needs to import MembershipType)
importtoSubject() method to convert it.

import edu.internet2.middleware.grouper.membership.MembershipSubjectContainer

GrouperSession grouperSession = GrouperSession.startRootSession();

Group group = GroupFinder.findByName(grouperSession, "test:testGroup", true);
Subject subject = g.toSubject();

Set<MembershipSubjectContainer> msc = new MembershipFinder().addSubject(subject).findMembershipResult().getMembershipSubjectContainers();

for (MembershipSubjectContainer membershipSubjectContainer : msc) { println(membershipSubjectContainer.getGroupOwner().getName());}

//Note there are a few other options for the search. Add these to the MembershipFinder method chain before calling findMembershipResult():
//  - search immediate, effective, etc. (needs to import MembershipType)
import edu.internet2.middleware.grouper.membership.MembershipType
membershipFinder.assignMembershipType(MembershipType.IMMEDIATE) // options are IMMEDIATE|NONIMMEDIATE|EFFECTIVE|COMPOSITE
//  - retrieve specific groups based on pattern
membershipFinder.assignScope("%:test:%")
//  - Enabled status -- true means enabled only, false, means disabled only, and null means all
membershipFinder.assignEnabled(false)
// For other methods, refer to the Javadoc at https://software.internet2.edu/grouper/doc/master/grouper/apidocs/index.html?edu/internet2/middleware/grouper/MembershipFinder.html


Configuration in the database

In v2.4.0 ui patch #56, and GSH must be run from the UI in WEB-INF/bin

Code Block
GrouperSession.startRootSession();

ADD
new edu.internet2.middleware.grouper.grouperUi.beans.config.GrouperDbConfig().configFileName("grouper.properties").propertyName("abc").value("123").store();

DELETE
new edu.internet2.middleware.grouper.grouperUi.beans.config.GrouperDbConfig().configFileName("grouper.properties").propertyName("abc").delete();

IMPORT
new edu.internet2.middleware.grouper.grouperUi.beans.config.GrouperDbConfigImport().configFilePath("d:/temp/temp/grouper.properties").store();


Misc

Note: you cannot encrypt passwords with GSH since the passwords end up in the GSH history.  To encrypt passwords, issue the command:

No Format
C:\mchyzer\isc\dev\grouper-qs-1.2.0\grouper>java -jar lib\morphString.jar
Enter the location of morphString.properties: conf/morphString.properties
Type the string to encrypt (note: pasting might echo it back):
The encrypted string is: ca8a15be4ad0fb45c6f1b3ca0cfd9c9e

v2.0: to sync up the point in time tables with regular tables, run this:

Code Block
new edu.internet2.middleware.grouper.misc.SyncPITTables().syncAllPITTables()

To create missing group sets:

Code Block
new edu.internet2.middleware.grouper.membership.MembershipType
membershipFinder.assignMembershipType(MembershipType.IMMEDIATE) // options are IMMEDIATE|NONIMMEDIATE|EFFECTIVE|COMPOSITE
//  - retrieve specific groups based on pattern
membershipFinder.assignScope("%:test:%")
//  - Enabled status -- true means enabled only, false, means disabled only, and null means all
membershipFinder.assignEnabled(false)
// For other methods, refer to the Javadoc at http://internet2.github.io/grouper/master/grouper-parent/apidocs/edu/internet2/middleware/grouper/MembershipFinder.html

Misc

Note: you cannot encrypt passwords with GSH since the passwords end up in the GSH history.  To encrypt passwords, issue the command:

No Format
C:\mchyzer\isc\dev\grouper-qs-1.2.0\grouper>java -jar lib\morphString.jar
Enter the location of morphString.properties: conf/morphString.properties
Type the string to encrypt (note: pasting might echo it back):
The encrypted string is: ca8a15be4ad0fb45c6f1b3ca0cfd9c9e

v2.0: to sync up the point in time tables with regular tables, run this:

Code Block
new edu.internet2.middleware.grouper.misc.SyncPITTables().syncAllPITTables()

To create missing group sets:

misc.AddMissingGroupSets().addAllMissingGroupSets();

Delete memberships not in transaction

Code Block
grouperSession = GrouperSession.startRootSession();
group = GroupFinder.findByName(grouperSession, "test:testGroup3", true);
for (membership : group.getImmediateMemberships()) {membership.delete();}
group.delete();

Note: in v2.4.0 patch 91+ ( unreleased at the time of writing ) you can use gsh to do simple sql tests through jdbc loader connection

Code Block
languagejava
gcDbAccess = new edu.internet2.middleware.grouperClient.jdbc.GcDbAccess();
// "loaderConnection" is the string used in the grouper-loader.properties ( Example: db.warehouse.url --> "warehouse")
gcDbAccess.connectionName("loaderConnection").sql("select count(1) from test1").select(int.class);


Code Block
List results = 
Code Block
new edu.internet2.middleware.groupergrouperClient.miscjdbc.AddMissingGroupSetsGcDbAccess().addAllMissingGroupSets();

Delete memberships not in transaction

Code Block
grouperSession = GrouperSession.startRootSession();
group = GroupFinder.findByName(grouperSession, "test:testGroup3", truesql("select name, id from grouper_groups").selectList(Object[].class);
for (membershipObject[] row : group.getImmediateMemberships()results) {membership.delete( System.out.println(row[0] + ", " + row[1]);}
group.delete();


See the WIKI for running the Grouper Report manually

...

Code Block
GrouperSession grouperSession = GrouperSession.startRootSession();
AttributeAssign attributeAssign = AttributeAssignFinder.findById("b629bd8170964663be507968752f4f17", true);
attributeAssign.delete();"b629bd8170964663be507968752f4f17", true);
attributeAssign.delete();

NOTE: You can also use the AttributeAssignFinder.findById(String id, boolean exceptionIfNull)  to find attribute assignments from the logs too.
Example log "ERROR RuleEngine$3.callback(560) - - Error with daemon on rule: attributeAssignTypeId: 3d6ccb6c5a584f32919682ae154c0523". id="3d6ccb6c5a584f32919682ae154c0523". The returned AttributeAssign object will show you the stem/group that the attribute is attached to. (smile)

Grouper Builtin Messaging

...

Code Block
    String provisionTarget = "ad";
    GrouperSession grouperSession = GrouperSession.startRootSession();
    
    Set stemsToProvisionToSet = HibernateSession.byHqlStatic().createQuery("select s from Stem s, AttributeAssign aa, AttributeDefName adn, AttributeAssignValue aav where s.id = aa.ownerStemId and aav.attributeAssignId = aa.id and aa.attributeDefNameId = adn.id and aa.attributeAssignTypeDb = 'stem' and aa.enabledDb = 'T' and adn.extensionDb = 'provision_to' and aav.valueString = '" + provisionTarget + "'").listSet(Stem.class);
    for (Object stemObject : stemsToProvisionToSet) { Stem stem = (Stem)stemObject; System.out.println("provision_to assigned to stem: " + stem.getName());  }
    Set stemsToNotProvisionToSet = HibernateSession.byHqlStatic().createQuery("select s from Stem s, AttributeAssign aa, AttributeDefName adn, AttributeAssignValue aav where s.id = aa.ownerStemId and aav.attributeAssignId = aa.id and aa.attributeDefNameId = adn.id and aa.attributeAssignTypeDb = 'stem' and aa.enabledDb = 'T' and adn.extensionDb = 'do_not_provision_to' and aav.valueString = '" + provisionTarget + "'").listSet(Stem.class);
    for (Object stemObject : stemsToNotProvisionToSet) { Stem stem = (Stem)stemObject; System.out.println("do_not_provision_to assigned to stem: " + stem.getName());  }
    Set groupsToProvisionToSet = HibernateSession.byHqlStatic().createQuery("select g from Group g, AttributeAssign aa, AttributeDefName adn, AttributeAssignValue aav where g.id = aa.ownerGroupId and aav.attributeAssignId = aa.id and aa.attributeDefNameId = adn.id and aa.attributeAssignTypeDb = 'group' and aa.enabledDb = 'T' and adn.extensionDb = 'provision_to' and aav.valueString = '" + provisionTarget + "'").listSet(Stem.class);
    for (Object groupObject : groupsToProvisionToSet) { Group group = (Group)groupObject; System.out.println("provision_to assigned to group: " + group.getName());  }
    Set groupsToNotProvisionToSet = HibernateSession.byHqlStatic().createQuery("select g from Group g, AttributeAssign aa, AttributeDefName adn, AttributeAssignValue aav where g.id = aa.ownerGroupId and aav.attributeAssignId = aa.id and aa.attributeDefNameId = adn.id and aa.attributeAssignTypeDb = 'group' and aa.enabledDb = 'T' and adn.extensionDb = 'do_not_provision_to' and aav.valueString = '" + provisionTarget + "'").listSet(Stem.class);
    for (Object groupObject : groupsToNotProvisionToSet) { Group group = (Group)groupObject; System.out.println("do_not_provision_to assigned to group: " + group.getName());  }
    Set allGroups = new LinkedHashSet();
    Set allGroupsToProvision = new TreeSet();
    allGroupsToProvision.addAll(groupsToProvisionToSet);

    Set stemNamesToNotProvisionTo = new HashSet();
    Set stemNamesToProvisionTo = new HashSet();
    
    for (Object stemToProvision : stemsToProvisionToSet) { stemNamesToProvisionTo.add(((Stem)stemToProvision).getName()); }
    for (Object stemNotToProvision : stemsToNotProvisionToSet) { stemNamesToNotProvisionTo.add(((Stem)stemNotToProvision).getName()); }

    for (Object stemToProvision : stemsToProvisionToSet) { allGroups.addAll(((Stem)stemToProvision).getChildGroups(edu.internet2.middleware.grouper.Stem.Scope.SUB)); }
    
    Map groupToPaths = new HashMap();
    for (Object groupObject : allGroups) { Group group = (Group)groupObject; if (allGroupsToProvision.contains(group)) {continue;} if (groupsToNotProvisionToSet.contains(group)) {continue;} List paths = new ArrayList(); groupToPaths.put(group, paths); String currentName = group.getName(); paths.add(currentName);  while(true) { currentName = GrouperUtil.parentStemNameFromName(currentName);  if (GrouperUtil.isBlank(currentName)) {break;} paths.add(currentName);  }   }
    
    for (Object groupObject : groupToPaths.keySet()) {Group group = (Group)groupObject; List paths = (List)groupToPaths.get(group); for (Object pathObject : paths) { String path = (String)pathObject; if (stemNamesToProvisionTo.contains(path)) { allGroupsToProvision.add(group); break; } if (stemNamesToNotProvisionTo.contains(path)) { break; } } }
    
    for (Object groupObject : allGroupsToProvision) { Group group = (Group)groupObject; System.out.println("configured to provision to: " + provisionTarget + ": " + group.getName()); }

.contains(path)) { allGroupsToProvision.add(group); break; } if (stemNamesToNotProvisionTo.contains(path)) { break; } } }
    
    for (Object groupObject : allGroupsToProvision) { Group group = (Group)groupObject; System.out.println("configured to provision to: " + provisionTarget + ": " + group.getName()); }


Stem move

try this:

Code Block
GrouperSession.startRootSession();
stemFrom = StemFinder.findByName(grouperSession, "a:b", true);
stemTo = StemFinder.findByName(grouperSession, "a:c", true);
new edu.internet2.middleware.grouper.StemMove(stemFrom, stemTo).assignAlternateName(false).save();

Check health of database connection or run a query

(in 2.4.0 api patch 93+)

Code Block
gcDbAccess = new edu.internet2.middleware.grouperClient.jdbc.GcDbAccess();
gcDbAccess.connectionName("warehouse").sql("select count(1) from grouper_groups").select(int.class);


Set password using Grouper built-in authentication

Code Block
v2.5.29+
new GrouperPasswordSave().assignApplication(GrouperPassword.Application.UI).assignUsername("username").assignPassword("password").save();