mirror of
https://github.com/Icinga/icinga2.git
synced 2025-04-08 17:05:25 +02:00
Merge pull request #6205 from Icinga/feature/api-verbose-errors
API: Unify verbose error messages
This commit is contained in:
commit
a8b5d8e64a
@ -103,7 +103,7 @@ The output will be sent back as a JSON object:
|
||||
|
||||
> **Tip**
|
||||
>
|
||||
> You can use the `pretty` parameter to beautify the JSON response with Icinga v2.9+.
|
||||
> You can use the [pretty](12-icinga2-api.md#icinga2-api-parameters-global) parameter to beautify the JSON response with Icinga v2.9+.
|
||||
|
||||
You can also use [jq](https://stedolan.github.io/jq/) or `python -m json.tool`
|
||||
in combination with curl on the CLI.
|
||||
@ -124,7 +124,8 @@ The API will return standard [HTTP statuses](https://www.ietf.org/rfc/rfc2616.tx
|
||||
including error codes.
|
||||
|
||||
When an error occurs, the response body will contain additional information
|
||||
about the problem and its source.
|
||||
about the problem and its source. Set `verbose` to true to retrieve more
|
||||
insights into what may be causing the error.
|
||||
|
||||
A status code between 200 and 299 generally means that the request was
|
||||
successful.
|
||||
@ -271,6 +272,27 @@ Here are the exact same query parameters as a JSON object:
|
||||
The [match function](18-library-reference.md#global-functions-match) is available as global function
|
||||
in Icinga 2.
|
||||
|
||||
### Global Parameters <a id="icinga2-api-parameters-global"></a>
|
||||
|
||||
Name | Description
|
||||
----------------|--------------------
|
||||
pretty | Pretty-print the JSON response.
|
||||
verbose | Add verbose debug information inside the `diagnostic_information` key into the response if available. This helps with troubleshooting failing requests.
|
||||
|
||||
Example as URL parameter:
|
||||
|
||||
```
|
||||
/v1/objects/hosts?pretty=1
|
||||
```
|
||||
|
||||
Example as JSON object:
|
||||
|
||||
```
|
||||
{ "pretty": true }
|
||||
```
|
||||
|
||||
Both parameters have been added in Icinga 2 v2.9.
|
||||
|
||||
### Request Method Override <a id="icinga2-api-requests-method-override"></a>
|
||||
|
||||
`GET` requests do not allow you to send a request body. In case you cannot pass everything as URL
|
||||
|
@ -702,6 +702,33 @@ Look into the log and check whether the feature logs anything specific for this
|
||||
grep GraphiteWriter /var/log/icinga2/icinga2.log
|
||||
```
|
||||
|
||||
## REST API Troubleshooting <a id="troubleshooting-api"></a>
|
||||
|
||||
In order to analyse errors on API requests, you can explicitly enable the [verbose parameter](12-icinga2-api.md#icinga2-api-parameters-global).
|
||||
|
||||
```
|
||||
$ curl -k -s -u root:icinga -H 'Accept: application/json' -X DELETE 'https://localhost:5665/v1/objects/hosts/example-cmdb?pretty=1&verbose=1'
|
||||
{
|
||||
"diagnostic_information": "Error: Object does not exist.\n\n ....",
|
||||
"error": 404.0,
|
||||
"status": "No objects found."
|
||||
}
|
||||
```
|
||||
|
||||
## REST API Troubleshooting: No Objects Found <a id="troubleshooting-api-no-objects-found"></a>
|
||||
|
||||
Please note that the `404` status with no objects being found can also originate
|
||||
from missing or too strict object permissions for the authenticated user.
|
||||
|
||||
This is a security feature to disable object name guessing. If this would not be the
|
||||
case, restricted users would be able to get a list of names of your objects just by
|
||||
trying every character combination.
|
||||
|
||||
In order to analyse and fix the problem, please check the following:
|
||||
|
||||
- use an administrative account with full permissions to check whether the objects are actually there.
|
||||
- verify the permissions on the affected ApiUser object and fix them.
|
||||
|
||||
|
||||
## Certificate Troubleshooting <a id="troubleshooting-certificate"></a>
|
||||
|
||||
|
@ -182,7 +182,7 @@ String Comment::AddComment(const Checkable::Ptr& checkable, CommentType entryTyp
|
||||
|
||||
Array::Ptr errors = new Array();
|
||||
|
||||
if (!ConfigObjectUtility::CreateObject(Comment::TypeInstance, fullName, config, errors)) {
|
||||
if (!ConfigObjectUtility::CreateObject(Comment::TypeInstance, fullName, config, errors, nullptr)) {
|
||||
ObjectLock olock(errors);
|
||||
for (const String& error : errors) {
|
||||
Log(LogCritical, "Comment", error);
|
||||
@ -214,7 +214,7 @@ void Comment::RemoveComment(const String& id, const MessageOrigin::Ptr& origin)
|
||||
|
||||
Array::Ptr errors = new Array();
|
||||
|
||||
if (!ConfigObjectUtility::DeleteObject(comment, false, errors)) {
|
||||
if (!ConfigObjectUtility::DeleteObject(comment, false, errors, nullptr)) {
|
||||
ObjectLock olock(errors);
|
||||
for (const String& error : errors) {
|
||||
Log(LogCritical, "Comment", error);
|
||||
|
@ -255,7 +255,7 @@ String Downtime::AddDowntime(const Checkable::Ptr& checkable, const String& auth
|
||||
|
||||
Array::Ptr errors = new Array();
|
||||
|
||||
if (!ConfigObjectUtility::CreateObject(Downtime::TypeInstance, fullName, config, errors)) {
|
||||
if (!ConfigObjectUtility::CreateObject(Downtime::TypeInstance, fullName, config, errors, nullptr)) {
|
||||
ObjectLock olock(errors);
|
||||
for (const String& error : errors) {
|
||||
Log(LogCritical, "Downtime", error);
|
||||
@ -308,7 +308,7 @@ void Downtime::RemoveDowntime(const String& id, bool cancelled, bool expired, co
|
||||
|
||||
Array::Ptr errors = new Array();
|
||||
|
||||
if (!ConfigObjectUtility::DeleteObject(downtime, false, errors)) {
|
||||
if (!ConfigObjectUtility::DeleteObject(downtime, false, errors, nullptr)) {
|
||||
ObjectLock olock(errors);
|
||||
for (const String& error : errors) {
|
||||
Log(LogCritical, "Downtime", error);
|
||||
|
@ -62,7 +62,7 @@ bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& reques
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 404,
|
||||
"No objects found.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@ -75,6 +75,11 @@ bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& reques
|
||||
Log(LogNotice, "ApiActionHandler")
|
||||
<< "Running action " << actionName;
|
||||
|
||||
bool verbose = false;
|
||||
|
||||
if (params)
|
||||
verbose = HttpUtility::GetLastParameter(params, "verbose");
|
||||
|
||||
for (const ConfigObject::Ptr& obj : objs) {
|
||||
try {
|
||||
results.emplace_back(action->Invoke(obj, params));
|
||||
@ -84,8 +89,9 @@ bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& reques
|
||||
{ "status", "Action execution failed: '" + DiagnosticInformation(ex, false) + "'." }
|
||||
});
|
||||
|
||||
if (HttpUtility::GetLastParameter(params, "verboseErrors"))
|
||||
fail->Set("diagnostic information", DiagnosticInformation(ex));
|
||||
/* Exception for actions. Normally we would handle this inside SendJsonError(). */
|
||||
if (verbose)
|
||||
fail->Set("diagnostic_information", DiagnosticInformation(ex));
|
||||
|
||||
results.emplace_back(std::move(fail));
|
||||
}
|
||||
|
@ -116,15 +116,14 @@ Value ApiListener::ConfigUpdateObjectAPIHandler(const MessageOrigin::Ptr& origin
|
||||
/* object does not exist, create it through the API */
|
||||
Array::Ptr errors = new Array();
|
||||
|
||||
if (!ConfigObjectUtility::CreateObject(ptype,
|
||||
objName, config, errors)) {
|
||||
if (!ConfigObjectUtility::CreateObject(ptype, objName, config, errors, nullptr)) {
|
||||
Log(LogCritical, "ApiListener")
|
||||
<< "Could not create object '" << objName << "':";
|
||||
|
||||
ObjectLock olock(errors);
|
||||
ObjectLock olock(errors);
|
||||
for (const String& error : errors) {
|
||||
Log(LogCritical, "ApiListener", error);
|
||||
}
|
||||
Log(LogCritical, "ApiListener", error);
|
||||
}
|
||||
|
||||
return Empty;
|
||||
}
|
||||
@ -256,7 +255,7 @@ Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin
|
||||
|
||||
Array::Ptr errors = new Array();
|
||||
|
||||
if (!ConfigObjectUtility::DeleteObject(object, true, errors)) {
|
||||
if (!ConfigObjectUtility::DeleteObject(object, true, errors, nullptr)) {
|
||||
Log(LogCritical, "ApiListener", "Could not delete object:");
|
||||
|
||||
ObjectLock olock(errors);
|
||||
|
@ -91,7 +91,7 @@ bool ConfigFilesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
||||
response.WriteBody(content.CStr(), content.GetLength());
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 500, "Could not read file.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -98,7 +98,7 @@ String ConfigObjectUtility::CreateObjectConfig(const Type::Ptr& type, const Stri
|
||||
}
|
||||
|
||||
bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& fullName,
|
||||
const String& config, const Array::Ptr& errors)
|
||||
const String& config, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(ConfigPackageUtility::GetStaticMutex());
|
||||
@ -121,7 +121,7 @@ bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& full
|
||||
Utility::MkDirP(Utility::DirName(path), 0700);
|
||||
|
||||
if (Utility::PathExists(path)) {
|
||||
errors->Add("Configuration file '" + path + "' already exists.");
|
||||
errors->Add("Cannot create object '" + fullName + "'. Configuration file '" + path + "' already exists.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -151,7 +151,10 @@ bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& full
|
||||
}
|
||||
|
||||
for (const boost::exception_ptr& ex : upq.GetExceptions()) {
|
||||
errors->Add(DiagnosticInformation(ex));
|
||||
errors->Add(DiagnosticInformation(ex, false));
|
||||
|
||||
if (diagnosticInformation)
|
||||
diagnosticInformation->Add(DiagnosticInformation(ex));
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +171,10 @@ bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& full
|
||||
}
|
||||
|
||||
if (errors)
|
||||
errors->Add(DiagnosticInformation(ex));
|
||||
errors->Add(DiagnosticInformation(ex, false));
|
||||
|
||||
if (diagnosticInformation)
|
||||
diagnosticInformation->Add(DiagnosticInformation(ex));
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -176,17 +182,21 @@ bool ConfigObjectUtility::CreateObject(const Type::Ptr& type, const String& full
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors)
|
||||
bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade,
|
||||
const Array::Ptr& errors, const Array::Ptr& diagnosticInformation)
|
||||
{
|
||||
std::vector<Object::Ptr> parents = DependencyGraph::GetParents(object);
|
||||
|
||||
Type::Ptr type = object->GetReflectionType();
|
||||
|
||||
String name = object->GetName();
|
||||
|
||||
if (!parents.empty() && !cascade) {
|
||||
if (errors)
|
||||
errors->Add("Object '" + object->GetName() + "' of type '" + type->GetName() +
|
||||
if (errors) {
|
||||
errors->Add("Object '" + name + "' of type '" + type->GetName() +
|
||||
"' cannot be deleted because other objects depend on it. "
|
||||
"Use cascading delete to delete it anyway.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -197,10 +207,10 @@ bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bo
|
||||
if (!parentObj)
|
||||
continue;
|
||||
|
||||
DeleteObjectHelper(parentObj, cascade, errors);
|
||||
DeleteObjectHelper(parentObj, cascade, errors, diagnosticInformation);
|
||||
}
|
||||
|
||||
ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, object->GetName());
|
||||
ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, name);
|
||||
|
||||
try {
|
||||
/* mark this object for cluster delete event */
|
||||
@ -215,12 +225,15 @@ bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bo
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
if (errors)
|
||||
errors->Add(DiagnosticInformation(ex));
|
||||
errors->Add(DiagnosticInformation(ex, false));
|
||||
|
||||
if (diagnosticInformation)
|
||||
diagnosticInformation->Add(DiagnosticInformation(ex));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String path = GetObjectConfigPath(object->GetReflectionType(), object->GetName());
|
||||
String path = GetObjectConfigPath(object->GetReflectionType(), name);
|
||||
|
||||
if (Utility::PathExists(path)) {
|
||||
if (unlink(path.CStr()) < 0 && errno != ENOENT) {
|
||||
@ -234,7 +247,7 @@ bool ConfigObjectUtility::DeleteObjectHelper(const ConfigObject::Ptr& object, bo
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigObjectUtility::DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors)
|
||||
bool ConfigObjectUtility::DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation)
|
||||
{
|
||||
if (object->GetPackage() != "_api") {
|
||||
if (errors)
|
||||
@ -243,5 +256,5 @@ bool ConfigObjectUtility::DeleteObject(const ConfigObject::Ptr& object, bool cas
|
||||
return false;
|
||||
}
|
||||
|
||||
return DeleteObjectHelper(object, cascade, errors);
|
||||
return DeleteObjectHelper(object, cascade, errors, diagnosticInformation);
|
||||
}
|
||||
|
@ -45,13 +45,15 @@ public:
|
||||
bool ignoreOnError, const Array::Ptr& templates, const Dictionary::Ptr& attrs);
|
||||
|
||||
static bool CreateObject(const Type::Ptr& type, const String& fullName,
|
||||
const String& config, const Array::Ptr& errors);
|
||||
const String& config, const Array::Ptr& errors, const Array::Ptr& diagnosticInformation);
|
||||
|
||||
static bool DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors);
|
||||
static bool DeleteObject(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors,
|
||||
const Array::Ptr& diagnosticInformation);
|
||||
|
||||
private:
|
||||
static String EscapeName(const String& name);
|
||||
static bool DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors);
|
||||
static bool DeleteObjectHelper(const ConfigObject::Ptr& object, bool cascade, const Array::Ptr& errors,
|
||||
const Array::Ptr& diagnosticInformation);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ void ConfigPackagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& req
|
||||
packages = ConfigPackageUtility::GetPackages();
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 500, "Could not retrieve packages.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& re
|
||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||
|
||||
if (!ConfigPackageUtility::ValidateName(packageName)) {
|
||||
HttpUtility::SendJsonError(response, params, 400, "Invalid package name.");
|
||||
HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -97,13 +97,14 @@ void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& re
|
||||
boost::mutex::scoped_lock lock(ConfigPackageUtility::GetStaticMutex());
|
||||
ConfigPackageUtility::CreatePackage(packageName);
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 500, "Could not create package.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
HttpUtility::SendJsonError(response, params, 500, "Could not create package '" + packageName + "'.",
|
||||
DiagnosticInformation(ex));
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary::Ptr result1 = new Dictionary({
|
||||
{ "code", 200 },
|
||||
{ "package", packageName },
|
||||
{ "status", "Created package." }
|
||||
});
|
||||
|
||||
@ -125,31 +126,28 @@ void ConfigPackagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest&
|
||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||
|
||||
if (!ConfigPackageUtility::ValidateName(packageName)) {
|
||||
HttpUtility::SendJsonError(response, params, 400, "Invalid package name.");
|
||||
HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
|
||||
return;
|
||||
}
|
||||
|
||||
int code = 200;
|
||||
String status = "Deleted package.";
|
||||
DictionaryData result1;
|
||||
|
||||
try {
|
||||
ConfigPackageUtility::DeletePackage(packageName);
|
||||
} catch (const std::exception& ex) {
|
||||
code = 500;
|
||||
status = "Failed to delete package.";
|
||||
if (HttpUtility::GetLastParameter(params, "verboseErrors"))
|
||||
result1.emplace_back("diagnostic information", DiagnosticInformation(ex));
|
||||
HttpUtility::SendJsonError(response, params, 500, "Failed to delete package '" + packageName + "'.",
|
||||
DiagnosticInformation(ex));
|
||||
return;
|
||||
}
|
||||
|
||||
result1.emplace_back("package", packageName);
|
||||
result1.emplace_back("code", code);
|
||||
result1.emplace_back("status", status);
|
||||
|
||||
Dictionary::Ptr result = new Dictionary({
|
||||
{ "results", new Array({ new Dictionary(std::move(result1)) }) }
|
||||
Dictionary::Ptr result1 = new Dictionary({
|
||||
{ "code", 200 },
|
||||
{ "package", packageName },
|
||||
{ "status", "Deleted package." }
|
||||
});
|
||||
|
||||
response.SetStatus(code, (code == 200) ? "OK" : "Internal Server Error");
|
||||
Dictionary::Ptr result = new Dictionary({
|
||||
{ "results", new Array({ result1 }) }
|
||||
});
|
||||
|
||||
response.SetStatus(200, "OK");
|
||||
HttpUtility::SendJsonBody(response, params, result);
|
||||
}
|
||||
|
@ -59,10 +59,10 @@ void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& reque
|
||||
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
||||
|
||||
if (!ConfigPackageUtility::ValidateName(packageName))
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid package name.");
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
|
||||
|
||||
if (!ConfigPackageUtility::ValidateName(stageName))
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid stage name.");
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid stage name '" + stageName + "'.");
|
||||
|
||||
ArrayData results;
|
||||
|
||||
@ -95,9 +95,10 @@ void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& requ
|
||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||
|
||||
if (!ConfigPackageUtility::ValidateName(packageName))
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid package name.");
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
|
||||
|
||||
bool reload = true;
|
||||
|
||||
if (params->Contains("reload"))
|
||||
reload = HttpUtility::GetLastParameter(params, "reload");
|
||||
|
||||
@ -116,13 +117,17 @@ void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& requ
|
||||
ConfigPackageUtility::AsyncTryActivateStage(packageName, stageName, reload);
|
||||
} catch (const std::exception& ex) {
|
||||
return HttpUtility::SendJsonError(response, params, 500,
|
||||
"Stage creation failed.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
"Stage creation failed.",
|
||||
DiagnosticInformation(ex));
|
||||
}
|
||||
|
||||
|
||||
String responseStatus = "Created stage. ";
|
||||
responseStatus += (reload ? " Icinga2 will reload." : " Icinga2 reload skipped.");
|
||||
|
||||
if (reload)
|
||||
responseStatus += "Reload triggered.";
|
||||
else
|
||||
responseStatus += "Reload skipped.";
|
||||
|
||||
Dictionary::Ptr result1 = new Dictionary({
|
||||
{ "package", packageName },
|
||||
@ -153,21 +158,23 @@ void ConfigStagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& re
|
||||
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
||||
|
||||
if (!ConfigPackageUtility::ValidateName(packageName))
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid package name.");
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid package name '" + packageName + "'.");
|
||||
|
||||
if (!ConfigPackageUtility::ValidateName(stageName))
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid stage name.");
|
||||
return HttpUtility::SendJsonError(response, params, 400, "Invalid stage name '" + stageName + "'.");
|
||||
|
||||
try {
|
||||
ConfigPackageUtility::DeleteStage(packageName, stageName);
|
||||
} catch (const std::exception& ex) {
|
||||
return HttpUtility::SendJsonError(response, params, 500,
|
||||
"Failed to delete stage.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
"Failed to delete stage '" + stageName + "' in package '" + packageName + "'.",
|
||||
DiagnosticInformation(ex));
|
||||
}
|
||||
|
||||
Dictionary::Ptr result1 = new Dictionary({
|
||||
{ "code", 200 },
|
||||
{ "package", packageName },
|
||||
{ "stage", stageName },
|
||||
{ "status", "Stage deleted." }
|
||||
});
|
||||
|
||||
|
@ -74,6 +74,7 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||
Dictionary::Ptr result1 = new Dictionary();
|
||||
String status;
|
||||
Array::Ptr errors = new Array();
|
||||
Array::Ptr diagnosticInformation = new Array();
|
||||
|
||||
bool ignoreOnError = false;
|
||||
|
||||
@ -86,10 +87,22 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||
|
||||
String config;
|
||||
|
||||
bool verbose = false;
|
||||
|
||||
if (params)
|
||||
verbose = HttpUtility::GetLastParameter(params, "verbose");
|
||||
|
||||
/* Object creation can cause multiple errors and optionally diagnostic information.
|
||||
* We can't use SendJsonError() here.
|
||||
*/
|
||||
try {
|
||||
config = ConfigObjectUtility::CreateObjectConfig(type, name, ignoreOnError, templates, attrs);
|
||||
} catch (const std::exception& ex) {
|
||||
errors->Add(DiagnosticInformation(ex));
|
||||
errors->Add(DiagnosticInformation(ex, false));
|
||||
diagnosticInformation->Add(DiagnosticInformation(ex));
|
||||
|
||||
if (verbose)
|
||||
result1->Set("diagnostic_information", diagnosticInformation);
|
||||
|
||||
result1->Set("errors", errors);
|
||||
result1->Set("code", 500);
|
||||
@ -101,11 +114,14 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ConfigObjectUtility::CreateObject(type, name, config, errors)) {
|
||||
if (!ConfigObjectUtility::CreateObject(type, name, config, errors, diagnosticInformation)) {
|
||||
result1->Set("errors", errors);
|
||||
result1->Set("code", 500);
|
||||
result1->Set("status", "Object could not be created.");
|
||||
|
||||
if (verbose)
|
||||
result1->Set("diagnostic_information", diagnosticInformation);
|
||||
|
||||
response.SetStatus(500, "Object could not be created");
|
||||
HttpUtility::SendJsonBody(response, params, result);
|
||||
|
||||
|
@ -65,11 +65,12 @@ bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 404,
|
||||
"No objects found.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cascade = HttpUtility::GetLastParameter(params, "cascade");
|
||||
bool verbose = HttpUtility::GetLastParameter(params, "verbose");
|
||||
|
||||
ArrayData results;
|
||||
|
||||
@ -79,8 +80,9 @@ bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||
int code;
|
||||
String status;
|
||||
Array::Ptr errors = new Array();
|
||||
Array::Ptr diagnosticInformation = new Array();
|
||||
|
||||
if (!ConfigObjectUtility::DeleteObject(obj, cascade, errors)) {
|
||||
if (!ConfigObjectUtility::DeleteObject(obj, cascade, errors, diagnosticInformation)) {
|
||||
code = 500;
|
||||
status = "Object could not be deleted.";
|
||||
success = false;
|
||||
@ -89,13 +91,18 @@ bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||
status = "Object was deleted.";
|
||||
}
|
||||
|
||||
results.push_back(new Dictionary({
|
||||
Dictionary::Ptr result = new Dictionary({
|
||||
{ "type", type->GetName() },
|
||||
{ "name", obj->GetName() },
|
||||
{ "code", code },
|
||||
{ "status", status },
|
||||
{ "errors", errors }
|
||||
}));
|
||||
});
|
||||
|
||||
if (verbose)
|
||||
result->Set("diagnostic_information", diagnosticInformation);
|
||||
|
||||
results.push_back(result);
|
||||
}
|
||||
|
||||
Dictionary::Ptr result = new Dictionary({
|
||||
|
@ -89,11 +89,18 @@ void HttpUtility::SendJsonError(HttpResponse& response, const Dictionary::Ptr& p
|
||||
response.SetStatus(code, HttpUtility::GetErrorNameByCode(code));
|
||||
result->Set("error", code);
|
||||
|
||||
bool verbose = false;
|
||||
|
||||
if (params)
|
||||
verbose = HttpUtility::GetLastParameter(params, "verbose");
|
||||
|
||||
if (!info.IsEmpty())
|
||||
result->Set("status", info);
|
||||
|
||||
if (!diagnosticInformation.IsEmpty())
|
||||
result->Set("diagnostic information", diagnosticInformation);
|
||||
if (verbose) {
|
||||
if (!diagnosticInformation.IsEmpty())
|
||||
result->Set("diagnostic_information", diagnosticInformation);
|
||||
}
|
||||
|
||||
HttpUtility::SendJsonBody(response, params, result);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ bool ModifyObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 404,
|
||||
"No objects found.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -71,12 +71,17 @@ bool ModifyObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||
|
||||
if (attrsVal.GetReflectionType() != Dictionary::TypeInstance) {
|
||||
HttpUtility::SendJsonError(response, params, 400,
|
||||
"Invalid type for 'attrs' attribute specified. Dictionary type is required.", Empty);
|
||||
"Invalid type for 'attrs' attribute specified. Dictionary type is required.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Dictionary::Ptr attrs = attrsVal;
|
||||
|
||||
bool verbose = false;
|
||||
|
||||
if (params)
|
||||
verbose = HttpUtility::GetLastParameter(params, "verbose");
|
||||
|
||||
ArrayData results;
|
||||
|
||||
for (const ConfigObject::Ptr& obj : objs) {
|
||||
@ -100,7 +105,10 @@ bool ModifyObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||
result1->Set("status", "Attributes updated.");
|
||||
} catch (const std::exception& ex) {
|
||||
result1->Set("code", 500);
|
||||
result1->Set("status", "Attribute '" + key + "' could not be set: " + DiagnosticInformation(ex));
|
||||
result1->Set("status", "Attribute '" + key + "' could not be set: " + DiagnosticInformation(ex, false));
|
||||
|
||||
if (verbose)
|
||||
result1->Set("diagnostic_information", DiagnosticInformation(ex));
|
||||
}
|
||||
|
||||
results.push_back(std::move(result1));
|
||||
|
@ -129,7 +129,7 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
||||
uattrs = params->Get("attrs");
|
||||
} catch (const std::exception&) {
|
||||
HttpUtility::SendJsonError(response, params, 400,
|
||||
"Invalid type for 'attrs' attribute specified. Array type is required.", Empty);
|
||||
"Invalid type for 'attrs' attribute specified. Array type is required.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
||||
ujoins = params->Get("joins");
|
||||
} catch (const std::exception&) {
|
||||
HttpUtility::SendJsonError(response, params, 400,
|
||||
"Invalid type for 'joins' attribute specified. Array type is required.", Empty);
|
||||
"Invalid type for 'joins' attribute specified. Array type is required.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
||||
umetas = params->Get("meta");
|
||||
} catch (const std::exception&) {
|
||||
HttpUtility::SendJsonError(response, params, 400,
|
||||
"Invalid type for 'meta' attribute specified. Array type is required.", Empty);
|
||||
"Invalid type for 'meta' attribute specified. Array type is required.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 404,
|
||||
"No objects found.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ bool StatusHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 404,
|
||||
"No objects found.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ bool TemplateQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest&
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 404,
|
||||
"No templates found.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& requ
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 404,
|
||||
"No objects found.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ bool VariableQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest&
|
||||
} catch (const std::exception& ex) {
|
||||
HttpUtility::SendJsonError(response, params, 404,
|
||||
"No variables found.",
|
||||
HttpUtility::GetLastParameter(params, "verboseErrors") ? DiagnosticInformation(ex) : "");
|
||||
DiagnosticInformation(ex));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user