TEST_F(MesosSchedulerDriverTest, MetricsEndpoint) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL); Future<Nothing> registered; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureSatisfy(®istered)); ASSERT_EQ(DRIVER_RUNNING, driver.start()); AWAIT_READY(registered); Future<process::http::Response> response = process::http::get(MetricsProcess::instance()->self(), "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); ASSERT_SOME(parse); JSON::Object metrics = parse.get(); EXPECT_EQ(1u, metrics.values.count("scheduler/event_queue_messages")); EXPECT_EQ(1u, metrics.values.count("scheduler/event_queue_dispatches")); driver.stop(); driver.join(); }
// Testing route without authorization header. TEST_F(TeardownTest, TeardownEndpointNoHeader) { Try<PID<Master> > master = StartMaster(); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); Future<FrameworkID> frameworkId; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureArg<1>(&frameworkId)); ASSERT_EQ(DRIVER_RUNNING, driver.start()); AWAIT_READY(frameworkId); Future<Response> response = process::http::post( master.get(), "teardown", None(), "frameworkId=" + frameworkId.get().value()); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ( Unauthorized("Mesos master").status, response); driver.stop(); driver.join(); Shutdown(); }
// This test expects a BadRequest when 'Content-Type' is omitted. TEST_F(ExecutorHttpApiTest, NoContentType) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); Call call; call.set_type(Call::MESSAGE); call.mutable_message()->set_data("hello world"); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); Future<Response> response = process::http::post( slave.get(), "api/v1/executor", None(), serialize(ContentType::JSON, call), None()); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); Shutdown(); }
// Testing route without frameworkId value. TEST_F(TeardownTest, TeardownEndpointNoFrameworkId) { Try<PID<Master> > master = StartMaster(); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); Future<FrameworkID> frameworkId; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureArg<1>(&frameworkId)); ASSERT_EQ(DRIVER_RUNNING, driver.start()); AWAIT_READY(frameworkId); process::http::Headers headers; headers["Authorization"] = "Basic " + base64::encode(DEFAULT_CREDENTIAL.principal() + ":" + DEFAULT_CREDENTIAL.secret()); Future<Response> response = process::http::post(master.get(), "teardown", headers, ""); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); driver.stop(); driver.join(); Shutdown(); }
// Testing route without frameworkId value. TEST_F(TeardownTest, NoFrameworkId) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL); Future<FrameworkID> frameworkId; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureArg<1>(&frameworkId)); ASSERT_EQ(DRIVER_RUNNING, driver.start()); AWAIT_READY(frameworkId); Future<Response> response = process::http::post( master.get()->pid, "teardown", createBasicAuthHeaders(DEFAULT_CREDENTIAL), ""); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); driver.stop(); driver.join(); }
// Testing route with bad credentials. TEST_F(TeardownTest, BadCredentials) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL); Future<FrameworkID> frameworkId; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureArg<1>(&frameworkId)); ASSERT_EQ(DRIVER_RUNNING, driver.start()); AWAIT_READY(frameworkId); Credential badCredential; badCredential.set_principal("badPrincipal"); badCredential.set_secret("badSecret"); Future<Response> response = process::http::post( master.get()->pid, "teardown", createBasicAuthHeaders(badCredential), "frameworkId=" + frameworkId.get().value()); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response); driver.stop(); driver.join(); }
// This test sends a GET request to the executor HTTP endpoint instead // of a POST. The call should return a MethodNotAllowed response. TEST_F(ExecutorHttpApiTest, GetRequest) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); Future<Response> response = process::http::get( slave.get(), "api/v1/executor"); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(MethodNotAllowed().status, response); Shutdown(); }
// This test sends a malformed body that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_P(ExecutorHttpApiTest, MalformedContent) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); const string body = "MALFORMED_CONTENT"; const ContentType contentType = GetParam(); process::http::Headers headers; headers["Accept"] = stringify(contentType); Future<Response> response = process::http::post( slave.get(), "api/v1/executor", headers, body, stringify(contentType)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); Shutdown(); }
// This test sends a valid JSON blob that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_F(ExecutorHttpApiTest, ValidJsonButInvalidProtobuf) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); JSON::Object object; object.values["string"] = "valid_json"; process::http::Headers headers; headers["Accept"] = APPLICATION_JSON; Future<Response> response = process::http::post( slave.get(), "api/v1/executor", headers, stringify(object), APPLICATION_JSON); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); Shutdown(); }
// This test sets an unsupported media type as Content-Type. This // should result in a 415 (UnsupportedMediaType) response. TEST_P(SchedulerHttpApiTest, UnsupportedContentMediaType) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); const string contentType = GetParam(); process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); headers["Accept"] = contentType; Call call; call.set_type(Call::SUBSCRIBE); Call::Subscribe* subscribe = call.mutable_subscribe(); subscribe->mutable_framework_info()->CopyFrom(v1::DEFAULT_FRAMEWORK_INFO); const string unknownMediaType = "application/unknown-media-type"; Future<Response> response = process::http::post( master.get()->pid, "api/v1/scheduler", headers, serialize(call, contentType), unknownMediaType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(UnsupportedMediaType().status, response); }
// This test verifies that only authorized principals // can access the '/flags' endpoint. TYPED_TEST(SlaveAuthorizerTest, AuthorizeFlagsEndpoint) { const string endpoint = "flags"; // Setup ACLs so that only the default principal // can access the '/flags' endpoint. ACLs acls; acls.set_permissive(false); mesos::ACL::GetEndpoint* acl = acls.add_get_endpoints(); acl->mutable_principals()->add_values(DEFAULT_CREDENTIAL.principal()); acl->mutable_paths()->add_values("/" + endpoint); // Create an `Authorizer` with the ACLs. Try<Authorizer*> create = TypeParam::create(parameterize(acls)); ASSERT_SOME(create); Owned<Authorizer> authorizer(create.get()); StandaloneMasterDetector detector; Try<Owned<cluster::Slave>> agent = this->StartSlave(&detector, authorizer.get()); ASSERT_SOME(agent); Future<Response> response = http::get( agent.get()->pid, endpoint, None(), createBasicAuthHeaders(DEFAULT_CREDENTIAL)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response) << response.get().body; response = http::get( agent.get()->pid, endpoint, None(), createBasicAuthHeaders(DEFAULT_CREDENTIAL_2)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(Forbidden().status, response) << response.get().body; }
TEST_F(SchedulerHttpApiTest, AuthenticationRequired) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Future<Response> response = process::http::post( master.get()->pid, "api/v1/scheduler", None(), None()); AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response); }
TEST_F(SchedulerHttpApiTest, GetRequest) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Future<Response> response = process::http::get( master.get()->pid, "api/v1/scheduler", None(), createBasicAuthHeaders(DEFAULT_CREDENTIAL)); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(MethodNotAllowed({"POST"}).status, response); }
JSON::Object Metrics() { process::UPID upid("metrics", process::address()); process::Future<process::http::Response> response = process::http::get(upid, "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); CHECK_SOME(parse); return parse.get(); }
// Testing route with bad ACLs. TEST_F(TeardownTest, TeardownEndpointBadACLs) { // Setup ACLs so that no principal can do teardown the framework. ACLs acls; mesos::ACL::ShutdownFramework* acl = acls.add_shutdown_frameworks(); acl->mutable_principals()->set_type(mesos::ACL::Entity::NONE); acl->mutable_framework_principals()->add_values( DEFAULT_CREDENTIAL.principal()); master::Flags flags = CreateMasterFlags(); flags.acls = acls; Try<PID<Master> > master = StartMaster(flags); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); Future<FrameworkID> frameworkId; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureArg<1>(&frameworkId)); ASSERT_EQ(DRIVER_RUNNING, driver.start()); AWAIT_READY(frameworkId); process::http::Headers headers; headers["Authorization"] = "Basic " + base64::encode(DEFAULT_CREDENTIAL.principal() + ":" + DEFAULT_CREDENTIAL.secret()); Future<Response> response = process::http::post( master.get(), "teardown", headers, "frameworkId=" + frameworkId.get().value()); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ( Unauthorized("Mesos master").status, response); driver.stop(); driver.join(); Shutdown(); }
// TODO(anand): Add additional tests for validation. TEST_F(SchedulerHttpApiTest, NoContentType) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); // Expect a BadRequest when 'Content-Type' is omitted. // // TODO(anand): Send a valid call here to ensure that // the BadRequest is only due to the missing header. Future<Response> response = process::http::post( master.get()->pid, "api/v1/scheduler", createBasicAuthHeaders(DEFAULT_CREDENTIAL), None()); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
// This test verifies if the role is invalid in scheduler's framework message, // the event is error on the stream in response to a Subscribe call request. TEST_P(SchedulerHttpApiTest, RejectFrameworkWithInvalidRole) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); Call call; call.set_type(Call::SUBSCRIBE); Call::Subscribe* subscribe = call.mutable_subscribe(); v1::FrameworkInfo framework = v1::DEFAULT_FRAMEWORK_INFO; // Set invalid role. framework.set_role("/test/test1"); subscribe->mutable_framework_info()->CopyFrom(framework); // Retrieve the parameter passed as content type to this test. const string contentType = GetParam(); process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); headers["Accept"] = contentType; Future<Response> response = process::http::streaming::post( master.get()->pid, "api/v1/scheduler", headers, serialize(call, contentType), contentType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ("chunked", "Transfer-Encoding", response); ASSERT_EQ(Response::PIPE, response.get().type); Option<Pipe::Reader> reader = response.get().reader; ASSERT_SOME(reader); auto deserializer = lambda::bind( &SchedulerHttpApiTest::deserialize, this, contentType, lambda::_1); Reader<Event> responseDecoder(Decoder<Event>(deserializer), reader.get()); Future<Result<Event>> event = responseDecoder.read(); AWAIT_READY(event); ASSERT_SOME(event.get()); // Check event type is error. ASSERT_EQ(Event::ERROR, event.get().get().type()); }
JSON::Object Metrics() { process::UPID upid("metrics", process::address()); process::Future<process::http::Response> response = process::http::get(upid, "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response); EXPECT_SOME_EQ( "application/json", response.get().headers.get("Content-Type")); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); CHECK_SOME(parse); return parse.get(); }
JSON::Object Metrics() { process::UPID upid("metrics", process::address()); // TODO(neilc): This request might timeout if the current value of a // metric cannot be determined. In tests, a common cause for this is // MESOS-6231 when multiple scheduler drivers are in use. process::Future<process::http::Response> response = process::http::get(upid, "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); CHECK_SOME(parse); return parse.get(); }
TEST_F(FilesTest, ReadTest) { Files files; process::UPID upid("files", process::address()); Future<Response> response = process::http::get(upid, "read.json"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ( "Expecting 'path=value' in query.\n", response); response = process::http::get(upid, "read.json", "path=none&offset=hello"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ( "Failed to parse offset: Failed to convert 'hello' to number.\n", response); response = process::http::get(upid, "read.json", "path=none&length=hello"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ( "Failed to parse length: Failed to convert 'hello' to number.\n", response); // Now write a file. ASSERT_SOME(os::write("file", "body")); AWAIT_EXPECT_READY(files.attach("file", "/myname")); AWAIT_EXPECT_READY(files.attach("file", "myname")); // Read a valid file. JSON::Object expected; expected.values["offset"] = 0; expected.values["data"] = "body"; response = process::http::get(upid, "read.json", "path=/myname&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); response = process::http::get(upid, "read.json", "path=myname&offset=0"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); AWAIT_EXPECT_RESPONSE_BODY_EQ(stringify(expected), response); // Missing file. AWAIT_EXPECT_RESPONSE_STATUS_EQ( NotFound().status, process::http::get(upid, "read.json", "path=missing")); }
// Tests that requests for an agent endpoint // always succeed if the authorizer is absent. TEST_P(SlaveEndpointTest, NoAuthorizer) { const string endpoint = GetParam(); StandaloneMasterDetector detector; Try<Owned<cluster::Slave>> agent = StartSlave(&detector, CreateSlaveFlags()); ASSERT_SOME(agent); Future<Response> response = http::get( agent.get()->pid, endpoint, None(), createBasicAuthHeaders(DEFAULT_CREDENTIAL)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response) << response.get().body; }
// This test verifies the correct handling of the statistics // endpoint when there is no executor running. TEST(MonitorTest, NoExecutor) { ResourceMonitor monitor([]() -> Future<ResourceUsage> { return ResourceUsage(); }); UPID upid("monitor", process::address()); Future<http::Response> response = http::get(upid, "statistics"); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response); AWAIT_EXPECT_RESPONSE_HEADER_EQ( "application/json", "Content-Type", response); AWAIT_EXPECT_RESPONSE_BODY_EQ("[]", response); }
// This test sends a unsupported Accept media type for the Accept // header. The response should be NotAcceptable in this case. TEST_P(ExecutorHttpApiTest, NotAcceptable) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); // Retrieve the parameter passed as content type to this test. const ContentType contentType = GetParam(); process::http::Headers headers; headers["Accept"] = "foo"; // Only subscribe needs to 'Accept' JSON or protobuf. Call call; call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); call.set_type(Call::SUBSCRIBE); call.mutable_subscribe(); Future<Response> response = process::http::streaming::post( slave.get(), "api/v1/executor", headers, serialize(contentType, call), stringify(contentType)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(NotAcceptable().status, response); Shutdown(); }
// This test sends a valid JSON blob that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_F(SchedulerHttpApiTest, ValidJsonButInvalidProtobuf) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); JSON::Object object; object.values["string"] = "valid_json"; process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); headers["Accept"] = APPLICATION_JSON; Future<Response> response = process::http::post( master.get()->pid, "api/v1/scheduler", headers, stringify(object), APPLICATION_JSON); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
// This test sends a malformed body that cannot be deserialized // into a valid protobuf resulting in a BadRequest. TEST_P(SchedulerHttpApiTest, MalformedContent) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); const string body = "MALFORMED_CONTENT"; const string contentType = GetParam(); process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); headers["Accept"] = contentType; Future<Response> response = process::http::post( master.get()->pid, "api/v1/scheduler", headers, body, contentType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response); }
// This test sets an unsupported media type as Content-Type. This // should result in a 415 (UnsupportedMediaType) response. TEST_P(ExecutorHttpApiTest, UnsupportedContentMediaType) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); ContentType contentType = GetParam(); process::http::Headers headers; headers["Accept"] = stringify(contentType); Call call; call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); call.set_type(Call::SUBSCRIBE); call.mutable_subscribe(); const string unknownMediaType = "application/unknown-media-type"; Future<Response> response = process::http::post( slave.get(), "api/v1/executor", headers, serialize(contentType, call), unknownMediaType); AWAIT_EXPECT_RESPONSE_STATUS_EQ(UnsupportedMediaType().status, response); Shutdown(); }
// Testing route with deprecated (but still good) ACLs. // This ACL/test will be removed at the end of the deprecation cycle on 0.27. TEST_F(TeardownTest, GoodDeprecatedACLs) { // Setup ACLs so that the default principal can teardown the // framework. ACLs acls; mesos::ACL::ShutdownFramework* acl = acls.add_shutdown_frameworks(); acl->mutable_principals()->add_values(DEFAULT_CREDENTIAL.principal()); acl->mutable_framework_principals()->add_values( DEFAULT_CREDENTIAL.principal()); master::Flags flags = CreateMasterFlags(); flags.acls = acls; Try<Owned<cluster::Master>> master = StartMaster(flags); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL); Future<FrameworkID> frameworkId; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureArg<1>(&frameworkId)); ASSERT_EQ(DRIVER_RUNNING, driver.start()); AWAIT_READY(frameworkId); Future<Response> response = process::http::post( master.get()->pid, "teardown", createBasicAuthHeaders(DEFAULT_CREDENTIAL), "frameworkId=" + frameworkId.get().value()); AWAIT_READY(response); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); driver.stop(); driver.join(); }
// This test verifies that access to the '/flags' endpoint can be authorized // without authentication if an authorization rule exists that applies to // anyone. The authorizer will map the absence of a principal to "ANY". TYPED_TEST(SlaveAuthorizerTest, AuthorizeFlagsEndpointWithoutPrincipal) { const string endpoint = "flags"; // Because the authenticators' lifetime is tied to libprocess's lifetime, // it may already be set by other tests. We have to unset it here to disable // HTTP authentication. // TODO(nfnt): Fix this behavior. The authenticator should be unset by // every test case that sets it, similar to how it's done for the master. http::authentication::unsetAuthenticator( slave::DEFAULT_HTTP_AUTHENTICATION_REALM); // Setup ACLs so that any principal can access the '/flags' endpoint. ACLs acls; acls.set_permissive(false); mesos::ACL::GetEndpoint* acl = acls.add_get_endpoints(); acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY); acl->mutable_paths()->add_values("/" + endpoint); slave::Flags agentFlags = this->CreateSlaveFlags(); agentFlags.acls = acls; agentFlags.authenticate_http = false; agentFlags.http_credentials = None(); // Create an `Authorizer` with the ACLs. Try<Authorizer*> create = TypeParam::create(parameterize(acls)); ASSERT_SOME(create); Owned<Authorizer> authorizer(create.get()); StandaloneMasterDetector detector; Try<Owned<cluster::Slave>> agent = this->StartSlave( &detector, authorizer.get(), agentFlags); ASSERT_SOME(agent); Future<Response> response = http::get(agent.get()->pid, endpoint); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response) << response.get().body; }
// Tests that an agent endpoint handler forms // correct queries against the authorizer. TEST_P(SlaveEndpointTest, AuthorizedRequest) { const string endpoint = GetParam(); StandaloneMasterDetector detector; MockAuthorizer mockAuthorizer; Try<Owned<cluster::Slave>> agent = StartSlave(&detector, &mockAuthorizer); ASSERT_SOME(agent); Future<authorization::Request> request; EXPECT_CALL(mockAuthorizer, authorized(_)) .WillOnce(DoAll(FutureArg<0>(&request), Return(true))); Future<Response> response = http::get( agent.get()->pid, endpoint, None(), createBasicAuthHeaders(DEFAULT_CREDENTIAL)); AWAIT_READY(request); const string principal = DEFAULT_CREDENTIAL.principal(); EXPECT_EQ(principal, request.get().subject().value()); // TODO(bbannier): Once agent endpoint handlers use more than just // `GET_ENDPOINT_WITH_PATH` we should factor out the request method // and expected authorization action and parameterize // `SlaveEndpointTest` on that as well in addition to the endpoint. EXPECT_EQ(authorization::GET_ENDPOINT_WITH_PATH, request.get().action()); EXPECT_EQ("/" + endpoint, request.get().object().value()); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response) << response.get().body; }
// Tests that unauthorized requests for an agent endpoint are properly rejected. TEST_P(SlaveEndpointTest, UnauthorizedRequest) { const string endpoint = GetParam(); StandaloneMasterDetector detector; MockAuthorizer mockAuthorizer; Try<Owned<cluster::Slave>> agent = StartSlave(&detector, &mockAuthorizer); ASSERT_SOME(agent); EXPECT_CALL(mockAuthorizer, authorized(_)) .WillOnce(Return(false)); Future<Response> response = http::get( agent.get()->pid, endpoint, None(), createBasicAuthHeaders(DEFAULT_CREDENTIAL)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(Forbidden().status, response) << response.get().body; }