Skip to content

Commit 665a274

Browse files
rjrudinMarkLogic Builder
authored andcommitted
DHFPROD-4123: DHF installer no longer assumes group or server names
The group and server names can now be defined via the command line. The server names are used for copying REST options around. Group names are also used for copying REST options around, and also for granular scheduled task privileges.
1 parent 262045c commit 665a274

File tree

9 files changed

+284
-116
lines changed

9 files changed

+284
-116
lines changed

marklogic-data-hub/src/main/java/com/marklogic/hub/deploy/commands/CreateGranularPrivilegesCommand.java

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.marklogic.mgmt.resource.security.PrivilegeManager;
1414

1515
import java.util.ArrayList;
16+
import java.util.Arrays;
1617
import java.util.List;
1718

1819
/**
@@ -21,11 +22,17 @@
2122
public class CreateGranularPrivilegesCommand implements Command, UndoableCommand {
2223

2324
private HubConfig hubConfig;
25+
private List<String> groupNames;
2426

2527
public CreateGranularPrivilegesCommand(HubConfig hubConfig) {
2628
this.hubConfig = hubConfig;
2729
}
2830

31+
public CreateGranularPrivilegesCommand(HubConfig hubConfig, List<String> groupNames) {
32+
this.hubConfig = hubConfig;
33+
this.groupNames = groupNames;
34+
}
35+
2936
/**
3037
* It is anticipated that these privileges can always be added at the end of a deployment because none of the steps
3138
* before that should depend on the privileges being added.
@@ -78,29 +85,7 @@ public void execute(CommandContext context) {
7885
p.setAction("http://marklogic.com/xdmp/privileges/admin/database/alerts/$$database-id(" + finalDbName + ")");
7986
mgr.save(p.getJson());
8087

81-
if (hubConfig.getIsProvisionedEnvironment()) {
82-
p.setPrivilegeName("admin-group-scheduled-task-Analyzer");
83-
p.setAction("http://marklogic.com/xdmp/privileges/admin/group/scheduled-task/$$group-id(Analyzer)");
84-
mgr.save(p.getJson());
85-
86-
p.setPrivilegeName("admin-group-scheduled-task-Curator");
87-
p.setAction("http://marklogic.com/xdmp/privileges/admin/group/scheduled-task/$$group-id(Curator)");
88-
mgr.save(p.getJson());
89-
90-
p.setPrivilegeName("admin-group-scheduled-task-Evaluator");
91-
p.setAction("http://marklogic.com/xdmp/privileges/admin/group/scheduled-task/$$group-id(Evaluator)");
92-
mgr.save(p.getJson());
93-
94-
p.setPrivilegeName("admin-group-scheduled-task-Operator");
95-
p.setAction("http://marklogic.com/xdmp/privileges/admin/group/scheduled-task/$$group-id(Operator)");
96-
mgr.save(p.getJson());
97-
} else {
98-
String groupName = hubConfig.getAppConfig().getGroupName();
99-
100-
p.setPrivilegeName("admin-group-scheduled-task-" + groupName);
101-
p.setAction("http://marklogic.com/xdmp/privileges/admin/group/scheduled-task/$$group-id(" + groupName + ")");
102-
mgr.save(p.getJson());
103-
}
88+
buildScheduledTaskPrivileges().forEach(privilege -> mgr.save(privilege.getJson()));
10489
}
10590

10691
@Override
@@ -128,15 +113,9 @@ public void undo(CommandContext context) {
128113
mgr.deleteAtPath("/manage/v2/privileges/admin-database-alerts-" + finalDbName + "?kind=execute");
129114
mgr.deleteAtPath("/manage/v2/privileges/admin-database-alerts-" + stagingDbName + "?kind=execute");
130115

131-
if (hubConfig.getIsProvisionedEnvironment()) {
132-
mgr.deleteAtPath("/manage/v2/privileges/admin-group-scheduled-task-Analyzer" + "?kind=execute");
133-
mgr.deleteAtPath("/manage/v2/privileges/admin-group-scheduled-task-Curator" + "?kind=execute");
134-
mgr.deleteAtPath("/manage/v2/privileges/admin-group-scheduled-task-Evaluator" + "?kind=execute");
135-
mgr.deleteAtPath("/manage/v2/privileges/admin-group-scheduled-task-Operator" + "?kind=execute");
136-
} else {
137-
String groupName = hubConfig.getAppConfig().getGroupName();
116+
getGroupNamesForScheduledTaskPrivileges().forEach(groupName -> {
138117
mgr.deleteAtPath("/manage/v2/privileges/admin-group-scheduled-task-" + groupName + "?kind=execute");
139-
}
118+
});
140119
}
141120

142121
/**
@@ -183,4 +162,32 @@ protected Privilege buildPrivilege(ManageClient client, String name, String acti
183162
p.addRole(role);
184163
return p;
185164
}
165+
166+
/**
167+
* Builds a list of privileges to create based on the groupNames configured on this object. If none have been
168+
* configured, then the groupName in AppConfig is used.
169+
*
170+
* @return
171+
*/
172+
protected List<Privilege> buildScheduledTaskPrivileges() {
173+
List<Privilege> privileges = new ArrayList<>();
174+
getGroupNamesForScheduledTaskPrivileges().forEach(groupName -> {
175+
Privilege p = new Privilege(null, "admin-group-scheduled-task-" + groupName);
176+
p.setKind("execute");
177+
p.setAction("http://marklogic.com/xdmp/privileges/admin/group/scheduled-task/$$group-id(" + groupName + ")");
178+
p.addRole("data-hub-developer");
179+
privileges.add(p);
180+
});
181+
return privileges;
182+
}
183+
184+
protected List<String> getGroupNamesForScheduledTaskPrivileges() {
185+
return (groupNames != null && !groupNames.isEmpty()) ?
186+
groupNames :
187+
Arrays.asList(hubConfig.getAppConfig().getGroupName());
188+
}
189+
190+
public List<String> getGroupNames() {
191+
return groupNames;
192+
}
186193
}

marklogic-data-hub/src/main/java/com/marklogic/hub/dhs/installer/Options.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ public class Options {
4545
)
4646
private boolean disableSsl;
4747

48+
@Parameter(
49+
names = {"--groups"},
50+
description = "Comma-delimited list of group names that REST options should be copied to, and for which granular " +
51+
"privileges should be created for scheduled tasks"
52+
)
53+
private String groupNames = "Evaluator,Curator,Analyzer,Operator";
54+
55+
@Parameter(
56+
names = {"--servers"},
57+
description = "Comma-delimited list of server names. Search options are expected to be loaded into the first server, and then they " +
58+
"will be copied to the appropriate locations for each of the other servers combined with each of the groups defined by --groups."
59+
)
60+
private String serverNames = "data-hub-STAGING,data-hub-FINAL,data-hub-ANALYTICS,data-hub-ANALYTICS-REST,data-hub-OPERATION,data-hub-OPERATION-REST";
61+
4862
@DynamicParameter(
4963
names = "-P",
5064
description = "Use this argument to include any property supported by DHF; e.g. -PmlHost=somehost"
@@ -98,4 +112,20 @@ public boolean isDisableSsl() {
98112
public void setDisableSsl(boolean disableSsl) {
99113
this.disableSsl = disableSsl;
100114
}
115+
116+
public String getGroupNames() {
117+
return groupNames;
118+
}
119+
120+
public void setGroupNames(String groupNames) {
121+
this.groupNames = groupNames;
122+
}
123+
124+
public String getServerNames() {
125+
return serverNames;
126+
}
127+
128+
public void setServerNames(String serverNames) {
129+
this.serverNames = serverNames;
130+
}
101131
}

marklogic-data-hub/src/main/java/com/marklogic/hub/dhs/installer/command/InstallIntoDhsCommand.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.marklogic.appdeployer.command.security.DeployPrivilegesCommand;
88
import com.marklogic.appdeployer.command.security.DeployRolesCommand;
99
import com.marklogic.appdeployer.command.triggers.DeployTriggersCommand;
10+
import com.marklogic.hub.DatabaseKind;
1011
import com.marklogic.hub.deploy.HubAppDeployer;
1112
import com.marklogic.hub.deploy.commands.*;
1213
import com.marklogic.hub.dhs.installer.Options;
@@ -34,7 +35,7 @@ public void run(ApplicationContext context, Options options) {
3435

3536
String groupName = "Evaluator";
3637
modifyHubConfigForDhs(groupName);
37-
deployer.setCommands(buildCommandsForDhs());
38+
deployer.setCommands(buildCommandsForDhs(options));
3839
deployer.deploy(hubConfig.getAppConfig());
3940

4041
// Update the servers in the Curator group
@@ -50,10 +51,12 @@ public void run(ApplicationContext context, Options options) {
5051
* In the spirit of whitelisting, we'll only setup the commands that we know we need for installing DHF.
5152
* We may need a more broad set of commands for user files.
5253
*/
53-
protected List<Command> buildCommandsForDhs() {
54+
protected List<Command> buildCommandsForDhs(Options options) {
5455
DeployOtherDatabasesCommand dbCommand = new DeployOtherDatabasesCommand();
5556
dbCommand.setDeployDatabaseCommandFactory(new HubDeployDatabaseCommandFactory(hubConfig));
5657

58+
List<String> groupNames = Arrays.asList(options.getGroupNames().split(","));
59+
5760
List<Command> commands = new ArrayList<>();
5861
commands.add(new DeployPrivilegesCommand());
5962

@@ -82,10 +85,12 @@ protected List<Command> buildCommandsForDhs() {
8285
// another DatabaseClient, which the Versions class will do.
8386
commands.add(new GenerateFunctionMetadataCommand(hubConfig, true));
8487

85-
commands.add(new CopyQueryOptionsCommand(hubConfig));
88+
commands.add(new CopyQueryOptionsCommand(hubConfig, groupNames,
89+
Arrays.asList(options.getServerNames().split(",")), hubConfig.getDbName(DatabaseKind.JOB)
90+
));
8691
commands.add(new UpdateDhsModulesPermissionsCommand(hubConfig));
8792

88-
commands.add(new CreateGranularPrivilegesCommand(hubConfig));
93+
commands.add(new CreateGranularPrivilegesCommand(hubConfig, groupNames));
8994

9095
return commands;
9196
}

marklogic-data-hub/src/main/java/com/marklogic/hub/dhs/installer/deploy/CopyQueryOptionsCommand.java

Lines changed: 75 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,61 +6,99 @@
66
import com.marklogic.hub.HubConfig;
77
import com.marklogic.hub.deploy.commands.LoadUserModulesCommand;
88

9+
import java.util.List;
10+
import java.util.stream.Collectors;
11+
912
public class CopyQueryOptionsCommand extends AbstractCommand {
1013

1114
private HubConfig hubConfig;
15+
private List<String> groupNames;
16+
private List<String> serverNames;
17+
private String jobDatabaseName;
18+
19+
private String scriptResponse;
1220

13-
public CopyQueryOptionsCommand(HubConfig hubConfig) {
21+
public CopyQueryOptionsCommand(HubConfig hubConfig, List<String> groupNames, List<String> serverNames, String jobDatabaseName) {
1422
this.hubConfig = hubConfig;
23+
this.groupNames = groupNames;
24+
this.serverNames = serverNames;
25+
this.jobDatabaseName = jobDatabaseName;
1526

1627
// Need to run this after the contents of ml-modules-final is loaded
1728
setExecuteSortOrder(new LoadUserModulesCommand().getExecuteSortOrder() + 1);
1829
}
1930

2031
@Override
2132
public void execute(CommandContext context) {
22-
String script = "declareUpdate();\n" +
23-
"[\n" +
24-
" '/Evaluator/data-hub-JOBS/rest-api/options/jobs.xml',\n" +
25-
" '/Evaluator/data-hub-JOBS/rest-api/options/traces.xml',\n" +
26-
" '/Evaluator/data-hub-STAGING/rest-api/options/default.xml',\n" +
27-
" '/Evaluator/data-hub-STAGING/rest-api/options/exp-default.xml'\n" +
28-
"].forEach(uri => {\n" +
29-
" if (fn.docAvailable(uri)) { console.log('Reproducing: ' + uri); xdmp.documentInsert(uri.replace('Evaluator', 'Curator'), cts.doc(uri), \n" +
30-
" xdmp.documentGetPermissions(uri), xdmp.documentGetCollections(uri));}\n" +
31-
"});\n" +
32-
33-
"\n" +
34-
"const stagingUri = '/Evaluator/data-hub-STAGING/rest-api/options/default.xml';\n" +
35-
"if (fn.docAvailable(stagingUri)) { " +
36-
" xdmp.documentInsert('/Evaluator/data-hub-FINAL/rest-api/options/default.xml', cts.doc(stagingUri), xdmp.documentGetPermissions(stagingUri), xdmp.documentGetCollections(stagingUri));\n" +
37-
" xdmp.documentInsert('/Curator/data-hub-FINAL/rest-api/options/default.xml', cts.doc(stagingUri), xdmp.documentGetPermissions(stagingUri), xdmp.documentGetCollections(stagingUri));" +
38-
"}\n\n" +
39-
40-
"const explorerUri = '/Evaluator/data-hub-STAGING/rest-api/options/exp-default.xml';\n" +
41-
"if (fn.docAvailable(explorerUri)) { " +
42-
" xdmp.documentInsert('/Evaluator/data-hub-FINAL/rest-api/options/exp-default.xml', cts.doc(explorerUri), xdmp.documentGetPermissions(explorerUri), xdmp.documentGetCollections(explorerUri));\n" +
43-
" xdmp.documentInsert('/Curator/data-hub-FINAL/rest-api/options/exp-default.xml', cts.doc(explorerUri), xdmp.documentGetPermissions(explorerUri), xdmp.documentGetCollections(explorerUri));" +
44-
"}\n\n" +
45-
46-
"[\n" +
47-
" '/Analyzer/data-hub-ANALYTICS/rest-api/options/default.xml',\n" +
48-
" '/Analyzer/data-hub-ANALYTICS-REST/rest-api/options/default.xml',\n" +
49-
" '/Operator/data-hub-OPERATION/rest-api/options/default.xml',\n" +
50-
" '/Operator/data-hub-OPERATION-REST/rest-api/options/default.xml',\n" +
51-
" '/Evaluator/data-hub-ANALYTICS/rest-api/options/default.xml',\n" +
52-
" '/Evaluator/data-hub-OPERATION/rest-api/options/default.xml'\n" +
53-
"].forEach(uri => {\n" +
54-
" if (fn.docAvailable(stagingUri)) {console.log('Inserting: ' + uri); xdmp.documentInsert(uri, cts.doc(stagingUri), xdmp.documentGetPermissions(stagingUri), \n" +
55-
" xdmp.documentGetCollections(stagingUri));}\n" +
56-
"})";
33+
final String script = buildScript();
5734

5835
DatabaseClient client = hubConfig.newModulesDbClient();
5936
try {
60-
client.newServerEval().javascript(script).eval().close();
37+
scriptResponse = client.newServerEval().javascript(script)
38+
.addVariable("stagingServer", serverNames.get(0))
39+
.addVariable("jobServer", jobDatabaseName)
40+
.addVariable("groups", groupNames.stream().collect(Collectors.joining(",")))
41+
.addVariable("servers", serverNames.subList(1, serverNames.size()).stream().collect(Collectors.joining(",")))
42+
.evalAs(String.class);
6143
} finally {
6244
client.release();
6345
}
6446

47+
logger.info("Copied search options to the following URIs in the modules database:\n" + scriptResponse);
48+
}
49+
50+
protected String buildScript() {
51+
return "declareUpdate();\n" +
52+
"var stagingServer;\n" +
53+
"var jobServer;\n" +
54+
"var groups;\n" +
55+
"var servers;\n" +
56+
"\n" +
57+
"groups = groups.split(',');\n" +
58+
"servers = servers.split(',');\n" +
59+
"const firstGroup = groups[0];\n" +
60+
"\n" +
61+
"// This array is returned for testing purposes\n" +
62+
"const createdUris = [];\n" +
63+
"\n" +
64+
"let stagingUris = cts.uriMatch('/' + firstGroup + '/' + stagingServer + '/rest-api/options/*').toArray().forEach(uri => {\n" +
65+
" const doc = cts.doc(uri);\n" +
66+
" const perms = xdmp.documentGetPermissions(uri);\n" +
67+
" const collections = xdmp.documentGetCollections(uri);\n" +
68+
" // Copy options from first group to other groups for stagingServer\n" +
69+
" groups.slice(1).map(group => {\n" +
70+
" let newUri = uri.toString().replace('/' + firstGroup + '/', '/' + group + '/');\n" +
71+
" xdmp.documentInsert(newUri, doc, perms, collections);\n" +
72+
" createdUris.push(newUri);\n" +
73+
" });\n" +
74+
" \n" +
75+
" // Copy options to every group for all other servers\n" +
76+
" groups.forEach(group => {\n" +
77+
" servers.forEach(server => {\n" +
78+
" let newUri = uri.toString().replace('/' + firstGroup + '/', '/' + group + '/');\n" +
79+
" newUri = newUri.replace('/' + stagingServer + '/', '/' + server + '/');\n" +
80+
" xdmp.documentInsert(newUri, doc, perms, collections);\n" +
81+
" createdUris.push(newUri);\n" +
82+
" });\n" +
83+
" });\n" +
84+
"});\n" +
85+
"\n" +
86+
"// Copy jobs options to job servers in other groups\n" +
87+
"cts.uriMatch('/' + firstGroup + '/' + jobServer + '/rest-api/options/*').toArray().map(uri => {\n" +
88+
" const doc = cts.doc(uri);\n" +
89+
" const perms = xdmp.documentGetPermissions(uri);\n" +
90+
" const collections = xdmp.documentGetCollections(uri);\n" +
91+
" groups.slice(1).forEach(group => {\n" +
92+
" let newUri = uri.toString().replace('/' + firstGroup + '/', '/' + group + '/');\n" +
93+
" xdmp.documentInsert(newUri, doc, perms, collections);\n" +
94+
" createdUris.push(newUri);\n" +
95+
" });\n" +
96+
"});\n" +
97+
"\n" +
98+
"createdUris;";
99+
}
100+
101+
public String getScriptResponse() {
102+
return scriptResponse;
65103
}
66104
}

marklogic-data-hub/src/test/java/com/marklogic/bootstrap/Installer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ public void bootstrapHub() {
5151
dataHubOperator.setPassword("password");
5252
dataHubOperator.addRole("data-hub-operator");
5353
dataHubOperator.save();
54+
55+
User testAdmin = new User(new API(adminHubConfig.getManageClient()), "test-admin-for-data-hub-tests");
56+
testAdmin.setDescription("This user is intended to be used by DHF tests that require admin or " +
57+
"admin-like capabilities, such as being able to deploy a DHF application");
58+
testAdmin.setPassword("password");
59+
testAdmin.addRole("admin");
60+
testAdmin.save();
5461
}
5562

5663
if (getDataHubAdminConfig().getIsProvisionedEnvironment()) {

marklogic-data-hub/src/test/java/com/marklogic/hub/HubTestBase.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,10 @@ protected HubConfigImpl runAsDataHubOperator() {
459459
return runAsFlowOperator();
460460
}
461461

462+
protected HubConfigImpl runAsAdmin() {
463+
return runAsUser("test-admin-for-data-hub-tests", "password");
464+
}
465+
462466
protected HubConfigImpl runAsUser(String mlUsername, String mlPassword) {
463467
adminHubConfig.setMlUsername(mlUsername);
464468
adminHubConfig.setMlPassword(mlPassword);

0 commit comments

Comments
 (0)