mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/arangodb/arangodb into devel
This commit is contained in:
commit
ed132992ea
|
@ -8,7 +8,7 @@ For a full example of sessions with authentication and registration see the exam
|
|||
|
||||
!SECTION Creating an authenticator
|
||||
|
||||
`auth([options]): Authenticator`
|
||||
`createAuth([options]): Authenticator`
|
||||
|
||||
Creates an authenticator.
|
||||
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
!CHAPTER OAuth 2.0
|
||||
|
||||
`const createOAuth2Client = require('@arangodb/foxx/oauth2');`
|
||||
|
||||
The OAuth2 module provides abstractions over OAuth2 providers like Facebook, GitHub and Google.
|
||||
|
||||
**Examples**
|
||||
|
||||
The following extends the [user management example](Users.md):
|
||||
|
||||
```js
|
||||
const crypto = require('@arangodb/crypto');
|
||||
const router = createRouter();
|
||||
const oauth2 = createOAuth2Client({
|
||||
// We'll use Facebook for this example
|
||||
authEndpoint: 'https://www.facebook.com/dialog/oauth',
|
||||
tokenEndpoint: 'https://graph.facebook.com/oauth/access_token',
|
||||
activeUserEndpoint: 'https://graph.facebook.com/v2.0/me',
|
||||
clientId: 'keyboardcat',
|
||||
clientSecret: 'keyboardcat'
|
||||
});
|
||||
|
||||
module.context.use('/oauth2', router);
|
||||
|
||||
// See the user management example for setting up the
|
||||
// sessions and users objects used in this example
|
||||
router.use(sessions);
|
||||
|
||||
router.post('/auth', function (req, res) {
|
||||
const csrfToken = crypto.genRandomAlphaNumbers(32);
|
||||
const url = req.reverse('oauth2_callback', {csrfToken});
|
||||
const redirect_uri = req.makeAbsolute(url);
|
||||
// Set CSRF cookie for five minutes
|
||||
res.cookie('oauth2_csrf_token', csrfToken, {ttl: 60 * 5});
|
||||
// Redirect to the provider's authorization URL
|
||||
res.redirect(303, oauth2.getAuthUrl(url));
|
||||
});
|
||||
|
||||
router.get('/auth', function (req, res) {
|
||||
// Some providers pass errors as query parameter
|
||||
if (req.queryParams.error) {
|
||||
res.throw(500, `Provider error: ${req.queryParams.error}`)
|
||||
}
|
||||
// Make sure CSRF cookie matches the URL
|
||||
const expectedToken = req.cookie('oauth2_csrf_token');
|
||||
if (!expectedToken || req.queryParams.csrfToken !== expectedToken) {
|
||||
res.throw(400, 'CSRF mismatch.');
|
||||
}
|
||||
// Make sure the URL contains a grant token
|
||||
if (!req.queryParams.code) {
|
||||
res.throw(400, 'Provider did not pass grant token.');
|
||||
}
|
||||
// Reconstruct the redirect_uri used for the grant token
|
||||
const url = req.reverse('oauth2_callback');
|
||||
const redirect_uri = req.makeAbsolute(url);
|
||||
// Fetch an access token from the provider
|
||||
const authData = oauth2.exchangeGrantToken(
|
||||
req.queryParams.code,
|
||||
redirect_uri
|
||||
);
|
||||
const facebookToken = authData.access_token;
|
||||
// Fetch the active user's profile info
|
||||
const profile = oauth2.fetchActiveUser(facebookToken);
|
||||
const facebookId = profile.id;
|
||||
// Try to find an existing user with the user ID
|
||||
// (this requires the users collection)
|
||||
let user = users.firstExample({facebookId});
|
||||
if (user) {
|
||||
// Update the access_token if it has changed
|
||||
if (user.facebookToken !== facebookToken) {
|
||||
users.update(user, {facebookToken});
|
||||
}
|
||||
} else {
|
||||
// Create a new user document
|
||||
user = {
|
||||
username: `fb:${facebookId}`,
|
||||
facebookId,
|
||||
access_token
|
||||
}
|
||||
const meta = users.save(user);
|
||||
Object.assign(user, meta);
|
||||
}
|
||||
// Log the user in (this requires the session middleware)
|
||||
req.session.uid = user._key;
|
||||
req.session.access_token = authData.access_token;
|
||||
req.sessionStorage.save(req.session);
|
||||
// Redirect to the default route
|
||||
res.redirect(303, req.makeAbsolute('/'));
|
||||
}, 'oauth2_callback')
|
||||
.queryParam('error', joi.string().optional())
|
||||
.queryParam('csrfToken', joi.string().optional())
|
||||
.queryParam('code', joi.string().optional());
|
||||
```
|
||||
|
||||
!SECTION Creating an OAuth2 client
|
||||
|
||||
`createOAuth2Client(options): OAuth2Client`
|
||||
|
||||
Creates an OAuth2 client.
|
||||
|
||||
**Arguments**
|
||||
|
||||
* **options**: `Object`
|
||||
|
||||
An object with the following properties:
|
||||
|
||||
* **authEndpoint**: `string`
|
||||
|
||||
The fully-qualified URL of the provider's [authorization endpoint](http://tools.ietf.org/html/rfc6749#section-3.1).
|
||||
|
||||
* **tokenEndpoint**: `string`
|
||||
|
||||
The fully-qualified URL of the provider's [token endpoint](http://tools.ietf.org/html/rfc6749#section-3.2).
|
||||
|
||||
* **refreshEndpoint**: `string` (optional)
|
||||
|
||||
The fully-qualified URL of the provider's [refresh token endpoint](http://tools.ietf.org/html/rfc6749#section-6).
|
||||
|
||||
* **activeUserEndpoint**: `string` (optional)
|
||||
|
||||
The fully-qualified URL of the provider's endpoint for fetching details about the current user.
|
||||
|
||||
* **clientId**: `string`
|
||||
|
||||
The application's *Client ID* (or *App ID*) for the provider.
|
||||
|
||||
* **clientSecret**: `string`
|
||||
|
||||
The application's *Client Secret* (or *App Secret*) for the provider.
|
||||
|
||||
Returns an OAuth2 client for the given provider.
|
||||
|
||||
!SUBSECTION Setting up OAuth2 for Facebook
|
||||
|
||||
If you want to use Facebook as the OAuth2 provider, use the following options:
|
||||
|
||||
* *authEndpoint*: `https://www.facebook.com/dialog/oauth`
|
||||
* *tokenEndpoint*: `https://graph.facebook.com/oauth/access_token`
|
||||
* *activeUserEndpoint*: `https://graph.facebook.com/v2.0/me`
|
||||
|
||||
You also need to obtain a client ID and client secret from Facebook:
|
||||
|
||||
1. Create a regular account at [Facebook](https://www.facebook.com) or use an existing account you own.
|
||||
2. Visit the [Facebook Developers](https://developers.facebook.com) page.
|
||||
3. Click on *Apps* in the menu, then select *Register as a Developer* (the only option) and follow the instructions provided. You may need to verify your account by phone.
|
||||
4. Click on *Apps* in the menu, then select *Create a New App* and follow the instructions provided.
|
||||
5. Open the app dashboard, then note down the *App ID* and *App Secret*. The secret may be hidden by default.
|
||||
6. Click on *Settings*, then *Advanced* and enter one or more *Valid OAuth redirect URIs*. At least one of them must match your *redirect_uri* later. Don't forget to save your changes.
|
||||
7. Set the option *clientId* to the *App ID* and the option *clientSecret* to the *App Secret*.
|
||||
|
||||
!SUBSECTION Setting up OAuth2 for GitHub
|
||||
|
||||
If you want to use GitHub as the OAuth2 provider, use the following options:
|
||||
|
||||
* *authEndpoint*: `https://github.com/login/oauth/authorize?scope=user`
|
||||
* *tokenEndpoint*: `https://github.com/login/oauth/access_token`
|
||||
* *activeUserEndpoint*: `https://api.github.com/user`
|
||||
|
||||
You also need to obtain a client ID and client secret from GitHub:
|
||||
|
||||
1. Create a regular account at [GitHub](https://github.com) or use an existing account you own.
|
||||
2. Go to [Account Settings > Applications > Register new application](https://github.com/settings/applications/new).
|
||||
3. Provide an *authorization callback URL*. This must match your *redirect_uri* later.
|
||||
4. Fill in the other required details and follow the instructions provided.
|
||||
5. Open the application page, then note down the *Client ID* and *Client Secret*.
|
||||
6. Set the option *clientId* to the *Client ID* and the option *clientSecret* to the *Client Secret*.
|
||||
|
||||
!SUBSECTION Setting up OAuth2 for Google
|
||||
|
||||
If you want to use Google as the OAuth2 provider, use the following options:
|
||||
|
||||
* *authEndpoint*: `https://accounts.google.com/o/oauth2/auth?access_type=offline&scope=profile`
|
||||
* *tokenEndpoint*: `https://accounts.google.com/o/oauth2/token`
|
||||
* *activeUserEndpoint*: `https://www.googleapis.com/plus/v1/people/me`
|
||||
|
||||
You also need to obtain a client ID and client secret from Google:
|
||||
|
||||
1. Create a regular account at [Google](https://www.google.com) or use an existing account you own.
|
||||
2. Visit the [Google Developers Console](https://console.developers.google.com).
|
||||
3. Click on *Create Project*, then follow the instructions provided.
|
||||
4. When your project is ready, open the project dashboard, then click on *Enable an API*.
|
||||
5. Enable the *Google+ API* to allow your app to distinguish between different users.
|
||||
6. Open the *Credentials* page and click *Create new Client ID*, then follow the instructions provided. At least one *Authorized Redirect URI* must match your *redirect_uri* later. At least one *Authorized JavaScript Origin* must match your app's fully-qualified domain.
|
||||
7. When the Client ID is ready, note down the *Client ID* and *Client secret*.
|
||||
8. Set the option *clientId* to the *Client ID* and the option *clientSecret* to the *Client secret*.
|
||||
|
||||
!SECTION Get the authorization URL
|
||||
|
||||
`oauth2.getAuthUrl(redirect_uri, args): string`
|
||||
|
||||
Generates the authorization URL for the authorization endpoint.
|
||||
|
||||
**Arguments**
|
||||
|
||||
* **redirect_uri**: `string`
|
||||
|
||||
The fully-qualified URL of your application's OAuth2 callback.
|
||||
|
||||
* **args**: (optional)
|
||||
|
||||
An object with any of the following properties:
|
||||
|
||||
* **response_type**: `string` (Default: `"code"`)
|
||||
|
||||
See [RFC 6749](http://tools.ietf.org/html/rfc6749).
|
||||
|
||||
Returns a fully-qualified URL for the authorization endpoint of the provider by appending the client ID and any additional arguments from *args* to the *authEndpoint*.
|
||||
|
||||
!SECTION Exchange a grant code for an access token
|
||||
|
||||
`oauth2.exchangeGrantToken(code, redirect_uri)`
|
||||
|
||||
Exchanges a grant code for an access token.
|
||||
|
||||
Performs a *POST* response to the *tokenEndpoint*.
|
||||
|
||||
Throws an exception if the remote server responds with an empty response body.
|
||||
|
||||
**Arguments**
|
||||
|
||||
* **code**: `string`
|
||||
|
||||
A grant code returned by the provider's authorization endpoint.
|
||||
|
||||
* **redirect_uri**: `string`
|
||||
|
||||
The original callback URL with which the code was requested.
|
||||
|
||||
* **args**: `Object` (optional)
|
||||
|
||||
An object with any of the following properties:
|
||||
|
||||
* **grant_type**: `string` (Default: `"authorization_code"`)
|
||||
|
||||
See [RFC 6749](http://tools.ietf.org/html/rfc6749).
|
||||
|
||||
Returns the parsed response object.
|
||||
|
||||
!SECTION Fetch the active user
|
||||
|
||||
`oauth2.fetchActiveUser(access_token): Object`
|
||||
|
||||
Fetches details of the active user.
|
||||
|
||||
Performs a *GET* response to the *activeUserEndpoint*.
|
||||
|
||||
Throws an exception if the remote server responds with an empty response body.
|
||||
|
||||
Also throws an exception if the *activeUserEndpoint* is not configured.
|
||||
|
||||
**Arguments**
|
||||
|
||||
* **access_token**: `string`
|
||||
|
||||
An OAuth2 access token as returned by *exchangeGrantToken*.
|
||||
|
||||
Returns the parsed response object.
|
||||
|
||||
**Examples**
|
||||
|
||||
```js
|
||||
const authData = oauth2.exchangeGrantToken(code, redirect_uri);
|
||||
const userData = oauth2.fetchActiveUser(authData.access_token);
|
||||
```
|
|
@ -106,7 +106,7 @@
|
|||
* [User management](Foxx/Users.md)
|
||||
* [Related modules](Foxx/Modules.md)
|
||||
* [Authentication](Foxx/Auth.md)
|
||||
# * [OAuth 2.0](Foxx/OAuth2.md)
|
||||
* [OAuth 2.0](Foxx/OAuth2.md)
|
||||
* [Transactions](Transactions/README.md)
|
||||
* [Transaction invocation](Transactions/TransactionInvocation.md)
|
||||
* [Passing parameters](Transactions/Passing.md)
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
!CHAPTER The OAuth2 module
|
||||
|
||||
TODO
|
||||
|
|
@ -778,15 +778,15 @@ Section "-Core installation"
|
|||
|
||||
;Create shortcuts
|
||||
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Shell.lnk" "$INSTDIR\bin\arangosh.exe" '' '$INSTDIR\resources\Icons\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Server.lnk" "$INSTDIR\bin\arangod.exe" '' '$INSTDIR\resources\Icons\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Shell.lnk" "$INSTDIR\usr\bin\arangosh.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Server.lnk" "$INSTDIR\usr\sbin\arangod.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||
|
||||
;Read a value from an InstallOptions INI file
|
||||
|
||||
StrCmp "0" "$INSTALL_DESKTOP" noDesktopIcon
|
||||
CreateShortCut "$DESKTOP\Arango Shell.lnk" "$INSTDIR\bin\arangosh.exe" '' '$INSTDIR\resources\Icons\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$DESKTOP\Arango Management Interface.lnk" "http://127.0.0.1:8529" '' '$INSTDIR\resources\Icons\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$DESKTOP\Arango Shell.lnk" "$INSTDIR\bin\arangosh.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$DESKTOP\Arango Management Interface.lnk" "http://127.0.0.1:8529" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
noDesktopIcon:
|
||||
|
||||
; Write special uninstall registry entries
|
||||
|
@ -810,7 +810,7 @@ Section "-Core installation"
|
|||
|
||||
System::Call 'Kernel32::SetEnvironmentVariable(t, t)i ("ARANGODB_DEFAULT_ROOT_PASSWORD", "$PASSWORD").r0'
|
||||
StrCmp $0 0 error
|
||||
ExecWait "$INSTDIR\bin\arangod.exe --database.init-database"
|
||||
ExecWait "$INSTDIR\usr\sbin\arangod.exe --database.init-database"
|
||||
Goto done
|
||||
error:
|
||||
MessageBox MB_OK "Failed to initialize database password."
|
||||
|
@ -819,7 +819,7 @@ Section "-Core installation"
|
|||
StrCmp $TRI_INSTALL_TYPE 'Service' 0 nothing
|
||||
SimpleSC::StopService '${TRI_SVC_NAME}' 0 30
|
||||
SimpleSC::RemoveService '${TRI_SVC_NAME}'
|
||||
SimpleSC::InstallService '${TRI_SVC_NAME}' '${TRI_SVC_NAME}' '16' '2' '"$INSTDIR\bin\arangod.exe" --start-service' '' '' ''
|
||||
SimpleSC::InstallService '${TRI_SVC_NAME}' '${TRI_SVC_NAME}' '16' '2' '"$INSTDIR\usr\sbin\arangod.exe" --start-service' '' '' ''
|
||||
SimpleSC::SetServiceDescription '${TRI_SVC_NAME}' '${TRI_FRIENDLY_SVC_NAME}'
|
||||
SimpleSC::StartService '${TRI_SVC_NAME}' '' 30
|
||||
Call WaitForServiceUp
|
||||
|
@ -833,7 +833,7 @@ Function .onInstSuccess
|
|||
FunctionEnd
|
||||
|
||||
Section "-Add to path"
|
||||
Push $INSTDIR\bin
|
||||
Push $INSTDIR\usr\bin
|
||||
StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath
|
||||
StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0
|
||||
Call AddToPath
|
||||
|
@ -1182,9 +1182,9 @@ Section "Uninstall"
|
|||
SimpleSC::GetServiceBinaryPath '${TRI_SVC_NAME}'
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the binary path of the service
|
||||
; $1 should contain '"$INSTDIR\bin\arangod.exe" --start-service' - if $INSTDIR is equal
|
||||
; $1 should contain '"$INSTDIR\usr\sbin\arangod.exe" --start-service' - if $INSTDIR is equal
|
||||
; to our $INSTDIR uninstall the service - else its another installation and we jump to Done instead.
|
||||
StrCmp $1 '"$INSTDIR\bin\arangod.exe" --start-service' '' Done
|
||||
StrCmp $1 '"$INSTDIR\usr\sbin\arangod.exe" --start-service' '' Done
|
||||
DetailPrint 'Shutting down Service'
|
||||
SimpleSC::StopService '${TRI_SVC_NAME}' 0 30
|
||||
SimpleSC::RemoveService '${TRI_SVC_NAME}'
|
||||
|
@ -1275,7 +1275,7 @@ Section "Uninstall"
|
|||
${EndIf}
|
||||
DeleteRegKey HKLM "${TRI_UNINSTALL_REG_PATH}"
|
||||
|
||||
Push $INSTDIR\bin
|
||||
Push $INSTDIR\usr\bin
|
||||
StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0
|
||||
Call un.RemoveFromPath
|
||||
doNotRemoveFromPath:
|
||||
|
|
|
@ -638,15 +638,14 @@ Section "-Core installation"
|
|||
|
||||
;Create shortcuts
|
||||
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Shell.lnk" "$INSTDIR\bin\arangosh.exe" '' '$INSTDIR\resources\Icons\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Server.lnk" "$INSTDIR\bin\arangod.exe" '' '$INSTDIR\resources\Icons\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Shell.lnk" "$INSTDIR\usr\bin\arangosh.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||
|
||||
;Read a value from an InstallOptions INI file
|
||||
|
||||
StrCmp "0" "$INSTALL_DESKTOP" noDesktopIcon
|
||||
CreateShortCut "$DESKTOP\Arango Shell.lnk" "$INSTDIR\bin\arangosh.exe" '' '$INSTDIR\resources\Icons\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$DESKTOP\Arango Management Interface.lnk" "http://127.0.0.1:8529" '' '$INSTDIR\resources\Icons\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$DESKTOP\Arango Shell.lnk" "$INSTDIR\usr\bin\arangosh.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
CreateShortCut "$DESKTOP\Arango Management Interface.lnk" "http://127.0.0.1:8529" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||
noDesktopIcon:
|
||||
|
||||
; Write special uninstall registry entries
|
||||
|
@ -668,13 +667,6 @@ Section "-Core installation"
|
|||
|
||||
!insertmacro MUI_STARTMENU_WRITE_END
|
||||
|
||||
System::Call 'Kernel32::SetEnvironmentVariable(t, t)i ("ARANGODB_DEFAULT_ROOT_PASSWORD", "$PASSWORD").r0'
|
||||
StrCmp $0 0 error
|
||||
ExecWait "$INSTDIR\bin\arangod.exe --database.init-database"
|
||||
Goto done
|
||||
error:
|
||||
MessageBox MB_OK "Failed to initialize database password."
|
||||
done:
|
||||
@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@
|
||||
SectionEnd
|
||||
|
||||
|
@ -682,7 +674,7 @@ Function .onInstSuccess
|
|||
FunctionEnd
|
||||
|
||||
Section "-Add to path"
|
||||
Push $INSTDIR\bin
|
||||
Push $INSTDIR\usr\bin
|
||||
StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath
|
||||
StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0
|
||||
Call AddToPath
|
||||
|
@ -989,7 +981,7 @@ Section "Uninstall"
|
|||
DeleteRegKey HKCU "Software\@CPACK_NSIS_PACKAGE_NAME@"
|
||||
DeleteRegKey HKLM "${TRI_UNINSTALL_REG_PATH}"
|
||||
|
||||
Push $INSTDIR\bin
|
||||
Push $INSTDIR\usr\bin
|
||||
StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0
|
||||
Call un.RemoveFromPath
|
||||
doNotRemoveFromPath:
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#if _WIN32
|
||||
#include "Basics/win-utils.h"
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv(BIN_DIRECTORY)
|
||||
#else
|
||||
#define FIX_ICU_ENV
|
||||
#endif
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
#if _WIN32
|
||||
#include "Basics/win-utils.h"
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv(SBIN_DIRECTORY)
|
||||
#else
|
||||
#define FIX_ICU_ENV
|
||||
#endif
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
#if _WIN32
|
||||
#include "Basics/win-utils.h"
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv(SBIN_DIRECTORY)
|
||||
#else
|
||||
#define FIX_ICU_ENV
|
||||
#endif
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
#if _WIN32
|
||||
#include "Basics/win-utils.h"
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv(SBIN_DIRECTORY)
|
||||
#else
|
||||
#define FIX_ICU_ENV
|
||||
#endif
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
#if _WIN32
|
||||
#include "Basics/win-utils.h"
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv()
|
||||
#define FIX_ICU_ENV TRI_FixIcuDataEnv(SBIN_DIRECTORY)
|
||||
#else
|
||||
#define FIX_ICU_ENV
|
||||
#endif
|
||||
|
|
|
@ -1166,6 +1166,13 @@ int ClusterInfo::createCollectionCoordinator(std::string const& databaseName,
|
|||
}
|
||||
|
||||
if (TRI_microtime() > endTime) {
|
||||
LOG_TOPIC(ERR, Logger::CLUSTER) << "Timeout in _create collection"
|
||||
<< ": database: " << databaseName << ", collId:" << collectionID
|
||||
<< "\njson: " << json.toString()
|
||||
<< "\ntransaction sent to agency: " << transaction.toJson();
|
||||
AgencyCommResult ag = ac.getValues("");
|
||||
LOG_TOPIC(ERR, Logger::CLUSTER) << "Agency dump:\n"
|
||||
<< ag.slice().toJson();
|
||||
events::CreateCollection(name, TRI_ERROR_CLUSTER_TIMEOUT);
|
||||
return setErrormsg(TRI_ERROR_CLUSTER_TIMEOUT, errorMsg);
|
||||
}
|
||||
|
@ -1270,6 +1277,12 @@ int ClusterInfo::dropCollectionCoordinator(std::string const& databaseName,
|
|||
}
|
||||
|
||||
if (TRI_microtime() > endTime) {
|
||||
LOG_TOPIC(ERR, Logger::CLUSTER) << "Timeout in _drop collection"
|
||||
<< ": database: " << databaseName << ", collId:" << collectionID
|
||||
<< "\ntransaction sent to agency: " << trans.toJson();
|
||||
AgencyCommResult ag = ac.getValues("");
|
||||
LOG_TOPIC(ERR, Logger::CLUSTER) << "Agency dump:\n"
|
||||
<< ag.slice().toJson();
|
||||
events::DropCollection(collectionID, TRI_ERROR_CLUSTER_TIMEOUT);
|
||||
return setErrormsg(TRI_ERROR_CLUSTER_TIMEOUT, errorMsg);
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ static int runServer(int argc, char** argv) {
|
|||
std::string name = context.binaryName();
|
||||
|
||||
auto options = std::make_shared<options::ProgramOptions>(
|
||||
argv[0], "Usage: " + name + " [<options>]", "For more information use:");
|
||||
argv[0], "Usage: " + name + " [<options>]", "For more information use:", SBIN_DIRECTORY);
|
||||
|
||||
application_features::ApplicationServer server(options, SBIN_DIRECTORY);
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ int main(int argc, char* argv[]) {
|
|||
context.installHup();
|
||||
|
||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||
argv[0], "Usage: arangobench [<options>]", "For more information use:"));
|
||||
argv[0], "Usage: arangobench [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||
|
||||
ApplicationServer server(options, BIN_DIRECTORY);
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ int main(int argc, char* argv[]) {
|
|||
context.installHup();
|
||||
|
||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||
argv[0], "Usage: arangodump [<options>]", "For more information use:"));
|
||||
argv[0], "Usage: arangodump [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||
|
||||
ApplicationServer server(options, BIN_DIRECTORY);
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ int main(int argc, char* argv[]) {
|
|||
context.installHup();
|
||||
|
||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||
argv[0], "Usage: arangoimp [<options>]", "For more information use:"));
|
||||
argv[0], "Usage: arangoimp [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||
|
||||
ApplicationServer server(options, BIN_DIRECTORY);
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ int main(int argc, char* argv[]) {
|
|||
context.installHup();
|
||||
|
||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||
argv[0], "Usage: arangorestore [<options>]", "For more information use:"));
|
||||
argv[0], "Usage: arangorestore [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||
|
||||
ApplicationServer server(options, BIN_DIRECTORY);
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ int main(int argc, char* argv[]) {
|
|||
std::string name = context.binaryName();
|
||||
|
||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||
argv[0], "Usage: " + name + " [<options>]", "For more information use:"));
|
||||
argv[0], "Usage: " + name + " [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||
|
||||
ApplicationServer server(options, BIN_DIRECTORY);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ int main(int argc, char* argv[]) {
|
|||
context.installHup();
|
||||
|
||||
std::shared_ptr<options::ProgramOptions> options(new options::ProgramOptions(
|
||||
argv[0], "Usage: arangovpack [<options>]", "For more information use:"));
|
||||
argv[0], "Usage: arangovpack [<options>]", "For more information use:", BIN_DIRECTORY));
|
||||
|
||||
ApplicationServer server(options, BIN_DIRECTORY);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ endif()
|
|||
# Global macros ----------------------------------------------------------------
|
||||
macro (generate_root_config name)
|
||||
FILE(READ ${PROJECT_SOURCE_DIR}/etc/arangodb3/${name}.conf.in FileContent)
|
||||
STRING(REPLACE "@PKGDATADIR@" "@ROOTDIR@/share/arangodb3"
|
||||
STRING(REPLACE "@PKGDATADIR@" "@ROOTDIR@/${CMAKE_INSTALL_DATAROOTDIR_ARANGO}"
|
||||
FileContent "${FileContent}")
|
||||
STRING(REPLACE "@LOCALSTATEDIR@" "@ROOTDIR@/var"
|
||||
FileContent "${FileContent}")
|
||||
|
|
|
@ -47,7 +47,7 @@ install (FILES "${SSL_EAY_RELEASE_DLL}" DESTINATION "${CMAKE_INSTALL_BINDIR}/" C
|
|||
set (ICON_PATH "${W_INSTALL_FILES}/Icons/")
|
||||
install(DIRECTORY "${ICON_PATH}" DESTINATION "resources")
|
||||
|
||||
file(TO_NATIVE_PATH "resources/Icons/arangodb.ico" RELATIVE_ARANGO_ICON)
|
||||
file(TO_NATIVE_PATH "resources/arangodb.ico" RELATIVE_ARANGO_ICON)
|
||||
file(TO_NATIVE_PATH "${ICON_PATH}arangodb.bmp" ARANGO_IMG)
|
||||
file(TO_NATIVE_PATH "${ICON_PATH}/arangodb.ico" ARANGO_ICON)
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
<% } %>
|
||||
<% if (scaleProperties.coordsPending && scaling === true) { %>
|
||||
<span class="warning"><span> <%= scaleProperties.coordsPending %> </span><i class="fa fa-circle-o-notch fa-spin"></i></span>
|
||||
<button class="abortClusterPlan button-navbar button-default">Abort</button>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -112,6 +113,7 @@
|
|||
<% } %>
|
||||
<% if (scaleProperties.dbsPending && scaling === true) { %>
|
||||
<span class="warning"><span> <%= scaleProperties.dbsPending %> </span><i class="fa fa-circle-o-notch fa-spin"></i></span>
|
||||
<button class="abortClusterPlan button-navbar button-default">Abort</button>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
'click #removeCoord': 'removeCoord',
|
||||
'click #addDBs': 'addDBs',
|
||||
'click #removeDBs': 'removeDBs',
|
||||
'click .abortClusterPlan': 'abortClusterPlanModal',
|
||||
'keyup #plannedCoords': 'checkKey',
|
||||
'keyup #plannedDBs': 'checkKey'
|
||||
},
|
||||
|
@ -225,13 +226,45 @@
|
|||
});
|
||||
},
|
||||
|
||||
abortClusterPlanModal: function () {
|
||||
var buttons = []; var tableContent = [];
|
||||
tableContent.push(
|
||||
window.modalView.createReadOnlyEntry(
|
||||
'plan-abort-button',
|
||||
'Caution',
|
||||
'You are aborting the planned cluster plan. All pending servers are going to be removed. Continue?',
|
||||
undefined,
|
||||
undefined,
|
||||
false,
|
||||
/[<>&'"]/
|
||||
)
|
||||
);
|
||||
buttons.push(
|
||||
window.modalView.createSuccessButton('Yes', this.abortClusterPlan.bind(this))
|
||||
);
|
||||
window.modalView.show('modalTable.ejs', 'Modify Cluster Size', buttons, tableContent);
|
||||
},
|
||||
|
||||
abortClusterPlan: function () {
|
||||
window.modalView.hide();
|
||||
try {
|
||||
var coords = JSON.parse($('#infoCoords > .positive > span').text());
|
||||
var dbs = JSON.parse($('#infoDBs > .positive > span').text());
|
||||
this.setCoordSize(coords);
|
||||
this.setDBsSize(dbs);
|
||||
} catch (ignore) {
|
||||
console.log(ignore);
|
||||
arangoHelper.arangoError('Plan', 'Could not abort Cluster Plan');
|
||||
}
|
||||
},
|
||||
|
||||
renderCounts: function (scale, callback) {
|
||||
var self = this;
|
||||
|
||||
var renderFunc = function (id, ok, pending, error) {
|
||||
var string = '<span class="positive"><span>' + ok + '</span><i class="fa fa-check-circle"></i></span>';
|
||||
if (pending && scale === true) {
|
||||
string = string + '<span class="warning"><span>' + pending + '</span><i class="fa fa-circle-o-notch fa-spin"></i></span>';
|
||||
string = string + '<span class="warning"><span>' + pending +
|
||||
'</span><i class="fa fa-circle-o-notch fa-spin"></i></span><button class="abortClusterPlan button-navbar button-default">Abort</button>';
|
||||
}
|
||||
if (error) {
|
||||
string = string + '<span class="negative"><span>' + error + '</span><i class="fa fa-exclamation-circle"></i></span>';
|
||||
|
|
|
@ -195,6 +195,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
%default {
|
||||
background-color: $c-white;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: $c-neutral;
|
||||
color: $c-white;
|
||||
}
|
||||
}
|
||||
|
||||
%icon-neutral {
|
||||
color: $c-neutral;
|
||||
|
||||
|
|
|
@ -58,6 +58,10 @@
|
|||
@extend %info;
|
||||
}
|
||||
|
||||
.button-navbar {
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
[class^='button-']:disabled,
|
||||
button.disabled,
|
||||
[class*=' button-']:disabled {
|
||||
|
@ -86,6 +90,12 @@ button.disabled,
|
|||
@extend %neutral;
|
||||
}
|
||||
|
||||
.button-default {
|
||||
@extend %btn;
|
||||
@extend %default;
|
||||
color: $c-black;
|
||||
}
|
||||
|
||||
.addButton {
|
||||
@extend %clickable;
|
||||
@extend %icon-positive;
|
||||
|
|
|
@ -1464,6 +1464,7 @@ function startInstanceAgency (instanceInfo, protocol, options,
|
|||
|
||||
for (let i = 0; i < N; i++) {
|
||||
let instanceArgs = _.clone(addArgs);
|
||||
instanceArgs['log.file'] = fs.join(rootDir, 'log' + String(i));
|
||||
instanceArgs['agency.activate'] = 'true';
|
||||
instanceArgs['agency.size'] = String(N);
|
||||
instanceArgs['agency.pool-size'] = String(N);
|
||||
|
|
|
@ -102,6 +102,7 @@ class ProgramOptions {
|
|||
|
||||
ProgramOptions(char const* progname, std::string const& usage,
|
||||
std::string const& more,
|
||||
const char *binaryPath,
|
||||
TerminalWidthFuncType const& terminalWidth = TRI_ColumnsWidth,
|
||||
SimilarityFuncType const& similarity = TRI_Levenshtein)
|
||||
: _progname(progname),
|
||||
|
@ -111,7 +112,8 @@ class ProgramOptions {
|
|||
_similarity(similarity),
|
||||
_processingResult(),
|
||||
_sealed(false),
|
||||
_overrideOptions(false) {
|
||||
_overrideOptions(false),
|
||||
_binaryPath(binaryPath){
|
||||
// find progname wildcard in string
|
||||
size_t const pos = _usage.find(ARANGODB_PROGRAM_OPTIONS_PROGNAME);
|
||||
|
||||
|
@ -126,7 +128,7 @@ class ProgramOptions {
|
|||
|
||||
// sets a value translator
|
||||
void setTranslator(
|
||||
std::function<std::string(std::string const&)> translator) {
|
||||
std::function<std::string(std::string const&, char const*)> translator) {
|
||||
_translator = translator;
|
||||
}
|
||||
|
||||
|
@ -357,7 +359,7 @@ class ProgramOptions {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string result = option.parameter->set(_translator(value));
|
||||
std::string result = option.parameter->set(_translator(value, _binaryPath));
|
||||
|
||||
if (!result.empty()) {
|
||||
// parameter validation failed
|
||||
|
@ -621,7 +623,9 @@ class ProgramOptions {
|
|||
// allow or disallow overriding already set options
|
||||
bool _overrideOptions;
|
||||
// translate input values
|
||||
std::function<std::string(std::string const&)> _translator;
|
||||
std::function<std::string(std::string const&, char const*)> _translator;
|
||||
// directory of this binary
|
||||
char const* _binaryPath;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "Translator.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
#include "Basics/files.h"
|
||||
std::string arangodb::options::EnvironmentTranslator(std::string const& value) {
|
||||
std::string arangodb::options::EnvironmentTranslator(std::string const& value, const char *binaryPath) {
|
||||
if (value.empty()) {
|
||||
return value;
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ std::string arangodb::options::EnvironmentTranslator(std::string const& value) {
|
|||
if (v == nullptr) {
|
||||
#if _WIN32
|
||||
if (TRI_EqualString(k.c_str(), "ROOTDIR")) {
|
||||
vv = TRI_LocateInstallDirectory();
|
||||
vv = TRI_LocateInstallDirectory(binaryPath);
|
||||
|
||||
if (! vv.empty()) {
|
||||
char c = *(vv.rbegin());
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
namespace arangodb {
|
||||
namespace options {
|
||||
std::string EnvironmentTranslator(std::string const& value);
|
||||
std::string EnvironmentTranslator(std::string const& value, const char* binaryPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue