Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15488649
D15701.id37844.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
17 KB
Referenced Files
None
Subscribers
None
D15701.id37844.diff
View Options
diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@
/conf/keys/device.pub
/conf/keys/device.key
/conf/keys/device.id
+/conf/aphlict/aphlict.custom.json
# Impact Font
/resources/font/impact.ttf
diff --git a/conf/aphlict/README b/conf/aphlict/README
new file mode 100644
--- /dev/null
+++ b/conf/aphlict/README
@@ -0,0 +1,16 @@
+To customize this configuration, you have two options: create a custom
+configuration file in this directory, or specify a path to a configuration file
+explicitly when starting Aphlict.
+
+To create a custom configuration file, copy `aphlict.default.json` in this
+directory and rename it `aphlict.custom.json`. If this file exists, it will
+be read by default.
+
+To specify a path when starting Aphlict, use the `--config` flag:
+
+ phabricator/ $ ./bin/aphlict start --config path/to/config.json
+
+Specifying a configuration file explicitly overrides default configuration.
+
+For more information about configuring notifications, see the article
+"Notifications User Guide: Setup and Configuration" in the documentation.
diff --git a/conf/aphlict/aphlict.default.json b/conf/aphlict/aphlict.default.json
new file mode 100644
--- /dev/null
+++ b/conf/aphlict/aphlict.default.json
@@ -0,0 +1,18 @@
+{
+ "servers": [
+ {
+ "type": "client",
+ "port": 22280,
+ "listen": "0.0.0.0",
+ "ssl.key": null,
+ "ssl.cert": null
+ },
+ {
+ "type": "admin",
+ "port": 22281,
+ "listen": "127.0.0.1",
+ "ssl.key": null,
+ "ssl.cert": null
+ }
+ ]
+}
diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
--- a/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
+++ b/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php
@@ -4,8 +4,7 @@
extends PhabricatorManagementWorkflow {
private $debug = false;
- private $clientHost;
- private $clientPort;
+ private $configPath;
final protected function setDebug($debug) {
$this->debug = $debug;
@@ -15,21 +14,167 @@
protected function getLaunchArguments() {
return array(
array(
- 'name' => 'client-host',
- 'param' => 'hostname',
- 'help' => pht('Hostname to bind to for the client server.'),
- ),
- array(
- 'name' => 'client-port',
- 'param' => 'port',
- 'help' => pht('Port to bind to for the client server.'),
+ 'name' => 'config',
+ 'param' => 'file',
+ 'help' => pht(
+ 'Use a specific configuration file instead of the default '.
+ 'configuration.'),
),
);
}
protected function parseLaunchArguments(PhutilArgumentParser $args) {
- $this->clientHost = $args->getArg('client-host');
- $this->clientPort = $args->getArg('client-port');
+ $config_file = $args->getArg('config');
+ if ($config_file) {
+ $full_path = Filesystem::resolvePath($config_file);
+ $show_path = $full_path;
+ } else {
+ $root = dirname(dirname(phutil_get_library_root('phabricator')));
+
+ $try = array(
+ 'phabricator/conf/aphlict/aphlict.custom.json',
+ 'phabricator/conf/aphlict/aphlict.default.json',
+ );
+
+ foreach ($try as $config) {
+ $full_path = $root.'/'.$config;
+ $show_path = $config;
+ if (Filesystem::pathExists($full_path)) {
+ break;
+ }
+ }
+ }
+
+ echo tsprintf(
+ "%s\n",
+ pht(
+ 'Reading configuration from: %s',
+ $show_path));
+
+ try {
+ $data = Filesystem::readFile($full_path);
+ } catch (Exception $ex) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Failed to read configuration file. %s',
+ $ex->getMessage()));
+ }
+
+ try {
+ $data = phutil_json_decode($data);
+ } catch (Exception $ex) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Configuration file is not properly formatted JSON. %s',
+ $ex->getMessage()));
+ }
+
+ try {
+ PhutilTypeSpec::checkMap(
+ $data,
+ array(
+ 'servers' => 'list<wild>',
+ ));
+ } catch (Exception $ex) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Configuration file has improper configuration keys at top '.
+ 'level. %s',
+ $ex->getMessage()));
+ }
+
+ $servers = $data['servers'];
+ $has_client = false;
+ $has_admin = false;
+ $port_map = array();
+ foreach ($servers as $index => $server) {
+ PhutilTypeSpec::checkMap(
+ $server,
+ array(
+ 'type' => 'string',
+ 'port' => 'int',
+ 'listen' => 'optional string|null',
+ 'ssl.key' => 'optional string|null',
+ 'ssl.cert' => 'optional string|null',
+ ));
+
+ $port = $server['port'];
+ if (!isset($port_map[$port])) {
+ $port_map[$port] = $index;
+ } else {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Two servers (at indexes "%s" and "%s") both bind to the same '.
+ 'port ("%s"). Each server must bind to a unique port.',
+ $port_map[$port],
+ $index,
+ $port));
+ }
+
+ $type = $server['type'];
+ switch ($type) {
+ case 'admin':
+ $has_admin = true;
+ break;
+ case 'client':
+ $has_client = true;
+ break;
+ default:
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'A specified server (at index "%s", on port "%s") has an '.
+ 'invalid type ("%s"). Valid types are: admin, client.',
+ $index,
+ $port,
+ $type));
+ }
+
+ $ssl_key = idx($server, 'ssl.key');
+ $ssl_cert = idx($server, 'ssl.cert');
+ if (($ssl_key && !$ssl_cert) || ($ssl_cert && !$ssl_key)) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'A specified server (at index "%s", on port "%s") specifies '.
+ 'only one of "%s" and "%s". Each server must specify neither '.
+ '(to disable SSL) or specify both (to enable it).',
+ $index,
+ $port,
+ 'ssl.key',
+ 'ssl.cert'));
+ }
+ }
+
+ if (!$servers) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Configuration file does not specify any servers. This service '.
+ 'will not be able to interact with the outside world if it does '.
+ 'not listen on any ports. You must specify at least one "%s" '.
+ 'server and at least one "%s" server.',
+ 'admin',
+ 'client'));
+ }
+
+ if (!$has_client) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Configuration file does not specify any client servers. This '.
+ 'service will be unable to transmit any notifications without a '.
+ 'client server. You must specify at least one server with '.
+ 'type "%s".',
+ 'client'));
+ }
+
+ if (!$has_admin) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Configuration file does not specify any administrative '.
+ 'servers. This service will be unable to receive messages. '.
+ 'You must specify at least one server with type "%s".',
+ 'admin'));
+ }
+
+ $this->configPath = $full_path;
}
final public function getPIDPath() {
@@ -148,38 +293,12 @@
}
private function getServerArgv() {
- $ssl_key = PhabricatorEnv::getEnvConfig('notification.ssl-key');
- $ssl_cert = PhabricatorEnv::getEnvConfig('notification.ssl-cert');
-
- $server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri');
- $server_uri = new PhutilURI($server_uri);
-
- $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
- $client_uri = new PhutilURI($client_uri);
-
$log = $this->getLogPath();
$server_argv = array();
- $server_argv[] = '--client-port='.coalesce(
- $this->clientPort,
- $client_uri->getPort());
- $server_argv[] = '--admin-port='.$server_uri->getPort();
- $server_argv[] = '--admin-host='.$server_uri->getDomain();
-
- if ($ssl_key) {
- $server_argv[] = '--ssl-key='.$ssl_key;
- }
-
- if ($ssl_cert) {
- $server_argv[] = '--ssl-cert='.$ssl_cert;
- }
-
+ $server_argv[] = '--config='.$this->configPath;
$server_argv[] = '--log='.$log;
- if ($this->clientHost) {
- $server_argv[] = '--client-host='.$this->clientHost;
- }
-
return $server_argv;
}
diff --git a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
--- a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
+++ b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
@@ -182,6 +182,10 @@
'Garbage collectors are now configured with "%s".',
'bin/garbage set-policy');
+ $aphlict_reason = pht(
+ 'Configuration of the notification server has changed substantially. '.
+ 'For discussion, see T10794.');
+
$ancient_config += array(
'phid.external-loaders' =>
pht(
@@ -298,6 +302,9 @@
'phd.variant-config' => pht(
'This configuration is no longer relevant because daemons '.
'restart automatically on configuration changes.'),
+
+ 'notification.ssl-cert' => $aphlict_reason,
+ 'notification.ssl-key' => $aphlict_reason,
);
return $ancient_config;
diff --git a/src/applications/config/option/PhabricatorNotificationConfigOptions.php b/src/applications/config/option/PhabricatorNotificationConfigOptions.php
--- a/src/applications/config/option/PhabricatorNotificationConfigOptions.php
+++ b/src/applications/config/option/PhabricatorNotificationConfigOptions.php
@@ -46,14 +46,6 @@
->setDescription(pht('Location of the notification receiver server.')),
$this->newOption('notification.log', 'string', '/var/log/aphlict.log')
->setDescription(pht('Location of the server log file.')),
- $this->newOption('notification.ssl-key', 'string', null)
- ->setLocked(true)
- ->setDescription(
- pht('Path to SSL key to use for secure WebSockets.')),
- $this->newOption('notification.ssl-cert', 'string', null)
- ->setLocked(true)
- ->setDescription(
- pht('Path to SSL certificate to use for secure WebSockets.')),
$this->newOption(
'notification.pidfile',
'string',
diff --git a/src/docs/user/configuration/notifications.diviner b/src/docs/user/configuration/notifications.diviner
--- a/src/docs/user/configuration/notifications.diviner
+++ b/src/docs/user/configuration/notifications.diviner
@@ -59,19 +59,44 @@
phabricator/ $ bin/aphlict start
-The server must be able to listen on port **22280** for Aphlict to work. In
-particular, if you're running in EC2, you need to unblock this port in the
-server's security group configuration. You can change this port in the
-`notification.client-uri` config.
+By default, the server must be able to listen on port `22280`. If you're using
+a host firewall (like a security group in EC2), make sure traffic can reach the
+server.
+
+The server configuration is controlled by a configuration file, which is
+separate from Phabricator's configuration settings. The default file can
+be found at `phabricator/conf/aphlict/aphlict.default.json`.
+
+To make adjustments to the default configuration, either copy this file to
+create `aphlict.custom.json` in the same directory (this file will be used if
+it exists) or specify a configuration file explicitly with the `--config` flag:
+
+ phabricator/ $ bin/aphlict start --config path/to/config.json
+
+The configuration file has these settings:
-You may need to adjust these settings:
+ - `servers`: A list of servers to start.
- - `notification.ssl-cert` Point this at an SSL certificate for secure
- WebSockets.
- - `notification.ssl-key` Point this at an SSL keyfile for secure WebSockets.
+Each server in the `servers` list should be an object with these keys:
-In particular, if your server uses HTTPS, you **must** configure these options.
-Browsers will not allow you to use non-SSL websockets from an SSL web page.
+ - `type`: //Required string.// The type of server to start. Options are
+ `admin` or `client`. Normally, you should run one of each.
+ - `port`: //Required int.// The port this server should listen on.
+ - `listen`: //Optional string.// Which interface to bind to. By default,
+ the `admin` server is bound to localhost (so only other services on the
+ local machine can connect to it), while the `client` server is bound
+ to `0.0.0.0` (so any client can connect.
+ - `ssl.key`: //Optional string.// If you want to use SSL on this port,
+ the path to an SSL key.
+ - `ssl.cert`: //Optional string.// If you want to use SSL on this port,
+ the path to an SSL certificate.
+
+The defaults are appropriate for simple cases, but you may need to adjust them
+if you are running a more complex configuration.
+
+
+Configuring Phabricator
+=======================
You may also want to adjust these settings:
diff --git a/support/aphlict/server/aphlict_server.js b/support/aphlict/server/aphlict_server.js
--- a/support/aphlict/server/aphlict_server.js
+++ b/support/aphlict/server/aphlict_server.js
@@ -7,15 +7,10 @@
var fs = require('fs');
function parse_command_line_arguments(argv) {
- var config = {
- 'client-port': 22280,
- 'admin-port': 22281,
- 'client-host': '0.0.0.0',
- 'admin-host': '127.0.0.1',
+ var args = {
log: '/var/log/aphlict.log',
- 'ssl-key': null,
- 'ssl-cert': null,
- test: false
+ test: false,
+ config: null
};
for (var ii = 2; ii < argv.length; ii++) {
@@ -24,16 +19,18 @@
if (!matches) {
throw new Error('Unknown argument "' + arg + '"!');
}
- if (!(matches[1] in config)) {
+ if (!(matches[1] in args)) {
throw new Error('Unknown argument "' + matches[1] + '"!');
}
- config[matches[1]] = matches[2];
+ args[matches[1]] = matches[2];
}
- config['client-port'] = parseInt(config['client-port'], 10);
- config['admin-port'] = parseInt(config['admin-port'], 10);
+ return args;
+}
- return config;
+function parse_config(args) {
+ var data = fs.readFileSync(args.config);
+ return JSON.parse(data);
}
require('./lib/AphlictLog');
@@ -41,7 +38,8 @@
var debug = new JX.AphlictLog()
.addConsole(console);
-var config = parse_command_line_arguments(process.argv);
+var args = parse_command_line_arguments(process.argv);
+var config = parse_config(args);
function set_exit_code(code) {
process.on('exit', function() {
@@ -51,7 +49,7 @@
process.on('uncaughtException', function(err) {
var context = null;
- if (err.code == 'EACCES' && err.path == config.log) {
+ if (err.code == 'EACCES' && err.path == args.log) {
context = util.format(
'Unable to open logfile ("%s"). Check that permissions are set ' +
'correctly.',
@@ -71,8 +69,8 @@
});
// Add the logfile so we'll fail if we can't write to it.
-if (config.log) {
- debug.addLog(config.log);
+if (args.log) {
+ debug.addLog(args.log);
}
try {
@@ -90,51 +88,37 @@
require('./lib/AphlictAdminServer');
require('./lib/AphlictClientServer');
-var ssl_config = {
- enabled: (config['ssl-key'] || config['ssl-cert'])
-};
-
-// Load the SSL certificates (if any were provided) now, so that runs with
-// `--test` will see any errors.
-if (ssl_config.enabled) {
- ssl_config.key = fs.readFileSync(config['ssl-key']);
- ssl_config.cert = fs.readFileSync(config['ssl-cert']);
-} else {
- ssl_config.key = null;
- ssl_config.cert = null;
-}
-
+var ii;
var servers = [];
+for (ii = 0; ii < config.servers.length; ii++) {
+ var spec = config.servers[ii];
-servers.push({
- type: 'client',
- port: config['client-port'],
- listen: config['client-host'],
- 'ssl.key': ssl_config.key,
- 'ssl.certificate': ssl_config.cert
-});
+ spec.listen = spec.listen || '0.0.0.0';
-servers.push({
- type: 'admin',
- port: config['admin-port'],
- listen: config['admin-host'],
- 'ssl.key': null,
- 'ssl.cert': null
-});
+ if (spec['ssl.key']) {
+ spec['ssl.key'] = fs.readFileSync(spec['ssl.key']);
+ }
+
+ if (spec['ssl.cert']){
+ spec['ssl.cert'] = fs.readFileSync(spec['ssl.cert']);
+ }
+
+ servers.push(spec);
+}
// If we're just doing a configuration test, exit here before starting any
// servers.
-if (config.test) {
+if (args.test) {
debug.log('Configuration test OK.');
set_exit_code(0);
return;
}
+debug.log('Starting servers (service PID %d).', process.pid);
+
var aphlict_servers = [];
var aphlict_clients = [];
var aphlict_admins = [];
-
-var ii;
for (ii = 0; ii < servers.length; ii++) {
var server = servers[ii];
var is_client = (server.type == 'client');
@@ -161,6 +145,12 @@
aphlict_server.setLogger(debug);
aphlict_server.listen(server.port, server.listen);
+ debug.log(
+ 'Started %s server (Port %d, %s).',
+ server.type,
+ server.port,
+ server['ssl.key'] ? 'With SSL' : 'No SSL');
+
aphlict_servers.push(aphlict_server);
if (is_client) {
@@ -174,5 +164,3 @@
var admin_server = aphlict_admins[ii];
admin_server.setClientServers(aphlict_clients);
}
-
-debug.log('Started Server (PID %d)', process.pid);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 12, 12:49 AM (1 w, 2 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7223557
Default Alt Text
D15701.id37844.diff (17 KB)
Attached To
Mode
D15701: Move server-related Aphlict options to a configuration file
Attached
Detach File
Event Timeline
Log In to Comment