This repository has been archived by the owner on Aug 9, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathService.java
372 lines (343 loc) · 12.1 KB
/
Service.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.io.*;
import java.util.*;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
public class Service {
private File workingdir;
private String id;
private Queue<String> stdOut = new LinkedList<String>();
private Queue<String> stdErr = new LinkedList<String>();
// Whether the service refers to this program
private final boolean isMaster;
// A list of the commands which can be run for this service
private Map<String, Command> commands = new HashMap<String, Command>();
private ServiceSettings settings = new ServiceSettings();
// A list of all the services
private static Map<String, Service> serviceList = new HashMap<String, Service>();
private Service(String id, File workingdir) {
this.isMaster = id.equals("services");
this.workingdir = workingdir;
this.id = id;
commands.put("clearlog", new ClearLogCommand(this));
commands.put("reloadconfig", new ReloadConfigCommand(this));
this.updateFromConfig();
// The "services" service (ie this program) is already running
if (isMaster) {
commands.put("reloadservicelist", new ReloadServiceListCommand(this));
commands.put("updatevarnish", new UpdateVarnishCommand(this));
// For other services, start the start command
} else {
commands.put("start", new StartCommand(this));
commands.put("stop", new StopCommand(this));
commands.put("restart", new RestartCommand(this));
execCommand("start");
}
}
public void updateFromConfig() {
File settingsFile = new File(this.workingdir, Manager.getSetting("service_json", "service.json"));
Map<String,String> serviceDirList;
try {
String json = Manager.readFile(new FileInputStream(settingsFile));
Gson gson = new Gson();
settings = gson.fromJson(json, ServiceSettings.class);
} catch (FileNotFoundException e) {
logErr("Can't find service settings file: ".concat(settingsFile.getAbsolutePath()));
return;
} catch (IOException e) {
logErr("Can't read service settings file: ".concat(settingsFile.getAbsolutePath()));
return;
} catch (JsonSyntaxException e) {
logErr("Invalid JSON in service settings file: ".concat(settingsFile.getAbsolutePath()));
return;
} catch (JsonParseException e) {
logErr("Invalid format in service settings file: ".concat(settingsFile.getAbsolutePath()));
return;
}
Iterator iter = settings.getCommands().entrySet().iterator();
while (iter.hasNext()) {
Map.Entry header = (Map.Entry)iter.next();
String cmd = (String)header.getValue();
String name = (String)header.getKey();
String key = name.toLowerCase();
if (commands.containsKey(key)) {
commands.get(key).update(cmd, name);
} else {
Command command = new Command(this, cmd, name);
commands.put(key, command);
}
}
// TODO: remove any commands which have been removed from JSON
if (settings.name == null) logErr("Missing name in settings file: ".concat(settingsFile.getAbsolutePath()));
}
public int getPort() {
return settings.port;
}
public String getName() {
if (settings.name == null) return id;
return settings.name;
}
public File getWorkingDir() {
return workingdir;
}
public void log(String line) {
if (isMaster || id.equals("auth")) System.out.println(line);
int outputLength;
try {
outputLength = Integer.parseInt(Manager.getSetting("output_length"));
} catch (NumberFormatException e) {
outputLength = 10;
}
stdOut.add(line);
while (stdOut.size() > outputLength) stdOut.remove();
}
public void logErr(String line) {
if (settings.combinestdouterr) {
log(line);
return;
}
if (isMaster || id.equals("auth")) System.err.println(line);
int outputLength;
try {
outputLength = Integer.parseInt(Manager.getSetting("output_length"));
} catch (NumberFormatException e) {
outputLength = 10;
}
stdErr.add(line);
while (stdErr.size() > outputLength) stdErr.remove();
}
public void logErr(Exception e) {
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
e.printStackTrace(printWriter);
logErr(writer.toString());
}
void clearLog() {
stdErr.clear();
stdOut.clear();
}
public boolean execCommand(String key) {
return execCommand(key, false);
}
public boolean execCommand(String key, boolean keepRunning) {
Command command = commands.get(key);
if (command == null) {
logErr("Can't find command '"+key+"'");
return false;
}
command.exec(keepRunning);
return true;
}
public void stopCommand(String key) {
Command command = commands.get(key);
if (command == null) return;
command.kill();
}
public boolean isRunning() {
if (isMaster) return true;
if (!commands.containsKey("main")) return false;
return commands.get("main").isRunning();
}
public boolean hasError() {
return (stdErr.size() > 0);
}
public String getId() {
return id;
}
public String getDomain() {
return settings.getDomain();
}
public Template getFullTemplate() throws IOException {
Template serviceTemplate = new Template("service");
setBasicData(serviceTemplate);
setExtendedData(serviceTemplate);
return serviceTemplate;
}
public Template getItemTemplate() throws IOException {
Template serviceTemplate = new Template("serviceitem");
setBasicData(serviceTemplate);
return serviceTemplate;
}
public Template getVCLBackend() throws IOException {
Template backendTemplate = new Template("backend", "vcl");
setBasicData(backendTemplate);
return backendTemplate;
}
public Template getVCLRecvHost() throws IOException {
Template recvHostTemplate = new Template("recvhost", "vcl");
setBasicData(recvHostTemplate);
String customvcl = null;
if (settings.disablecaching) {
customvcl = "return (pass); #turn off caching for now";
}
recvHostTemplate.setData("custom", customvcl);
return recvHostTemplate;
}
private void setBasicData(Template template) {
template.setData("port", this.getPort()+"");
template.setData("path", workingdir.getAbsolutePath());
template.setData("name", this.getName());
template.setData("running", (this.isRunning())?"running":"stopped");
template.setData("domain", this.getDomain());
template.setData("error", this.hasError()?"error":"");
template.setData("url", "/services/"+this.getId());
template.setData("id", this.getId());
}
private void setExtendedData(Template template) throws IOException {
// Create a copy of the stdOut list in an attempt to prevent Concurrency Errors (as commands may be writing to it whilst this iterates through)
Queue<String> stdOutCopy = new LinkedList<String>(stdOut);
Iterator<String> outIter = stdOutCopy.iterator();
String stdOutContent = "";
while (outIter.hasNext()) {
stdOutContent += outIter.next();
stdOutContent += "\n";
}
template.setData("stdOut", stdOutContent);
Queue<String> stdErrCopy = new LinkedList<String>(stdErr);
Iterator<String> errIter = stdErrCopy.iterator();
String stdErrContent = "";
while (errIter.hasNext()) {
stdErrContent += errIter.next();
stdErrContent += "\n";
}
template.setData("stdErr", stdErrContent);
Iterator<Map.Entry<String, Command>> commandIter = commands.entrySet().iterator();
TemplateGroup commandTemplates = new TemplateGroup("html");
while (commandIter.hasNext()) {
Map.Entry<String, Command> header = commandIter.next();
String key = header.getKey();
Command command = header.getValue();
Template commandTemplate = new Template("commanditem");
// Ignore the main command, as it's wrapped by Start/Stop/Restart
if (key.equals("main")) continue;
commandTemplate.setData("action", "/services/"+this.getId()+"/"+key);
commandTemplate.setData("name", command.getName());
commandTemplates.add(commandTemplate);
}
template.setData("commandlist", commandTemplates);
if (settings.combinestdouterr) template.setData("outputclass", "combinestdouterr");
}
public static Template getIndexTemplate() {
try {
Template indexTemplate = new Template("index");
TemplateGroup serviceTemplates = new TemplateGroup("html");
Iterator<Service> iter = serviceList.values().iterator();
while (iter.hasNext()) {
Service service = iter.next();
serviceTemplates.add(service.getItemTemplate());
}
indexTemplate.setData("servicelist", serviceTemplates);
return indexTemplate;
} catch (IOException e) {
Manager.logErr("Problem with index template");
Manager.logErr(e);
return null;
}
}
public static Template getVCL() {
try {
Template vclTemplate = new Template("services", "vcl");
TemplateGroup backendTemplates = new TemplateGroup("vcl");
TemplateGroup recvHostTemplates = new TemplateGroup("vcl");
Iterator<Service> iter = serviceList.values().iterator();
while (iter.hasNext()) {
Service service = iter.next();
backendTemplates.add(service.getVCLBackend());
recvHostTemplates.add(service.getVCLRecvHost());
}
vclTemplate.setData("backends", backendTemplates);
vclTemplate.setData("recvhosts", recvHostTemplates);
return vclTemplate;
} catch (IOException e) {
Manager.logErr("Problem with index template");
Manager.logErr(e);
return null;
}
}
/**
* Returns a mapping of all the services (running and not) and their domains
*/
public static Map getHosts() {
Map<String, String> hosts = new HashMap<String, String>();
Iterator<Service> iter = serviceList.values().iterator();
while (iter.hasNext()) {
Service service = iter.next();
hosts.put(service.getId(), service.getDomain());
}
return hosts;
}
/**
* Loads the Service for the currently running Service (this is quite meta, but allows for easy logging etc)
*
* @returns Service
*/
public static Service loadServicesService() {
Service services = new Service("services", new File("."));
serviceList.put("services", services);
return services;
}
/**
* Loads all the services in the service list
*
* @returns void
*/
public static void loadServiceList() {
File serviceListFile = new File (Manager.getSetting("root_path", ""), Manager.getSetting("service_list", "service_list.json"));
Map<String,String> serviceDirList;
try {
String json = Manager.readFile(new FileInputStream(serviceListFile));
Type listType = new TypeToken<HashMap<String,String>>(){}.getType();
Gson gson = new Gson();
serviceDirList = gson.fromJson(json, listType);
} catch (FileNotFoundException e) {
Manager.logErr("Can't find service list file: ".concat(serviceListFile.getAbsolutePath()));
return;
} catch (IOException e) {
Manager.logErr("Can't read service list file: ".concat(serviceListFile.getAbsolutePath()));
return;
} catch (JsonSyntaxException e) {
Manager.logErr("Invalid JSON in service list file: ".concat(serviceListFile.getAbsolutePath()));
return;
} catch (JsonParseException e) {
Manager.logErr("Invalid format in service list file (should be an object of key/value pairs): ".concat(serviceListFile.getAbsolutePath()));
return;
}
for (Map.Entry<String,String> entry : serviceDirList.entrySet()) {
String serviceKey = entry.getKey();
if (serviceList.containsKey(serviceKey)) {
serviceList.get(serviceKey).updateFromConfig();
} else {
File directory = new File(Manager.getSetting("root_path", ""), entry.getValue());
Service service = new Service(serviceKey, directory);
serviceList.put(serviceKey, service);
}
}
Manager.updateVarnish();
}
public static Service getById(String id) {
Service service = serviceList.get(id);
if (service == null) throw new RuntimeException("Can't find " + id + " service");
return service;
}
static class ServiceSettings {
public int port;
public String name;
public boolean disablecaching;
public boolean combinestdouterr;
private Map<String, String> commands;
private String subdomain;
private String domain;
public Map<String, String> getCommands() {
if (commands == null) return new HashMap<String, String>();
return commands;
}
public String getDomain() {
if (domain != null) return domain;
String rootdomain = Manager.getSetting("root_domain", "example.com");
if (subdomain == null || subdomain.equals("")) return rootdomain;
return subdomain + "." +rootdomain;
}
}
}