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 health checkendpoint #75

Merged
merged 1 commit into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions api/src/gmsa_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,149 @@ class CredentialsFetcherImpl final
}

private:
// Class encompasing the state and logic needed to serve a request.
class CallDataHealthCheck
{
public:
std::string cookie;

#define CLASS_NAME_CallDataHealthCheck "CallDataHealthCheck"
// Take in the "service" instance (in this case representing an asynchronous
// server) and the completion queue "cq" used for asynchronous communication
// with the gRPC runtime.
CallDataHealthCheck(
credentialsfetcher::CredentialsFetcherService::AsyncService* service,
grpc::ServerCompletionQueue* cq )
: service_( service )
, cq_( cq )
, health_check_responder_( &health_check_ctx_ )
, status_( CREATE )
{
cookie = CLASS_NAME_CallDataHealthCheck;
// Invoke the serving logic right away.
Proceed();
}

void Proceed(creds_fetcher::CF_logger& cf_logger)
{
if ( cookie.compare( CLASS_NAME_CallDataHealthCheck ) != 0 )
{
return;
}
printf( "CallDataHealthCheck %p status: %d\n", this, status_ );
if ( status_ == CREATE )
{
// Make this instance progress to the PROCESS state.
status_ = PROCESS;

// As part of the initial CREATE state, we *request* that the system
// start processing RequestHealthCheck requests. In this request, "this" acts
// are the tag uniquely identifying the request (so that different CallData
// instances can serve different requests concurrently), in this case
// the memory address of this CallData instance.

service_->RequestHealthCheck( &health_check_ctx_, &health_check_request_,
&health_check_responder_, cq_, cq_, this );
}
else if ( status_ == PROCESS )
{
// Spawn a new CallData instance to serve new clients while we process
// the one for this CallData. The instance will deallocate itself as
// part of its FINISH state.
new CallDataHealthCheck( service_, cq_ );

// The actual processing.
health_check_reply_.set_status( "OK" );
status_ = FINISH;
health_check_responder_.Finish( health_check_reply_, grpc::Status::OK, this );

}
else
{
GPR_ASSERT( status_ == FINISH );
// Once in the FINISH state, deallocate ourselves (CallData).
delete this;
}

return;
}
void Proceed()
{
if ( cookie.compare( CLASS_NAME_CallDataHealthCheck ) != 0 )
{
return;
}
printf( "CallHealthCheck %p status: %d\n", this, status_ );
if ( status_ == CREATE )
{
// Make this instance progress to the PROCESS state.
status_ = PROCESS;

// As part of the initial CREATE state, we *request* that the system
// start processing RequestHealthCheck requests. In this request, "this" acts
// are the tag uniquely identifying the request (so that different CallData
// instances can serve different requests concurrently), in this case
// the memory address of this CallData instance.

service_->RequestHealthCheck( &health_check_ctx_, &health_check_request_,
&health_check_responder_, cq_, cq_, this );
}
else if ( status_ == PROCESS )
{
// Spawn a new CallData instance to serve new clients while we process
// the one for this CallData. The instance will deallocate itself as
// part of its FINISH state.
new CallDataHealthCheck( service_, cq_ );

// The actual processing.
health_check_reply_.set_status( "OK" );

// And we are done! Let the gRPC runtime know we've finished, using the
// memory address of this instance as the uniquely identifying tag for
// the event.
status_ = FINISH;
health_check_responder_.Finish( health_check_reply_, grpc::Status::OK, this );
}
else
{
GPR_ASSERT( status_ == FINISH );
// Once in the FINISH state, deallocate ourselves (CallData).
delete this;
}

return;
}

private:
// The means of communication with the gRPC runtime for an asynchronous
// server.
credentialsfetcher::CredentialsFetcherService::AsyncService* service_;
// The producer-consumer queue where for asynchronous server notifications.
grpc::ServerCompletionQueue* cq_;
// Context for the rpc, allowing to tweak aspects of it such as the use
// of compression, authentication, as well as to send metadata back to the
// client.
grpc::ServerContext health_check_ctx_;

// What we get from the client.
credentialsfetcher::HealthCheckRequest health_check_request_;
// What we send back to the client.
credentialsfetcher::HealthCheckResponse health_check_reply_;

// The means to get back to the client.
grpc::ServerAsyncResponseWriter<credentialsfetcher::HealthCheckResponse>
health_check_responder_;

// Let's implement a tiny state machine with the following states.
enum CallStatus
{
CREATE,
PROCESS,
FINISH
};
CallStatus status_; // The current serving state.
};

// Class encompasing the state and logic needed to serve a request.
class CallDataCreateKerberosLease
{
Expand Down Expand Up @@ -1024,6 +1167,7 @@ class CredentialsFetcherImpl final
new CallDataAddNonDomainJoinedKerberosLease ( &service_, cq_.get() );
new CallDataRenewNonDomainJoinedKerberosLease ( &service_, cq_.get() );
new CallDataDeleteKerberosLease( &service_, cq_.get() );
new CallDataHealthCheck( &service_, cq_.get() );

while ( pthread_shutdown_signal != nullptr && !( *pthread_shutdown_signal ) )
{
Expand All @@ -1046,6 +1190,7 @@ class CredentialsFetcherImpl final
aws_sm_secret_name );
static_cast<CallDataDeleteKerberosLease*>( got_tag )->Proceed( krb_files_dir, cf_logger,
aws_sm_secret_name );
static_cast<CallDataHealthCheck*>( got_tag )->Proceed( cf_logger);
}
}

Expand Down
49 changes: 49 additions & 0 deletions api/tests/gmsa_test_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,38 @@ class CredentialsFetcherClient
{
}

/**
* Health check method
* @return
*/
std::string HealthCheckMethod( std::string service_name )
{
std::string result;
// Prepare request
credentialsfetcher::HealthCheckRequest request;
request.set_service( service_name );

credentialsfetcher::HealthCheckResponse response;
grpc::ClientContext context;
grpc::Status status;

// Send request
status = _stub->HealthCheck( &context, request, &response );

// Handle response
if ( status.ok() )
{
return response.status();
}
else
{
std::cerr << status.error_code() << ": " << status.error_message() << std::endl;
return response.status();
}
}



/**
* Test method to create kerberos tickets
* @param credspec_contents - information of service account
Expand Down Expand Up @@ -235,6 +267,7 @@ static void show_usage( std::string name )
std::cout << "Usage: " << name << " <option(s)> SOURCES"
<< "Options:\n"
<< "\t-h,--help\t\tShow this help message\n"
<< "\t --check \t\thealth check of daemon\n"
<< "\t-no option\t\tcreate & delete kerberos tickets\n"
<< "\t --create \t\tcreate krb tickets for service account\n"
<< "\t --delete \t\tdelete krb tickets for a given lease_id\tprovide lease_id to be "
Expand All @@ -249,6 +282,17 @@ static void show_usage( std::string name )
<< std::endl;
}

// health check daemon
std::string health_check(
CredentialsFetcherClient& client)
{
std::string health_check_response =
client.HealthCheckMethod("cfservice");
std::cout << "Client received output for health check: "
<< health_check_response << std::endl;
return health_check_response;
}

// create kerberos tickets
std::pair<std::string, std::list<std::string>> create_krb_ticket(
CredentialsFetcherClient& client, std::list<std::string> credspec_contents )
Expand Down Expand Up @@ -438,6 +482,11 @@ int main( int argc, char** argv )
show_usage( argv[0] );
return 0;
}
else if ( arg == "--check" )
{
health_check(client);
return 0;
}
else if ( arg == "--delete" )
{
if ( i + 1 < argc )
Expand Down
9 changes: 9 additions & 0 deletions protos/credentialsfetcher.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ service CredentialsFetcherService {
rpc RenewNonDomainJoinedKerberosLease
(RenewNonDomainJoinedKerberosLeaseRequest) returns (RenewNonDomainJoinedKerberosLeaseResponse);
rpc DeleteKerberosLease (DeleteKerberosLeaseRequest) returns (DeleteKerberosLeaseResponse);
rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse);
}

message HealthCheckRequest {
string service = 1;
}

message HealthCheckResponse {
string status = 1;
}

message CreateKerberosLeaseRequest {
Expand Down