Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add package parameter in object creation API #8640

Conversation

mcodato
Copy link
Contributor

@mcodato mcodato commented Feb 16, 2021

Hi, this is our proposed implementation for #8639

Test: create an object in a custom package

Request

curl -X PUT -v -k -H 'Accept: application/json' -u "root:admin" "https://localhost:5665/v1/objects/hosts/test_host1" -d '{"package": "custom_package", "attrs": { "address": "192.168.1.1", "check_command": "hostalive", "vars.os" : "Linux", "zone": "master" }}'

Response

{"results":[{"code":200.0,"status":"Object was created"}]}

Logs

[2021-02-16 11:57:57 +0100] information/ApiListener: New client connection from [::1]:42740 (no client certificate)
[2021-02-16 11:57:57 +0100] notice/ApiListener: New HTTP client
[2021-02-16 11:57:57 +0100] debug/HttpUtility: Request body: '{"package": "custom_package", "attrs": { "address": "192.168.1.1", "check_command": "hostalive", "vars.os" : "Linux", "zone": "master" }}'
[2021-02-16 11:57:57 +0100] notice/ConfigObjectUtility: Package custom_package doesn't exist yet, creating it.
[2021-02-16 11:57:57 +0100] notice/ConfigCompiler: Compiling config file: /home/iciga2/tests/master/var/lib/icinga2/api/packages/custom_package/9c7d6049-a95d-48e8-9a7b-71148be832ba/conf.d/hosts/test_host1.conf
[2021-02-16 11:57:57 +0100] debug/configitem: Committing 1 new items.
[2021-02-16 11:57:57 +0100] notice/WorkQueue: Spawning WorkQueue threads for 'ConfigObjectUtility::CreateObject'
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Commit called for ConfigItem Type=Host, Name=test_host1
[2021-02-16 11:57:57 +0100] debug/configitem: Committed 1 items of type 'Host'.
[2021-02-16 11:57:57 +0100] debug/configitem: Committed 1 items.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent OnAllConfigLoaded to 1 items of type 'Host'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 1 items of type 'Service'.
[2021-02-16 11:57:57 +0100] debug/configitem: Committing 2 new items.
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Commit called for ConfigItem Type=Service, Name=ping
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Commit called for ConfigItem Type=Service, Name=custom_service
[2021-02-16 11:57:57 +0100] debug/configitem: Committed 2 items of type 'Service'.
[2021-02-16 11:57:57 +0100] debug/configitem: Committed 2 items.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent OnAllConfigLoaded to 2 items of type 'Service'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 2 items of type 'ScheduledDowntime'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 2 items of type 'Downtime'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 2 items of type 'Dependency'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 2 items of type 'Notification'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 2 items of type 'Comment'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 1 items of type 'ScheduledDowntime'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 1 items of type 'Downtime'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 1 items of type 'Dependency'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 1 items of type 'Notification'.
[2021-02-16 11:57:57 +0100] debug/configitem: Committing 1 new items.
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Commit called for ConfigItem Type=Notification, Name=MyNotification
[2021-02-16 11:57:57 +0100] debug/configitem: Committed 1 items of type 'Notification'.
[2021-02-16 11:57:57 +0100] debug/configitem: Committed 1 items.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent OnAllConfigLoaded to 1 items of type 'Notification'.
[2021-02-16 11:57:57 +0100] debug/configitem: Sent CreateChildObjects to 1 items of type 'Comment'.
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Setting 'active' to true for object 'test_host1' of type 'Host'
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Setting 'active' to true for object 'test_host1!ping' of type 'Service'
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Setting 'active' to true for object 'test_host1!custom_service' of type 'Service'
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Setting 'active' to true for object 'test_host1!MyNotification' of type 'Notification'
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Activating object 'test_host1' of type 'Host' with priority 0
[2021-02-16 11:57:57 +0100] notice/ApiListener: Relaying 'event::SetNextCheck' message
[2021-02-16 11:57:57 +0100] debug/ApiListener: Sent update for object 'test_host1': {"config":"object Host \"test_host1\" {\n\taddress = \"192.168.1.1\"\n\tcheck_command = \"hostalive\"\n\tvars[\"os\"] = \"Linux\"\n\tversion = 1613473077.747474\n\tzone = \"master\"\n}\n","modified_attributes":{},"name":"test_host1","original_attributes":[],"package":"custom_package","type":"Host","version":1613473077.747474,"zone":"master"}
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Activating object 'test_host1!MyNotification' of type 'Notification' with priority 0
[2021-02-16 11:57:57 +0100] notice/ApiListener: Relaying 'config::UpdateObject' message
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Activating object 'test_host1!ping' of type 'Service' with priority 0
[2021-02-16 11:57:57 +0100] notice/ApiListener: Relaying 'event::SetNextCheck' message
[2021-02-16 11:57:57 +0100] debug/ConfigItem: Activating object 'test_host1!custom_service' of type 'Service' with priority 0
[2021-02-16 11:57:57 +0100] notice/ApiListener: Relaying 'event::SetNextCheck' message
[2021-02-16 11:57:57 +0100] notice/ApiListener: Updating object authority for objects at endpoint 'master'.
[2021-02-16 11:57:57 +0100] information/ConfigObjectUtility: Created and activated object 'test_host1' of type 'Host'.
[2021-02-16 11:57:57 +0100] notice/WorkQueue: Stopped WorkQueue threads for 'ConfigObjectUtility::CreateObject'
[2021-02-16 11:57:57 +0100] information/HttpServerConnection: Request: PUT /v1/objects/hosts/test_host1 (from [::1]:42740), user: root, agent: curl/7.71.1, status: OK).
[2021-02-16 11:57:57 +0100] information/HttpServerConnection: HTTP client disconnected (from [::1]:42740)

Test: delete an object of a custom package

Request

curl -X DELETE -v -k -H 'Accept: application/json' -u "root:admin" "https://localhost:5665/v1/objects/hosts/test_host1?package=custom_package&cascade=1" 

Response

{"results":[{"code":200.0,"errors":[],"name":"test_host1","status":"Object was deleted.","type":"Host"}]}

Logs

[2021-02-16 11:59:59 +0100] information/ApiListener: New client connection from [::1]:42756 (no client certificate)
[2021-02-16 11:59:59 +0100] notice/ApiListener: New HTTP client
[2021-02-16 11:59:59 +0100] debug/ApiListener: Sent delete for object 'test_host1!custom_service': {"name":"test_host1!custom_service","type":"Service","version":0.0}
[2021-02-16 11:59:59 +0100] notice/ApiListener: Relaying 'config::DeleteObject' message
[2021-02-16 11:59:59 +0100] information/ConfigObjectUtility: Deleted object 'test_host1!custom_service' of type 'Service'.
[2021-02-16 11:59:59 +0100] debug/ApiListener: Sent delete for object 'test_host1!ping': {"name":"test_host1!ping","type":"Service","version":0.0}
[2021-02-16 11:59:59 +0100] information/ConfigObjectUtility: Deleted object 'test_host1!ping' of type 'Service'.
[2021-02-16 11:59:59 +0100] notice/ApiListener: Relaying 'config::DeleteObject' message
[2021-02-16 11:59:59 +0100] debug/ApiListener: Sent delete for object 'test_host1!MyNotification': {"name":"test_host1!MyNotification","type":"Notification","version":0.0}
[2021-02-16 11:59:59 +0100] information/ConfigObjectUtility: Deleted object 'test_host1!MyNotification' of type 'Notification'.
[2021-02-16 11:59:59 +0100] notice/ApiListener: Relaying 'config::DeleteObject' message
[2021-02-16 11:59:59 +0100] debug/ApiListener: Sent delete for object 'test_host1': {"name":"test_host1","type":"Host","version":1613473077.747474}
[2021-02-16 11:59:59 +0100] notice/ApiListener: Relaying 'config::DeleteObject' message
[2021-02-16 11:59:59 +0100] information/ConfigObjectUtility: Deleted object 'test_host1' of type 'Host'.
[2021-02-16 11:59:59 +0100] information/HttpServerConnection: Request: DELETE /v1/objects/hosts/test_host1?cascade=1 (from [::1]:42756), user: root, agent: curl/7.71.1, status: OK).
[2021-02-16 11:59:59 +0100] information/HttpServerConnection: HTTP client disconnected (from [::1]:42756)

@icinga-probot icinga-probot bot added this to the 2.13.0 milestone Feb 16, 2021
@mcodato mcodato force-pushed the feature/api-parametrized-package-8639 branch 2 times, most recently from 614efe4 to a579f75 Compare April 8, 2021 15:40
@mcodato mcodato force-pushed the feature/api-parametrized-package-8639 branch from a579f75 to 5aacae7 Compare April 23, 2021 06:53
@Al2Klimov
Copy link
Member

@lippserd Are we definitively gonna support this (so shall I review it)?

@lippserd
Copy link
Member

lippserd commented May 3, 2021

@lippserd Are we definitively gonna support this (so shall I review it)?

Yes, please!

Copy link
Member

@Al2Klimov Al2Klimov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disallow operations on packages with names starting with underscores. Even _api shall not be specified explicitly, it’s just the default.

Copy link
Contributor

@julianbrost julianbrost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like validation of the package name is missing completely (should use ConfigPackageUtility::ValidateName()).

Have you considered what happens when Icinga 2 is restarted after this was used but without deploying a new config? I haven't tried but given that this attempts to update config files if they happen to match the file structure usually present in the _api package, I have the feeling that this might lead to inconsistencies.

lib/remote/configobjectutility.cpp Show resolved Hide resolved
Comment on lines 334 to 350
if (object->GetPackage() == "_api") {
String file;

try {
file = ConfigObjectUtility::GetObjectConfigPath(object->GetReflectionType(), object->GetName());
} catch (const std::exception& ex) {
Log(LogNotice, "ApiListener")
<< "Cannot sync object '" << object->GetName() << "': " << ex.what();
return;
}
String file;

std::ifstream fp(file.CStr(), std::ifstream::binary);
if (!fp)
return;
try {
file = ConfigObjectUtility::GetObjectConfigPath(object->GetReflectionType(), object->GetName(),
object->GetPackage());
} catch (const std::exception& ex) {
Log(LogNotice, "ApiListener")
<< "Cannot sync object '" << object->GetName() << "': " << ex.what();
return;
}

std::ifstream fp(file.CStr(), std::ifstream::binary);
if (fp) {
String content((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
params->Set("config", content);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this change. If the object is not the _api package, there's no guarantee that this file exists anyways. And if it's in the _api package, this changes the behavior when there's an error opening the file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change we support objects created via the API and objects created via the Director.

The config is used here in ConfigUpdateObjectAPIHandler in conjunction with the object to figure out if it is a new object.

If it is a new object created via API, the file will be present. If the object was created with the Director, when it is updated via API the file will not be found (the director uses different filenames) but the object will not be empty so the changes will be applied.

For sure if the file exists and an error occurs while reading, it will no longer fail here but fail here.

Do you suggest adding something like this in order to keep the same behavior for the _api package?

std::ifstream fp(file.CStr(), std::ifstream::binary);
if (fp) {
	String content((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
	params->Set("config", content);
} else if (!fp && object->GetPackage() == "_api") {
	return;
}

@mcodato mcodato force-pushed the feature/api-parametrized-package-8639 branch from 5aacae7 to 889d819 Compare May 31, 2021 10:26
@mcodato mcodato requested review from julianbrost and Al2Klimov May 31, 2021 10:28
@julianbrost julianbrost modified the milestones: 2.13.0, 2.14.0 Jun 7, 2021
for (const Dictionary::Pair& kv : attrs) {
key = kv.first;
obj->ModifyAttribute(kv.first, kv.second);
if (obj->GetPackage() != package) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @julianbrost , @Al2Klimov
we found the following problem with this check:

  • a host is created via the API in the package "director"
  • then it is edited via the icingaweb2 page (Overview -> Hosts -> Feature Commands)
  • the change is not applied because the code enters in this if

One possible solution is to validate the package only when the package parameter is specified in the API request.
Does this make sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a plan.

@mcodato mcodato force-pushed the feature/api-parametrized-package-8639 branch from 889d819 to 9e532e1 Compare August 27, 2021 14:21
@cla-bot cla-bot bot added the cla/signed label Aug 27, 2021
@mcodato mcodato force-pushed the feature/api-parametrized-package-8639 branch 2 times, most recently from 775af2f to 3d953ea Compare August 27, 2021 14:57
Allow deletion via API of objects belonging to any package

refs Icinga#8639
@mcodato mcodato force-pushed the feature/api-parametrized-package-8639 branch from 3d953ea to 818cf21 Compare November 23, 2021 09:07
Copy link
Contributor

@julianbrost julianbrost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, as this is quite a heavy change to some core functionality, I think this will probably need quite some more work, especially in testing.

It looks like this PR is interacting with modified attributes (i.e. runtime updates for non-API-created objects) in a strange way, see the inline comments for more details.

@@ -266,12 +271,6 @@ Value ApiListener::ConfigDeleteObjectAPIHandler(const MessageOrigin::Ptr& origin
return Empty;
}

if (object->GetPackage() != "_api") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of removing this check completely, can the package instead be added to the cluster message and then be checked here, that is indeed the expected package?

Comment on lines +113 to +115
String package = "_api";
if (params->Contains("package"))
package = params->Get("package");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value is only used as a parameter for ConfigObjectUtility::CreateObject(). I think it might also be a good idea to verify that the object is actually in the expected package in case of object updates.

if (params->Contains("package")) {
package = HttpUtility::GetLastParameter(params, "package");

if (!ConfigPackageUtility::ValidatePackageName(package) || package.GetData().at(0) == '_') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs #include "remote/configpackageutility.hpp" (only gives an error when building with -DICINGA2_UNITY_BUILD=OFF)

if (package == Empty) {
package = "_api";
} else {
if (!ConfigPackageUtility::ValidatePackageName(package) || package.GetData().at(0) == '_') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs #include "remote/configpackageutility.hpp" (only gives an error when building with -DICINGA2_UNITY_BUILD=OFF)

if (params->Contains("package")) {
package = HttpUtility::GetLastParameter(params, "package");

if (!ConfigPackageUtility::ValidatePackageName(package) || package.GetData().at(0) == '_') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs #include "remote/configpackageutility.hpp" (only gives an error when building with -DICINGA2_UNITY_BUILD=OFF)

Comment on lines -314 to -315
if (object->GetPackage() != "_api" && object->GetVersion() == 0)
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this PR, Icinga now sends loads of additional config update messages for all packages on startup, like this one:

debug/ApiListener: Sent update for object 'satellite-b-2!infrequent-check!dummy-service-notification': {"modified_attributes":{},"name":"satellite-b-2!infrequent-check!dummy-service-notification","original_attributes":[],"package":"_etc","type":"Notification","version":0,"zone":"master"}

I think this happens due to this check just being removed.

@Al2Klimov Al2Klimov removed their request for review January 10, 2022 15:05
@Al2Klimov Al2Klimov added the TBD To be defined - We aren't certain about this yet label Jan 20, 2023
@mcodato
Copy link
Contributor Author

mcodato commented Feb 7, 2023

As discussed with @lippserd, this PR is no more needed and can be discarded.

@mcodato mcodato closed this Feb 7, 2023
@icinga-probot icinga-probot bot removed this from the 2.14.0 milestone Feb 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla/signed TBD To be defined - We aren't certain about this yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants