Activating changes via API

I’m having a hard time figuring out how to activate changes via the api. It seems I need to find an etag first. However, the endpoint to get all pending changes provides multiple IDs (if there are multiple changes) but nothing called an etag.

Is there a simple way to just tell it to activate all changes? This was much easier prior to cmk 2.0.

On another API related topic, I’m also trying to run discovery on hosts via the api. Is this possible? I’ve tried ‘new’, ‘refresh’, ‘fix_all’, and ‘tabula_rasa’ but none of them actually add any services. This was also much easier on the old API.

Ok, so I got around the activating changes issue. The ETag is not in the payload of the get pending changes end point. It is in the headers. Is this documented somewhere? If so, I have not found that document.

I still have no idea how to run discovery on hosts via the api. The documentation on that is either incorrect, or I am misinterpreting it.

I wish I could have the cmk 2.2 gui with the 1.5 api.

1 Like

There was a post not long ago, about the same.
linking for reference: https://forum.checkmk.com/t/checkmk-rest-api-activation-error/43072

I think the answer you are looking for is also discussed there.

  • Glowsome

Yea its in the documentation, did you read it? I can agree that most API end-points are not well documented, but its clear that the eTag is an HTTP header, its even clear in the examples the documentation provides.

So what is the issue here? You just say its not working? I assume you have made an activate changes after the discovery as usual?

In the get all pending changes endpoint section of ReDoc it makes no mention of the etag at all, let alone that it is in the headers.

The issue with running discovery via the api is that it seems to do nothing. I don’t see errors. But discovery just doesn’t run.

If-Match

The value of the, to be modified, object’s ETag header. You can get this value by displaying the object it individually. To update this object the currently stored ETag needs to be the same as the one sent. The content of the ETag can potentially be anything and should be treated as semantically opaque.

There is no “get all pending changes”, I assume you mean “Activate pending changes” as was your original question?

If you have issues with discovery, perhaps that would help to post a separate post about that?
I have used both of these API end-points to enable new services and activate these and it works fine. not sure what version you are running as you did not mentioned that, so I assume its 2.2.0p17

It’s “show all pending changes.” That is the endpoint that has the ETag in it’s header. This is all the doc says:

Show all pending changes

This endpoint requires the following permissions:

  • Optionally:
    • Any of:
      • general.see_all: See all objects regardless of contacts and contact groups. If combined with ‘perform commands’ then commands may be done on all objects.
      • bi.see_all: With this permission set, the BI aggregation rules are applied to all hosts and services - not only those the user is a contact for. If you remove this permissions then the user will see incomplete aggregation trees with status based only on those items.
      • mkeventd.seeall: If a user lacks this permission then he/she can see only those events that originate from a host that he/she is a contact for.
AUTHORIZATIONS:

headerAuthwebserverAuthcookieAuth

Responses

200

OK: The operation was done successfully.

RESPONSE HEADERS Content-Type

required string

Example: “application/json”

A header specifying which type of content is in the request/response body. This is required when sending encoded data in a POST/PUT body. When the request body is empty, this header should not be sent.
X-Checkmk-Edition

required string

Example: “cre”

The checkmk edition.
X-Checkmk-Version

required string

Example: “2.2.0p10”

The checkmk version.

RESPONSE SCHEMA: application/json

links

required Array of objects (Link)

list of links to other resources.
domainType any

Default: “activation_run”

The domain type of the objects in the collection.
value Array of objects (ChangesFields)

The changes that are pending
extensions object

Additional attributes alongside the collection.

Yes, I’m on 2.2p17. I’ll see if I can get any info on the discovery that doesn’t want to run.

in perl I use this.

our @envvars;
$envvars{external_protocol} = "http";
$envvars{external_address} = "10.20.30.40";
$envvars{omdsite} = "my_sitename";



sub cmk_activate_changes {
  # this sub is used in the next sub (cmk_apply_pending_sysaid_changes) only
  my ($token, $etag, $site, $force_foreign_changes) = @_;
  $site = $envvars{omdsite} unless defined $site;
  $force_foreign_changes = JSON::false unless defined $force_foreign_changes;
  my $url = $envvars{external_protocol}.'://'.$envvars{external_address}.'/'.$envvars{omdsite}.'/check_mk/api/1.0/domain-types/activation_run/actions/activate-changes/invoke';
  my $header = [
    'Accept'          => 'application/json',
    'If-Match'        => $etag,  
    'Content-Type'    => 'application/json',
    'Authorization'   => "Bearer $token",
  ];
  my $data = {
    redirect              => JSON::false,
    sites                 => [$site],
    force_foreign_changes => $force_foreign_changes,
  };
  my $json_data = encode_json($data);
  my $ua = LWP::UserAgent->new;
  my $request = HTTP::Request->new('POST', $url, $header, $json_data);
  my $response = $ua->request($request);
  if ($response->is_success) {
    print "Checkmk rule changes activated successfully.\n";
    #print $response->decoded_content . "\n";
  } else {
    my $a = $response->status_line // '';  
    my $decoded_json = $response->decoded_content ? decode_json($response->decoded_content) : {};
    my $b = $decoded_json->{'detail'} // '';  
    print "Checkmk rule changes failed: ".$b."\n";  
  }
}


sub cmk_apply_pending_sysaid_changes {
  my ($token) = @_;
  my $r = "";
  my $a = "";
  my $user_agent_a = LWP::UserAgent->new;
  my $url = $envvars{external_protocol}.'://'.$envvars{external_address}.'/'.$envvars{omdsite}.'/check_mk/api/1.0/domain-types/activation_run/collections/pending_changes';
  my $header = [
    'Authorization' => "Bearer $token",
    'Accept'        => 'application/json',
    'Content-Type'  => 'application/json',
  ];
  my $request = HTTP::Request->new('GET', $url, $header); #, encode_json($content));
  my $response = $user_agent_a->request($request);
  if ($response->is_success) {
    $a = $response->decoded_content;
    my $etag = $response->header('etag');
    my $j = eval { decode_json($a) }; 
    if ($@) {
      die "Error decoding JSON: $@";
    }
    my @b = @{ $j->{'value'} };
    foreach my $c (@b) {
      if ($c->{'user_id'} eq "sysaid") {
        print "Applying pending changes for user sysaid: change_id ".$c->{'id'} . "\n";
      }
    }
    cmk_activate_changes($token,$etag);
  } else {
    my $a = $response->status_line // '';  
    my $decoded_json = $response->decoded_content ? decode_json($response->decoded_content) : {};
    my $b = $decoded_json->{'detail'} // '';        
    die "Error: " . $a." ".$b;
  }
}


my $token = "username password";
cmk_apply_pending_sysaid_changes($token);

Does this code (using force_foreign_changes=false) work when there are some changes made by other users?

I would like to activate only changes made by the script user.

I’m using Checkmk Raw Edition 2.3.0p9.

I get this error
HTTP Error 401: UNAUTHORIZED

Thanks.