1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.linecorp.centraldogma.server;
18
19 import static com.linecorp.centraldogma.server.auth.AuthConfig.DEFAULT_SESSION_CACHE_SPEC;
20 import static com.linecorp.centraldogma.server.auth.AuthConfig.DEFAULT_SESSION_TIMEOUT_MILLIS;
21 import static com.linecorp.centraldogma.server.auth.AuthConfig.DEFAULT_SESSION_VALIDATION_SCHEDULE;
22 import static com.linecorp.centraldogma.server.internal.storage.repository.RepositoryCache.validateCacheSpec;
23 import static java.util.Objects.requireNonNull;
24
25 import java.io.File;
26 import java.net.InetSocketAddress;
27 import java.time.Duration;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Set;
32
33 import javax.annotation.Nullable;
34
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import com.github.benmanes.caffeine.cache.CaffeineSpec;
39 import com.google.common.collect.ImmutableList;
40 import com.google.common.collect.ImmutableSet;
41 import com.google.common.collect.ImmutableSet.Builder;
42
43 import com.linecorp.armeria.common.Flags;
44 import com.linecorp.armeria.common.SessionProtocol;
45 import com.linecorp.armeria.server.ServerPort;
46 import com.linecorp.centraldogma.internal.Jackson;
47 import com.linecorp.centraldogma.server.auth.AuthConfig;
48 import com.linecorp.centraldogma.server.auth.AuthProvider;
49 import com.linecorp.centraldogma.server.auth.AuthProviderFactory;
50 import com.linecorp.centraldogma.server.auth.Session;
51 import com.linecorp.centraldogma.server.plugin.Plugin;
52 import com.linecorp.centraldogma.server.plugin.PluginConfig;
53 import com.linecorp.centraldogma.server.storage.repository.Repository;
54
55 import io.micrometer.core.instrument.MeterRegistry;
56
57
58
59
60
61
62
63
64
65
66
67
68 public final class CentralDogmaBuilder {
69 private static final Logger logger = LoggerFactory.getLogger(CentralDogmaBuilder.class);
70
71
72 private static final ServerPort DEFAULT_PORT = new ServerPort(36462, SessionProtocol.HTTP);
73
74 static final int DEFAULT_NUM_REPOSITORY_WORKERS = 16;
75 static final long DEFAULT_MAX_REMOVED_REPOSITORY_AGE_MILLIS = 604_800_000;
76
77 public static final String DEFAULT_REPOSITORY_CACHE_SPEC =
78 "maximumWeight=268435456," +
79 "expireAfterAccess=5m";
80
81
82
83
84 private final List<ServerPort> ports = new ArrayList<>(2);
85 @Nullable
86 private TlsConfig tls;
87 private final List<String> trustedProxyAddresses = new ArrayList<>();
88 private final List<String> clientAddressSources = new ArrayList<>();
89 @Nullable
90 private Integer numWorkers;
91 @Nullable
92 private Integer maxNumConnections;
93 @Nullable
94 private Long requestTimeoutMillis;
95 @Nullable
96 private Long idleTimeoutMillis;
97 @Nullable
98 private Integer maxFrameLength;
99
100
101 private final File dataDir;
102 private int numRepositoryWorkers = DEFAULT_NUM_REPOSITORY_WORKERS;
103 private long maxRemovedRepositoryAgeMillis = DEFAULT_MAX_REMOVED_REPOSITORY_AGE_MILLIS;
104
105 @Nullable
106 private String repositoryCacheSpec = DEFAULT_REPOSITORY_CACHE_SPEC;
107 private boolean webAppEnabled = true;
108 @Nullable
109 private String webAppTitle;
110
111 @Nullable
112 private GracefulShutdownTimeout gracefulShutdownTimeout;
113 private ReplicationConfig replicationConfig = ReplicationConfig.NONE;
114 @Nullable
115 private String accessLogFormat;
116
117
118 @Nullable
119 private AuthProviderFactory authProviderFactory;
120 private final ImmutableSet.Builder<String> systemAdministrators = new Builder<>();
121 private boolean caseSensitiveLoginNames;
122 private String sessionCacheSpec = DEFAULT_SESSION_CACHE_SPEC;
123 private long sessionTimeoutMillis = DEFAULT_SESSION_TIMEOUT_MILLIS;
124 private String sessionValidationSchedule = DEFAULT_SESSION_VALIDATION_SCHEDULE;
125 @Nullable
126 private Object authProviderProperties;
127 private MeterRegistry meterRegistry = Flags.meterRegistry();
128
129 @Nullable
130 private CorsConfig corsConfig;
131
132 private final List<PluginConfig> pluginConfigs = new ArrayList<>();
133 private final List<Plugin> plugins = new ArrayList<>();
134 @Nullable
135 private ManagementConfig managementConfig;
136 @Nullable
137 private ZoneConfig zoneConfig;
138
139
140
141
142 public CentralDogmaBuilder(File dataDir) {
143 this.dataDir = requireNonNull(dataDir, "dataDir");
144 if (dataDir.exists() && !dataDir.isDirectory()) {
145 throw new IllegalArgumentException("dataDir: " + dataDir + " (not a directory)");
146 }
147 }
148
149
150
151
152
153
154
155 public CentralDogmaBuilder port(int port, SessionProtocol protocol) {
156 return port(new ServerPort(port, protocol));
157 }
158
159
160
161
162
163
164
165 public CentralDogmaBuilder port(InetSocketAddress localAddress, SessionProtocol protocol) {
166 return port(new ServerPort(localAddress, protocol));
167 }
168
169
170
171
172 public CentralDogmaBuilder port(ServerPort port) {
173 ports.add(requireNonNull(port, "port"));
174 return this;
175 }
176
177
178
179
180 public CentralDogmaBuilder tls(TlsConfig tls) {
181 this.tls = requireNonNull(tls, "tls");
182 return this;
183 }
184
185
186
187
188
189
190
191
192 public CentralDogmaBuilder trustedProxyAddresses(String... exactOrCidrAddresses) {
193 requireNonNull(exactOrCidrAddresses, "exactOrCidrAddresses");
194 trustedProxyAddresses.addAll(ImmutableList.copyOf(exactOrCidrAddresses));
195 return this;
196 }
197
198
199
200
201
202
203
204
205 public CentralDogmaBuilder trustedProxyAddresses(Iterable<String> exactOrCidrAddresses) {
206 requireNonNull(exactOrCidrAddresses, "exactOrCidrAddresses");
207 trustedProxyAddresses.addAll(ImmutableList.copyOf(exactOrCidrAddresses));
208 return this;
209 }
210
211
212
213
214
215
216
217
218
219
220
221
222
223 public CentralDogmaBuilder clientAddressSources(String... clientAddressSources) {
224 requireNonNull(clientAddressSources, "clientAddressSources");
225 this.clientAddressSources.addAll(ImmutableList.copyOf(clientAddressSources));
226 return this;
227 }
228
229
230
231
232
233
234
235
236
237
238
239
240
241 public CentralDogmaBuilder clientAddressSources(Iterable<String> clientAddressSources) {
242 requireNonNull(clientAddressSources, "clientAddressSources");
243 this.clientAddressSources.addAll(ImmutableList.copyOf(clientAddressSources));
244 return this;
245 }
246
247
248
249
250
251 public CentralDogmaBuilder numWorkers(int numWorkers) {
252 this.numWorkers = numWorkers;
253 return this;
254 }
255
256
257
258
259 public CentralDogmaBuilder maxNumConnections(int maxNumConnections) {
260 this.maxNumConnections = maxNumConnections;
261 return this;
262 }
263
264
265
266
267
268
269 public CentralDogmaBuilder requestTimeout(Duration requestTimeout) {
270 return requestTimeoutMillis(requireNonNull(requestTimeout, "requestTimeout").toMillis());
271 }
272
273
274
275
276
277
278 public CentralDogmaBuilder requestTimeoutMillis(long requestTimeoutMillis) {
279 this.requestTimeoutMillis = requestTimeoutMillis;
280 return this;
281 }
282
283
284
285
286
287
288 public CentralDogmaBuilder idleTimeout(Duration idleTimeout) {
289 return idleTimeoutMillis(requireNonNull(idleTimeout, "idleTimeout").toMillis());
290 }
291
292
293
294
295
296 public CentralDogmaBuilder idleTimeoutMillis(long idleTimeoutMillis) {
297 this.idleTimeoutMillis = idleTimeoutMillis;
298 return this;
299 }
300
301
302
303
304 public CentralDogmaBuilder maxFrameLength(int maxFrameLength) {
305 this.maxFrameLength = maxFrameLength;
306 return this;
307 }
308
309
310
311
312
313 public CentralDogmaBuilder numRepositoryWorkers(int numRepositoryWorkers) {
314 this.numRepositoryWorkers = numRepositoryWorkers;
315 return this;
316 }
317
318
319
320
321
322
323 public CentralDogmaBuilder maxRemovedRepositoryAge(Duration maxRemovedRepositoryAge) {
324 maxRemovedRepositoryAgeMillis(
325 requireNonNull(maxRemovedRepositoryAge, "maxRemovedRepositoryAge").toMillis());
326 return this;
327 }
328
329
330
331
332
333
334
335 public CentralDogmaBuilder maxRemovedRepositoryAgeMillis(long maxRemovedRepositoryAgeMillis) {
336 this.maxRemovedRepositoryAgeMillis = maxRemovedRepositoryAgeMillis;
337 return this;
338 }
339
340
341
342
343
344
345
346
347 @Deprecated
348 public CentralDogmaBuilder cacheSpec(String cacheSpec) {
349 repositoryCacheSpec = validateCacheSpec(cacheSpec);
350 return this;
351 }
352
353
354
355
356
357
358 public CentralDogmaBuilder repositoryCacheSpec(String repositoryCacheSpec) {
359 this.repositoryCacheSpec = validateCacheSpec(repositoryCacheSpec);
360 return this;
361 }
362
363
364
365
366
367 public CentralDogmaBuilder webAppEnabled(boolean webAppEnabled) {
368 this.webAppEnabled = webAppEnabled;
369 return this;
370 }
371
372
373
374
375 public CentralDogmaBuilder webAppTitle(String webAppTitle) {
376 this.webAppTitle = requireNonNull(webAppTitle, "webAppTitle");
377 return this;
378 }
379
380
381
382
383 public CentralDogmaBuilder gracefulShutdownTimeout(GracefulShutdownTimeout gracefulShutdownTimeout) {
384 this.gracefulShutdownTimeout = gracefulShutdownTimeout;
385 return this;
386 }
387
388
389
390
391
392 public CentralDogmaBuilder replication(ReplicationConfig replicationConfig) {
393 this.replicationConfig = requireNonNull(replicationConfig, "replicationConfig");
394 return this;
395 }
396
397
398
399
400
401
402 public CentralDogmaBuilder accessLogFormat(String accessLogFormat) {
403 this.accessLogFormat = requireNonNull(accessLogFormat, "accessLogFormat");
404 return this;
405 }
406
407
408
409
410 public CentralDogmaBuilder authProviderFactory(AuthProviderFactory authProviderFactory) {
411 this.authProviderFactory = requireNonNull(authProviderFactory, "authProviderFactory");
412 return this;
413 }
414
415
416
417
418 public CentralDogmaBuilder systemAdministrators(String... systemAdministrators) {
419 requireNonNull(systemAdministrators, "systemAdministrators");
420 for (final String systemAdministrator : systemAdministrators) {
421 this.systemAdministrators.add(systemAdministrator);
422 }
423 return this;
424 }
425
426
427
428
429 public CentralDogmaBuilder systemAdministrators(Iterable<String> systemAdministrators) {
430 requireNonNull(systemAdministrators, "systemAdministrators");
431 this.systemAdministrators.addAll(systemAdministrators);
432 return this;
433 }
434
435
436
437
438 public CentralDogmaBuilder caseSensitiveLoginNames(boolean caseSensitiveLoginNames) {
439 this.caseSensitiveLoginNames = caseSensitiveLoginNames;
440 return this;
441 }
442
443
444
445
446
447
448
449 public CentralDogmaBuilder sessionCacheSpec(String sessionCacheSpec) {
450 this.sessionCacheSpec = validateCacheSpec(sessionCacheSpec);
451 return this;
452 }
453
454
455
456
457
458 public CentralDogmaBuilder sessionTimeoutMillis(long sessionTimeoutMillis) {
459 this.sessionTimeoutMillis = sessionTimeoutMillis;
460 return this;
461 }
462
463
464
465
466
467 public CentralDogmaBuilder sessionTimeout(Duration sessionTimeout) {
468 return sessionTimeoutMillis(
469 requireNonNull(sessionTimeout, "sessionTimeout").toMillis());
470 }
471
472
473
474
475
476 public CentralDogmaBuilder sessionValidationSchedule(String sessionValidationSchedule) {
477 this.sessionValidationSchedule =
478 requireNonNull(sessionValidationSchedule, "sessionValidationSchedule");
479 return this;
480 }
481
482
483
484
485 public CentralDogmaBuilder authProviderProperties(Object authProviderProperties) {
486 this.authProviderProperties = requireNonNull(authProviderProperties, "authProviderProperties");
487 return this;
488 }
489
490
491
492
493 public CentralDogmaBuilder meterRegistry(MeterRegistry meterRegistry) {
494 this.meterRegistry = requireNonNull(meterRegistry, "meterRegistry");
495 return this;
496 }
497
498
499
500
501 public CentralDogmaBuilder cors(String... allowedOrigins) {
502 requireNonNull(allowedOrigins, "allowedOrigins");
503 corsConfig = new CorsConfig(ImmutableList.copyOf(allowedOrigins), null);
504 return this;
505 }
506
507
508
509
510 public CentralDogmaBuilder cors(CorsConfig corsConfig) {
511 this.corsConfig = requireNonNull(corsConfig, "corsConfig");
512 return this;
513 }
514
515
516
517
518 public CentralDogmaBuilder pluginConfigs(PluginConfig... pluginConfigs) {
519 requireNonNull(pluginConfigs, "pluginConfigs");
520 this.pluginConfigs.addAll(ImmutableList.copyOf(pluginConfigs));
521 return this;
522 }
523
524
525
526
527 public List<PluginConfig> pluginConfigs() {
528 return pluginConfigs;
529 }
530
531
532
533
534 public CentralDogmaBuilder plugins(Plugin... plugins) {
535 requireNonNull(plugins, "plugins");
536 return plugins(ImmutableList.copyOf(plugins));
537 }
538
539
540
541
542 public CentralDogmaBuilder plugins(Iterable<? extends Plugin> plugins) {
543 requireNonNull(plugins, "plugins");
544 this.plugins.addAll(ImmutableList.copyOf(plugins));
545 return this;
546 }
547
548
549
550
551 public CentralDogmaBuilder management(ManagementConfig managementConfig) {
552 requireNonNull(managementConfig, "managementConfig");
553 this.managementConfig = managementConfig;
554 return this;
555 }
556
557
558
559
560 public CentralDogmaBuilder zone(ZoneConfig zoneConfig) {
561 requireNonNull(zoneConfig, "zoneConfig");
562 this.zoneConfig = zoneConfig;
563 return this;
564 }
565
566
567
568
569 public CentralDogma build() {
570 return new CentralDogma(buildConfig(), meterRegistry, ImmutableList.copyOf(plugins));
571 }
572
573 private CentralDogmaConfig buildConfig() {
574 final List<ServerPort> ports = !this.ports.isEmpty() ? this.ports
575 : Collections.singletonList(DEFAULT_PORT);
576 final Set<String> systemAdminSet = systemAdministrators.build();
577 final AuthConfig authCfg;
578 if (authProviderFactory != null) {
579 authCfg = new AuthConfig(
580 authProviderFactory, systemAdminSet, caseSensitiveLoginNames,
581 sessionCacheSpec, sessionTimeoutMillis, sessionValidationSchedule,
582 authProviderProperties != null ? Jackson.valueToTree(authProviderProperties) : null);
583 } else {
584 authCfg = null;
585 logger.info("{} is not specified, so {} will not be configured.",
586 AuthProviderFactory.class.getSimpleName(),
587 AuthConfig.class.getSimpleName());
588 }
589
590 return new CentralDogmaConfig(dataDir, ports, tls, trustedProxyAddresses, clientAddressSources,
591 numWorkers, maxNumConnections,
592 requestTimeoutMillis, idleTimeoutMillis, maxFrameLength,
593 numRepositoryWorkers, repositoryCacheSpec,
594 maxRemovedRepositoryAgeMillis, gracefulShutdownTimeout,
595 webAppEnabled, webAppTitle, replicationConfig,
596 null, accessLogFormat, authCfg,
597 corsConfig, pluginConfigs, managementConfig, zoneConfig);
598 }
599 }