...
- 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.
...
- 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
...
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. | ||
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 |
| ||
Delete stem and subcontents | |||
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, 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(ididOrIdentifier, 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(); | Find all subjects in a source by search string | ||
grouperSession = GrouperSession.startRootSession(); | Find a subject by id in a certain source | ||
grouperSession = GrouperSession.startRootSession(); | Find a subject by identifier in a certain source | ||
grouperSession = GrouperSession.startRootSession(); | 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(); | ||
Edit subject (in this case name) | RegistrySubject registrySubject = GrouperDAOFactory.getFactory().getRegistrySubject().find("user1a", "person", true); | ||
add a subject application principal with attributes (GSH) |
| ||
remove a subject with attributes (GSH) |
|
System
subject api diagnostics | grouper.properties (temporarily)
gsh
|
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) | |
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 |
...
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 |
transactionCommit("<GrouperCommitType>") | commit a transaction |
transactionRollback("<GrouperRollbackType>") | rollback a transaction |
transactionEnd() | end a transaction |
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(); | 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"); | Run the Grouper Rules daemon (the changelog or full version) | loaderRunOneJob("CHANGE_LOG_consumer_test"); | Run a change log consumer) |
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 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
- Stop all daemons
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
- 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!
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)
...
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 " + 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. , 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 " + 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) 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) importMembershipType 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.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.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:
...
Code Block |
---|
new edu.internet2.middleware.grouper.misc.SyncPITTables().syncAllPITTables()
|
To create missing group sets:
.misc.SyncPITTables().syncAllPITTables()
|
To create missing group sets:
Code Block |
---|
new edu.internet2.middleware.grouper.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 | ||
---|---|---|
| ||
gcDbAccess = | ||
Code Block | ||
new edu.internet2.middleware.groupergrouperClient.misc.AddMissingGroupSets().addAllMissingGroupSetsjdbc.GcDbAccess(); |
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(// "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); |
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.
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(); |