Modified: trunk/CHANGES
===================================================================
--- trunk/CHANGES 2010-11-05 17:25:22 UTC (rev 5325)
+++ trunk/CHANGES 2010-11-07 22:24:42 UTC (rev 5326)
@@ -51,6 +51,7 @@
http://docs.opsview.com/doku.php?id=opsview-community:upgrading#opsview_391
As the old Opsview API did not clone the enable_snmp parameter correctly and since Enable SNMP overrides Use MRTG and Use NMIS,
you will need to confirm that this flag is set appropriately for each host. This only affects hosts cloned via the API.
+ The REST API now requires setting the content-type and accept headers to get the expected data
FIXES:
Fixed new creation of SNMP trap rule type service check redirecting to rules page on create/clone
Modified: trunk/opsview-core/lib/Opsview/API.pm
===================================================================
--- trunk/opsview-core/lib/Opsview/API.pm 2010-11-05 17:25:22 UTC (rev 5325)
+++ trunk/opsview-core/lib/Opsview/API.pm 2010-11-07 22:24:42 UTC (rev 5326)
@@ -91,11 +91,15 @@
$self->{content_type} = $content_type;
$self->{url_prefix} =~ s/\/$//; # Remove trailing / if present
$self->{url_prefix} .= "/rest";
- $self->{_mech} = WWW::Mechanize->new( autocheck => 1, sub { $self->throw(@_) }, stack_depth => 0 );
+ my $mech = WWW::Mechanize->new( autocheck => 1, sub { $self->throw(@_) }, stack_depth => 0 );
+ $self->{_mech} = $mech;
+
# Need to set this header to stop Apache from returning a gzip'd response. I think there is a bug in WWW::Mechanize
# where it is not uncompressing the result properly when a request is for json but response is in HTML
- $self->{_mech}->add_header( "Accept-Encoding" => "identity" );
+ $mech->add_header( "Accept-Encoding" => "identity" );
+ $mech->add_header( 'Content-Type' => $content_type );
+ $mech->add_header( 'Accept' => $content_type );
$self->{_logged_in} = 0;
$self->{error} = "";
@@ -128,6 +132,10 @@
my $data;
my $mech = $self->mech;
+ # Force login in perl format
+ $mech->add_header( 'Content-Type' => 'text/x-data-dumper' );
+ $mech->add_header( 'Accept' => 'text/x-data-dumper' );
+
# Check API version
$mech->get( $self->{url_prefix} );
@@ -137,7 +145,7 @@
}
# Login
- $mech->post( $self->{url_prefix} . "/login", { username => $self->{username}, password => $self->{password} } );
+ $mech->post( $self->{url_prefix} . "/login", Content => '{ username => "' . $self->{username} . '", password => "' . $self->{password} . '" }' );
$data = "" $mech->content;
if ( !$data->{token} ) {
$self->throw("No token found");
@@ -145,7 +153,7 @@
$self->{_mech}->add_header( "X-Opsview-Username", $self->{username} );
$self->{_mech}->add_header( "X-Opsview-Token", $data->{token} );
- # Set Content-type for input data and Accept for output
+ # Set requested Content-type for subsequent conversations
$self->mech->add_header( "Content-Type" => $self->{content_type} );
$self->mech->add_header( "Accept" => $self->{content_type} );
$self->{_logged_in} = 1;
Modified: trunk/opsview-web/lib/Opsview/Web/ControllerBase/REST.pm
===================================================================
--- trunk/opsview-web/lib/Opsview/Web/ControllerBase/REST.pm 2010-11-05 17:25:22 UTC (rev 5325)
+++ trunk/opsview-web/lib/Opsview/Web/ControllerBase/REST.pm 2010-11-07 22:24:42 UTC (rev 5326)
@@ -26,17 +26,21 @@
extends 'Catalyst::Controller::REST';
__PACKAGE__->config(
- 'default' => 'text/x-data-dumper',
+
+ # Do not set a default - this causes problems when a web page makes a request
+ # Documentation says you must set a content-type & accept header
+ #'default' => 'text/x-data-dumper',
json_options => { relaxed => 1, },
map => {
- 'text/html' => 'YAML::HTML',
- 'text/xml' => 'XMLSerialisation',
- 'text/x-yaml' => 'YAML',
- 'text/_javascript_' => 'JSONP',
- 'application/json' => 'JSON',
- 'text/json' => 'JSON',
- 'text/x-data-dumper' => [ 'Data::Serializer', 'Data::Dumper' ],
- 'application/x-www-form-urlencoded' => 'FormJSON',
+ 'text/html' => 'YAML::HTML',
+ 'text/xml' => 'XMLSerialisation',
+ 'text/x-yaml' => 'YAML',
+ 'text/_javascript_' => 'JSONP',
+ 'application/json' => 'JSON',
+ 'text/json' => 'JSON',
+ 'text/x-data-dumper' => [ 'Data::Serializer', 'Data::Dumper' ],
+
+ #'application/x-www-form-urlencoded' => 'FormJSON',
},
);
Modified: trunk/opsview-web/t/650-api2-version.t
===================================================================
--- trunk/opsview-web/t/650-api2-version.t 2010-11-05 17:25:22 UTC (rev 5325)
+++ trunk/opsview-web/t/650-api2-version.t 2010-11-07 22:24:42 UTC (rev 5326)
@@ -24,12 +24,13 @@
#my $ua = Test::WWW::Mechanize::Catalyst->new( stack_depth => 0 );
#my $json = Test::WWW::Mechanize::Catalyst->new( stack_depth => 0 );
my $ua = Test::WWW::Mechanize->new( stack_depth => 0 );
+$ua->add_header( 'content-type' => 'text/x-data-dumper' );
my $json = Test::WWW::Mechanize->new( stack_depth => 0 );
-$json->add_header( 'Accept' => "application/json" );
+$json->add_header( 'content-type' => "application/json" );
# Used for testing JSONP
my $js = Test::WWW::Mechanize->new( stack_depth => 0 );
-$js->add_header( 'Accept' => "text/_javascript_" );
+$js->add_header( 'content-type' => "text/_javascript_" );
# Bit rubbish, but couldn't get YAML to read opsview_web.yml directly
@@ -66,7 +67,8 @@
</html>
%, "Got expected data" );
-$ua->post_ok( "$url_prefix/rest/login", { username => "admin", password => "initial" }, "Login to API2" );
+$ua->post( "$url_prefix/rest/login", Content => qq%{ username => "admin", password => "initial" }%, "Login to API2" );
+is( $ua->status, 200 );
$ua->content_contains( "token", "Should return some ticket information" );
$content = $ua->content;
like( $content, qr%^\{'token' => '[0-9a-f]{40}'\}$%, "Got expected content" );
Modified: trunk/opsview-web/t/650-api2.t
===================================================================
--- trunk/opsview-web/t/650-api2.t 2010-11-05 17:25:22 UTC (rev 5325)
+++ trunk/opsview-web/t/650-api2.t 2010-11-07 22:24:42 UTC (rev 5326)
@@ -20,8 +20,9 @@
my $content;
my $expected;
my $ua = Test::WWW::Mechanize->new( stack_depth => 0 );
+$ua->add_header( 'content-type' => "text/x-data-dumper" );
my $json = Test::WWW::Mechanize->new( stack_depth => 0 );
-$json->add_header( 'Accept' => "application/json" );
+$json->add_header( 'content-type' => "application/json" );
my $url_prefix="http://localhost:3000";
$ua->get_ok("$url_prefix/rest");
@@ -40,27 +41,26 @@
is( $ua->status, 401, "Cannot DELETE session token as not authenticated");
is( $ua->content, "{'message' => 'Token invalid'}" );
-
-$ua->post( "$url_prefix/rest/login", { username => "fake", password => "stuff" }, "Failed login to API2" );
+$ua->post( "$url_prefix/rest/login", Content => qq%{ username => "fake", password => "stuff" }%, "Failed login to API2" );
$ua->content_contains( "Invalid login", "Invalid login" );
is( $ua->status, 401, "Unauthorized" );
$content = $ua->content;
is( $content, qq%{'message' => 'Invalid login'}%, 'Login error message' );
-$ua->post_ok( "$url_prefix/rest/login", { username => "admin", password => "initial" }, "Login to API2" );
+$ua->post( "$url_prefix/rest/login", Content => qq%{ username => "admin", password => "initial" }%, "Login to API2" );
+is( $ua->status, 200 );
$ua->content_contains( "token", "Should return some ticket information" );
$content = $ua->content;
like( $content, qr%^\{'token' => '[0-9a-f]{40}'\}$%, "Got expected content" );
my $data = "" $content;
like( $data->{token}, qr/^[0-9a-f]{40}$/, "Got token value" );
-$json->post_ok( "$url_prefix/rest/login", { username => "admin", password => "initial" }, "Login to API2, with JSON output" );
+$json->post( "$url_prefix/rest/login", Content => qq%{"username":"admin","password":"initial"}%, "Login to API2, with JSON output" );
+is( $json->status, 200 );
$json->content_contains( "token", "Should return some ticket information" );
$content = $json->content;
like( $content, qr%^\{"token":"[0-9a-f]{40}"\}$%, "Got JSON content" );
-$json->add_header( 'Content-type' => "application/json" );
-
# Have to use post. Cannot use post_ok as this converts Content into a request parameter
$json->post( "$url_prefix/rest/login", Content => qq%{"username":"admin","password":"initial"}% );
is( $json->status, 200, "Can login correctly" );
@@ -441,7 +441,8 @@
is_deeply( $res_data->{object}, $expected, "Expected return of data too" ) || diag("Full dump: ".Data::Dump::dump($res_data->{object}));
my $newbody = Test::WWW::Mechanize->new( stack_depth => 0 );
-$newbody->post( "$url_prefix/rest/login", { username => "newbody", password => "torso" }, "Check can login with password" );
+$newbody->add_header( 'content-type' => 'text/x-data-dumper' );
+$newbody->post( "$url_prefix/rest/login", Content => qq%{ username => "newbody", password => "torso" }%, "Check can login with password" );
is( $newbody->status, 200, "Login with password specified good to go!" );
$creation = { fullname => "Missing name", };
Modified: trunk/opsview-web/t/651-api2-acl.t
===================================================================
--- trunk/opsview-web/t/651-api2-acl.t 2010-11-05 17:25:22 UTC (rev 5325)
+++ trunk/opsview-web/t/651-api2-acl.t 2010-11-07 22:24:42 UTC (rev 5326)
@@ -21,9 +21,12 @@
my $content;
#my $ua = Test::WWW::Mechanize::Catalyst->new( stack_depth => 0 );
my $ua = Test::WWW::Mechanize->new( stack_depth => 0 );
+$ua->add_header( 'content-type' => 'text/x-data-dumper' );
my $readonly = Test::WWW::Mechanize->new( stack_depth => 0 );
+$readonly->add_header( 'content-type' => 'text/x-data-dumper' );
-$ua->post_ok("http://localhost:3000/rest/login", { username => "somehosts", password => "somehosts" }, "Login to API2 as somehosts" );
+$ua->post("http://localhost:3000/rest/login", Content => qq%{ username => "somehosts", password => "somehosts" }%, "Login to API2 as somehosts" );
+is( $ua->status, 200 );
$content = $ua->content;
like( $content, qr/token/, "Got token" );
my $data = "" $content;
@@ -50,7 +53,8 @@
$data = "" $ua->content;
is( $data->{summary}->{allrows}, 5, "Still only 5 - not hackable" );
-$readonly->post_ok("http://localhost:3000/rest/login", { username => "viewsomechangenone", password => "viewsomechangenone" }, "Login to API2 as viewsomechangenone" );
+$readonly->post("http://localhost:3000/rest/login", Content => qq%{ username => "viewsomechangenone", password => "viewsomechangenone" }%, "Login to API2 as viewsomechangenone" );
+is( $readonly->status, 200 );
$content = $readonly->content;
like( $content, qr/token/, "Got token" );
$data = "" $content;
Modified: trunk/opsview-web/t/652-api2-tests.t
===================================================================
--- trunk/opsview-web/t/652-api2-tests.t 2010-11-05 17:25:22 UTC (rev 5325)
+++ trunk/opsview-web/t/652-api2-tests.t 2010-11-07 22:24:42 UTC (rev 5326)
@@ -30,6 +30,8 @@
my $ua = Test::WWW::Mechanize->new( stack_depth => 0 );
rest_log_in( $ua, "admin", "initial" );
+$ua->add_header('content-type' => 'application/json' );
+
my $url_prefix = "http://localhost:3000";
my $testcase_dir = "$Bin/var/api";
Modified: trunk/opsview-web/t/654-api2-reload.t
===================================================================
--- trunk/opsview-web/t/654-api2-reload.t 2010-11-05 17:25:22 UTC (rev 5325)
+++ trunk/opsview-web/t/654-api2-reload.t 2010-11-07 22:24:42 UTC (rev 5326)
@@ -21,9 +21,11 @@
my $content;
my $expected;
my $ua = Test::WWW::Mechanize->new( stack_depth => 0 );
+$ua->add_header('content-type' => 'text/x-data-dumper' );
my $url_prefix="http://localhost:3000";
-$ua->post_ok( "$url_prefix/rest/login", { username => "admin", password => "initial" }, "Login to API2" );
+$ua->post( "$url_prefix/rest/login", Content => qq%{ username => "admin", password => "initial" }%, "Login to API2" );
+is( $ua->status, 200 );
$ua->content_contains( "token", "Should return some ticket information" );
$content = $ua->content;
like( $content, qr%^\{'token' => '[0-9a-f]{40}'\}$%, "Got expected content" );
@@ -73,7 +75,8 @@
system("/usr/local/nagios/utils/test_db_post");
-$ua->post_ok("$url_prefix/rest/reload");
+$ua->post("$url_prefix/rest/reload");
+is( $ua->status, 200 );
$res_data = eval $ua->content;
is( $res_data->{server_status}, "4", "Some warnings for server status" );
is( $res_data->{configuration_status}, "uptodate", "Now configuration up to date" );
Added: trunk/opsview-web/t/656-api2-lib.t
===================================================================
--- trunk/opsview-web/t/656-api2-lib.t (rev 0)
+++ trunk/opsview-web/t/656-api2-lib.t 2010-11-07 22:24:42 UTC (rev 5326)
@@ -0,0 +1,67 @@
+#!/usr/bin/perl
+# Test REST via Opsview::API
+
+use warnings;
+use strict;
+use FindBin qw($Bin);
+use lib "$Bin/../lib";
+
+use lib "/usr/local/nagios/lib", "/usr/local/nagios/etc", "/usr/local/nagios/t/lib";
+
+use Test::More qw(no_plan);
+use Test::Deep;
+
+use Opsview::Test qw(opsview);
+use Test::WWW::Mechanize;
+
+use Data::Dump qw(dump);
+
+use Opsview::API;
+use JSON qw(decode_json);
+
+my ($content, $data);
+
+my $ua = Opsview::API->new(
+ username => "admin",
+ password => "initial",
+ api_min_version => "2.0",
+ data_format => "json",
+ url_prefix => "http://localhost",
+);
+
+$ua->login;
+
+$ua->get( "info" );
+like( $ua->content, qr/"opsview_edition":"(community|enterprise)"/, "Data in JSON" );
+
+$ua->get( "config/host?s.name=cisco4" );
+is( $ua->mech->status, 200 );
+$content = $ua->content;
+$data = "" $content );
+is( $data->{summary}->{rows}, 1, "Got 1 host" ) || diag( Data::Dump::dump( $data ) );
+is( $data->{list}->[0]->{id}, 11, "With right id" );
+
+$ua->put( "config/host/1", '{"name":"opsview", "alias":"changed by rest api"}' );
+is( $ua->mech->status, 200 );
+$content = $ua->content;
+$data = "" $content );
+is( $data->{object}->{id}, 1, "Got object back" );
+is( $data->{object}->{alias}, "changed by rest api", "changed by rest api" );
+
+eval {
+ $ua->post( "config/host", '{"name":"opsview"}' );
+};
+is( $ua->mech->status, 400 );
+$content = $ua->content;
+$data = "" $content );
+is( $data->{message}, "Error trying to create object") || diag(Data::Dump::dump( $data ));
+like( $data->{detail}, qr/Duplicate entry/ );
+
+$ua->delete( "config/host/11" );
+is( $ua->mech->status, 200, "Delete ok" );
+$ua->get( "config/host?s.name=cisco4" );
+is( $ua->mech->status, 200 );
+$content = $ua->content;
+$data = "" $content );
+is( $data->{summary}->{rows}, 0 );
+
Modified: trunk/opsview-web/t/lib/Opsview/TestUtils.pm
===================================================================
--- trunk/opsview-web/t/lib/Opsview/TestUtils.pm 2010-11-05 17:25:22 UTC (rev 5325)
+++ trunk/opsview-web/t/lib/Opsview/TestUtils.pm 2010-11-07 22:24:42 UTC (rev 5326)
@@ -72,7 +72,8 @@
sub rest_log_in {
my ( $mech, $user, $pass ) = @_;
witter("Logging in as $user") if ( $ENV{VERBOSE_TESTS} );
- $mech->post( "http://localhost:3000/rest/login", { username => $user, password => $pass } );
+ $mech->add_header( 'content-type' => 'text/x-data-dumper' );
+ $mech->post( "http://localhost:3000/rest/login", Content => "{ username => $user, password => $pass }" );
is( $mech->status, 200, "Logged in to REST okay" );
my $content = eval $mech->content;
$mech->add_header( "X-Opsview-Username" => $user );