Skip to content

Commit

Permalink
Merge pull request #75 from aws/health_check
Browse files Browse the repository at this point in the history
Add health checkendpoint
  • Loading branch information
saikiranakula-amzn authored Oct 30, 2023
2 parents 3477757 + c9f0b05 commit 17b9df0
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 0 deletions.
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

0 comments on commit 17b9df0

Please sign in to comment.