553 lines
17 KiB
C++
553 lines
17 KiB
C++
/*
|
|
* Copyright (c) 2013-2017 Wind River Systems, Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* Wind River CGTS Platform Resource Monitor Resource Notify
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/ioctl.h>
|
|
#include <net/if.h>
|
|
#include <netdb.h>
|
|
#include <iostream>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <list>
|
|
#include <vector>
|
|
#include <sstream>
|
|
#include <time.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
|
|
using namespace std;
|
|
|
|
#include "../rmonApi/rmon_nodeMacro.h" /* for ... CREATE_NONBLOCK_INET_UDP_RX_SOCKET */
|
|
#include "rmon_resource_notify.h"
|
|
|
|
extern "C"
|
|
{
|
|
#include "../rmonApi/rmon_api.h"
|
|
}
|
|
#define LOOPBACK_IP "127.0.0.1"
|
|
#define RX_PORT (2304)
|
|
|
|
static char my_hostname [MAX_HOST_NAME_SIZE+1];
|
|
static rmon_socket_type rmon_sock ;
|
|
static rmon_socket_type * sock_ptr ;
|
|
|
|
/** Client Config mask */
|
|
#define CONFIG_CLIENT_MASK (CONFIG_AGENT_PORT |\
|
|
CONFIG_CLIENT_API_PORT |\
|
|
CONFIG_CLIENT_PORT)
|
|
|
|
/****************************/
|
|
/* Initialization Utilities */
|
|
/****************************/
|
|
|
|
/* Initialize the unicast api response message */
|
|
/* One time thing ; tx same message all the time. */
|
|
int rmon_message_init ( void )
|
|
{
|
|
/* Build the transmit api response message */
|
|
memset ( &sock_ptr->tx_message, 0, sizeof (rmon_message_type));
|
|
memcpy ( &sock_ptr->tx_message.m[RMON_HEADER_SIZE], my_hostname, strlen(my_hostname));
|
|
return (PASS);
|
|
}
|
|
|
|
int rmon_socket_init ( int port, const char * process_name )
|
|
{
|
|
|
|
int on = 1 ;
|
|
int rc = PASS ;
|
|
|
|
CREATE_NONBLOCK_INET_UDP_RX_SOCKET ( LOOPBACK_IP,
|
|
port,
|
|
rmon_sock.rmon_api_sock,
|
|
rmon_sock.rmon_api_addr,
|
|
rmon_sock.rmon_api_port,
|
|
rmon_sock.rmon_api_len,
|
|
"rmon api socket receive",
|
|
rc );
|
|
if ( rc ) return (rc) ;
|
|
|
|
/* Open the monitoring socket */
|
|
rmon_sock.rmon_socket = resource_monitor_initialize ( process_name, port, RMON_RESOURCE_NOT );
|
|
//ilog("Resource Monitor API Socket %d\n", rmon_sock.rmon_socket);
|
|
if ( 0 > rmon_sock.rmon_socket )
|
|
{
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
|
|
/* Make the socket non-blocking */
|
|
rc = ioctl(rmon_sock.rmon_socket, FIONBIO, (char *)&on);
|
|
if ( 0 > rc )
|
|
{
|
|
//elog("Failed to set rmon socket non-blocking (%d:%m)\n", errno );
|
|
return (FAIL_SOCKET_NOBLOCK);
|
|
}
|
|
return (PASS);
|
|
}
|
|
|
|
|
|
int daemon_init (int port, const char * process_name )
|
|
{
|
|
int rc = PASS ;
|
|
|
|
/* Initialize socket construct and pointer to it */
|
|
memset ( &rmon_sock, 0, sizeof(rmon_sock));
|
|
sock_ptr = &rmon_sock ;
|
|
|
|
/* Setup the resmon api rx messaging sockets */
|
|
if ( (rc = rmon_socket_init (port, process_name)) != PASS )
|
|
{
|
|
// elog("socket initialization failed (rc:%d)\n", rc);
|
|
rc = FAIL_SOCKET_INIT;
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
#define RMON_MAX_LEN (100)
|
|
int client_service_inbox ()
|
|
{
|
|
#define MAX_T 100
|
|
int bytes = 0 ;
|
|
char buf[RMON_MAX_LEN] ;
|
|
socklen_t len = sizeof(struct sockaddr_in) ;
|
|
char str[RMON_MAX_LEN];
|
|
int rc = FAIL;
|
|
|
|
do
|
|
{
|
|
memset ( buf,0,RMON_MAX_LEN);
|
|
memset ( str,0,RMON_MAX_LEN);
|
|
|
|
bytes = recvfrom( rmon_sock.rmon_socket, buf, RMON_MAX_LEN, 0, (struct sockaddr *)&rmon_sock.client_sockAddr, &len);
|
|
if ( bytes > 0 )
|
|
{
|
|
sscanf ( buf, "%99s", str);
|
|
if ( str[0] != '\0' )
|
|
{
|
|
if ( strcmp(str, RMON_DONE) == 0)
|
|
{
|
|
return (PASS);
|
|
}
|
|
}
|
|
return (FAIL);
|
|
}
|
|
else if (( 0 > bytes ) && ( errno != EINTR ) && ( errno != EAGAIN ))
|
|
{
|
|
//ilog("problem with test client recv \n");
|
|
}
|
|
} while ( bytes > 0 ) ;
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* Maximum length of the dynamic resource list */
|
|
#define DYNAMIC_RESOURCE_MAX (1024)
|
|
|
|
int main ( int argc, char *argv[] )
|
|
{
|
|
int rc;
|
|
int port = RX_PORT;
|
|
const char * process_name = PROCESS_NAME;
|
|
char res_name[30];
|
|
char state[20];
|
|
char mount[50];
|
|
char type[20];
|
|
char device[50];
|
|
char volume_group[50];
|
|
string delimiter = ",";
|
|
unsigned long long timeout = DEFAULT_RESPONSE_TIMEOUT;
|
|
char dynamic_res[DYNAMIC_RESOURCE_MAX];
|
|
char resource_name [50];
|
|
struct stat fileInfo;
|
|
struct timespec start, stop;
|
|
struct flock fl;
|
|
int fd;
|
|
bool toNotify = false;
|
|
vector<string> dynamic_resources;
|
|
size_t pos;
|
|
string token;
|
|
|
|
open_syslog();
|
|
|
|
memset ((char *)&fileInfo, 0 , sizeof(fileInfo));
|
|
memset(&res_name[0], 0, sizeof(res_name));
|
|
memset(&state[0], 0, sizeof(state));
|
|
memset(&mount[0], 0, sizeof(mount));
|
|
memset(&type[0], 0, sizeof(type));
|
|
memset(&device[0], 0, sizeof(device));
|
|
memset(&volume_group[0], 0, sizeof(volume_group));
|
|
memset(&dynamic_res[0], 0, sizeof(dynamic_res));
|
|
memset(&resource_name[0], 0, sizeof(resource_name));
|
|
|
|
fl.l_whence = SEEK_SET;
|
|
fl.l_start = 0;
|
|
fl.l_len = 0;
|
|
fl.l_pid = getpid();
|
|
|
|
if ((argc > 1) && (strcmp(argv[1],"--help") == 0)) {
|
|
printf("usage: rmon_resource_notify "
|
|
"--resource-name <entity_name> "
|
|
"--resource-state <enabled|disabled> "
|
|
"--resource-type <filesystem> "
|
|
"--device <device_name> "
|
|
"--mount-point <mount_path> "
|
|
"--volume_group <volume_name> "
|
|
"--timeout <ms> \n");
|
|
close_syslog();
|
|
return FAIL;
|
|
}
|
|
|
|
for (int i=0; i<argc; ++i)
|
|
{
|
|
/* parse the dynamic resource monitor request list/table */
|
|
if (strcmp(argv[i], "--resource-name") == 0) {
|
|
sscanf(argv[i+1], "%29s", res_name);
|
|
}
|
|
else if (strcmp(argv[i], "--resource-state") == 0) {
|
|
sscanf(argv[i+1], "%19s", state);
|
|
if (strcmp(state, "disabled") == 0)
|
|
{
|
|
/* because enabled and disable have the same number of characters */
|
|
strcpy(state, "disable");
|
|
}
|
|
}
|
|
else if (strcmp(argv[i], "--resource-type") == 0) {
|
|
sscanf(argv[i+1], "%19s", type);
|
|
}
|
|
else if (strcmp(argv[i], "--device") == 0) {
|
|
sscanf(argv[i+1], "%49s", device);
|
|
}
|
|
else if (strcmp(argv[i], "--mount-point") == 0) {
|
|
sscanf(argv[i+1], "%49s", mount);
|
|
}
|
|
else if (strcmp(argv[i], "--timeout") == 0) {
|
|
sscanf(argv[i+1], "%llu", &timeout);
|
|
}
|
|
else if (strcmp(argv[i], "--volume-group") == 0) {
|
|
sscanf(argv[i+1], "%49s", volume_group);
|
|
}
|
|
}
|
|
|
|
if (res_name[0] != '\0') {
|
|
strcpy( dynamic_res, res_name);
|
|
strcat( dynamic_res, " " );
|
|
}
|
|
if (state[0] != '\0') {
|
|
strcat( dynamic_res, state );
|
|
strcat( dynamic_res, " " );
|
|
}
|
|
if (type[0] != '\0') {
|
|
strcat( dynamic_res, type );
|
|
strcat( dynamic_res, " " );
|
|
}
|
|
if (device[0] != '\0') {
|
|
strcat( dynamic_res, device );
|
|
}
|
|
else if (volume_group[0] != '\0')
|
|
{
|
|
strcat( dynamic_res, volume_group );
|
|
}
|
|
if (mount[0] != '\0') {
|
|
strcat( dynamic_res, " " );
|
|
strcat( dynamic_res, mount );
|
|
}
|
|
strcat( dynamic_res, delimiter.c_str() );
|
|
|
|
// syslog ( LOG_DEBUG, "dynamic_res: %s\n", dynamic_res);
|
|
|
|
if ( stat(DYNAMIC_FS_FILE, &fileInfo) != -1 )
|
|
{
|
|
/*******************************************************************************************
|
|
* Dynamic Resource Monitor Request - Example
|
|
*
|
|
* cat /etc/rmonfiles.d/dynamic.conf
|
|
* nova-local disable lvg nova-local,
|
|
* /etc/nova/instances enabled mount /dev/mapper/nova--local-instances_lv /etc/nova/instances,
|
|
* platform-storage disable mount /dev/drbd2 /opt/platform,
|
|
* cloud-storage disable mount /dev/drbd3 /opt/cgcs,
|
|
* volume-storage disable lvg cinder-volumes,
|
|
* database-storage disable mount /dev/drbd0 /var/lib/postgresql,
|
|
* messaging-storage disable mount /dev/drbd1 /var/lib/rabbitmq,
|
|
* extension-storage disable mount /dev/drbd5 /opt/extension,
|
|
*
|
|
*********************************************************************************************/
|
|
/* file is yet to be read and written */
|
|
fd = open(DYNAMIC_FS_FILE, O_RDWR, (mode_t)0600);
|
|
if (fd == -1)
|
|
{
|
|
// elog("Error opening file for read/write");
|
|
close_syslog();
|
|
return(FAIL);
|
|
}
|
|
/* lock the file for read and write */
|
|
fl.l_type = F_WRLCK;
|
|
fcntl(fd, F_SETLKW, &fl);
|
|
|
|
if (fd == -1)
|
|
{
|
|
// elog("Error opening file for reading");
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
|
|
if (fstat(fd, &fileInfo) == -1)
|
|
{
|
|
// elog("Error getting the file size");
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
|
|
//ilog("File size is %ji\n", (intmax_t)fileInfo.st_size);
|
|
|
|
char *map = static_cast<char*>(mmap(0, fileInfo.st_size, PROT_READ, MAP_SHARED, fd, 0));
|
|
if (map == MAP_FAILED)
|
|
{
|
|
close(fd);
|
|
// elog("Error mmapping the file");
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
string oldFile(map);
|
|
/* extract the resource name */
|
|
sscanf(dynamic_res, "%49s", resource_name);
|
|
string newResource(resource_name);
|
|
string updatedResource(dynamic_res);
|
|
dynamic_resources.clear();
|
|
|
|
if ( oldFile.find(updatedResource) == string::npos )
|
|
{
|
|
if ( oldFile.find(newResource) != string::npos )
|
|
{
|
|
/* the resource exists, update it in the file */
|
|
while ((pos = oldFile.find(delimiter)) != string::npos)
|
|
{
|
|
/* separate the resources from the file */
|
|
token = oldFile.substr(0, pos);
|
|
if (token.find(newResource) == string::npos)
|
|
{
|
|
dynamic_resources.push_back(token);
|
|
}
|
|
oldFile.erase(0, pos + delimiter.length());
|
|
}
|
|
oldFile = "";
|
|
for (unsigned int i=0; i<dynamic_resources.size(); i++)
|
|
{
|
|
oldFile.append(dynamic_resources.at(i));
|
|
oldFile.append(delimiter);
|
|
}
|
|
oldFile.append(updatedResource);
|
|
}
|
|
else
|
|
{
|
|
/* the resource does not exist, add it to the file */
|
|
//ilog("updated_resource: %s", oldFile.c_str());
|
|
oldFile.append(updatedResource);
|
|
}
|
|
snprintf ( dynamic_res, DYNAMIC_RESOURCE_MAX-1, "%s", oldFile.data());
|
|
// syslog ( LOG_DEBUG, "%s\n", dynamic_res);
|
|
}
|
|
else
|
|
{
|
|
/* resource already exists no need to add it */
|
|
memset(dynamic_res, 0, DYNAMIC_RESOURCE_MAX ) ; // sizeof(dynamic_res));
|
|
}
|
|
|
|
/* free the mmapped memory */
|
|
if (munmap(map, fileInfo.st_size) == -1)
|
|
{
|
|
/* unlock the file */
|
|
fl.l_type = F_UNLCK;
|
|
fcntl(fd, F_SETLK, &fl);
|
|
// elog("Error un-mmapping the file");
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
}
|
|
|
|
/* add or modify the dynamic resource */
|
|
else
|
|
{
|
|
/* file is yet to be written to create a new one */
|
|
fd = open(DYNAMIC_FS_FILE, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
|
|
if (fd == -1)
|
|
{
|
|
// elog("Error opening file for writing");
|
|
close_syslog();
|
|
return(FAIL);
|
|
}
|
|
/* lock the file for writing */
|
|
fl.l_type = F_WRLCK;
|
|
fcntl(fd, F_SETLKW, &fl);
|
|
}
|
|
|
|
if (dynamic_res[0] != '\0')
|
|
{
|
|
toNotify = true;
|
|
/* stretch the file size to the size of the (mmapped) array of char */
|
|
string text (dynamic_res);
|
|
//ilog("dynamicres: %s\n", dynamic_res);
|
|
size_t textsize = strlen(text.c_str());
|
|
|
|
if (lseek(fd, textsize, SEEK_SET) == -1)
|
|
{
|
|
close(fd);
|
|
// elog("Error calling lseek() to 'stretch' the file");
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
|
|
if (write(fd, "", 1) == -1)
|
|
{
|
|
close(fd);
|
|
// elog("Error writing last byte of the file");
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
|
|
/* memory map the file */
|
|
char *map = static_cast<char*>(mmap(0, textsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
|
if (map == MAP_FAILED)
|
|
{
|
|
close(fd);
|
|
// elog("Error mmapping the file");
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
|
|
/* write the resource into memory */
|
|
memcpy(map, text.c_str(), textsize);
|
|
|
|
/* write the updated list to the disk */
|
|
if (msync(map, textsize, MS_SYNC) == -1)
|
|
{
|
|
; // elog("Could not sync the file to disk");
|
|
}
|
|
|
|
|
|
/* free the mmapped memory */
|
|
if (munmap(map, textsize) == -1)
|
|
{
|
|
/* unlock the file */
|
|
fl.l_type = F_UNLCK;
|
|
fcntl(fd, F_SETLK, &fl);
|
|
// elog("Error un-mmapping the file");
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
}
|
|
close(fd);
|
|
/* unlock the file */
|
|
fl.l_type = F_UNLCK;
|
|
fcntl(fd, F_SETLK, &fl);
|
|
if (!toNotify)
|
|
{
|
|
close_syslog();
|
|
return (PASS);
|
|
}
|
|
|
|
/* Check to see if rmond is running */
|
|
rc = system("pidof rmond");
|
|
if (WEXITSTATUS(rc) != 0)
|
|
{
|
|
return (PASS);
|
|
}
|
|
|
|
rc = daemon_init(port, process_name);
|
|
if (rc == PASS) {
|
|
|
|
if( clock_gettime( CLOCK_MONOTONIC, &start) == -1 ) {
|
|
// elog("clock gettime \n" );
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
|
|
rmon_message_init();
|
|
rmon_sock.rmon_socket = resource_monitor_get_sel_obj ();
|
|
std::list<int> socks;
|
|
socks.clear();
|
|
socks.push_front ( rmon_sock.rmon_socket );
|
|
socks.sort();
|
|
// remove the rmon resource notify flag file
|
|
// as this will be reset by rmon
|
|
remove (RESPONSE_RMON_RESOURCE_NOT);
|
|
/* signal to rmon that the dynamic file has been written */
|
|
rc = rmon_notification ( RMON_RESOURCE_NOT );
|
|
|
|
for ( ; ; )
|
|
{
|
|
/* Initialize the timeval struct */
|
|
rmon_sock.waitd.tv_sec = 0;
|
|
rmon_sock.waitd.tv_usec = SELECT_TIMEOUT * 100;
|
|
|
|
/* Initialize the master fd_set */
|
|
FD_ZERO(&rmon_sock.readfds);
|
|
FD_SET(rmon_sock.rmon_socket, &rmon_sock.readfds);
|
|
|
|
rc = select( socks.back()+1,
|
|
&rmon_sock.readfds, NULL, NULL,
|
|
&rmon_sock.waitd);
|
|
|
|
/* If the select time out expired then */
|
|
if (( rc < 0 ) || ( rc == 0 ))
|
|
{
|
|
/* Check to see if the select call failed. */
|
|
/* ... but filter Interrupt signal */
|
|
if (( rc < 0 ) && ( errno != EINTR ))
|
|
{
|
|
//ilog("Socket Select Failed (rc:%d) %s \n", errno, strerror(errno));
|
|
}
|
|
}
|
|
|
|
if ( FD_ISSET(rmon_sock.rmon_socket, &rmon_sock.readfds))
|
|
{
|
|
rc = client_service_inbox();
|
|
|
|
if (rc == PASS) {
|
|
close_syslog();
|
|
return PASS;
|
|
}
|
|
}
|
|
|
|
if ( clock_gettime( CLOCK_MONOTONIC, &stop) == -1 ) {
|
|
// elog("clock gettime\n");
|
|
return (FAIL);
|
|
}
|
|
unsigned long delta = (stop.tv_sec - start.tv_sec) * 1000 + (stop.tv_nsec - start.tv_nsec) / 1000000;
|
|
if (delta > timeout)
|
|
{
|
|
/* we exceeded the timeout.
|
|
* It may have happened that rmon
|
|
* sent its acknowledgment but that response
|
|
* got lost. In that case check for the flag file
|
|
* as a last ditch effort
|
|
*/
|
|
if (access(RESPONSE_RMON_RESOURCE_NOT, F_OK) != -1) {
|
|
close_syslog()
|
|
return (PASS);
|
|
}
|
|
close_syslog();
|
|
return (FAIL);
|
|
}
|
|
}
|
|
}
|
|
close_syslog();
|
|
return FAIL;
|
|
}
|
|
|