This commit is contained in:
biosvos
2026-08-07 17:38:18 +09:00
commit 873193a243
9613 changed files with 2755992 additions and 0 deletions
+338
View File
@@ -0,0 +1,338 @@
#include "FhsShm.h"
#include "Logger.h"
#include <string.h>
#include <math.h>
// ShmDefine.h 에서 정의된 서비스 상태 코드 외에 미정의된 코드 처리를 위한 정의
#define SERVICE_STAT_NOT_DEFINE -1
// 생성자
CFhsShm::CFhsShm( struct FhsInfo * p )
: m_pShm( p )
{
// 서비스 상태 code 에 대한 문자열 정보를 저장하기 위한 멤버 변수 설정.
// - may 객체이므로.. key - value 형식으로 저장 처리
m_mapServiceStatString[SERVICE_STAT_NOT_DEFINE] = "Not_Define";
m_mapServiceStatString[SERVICE_STAT_OK] = "OK";
m_mapServiceStatString[SERVICE_STAT_OUT] = "Out";
m_mapServiceStatString[SERVICE_STAT_DISABLE] = "Disable";
m_mapServiceStatString[SERVICE_STAT_RONLY] = "Read-only";
}
// 소멸자
CFhsShm::~CFhsShm()
{
}
// 멤버 변수인 공유메모리에 대한 포인터가 유효하지 여부를 판단하기 위한 함수.
bool CFhsShm::IsValid() const
{
if( m_pShm != NULL )
return true;
else
return false;
}
// 공유메모리 전체 영역을 초기화하기 위한 함수.
void CFhsShm::ClearAll() const
{
if( m_pShm != NULL )
{
memset( m_pShm, 0x00, sizeof( struct FhsInfo ) );
}
}
// 공유메모리 정보를 로그 파일에 기록 처리.
void CFhsShm::Print()
{
_LOG( LINF, "-- shared memory --" );
_LOG( LINF, "hostname : %s", m_pShm->system.hostname );
_LOG( LINF, "load_avg : %5.2lf, %5.2lf, %5.2lf", m_pShm->system.load_avg[0], m_pShm->system.load_avg[1], m_pShm->system.load_avg[2] );
_LOG( LINF, "memory usage : %3d %%, free %13ju byte, total %13ju byte", m_pShm->system.memory_usage, m_pShm->system.memory_free, m_pShm->system.memory_total );
_LOG( LINF, "swap usage : %3d %%, used %13ju byte, total %13ju byte", m_pShm->system.swap_usage, m_pShm->system.swap_used, m_pShm->system.swap_total );
_LOG( LINF, "disk max busy : %.1lf %%, max queue %ju", m_pShm->system.disk_max_busy, m_pShm->system.disk_max_queue );
_LOG( LINF, "storage usage : max %d %%, avg %d %%, avail %ju byte, total %ju byte"
, m_pShm->system.storage_max_usage
, ( int ) ceil( (( double ) (m_pShm->system.storage_total - m_pShm->system.storage_avail )) / m_pShm->system.storage_total * 100.0 )
, m_pShm->system.storage_avail, m_pShm->system.storage_total );
_LOG( LINF, "tcp session : %u, %u, %u (80_est, 80_total, total)", m_pShm->system.tcp_80_establish, m_pShm->system.tcp_80, m_pShm->system.tcp_total );
_LOG( LINF, "traffic in : %10ju byte/sec, packet %8ju count/sec", m_pShm->system.network_traffic_in, m_pShm->system.network_packet_in );
_LOG( LINF, "traffic out : %10ju byte/sec, packet %8ju count/sec", m_pShm->system.network_traffic_out, m_pShm->system.network_packet_out );
_LOG( LINF, "check time" );
_LOG( LINF, " last service check start : %ld", m_pShm->time_service_check_start_sec );
_LOG( LINF, " last system check start : %ld", m_pShm->time_system_check_start_sec );
_LOG( LINF, " last storage check ok : %ld", m_pShm->time_storage_check_ok_sec );
_LOG( LINF, "service stat : %s ( %d )", GetServiceStatString(), m_pShm->service.stat );
_LOG( LINF, "--------------" );
// 2018-02-08 NEW huibong 수집된 공유메모리 정보에 대한 시간별 분석이 용이하도록 해당 정보를 RAW 형식으로 로깅한다. (#31701)
_LOG( LINF, "RAW %s %.2lf %.2lf %.2lf"
" %d %ju %d %ju"
" %.1lf %ju %d %ju"
" %u %u %u %ju %ju"
" %ld %ld %ld"
, GetServiceStatString(), m_pShm->system.load_avg[0], m_pShm->system.load_avg[1], m_pShm->system.load_avg[2]
, m_pShm->system.memory_usage, m_pShm->system.memory_free, m_pShm->system.swap_usage, m_pShm->system.swap_used
, m_pShm->system.disk_max_busy, m_pShm->system.disk_max_queue, m_pShm->system.storage_max_usage, m_pShm->system.storage_avail
, m_pShm->system.tcp_80_establish, m_pShm->system.tcp_80, m_pShm->system.tcp_total, m_pShm->system.network_traffic_in, m_pShm->system.network_traffic_out
, m_pShm->time_service_check_start_sec, m_pShm->time_system_check_start_sec, m_pShm->time_storage_check_ok_sec
);
_LOG( LINF, "--------------" );
return;
}
// hostname
bool CFhsShm::SetHostname( const char * name ) const
{
// 전달받은 hostname 정보를 저장 처리한다.
// - hostname 정보는 규칙상 HOST_NAME_MAX_LENGTH 값만큼 저장 가능하므로...
// - HOST_NAME_MAX_LENGTH 길이 초과시... 저장 실패로 false 를 반환 처리한다.
if( name == NULL )
{
LOG( LERR, "[FhsShm] hostname is null point.");
return false;
}
if( strlen( name ) > HOST_NAME_MAX_LENGTH )
{
LOG( LERR, "[FhsShm] hostname[%s] too long. max length [%d]", name, HOST_NAME_MAX_LENGTH );
return false;
}
// hostname 이 중간에 변경될 경우.. 서비스에 영향을 미치게 되므로....
// 변경 여부를 로깅한다.
if( strlen( m_pShm->system.hostname ) != 0 )
{
if( strcmp( m_pShm->system.hostname, name ) != 0 )
{
_LOG( LWAR, "hostname changed.[%s] -> [%s]", m_pShm->system.hostname, name );
strcpy( m_pShm->system.hostname, name );
}
}
else
{
strcpy( m_pShm->system.hostname, name );
}
return true;
}
// loadaverage
bool CFhsShm::SetLoadaverage( const int & index, const double & value ) const
{
if( index > 2 )
{
LOG( LERR, "[FhsShm] loadaverage index[%d] not valid.", index );
return false;
}
m_pShm->system.load_avg[index] = value;
return true;
}
// memory total
void CFhsShm::SetMemoryTotal( const uint64_t & value ) const
{
m_pShm->system.memory_total = value;
return;
}
// memory free
void CFhsShm::SetMemoryFree( const uint64_t & value ) const
{
m_pShm->system.memory_free = value;
if( m_pShm->system.memory_total == 0 )
m_pShm->system.memory_usage = 0;
else
m_pShm->system.memory_usage = (int)ceil( (double)( m_pShm->system.memory_total - value ) * 100.0 / m_pShm->system.memory_total );
return;
}
// swap total, used
// - 사용률은 자체적으로 계산하여 처리한다.
void CFhsShm::SetSwapInfo( const uint64_t & total, const uint64_t & used ) const
{
m_pShm->system.swap_total = total;
m_pShm->system.swap_used = used;
if( total == 0 )
m_pShm->system.swap_usage = 0;
else
m_pShm->system.swap_usage = (int)ceil( (double)(used ) * 100.0 / total );
return;
}
// storage 용량, 사용률
void CFhsShm::SetStorageInfo( const uint64_t & total, const uint64_t & avail, const int & max_usage ) const
{
m_pShm->system.storage_total = total;
m_pShm->system.storage_avail = avail;
m_pShm->system.storage_max_usage = max_usage;
return;
}
// Disk max queuelength, max busy.
void CFhsShm::SetDiskInfo( const uint64_t & queue, const double & busy ) const
{
m_pShm->system.disk_max_queue = queue;
m_pShm->system.disk_max_busy = busy;
return;
}
// Network packet, traffic
void CFhsShm::SetNetworkInfo( const uint64_t & packetIn, const uint64_t & packetOut, const uint64_t & trafficIn, const uint64_t & trafficOut ) const
{
m_pShm->system.network_packet_in = packetIn;
m_pShm->system.network_packet_out = packetOut;
m_pShm->system.network_traffic_in = trafficIn;
m_pShm->system.network_traffic_out = trafficOut;
return;
}
// TCP 세션 정보
void CFhsShm::SetTcpInfo( const unsigned int & total, const unsigned int & tcp80, const unsigned int & tcp80Establish ) const
{
m_pShm->system.tcp_total = total;
m_pShm->system.tcp_80 = tcp80;
m_pShm->system.tcp_80_establish = tcp80Establish;
return;
}
// Service 상태 정보 설정.
bool CFhsShm::SetServiceStat( const int & stat )
{
if( stat < SERVICE_STAT_OK || stat > SERVICE_STAT_MAX )
{
LOG( LERR, "[FhsShm] service stat code[%d] not vaild. normal range: %d~%d", stat, SERVICE_STAT_OK, SERVICE_STAT_MAX );
return false;
}
else
{
// Service Stat 정보가 변경될 경우.. 이를 로깅 처리한다.
if( m_pShm->service.stat != stat )
{
// 상태 변경 처리.
int iOldStat = m_pShm->service.stat;
m_pShm->service.stat = stat;
_LOG( LINF, "[FhsShm] service stat change : %d (%s) -> %d (%s)"
, iOldStat, GetServiceStatString(iOldStat)
, m_pShm->service.stat, GetServiceStatString() );
}
}
return true;
}
// Service 상태 정보에 대한 문자열 반환.
const char * CFhsShm::GetServiceStatString( const int & stat )
{
std::map< int, std::string >::iterator pos;
pos = m_mapServiceStatString.find( stat );
if( pos != m_mapServiceStatString.end() )
{
// 해당 항목 존재시
return pos->second.c_str();
}
else
{
// 해당 항목이 존재하지 않는 경우.
return m_mapServiceStatString[SERVICE_STAT_NOT_DEFINE].c_str();
}
}
// 현재 Service 상태 정보에 대한 문자열 반환.
const char * CFhsShm::GetServiceStatString()
{
std::map< int, std::string >::iterator pos;
pos = m_mapServiceStatString.find( m_pShm->service.stat );
if( pos != m_mapServiceStatString.end() )
{
// 해당 항목 존재시
return pos->second.c_str();
}
else
{
// 해당 항목이 존재하지 않는 경우.
return m_mapServiceStatString[SERVICE_STAT_NOT_DEFINE].c_str();
}
}
// Storage last check 시간 정보 업데이트
// 전달받은 인자값이 true 인 경우 시간 정보 설정, false 인 경우 -1 설정 처리함.
void CFhsShm::UpdateTimeStorageCheck( bool bCheckSuccess )
{
if( bCheckSuccess == true )
{
// storage check 성공시
// - 현재 시스템 기준 시간 정보 중 sec 정보를 계산하여 공유메모리에 저장 처리.
struct timespec currentClock;
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
m_pShm->time_storage_check_ok_sec = currentClock.tv_sec;
}
else
{
// storage check 실패시
// time_storage_check_ok_sec 값의 정의 규약에 따라 -1 설정
// TODO: 우선 -1 로 설정하면 바로 Service Disable 처리 할 수 있지만...
// Disk write/read 관련 일시적인 이유로 실패할 수 있어
// 오류 상황에 대한 검증 없이 바로 서비스 disable 처리하면 오탐등으로 서비스에 문제가 발생할 수 있으므로...
// 우선은 -1 설정을 하지 않고.. expire 처리되도록 한다.
// -1 설정 활성화는 장애시 여러 data 를 분석하여.. write/read 오류에 대한 검증 후 진행한다.
//m_pShm->time_storage_check_ok_sec = -1;
}
return;
}
// Service 상태 Check Start 시간 정보 업데이트
void CFhsShm::UpdateTimeServiceCheck()
{
// 현재 시스템 기준 시간 정보 중 sec 정보를 계산하여 공유메모리에 저장 처리.
struct timespec currentClock;
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
m_pShm->time_service_check_start_sec = currentClock.tv_sec;
return;
}
// System 상태 Check Start 시간 정보 업데이트
void CFhsShm::UpdateTimeSystemCheck()
{
// 현재 시스템 기준 시간 정보 중 sec 정보를 계산하여 공유메모리에 저장 처리.
struct timespec currentClock;
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
m_pShm->time_system_check_start_sec = currentClock.tv_sec;
return;
}
+142
View File
@@ -0,0 +1,142 @@
/****************************************************************************
csagentd shared memory interface function class
-----------------------------------------
begin : 2015/04/21
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __FHS_SHM_H__
#define __FHS_SHM_H__
#include "ShmDefine.h"
#include <string>
#include <map>
// 공유메모리 영역 전체에 대한 접근 인터페이스를 제공하기 위한 클래스
class CFhsShm
{
private:
// 공유메모리에 대한 포인터
struct FhsInfo * const m_pShm;
// 서비스 상태 code 에 대한 문자열 정보를 저장하기 위한 변수.
std::map<int, std::string> m_mapServiceStatString;
public:
// 생성자
CFhsShm( struct FhsInfo * p );
// 소멸자
~CFhsShm();
public:
// 함수 선언시 const 구문 사용 이유
// - 멤버변수인 m_pShm 값이 변경될 경우...엉뚱한 메모리 영역을 참조하는 불상사 발생.
// - 따라서 코딩시 m_pShm 값이 변경되지 않음을 선언하여....
// - 컴파일시 문제가 없는지 확인하기 위한 목적으로 사용함.
// - map 관련 멤버 변수 사용으로 인해.. 일부 함수에서는 사용하지 못함.
// 멤버 변수인 공유메모리에 대한 포인터가 유효하지 여부를 판단하기 위한 함수.
// return 유효한 경우 true, NULL 인 경우 false
bool IsValid( void ) const;
// 공유메모리 전체 영역을 초기화하기 위한 함수.
// return
void ClearAll( void ) const;
// 공유메모리 정보를 로그에 write
void Print( void ) ;
public:
// shared memory 각 항목에 대한 interface 함수
// hostname
bool SetHostname( const char * name ) const;
const char * GetHostName() { return m_pShm->system.hostname; }
// loadaverage
bool SetLoadaverage( const int & index, const double & value ) const;
// memory
void SetMemoryTotal( const uint64_t & value ) const;
void SetMemoryFree( const uint64_t & value ) const;
// swap
void SetSwapInfo( const uint64_t & total, const uint64_t & used ) const;
// storage 용량, 사용률
void SetStorageInfo( const uint64_t & total, const uint64_t & avail, const int & max_usage ) const;
int GetStorageMaxUsage() const { return m_pShm->system.storage_max_usage; }
uint64_t GetStorageTotal() const { return m_pShm->system.storage_total; }
// Disk max queuelength, max busy.
void SetDiskInfo( const uint64_t & queue, const double & busy ) const;
// Network packet, traffic
void SetNetworkInfo( const uint64_t & packetIn, const uint64_t & packetOut, const uint64_t & trafficIn, const uint64_t & trafficOut ) const;
// TCP 세션 정보
void SetTcpInfo( const unsigned int & total, const unsigned int & tcp80, const unsigned int & tcp80Establish ) const;
// Service 상태 정보 설정.
// false - 정의되지 않은 상태값인 경우...
bool SetServiceStat( const int & stat );
// Service 상태 정보 반환.
int GetServiceStat() { return m_pShm->service.stat; }
// Service 상태 정보에 대한 문자열 반환.
const char * GetServiceStatString( const int & stat );
// 현재 Service 상태 정보에 대한 문자열 반환.
const char * GetServiceStatString();
// 2018-02-07 NEW huibong Disk Busy 상황에서 Read Only 상태로 변경을 위한 Disk queue, busy 정보 반환 함수 추가 (#31701)
uint64_t GetDiskMaxQueue() const { return m_pShm->system.disk_max_queue; }
double GetDiskMaxBusy() const { return m_pShm->system.disk_max_busy; }
// 2018-01-31 NEW huibong 공유메모리 상에 신규로 추가 time 관련 처리를 위한 함수 추가 (#31701)
// Storage last check 시간 정보 업데이트
// 전달받은 인자값이 true 인 경우 시간 정보 설정, false 인 경우 -1 설정 처리함.
void UpdateTimeStorageCheck( bool bCheckSuccess );
// Service 상태 Check Start 시간 정보 업데이트
void UpdateTimeServiceCheck( void );
// System 상태 Check Start 시간 정보 업데이트
void UpdateTimeSystemCheck( void );
time_t GetTimeStorageCheck() const { return m_pShm->time_storage_check_ok_sec; }
time_t GetTimeServiceCheck() const { return m_pShm->time_service_check_start_sec; }
time_t GetTimeSystemCheck() const { return m_pShm->time_system_check_start_sec; }
public:
// RCTS 전송 처리 모듈에서 사용하기 위한 interface 함수.
const struct SystemInfo * GetSystemInfo() { return &(m_pShm->system); };
const struct ServiceStatus * GetServiceStatus() { return &( m_pShm->service ); };
};
#endif /* __FHS_SHM_H__ */
+996
View File
@@ -0,0 +1,996 @@
#include "Main.h"
#include "ProcessConfig.h"
#include "Logger.h"
#include "ShmDefine.h"
#include "ShmControl.h"
#include "FhsShm.h"
#include "WorkerSystemCollect.h"
#include "WorkerServiceCheck.h"
#include "WorkerStorageCheck.h"
#include "WorkerSend.h"
#include "WorkerMonitoringPortControl.h"
#include "WorkerTelegrafControl.h"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <time.h>
#include <iostream>
// Shared memory key 생성용 임시 파일.
// 2018-01-29 CHG huibong
// - /tmp 폴더에 대한 clean 모듈이 동작할 경우 자동 삭제되므로.. 경로 변경 처리 (#31701)
//#define FHS_SHARED_MEMORY_FILE "/tmp/"PROG_NAME".shm"
#define FHS_SHARED_MEMORY_FILE "/user/service/" PROG_NAME ".shm"
// 공유메모리 생성, 삭제 등의 Manager 객체에 대한 포인터.
CShmControl< struct FhsInfo > * g_pShmManager = NULL;
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
CFhsShm * g_pFhsShm = NULL;
// Worker 프로세스 중 SystemCollect Worker 프로세스의 PID 정보.
// 시그널 처리에 의해 재생성 처리 단순화를 위해 전역 변수로 처리.
pid_t g_pidWorkerSystemCollect = -1;
// Worker 프로세스 중 ServiceCheck Worker 프로세스의 PID 정보.
// 시그널 처리에 의해 재생성 처리 단순화를 위해 전역 변수로 처리.
pid_t g_pidWorkerServiceCheck = -1;
// Worker 프로세스 중 StorageCheck Worker 프로세스의 PID 정보.
// 시그널 처리에 의해 재생성 처리 단순화를 위해 전역 변수로 처리.
pid_t g_pidWorkerStorageCheck = -1;
// Worker 프로세스 중 Send Worker 프로세스의 PID 정보.
// 시그널 처리에 의해 재생성 처리 단순화를 위해 전역 변수로 처리.
pid_t g_pidWorkerSend = -1;
// Wokrker 프로세스 중 서비스 상태에 따른 Monitoring TCP Port Control 관련 Worker 프로세스 PID
pid_t g_pidWorkerMonitoringPortControl = -1;
// 2021-05-07 NEW huibong telegraf control 기능 추가 (#33542)
// Worker 프로세스 중 telegraf 모니터링, 재기동 처리를 담당하는 프로세스의 PID 정보
pid_t g_pidWorkerTelegrafControl = -1;
int main( int argc, char * argv[] )
{
// 설정 파일을 저장할 변수.
std::string strConfigFileName = DEFAULT_CONFIG_FILE;
// 전달 받은 옵션 여부 확인 및 처리
if( argc >= 2 )
{
int opt;
while( ( opt = getopt( argc, argv, "hvc:" ) ) != -1 ) // 옵션 끝까지 파싱처리
{
switch( opt )
{
case 'h':
case '?': // 정의되지 않은 문자가 나타날 경우 getopt 에 자동반환. 도움말 표시 처리.
PrintUsage();
return EXIT_SUCCESS;
case 'v':
PrintVersion();
return EXIT_SUCCESS;
case 'c':
strConfigFileName = optarg;
fprintf( stderr, PROG_NAME " start with user define conf[%s]\n", strConfigFileName.c_str() );
break;
default: // 본 조건절은 getopt 특성상 동작하지 않지만...업무 Flow 이해(?)를 위해 유지한다.
fprintf( stderr, "Unkonwn options[%c] used. program terminated.\n", opt );
return EXIT_FAILURE;
}
}
}
// 프로세스 중복 실행 여부 검사
if( IsCurrentProcessRun() == true )
{
fprintf( stderr, "[warning] Process [" PROG_NAME "] is already running....\n" );
return EXIT_FAILURE;
}
std::string szErrorMessage;
// conf 로딩 및 검사
if( CProcessConfig::Init( PROG_NAME, strConfigFileName, szErrorMessage ) == false )
{
fprintf( stderr, "[ERR] %s\n\n", szErrorMessage.c_str() );
return EXIT_FAILURE;
}
// Log 객체 생성 및 초기화
if( CLogger::Init( PROG_NAME, CProcessConfig::GetInstance()->GetLogPath(), LINF ) == false )
{
fprintf( stderr, "[ERR] Log module initialize failed.[%s]\n\n", CProcessConfig::GetInstance()->GetLogPath() );
return EXIT_FAILURE;
}
// Daemonize...
if( daemon( 1, 0 ) == -1 ) // nochdir: true(작업 디렉토리 변경 안함), noclose: false (표준 입출력, 에러를 /dev/null 로 리디렉트 처리)
{
fprintf( stderr, "[ERR] Process daemonize failed.[%s]\n\n", strerror( errno ) );
return EXIT_FAILURE;
}
// 공유메모리 생성 후 daemonize 처리시 문제
// - ipcs -ma 에 표시되는 CPID, LPID 에 daemonize 수행으로 인해 종료된 이전 process id 가 기록됨.
// - 이로 인해 정확한 상태를 판단하기 어려우므로.....
// - daemonzie 수행 후 공유메모리 생성, 접근을 수행하도록 한다.
// - 이로 인해 daemonizs 이후에는 fprintf 처리가 안되므로.. fprintf 구문은 주석 처리.
// 공유메모리 key
// - 다른 프로세스에서 사용하지 않으므로.. 고정키 값을 사용할 필요는 없다.
// - opendav 의 경우.. /tmp 상의 파일 생성 후 ftok() 함수를 이용하여 공유메모리 key 를 생성.
// - 따라서.. 고정 key 를 사용할 경우.. opendav 와 key 충돌 발생 우려가 있으므로...
// - opendav 와 동일한 방식으로 key 값을 생성하도록 처리한다.
// 공유메모리 key 생성 관련 기존 임시 파일 존재시 삭제 처리.
unlink( FHS_SHARED_MEMORY_FILE );
key_t iShmKey;
// 공유메모리 key 생성을 위한 임시 파일 생성 처리.
FILE * pShmFile = fopen( FHS_SHARED_MEMORY_FILE, "a+" );
if( pShmFile != NULL )
{
// Key file 생성이 성공한 경우... 파일만 있으면 되니까.. close 처리한다.
fclose( pShmFile );
pShmFile = NULL;
}
else
{
// Key file 생성에 실패한 경우...
int errorNum = errno;
LOG( LERR, "[Main] Shared memory key file create failed.[%s][%d][%s] => Process exit.", FHS_SHARED_MEMORY_FILE, errorNum, strerror( errorNum ) );
return EXIT_FAILURE;
}
// 임시 파일로 부터 key 값 추출
iShmKey = ftok( FHS_SHARED_MEMORY_FILE, 1 );
if( iShmKey == (key_t) -1 )
{
// 공유메모리 Key 생성 실패시
//fprintf( stderr, "[ERR] Shared memory key create failed. temp file[%s]\n\n", FHS_SHARED_MEMORY_FILE );
LOG( LERR, "[Main] Shared memory key create failed. key file[%s] => Process exit.", FHS_SHARED_MEMORY_FILE );
ReadyToExit();
return EXIT_FAILURE;
}
// 공유메모리에 생성 담당 class 객체를 생성 및 공유메모리 생성 or attach
CShmControl< struct FhsInfo > fhsShmManager;
if( fhsShmManager.Create( iShmKey, sizeof( struct FhsInfo ) ) == false )
{
//fprintf( stderr, "[ERR] Shared memory create failed. key[%ld] size[%lu]\n\n", iShmKey, sizeof( struct FhsInfo ) );
LOG( LERR, "[Main] Shared memory create failed. key[%ld] size[%lu] => Process exit.", iShmKey, sizeof( struct FhsInfo ) );
ReadyToExit();
return EXIT_FAILURE;
}
g_pShmManager = &fhsShmManager; // 전역 포인터에 대한 포인터 지정.
// 공유메모리에 데이터 입출력 처리를 담당할 class 객체 생성
CFhsShm fhsShm( fhsShmManager.GetShmPtr() );
if( fhsShm.IsValid() == false )
{
fhsShmManager.Remove();
//fprintf( stderr, "[ERR] Shared memory address not valid.\n\n" );
LOG( LERR, "[Main] Shared memory address not valid. => Process exit." );
ReadyToExit();
return EXIT_FAILURE;
}
g_pFhsShm = &fhsShm; // 전역 포인터에 대한 포인터 지정.
fhsShm.ClearAll(); // 공유메모리를 우선 초기화
fhsShm.SetServiceStat( SERVICE_STAT_OUT ); // 최초 기동시 서비스 상태는 수동 중지(1) 상태로 설정한다.
// signal 처리 설정
SetSignalMain();
// Process 기동 관련 정보 기록 -> Log
std::vector<std::string> vecTemp;
std::vector< std::string >::const_iterator it;
_LOG( LINF, "***********************************************************" );
_LOG( LINF, " %s Start. Version: %s", PROG_NAME, PROG_VERSION );
_LOG( LINF, "***********************************************************" );
_LOG( LINF, "Config : %s", strConfigFileName.c_str() );
_LOG( LINF, "Log : %s/%s", CProcessConfig::GetInstance()->GetLogPath(), PROG_NAME );
_LOG( LINF, "Log level : %d", CProcessConfig::GetInstance()->GetLogLevel() );
_LOG( LINF, "RC ID : %s", CProcessConfig::GetInstance()->GetRcId() );
_LOG( LINF, "Storage root : %s", CProcessConfig::GetInstance()->GetStorageRoot() );
_LOG( LINF, "Fimngd alive tcp port : %u", CProcessConfig::GetInstance()->GetFimngdCheckPort() );
_LOG( LINF, "Alive control listen tcp port : %u", CProcessConfig::GetInstance()->GetListenPortForStatusMonitoring() );
_LOG( LINF, "Service NIC" );
vecTemp = CProcessConfig::GetInstance()->GetSvcNic();
for( it = vecTemp.begin(); it != vecTemp.end(); it++ )
{
_LOG( LINF, " : %s", it->c_str() );
}
_LOG( LINF, "Check DNS List" );
vecTemp = CProcessConfig::GetInstance()->GetCheckDns();
for( it = vecTemp.begin(); it != vecTemp.end(); it++ )
{
_LOG( LINF, " : %s", it->c_str() );
}
_LOG( LINF, "RCTS");
_LOG( LINF, " Server address : %s", CProcessConfig::GetInstance()->GetRctsServer() );
_LOG( LINF, " System send tcp port : %u", CProcessConfig::GetInstance()->GetRctsSystemInfoPort() );
_LOG( LINF, " Service send tcp port : %u", CProcessConfig::GetInstance()->GetRctsServiceInfoPort() );
_LOG( LINF, "Shared Memory" );
_LOG( LINF, " Key : %ld", iShmKey );
_LOG( LINF, " Size : %lu", sizeof( struct FhsInfo ) );
_LOG( LINF, "***********************************************************" );
// Log Level 재설정. -> conf 설정대로 변경 처리.
#ifdef _DEBUG_
CLogger::GetInstance()->SetLogLevel( LDBG );
#else
CLogger::GetInstance()->SetLogLevel( CProcessConfig::GetInstance()->GetLogLevel() );
#endif
// Worker Process 생성
// FHS status 에 따른 GMS, Neocast 의 모니터링을 위한 TCP Port Control Worker 프로세스 생성
if( MakeWorkerMonitoringPortControl() == false )
{
LOG( LERR, "[Main] MonPortControl process create failed. => Process exit." );
ReadyToExit();
return EXIT_FAILURE;
}
// Worker Process 생성
// System 정보 Collect 처리를 담당할 SystemCollect Worker 프로세스 생성
if( MakeWorkerSystemCollect() == false )
{
LOG( LERR, "[Main] SystemCollect process create failed. => Process exit." );
ReadyToExit();
return EXIT_FAILURE;
}
// Storage 상태 Check 를 담당할 StorageCheck Worker 프로세스 생성
if( MakeWorkerStorageCheck() == false )
{
LOG( LERR, "[Main] StorageCheck process create failed. => Process exit." );
ReadyToExit();
return EXIT_FAILURE;
}
// Service 상태 Check 를 담당할 ServiceCheck Worker 프로세스 생성
if( MakeWorkerServiceCheck() == false )
{
LOG( LERR, "[Main] ServiceCheck process create failed. => Process exit." );
ReadyToExit();
return EXIT_FAILURE;
}
// RCTS 로 System, Service 상태 정보를 전송할 Send Worker 프로세스 생성
if( MakeWorkerSend() == false )
{
LOG( LERR, "[Main] Send process create failed. => Process exit." );
ReadyToExit();
return EXIT_FAILURE;
}
// telegraf control 을 담당할 worker 프로세스 생성
if( MakeWorkerTelegrafControl() == false )
{
LOG( LERR, "[Main] TelegrafControl process create failed. => Process exit." );
ReadyToExit();
return EXIT_FAILURE;
}
// Process Name 처리
setproctitle( "Main" );
// Main Process : 그냥 대기
while( 1 )
{
// Main Process 는 할 일이 없다.
// => Worker 프로세스 종료시 SIGCHLD 신호로 인해 신호처리기에서 Worker Process 재성성 수행함.
// => 따라서 그냥 시그널 대기
pause();
}
// 다음의 코드는 Daemon 으로 동작하기 때문에 수행되지 않는다.
ReadyToExit();
return EXIT_SUCCESS;
}
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExit()
{
// 공유메모리 key 생성에 사용된 임시 파일 삭제
unlink( FHS_SHARED_MEMORY_FILE );
// 공유메모리 제거
// - 다른 프로세스에서 사용할 것이 아니므로.. 종료시 삭제 처리한다.
if( g_pShmManager != NULL )
g_pShmManager->Remove();
// Logger 객체 종료 처리.
CLogger::Exit();
return;
}
// 사용방법 표시
void PrintUsage()
{
fprintf( stderr, "\n" );
fprintf( stderr, "Usage: " PROG_NAME " [-h] [-v] [-c {file}] \n" );
fprintf( stderr, "Options: \n" );
fprintf( stderr, " -h Display help information \n" );
fprintf( stderr, " -v Display version \n" );
fprintf( stderr, " -c {file} Use {file} as config file \n" );
fprintf( stderr, "\n" );
fprintf( stderr, PROG_NAME " is Solbox Cloud Storage module.\n" );
fprintf( stderr, " - System status collect periodically and transfer to RCTS.\n" );
fprintf( stderr, " - Service status check periodically and transfer to RCTS.\n" );
fprintf( stderr, " - Storage status check periodically.\n" );
fprintf( stderr, " - TCP port listen and control for FHS status monitoring.\n" );
fprintf( stderr, " - Telegraf hang check and auto restart.\n\n" );
return;
}
// 버전 정보 표시
void PrintVersion()
{
fprintf( stderr, "\n" );
fprintf( stderr, PROG_NAME " version: " PROG_VERSION "\n\n" );
return;
}
/// @brief 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
/// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
bool IsCurrentProcessRun( )
{
char tempBuffer[512];
FILE * fd = NULL;
bool bRun = false;
snprintf( tempBuffer, sizeof( tempBuffer ), "pgrep -x %s | sort", PROG_NAME );
fd = popen( tempBuffer, "r" );
if( fd == NULL )
{
std::cerr << "[error] Process duplication check failed.[popen error][" << strerror( errno ) << "]" << std::endl;
// 오류 발생시 true 반환하여 프로세스 실행 방지처리
return true;
}
else
{
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
while( fgets( tempBuffer, sizeof( tempBuffer ) - 1, fd ) != NULL )
{
std::string tempPid( tempBuffer );
Trim( tempPid );
if( atoi( tempPid.c_str() ) != getpid() )
{
std::cout << "[info] Process duplication found. pid[" << atoi( tempPid.c_str() ) << "]" << std::endl;
bRun = true;
break;
}
}
pclose( fd );
return bRun;
}
}
/// @brief std 상에 trim 함수가 없어서 직접 구현. 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
/// @return void
void Trim( std::string & str )
{
if( str.length() == 0 )
return;
// 문자열 뒤의 공백, TAB, CR 등의 문자 제거처리.
std::string::size_type pos = str.find_last_not_of( " \a\b\f\n\r\t\v" );
if( pos != std::string::npos )
str.erase( pos + 1 );
// 문자열 앞의 공백, TAB, CR 등의 문자 제거처리.
pos = str.find_first_not_of( " \a\b\f\n\r\t\v" );
if( pos != std::string::npos )
str.erase( 0, pos );
}
// Worker 프로세스 종료 신호 수신시
static void SignalWorkerDead( int nSignalNumber )
{
pid_t deadPid;
int nDeadStatus;
while( ( deadPid = waitpid( -1, &nDeadStatus, WNOHANG ) ) > 0 )
{
// Worker 프로세스가 signal 에 의해 종료되었는지 검사.
// - 종료 사유 로깅 및
// - Worker 의 초기화 실패로 인한 종료시... Main 프로세스가 종료되도록 처리.
if( WIFSIGNALED( nDeadStatus ) )
{
// signal 에 의해 종료된 경우...
// - 관련 내역 로깅
if( deadPid == g_pidWorkerSystemCollect )
{
_LOG( LWAR, "[Main] SystemCollect process[%d] killed by signal[%d]", deadPid, WTERMSIG( nDeadStatus ) );
}
else if( deadPid == g_pidWorkerStorageCheck )
{
_LOG( LWAR, "[Main] StorageCheck process[%d] killed by signal[%d]", deadPid, WTERMSIG( nDeadStatus ) );
}
else if( deadPid == g_pidWorkerServiceCheck )
{
_LOG( LWAR, "[Main] ServiceCheck process[%d] killed by signal[%d]", deadPid, WTERMSIG( nDeadStatus ) );
}
else if( deadPid == g_pidWorkerSend )
{
_LOG( LWAR, "[Main] Send process[%d] killed by signal[%d]", deadPid, WTERMSIG( nDeadStatus ) );
}
else if( deadPid == g_pidWorkerMonitoringPortControl )
{
_LOG( LWAR, "[Main] MonPortControl process[%d] killed by signal[%d]", deadPid, WTERMSIG( nDeadStatus ) );
}
else if( deadPid == g_pidWorkerTelegrafControl )
{
_LOG( LWAR, "[Main] TelegrafControl process[%d] killed by signal[%d]", deadPid, WTERMSIG( nDeadStatus ) );
}
else
{
_LOG( LWAR, "[Main] Unknown child process[%d] killed by signal[%d]", deadPid, WTERMSIG( nDeadStatus ) );
}
}
else
{
// signal 에 종료된 상황이 아닌 경우...
// - 각 Worker 의 초기화 실패 발생시... return 구문에 의해 종료됨.
// - 기타 등등.
// 관련 내역 로깅.
if( deadPid == g_pidWorkerSystemCollect )
{
_LOG( LWAR, "[Main] SystemCollect process[%d] killed. Not signal.", deadPid );
}
else if( deadPid == g_pidWorkerStorageCheck )
{
_LOG( LWAR, "[Main] StorageCheck process[%d] killed. Not signal.", deadPid );
}
else if( deadPid == g_pidWorkerServiceCheck )
{
_LOG( LWAR, "[Main] ServiceCheck process[%d] killed. Not signal.", deadPid );
}
else if( deadPid == g_pidWorkerSend )
{
_LOG( LWAR, "[Main] Send process[%d] killed. Not signal", deadPid );
}
else if( deadPid == g_pidWorkerMonitoringPortControl )
{
_LOG( LWAR, "[Main] MonPortControl process[%d] killed. Not signal", deadPid );
}
else if( deadPid == g_pidWorkerTelegrafControl )
{
_LOG( LWAR, "[Main] TelegrafControl process[%d] killed. Not signal", deadPid );
}
else
{
_LOG( LWAR, "[Main] Unknown child process[%d] killed. Not signal", deadPid );
}
// 만약 Worker 프로세스들이 초기화 실패로 인해 EXIT_FAILURE 반환되는 상황이라면...
// 자식 프로세스를 재생성하지 않고.. 프로세스를 종료 처리한다.
if( WIFEXITED( nDeadStatus ) )
{
if( WEXITSTATUS( nDeadStatus ) == EXIT_FAILURE )
{
if( deadPid == g_pidWorkerSystemCollect )
{
_LOG( LWAR, "[Main] SystemCollect process[%d] initialize failed.", deadPid );
}
else if( deadPid == g_pidWorkerStorageCheck )
{
_LOG( LWAR, "[Main] StorageCheck process[%d] initialize failed.", deadPid );
}
else if( deadPid == g_pidWorkerServiceCheck )
{
_LOG( LWAR, "[Main] ServiceCheck process[%d] initialize failed.", deadPid );
}
else if( deadPid == g_pidWorkerSend )
{
_LOG( LWAR, "[Main] Send process[%d] initialize failed.", deadPid );
}
else if( deadPid == g_pidWorkerMonitoringPortControl )
{
_LOG( LWAR, "[Main] MonPortControl process[%d] initialize failed.", deadPid );
}
else if( deadPid == g_pidWorkerTelegrafControl )
{
_LOG( LWAR, "[Main] TelegrafControl process[%d] initialize failed.", deadPid );
}
else
{
_LOG( LWAR, "[Main] Unknown child process[%d] exit with fail.", deadPid );
}
_LOG( LERR, "[Main] Program abnormally exited because Worker initialize faild.." );
// Main 종료 시그널 발생
raise( SIGTERM );
continue;
}
}
}
// 위에서 로깅 및 초기화 실패로 인한 Main 종료 처리 작업을 수행했으므로...
// 죽은 Worker 프로세스를 재생성 처리한다.
if( deadPid == g_pidWorkerSystemCollect )
{
if( MakeWorkerSystemCollect() == false )
{
_LOG( LERR, "[Main] SystemCollect process recreate failed.=> Main process exit.");
raise( SIGTERM );
}
else
{
_LOG( LWAR, "[Main] SystemCollect process recreate success." );
}
}
else if( deadPid == g_pidWorkerStorageCheck )
{
if( MakeWorkerStorageCheck() == false )
{
_LOG( LERR, "[Main] StorageCheck process recreate failed.=> Main process exit." );
raise( SIGTERM );
}
else
{
_LOG( LWAR, "[Main] StorageCheck process recreate success." );
}
}
else if( deadPid == g_pidWorkerServiceCheck )
{
if( MakeWorkerServiceCheck() == false )
{
_LOG( LERR, "[Main] ServiceCheck process recreate failed.=> Main process exit." );
raise( SIGTERM );
}
else
{
_LOG( LWAR, "[Main] ServiceCheck process recreate success." );
}
}
else if( deadPid == g_pidWorkerSend )
{
if( MakeWorkerSend() == false )
{
_LOG( LERR, "[Main] Send process recreate failed.=> Main process exit." );
raise( SIGTERM );
}
else
{
_LOG( LWAR, "[Main] Send process recreate success." );
}
}
else if( deadPid == g_pidWorkerMonitoringPortControl )
{
if( MakeWorkerMonitoringPortControl() == false )
{
_LOG( LERR, "[Main] MonPortControl process recreate failed.=> Main process exit." );
raise( SIGTERM );
}
else
{
_LOG( LWAR, "[Main] MonPortControl process recreate success." );
}
}
else if( deadPid == g_pidWorkerTelegrafControl )
{
if( MakeWorkerTelegrafControl() == false )
{
_LOG( LERR, "[Main] TelegrafControl process recreate failed.=> Main process exit." );
raise( SIGTERM );
}
else
{
_LOG( LWAR, "[Main] TelegrafControl process recreate success." );
}
}
}
// 오류 발생시 해당 내역 로깅
if( deadPid < 0 )
{
int errorNum = errno;
LOG( LERR, "[Main] SIG_CHLD receive but waitpid return error[%d][%s]", errorNum, strerror( errorNum ) );
}
return;
}
// Main 프로세스에 대한 종료 처리 수신시
static void SignalMainTerminate( int nSignalNumber )
{
// 자식 프로세스를 종료 처리한다.
if( g_pidWorkerMonitoringPortControl != -1 )
{
kill( g_pidWorkerMonitoringPortControl, SIGTERM );
}
if( g_pidWorkerSystemCollect != -1 )
{
kill( g_pidWorkerSystemCollect, SIGTERM );
}
if( g_pidWorkerStorageCheck != -1 )
{
kill( g_pidWorkerStorageCheck, SIGTERM );
}
if( g_pidWorkerServiceCheck != -1 )
{
kill( g_pidWorkerServiceCheck, SIGTERM );
}
if( g_pidWorkerSend != -1 )
{
kill( g_pidWorkerSend, SIGTERM );
}
if( g_pidWorkerTelegrafControl != -1 )
{
kill( g_pidWorkerTelegrafControl, SIGTERM );
}
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LINF, "[Main:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
}
else
{
_LOG( LWAR, "[Main:%d] Process exit by abnormal signal[%d]. Good Bye..", getpid(), nSignalNumber );
}
// 기타 모듈들의 종료 처리 수행
ReadyToExit();
// 종료전 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
// Main Process 의 signal 처리기...
// fork 된 worker 프로세스 역시 기본적으로 본 signal 처리 action 을 상속받는다.
void SetSignalMain()
{
sigset_t set;
struct sigaction act;
memset( &act, 0x00, sizeof( act ) );
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
sigfillset( &act.sa_mask );
// 무시 처리 signal
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker child process 종료에 대한 처리기 설정.
act.sa_handler = SignalWorkerDead;
sigaction( SIGCHLD, &act, NULL );
// 사용자의 종료 또는 에러 관련 신호 처리.
act.sa_handler = SignalMainTerminate;
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
// 나머지 신호는 default 처리.
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask( SIG_SETMASK, &set, NULL );
}
// System 정보 Collect 처리를 담당할 SystemCollect Worker 프로세스 생성
bool MakeWorkerSystemCollect()
{
// fork() 결과를 SystemCollect Worker 프로세스의 PID 정보 저장 목적 전역 변수에 저장
g_pidWorkerSystemCollect = fork();
if( g_pidWorkerSystemCollect == 0 )
{
// 생성된 Worker 프로세스인 경우...
int iResult;
// Worker SystemCollect 프로세스의 Main 함수 호출
iResult = WorkerSystemCollectMain();
// Worker SystemCollect 프로세스의 Main 함수 종료시 종료 처리
_LOG( LINF, "[Main] SystemCollect process exit. PID[%d] return[%d]", getpid(), iResult );
ReadyToExit();
exit( iResult );
}
else if( g_pidWorkerSystemCollect < 0 )
{
// fork 실패시
int errorNum = errno;
LOG( LERR, "[Main] SystemCollect process create failed. [%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
else
{
// 현재의 Main 프로세스
_LOG( LINF, "[Main] SystemCollect process created.. PID[%d]", g_pidWorkerSystemCollect );
// 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 200000000; // 0.2 sec
nanosleep( &sleep, NULL );
}
return true;
}
// Service 상태 Check 를 담당할 ServiceCheck Worker 프로세스 생성
bool MakeWorkerServiceCheck()
{
// fork() 결과를 ServiceCheck Worker 프로세스의 PID 정보 저장 목적 전역 변수에 저장.
g_pidWorkerServiceCheck = fork();
if( g_pidWorkerServiceCheck == 0 )
{
// 생성된 Worker 프로세스인 경우...
int iResult;
// Worker ServiceCheck 프로세스의 Main 함수 호출
iResult = WorkerServiceCheckMain();
// Worker ServiceCheck 프로세스의 Main 함수 종료시 종료 처리
_LOG( LINF, "[Main] ServiceCheck process exit. PID[%d] return[%d]", getpid(), iResult );
ReadyToExit();
exit( iResult );
}
else if( g_pidWorkerServiceCheck < 0 )
{
// fork 실패시
int errorNum = errno;
LOG( LERR, "[Main] ServiceCheck process create failed. [%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
else
{
// 현재의 Main 프로세스
_LOG( LINF, "[Main] ServiceCheck process created.. PID[%d]", g_pidWorkerServiceCheck );
// 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 200000000; // 0.2 sec
nanosleep( &sleep, NULL );
}
return true;
}
// RCTS 로 System, Service 상태 정보를 전송할 Send Worker 프로세스 생성
bool MakeWorkerSend()
{
// fork() 결과를 Send Worker 프로세스의 PID 정보 저장 목적 전역변수에 저장.
g_pidWorkerSend = fork();
if( g_pidWorkerSend == 0 )
{
// 생성된 Worker 프로세스인 경우...
int iResult;
// Worker Send 프로세스의 Main 함수 호출
iResult = WorkerSendMain();
// Worker Send 프로세스의 Main 함수 종료시 종료 처리
_LOG( LINF, "[Main] Send process exit. PID[%d] return[%d]", getpid(), iResult );
ReadyToExit();
exit( iResult );
}
else if( g_pidWorkerSend < 0 )
{
// fork 실패시
int errorNum = errno;
LOG( LERR, "[Main] Send process create failed. [%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
else
{
// 현재의 Main 프로세스
_LOG( LINF, "[Main] Send process created.. PID[%d]", g_pidWorkerSend );
// 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 200000000; // 0.2 sec
nanosleep( &sleep, NULL );
}
return true;
}
// Storage 상태 Check 를 담당할 StorageCheck Worker 프로세스 생성
bool MakeWorkerStorageCheck()
{
// fork() 결과를 StorageCheck Worker 프로세스의 PID 정보 저장 목적 전역 변수에 저장.
g_pidWorkerStorageCheck = fork();
if( g_pidWorkerStorageCheck == 0 )
{
// 생성된 Worker 프로세스인 경우...
int iResult;
// Worker StorageCheck 프로세스의 Main 함수 호출
iResult = WorkerStorageCheckMain();
// Worker StorageCheck 프로세스의 Main 함수 종료시 종료 처리
_LOG( LINF, "[Main] StorageCheck process exit. PID[%d] return[%d]", getpid(), iResult );
ReadyToExit();
exit( iResult );
}
else if( g_pidWorkerStorageCheck < 0 )
{
// fork 실패시
int errorNum = errno;
LOG( LERR, "[Main] StorageCheck process create failed. [%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
else
{
// 현재의 Main 프로세스
_LOG( LINF, "[Main] StorageCheck process created.. PID[%d]", g_pidWorkerStorageCheck );
// 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 200000000; // 0.2 sec
nanosleep( &sleep, NULL );
}
return true;
}
// TCP Port 를 Listen 상태로 Open 후 서비스 상태에 따른 Port 상태 제어를 담당할 Worker 프로세스 생성
bool MakeWorkerMonitoringPortControl()
{
// fork() 결과를 MonPortControl Worker 프로세스의 PID 정보 저장 목적 전역 변수에 저장.
g_pidWorkerMonitoringPortControl = fork();
if( g_pidWorkerMonitoringPortControl == 0 )
{
// 생성된 Worker 프로세스인 경우...
int iResult;
// Worker MonPortControl 프로세스의 Main 함수 호출
iResult = WorkerMonPortControlMain();
// Worker MonPortControl 프로세스의 Main 함수 종료시 종료 처리
_LOG( LINF, "[Main] MonPortControl process exit. PID[%d] return[%d]", getpid(), iResult );
ReadyToExit();
exit( iResult );
}
else if( g_pidWorkerMonitoringPortControl < 0 )
{
// fork 실패시
int errorNum = errno;
LOG( LERR, "[Main] MonPortControl process create failed. [%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
else
{
// 현재의 Main 프로세스
_LOG( LINF, "[Main] MonPortControl process created.. PID[%d]", g_pidWorkerMonitoringPortControl );
// 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 200000000; // 0.2 sec
nanosleep( &sleep, NULL );
}
return true;
}
// Telegarf control 을 담당할 worker 프로세스 생성
bool MakeWorkerTelegrafControl()
{
// fork() 결과를 TelegrafControl Worker 프로세스의 PID 정보 저장 목적 전역 변수에 저장.
g_pidWorkerTelegrafControl = fork();
if( g_pidWorkerTelegrafControl == 0 )
{
// 생성된 Worker 프로세스인 경우...
int iResult;
// Worker TelegrafControl 프로세스의 Main 함수 호출
iResult = WorkerTelegrafControlMain();
// Worker TelegrafControl 프로세스의 Main 함수 종료시 종료 처리
_LOG( LINF, "[Main] TelegrafControl process exit. PID[%d] return[%d]", getpid(), iResult );
ReadyToExit();
exit( iResult );
}
else if( g_pidWorkerTelegrafControl < 0 )
{
// fork 실패시
int errorNum = errno;
LOG( LERR, "[Main] TelegrafControl process create failed. [%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
else
{
// 현재의 Main 프로세스
_LOG( LINF, "[Main] TelegrafControl process created.. PID[%d]", g_pidWorkerTelegrafControl );
// 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 200000000; // 0.2 sec
nanosleep( &sleep, NULL );
}
return true;
}
+85
View File
@@ -0,0 +1,85 @@
/****************************************************************************
Main.h for csagentd
-----------------------------------------
begin : 2015/04/13
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __CS_AGENTD_MAIN_H__
#define __CS_AGENTD_MAIN_H__
#include <unistd.h>
#include <stdlib.h>
#include <string>
#ifdef __cplusplus
extern "C" {
#endif
/// @brief 사용 방법을 화면에 표시하기 위한 함수.
void PrintUsage( void );
/// @brief Version 정보를 화면에 표시하기 위한 함수
void PrintVersion( void );
/// @brief 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
/// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
bool IsCurrentProcessRun( void );
/// @brief std 상에 trim 함수가 없어서 직접 구현 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
/// @param str [in/out] Trim 할 문자열을 저장한 String 참조변수.
/// @return void
void Trim( std::string & str );
/// @brief 프로세스 종료에 따른 반복적인 종료 관련 작업을 수행하기 위한 함수.
void ReadyToExit( void );
/// @brief Main 프로세스 signal 처리 설정을 위한 함수
/// @return void
void SetSignalMain( void );
/// @brief System 정보 Collect 처리를 담당할 SystemCollect Worker 프로세스 생성
/// @return 생성 성공시 true, 실패시 false
bool MakeWorkerSystemCollect();
/// @brief Service 상태 Check 를 담당할 ServiceCheck Worker 프로세스 생성
/// @return 생성 성공시 true, 실패시 false
bool MakeWorkerServiceCheck();
/// @brief RCTS 로 System, Service 상태 정보를 전송할 Send Worker 프로세스 생성
/// @return 생성 성공시 true, 실패시 false
bool MakeWorkerSend();
/// @brief Storage 상태 Check 를 담당할 StorageCheck Worker 프로세스 생성
/// @return 생성 성공시 true, 실패시 false
bool MakeWorkerStorageCheck();
/// @brief TCP Port 를 Listen 상태로 Open 후 서비스 상태에 따른 Port 상태 제어를 담당할 Worker 프로세스 생성
/// @return 생성 성공시 true, 실패시 false
bool MakeWorkerMonitoringPortControl();
// Telegarf control 을 담당할 worker 프로세스 생성
bool MakeWorkerTelegrafControl();
#ifdef __cplusplus
}
#endif
#endif /* __CS_AGENTD_MAIN_H__ */
+81
View File
@@ -0,0 +1,81 @@
#****************************************************************************
# Makefile for csagentd
# -----------------------------------------
#
# begin : 2015/04/13
# copyright : (C) 2005 Solbox Inc.
# author : Dev Storage Team
# email : huibong@solbox.com
# version : 3.5
#
# CopyRight(C) 2005 Solbox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of Solbox Inc.
#****************************************************************************
# Program info
PROG_NAME = csagentd
REVISION = 1539
PROG_VERSION = 3.5.0.$(REVISION)-`date +%Y%m%d%H%M%S`
DEFAULT_CONFIG_FILE = /user/service/etc/fhs.conf
INSTALL_BIN = /user/service/bin
INSTALL_CONF = /user/service/etc
# Compiler info
CC = /usr/bin/g++
CFLAGS = -Wall -O2 -g -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-fno-rtti -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LFLAGS =
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
# Application Enviroment
APP = $(PROG_NAME)
DIR_INCLUDE = -I../lib
DIR_LIB = -L../lib
OBJ = ProcessConfig.o FhsShm.o StorageInfo.o \
SystemInfo.o ServiceCheck.o RctsSocket.o StorageCheck.o TelegrafControl.o \
WorkerSystemCollect.o WorkerServiceCheck.o WorkerSend.o WorkerStorageCheck.o \
WorkerMonitoringPortControl.o WorkerTelegrafControl.o \
Main.o
LIBS = ../lib/libInterCommon.a -lpthread -lkvm -lgeom -ldevstat -lc -lm
#---------------------------------------------------------------------#
all:$(APP)
sync
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
$(PROG_NAME): $(OBJ)
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
clean:
-rm -f *.o core *.out *.log
-rm -f $(APP)
sync
install : $(APP)
-cp $(APP) $(INSTALL_BIN)/$(APP)
sync
# End of Makefile
+322
View File
@@ -0,0 +1,322 @@
#include "ProcessConfig.h"
#include <stdlib.h>
#include "Logger.h"
// static 변수 초기화
CProcessConfig * CProcessConfig::m_pInstance = NULL;
// conf 상의 FHS_LISTEN_PORT_FOR_STATUS_MONITORING 정보가 없을 경우 사용할 Default 정보
// - GMS, Neocast 등에서 FHS 상태를 감시하기 위한 TCP port
// - 본 모듈에서 해당 TCP port 를 Listen 하면서 서비스 상태에 따라 TCP 상태를 제어하여
// - FHS 서비스 불가 등의 문제 발생시.. GMS, Neocast 가 이를 인지할 수 있도록 하기 위한 Port 정보임
#define DEFAULT_TCP_LISTEN_PORT_FOR_STATUS_MONITORING 8083
// 생성자
CProcessConfig::CProcessConfig()
{
// default 값 설정.
// FHS_LISTEN_PORT_FOR_STATUS_MONITORING
m_nListenPortForStatusMonitoring = DEFAULT_TCP_LISTEN_PORT_FOR_STATUS_MONITORING;
}
// 소멸자
CProcessConfig::~CProcessConfig()
{
// 객체 소멸시...
// 만약 static GetInstance() 함수가 가르키는 객체가 자기 자신이라면...
// 소멸 처리에 의해 문제가 발생할 수 있으므로... 이에 대한 처리를 해 준다.
if( CProcessConfig::GetInstance() == this )
{
CProcessConfig::m_pInstance = NULL;
}
}
bool CProcessConfig::Init( const std::string strProgramName, const std::string & strConfFileName, std::string & strErrorMessage )
{
// 1. 임시 처리용 Instance 를 생성한다.
CProcessConfig * pTempInstance = new CProcessConfig();
// 2. 전달 받은 Config 정보를 임시 Instance 로 로딩한다.
// - 만약 로딩이 실패할 경우... 임시 Instance 객체를 삭제 처리한다.
if( pTempInstance->Load( strProgramName, strConfFileName, strErrorMessage ) == false )
{
delete pTempInstance;
pTempInstance = NULL;
return false; // 생성 실패 사유는 Error String 관련 함수를 사용하여 확인.
}
// 3. 전달받은 Conf 정보 로딩에 성공한 경우...
// - 기존 Instance 객체가 존재하는 경우.. 교체 처리..
// - 기존 Instance 객체가 없는 경우는 신규 Instance 사용토록 처리.
if( CProcessConfig::GetInstance() == NULL )
{
CProcessConfig::m_pInstance = pTempInstance;
}
else
{
// Instance replace...
CProcessConfig * pPreviosInstance = CProcessConfig::m_pInstance;
CProcessConfig::m_pInstance = pTempInstance;
delete pPreviosInstance;
}
return true;
}
CProcessConfig * CProcessConfig::GetInstance()
{
return CProcessConfig::m_pInstance;
}
bool CProcessConfig::Load( const std::string & strProgramName, const std::string & strConfFileName, std::string & strErrorMessage )
{
// 변수 유효성 확인
if( strProgramName.size() <= 0 )
{
strErrorMessage = "Config Program Name[" + strProgramName + "] not valid.";
return false;
}
// Config class (lib 하위) 를 이용하여 config 파일 상의 정보를 로딩 처리
Config conf;
if( conf.Open( strConfFileName ) == false )
{
strErrorMessage = "Config file[" + strConfFileName + "] open failed.";
return false;
}
// Config 모듈에 로딩된 정보 중 필요한 정보만 가져온다...
// - 만약 오류가 발생할 경우... 해당 내역은 Error String 에 저장 처리...
std::string strValue;
std::vector< std::string > vecValue;
// DEFAULT_LOG_DIR
if( GetConfigValue( conf, strProgramName, "DEFAULT_LOG_DIR", strValue, strErrorMessage ) == false )
return false;
else
{
m_strLogPath = strValue;
strValue.clear();
}
// LOG_LEVEL
if( GetConfigValue( conf, strProgramName, "LOG_LEVEL", strValue, strErrorMessage ) == false )
return false;
else
{
m_nLogLevel = atoi(strValue.c_str());
if( m_nLogLevel < 0 || m_nLogLevel > MAX_LOG_LEVEL )
{
strErrorMessage = "Config [LOG_LEVEL] value[" + strValue + "] is not valid";
return false;
}
strValue.clear();
}
// RCID
if( GetConfigValue( conf, strProgramName, "RCID", strValue, strErrorMessage ) == false )
return false;
else
{
m_strRcId = strValue;
strValue.clear();
}
// FILE_STORAGE_ROOT
if( GetConfigValue( conf, strProgramName, "FILE_STORAGE_ROOT", strValue, strErrorMessage ) == false )
return false;
else
{
m_strStorageRoot = strValue;
strValue.clear();
}
// RCTS_SERVER
if( GetConfigValue( conf, strProgramName, "RCTS_SERVER", strValue, strErrorMessage ) == false )
return false;
else
{
m_strRctsServer = strValue;
strValue.clear();
}
// FHS_PORT_MNGCHECK
// - fhs fimngd 의 alive check 를 위한 tcp port
if( GetConfigValue( conf, strProgramName, "FHS_PORT_MNGCHECK", strValue, strErrorMessage ) == false )
return false;
else
{
m_nFimngdCheckPort = atoi( strValue.c_str() );
if( m_nFimngdCheckPort <= 0 || m_nFimngdCheckPort > 65535 )
{
strErrorMessage = "Config [FHS_PORT_MNGCHECK] value[" + strValue + "] is not valid";
return false;
}
strValue.clear();
}
// FHS_LISTEN_PORT_FOR_STATUS_MONITORING
// - GMS, Neocast 등에서 FHS 상태를 감시하기 위한 TCP port
// - 본 모듈에서 해당 TCP port 를 Listen 하면서 서비스 상태에 따라 TCP 상태를 제어하여
// - FHS 서비스 불가 등의 문제 발생시.. GMS, Neocast 가 이를 인지할 수 있도록 하기 위한 Port 정보임
if( GetConfigValue( conf, strProgramName, "FHS_LISTEN_PORT_FOR_STATUS_MONITORING", strValue, strErrorMessage ) == false )
{
// 해당 항목이 존재하지 않을 경우
// 하위 호환성 및 binary 만 우선 적용 등의 이슈로 인해
// default 값을 적용 처리한다.
m_nListenPortForStatusMonitoring = DEFAULT_TCP_LISTEN_PORT_FOR_STATUS_MONITORING;
}
else
{
// 해당 값이 존재하는 경우
m_nListenPortForStatusMonitoring = atoi( strValue.c_str() );
if( m_nListenPortForStatusMonitoring <= 0 || m_nListenPortForStatusMonitoring > 65535 )
{
strErrorMessage = "Config [FHS_LISTEN_PORT_FOR_STATUS_MONITORING] value[" + strValue + "] is not valid";
return false;
}
strValue.clear();
}
// SERVICE_NIC_NAME
// - 다중 값으로 정의 될 수 있으며.. 존재하지 않는 경우.. 오류로 처리
if( conf.GetConfig( strProgramName, "SERVICE_NIC_NAME", vecValue ) == true )
{
// 해당 값이 존재할 경우
// - GetConfig() 에서 결과값이 empty 인 경우.. false 를 반환하므로...
// - ture 반환시에는 정상적인 값이 존재한다고 판단해도 무방
m_vecSvcNic = vecValue;
vecValue.clear();
}
else
{
// program section 에 존재하지 않을 경우... COMMON 세션 확인
if( conf.GetConfig( "COMMON", "SERVICE_NIC_NAME", vecValue ) == true )
{
m_vecSvcNic = vecValue;
vecValue.clear();
}
else
{
// program, COMMON section 에 해당값이 모두 설정되지 않은 경우....
// 오류 처리
strErrorMessage = "Config [SERVICE_NIC_NAME] value is not valid";
return false;
}
}
// CHECK_DNS_LIST
// - 다중 값으로 정의 될 수 있으며..
// - 설정값이 존재하지 않을 수 있다.
if( conf.GetConfig( strProgramName, "CHECK_DNS_LIST", vecValue ) == true )
{
// 해당 값이 존재할 경우
// - GetConfig() 에서 결과값이 empty 인 경우.. false 를 반환하므로...
// - ture 반환시에는 정상적인 값이 존재한다고 판단해도 무방
m_vecCheckDns = vecValue;
vecValue.clear();
}
else
{
// program section 에 존재하지 않을 경우... COMMON 세션 확인
if( conf.GetConfig( "COMMON", "CHECK_DNS_LIST", vecValue ) == true )
{
m_vecCheckDns = vecValue;
vecValue.clear();
}
else
{
// program, COMMON section 에 해당값이 모두 설정되지 않은 경우....
// - 설정값이 존재하지 않을 수 있으므로.. 그냥 통과.
m_vecCheckDns.clear();
vecValue.clear();
}
}
// RCTS_PORT_INFO_SYSTEM
// - rcts rc_mond 의 system info 수신을 위한 TCP listen port 정보
if( GetConfigValue( conf, strProgramName, "RCTS_PORT_INFO_SYSTEM", strValue, strErrorMessage ) == false )
return false;
else
{
m_nRctsSystemInfoPort = atoi( strValue.c_str() );
if( m_nRctsSystemInfoPort <= 0 || m_nRctsSystemInfoPort > 65535 )
{
strErrorMessage = "Config [RCTS_PORT_INFO_SYSTEM] value[" + strValue + "] is not valid";
return false;
}
strValue.clear();
}
// RCTS_PORT_INFO_SERVICE
// - rcts rc_mond 의 service check info 수신을 위한 TCP listen port 정보
if( GetConfigValue( conf, strProgramName, "RCTS_PORT_INFO_SERVICE", strValue, strErrorMessage ) == false )
return false;
else
{
m_nRctsServiceInfoPort = atoi( strValue.c_str() );
if( m_nRctsServiceInfoPort <= 0 || m_nRctsServiceInfoPort > 65535 )
{
strErrorMessage = "Config [RCTS_PORT_INFO_SERVICE] value[" + strValue + "] is not valid";
return false;
}
strValue.clear();
}
// conf 정보 로딩이 모두 정상적으로 완료된 경우... 마지막으로 전달받은 config 명, section 정보를 저장한다.
m_strConfigFileName = strConfFileName;
m_strProgramName = strProgramName;
return true;
}
bool CProcessConfig::GetConfigValue( Config & conf, const std::string & strProgramName, const std::string strKey, std::string & strValue, std::string & strErrorMessage )
{
// conf get value
if( conf.GetConfig( strProgramName, strKey, strValue) == false )
{
if( conf.GetConfig( "COMMON", strKey, strValue) == false )
{
strErrorMessage = "Config [" + strKey + "] value is not exist";
return false;
}
}
// value check.
if( strValue.empty() == true )
{
strErrorMessage = "Config [" + strKey + "] value is not valid";
return false;
}
return true;
}
+130
View File
@@ -0,0 +1,130 @@
/****************************************************************************
csagentd config processing module
-----------------------------------------
begin : 2015/04/20
copyright : (C) 2005 Solbox Inc.
author : Dev Storage team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __PROCESS_CONFIG_H__
#define __PROCESS_CONFIG_H__
#include <string>
#include "Config.h"
// 본 모듈은 conf 파일의 정보를 read 하여... 본 프로세스 관련 설정 정보를 저장한다.
// 본 모듈은 singleton 으로 동작시켜 Main 프로세스 및 Worker 프로세스에서도 접근이 가능토록 한다.
// conf 파일에 대한 파싱 및 설정 정보 추출은 lib 하위의 Config 클래스를 이용한다.
// 본 객체는 singleton 객체이므로 상속받아 사용하지 않도록 한다. ( 상속받아 사용할 수 없도록 private 처리함 )
class CProcessConfig
{
private:
// sigleton 객체 생성을 위해 생성자를 public 으로 처리하지 않음.
CProcessConfig();
// 소멸자
virtual ~CProcessConfig();
static CProcessConfig * m_pInstance;
public:
// 객체 초기화 처리용 Function.
// 본 함수 호출시 Instance 생성 후 입력 받은 Config 파일 load.
// 따라서 본 함수를 호출하지 않을 경우.. GetInstance() 함수는 NULL 을 반환
// 본 함수를 객체가 생성된 상태에서 재 호출할 경우
// - 주어진 Conf 파일 정보가 정확하다면.. conf 정보를 다시 load 함.
// - 주어진 conf 파일 정보가 부정확하다면... 이전 conf 를 계속 사용함.
static bool Init( const std::string strProgramName, const std::string & strConfFileName, std::string & strErrorMessage );
// Singleton 객체 접근 메소드
static CProcessConfig * GetInstance();
private:
// 전달받은 conf 파일에서 해당 config 정보를 로드하여 멤버 변수에 저장한다.
// 만약 반환값이 false 인 경우 해당 오류 관련 내역은 strErrorMessage 변수에 저장된다.
bool Load( const std::string & strProgramName, const std::string & strConfFileName, std::string & strErrorMessage );
// Config 객체로 부터 지정된 strKey 정보를 가져와 유효성 여부를 판단.
// 반환값이 false 인 경우 strErrorMessage 상에 오류 내역이 저장된다.
bool GetConfigValue( Config & conf, const std::string & strProgramName, const std::string strKey, std::string & strValue, std::string & strErrorMessage );
private:
// 객체 초기화시 전달받은 정보
std::string m_strConfigFileName; // 설정 파일 정보
std::string m_strProgramName; // 프로그램 명 (conf 상에서 해당 프로그램의 설정 정보를 가져올 때 사용)
// 기본 설정 정보.
std::string m_strLogPath; // 로그 저장 Path (/user/service/logs)
int m_nLogLevel; // 로그 기록 Level
std::string m_strRcId; // RC ID
std::string m_strStorageRoot; // content save path
std::string m_strRctsServer; // RCTS ip or domain
unsigned int m_nFimngdCheckPort; // FHS fimngd alive check tcp port
// GMS, Neocast 등에서 FHS 상태를 감시하기 위한 TCP port
// 본 모듈에서 해당 TCP port 를 Listen 하면서 서비스 상태에 따라 TCP 상태를 제어하여
// FHS 서비스 불가 등의 문제 발생시.. GMS, Neocast 가 이를 인지할 수 있도록 하기 위한 Port 정보임
unsigned int m_nListenPortForStatusMonitoring;
// 프로세스 설정 정보
std::vector<std::string> m_vecSvcNic; // Service NIC name 정보 저장.
std::vector<std::string> m_vecCheckDns; // DNS resolve check 대상 dns name
// - 설정값이 존재하지 않을 수 있음.
unsigned int m_nRctsSystemInfoPort; // RCTS system info listen tcp port
unsigned int m_nRctsServiceInfoPort; // RCTS service info listen tcp port
public: // 멤버 변수에 대한 Get 함수 선언 및 정의
const char * GetConfigFileName() { return m_strConfigFileName.c_str(); }
const char * GetProgramName() { return m_strProgramName.c_str(); }
const char * GetLogPath() { return m_strLogPath.c_str(); }
int GetLogLevel() { return m_nLogLevel; }
const char * GetRcId() { return m_strRcId.c_str(); }
const char * GetStorageRoot() { return m_strStorageRoot.c_str(); }
const char * GetRctsServer() { return m_strRctsServer.c_str(); }
std::vector<std::string> GetSvcNic() { return m_vecSvcNic; }
std::vector<std::string> GetCheckDns() { return m_vecCheckDns; }
unsigned int GetRctsSystemInfoPort() { return m_nRctsSystemInfoPort; }
unsigned int GetRctsServiceInfoPort() { return m_nRctsServiceInfoPort; }
unsigned int GetFimngdCheckPort() { return m_nFimngdCheckPort; }
unsigned int GetListenPortForStatusMonitoring() { return m_nListenPortForStatusMonitoring; }
};
#endif /* __PROCESS_CONFIG_H__ */
+128
View File
@@ -0,0 +1,128 @@
/****************************************************************************
socket 통신 관련 protocol 정의
-----------------------------------------
begin : 2015/05/15
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __PROTOCOL_DEFINE_H__
#define __PROTOCOL_DEFINE_H__
#include "ShmDefine.h"
// Packet Header stx 코드
#define HEADER_STX_CODE 0x05
// Packet Header type 구분코드
#define HEADER_TYPE_REQUEST 0x00
#define HEADER_TYPE_RESPONSE 0x01
// Packet Header command 구분 코드.
#define COMMAND_TRANSFER_SYSTEM 0x01 // system 수집 정보 전송.
#define COMMAND_TRANSFER_SERVICE 0x02 // service 상태 check 정보 전송.
// 기타 정보
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
// RCTS rc_mond 와 통신시 사용할 통신 Header
// - 계산상 크기는 16Byte 이지만...
// - 통신상 sizeof() : 20Byte ( 64Bit OS )
struct PacketHeader {
char stx; // Packet 유효성 관리 코드
char type; // Request or Response 여부 ( 0x00: Request, 0x01: Response )
char command[4]; // Command Code ( 4 Byte) : 0th csagent-rc_mond 만 사용.
char result[4]; // Result Code ( 4 Byte )
unsigned int data_length; // Packet Data 부분의 길이값 ( Network Byte Order 사용)
// 2015-05-15 huibong
// Protocol version 정보 추가로 인해... extend_code 2Byte 중 1Byte 사용.
//char extend_code[2]; // 확장 및 Padding bits ( 2 Byte )
char protocol_version; // Packet Data 의 Protocol Version 정보. (1 Byte)
char extend_code; // 확장 및 Padding bits ( 1 Byte )
};
////////////////////////////////////////////
// RC ID 최대 길이.
#define RC_ID_MAX_LENGTH 31
// RCTS rc_mond 로 전송할 system 수집 data 구조체 protocol version.
// - 최초 버전이므로 0x00 으로 설정.
#define PROTOCOL_VERSION_SYSTEM 0x00
// RCTS rc_mond 로 전송할 system 수집정보 data 구조체
// - 전송할 항목이 많아... struct 형식으로 전송 처리.
// - protocol version : 0x00
// - 공유메모리 SystemInfo 구조체를 사용하도록 처리할 수 있지만...
// -- 공유메모리 구조 변경시.. 통신 오류 발생 가능..
// -- 따라서 복잡하더라고.. 공유메모리 구조체와 통신 구조체를 별도로 분리 처리함.
struct PacketDataSystem {
char rcid[RC_ID_MAX_LENGTH+1]; // RCID 정보, 최대 31 자까지만 허용.
char hostname[HOST_NAME_MAX_LENGTH+1]; // hostname, key 값으로 사용, 최대 63자까지만 허용.
double load_avg[3]; // load average.
uint64_t memory_total; // Total memory size (byte 단위)
uint64_t memory_free; // Free memory size (byte 단위)
int memory_usage; // memory 사용률 (%)
uint64_t swap_total; // Total swap size (byte 단위)
uint64_t swap_used; // Used swap size (byte 단위)
int swap_usage; // swap 사용률 (%)
uint64_t storage_total; // Total Storage size (byte 단위)
uint64_t storage_avail; // Available Storage size (byte 단위)
int storage_max_usage; // Storage 중 최대 사용률 (%)
uint64_t disk_max_queue; // Disk 상태 정보 중 Max Queue Length
double disk_max_busy; // Disk 상태 정보 중 Max busy(%)
uint64_t network_packet_in; // Network inbound packet count (단위 시간내의 count)
uint64_t network_packet_out; // Network outbound packet count (단위 시간내의 count)
uint64_t network_traffic_in; // Network inbound 평균 traffic (Byte/sec)
uint64_t network_traffic_out; // Network outbound 평균 traffic (Byte/sec)
unsigned int tcp_total; // TCP 세션 total count
unsigned int tcp_80; // TCP 세션 중 local 80 port 를 사용하는 세션 count
unsigned int tcp_80_establish; // TCP 세션 중 local 80 port 를 사용하고.. ESTABLISH 상태인 세션 count
};
// RCTS rc_mond 로 전송할 service 상태 data 구조체 protocol version.
// - 최초 버전이므로 0x00 으로 설정.
#define PROTOCOL_VERSION_SERVICE 0x00
// RCTS rc_mond 로 전송할 service 상태 data 구조체
// - protocol version : 0x00
struct PacketDataService {
char rcid[RC_ID_MAX_LENGTH+1]; // RCID 정보, 최대 31 자까지만 허용.
char hostname[HOST_NAME_MAX_LENGTH+1]; // hostname, key 값으로 사용, 최대 63자까지만 허용.
int service_stat; // Service 상태 정보, ShmDefine.h 정의 참고.
int storage_max_usage; // Storage 최대 사용률(%), ShmDefine.h 정의 참고.
};
#endif /* __PROTOCOL_DEFINE_H__ */
+208
View File
@@ -0,0 +1,208 @@
#include "RctsSocket.h"
#include "Logger.h"
#include <string.h>
#include <netinet/in.h>
// 생성자
CRctsSocket::CRctsSocket()
: CBaseSocket( SOCKET_NOT_VALID )
, m_iPacketHeaderLen( sizeof( struct PacketHeader ) )
, m_uPacketDataLen( 0 )
{
}
// 소멸자
CRctsSocket::~CRctsSocket()
{
// 명시적인 Close 처리.
Close();
}
// 객체 초기화
// - false : 전달된 인자값 오류시
bool CRctsSocket::Init( const char * szServer, unsigned int uPort, const char * szRcId )
{
// 전달된 변수의 유효성 여부 판단.
if( szServer == NULL )
{
LOG( LERR, "server name or ip is null." );
return false;
}
if( szRcId == NULL )
{
LOG( LERR, "rcid is null." );
return false;
}
if( strlen( szRcId ) > RC_ID_MAX_LENGTH )
{
LOG( LERR, "rcid[%s] too long. max length [%d]", szRcId, RC_ID_MAX_LENGTH );
return false;
}
// 멤버 변수에 저장 처리.
m_strServer = szServer;
m_uPort = uPort;
m_strRcId = szRcId;
return true;
}
// RCTS 로 수집된 시스템 정보를 전송한다.
bool CRctsSocket::SendSystemInfo( const struct SystemInfo * pSystem )
{
// Socket 이 유효, 연결되어 있는지 확인.
if( IsValidSocket() == false )
{
// RCTS 에 연결되지 않은 경우....
// - RCTS 와 연결 시도.
if( Connect( m_strServer, m_uPort ) == false )
{
LOG( LERR, "rcts connect fail. rcts[%s][%u]", m_strServer.c_str(), m_uPort );
Close();
return false;
}
}
// 각 Packet 전송 관련 구조체 초기화.
memset( &m_packetHeader, 0x00, sizeof( struct PacketHeader ) );
memset( &m_packetDataSystem, 0x00, sizeof( struct PacketDataSystem ) );
// system 수집 정보 전송을 위한 Packet Data 구조체 설정.
strcpy( m_packetDataSystem.rcid, m_strRcId.c_str() );
// 공유메모리 구조체를 그대로 복사해도 되지만...
// - 향후 항목 추가시 통신 오류 발생 가능.
// - 이로 인해 protocol version 기능이 추가되어 있음.
// - 따라서 통신 오류 등을 방지하기 위해 공유메모리, 통신 구조체가 별도 분리되어 있음.
strcpy( m_packetDataSystem.hostname, pSystem->hostname );
m_packetDataSystem.load_avg[0] = pSystem->load_avg[0];
m_packetDataSystem.load_avg[1] = pSystem->load_avg[1];
m_packetDataSystem.load_avg[2] = pSystem->load_avg[2];
m_packetDataSystem.memory_total = pSystem->memory_total;
m_packetDataSystem.memory_free = pSystem->memory_free;
m_packetDataSystem.memory_usage = pSystem->memory_usage;
m_packetDataSystem.swap_total = pSystem->swap_total;
m_packetDataSystem.swap_used = pSystem->swap_used;
m_packetDataSystem.swap_usage = pSystem->swap_usage;
m_packetDataSystem.storage_total = pSystem->storage_total;
m_packetDataSystem.storage_avail = pSystem->storage_avail;
m_packetDataSystem.storage_max_usage = pSystem->storage_max_usage;
m_packetDataSystem.disk_max_queue = pSystem->disk_max_queue;
m_packetDataSystem.disk_max_busy = pSystem->disk_max_busy;
m_packetDataSystem.network_packet_in = pSystem->network_packet_in;
m_packetDataSystem.network_packet_out = pSystem->network_packet_out;
m_packetDataSystem.network_traffic_in = pSystem->network_traffic_in;
m_packetDataSystem.network_traffic_out = pSystem->network_traffic_out;
m_packetDataSystem.tcp_total = pSystem->tcp_total;
m_packetDataSystem.tcp_80 = pSystem->tcp_80;
m_packetDataSystem.tcp_80_establish = pSystem->tcp_80_establish;
m_uPacketDataLen = sizeof( m_packetDataSystem );
// system 수집 정보 전송을 위한 Packet Header 설정.
m_packetHeader.stx = HEADER_STX_CODE;
m_packetHeader.type = HEADER_TYPE_REQUEST;
m_packetHeader.command[0] = COMMAND_TRANSFER_SYSTEM;
m_packetHeader.data_length = htonl( m_uPacketDataLen );
m_packetHeader.protocol_version = PROTOCOL_VERSION_SYSTEM;
// Packet Header 정보 전송
if( WriteN( &m_packetHeader, m_iPacketHeaderLen ) != m_iPacketHeaderLen )
{
LOG( LERR, "system info send fail to rc_mond. " );
// send 실패시... socket close 하여 다음 전송시 새로 생성되도록 한다.
Close();
return false;
}
else
{
// Data 부분 전송
WriteN( &m_packetDataSystem, m_uPacketDataLen );
}
_LOG( LINF, "[RCTS send system] body[%u] mem_usage[%d] storage_avail[%ju] traffic_out[%ju] tcp80_est[%d]"
, m_uPacketDataLen
, m_packetDataSystem.memory_usage
, m_packetDataSystem.storage_avail
, m_packetDataSystem.network_traffic_out
, m_packetDataSystem.tcp_80_establish );
return true;
}
// RCTS 로 서비스 상태 정보를 전송한다.
bool CRctsSocket::SendServiceStatus( std::string & strHostname, const struct ServiceStatus * pService, int & iStorageMaxUsage )
{
// Socket 이 유효, 연결되어 있는지 확인.
if( IsValidSocket() == false )
{
// RCTS 에 연결되지 않은 경우....
// - RCTS 와 연결 시도.
if( Connect( m_strServer, m_uPort ) == false )
{
LOG( LERR, "rcts connect fail. rcts[%s][%u]", m_strServer.c_str(), m_uPort );
Close();
return false;
}
}
// 각 Packet 전송 관련 구조체 초기화.
memset( &m_packetHeader, 0x00, sizeof( struct PacketHeader ) );
memset( &m_packetDataService, 0x00, sizeof( struct PacketDataService ) );
// 서비스 상태 정보 전송을 위한 Packet Data 구조체 설정.
strcpy( m_packetDataService.rcid, m_strRcId.c_str() );
strcpy( m_packetDataService.hostname, strHostname.c_str() );
m_packetDataService.service_stat = pService->stat;
m_packetDataService.storage_max_usage = iStorageMaxUsage;
m_uPacketDataLen = sizeof( m_packetDataService );
// 서비스 상태 정보 전송을 위한 Packet Header 설정.
m_packetHeader.stx = HEADER_STX_CODE;
m_packetHeader.type = HEADER_TYPE_REQUEST;
m_packetHeader.command[0] = COMMAND_TRANSFER_SERVICE;
m_packetHeader.data_length = htonl( m_uPacketDataLen );
m_packetHeader.protocol_version = PROTOCOL_VERSION_SERVICE;
// Packet Header 정보 전송
if( WriteN( &m_packetHeader, m_iPacketHeaderLen ) != m_iPacketHeaderLen )
{
LOG( LERR, "service status send fail to rc_mond. " );
// send 실패시... socket close 하여 다음 전송시 새로 생성되도록 한다.
Close();
return false;
}
else
{
// Data 부분 전송
WriteN( &m_packetDataService, m_uPacketDataLen );
}
_LOG( LINF, "[RCTS send service] hostname[%s] service stat[%d] max_usage[%d]"
, m_packetDataService.hostname
, m_packetDataService.service_stat
, m_packetDataService.storage_max_usage );
return true;
}
+83
View File
@@ -0,0 +1,83 @@
/****************************************************************************
RCTS socket class
-----------------------------------------
begin : 2015/05/14
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __RCTS_SOCKET_H__
#define __RCTS_SOCKET_H__
#include "BaseSocket.h"
#include "ShmDefine.h"
#include "ProtocolDefine.h"
#include <unistd.h>
#include <string>
// CRctsSocket
// 본 클래스는 RCTS 와의 TCP socket 통신을 관리하고....
// Data 를 RCTS 로 전송하는 역활을 수행한다.
class CRctsSocket: public CBaseSocket
{
public:
// 생성자
// - 객체 생성시.. 접속 대상 RCTS 정보 및 통신시 사용할 RC ID 정보를 전달한다.
CRctsSocket();
// 소멸자
~CRctsSocket();
// 객체 초기화
// - false : 전달된 인자값 오류시
bool Init( const char * szServer, unsigned int uPort, const char * szRcId );
// RCTS 로 수집된 시스템 정보를 전송한다.
bool SendSystemInfo( const struct SystemInfo * pSystem );
// RCTS 로 서비스 상태 정보를 전송한다.
bool SendServiceStatus( std::string & strHostname, const struct ServiceStatus * pService, int & iStorageMaxUsage );
private:
// RCTS Server 정보
std::string m_strServer;
unsigned int m_uPort;
// 통신 관련 RC ID 정보
std::string m_strRcId;
// packet header 멤버 변수.
struct PacketHeader m_packetHeader;
// packet header 크기를 저장하기 위한 상수
const int m_iPacketHeaderLen;
// system 수집 정보 전송을 위한 data 구조체
struct PacketDataSystem m_packetDataSystem;
// service 상태 정보 전송을 위한 data 구조체
struct PacketDataService m_packetDataService;
// 전송할 Data 크기 정보를 저장할 멤버변수.
unsigned int m_uPacketDataLen;
};
#endif /* __RCTS_SOCKET_H__ */
File diff suppressed because it is too large Load Diff
+171
View File
@@ -0,0 +1,171 @@
/****************************************************************************
Service status check & shared memory set class
-----------------------------------------
begin : 2015/05/06
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __SERVICE_CHECK_H__
#define __SERVICE_CHECK_H__
#include "FhsShm.h"
#include "StorageInfo.h"
#include <string>
#include <vector>
// NIC 에 할당된 IP Type (AF_INET or AF_INET6) , IP 주소 정보를 저장하기 위한 구조체.
struct IpAddressInfo {
int type; // AF_INET or AF_INET6
std::string ip; // ip address
};
// ZFS 상태 정보 열거형 변수
typedef enum TypeZfsStatus {
ZFS_ERROR = -1, // Storage 상태 정보 수집 실패, FAULTED, OFFLINE, UNAVAIL 상태인 경우 -> Service Disable 처리 필요
ZFS_ONLINE, // 정상 상태 또는 ZFS 아닌 경우
ZFS_READONLY // DEGRADED 상태 -> Read only 처리 필요
} ZfsStatus;
// Service 상태 정보를 Check 하고... 그 결과를 공유메모리에 저장처리 하기 위한 class
class CServiceCheck
{
public:
// 생성자
CServiceCheck( CFhsShm * pFhsShm );
// 소멸자
~CServiceCheck();
// 초기화 함수
// - 초기화 작업 실패시 false 반환함.
bool Init( std::vector<std::string> vecNic, std::vector<std::string> vecDns, unsigned int uFimngdPort );
// Service 상태 Check 시작..
// - 오류 발생시.. false 반환.
bool Check();
private: // Service Check 관련 멤버 변수
// 공유메모리 interface 객체에 대한 포인터.
// - 공유메모리에 Data Set, Get 을 담당
CFhsShm * m_pFhsShm;
// Service NIC name 정보 저장.
std::vector<std::string> m_vecServiceNic;
// DNS resolve check 대상 dns name
// - 설정값이 존재하지 않을 수 있음
std::vector<std::string> m_vecCheckDns;
// fimngd check 관련 port 번호
unsigned int m_uCheckFimngdPort;
// fimngd 접속 실패 관련 count 정보를 저장하기 위한 변수.
// - 최초 기동시 -1 로 설정 처리.
int m_iFimngdDeadCount;
// Service NIC 에 할당된 IP 정보를 저장하기 위한 변수.
std::vector<struct IpAddressInfo> m_vecServiceIp;
// Storage 의 ZFS 여부 정보를 추출, 판단 처리할 Stroage Info 객체
CStorageInfo m_storageInfo;
struct timespec m_timeStart; // service check 소요시간 측정을 위한 멤버변수
struct timespec m_timeEnd; // service check 소요시간 측정을 위한 멤버변수
double m_dElapsedTime; // service check 소요시간 측정을 위한 멤버변수
private: // Check 관련 내부 함수
// fsck 프로세스 동작 여부 체크.
// - true : 해당 프로세스 동작 중
// - false : 동작 안함.
bool IsFsckRun();
// 멤버 변수 m_vecSvcNic 에 저장된 서비스 NIC 에 대한 상태 체크 수행
// - true : 모두 정상
// - false : 오류 발생 또는 1개라도 active 상태가 아닌 경우.
bool IsAliveServiceNic();
// 멤버 변수 m_vecSvcNic 에 저장된 서비스 NIC 에 대한 IP 정보를 추출하여 멤버 변수 m_vecServiceIp 에 저장
// - true : 추출 성공시.
// - false : 추출된 service IP 정보가 존재하지 않는 경우. ( 오류 발생 등으로 인해 추출 불가시 포함)
bool GetServiceIp();
// Apache 의 80 port 에 접속 가능한지 check.
// return true : 정상
// false : 추출된 서비스 IP 로 접속 테스트 수행시.. 1개라도 접속이 실패한 경우(Timeout 발생 포함)
// - 2015-05-11 현재 opendav 가 80 port listen 처리시 IPv4 에 대해서만 Listen 처리하므로...
// - 추출된 서비스 IP 중 IPv4 에 대해서만 테스트를 수행한다.
bool IsAliveApache();
// DNS resolve 체크 수행.
// - 장비의 hostname 을 기준으로 m_vecCheckDns 에 정의된 DNS 서버에 resolve 질의
// - resolve 결과가.. m_vecServiceIp 에 존재하는 경우.. true.
// - 만약 resolve 결과가 m_vecServiceIp 에 존재하지 않는 경우...
// -- 해당 domain 이 다른 장비를 가르키는 것일 수 있으므로.. fasle 반환.
bool IsResolveDns();
// Default DNS resolve check
// - 장비의 hostname 을 기준으로 시스템에 설정된 기본 DNS 서버에 resolve 질의
// - resolve 결과가.. m_vecServiceIp 에 존재하는 경우.. true.
// - 위의 DNS check 관련 설정 정보가 없거나.. Alive DNS 가 없는 경우 처리를 수행하기 위한 보조 방법임
bool IsResolveDefaultDns();
// std 상에 trim 함수가 없어서 직접 구현. 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
// @return void
void Trim( std::string & str );
// FHS 의 fimngd 프로세스 동작 여부 check.
// - init() 에서 설정된 m_uCheckFimngdPort 정보와 추출된 서비스 IP 를 이용하여 TCP 접속 테스트 수행.
// @return true 접속 성공시
// false 접속 실패 또는 오류 발생시.
bool IsAliveFimngd();
// Storage Write/Read 테스트 결과가 정상인지 Check
// - Storage 저장 공간에 대한 file write / read 테스트가 worker 프로세스에 의해 주기적으로 수행
// - 만약 test 실패 발생시 공유 메모리 상의 관련 값이 -1 로 설정됨
// - 만약 test 중 hang 발생시 공유 메모리 상의 값을 확인하여 timeout 여부 판단 필요.
// @return true storage check 정상인 경우
// false storage check 실패 또는 timeout 상황인 경우
bool IsNormalStatusStorageCheck();
// System Collecotr 관련 Worker 프로세스가 정상 동작하는지 Check
// - system 상태 정보 수집을 위한 system collector worker 프로세스는 주기적으로 수행되며
// - 수집 시작시간, 수집된 정보를 공유메모리에 저장
// - 만약 여러 요인에 의해 해당 worker 프로세스가 hang 상황인 경우 서비스 상태를 disable 로 변경 처리해야 함
// - 이를 판단하기 위한 함수로 공유메모리 정보를 이용하여 timeout 판단함.
// @return true 정상인 경우
// false timeout 상황인 경우
bool IsNormalStatusSystemCollect();
// ZFS 상태 관련 정보 추출하여 정상인지 Check
ZfsStatus GetZfsStatus();
};
#endif /* __SERVICE_CHECK_H__ */
+222
View File
@@ -0,0 +1,222 @@
/***************************************************************************
csagentd shared memory template header
-----------------------------------------
begin : 2015/04/13
copyright : (C) 2005 Solbox Inc.
author : Storage Dev Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
// 본 코드는 시스템 공유메모리 생성, 접근, 해제, 삭제 처리를 수행하기 위한 코드로서
// template 코드 방식으로 구성
#ifndef __SHM_CONTROL_H__
#define __SHM_CONTROL_H__
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
/*----------- MODE Flag ---------------
SHM_R 0400 read by user
SHM_W 0200 write by user
SHM_R >> 3 0040 read by group
SHM_W >> 3 0020 write by group
SHM_R >> 6 0004 read by others
SHM_W >> 6 0002 write by others
-------------------------------------*/
////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief ShmControl 공유메모리 관련 Template Class
template <typename T>
class CShmControl
{
public:
/// @brief 생성자
CShmControl();
/// @brief 소멸자
~CShmControl();
/// @brief 공유메모리 생성, 접근 또는 기존 공유메모리 접근.
/// @param iShmKey 공유메모리 접근을 위한 키
/// @param iSize 접근하고자 하는 공유메모리의 크기
/// @param iSize 공유메모리 생성및 접근시 권한
/// @return return true or false
bool Create( key_t iShmKey, size_t iSize, int iModeFlag = SHM_R | SHM_W );
/// @brief 기존 공유메모리 접근.
/// @param iShmKey 공유메모리 접근을 위한 키
/// @param iSize 접근하고자 하는 공유메모리의 크기
/// @param iSize 공유메모리 접근시 권한
/// @return return true or false
bool Attach( key_t iShmKey, size_t iSize, int iModeFlag = SHM_R | SHM_W );
/// @brief 기존 접근한 공유메모리와의 연결을 해제
/// @return return true or false
bool Detach( void );
/// @brief 기존 접근한 공유메모리와의 연결을 해제 및 삭제
/// @return return true or false
bool Remove( void );
/// @brief 공유메모리에 대한 포인터를 반환
/// @return 생성 및 접근한 공유메모리에 대한 포인터 또는 오류 발생시 NULL
T * GetShmPtr(void) const { return m_pShm; }
/// @brief 접근한 공유메모리의 ID 값을 반환
/// @return 생성 및 접근한 공유메모리 ID Value에 대한 참조.
int GetShmId(void) const { return m_iShmId; }
private:
///< m_pShm 공유메모리에 대한 포인터
T * m_pShm;
///< m_pShmId 접근한 공유메모리의 ID Value
int m_iShmId;
};
////////////////////////////////////////////////////////////////////////////////////////////////
// 기본 멤버변수 초기화.
template < typename T >
inline CShmControl<T>::CShmControl()
: m_pShm(NULL)
, m_iShmId(-1)
{
}
template < typename T >
inline CShmControl<T>::~CShmControl()
{
// 생성된 공유메모리를 종료시 다른 프로세스들이 사용한다면.. 맘대로 삭제해서는 안되며...
// 이럴 경우 detach 처리만 해야 한다.
// Detach();
// 이와 반대로.. 다른 프로세스에서 더이상 해당 공유메모리를 사용하지 않을 경우.. remove 처리한다.
Remove();
}
// 해당 공유메모리를 생성한다. 만약 기존에 생성된 것이 있다면 그놈을 사용하도록 한다.
template < typename T >
inline bool CShmControl<T>::Create( key_t iShmKey, size_t iSize, int iModeFlag )
{
// 우선 공유 메모리를 생성해 봅니다.
m_iShmId = shmget( iShmKey, iSize, IPC_CREAT | IPC_EXCL | iModeFlag );
// 생성에 실패한 경우.
if( m_iShmId == -1)
{
// 이미 기존에 생성된 놈이 있는지 확인해 봅시다.
return Attach( iShmKey, iSize, iModeFlag);
}
// 생성에 성공한 경우.
else
{
// 생성된 공유 메모리의 포인터를 받아옵니다.
m_pShm = (T *)shmat( m_iShmId, 0, 0 );
// 받아온 공유 메모리 포인터 값이 정확하면
if( reinterpret_cast<long>(m_pShm) != -1)
{
// 원래 시스템에서 생성시 자동으로 초기화됨 => 그렇지만 새로이 생성을 하였으므로 확인 사살 초기화 ^^
memset( m_pShm, 0x00, iSize);
return true;
}
// 받아온 공유 메모리 포인터를 가져오는데 실패한 경우
// => 만든놈이 삭제해 버립시다.
else
{
Remove();
return false;
}
}
}
// 기존에 생성된 것 공유 메모리에 접근하기 위해서 사용한다..
// 키값과 크기값을 정확히 알고 있어야 ( 혹시 다른데서 사용하는 놈으로 붙을까봐 ) 접근할 수 있도록 한다.
template < typename T >
inline bool CShmControl<T>::Attach( key_t iShmKey, size_t iSize, int iModeFlag )
{
// 기존 연결은 해제 시켜 버린다. => 그냥 놓은 상태에서 다시 접속할 경우 메모리 사용량이 올라감.
Detach();
m_iShmId = shmget( iShmKey, iSize, iModeFlag);
if( m_iShmId == -1 )
return false;
else
{
// 우선 기존에 있는 것과 크기가 동일한지 검사한다.
struct shmid_ds shmInfo;
memset(&shmInfo, 0x00, sizeof(struct shmid_ds));
shmctl( m_iShmId, IPC_STAT, &shmInfo);
// shm_segsz 정의 관련 참고사항
// - FreeBSD 6.X : int type으로 정의되어.. 컴파일시 waring 발생
// - FreeBSD 10.X : size_t type
// - CentOS 6.4 : size_t type
if( shmInfo.shm_segsz != iSize)
return false;
else
{
m_pShm = (T *)shmat( m_iShmId, 0, 0 );
// reinterpret_cast 을 사용한 것은 운영체제마다 포인터 형이 다를수가 있다고 참고한 라이브러리에 나와있어서 함.
if( reinterpret_cast<long>(m_pShm) == -1)
return false;
else
return true;
}
}
}
// 접근한 공유메모리로 부터 분리시킨다. ( 접근시 설정된 멤버 변수 이용)
template < typename T >
inline bool CShmControl<T>::Detach()
{
if( m_pShm > 0 )
{
if( shmdt( m_pShm) == 0)
{
m_iShmId = -1;
m_pShm = NULL;
return true;
}
else
return false;
}
else
return true;
}
// 공유메모리를 삭제한다. 이 작업을 하기 위해서는 먼저 공유 메모리를 생성 또는 접근을 해야하며
// 이때 설정된 멤버 변수를 가지고 삭제 작업을 수행한다.
// 공유 메모리는 여러 Process 들이 사용가능하기 때문에 삭제시 신중을 기할 것.
template < typename T >
inline bool CShmControl<T>::Remove()
{
if( m_iShmId > -1)
{
if( shmctl( m_iShmId, IPC_RMID, NULL) == -1)
return false;
else
{
m_iShmId = -1;
m_pShm = NULL;
return true;
}
}
return true;
}
#endif /* __SHM_CONTROL_H__ */
+145
View File
@@ -0,0 +1,145 @@
/****************************************************************************
Shared memory define for csagentd
-----------------------------------------
begin : 2015/04/20
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __SHM_DEFINE_H__
#define __SHM_DEFINE_H__
#include <unistd.h>
#include <sys/types.h>
// hostname 최대 길이.
#define HOST_NAME_MAX_LENGTH 63
// Service 상태 코드 정의
// TODO : 서비스 상태 코드 추가시 다음 작업 수행해야 함.
// - SERVICE_STAT_MAX 값을 최대 값으로 변경 처리.
// - CFhsShm 생성자에 화면 출력용 문자열 추가 및 변경 .
#define SERVICE_STAT_OK 0 // 정상 상태
#define SERVICE_STAT_OUT 1 // 수동 중지 상태
#define SERVICE_STAT_DISABLE 2 // 서비스 불가 상태
#define SERVICE_STAT_RONLY 3 // Read Only 상태
#define SERVICE_STAT_MAX 3 // Service 상태 코드 범위 Check 를 위한 값
// 독립 worker 프로세스가 storage 에 대한 write/read 테스트 수행하여 성공시 공유메모리에 시간 정보 기록
// 지정된 시간 동안 테스트를 성공하지 못하는 경우 Hang 으로 판단하여 서비스 disable 처리를 위한
// timeout 값 (단위 sec)
#define TIMEOUT_STORAGE_CHECK 30
// 독립 Worker 프로세스인 system collector 는 정보 수집 시작 시간을 공유메모리에 기록
// 만약 시스템 Hang 상황으로 system 관련 정보 추출 함수 block 발생시
// 이에 대한 timeout 을 판단하여 서비스 disable 상태로 변경하기 위한 timeout 값 (단위 sec)
#define TIMEOUT_SYSTEM_COLLECT 40
// 독립 Worker 프로세스인 service check 는 정보 수집 시작 시간을 공유메모리에 기록
// 만약 시스템 Hang 상황으로 service check 관련 함수 block 발생시
// 이에 대한 timeout 을 판단하여 서비스 disable 상태로 변경하기 위한 timeout 값 (단위 sec)
#define TIMEOUT_SERVICE_CHECK 15
// 2018-02-07 NEW huibong disk busy 상황시 Read Only 상태로 변경 처리를 위한 기준값 선언 (#31701)
// - Disk Busy 상황시 응답 지연 발생 또는 장비 Hang 상황인 것으로 판단됨
// - 2018-01 SK 에서 발생한 응답 지연으로 인한 SolProxy 오류 확인 결과...
// - queue 가 7 이상 & disk busy 50 % 이상인 경우 응답 지연 발생됨
// - 따라서 이에 대한 기준값을 정의하고.. 해당 값 이상인 경우 Read Only 상태로 변경할 수 있도록 한다.
#define DISK_BUSY_MIN_QUEUE_COUNT 7 // disk max queue 가 해당 값 이상인 경우 Disk Busy 상황으로 판단
#define DISK_BUSY_MIN_BUSY_PERCENT 50.0 // disk maxy busy 값이 해당 값 이상인 경우 Disk Busy 상황으로 판단
#ifdef __cplusplus
extern "C" {
#endif
// System info
struct SystemInfo {
char hostname[HOST_NAME_MAX_LENGTH + 1]; // hostname, 최대 63자까지만 허용.
double load_avg[3]; // load average.
uint64_t memory_total; // Total memory size (byte 단위)
uint64_t memory_free; // Free memory size (byte 단위)
int memory_usage; // memory 사용률 (%)
uint64_t swap_total; // Total swap size (byte 단위)
uint64_t swap_used; // Used swap size (byte 단위)
int swap_usage; // swap 사용률 (%)
uint64_t storage_total; // Total Storage size (byte 단위)
uint64_t storage_avail; // Available Storage size (byte 단위)
int storage_max_usage; // Storage 중 최대 사용률 (%)
uint64_t disk_max_queue; // Disk 상태 정보 중 Max Queue Length
double disk_max_busy; // Disk 상태 정보 중 Max busy(%)
uint64_t network_packet_in; // Network inbound packet 평균 count (count/sec)
uint64_t network_packet_out; // Network outbound packet 평균 count (count/sec)
uint64_t network_traffic_in; // Network inbound 평균 traffic (Byte/sec)
uint64_t network_traffic_out; // Network outbound 평균 traffic (Byte/sec)
unsigned int tcp_total; // TCP 세션 total count
unsigned int tcp_80; // TCP 세션 중 local 80 port 를 사용하는 세션 count
unsigned int tcp_80_establish; // TCP 세션 중 local 80 port 를 사용하고.. ESTABLISH 상태인 세션 count
};
// Service status
struct ServiceStatus {
int stat; // Service stat code.
};
// Shared momory
struct FhsInfo {
// 2018-01-30 NEW huibong 마지막 system 정보 추출 시작 시간 (#31701)
// - 추출 관련 hang 상황 발생시 expire 처리를 위한 시간값
// - 시간 동기화 영향을 없애기 위해 clock_gettime(CLOCK_MONOTONIC) 을 통해 추출된 sec 정보임
time_t time_system_check_start_sec;
struct SystemInfo system;
// 2018-01-30 NEW huibong 마지막 service check 시작 시간 (#31701)
// - service check 관련 hang 상황 발생시 expire 처리를 위한 시간값
// - 시간 동기화 영향을 없애기 위해 clock_gettime(CLOCK_MONOTONIC) 을 통해 추출된 sec 정보임
time_t time_service_check_start_sec;
struct ServiceStatus service;
// 2018-01-30 NEW huibong 신규로 추가한 Storage check 관련 last check 성공 시간 (#31701)
// - storage check 실패, hang 상황 발생시 expire 처리를 위한 시간값
// - 시간 동기화 영향을 없애기 위해 clock_gettime(CLOCK_MONOTONIC) 을 통해 추출된 sec 정보임
// - 0 : 최초 공유메모리 초기화시
// - -1 : storage check 실패 발생시
// - 그외 : storage check 를 마지막으로 성공한 시간 sec 정보 -> storage check hang 발생 가능하므로 expire 처리 필요.
time_t time_storage_check_ok_sec;
};
#ifdef __cplusplus
}
#endif
#endif /* __SHM_DEFINE_H__ */
+264
View File
@@ -0,0 +1,264 @@
#include "StorageCheck.h"
#include "Logger.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
// Storage Write / Read test 를 수행할 파일명 정의
#define CHECK_FILE_NAME PROG_NAME"_check.txt"
// 생성자
CStorageCheck::CStorageCheck( CFhsShm * pFhsShm )
: m_pFhsShm( pFhsShm )
{
}
// 소멸자
CStorageCheck::~CStorageCheck()
{
}
// 초기화 함수
// - szRoot : Write/Read 테스트를 수행할 mount 최상위 경로 정보.
bool CStorageCheck::Init( const char * szRoot )
{
// 공유메모리 접근 포인터가 유효하지 않은 경우
if( m_pFhsShm == NULL )
return false;
// 최초 storage 정보 추출을 수행해서 문제 없는지 체크
if( m_storageInfo.Init( szRoot ) == false )
{
LOG( LERR, "[Storage] storage info class init failed." );
return false;
}
// 소요시간 측정 관련 변수 초기화
memset( &m_timeTotalStart, 0x00, sizeof( struct timespec ) );
memset( &m_timeTotalEnd, 0x00, sizeof( struct timespec ) );
m_dElapsedTotalTime = 0.0;
memset( &m_timeDiskStart, 0x00, sizeof( struct timespec ) );
memset( &m_timeDiskEnd, 0x00, sizeof( struct timespec ) );
m_dElapsedDiskTime = 0.0;
return true;
}
// Storage 상태 Check 시작
// - szRoot : Write/Read 테스트를 수행할 mount 최상위 경로 정보.
// - 오류 발생시 false 반환
// - Hang 발생 가능하므로 본 함수 호출부에서 timeout 처리 필요
bool CStorageCheck::Check( const char * szRoot )
{
// Storage info 객체 초기화
// - 전달받은 최상위 경로값 오류시
// - 정보 추출 실패 또는 szRoot 에 맞는 경로 정보 추출 실패시 false 반환
// - mount 정보가 중간에 변경될 수 있으므로.. Check 수행시마다.. Storage 정보 추출하도록 한다.
if( m_storageInfo.Init( szRoot ) == false )
{
LOG( LERR, "[Storage] storage info class init failed.");
return false;
}
// write, read check 대상 경로 저장을 위한 vector
// - 전달받은 root 경로 정보를 이용하여 테스트 수행할 경로 정보 추출 저장
std::vector< std::string > vecCheckPath;
if( m_storageInfo.GetStoragePath( vecCheckPath ) == false )
{
// storage 정보가 유효하지 않은 경우
LOG( LERR, "[Storage] storage info not valid.");
return false;
}
// 실제 추출된 경로에 대한 파일 write, read 테스트 수행
// 변수 선언 & 초기화
std::vector< std::string >::iterator it;
std::string szFullFileName;
FILE * pFile = NULL;
int errorNum;
char szErrorBuffer[1024];
char szDataBuffer[1024];
char szReadBuffer[1024];
// write, read, unlink 작업 전 잠시 대기를 위한 sleep 설정
struct timespec sleepInterval;
sleepInterval.tv_sec = 0;
sleepInterval.tv_nsec = 200000000; // 0.2 sec
// check start time
clock_gettime( CLOCK_MONOTONIC, &m_timeTotalStart );
// 파일 저장 Data 생성
snprintf( szDataBuffer, sizeof( szDataBuffer ) - 1, "%ld.%ld", m_timeTotalStart.tv_sec, m_timeTotalStart.tv_nsec );
_LOG( LINF, "[Storage] check start with data [%s]", szDataBuffer );
// 설정된 경로별 파일 write, read 테스트 수행
for( it = vecCheckPath.begin(); it < vecCheckPath.end(); it++ )
{
// check start time
clock_gettime( CLOCK_MONOTONIC, &m_timeDiskStart );
// 파일명 조립
szFullFileName = *it + "/" + CHECK_FILE_NAME;
// 파일 open
pFile = fopen( szFullFileName.c_str(), "w" );
if( pFile == NULL )
{
// 파일 open 실패시
errorNum = errno;
snprintf( szErrorBuffer, sizeof( szErrorBuffer ) - 1, "File open failed to write.[%s] [%d][%s]", szFullFileName.c_str(), errorNum, strerror( errorNum ) );
LOG( LERR, "[Storage] %s", szErrorBuffer );
return false;
}
// 파일 write
// - fwrite 가 지정된 크기만큼 write 실패한 경우.. write error 발생
if( fwrite( szDataBuffer, 1, strlen( szDataBuffer ), pFile ) != strlen( szDataBuffer ) )
{
// write 실패시
errorNum = errno;
snprintf( szErrorBuffer, sizeof( szErrorBuffer ) - 1, "File write failed.[%s] [%d][%s]", szFullFileName.c_str(), errorNum, strerror( errorNum ) );
fclose( pFile );
pFile = NULL;
LOG( LERR, "[Storage] %s", szErrorBuffer );
return false;
}
// buffer flush 처리 - I/O 오류 발생으로 실패 발생 가능
if( fflush( pFile ) != 0 )
{
// flush 처리 실패시
errorNum = errno;
snprintf( szErrorBuffer, sizeof( szErrorBuffer ) - 1, "File write flush failed.[%s] [%d][%s]", szFullFileName.c_str(), errorNum, strerror( errorNum ) );
fclose( pFile );
pFile = NULL;
LOG( LERR, "[Storage] %s", szErrorBuffer );
return false;
}
//_LOG( LINF, "[Storage] %s check file write & flush ok. [%s]", szFullFileName.c_str(), tempBuffer );
// 파일 close
if( pFile != NULL )
{
fclose( pFile );
pFile = NULL;
}
// 잠시 대기
nanosleep( &sleepInterval, NULL );
// 파일 open
pFile = fopen( szFullFileName.c_str(), "r" );
if( pFile == NULL )
{
// 파일 open 실패시
errorNum = errno;
snprintf( szErrorBuffer, sizeof( szErrorBuffer ) - 1, "File open failed to read.[%s] [%d][%s]", szFullFileName.c_str(), errorNum, strerror( errorNum ) );
LOG( LERR, "[Storage] %s", szErrorBuffer );
return false;
}
// 파일 read
// - 파일 읽은 크기가 실제 저장한 크기보다 작은 경우
// - end of file 인지 read error 인지 체크해야 하며 (man page)
// - read buffer 는 작업 전 초기화하지 않으면.. garbage data 가 저장되어 있어 문제됨.
memset( szReadBuffer, 0x00, sizeof( szReadBuffer ) );
if( fread( szReadBuffer, 1, sizeof( szReadBuffer ), pFile ) != strlen( szDataBuffer ) )
{
// read 실패시
// - end of file : 실제 저장한 data 와 크기가 안 맞으므로.. 이거는 오류로 본다
// - read 실패 : read 오류로 처리
if( feof( pFile ) != 0 ) // end of file 인 경우
{
snprintf( szErrorBuffer, sizeof( szErrorBuffer ) - 1, "File read size not match[%s] src[%s] file[%s]"
, szFullFileName.c_str(), szDataBuffer, szReadBuffer );
}
else
{
errorNum = errno;
snprintf( szErrorBuffer, sizeof( szErrorBuffer ) - 1, "File read failed.[%s] [%d][%s]", szFullFileName.c_str(), errorNum, strerror( errorNum ) );
}
fclose( pFile );
pFile = NULL;
LOG( LERR, "[Storage] %s", szErrorBuffer );
return false;
}
// read data check
if( strcmp( szDataBuffer, szReadBuffer ) != 0 )
{
snprintf( szErrorBuffer, sizeof( szErrorBuffer ) - 1, "File read data not match[%s]. src[%s] file[%s]"
, szFullFileName.c_str(), szDataBuffer, szReadBuffer );
fclose( pFile );
pFile = NULL;
LOG( LERR, "[Storage] %s", szErrorBuffer );
return false;
}
// 파일 close
if( pFile != NULL )
{
fclose( pFile );
pFile = NULL;
}
// 잠시 대기
nanosleep( &sleepInterval, NULL );
// 파일 unlink
if( unlink( szFullFileName.c_str() ) != 0 )
{
// unlink 실패시
errorNum = errno;
snprintf( szErrorBuffer, sizeof( szErrorBuffer ) - 1, "File unlink failed.[%s] [%d][%s]", szFullFileName.c_str(), errorNum, strerror( errorNum ) );
LOG( LERR, "[Storage] %s", szErrorBuffer );
return false;
}
// check end time
clock_gettime( CLOCK_MONOTONIC, &m_timeDiskEnd );
// disk 당 작업 소요 시간 계산
m_dElapsedDiskTime = m_timeDiskEnd.tv_sec - m_timeDiskStart.tv_sec;
m_dElapsedDiskTime += ( m_timeDiskEnd.tv_nsec - m_timeDiskStart.tv_nsec ) * 1e-9;
_LOG( LINF, "[Storage] %s check ok. elapsed time: %.3lf sec.", it->c_str(), m_dElapsedDiskTime );
}
// check end time
clock_gettime( CLOCK_MONOTONIC, &m_timeTotalEnd );
// 작업 소요 시간 계산
m_dElapsedTotalTime = m_timeTotalEnd.tv_sec - m_timeTotalStart.tv_sec;
m_dElapsedTotalTime += ( m_timeTotalEnd.tv_nsec - m_timeTotalStart.tv_nsec ) * 1e-9;
_LOG( LINF, "[Storage] check end. total elapsed time: %.3lf sec.", m_dElapsedTotalTime );
return true;
}
+74
View File
@@ -0,0 +1,74 @@
/****************************************************************************
Storage write / read check class
-----------------------------------------
begin : 2018/01/29
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __STORAGE_CHECK_H__
#define __STORAGE_CHECK_H__
#include "FhsShm.h"
#include "StorageInfo.h"
#include <unistd.h>
#include <string>
#include <vector>
// Storage 관련 임시 file write, read 테스트를 수행하기 위한 class
class CStorageCheck
{
public:
// 생성자
CStorageCheck( CFhsShm * pFhsShm );
// 소멸자
~CStorageCheck();
public: // Storage Write, Read 테스트 관련 함수
// 초기화 함수
bool Init( const char * szRoot );
// Storage 상태 Check 시작
// - 인자값으로 최상위 storage root path 정보 입력 (check 시마다 정보 추출하여 check 수행하도록 하기 위함)
// - 오류 발생시 false 반환
// - Hang 발생 가능하므로 본 함수 호출부에서 timeout 처리 필요
bool Check( const char * szRoot );
private: // 멤버 변수
// 공유메모리 interface 객체에 대한 포인터.
// - 공유메모리에 Data Set, Get 을 담당
CFhsShm * m_pFhsShm;
// Storage 관련 정보 추출을 담당할 객체.
CStorageInfo m_storageInfo;
struct timespec m_timeTotalStart; // total 소요시간 측정을 위한 멤버변수
struct timespec m_timeTotalEnd; // total 소요시간 측정을 위한 멤버변수
double m_dElapsedTotalTime; // total 소요시간 측정을 위한 멤버변수
struct timespec m_timeDiskStart; // 각 disk 단위 소요시간 측정을 위한 멤버변수
struct timespec m_timeDiskEnd; // 각 disk 단위 소요시간 측정을 위한 멤버변수
double m_dElapsedDiskTime; // 각 disk 단위 소요시간 측정을 위한 멤버변수
private: // 처리 관련 내부 함수
};
#endif /* __STORAGE_CHECK_H__ */
+266
View File
@@ -0,0 +1,266 @@
#include "StorageInfo.h"
#include "Logger.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <math.h>
// 생성자
CStorageInfo::CStorageInfo()
{
// 멤버변수 초기화
m_vecStorageInfo.clear();
}
// 소멸자
CStorageInfo::~CStorageInfo()
{
m_vecStorageInfo.clear();
}
// 전달받은 경로로부터.. 상위 Path 정보를 추출하여 전달한다.
// 오류 발생시 [out] 값인 strUpperPath 가 empty 된다.
void CStorageInfo::GetUpperPath( const std::string & strSourcePath, std::string & strUpperPath )
{
// 인자로 전달되는 strSourcePath 끝에.. '/' 가 이미 제거되었다고 판단하고 작업을 수행한다.
std::string::size_type pos = strSourcePath.rfind( '/' );
if( pos == std::string::npos )
{
// 찾지 못한 경우...
// out 값을 empty 처리시킨다.
LOG( LNOT, "upper path not found. source[%s]", strSourcePath.c_str() );
strUpperPath.clear();
return;
}
// 찾은 경우..
strUpperPath = strSourcePath.substr( 0, pos );
// 추출된 경로가... 최상위 '/' 인 경우.. 유효하지 않으므로 오류로 처리한다.
if( strcmp( strUpperPath.c_str(), "/" ) == 0 )
{
LOG( LNOT, "upper path not vaild that root path. [%s]", strUpperPath.c_str() );
strUpperPath.clear();
}
return;
}
// 초기화 함수
// - szRoot : Content 저장 최상위 경로 정보.
bool CStorageInfo::Init( const char * szRoot )
{
// 전달받은 최상위 경로 정보에 대한 Check
if( szRoot == NULL || strlen( szRoot ) <= 0 )
{
LOG( LERR, "storage root path not valid.");
return false;
}
// 추출된 정보 저장을 위한 임시변수
int iMountCount = 0;
struct statfs * pMountBuf = NULL;
std::vector< struct stStorageInfo > vecStorageAll;
std::vector< struct stStorageInfo >::iterator it;
struct stStorageInfo stStorage;
// 추출 정보 저장 및 멤버 변수 초기화
vecStorageAll.clear();
m_vecStorageInfo.clear();
// Mount 정보 추출
// - MNT_WAIT flag 사용시 정확한 정보를 추출, 하지만 block 발생 가능
// - 따라서 항상 정확한 정보를 추출할 필요는 없으며.. block 이 발생하지 않도록
// - MNT_NOWAIT flag 사용한다.
iMountCount = getmntinfo( &pMountBuf, MNT_NOWAIT );
if( iMountCount == 0 )
{
// 정보 추출 실패시 오류 내역 로깅
int errorNum = errno;
LOG( LERR, "Storage info init error. getmntinfo() fail[%d]. [%d][%s]"
, iMountCount, errorNum, strerror( errorNum ) );
return false;
}
// 추출된 mount 관련 모든 정보를 임시 변수에 저장
for( int i = 0; i < iMountCount; i++ )
{
stStorage.strName = pMountBuf[i].f_mntonname;
stStorage.strFsTypeName = pMountBuf[i].f_fstypename;
stStorage.ulUsedByte = ( pMountBuf[i].f_blocks - pMountBuf[i].f_bfree ) * pMountBuf[i].f_bsize;
stStorage.ulAvailableByte = pMountBuf[i].f_bavail * pMountBuf[i].f_bsize;
stStorage.usage = 0;
vecStorageAll.push_back( stStorage );
}
// 전달받은 mount 최상위 경로와 동일한 명칭의 mount 가 존재하는 검사
// - 이럴 경우는 거의 없는데.. 혹시나 해서 기능 탑재함.
for( it = vecStorageAll.begin(); it < vecStorageAll.end(); it++ )
{
if( strcmp( szRoot, it->strName.c_str() ) == 0 )
{
m_vecStorageInfo.push_back( *it );
}
}
// 전달받은 최상위 mount 정보와 동일한 명칭의 mount 가 존재하지 않는 경우..
// - sub path 부분을 제외한 후 다시 장비 Mount 정보와 비교한다.
// - 장비 mount 정보를 찾을 때까지 본 비교를 반복하여 수행한다.
if( m_vecStorageInfo.empty() == true )
{
std::string strPreviousPath = szRoot;
std::string strCurrentPath = szRoot;
do
{
// 수정된 경로 정보만을 가지고 부분 비교를 수행....
for( it = vecStorageAll.begin(); it < vecStorageAll.end(); it++ )
{
// 부분 비교 처리
if( strncmp( strCurrentPath.c_str(), it->strName.c_str(), strlen( strCurrentPath.c_str() ) ) == 0 )
{
m_vecStorageInfo.push_back( *it );
}
}
// 위에서 정보 추출이 실패한 경우..상위 Path 정보를 추출한다. ( /user2/dav_storage, /stg/node0/aa/bb 등으로 설정된 경우를 위해 )
if( m_vecStorageInfo.empty() == true )
{
GetUpperPath( strPreviousPath, strCurrentPath );
if( strCurrentPath.empty() == true )
{
// 상위 path 가 더이상 유효하지 않은 경우.
break;
}
strPreviousPath = strCurrentPath;
}
} while( m_vecStorageInfo.empty() == true );
}
// 임시 vector 에 저장된 내용 초기화
vecStorageAll.clear();
// 최종
if( m_vecStorageInfo.empty() == true )
{
LOG( LERR, "Storage info init error. root path[%s] not found in system mount.", szRoot );
return false;
}
// 추출 성공시
// - Storage 사용률 정보 계산해서 저장해 놓는다.
for( it = m_vecStorageInfo.begin(); it < m_vecStorageInfo.end(); it++ )
{
if( it->ulAvailableByte + it->ulUsedByte == 0 )
it->usage = 100;
else
{
// 사용률은 정수로 구하며... 나머지가 존재할 경우... 올림 처리한다.
it->usage = ( int ) ceil( ( double ) it->ulUsedByte / ( it->ulUsedByte + it->ulAvailableByte ) * 100.0 );
}
}
return true;
}
// 멤버 vector 에 저장된 경로의 Total Size, Total availsize, Max usage 정보를 반환.
bool CStorageInfo::GetStorageSizeInfo( uint64_t & ulFhsTotal, uint64_t & ulFhsAvailable, int & iMaxUsage )
{
// storage 정보가 비어 있는 경우
if( m_vecStorageInfo.empty() == true )
return false;
// output 인자 초기화.
ulFhsTotal = 0;
ulFhsAvailable = 0;
iMaxUsage = 0;
// total : 각 mount 의 used + available size 합계.
// available : 각 mount 의 합계.
// 최대 storage 사용률 정보 추출
std::vector< struct stStorageInfo >::iterator it;
for( it = m_vecStorageInfo.begin(); it < m_vecStorageInfo.end(); it++ )
{
// 전체 용량, 사용 가능 용량 합산
ulFhsTotal = ulFhsTotal + it->ulUsedByte + it->ulAvailableByte;
ulFhsAvailable = ulFhsAvailable + it->ulAvailableByte;
// 최대 사용률 정보 추출
if( it->usage > iMaxUsage )
{
iMaxUsage = it->usage;
}
// 2018-02-06 NEW huibong Storage 사용률이 90% 초과하는 경우 해당 Storage 의 정보를 로깅 처리한다.(#31701)
if( it->usage > 90 )
{
_LOG( LINF, "[Storage Info] storage usage: %s %3d %%, used[%14ju], avail[%14ju]."
, it->strName.c_str(), it->usage, it->ulUsedByte, it->ulAvailableByte );
}
else
{
_LOG( LDBG, "%s used[%14ju] avail[%14ju] usage[%3d %%]"
, it->strName.c_str(), it->ulUsedByte, it->ulAvailableByte, it->usage );
}
}
return true;
}
// 멤버 vector 에 저장된 mount 경로명 정보를 반환
bool CStorageInfo::GetStoragePath( std::vector<std::string>& vecPath )
{
// storage 정보가 비어 있는 경우
if( m_vecStorageInfo.empty() == true )
return false;
// output 인자 초기화.
vecPath.clear();
std::vector< struct stStorageInfo >::iterator it;
for( it = m_vecStorageInfo.begin(); it < m_vecStorageInfo.end(); it++ )
{
vecPath.push_back( it->strName );
}
return true;
}
// 멤버 vector 에 저장된 storage 정보 중에 ZFS file system 정보 존재하는지 Check
bool CStorageInfo::IsExistZFS()
{
// storage 정보가 비어 있는 경우 - ZFS file system 없는 것으로 처리
if( m_vecStorageInfo.empty() == true )
return false;
std::vector< struct stStorageInfo >::iterator it;
for( it = m_vecStorageInfo.begin(); it < m_vecStorageInfo.end(); it++ )
{
if( strcasecmp( "zfs", it->strFsTypeName.c_str() ) == 0 )
{
// zfs filesystem 이 존재하는 경우...
// - 나머지는 check 할 필요 없이 그냥 true 반환.
return true;
}
}
// zfs filesystem 이 없는 경우
return false;
}
+77
View File
@@ -0,0 +1,77 @@
/****************************************************************************
Storage info class
-----------------------------------------
begin : 2018/02/06
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __STORAGE_INFO_H__
#define __STORAGE_INFO_H__
#include <unistd.h>
#include <string>
#include <vector>
// 각 Storage mount 의 정보를 저장할 구조체
struct stStorageInfo {
std::string strName; // mount name, statfs::f_mntonname 항목
std::string strFsTypeName; // zfs, ufs 형식의 Type Name, statfs::f_fstypename 항목
uint64_t ulUsedByte; // 사용 중인 용량 Byte
uint64_t ulAvailableByte; // 사용 가능한 용량 Byte
int usage; // Storage 사용률(%), ceil() 함수 사용으로 소수점 올림 처리되어 95.1 % -> 96 % 로 처리됨
};
// Storage 관련 정보 추출 담당 class
class CStorageInfo
{
public:
// 생성자
CStorageInfo();
// 소멸자
~CStorageInfo();
// 초기화 함수
bool Init( const char * szRoot );
public: // Storage info 관련 interface 함수
// 멤버 vector 에 저장된 경로의 Total Size, Total availsize, Max usage 정보를 반환.
bool GetStorageSizeInfo( uint64_t & ulFhsTotal, uint64_t & ulFhsAvailable, int & iMaxUsage );
// 멤버 vector 에 저장된 mount 경로명 정보를 반환
bool GetStoragePath( std::vector< std::string > & vecPath );
// 멤버 vector 에 저장된 storage 정보 중에 ZFS file system 정보 존재하는지 Check
bool IsExistZFS();
private: // 멤버 변수
// init() 에서 추출된 정보 저장을 위한 vector 멤버변수
std::vector< struct stStorageInfo > m_vecStorageInfo;
private: // 처리 관련 내부 함수
// 전달받은 경로로부터.. 상위 Path 정보를 추출하여 전달한다.
void GetUpperPath( const std::string & strSourcePath, std::string & strUpperPath );
};
#endif /* __STORAGE_INFO_H__ */
+775
View File
@@ -0,0 +1,775 @@
#include "SystemInfo.h"
#include "Logger.h"
#include <errno.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/param.h>
#include <stddef.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <stdint.h>
#include <math.h>
#include <fcntl.h>
#include <devstat.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_mib.h>
#include <time.h>
#include <stdlib.h>
#include <sys/socketvar.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/tcp_var.h>
#include <arpa/inet.h>
#include <netinet/tcp_fsm.h>
#include <vector>
// 생성자
CSystemInfo::CSystemInfo( CFhsShm * pFhsShm )
: m_pFhsShm( pFhsShm )
, m_pKvm(NULL)
{
memset( &m_stDiskGmesh, 0x00, sizeof( struct gmesh ) );
m_pDiskSnapshotPrev = NULL;
m_pDiskSnapshotNow = NULL;
memset( &m_timeDiskPrev, 0x00, sizeof( struct timespec ) );
memset( &m_timeDiskNow, 0x00, sizeof( struct timespec ) );
// 최초 수집시 계산 오류 회피을 위해 0 으로 초기화.
m_timeNetworkPrev.tv_sec = 0;
m_timeNetworkPrev.tv_nsec = 0;
m_ulNetworkPacketIn = 0;
m_ulNetworkPacketOut = 0;
m_ulNetworkByteIn = 0;
m_ulNetworkByteOut = 0;
}
// 소멸자
CSystemInfo::~CSystemInfo()
{
if( m_pKvm != NULL )
kvm_close( m_pKvm );
// Disk 상태 수집 관련 변수, 포인트 해제 처리
if( m_pDiskSnapshotPrev != NULL )
geom_stats_snapshot_free( m_pDiskSnapshotPrev );
if( m_pDiskSnapshotNow != NULL )
geom_stats_snapshot_free( m_pDiskSnapshotNow );
geom_deletetree( &m_stDiskGmesh );
}
// 초기화 함수
bool CSystemInfo::Init()
{
if( m_pFhsShm == NULL )
return false;
// Kernel data access library 객체 초기화.
m_pKvm = kvm_open( NULL, "/dev/null", NULL, O_RDONLY, PROG_NAME":CSystemInfo" );
if( m_pKvm == NULL )
{
LOG( LERR, "init fail. kvm_open() error.");
return false;
}
// Disk 상태 정보 수집을 위한 멤버 변수 초기화.
int iResult = 0;
iResult = geom_gettree( &m_stDiskGmesh );
if( iResult != 0 )
{
LOG( LERR, "init fail. geom_gettree() return error[%d]", iResult );
return false;
}
iResult = geom_stats_open();
if( iResult )
{
LOG( LERR, "init fail. geom_stats_open() return error[%d]", iResult );
return false;
}
m_pDiskSnapshotPrev = NULL;
m_pDiskSnapshotPrev = geom_stats_snapshot_get();
if( m_pDiskSnapshotPrev == NULL )
{
LOG( LERR, "init fail. geom_stats_snapshot_get() return NULL.");
return false;
}
geom_stats_snapshot_timestamp( m_pDiskSnapshotPrev, &m_timeDiskPrev );
return true;
}
// hostname 정보 수집
bool CSystemInfo::GetHostname()
{
char tempBuffer[256];
if( gethostname( tempBuffer, 255 ) == 0 )
{
// 정보 추출 성공시
// - shared memory 에 set 시도.
if( m_pFhsShm->SetHostname( tempBuffer ) == false )
{
// shared memory 에 저장 실패시.
// - 로그는 해당 모듈에서 처리하므로.. false 반환.
return false;
}
}
else
{
// hostname 정보 추출 실패시.
// - 호출한 프로세스 모듈에서 프로세스 종료 등의 후처리를 진행하므로....
// - false 반환 외에 따로 진행할 작업 없음.
int errorNum = errno;
LOG( LERR, "gethostname() fail. [%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
return true;
}
// load average 정보 수집
bool CSystemInfo::GetLoadAverage()
{
// 변수 초기화 안할 경우.. 오류 발생
int iIndex = 0;
struct loadavg stLoadAvg;
size_t length = sizeof( stLoadAvg );
memset( &stLoadAvg, 0x00, sizeof( struct loadavg ) );
if( sysctlbyname( "vm.loadavg", &stLoadAvg, &length, NULL, 0 ) == -1 )
{
// 함수 호출 실패시
// - 오류 내역 로깅 후
// - shraed memory 상의 설정 정보를 0 으로 초기화.
int errorNum = errno;
LOG( LERR, "load average collect error.[%d][%s]", errorNum, strerror( errorNum ) );
for( iIndex = 0; iIndex < 3; iIndex++ )
{
m_pFhsShm->SetLoadaverage( iIndex, (double)0.0 );
}
return false;
}
else
{
// 추출 성공시.
for( iIndex = 0; iIndex < 3; iIndex++ )
{
m_pFhsShm->SetLoadaverage( iIndex, (double)stLoadAvg.ldavg[iIndex] / stLoadAvg.fscale );
}
}
return true;
}
// total memory 정보 수집
bool CSystemInfo::GetMemoryTotal()
{
// 변수 초기화 안할 경우.. 오류 발생
uint64_t ulValue = 0;
size_t length = sizeof( ulValue );
if( sysctlbyname( "hw.physmem", &ulValue, &length, NULL, 0 ) == -1 )
{
// 함수 호출 실패시
// - 오류 내역 로깅 후
// - shraed memory 상의 설정 정보를 0 으로 초기화.
int errorNum = errno;
LOG( LERR, "total memory collect error.[%d][%s]", errorNum, strerror( errorNum ) );
ulValue = 0;
m_pFhsShm->SetMemoryTotal( ulValue );
return false;
}
else
{
// 추출 성공시
m_pFhsShm->SetMemoryTotal( ulValue );
}
return true;
}
// free memory 정보 수집
// 2018-01-10 CHG huibong
// - available memory 사용량 계산 방식 변경 free -> free + inactive + cache (#31360)
bool CSystemInfo::GetMemoryFree()
{
// 변수 초기화 안할 경우.. 오류 발생
uint64_t ulTotal = 0;
uint64_t ulValue = 0;
size_t length = sizeof( ulValue );
// free memory 정보 추출
if( sysctlbyname( "vm.stats.vm.v_free_count", &ulValue, &length, NULL, 0 ) == -1 )
{
// 함수 호출 실패시
// - 오류 내역 로깅 후
// - shraed memory 상의 설정 정보를 0 으로 초기화.
int errorNum = errno;
LOG( LERR, "available memory[free] collect error.[%d][%s]", errorNum, strerror( errorNum ) );
ulValue = 0;
m_pFhsShm->SetMemoryFree( ulValue );
return false;
}
ulTotal = ulTotal + ulValue;
// 변수 초기화 안할 경우.. 오류 발생
ulValue = 0;
// inactive memory 정보 추출
if( sysctlbyname( "vm.stats.vm.v_inactive_count", &ulValue, &length, NULL, 0 ) == -1 )
{
// 함수 호출 실패시
// - 오류 내역 로깅 후
// - shraed memory 상의 설정 정보를 0 으로 초기화.
int errorNum = errno;
LOG( LERR, "available memory[inactive] collect error.[%d][%s]", errorNum, strerror( errorNum ) );
ulValue = 0;
m_pFhsShm->SetMemoryFree( ulValue );
return false;
}
ulTotal = ulTotal + ulValue;
// 변수 초기화 안할 경우.. 오류 발생
ulValue = 0;
// cached memory 정보 추출
if( sysctlbyname( "vm.stats.vm.v_cache_count", &ulValue, &length, NULL, 0 ) == -1 )
{
// 함수 호출 실패시
// - 오류 내역 로깅 후
// - shraed memory 상의 설정 정보를 0 으로 초기화.
int errorNum = errno;
LOG( LERR, "available memory[cached] collect error.[%d][%s]", errorNum, strerror( errorNum ) );
ulValue = 0;
m_pFhsShm->SetMemoryFree( ulValue );
return false;
}
ulTotal = ulTotal + ulValue;
// 추출 성공시
// - 추출된 값이 page 단위이므로.. page 크기를 곱한다. ( pgagsize = 4096 )
ulTotal = ulTotal * getpagesize();
m_pFhsShm->SetMemoryFree( ulTotal );
return true;
}
// swap 정보 수집
bool CSystemInfo::GetSwap()
{
struct kvm_swap stSwap[1];
if( kvm_getswapinfo( m_pKvm, stSwap, 1, 0 ) == -1 )
{
// swap 정보 추출 실패시.
// - 오류 내역 로깅 후
// - shraed memory 상의 설정 정보를 0 으로 초기화.
LOG( LERR, "swap collect error. kvm_getswapinfo().");
m_pFhsShm->SetSwapInfo( 0, 0 );
return false;
}
else
{
// 추출 성공시
// - 추출된 값이 page 단위이므로.. page 크기를 곱한다. ( pgagsize = 4096 )
uint64_t ulTotal = 0;
uint64_t ulUsed = 0;
// swap total
ulTotal = (uint64_t)( stSwap[0].ksw_total ) * getpagesize();
// swap used
ulUsed = (uint64_t)( stSwap[0].ksw_used ) * getpagesize();
// shared memory set
m_pFhsShm->SetSwapInfo( ulTotal, ulUsed );
}
return true;
}
// mount 정보 수집 및 처리
// - szRoot : 정보를 수집할 mount 최상위 경로 정보.
bool CSystemInfo::GetMount( const char * szRoot )
{
// Storage 정보 추출 객체 초기화 실패시
if( m_storageInfo.Init( szRoot ) == false )
{
// 오류 내역 로깅 후
// shraed memory 상의 설정 정보를 0 으로 초기화.
LOG( LERR, "storage mount info class init failed." );
m_pFhsShm->SetStorageInfo( 0, 0, 0);
return false;
}
// Storage 관련 Total Size, Total Avvailable Size, Max usage percent 정보 추출
uint64_t ulFhsTotal = 0;
uint64_t ulFhsAvailable = 0;
int fhsMaxUsage = 0;
if( m_storageInfo.GetStorageSizeInfo( ulFhsTotal, ulFhsAvailable, fhsMaxUsage ) == false )
{
// 정보 추출 실패시
// - 오류 내역 로깅 후
// - shraed memory 상의 설정 정보를 0 으로 초기화.
LOG( LERR, "mount storage info collect fail. [%s] not found.", szRoot );
m_pFhsShm->SetStorageInfo( 0, 0, 0 );
return false;
}
else
{
// 정상 추출한 경우
// - 공유메모리 정보 update
m_pFhsShm->SetStorageInfo( ulFhsTotal, ulFhsAvailable, fhsMaxUsage );
}
return true;
}
bool CSystemInfo::GetDiskStatus()
{
uint64_t ulQueueLength = 0;
// FreeBSD 64bit 에서
// - double : 8 Byte
// - long double : 16 Byte
// - 본 변수 type 을 double type 으로 할 경우 오류 발생함.
// - 하지만. long double -> double 형변환은 유효 자리수 처리 문제를 제외하면.. 정상.
long double dBusy = 0.0;
uint64_t ulMaxQueueLength = 0;
double dMaxBusy = 0.0;
double dTimeInterval; // dt
struct gident * pGident; // gid
struct gprovider * pProvider; // pp
// 현재 snapshot 추출.
m_pDiskSnapshotNow = geom_stats_snapshot_get();
if( m_pDiskSnapshotNow == NULL )
{
// 오류 내역 로깅 후
// shraed memory 상의 설정 정보를 0 으로 초기화.
LOG( LERR, "now geom_stats_snapshot_get() return NULL." );
m_pFhsShm->SetDiskInfo( 0, (double)0.0 );
return false;
}
// 현재 시간 정보 추출.
geom_stats_snapshot_timestamp( m_pDiskSnapshotNow, &m_timeDiskNow );
// 이전 추출 시간과 현재 시간 간의 시간 간격 계산.
dTimeInterval = m_timeDiskNow.tv_sec - m_timeDiskPrev.tv_sec;
dTimeInterval += ( m_timeDiskNow.tv_nsec - m_timeDiskPrev.tv_nsec ) * 1e-9;
// 이전 수집 시간을 마지막 수집 시간으로 변경
m_timeDiskPrev = m_timeDiskNow;
// 수집된 snapshot 이 포인터 위치를 첫번째 인자로 reset 처리.
geom_stats_snapshot_reset( m_pDiskSnapshotPrev );
geom_stats_snapshot_reset( m_pDiskSnapshotNow );
struct devstat * pDevStatPrev; // gsq
struct devstat * pDevStatNow; // gsp
// 루프를 돌며서.. 필요 정보 추출
for( ;; )
{
// Disk stat 정보를 1개씩 추출
pDevStatNow = geom_stats_snapshot_next( m_pDiskSnapshotNow );
pDevStatPrev = geom_stats_snapshot_next( m_pDiskSnapshotPrev );
if( pDevStatNow == NULL || pDevStatPrev == NULL )
break;
if( pDevStatNow->id == NULL )
continue;
pGident = geom_lookupid( &m_stDiskGmesh, pDevStatNow->id );
if( pGident == NULL )
{
int i = 0;
geom_deletetree( &m_stDiskGmesh );
i = geom_gettree( &m_stDiskGmesh );
if( i != 0 )
{
// 루프를 빠져 나가도록 처리한다.
LOG( LERR, "geom_gettree() return error[%d]", i );
break;
}
pGident = geom_lookupid( &m_stDiskGmesh, pDevStatNow->id );
}
// ISCONSUMER 인 경우 제외
// - DEV/da7/da7, SWAP/swap/da12p1 등으로 표시됨.
// - 계산 대상에서 제외 처리함.
if( pGident == NULL || pGident->lg_what == gident::ISCONSUMER )
continue;
// physical provider ( rank = 1) 만 대상에 포함
// - da10p1, da12p3, gptid/2841d6b5-9659-11e4-9f9d-047d7b1a4e6 등의
// - 불필요한 항목을 대상에서 제외 처리한다.
if( pGident->lg_what == gident::ISPROVIDER
&& ( ( struct gprovider * )( pGident->lg_ptr ) )->lg_geom->lg_rank != 1 )
continue;
if( pDevStatNow->sequence0 != pDevStatNow->sequence1 )
continue;
// 추출된 Disk 정보의 Provider 정보가 유효하지 않은 경우...
// - 즉 표시되는 Name 정보가 유효하지 않는 것이므로...
// - 대상에서 제외 처리.
pProvider = ( struct gprovider * )( pGident->lg_ptr );
if( pProvider == NULL )
continue;
// Disk 정보 계산 처리.
devstat_compute_statistics( pDevStatNow, pDevStatPrev, dTimeInterval,
DSM_QUEUE_LENGTH, &ulQueueLength,
DSM_BUSY_PCT, &dBusy,
DSM_NONE );
// 추출된 값에서 최대값 정보를 추출한다.
if( ulQueueLength > ulMaxQueueLength )
ulMaxQueueLength = ulQueueLength;
// long double -> double 로 형변환할 경우... 소수점 이하 정밀도 부분에서 유실이 발생할 수 있지만...
// 기본적으로는 허용되는 형변환임.
if( dBusy > dMaxBusy )
dMaxBusy = (double)dBusy;
_LOG( LDBG, "disk status info: %s queue: %4ju, busy: %4.1Lf %%", pProvider->lg_name, ulQueueLength, dBusy );
// 2018-02-08 NEW huibong disk busy 상황시 해당 디스크 정보 로깅 (#31701)
// - Disky busy 상황시.. 실제 OS, Content 저장용 Disk 가 아닌 Raid Spare 디스크가 Busy 상황인 경우가 발견됨
// - 따라서 이를 좀더 정확히 확인하기 위해 Disk Busy 상황으로 판단되는 경우.. 해당 Disk 정보를 로깅하도록 처리한다.
if( dBusy >= DISK_BUSY_MIN_BUSY_PERCENT || ulQueueLength >= DISK_BUSY_MIN_QUEUE_COUNT )
{
_LOG( LINF, "disk busy: %s queue: %4ju busy: %4.1Lf %%", pProvider->lg_name, ulQueueLength, dBusy );
}
// 추출된 Data 를 Previous Data 에 저장 처리한다.
*pDevStatPrev = *pDevStatNow;
}
// 현재 추출한 shapshot 메모리 영역 해제 처리.
geom_stats_snapshot_free( m_pDiskSnapshotNow );
m_pDiskSnapshotNow = NULL;
// shared memory 저장 처리.
m_pFhsShm->SetDiskInfo( ulMaxQueueLength, dMaxBusy );
return true;
}
// Network 상태 정보 수집
bool CSystemInfo::GetNetworkStatus()
{
u_int uCount = 0;
size_t length = sizeof( uCount );
int arrayIfCount[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT };
int arrayIfInfo[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, 0 , IFDATA_GENERAL };
// Network Interface 갯수 정보 추출.
if( sysctl( arrayIfCount, 5, (void *)&uCount, (size_t *)&length, (void *)NULL, (size_t)0 ) != 0 )
{
// 정보 추출 실패시
// - 오류 로깅 후
// - shared memory 상의 network 통계 정보를 0 으로 설정 처리한다.
int errorNum = errno;
LOG( LERR, "network interface count collect error.[%d][%s]", errorNum, strerror( errorNum ) );
m_pFhsShm->SetNetworkInfo( 0, 0, 0, 0 );
return false;
}
// Network Interface 가 없는 경우...
if( uCount <= 0 )
{
LOG( LERR, "network interface count[%u] not valid", uCount );
// Network 통계 정보를 0 으로 설정 처리한다.
m_pFhsShm->SetNetworkInfo( 0, 0, 0, 0 );
return false;
}
// 추출된 정보를 저장하기 위한 변수
struct timespec timeNow;
memset( &timeNow, 0x00, sizeof( struct timespec ) );
uint64_t ulTotalPacketIn = 0;
uint64_t ulTotalPacketOut = 0;
uint64_t ulTotalByteIn = 0;
uint64_t ulTotalByteOut = 0;
struct ifmibdata stIfdata;
length = sizeof( struct ifmibdata );
// 추출된 count 숫자만큼 루프를 돌면서 Network interface 각 개별 정보를 수집 처리한다.
// - sysctl 호출 땜시 루프는 1 부터 시작.
for( int index = 1; index <= (int)uCount; index++ )
{
// 추출할 interface 번호 설정.
arrayIfInfo[4] = index;
// interface 세부 정보 추출.
if( ( sysctl( arrayIfInfo, 6, (void *)&stIfdata, (size_t *)&length, (void *)NULL, (size_t)0 ) != 0 ) && ( errno != ENOENT ) )
{
// 정보 추출 실패시
// - 오류 로깅 후
// - shared memory 상의 현재까지 추출, 합산된 정보만 set 처리.
int errorNum = errno;
LOG( LERR, "network interface info sysctl return error.[%d][%s]", errorNum, strerror( errorNum ) );
break;
}
// local loopback interface (lo) 제외
// - 장비의 트래픽 정보를 수집하는 것이므로.. lo 꺼는 빼는 것이 맞다.
if( strncmp( stIfdata.ifmd_name, "lo", 2 ) == 0 )
continue;
// link aggregation 처리되 lagg interface 제외
// - link ggreagtion 처리된 개별 interface 통계가 lagg 에 sum 되어 나타나므로... 통계 중복 발생.
// - 이를 해결하기 위해 lagg interface 는 수집 제외
if( strncmp( stIfdata.ifmd_name, "lagg", 4 ) == 0 )
continue;
_LOG( LDBG, "network interface collected: %s", stIfdata.ifmd_name );
// 추출 정보 합산 처리.
ulTotalPacketIn += stIfdata.ifmd_data.ifi_ipackets;
ulTotalPacketOut += stIfdata.ifmd_data.ifi_opackets;
ulTotalByteIn += stIfdata.ifmd_data.ifi_ibytes;
ulTotalByteOut += stIfdata.ifmd_data.ifi_obytes;
}
// 최종 시간 정보 추출.
clock_gettime( CLOCK_MONOTONIC, &timeNow );
// 이전에 추출된 Network 통계 정보와의 계산을 통해서...
// 실제 트래픽, packet 갯수 등을 추출.
if( m_timeNetworkPrev.tv_sec == 0 && m_timeNetworkPrev.tv_nsec == 0 )
{
// 최초 기동 후 이전 Data 가 아직 수집되지 않은 경우...
// - 통계 정보 계산이 불가능하므로...
// - 0 으로 정보 설정 처리한다.
m_pFhsShm->SetNetworkInfo( 0, 0, 0, 0 );
}
else
{
// 이전 추출 시간과 현재 시간 간의 시간 간격 계산.
double dTimeInterval = 0.0;
dTimeInterval = timeNow.tv_sec - m_timeNetworkPrev.tv_sec;
dTimeInterval += ( timeNow.tv_nsec - m_timeNetworkPrev.tv_nsec ) * 1e-9;
uint64_t ulPacketIn = ulTotalPacketIn - m_ulNetworkPacketIn;
uint64_t ulPacketOut = ulTotalPacketOut - m_ulNetworkPacketOut;
uint64_t ulByteIn = ulTotalByteIn - m_ulNetworkByteIn;
uint64_t ulByteOut = ulTotalByteOut - m_ulNetworkByteOut;
// 평균 packet count(count/sec), 트래픽(Byte/sec)은 반올림 또는 정수 올림 처리하지 않고.. 계산된 값의 정수 부분만 사용 처리한다.
uint64_t ulPacketInAvg = 0;
uint64_t ulPacketOutAvg = 0;
uint64_t ulTrafficIn = 0;
uint64_t ulTrafficOut = 0;
if( dTimeInterval > 0.0 )
{
ulPacketInAvg = (uint64_t)( ulPacketIn / dTimeInterval );
ulPacketOutAvg = (uint64_t)( ulPacketOut / dTimeInterval );
ulTrafficIn = (uint64_t)( ulByteIn / dTimeInterval );
ulTrafficOut = (uint64_t)( ulByteOut / dTimeInterval );
}
// Shared Memory 상에 저장 처리.
m_pFhsShm->SetNetworkInfo( ulPacketInAvg, ulPacketOutAvg, ulTrafficIn, ulTrafficOut );
}
// 멤버 변수에 현재 추출된 정보를 저장 처리한다.
m_timeNetworkPrev.tv_sec = timeNow.tv_sec;
m_timeNetworkPrev.tv_nsec = timeNow.tv_nsec;
m_ulNetworkPacketIn = ulTotalPacketIn;
m_ulNetworkPacketOut = ulTotalPacketOut;
m_ulNetworkByteIn = ulTotalByteIn;
m_ulNetworkByteOut = ulTotalByteOut;
return true;
}
// TCP session 상태 정보 수집
bool CSystemInfo::GetTcpSession()
{
unsigned int uTcpTotal = 0;
unsigned int uTcp80 = 0;
unsigned int uTcp80Establish = 0;
size_t length = 0;
// 세션 갯수 정보 추출.
if( sysctlbyname( "net.inet.tcp.pcblist", 0, &length, 0, 0 ) < 0 )
{
// 함수 호출 실패시
// - 오류 내역 로깅 후
// - shraed memory 상의 설정 정보를 0 으로 초기화.
int errorNum = errno;
if( errorNum == ENOENT )
{
LOG( LERR, "tcp session count collect error. OS version check[%d][%s]", errorNum, strerror( errorNum ) );
}
else
{
LOG( LERR, "tcp session count collect error.[%d][%s]", errorNum, strerror( errorNum ) );
}
m_pFhsShm->SetTcpInfo( 0, 0, 0 );
return false;
}
// 추출된 세션 정보를 저장할 임시 buf 할당.
char * szBuffer = NULL;
szBuffer = (char *)malloc( length );
if( szBuffer == NULL )
{
// 임시 buffer 생성 실패시..
int errorNum = errno;
LOG( LERR, "tcp session collect error. malloc fail.[%lu]Byte, [%d][%s]", length, errorNum, strerror( errorNum ) );
m_pFhsShm->SetTcpInfo( 0, 0, 0 );
return false;
}
// 세션 정보 추출.
if( sysctlbyname( "net.inet.tcp.pcblist", szBuffer, &length, 0, 0 ) < 0 )
{
// 세션 정보 추출 실패시
int errorNum = errno;
LOG( LERR, "tcp session collect error.[%d][%s]", errorNum, strerror( errorNum ) );
free( szBuffer );
m_pFhsShm->SetTcpInfo( 0, 0, 0 );
return false;
}
// 추출된 정보를 루프를 돌면서 count 처리한다.
// netstat 에서 사용된 source 코드를 거의 그대로 사용.
struct xinpgen *xig, *oxig;
struct xsocket *so;
// CHG 2020-10-29 huibong FreeBSD 12.x 지원을 위한 코드 분리 (#33233)
// - FreeBSD 12.x 에서 include/netinet/tcp_var.h 에서 tcpcb 구조체 변경이 발생
// - 이로 인해 기존 FreeBSD 6.x, 10.x 에서 동작하는 TCP 세션 정보 추출 코드가 컴파일 되지 않는 문제 발생
// - FreeBSD 12.x 의 /usr/src/usr.bin/netstat/inet.c 소스를 참고로..
// - FreeBSD 6.x, 10.x 와 FreeBSD 12.x 에서 분리된 코드로 컴파일 되도록 수정 처리함.
#if __FreeBSD_version < 1200000
struct inpcb *inp;
struct tcpcb *tp = NULL;
#else
struct xinpcb *inp;
struct xtcpcb *tp;
#endif
int port;
oxig = xig = ( struct xinpgen * )szBuffer;
for( xig = ( struct xinpgen * )( (char *)xig + xig->xig_len );
xig->xig_len > sizeof( struct xinpgen );
xig = ( struct xinpgen * )( (char *)xig + xig->xig_len ) )
{
// CHG 2020-10-29 huibong FreeBSD 12.x 지원을 위한 코드 분리 (#33233)
// - FreeBSD 12.x 에서 include/netinet/tcp_var.h 에서 tcpcb 구조체 변경이 발생
// - 이로 인해 기존 FreeBSD 6.x, 10.x 에서 동작하는 TCP 세션 정보 추출 코드가 컴파일 되지 않는 문제 발생
// - FreeBSD 12.x 의 /usr/src/usr.bin/netstat/inet.c 소스를 참고로..
// - FreeBSD 6.x, 10.x 와 FreeBSD 12.x 에서 분리된 코드로 컴파일 되도록 수정 처리함.
#if __FreeBSD_version < 1200000
so = &( ( struct xtcpcb * )xig )->xt_socket;
inp = &( ( struct xtcpcb * )xig )->xt_inp;
tp = &( ( struct xtcpcb * )xig )->xt_tp;
#else
tp = (struct xtcpcb *)xig;
inp = &tp->xt_inp;
so = &inp->xi_socket;
#endif
// Ignore sockets for protocols other than the desired one.
if( so->xso_protocol != IPPROTO_TCP )
continue;
// Ignore PCBs which were freed during copyout.
if( inp->inp_gencnt > oxig->xig_gen )
continue;
// IP v4, v6 가 아닌 경우 제외
if( ( inp->inp_vflag & INP_IPV4 ) == 0 && ( inp->inp_vflag & INP_IPV6 ) == 0 )
continue;
uTcpTotal++;
// Local port 정보 주출.
port = ntohs( (u_short)inp->inp_lport );
if( port == 80 )
{
uTcp80++;
if( tp && tp->t_state == TCPS_ESTABLISHED )
uTcp80Establish++;
}
}
// malloc 으로 할당된 임시 버퍼 해제 처리.
free( szBuffer );
// shared memory update.
m_pFhsShm->SetTcpInfo( uTcpTotal, uTcp80, uTcp80Establish );
return true;
}
+112
View File
@@ -0,0 +1,112 @@
/****************************************************************************
system infomation collect & shared memory set class
-----------------------------------------
begin : 2015/04/28
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __SYSTEM_INFO_H__
#define __SYSTEM_INFO_H__
#include "FhsShm.h"
#include "StorageInfo.h"
#include <unistd.h>
#include <kvm.h>
#include <libgeom.h>
#include <string>
// System 정보를 추출하여.. 공유메모리에 저장을 담당하기 위한 class
class CSystemInfo
{
public:
// 생성자
CSystemInfo( CFhsShm * pFhsShm );
// 소멸자
~CSystemInfo();
// 초기화 함수
bool Init();
public: // 시스템 정보 수집 관련 함수
// hostname 정보 수집
bool GetHostname();
// load average 정보 수집
bool GetLoadAverage();
// total memory 정보 수집
bool GetMemoryTotal();
// free memory 정보 수집
bool GetMemoryFree();
// swap 정보 수집
bool GetSwap();
// mount 정보 수집 및 처리
bool GetMount( const char * szRoot);
// Disk 상태 정보 수집
bool GetDiskStatus();
// Network 상태 정보 수집
bool GetNetworkStatus();
// TCP session 상태 정보 수집
bool GetTcpSession();
private: // 시스템 정보 수집 관련 멤버 변수
// 공유메모리 interface 객체에 대한 포인터.
// - 공유메모리에 Data Set, Get 을 담당
CFhsShm * m_pFhsShm;
// Kernel data access library 객체에 대한 포인터
// - swap 정보 추출을 위해 사용.
kvm_t * m_pKvm;
// Disk 상태 정보 수집을 위한 멤버변수
struct gmesh m_stDiskGmesh; // gmp
void * m_pDiskSnapshotPrev; // sq
void * m_pDiskSnapshotNow; // sp
struct timespec m_timeDiskPrev; // tq
struct timespec m_timeDiskNow; // tp
// Network 통계 정보 수집을 위한 멤버 변수
struct timespec m_timeNetworkPrev; // 최종 Network 통계 수집 시간.
uint64_t m_ulNetworkPacketIn; // total network in packet count
uint64_t m_ulNetworkPacketOut; // total network out packet count
uint64_t m_ulNetworkByteIn; // total network in byte
uint64_t m_ulNetworkByteOut; // total network out byte
// Storage mount 정보 추출 관련 처리를 수행할 class 객체
CStorageInfo m_storageInfo;
private: // 처리 관련 내부 함수
};
#endif /* __SYSTEM_INFO_H__ */
+506
View File
@@ -0,0 +1,506 @@
#include "TelegrafControl.h"
#include "Logger.h"
#include "BaseSocket.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
#include <signal.h>
#include <string>
#define TELEGRAF_PROCESS_NAME "telegraf"
#define TELEGRAF_BINARY_FULL_PATH "/usr/local/bin/telegraf"
#define TELEGRAF_PROMETHEUS_CLIENT_IP "127.0.0.1"
#define TELEGRAF_PROMETHEUS_CLIENT_PORT 9200
CTelegrafControl::CTelegrafControl()
{
}
CTelegrafControl::~CTelegrafControl()
{
}
// telegraf process 의 PID 정보 반환...
// - 정보 추출시 오류 또는 미동작 상황인 경우.. 0 반환
int CTelegrafControl::GetProcessId()
{
char tempBuffer[64];
FILE * fd = NULL;
int iProcessId = 0;
snprintf( tempBuffer, sizeof( tempBuffer ), "pgrep -x %s", TELEGRAF_PROCESS_NAME );
fd = popen( tempBuffer, "r" );
if( fd == NULL )
{
// popen 수행 실패시......
int errorNum = errno;
LOG( LERR, "[TelegrafControl] popen failed. [%d][%s]", errorNum, strerror( errorNum ) );
// 오류 발생시 0 반환
iProcessId = 0;
}
else
{
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
// 참고사항
// https://jarvis.solbox.com/redmine/issues/32973 에서 언급된 popen - fgets() 호출시 지연 발생 가능성 관련
// 서비스 자체에는 영향이 없고... 호출 빈도를 최소화하도록 조정하여....
// 사용하기로 결정함.
if( fgets( tempBuffer, sizeof( tempBuffer ) - 1, fd ) != NULL )
{
// 프로세스 ID 가 존재하는 경우
std::string tempPid( tempBuffer );
Trim( tempPid );
iProcessId = atoi( tempPid.c_str() );
_LOG( LDBG, "[TelegrafControl] %s process id %d.", TELEGRAF_PROCESS_NAME, iProcessId );
}
pclose( fd );
}
return iProcessId;
}
// telegraf service start
// - system() 호출 관련 service 명령어 수행시.. -1 이 반환되므로....
// - telegraf 가 정상 기동 되었는지 판단 불가하여.. 반환값은 void 로 처리한다.
void CTelegrafControl::ServiceStart()
{
// 우선 binary 가 정상적으로 존재하는지 check
// - FreeBSD 6.x, 10.0 버전에서는 telegraf 동작시키지 않으므로... binary 가 없는 경우.. 기동시키지 않는다.
if( access( TELEGRAF_BINARY_FULL_PATH, X_OK ) != 0 )
{
_LOG( LWAR, "[TelegrafControl] binary[%s] not exist.", TELEGRAF_BINARY_FULL_PATH );
return;
}
// service 명령을 이용하여... telegraf 를 기동 처리한다.
// - service 명령어로 기동시... system() 호출 결과는 -1, errno=10 (No child processes) 가 반환된다.
// - 따라서 system() 호출 결과 -1 을 반환으로 인해.. telegraf 가 정상 기동되었는지 판단 불가하므로...
// - 본 함수의 반환값은 void 로 처리한다.
system( "service telegraf start" );
_LOG( LINF, "[TelegrafControl] command \'service telegraf start\' executed.");
return;
}
// telegraf 가 hang 상태인지 check
// - hang 상황인 경우 true 반환
// - 그 외의 경우에는 false 반환
bool CTelegrafControl::IsHang()
{
// telegraf 의 prometheus_client 와 통신을 통하여.. telegraf 가 hang 상태인지 check 한다.
// [[outputs.prometheus_client]]
// listen = ":9200"
// telegraf 가
// TCP 9200 port 접속 후 전달한 잘못된 요청에 대해.. HTTP 400 Bad Request 등과 같은 어떠한 응답이라도 하면 정상..
// 그 외에는 hang 상황으로 판단한다.
// - 접속은 되나... 지정된 시간동안 응답을 수신하지 못할 경우...
// - 아예 접속이 안되는 경우.. ( Listen queue overflow 상황)
std::string strTragetIp = TELEGRAF_PROMETHEUS_CLIENT_IP;
// socket 관련 변수.
int sock = -1;
struct sockaddr_in stTarget;
int flags;
int result = 0;
int errorNum = 0;
// socket 생성.
sock = socket( AF_INET, SOCK_STREAM, 0 );
if( sock == -1 )
{
errorNum = errno;
_LOG( LERR, "[TelegrafControl] socket create error. [%d][%s]", errorNum, strerror( errorNum ) );
// hang check 수행하지 못했으므로.. 우선 정상 상태로 판단.
return false;
}
// Connnection 종료시 많은 TIME_WAIT 상태 발생 방지를 위해 SO_LINGER 옵션을 설정처리한다.
struct linger opt_linger;
opt_linger.l_onoff = 1; /* LINGER ON */
// 0 : No Wait for abortive disconnect
// - 0 으로 설정할 경우. close 처리시.. 상대편에서 정상 종료를 제대로 인지 못할 수 있음
// - 0 이외 정수값으로 설정할 경우.. TCP TIME_WAIT 이 발생하며... 60 sec 후 정리됨.
// - 우선 check 주기가 1 min 정도 이므로.. 많은 세션이 발생하지 않아... 1 로 설정한다.
opt_linger.l_linger = 3;
if( setsockopt( sock, SOL_SOCKET, SO_LINGER, &opt_linger, sizeof( opt_linger ) ) != 0 )
{
// 오류가 발생한 경우..
// - 관련 내역 로깅만 처리하고 check 작업은 그대로 진행한다.
errorNum = errno;
_LOG( LWAR, "[TelegrafControl] setsockopt SO_LINGER set error. [%d][%s]", errorNum, strerror( errorNum ) );
}
memset( &stTarget, 0x00, sizeof( struct sockaddr_in ) );
stTarget.sin_family = AF_INET;
stTarget.sin_port = htons( TELEGRAF_PROMETHEUS_CLIENT_PORT );
stTarget.sin_addr.s_addr = inet_addr( strTragetIp.c_str() );
// connection timeout 관련 처리
// - 접속 대상 장비가 부하 상황인 경우... connect() 함수의 block 발생
// - 이를 해결하기 위해 connection timeout 를 구현
// - non block socket 으로 만든 후.. connect 호출. select 함수를 호출하여 정상 처리 여부 확인.
/* Non Block Mode Set */
if( ( flags = fcntl( sock, F_GETFL, 0 ) ) >= 0 )
{
if( fcntl( sock, F_SETFL, flags | O_NONBLOCK ) < 0 )
{
errorNum = errno;
_LOG( LWAR, "[TelegrafControl] socket NONBLOCK set error [%d][%s]", errorNum, strerror( errorNum ) );
close( sock );
// hang check 수행하지 못했으므로.. 우선 정상 상태로 판단.
return false;
}
}
else
{
// fcntl 호출 오류시
errorNum = errno;
_LOG( LWAR, "[TelegrafControl] socket fcntl get error [%d][%s]", errorNum, strerror( errorNum ) );
close( sock );
// hang check 수행하지 못했으므로.. 우선 정상 상태로 판단.
return false;
}
// 접속 시도
result = connect( sock, (struct sockaddr *)&stTarget, sizeof( stTarget ) );
if( result < 0 )
{
// 중요 코드
// - connect 시도 후 결과를 바로 확인하지 않고... select 함수에서 결과 확인시..
// - 오류 코드 clear 발생 등의 문제로 인해...
// - 실제 접속이 되지 않았는데.. 접속된 것으로 처리 될 수 있음.
// - 이를 방지하기 위해 본 코드가 중요함.
errorNum = errno;
// non-block 모드이므로.. 처리 중인 경우 제외하고 오류로 처리.
if( errorNum != EINPROGRESS )
{
_LOG( LINF, "[TelegrafControl] telegraf connect fail.[%s][%d]->[%d][%s]"
, strTragetIp.c_str(), TELEGRAF_PROMETHEUS_CLIENT_PORT, errorNum, strerror( errorNum ) );
close( sock );
// 접속 실패이므로.. hang 으로 판단.
return true;
}
}
// 바로 접속이 된 경우...
if( result == 0 )
{
// 관련 내역 로깅
_LOG( LDBG, "[TelegrafControl] telegraf connect ok. ip[%s][%d]", strTragetIp.c_str(), TELEGRAF_PROMETHEUS_CLIENT_PORT );
}
else
{
// 바로 접속이 되지 않은 경우....
// select 함수를 이용하여 timeout 여부 확인.
// connect timeout 설정 관련 변수
fd_set selectReadFds, selectWriteFds;
struct timeval timeOver;
FD_ZERO( &selectReadFds );
FD_SET( sock, &selectReadFds );
selectWriteFds = selectReadFds;
timeOver.tv_sec = 2; /* 2 second timeout */
timeOver.tv_usec = 0;
// select 함수를 이용한 접속 결과 관련 처리.
if( select( sock + 1, &selectReadFds, &selectWriteFds, NULL, &timeOver ) == 1 )
{
errorNum = 0;
socklen_t errorLength = sizeof( errorNum );
if( getsockopt( sock, SOL_SOCKET, SO_ERROR, &errorNum, &errorLength ) == -1 )
{
// 오류 발생시.
errorNum = errno;
_LOG( LERR, "[TelegrafControl] telegraf connect fail. getsockopt SO_ERROR get error [%d][%s] ip[%s][%d]"
, errorNum, strerror( errorNum ), strTragetIp.c_str(), TELEGRAF_PROMETHEUS_CLIENT_PORT );
close( sock );
// 접속 실패로 판단하여.. hang 상태로 처리한다.
return true;
}
else
{
if( errorNum == 0 )
{
// 접속 성공시.
_LOG( LDBG, "[TelegrafControl] telegraf connect[wait] ok. ip[%s][%d]", strTragetIp.c_str(), TELEGRAF_PROMETHEUS_CLIENT_PORT );
}
else
{
// 접속 실패시.
_LOG( LINF, "[TelegrafControl] telegraf connect[wait] fail.[%s][%d]->[%d][%s]", strTragetIp.c_str(), TELEGRAF_PROMETHEUS_CLIENT_PORT, errorNum, strerror( errorNum ) );
close( sock );
// 접속 실패로 판단하여.. hang 상태로 처리한다.
return true;
}
}
}
else
{
// connect timeout or select 함수 오류 발생시
// - 접속 실패로 처리.
_LOG( LINF, "[TelegrafControl] telegraf connect timeout.[%s][%d]", strTragetIp.c_str(), TELEGRAF_PROMETHEUS_CLIENT_PORT );
close( sock );
// 접속 실패로 판단하여.. hang 상태로 처리한다.
return true;
}
}
// request 전송을 위해 socket 을 blocking 모드로 다시 전환
if( fcntl( sock, F_SETFL, flags ) < 0 )
{
errorNum = errno;
_LOG( LWAR, "[TelegrafControl] socket BLOCK set error [%d][%s]", errorNum, strerror( errorNum ) );
close( sock );
// 접속은 정상이지만... hang check 수행하지 못했으므로.. 우선 정상 상태로 판단.
return false;
}
// send time out 설정
// - request 전송시 timeout 설정 목적.
struct timeval tv_timeo = { 2, 0 };
result = setsockopt( sock, SOL_SOCKET, SO_SNDTIMEO, &tv_timeo, sizeof( tv_timeo ) );
if( result != 0 )
{
errorNum = errno;
_LOG( LERR, "[TelegrafControl] socket SO_SNDTIMEO set fail. [%d][%s]", errorNum, strerror( errorNum ) );
}
// data 전송, 수신 처리 단순화를 위해 basesocket 객체 이용
CBaseSocket basesock( sock );
// request 전송
std::string strMsg = "GET /hang_check\r\n";
long lResult = basesock.WriteN( strMsg.c_str(), strMsg.size() );
if( lResult <= 0 )
{
// 전송 실패시...
_LOG( LERR, "[TelegrafControl] telegraf request send fail. [%ld]", lResult );
basesock.Close();
// 전송 실패가 발생했으므로.. hang 상태로 판단.
return true;
}
// 수신 대기
char buffer[64];
memset( buffer, 0x00, 64 );
// HTTP/1.1 400 Bad Request 응답만 수신 시도, timeout 은 3 sec
lResult = basesock.ReadNTimeout( buffer, 24, 3 );
if( lResult <= 0 )
{
// 응답 수신 실패시....
if( lResult == -2 )
{
// timeout 발생시 명확하게 로깅 처리.
_LOG( LERR, "[TelegrafControl] telegraf response receive error. [timeout 3 sec]");
}
else
{
_LOG( LERR, "[TelegrafControl] telegraf response receive error. [%ld]", lResult );
}
basesock.Close();
// 수신 실패가 발생했으므로.. hang 상태로 판단.
return true;
}
else
{
// 정상 응답 수신한 경우..
_LOG( LDBG, "[TelegrafControl] telegraf response recevied. [%s]", buffer );
}
// 사용한 socket 종료 처리.
basesock.Close();
// telegraf 정상인 상태로 판단한다.
return false;
}
// telegraf SIGQUIT signal 전송
// - log 상에 stack trace 남기고 재기동 처리됨
// - hang 상황시.. trace 처리 후 재기동 처리하기 위한 함수.
void CTelegrafControl::ServiceQuit()
{
int pid = GetProcessId();
if( pid != 0 )
{
// telegraf 에 SIGQUIT 전송시.. log 상에 statck trace 정보 남기고.. 자동 재기동 됨..
// - hang 상태에서도 SIGQUIT 전송시.. 위의 내역대로 정상 동작함.
kill( pid, SIGQUIT );
_LOG( LINF, "[TelegrafControl] SIGQUIT send to restart telegraf[%d] in hang state.", pid );
}
else
{
_LOG( LERR, "[TelegrafControl] telegraf pid for restarting not valid. [%d]", pid );
}
return;
}
// telegraf 의 기동 후 elapsed time 정보를 추출한다.
// - ps -o etimes= -p `pgrep -x telegraf` 명령을 이용하여 추출
// - 0 인 경우.. 오류로 판단...
long long CTelegrafControl::GetProcessElapsedSec()
{
int pid = GetProcessId();
if( pid == 0 )
{
LOG( LERR, "[TelegrafControl] telegraf pid for elapsed time not valid. [%d]", pid );
// process id 정보가 유효하지 않은 경우.. 오류로 처리
return 0;
}
else
{
char tempBuffer[64];
FILE * fd = NULL;
long long llElapsedSec = 0;
snprintf( tempBuffer, sizeof( tempBuffer ), "ps -o etimes= -p %d", pid );
fd = popen( tempBuffer, "r" );
if( fd == NULL )
{
// popen 수행 실패시......
int errorNum = errno;
LOG( LERR, "[TelegrafControl] popen failed by ps -o etimes=. [%d][%s]", errorNum, strerror( errorNum ) );
// 오류 발생시 0 반환
return 0;
}
else
{
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
// 참고사항
// https://jarvis.solbox.com/redmine/issues/32973 에서 언급된 popen - fgets() 호출시 지연 발생 가능성 관련
// 서비스 자체에는 영향이 없고... 호출 빈도를 최소화하도록 조정하여....
// 사용하기로 결정함.
if( fgets( tempBuffer, sizeof( tempBuffer ) - 1, fd ) != NULL )
{
// result 값이 존재하는 경우
std::string tempResult( tempBuffer );
Trim( tempResult );
llElapsedSec = atoll( tempResult.c_str() );
_LOG( LDBG, "[TelegrafControl] %s process elapsed time %lld sec.", TELEGRAF_PROCESS_NAME, llElapsedSec );
}
pclose( fd );
}
return llElapsedSec;
}
return 0;
}
// telegraf service restart
// - ServiceStart() 함수와 마찬가지로.. service 명령어 호출시. .무조건 -1 이 반환되므로....
// - telegraf 가 정상적으로 restart 되었는지 판단 불가하여.. void 로 처리
void CTelegrafControl::ServiceRestart()
{
// 우선 binary 가 정상적으로 존재하는지 check
if( access( TELEGRAF_BINARY_FULL_PATH, X_OK ) != 0 )
{
_LOG( LWAR, "[TelegrafControl] binary[%s] not exist.", TELEGRAF_BINARY_FULL_PATH );
return;
}
// service 명령을 이용하여... telegraf 를 기동 처리한다.
// - service 명령어로 기동시... system() 호출 결과는 -1, errno=10 (No child processes) 가 반환된다.
// - 따라서 system() 호출 결과 -1 을 반환으로 인해.. telegraf 가 정상 기동되었는지 판단 불가하므로...
// - 본 함수의 반환값은 void 로 처리한다.
system( "service telegraf restart" );
_LOG( LINF, "[TelegrafControl] command \'service telegraf restart\' executed." );
return;
}
///////////////////////////////////////////////////////////////////////
void CTelegrafControl::Trim( std::string & str )
{
if( str.length() == 0 )
return;
// 문자열 뒤의 공백, TAB, CR 등의 문자 제거처리.
std::string::size_type pos = str.find_last_not_of( " \a\b\f\n\r\t\v" );
if( pos != std::string::npos )
str.erase( pos + 1 );
// 문자열 앞의 공백, TAB, CR 등의 문자 제거처리.
pos = str.find_first_not_of( " \a\b\f\n\r\t\v" );
if( pos != std::string::npos )
str.erase( 0, pos );
}
+73
View File
@@ -0,0 +1,73 @@
/****************************************************************************
Telegraf control calss
-----------------------------------------
begin : 2021/05/10
copyright : (C) 2005 Solbox Inc.
author : huibong
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __TELEGRAF_CONTROL_H__
#define __TELEGRAF_CONTROL_H__
#include <unistd.h>
#include <string>
// CTelegrafControl class
// telegraf 에 대한 alive 상태 check, 재기동 처리 등의 action 을 수행하기 위한 class
// 본 class 는 telegraf 관련 interface 만 제공하고...
// 실제 판단 및 명령은 상위 worker 프로세스 상에서 수행한다.
class CTelegrafControl
{
public:
// 생성자
CTelegrafControl();
// 소멸자
~CTelegrafControl();
// telegraf process 의 PID 정보 반환...
// - 정보 추출시 오류 또는 미동작 상황인 경우.. 0 반환
int GetProcessId();
// telegraf service start
void ServiceStart();
// telegraf hang check
bool IsHang();
// telegraf SIGQUIT signal 전송
// - log 상에 stack trace 남기고 재기동 처리됨
// - hang 상황시.. trace 처리 후 재기동 처리하기 위한 함수.
void ServiceQuit();
// telegraf 의 기동 후 elapsed time 정보를 추출한다.
// - ps -o etimes= -p `pgrep -x telegraf` 명령을 이용하여 추출
// - 0 인 경우.. 오류로 판단...
long long GetProcessElapsedSec();
// telegraf service restart
void ServiceRestart();
private:
void Trim( std::string & str );
};
#endif /* __TELEGRAF_CONTROL_H__ */
@@ -0,0 +1,425 @@
#include "WorkerMonitoringPortControl.h"
#include "ProcessConfig.h"
#include "Logger.h"
#include "FhsShm.h"
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// Service status Check 주기 (sec)
// - Service status 에 따른 Listen Port 제어 관련 Loop 주기
#define SERVICE_STATUS_CHECK_INTERVAL 2
// accept() 처리 관련 timeout (sec)
#define ACCEPT_TIMEOUT_SEC 2
// listen queue 에서 accept 대기 Count 수
// - 기본 적으로 Monitoring 용 Listen Port 이므로... 갯수를 적게 유지 처리한다.
#define DEFAULT_LISTEN_WAIT_COUNT 5
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
// Main 프로세스에서 생성 처리하며... 전역변수로 설정되어 있다.
extern CFhsShm * g_pFhsShm;
// Listener Socket
// 시그널 등의 전역 처리 문제로 전역 변수로 사용
int g_listenSocket = -1;
// Listen 처리를 위한 socket 생성
// @param listenSocket [out] 생성된 Socket 정보를 저장하기 위한 참조변수
// @return 성공시 true, 오류발생시 false 반환.
bool MakeListenSocketV6( int & listenSocket )
{
// socket 생성
listenSocket = socket( AF_INET6, SOCK_STREAM, 0 );
if( listenSocket == -1 )
{
int errorNum = errno;
LOG( LERR, "[MonPortControl] listen socket create failed. [%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
struct sockaddr_in6 listenSockAddr;
socklen_t listenSockLen = 0;
memset( &listenSockAddr, 0x00, sizeof( listenSockAddr ) );
listenSockAddr.sin6_family = AF_INET6;
listenSockAddr.sin6_flowinfo = 0;
listenSockAddr.sin6_port = htons( CProcessConfig::GetInstance()->GetListenPortForStatusMonitoring() );
listenSockAddr.sin6_addr = in6addr_any;
listenSockLen = sizeof( listenSockAddr );
int result = 0;
int opt = 0;
// socket address reuse option set
opt = 1;
result = setsockopt( listenSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof( opt ) );
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "[MonPortControl] listen socket option[SO_REUSEADDR] set failed. [%d][%s]", errorNum, strerror( errorNum ) );
close( listenSocket );
listenSocket = -1;
return false;
}
// keep alive option set
opt = 1;
result = setsockopt( listenSocket, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) );
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "[MonPortControl] listen socket option[SO_KEEPALIVE] set failed. [%d][%s]", errorNum, strerror( errorNum ) );
close( listenSocket );
listenSocket = -1;
return false;
}
// IPv6 에서 IPv4 지원을 위한 설정
opt = 0;
result = setsockopt( listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof( opt ) );
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "[MonPortControl] listen socket option[IPV6_V6ONLY] set failed. [%d][%s]", errorNum, strerror( errorNum ) );
close( listenSocket );
listenSocket = -1;
return false;
}
// socket bind
result = bind( listenSocket, ( struct sockaddr * )&listenSockAddr, listenSockLen );
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "[MonPortControl] listen socket bind failed. [%d][%s]", errorNum, strerror( errorNum ) );
close( listenSocket );
listenSocket = -1;
return false;
}
// socket listen
result = listen( listenSocket, DEFAULT_LISTEN_WAIT_COUNT );
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "[MonPortControl] listen socket listen failed. [%d][%s]", errorNum, strerror( errorNum ) );
close( listenSocket );
listenSocket = -1;
return false;
}
_LOG( LINF, "[MonPortControl] tcp port[%u] listen start."
, CProcessConfig::GetInstance()->GetListenPortForStatusMonitoring() );
return true;
}
// Listen 처리를 위한 socket close 처리
// @param listenSocket [in] listen socket 정보
void CloseListenSocket( int & listenSocket )
{
if( listenSocket != -1 )
{
close( listenSocket );
listenSocket = -1;
}
return;
}
// Worker::MonPortControl 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerMonPortControlMain()
{
setproctitle( "MonPortControl [initialize]" );
// Set Signal Handler
SetWorkerMonPortControlSignalHandler();
// Main Process 에서 생성한 공유메모리 접근 객체 유효성 확인
// NULL 인 경우... 초기화 실패로 처리한다.
if( g_pFhsShm == NULL )
{
// 객체 생성 실패시
LOG( LERR, "[MonPortControl:%d] Shared memory object not valid. process exit", getpid() );
ReadyToExitWorkerMonPortControl();
return EXIT_FAILURE;
}
// sleep 처리 관련 설정 처리
struct timespec sleepLoop;
sleepLoop.tv_sec = SERVICE_STATUS_CHECK_INTERVAL;
sleepLoop.tv_nsec = 0;
// 서비스 상태 Check 관련 변수
int iServiceStat;
time_t timeServiceCheck = 0;
struct timespec currentClock;
// select 관련 변수
struct timeval selectTimeOut;
int iSelectResult;
fd_set selectFds;
FD_ZERO( &selectFds );
// socket 처리 관련 변수
int errorNum;
char tempBuffer[INET6_ADDRSTRLEN];
int clientSocket;
struct sockaddr_in6 clientSockAddr;
socklen_t clientSockLen = sizeof( clientSockAddr );
// 전체 프로세스의 생성이 완료될때까지 대기 후 작업 시작
setproctitle( "MonPortControl [TCP %u]", CProcessConfig::GetInstance()->GetListenPortForStatusMonitoring() );
sleep( 3 );
// Listen 처리 관련 FreeBSD 10.X , 6.X 차이점
// - FB 10.X 의 경우.. listen 상태에서 accept() 를 호출하지 않아도.. neocast 에서 정상 상태로 인식
// - FB 6.X 의 경우.. neocast 에서 listen 만 하면 비정상 상태로 인식하고... accept 까지 해야 정상 상태로 인식됨.
// - 이러한 차이로 인해 accept() 를 하지 않는 방법으로 Port 제어를 하는 것으로 적합하지 않음.
// - 이에 따라 서비스 상태에 따른 Listen Socket 생성, Close 처리 방법을 사용한다.
// 주기적으로 Service Status 정보를 Check 한다.
// - 서비스 상태 Check 프로세스에서 blocking 상황 발생시
// - RCTS 전송 프로세스에서 Timeout 처리를 수행하여 서비스 상태를 Disable 로 처리한다.
// - 하지만 RCTS 전송 프로세스에서도 blocking 상황 발생하면.. 서비스 상태 변경이 안되서..
// - 모니터링 Port 관련 제어가 불가하므로... 보조적으로 RCTS 전송 프로세스에 적용한 Timeout Check 기능을 넣는다.
while( 1 )
{
iServiceStat = g_pFhsShm->GetServiceStat();
if( iServiceStat == SERVICE_STAT_DISABLE || iServiceStat == SERVICE_STAT_OUT )
{
// 서비스 상태가 out, disable 상태인 경우....
// - monitoring port close 처리한다.
if( g_listenSocket != -1 )
{
CloseListenSocket( g_listenSocket );
_LOG( LINF, "[MonPortControl] service stat [%s]. TCP monitoring port[%u] closed."
, g_pFhsShm->GetServiceStatString( iServiceStat )
, CProcessConfig::GetInstance()->GetListenPortForStatusMonitoring() );
}
// 지정된 시간동안 sleep 한 후 다시 check 수행
nanosleep( &sleepLoop, NULL );
continue;
}
else
{
// 서비스 상태가 정상인 상황인 경우...
// - 서비스 상태 check 가 정상적으로 동작 중인지 체크하여
// - 서비스 상태 check 가 blocking 상황이면.. 자체적으로 모니터링 Port 를 차단한다.
timeServiceCheck = g_pFhsShm->GetTimeServiceCheck();
if( timeServiceCheck == 0 )
{
// 아직 초기화 중인 상태
// - Port 관련 처리를 수행하지 않고.. 지정된 시간 sleep 후 다시 check 수행한다.
nanosleep( &sleepLoop, NULL );
continue;
}
else
{
// 현재 시간을 추출
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
if( timeServiceCheck < currentClock.tv_sec - TIMEOUT_SERVICE_CHECK )
{
// timeout 발생시 서비스 Disable 상태로 변경 처리
g_pFhsShm->SetServiceStat( SERVICE_STAT_DISABLE );
_LOG( LERR, "[MonPortControl] service check timeout[%d] last[%ld], current[%ld]. service stat set: %d (%s)"
, TIMEOUT_SERVICE_CHECK, timeServiceCheck, currentClock.tv_sec
, g_pFhsShm->GetServiceStat(), g_pFhsShm->GetServiceStatString() );
// 서비스 상태가 out, disable 상태이므로... monitoring port close 처리한다.
if( g_listenSocket != -1 )
{
CloseListenSocket( g_listenSocket );
_LOG( LINF, "[MonPortControl] service stat timeout changed [%s]. TCP monitoring port[%u] closed."
, g_pFhsShm->GetServiceStatString( iServiceStat )
, CProcessConfig::GetInstance()->GetListenPortForStatusMonitoring() );
}
// 지정된 시간동안 sleep 한 후 다시 check 수행
nanosleep( &sleepLoop, NULL );
continue;
}
}
}
// 서비스 상태가 정상 또는 Read Only 상태인 경우
// Listen Socket 이 이미 존재하는지 체크하여...
// - Listen Socket 가 생성되지 않은 경우 생성 처리.
if( g_listenSocket == -1 )
{
// Listen Socket 생성 처리
if( MakeListenSocketV6( g_listenSocket ) == false )
{
// Listen socket 실패시
// - 지정된 시간 대기 후 다시 실행하도록 처리
// 지정된 시간동안 sleep 한 후 다시 check 수행
nanosleep( &sleepLoop, NULL );
continue;
}
}
// client accept 처리를 수행한다.
// - accept 는 blocking 함수 이므로..
// - client 가 없는 상황에서 blocking 되면... 서비스 상태를 바로 반영할 수 없는 문제가 발생
// - 따라서... select() 함수를 사용하여 timeout 처리를 수행한다.
selectTimeOut.tv_sec = ACCEPT_TIMEOUT_SEC;
selectTimeOut.tv_usec = 0;
FD_SET( g_listenSocket, &selectFds );
iSelectResult = select( g_listenSocket + 1, &selectFds, ( fd_set * ) NULL, ( fd_set * ) NULL, &selectTimeOut );
if( iSelectResult == 0 )
{
// Timeout 인 경우
continue;
}
else if( iSelectResult > 0 )
{
// accept 처리 수행
clientSocket = accept( g_listenSocket, ( struct sockaddr * ) &clientSockAddr, &clientSockLen );
if( clientSocket == -1 )
{
// 오류 발생시
errorNum = errno;
LOG( LERR, "[MonPortControl] client accept faild. [%d][%s]", errorNum, strerror( errorNum ) );
}
else
{
// client IP 주소 추출
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
if( inet_ntop( AF_INET6, &( clientSockAddr.sin6_addr ), tempBuffer, sizeof( tempBuffer ) ) == NULL )
{
errorNum = errno;
LOG( LERR, "[MonPortControl] client inet_ntop error. [%d][%s]", errorNum, strerror( errorNum ) );
sprintf( tempBuffer, "unknown" );
}
// 관련 내역 로깅 후 monitoring 처리 socket 이므로 client 종료 처리.
_LOG( LINF, "[MonPortControl] client accepted. ip: %s", tempBuffer );
close( clientSocket );
}
}
else // select 함수 오류
{
errorNum = errno;
LOG( LERR, "[MonPortControl] listen socket select func faild. [%d][%s]", errorNum, strerror( errorNum ) );
// select 함수 오류시 listen socket 문제인 경우이므로... listen socket close 처리한다.
CloseListenSocket( g_listenSocket );
}
}
// 종료시 정리 작업 수행
ReadyToExitWorkerMonPortControl();
return EXIT_SUCCESS;
}
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerMonPortControl()
{
// listen socket close
CloseListenSocket( g_listenSocket );
// Logger 객체 종료 처리.
CLogger::Exit();
return;
}
// Worker MonPortControl 프로세스에 대한 종료 처리 수신시.
static void SignalWorkerMonPortControlTerminate( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LINF, "[MonPortControl:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
}
else
{
_LOG( LWAR, "[MonPortControl:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
}
ReadyToExitWorkerMonPortControl();
// 종료전 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
// Worker::MonPortControl Process 의 signal 처리기...
void SetWorkerMonPortControlSignalHandler()
{
sigset_t set;
struct sigaction act;
memset( &act, 0x00, sizeof( act ) );
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
sigfillset( &act.sa_mask );
// 무시 처리 signal
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
act.sa_handler = SIG_IGN;
sigaction( SIGCHLD, &act, NULL );
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SignalWorkerMonPortControlTerminate;
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
// 나머지 신호는 default 처리.
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask( SIG_SETMASK, &set, NULL );
}
@@ -0,0 +1,41 @@
/****************************************************************************
Worker::MonPortControl process main
-----------------------------------------
begin : 2018/02/09
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __WORKER_MONITORING_PORT_CONTROL_H__
#define __WORKER_MONITORING_PORT_CONTROL_H__
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
// Worker::MonPortControl 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerMonPortControlMain( void );
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerMonPortControl( void );
// Worker::MonPortControl Process 의 signal 처리기...
void SetWorkerMonPortControlSignalHandler( void );
#ifdef __cplusplus
}
#endif
#endif /* __WORKER_MONITORING_PORT_CONTROL_H__ */
+381
View File
@@ -0,0 +1,381 @@
#include "WorkerSend.h"
#include "ProcessConfig.h"
#include "Logger.h"
#include "ShmDefine.h"
#include "FhsShm.h"
#include "RctsSocket.h"
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <time.h>
// 수집된 시스템 정보 및 서비스 상태 정보의 RCTS 전송 주기.
#define SEND_INTERVAL_SYSTEM_INFO 10
#define SEND_INTERVAL_SERVICE_STATUS 4
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
// Main 프로세스에서 생성 처리하며... 전역변수로 설정되어 있다.
extern CFhsShm * g_pFhsShm;
// System 수집 정보의 RCTS 로 전송을 처리할 Thread 함수 선언. ( .h 에 선언시.. 다른 process 모듈에 포함되므로.. 이를 방지하기 위함)
void * WorkerSendSystemThread( void * arg );
// service 상태 정보의 RCTS 로 전송을 처리할 Thread 함수 선언. ( .h 에 선언시.. 다른 process 모듈에 포함되므로.. 이를 방지하기 위함)
void * WorkerSendServiceThread( void * arg );
// 생성된 각 Thread 의 초기화 실패 여부 flag
// - 초기화 실패시... 프로세스를 종료처리 하기 위함.
bool g_bThreadInitError = false;
// Worker::Send 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerSendMain()
{
setproctitle( "Send [initialize]" );
// Set Signal Handler
SetWorkerSendSignalHandler();
// Main Process 에서 생성한 공유메모리 접근 객체 유효성 확인
// NULL 인 경우... 초기화 실패로 처리한다.
if( g_pFhsShm == NULL )
{
// 객체 생성 실패시
LOG( LERR, "[Send:%d] Shared memory object not valid. process exit", getpid() );
ReadyToExitWorkerSend();
return EXIT_FAILURE;
}
// 전체 프로세스의 생성이 완료될때까지 대기 후 작업 시작
// - 시스템 정보 수집 및 서비스 체크가 1회 완료된 후 동작하도록 3 sec 간 대기 처리.
sleep( 3 );
setproctitle( "Send" );
// System 수집 정보의 RCTS 로 전송을 처리할 Thread 생성.
pthread_t threadWorkerSendSystem;
if( pthread_create( &threadWorkerSendSystem, NULL, WorkerSendSystemThread, NULL ) != 0 )
{
int errorNum = errno;
LOG( LERR, "[Send:%d] system info send thread create fail[%d][%s]. process exit", getpid(), errorNum, strerror( errorNum ) );
ReadyToExitWorkerSend();
return EXIT_FAILURE;
}
// service 상태 정보의 RCTS 로 전송을 처리할 Thread 생성.
pthread_t threadWorkerSendService;
if( pthread_create( &threadWorkerSendService, NULL, WorkerSendServiceThread, NULL ) != 0 )
{
int errorNum = errno;
LOG( LERR, "[Send:%d] service status send thread create fail[%d][%s]. process exit", getpid(), errorNum, strerror( errorNum ) );
ReadyToExitWorkerSend();
return EXIT_FAILURE;
}
// Thread 생성 및 초기화시 오류 발생 여부 확인.
// - Thread 생성 및 초기화가 완료될때까지 잠시 대기 후...
// - Thread 오류 발생시 프로세스 종료 처리.
for( int i = 0; i < 5; i++ )
{
sleep( 1 );
if( g_bThreadInitError == true )
{
LOG( LERR, "[Send:%d] send thread init fail. process exit", getpid());
ReadyToExitWorkerSend();
return EXIT_FAILURE;
}
}
// 대기
while( 1 )
{
// 할일 없어서.. 시그널 수신까지 대기 한다.
pause();
}
// 종료시 정리 작업 수행
ReadyToExitWorkerSend();
return EXIT_SUCCESS;
}
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerSend()
{
// Logger 객체 종료 처리.
CLogger::Exit();
return;
}
// Worker Send 프로세스에 대한 대한 종료 처리 수신시.
static void SignalWorkerSendTerminate( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LINF, "[Send:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
}
else
{
_LOG( LWAR, "[Send:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
}
ReadyToExitWorkerSend();
// 종료전 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
// Worker::Send Process 의 signal 처리기...
void SetWorkerSendSignalHandler()
{
sigset_t set;
struct sigaction act;
memset( &act, 0x00, sizeof( act ) );
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
sigfillset( &act.sa_mask );
// 무시 처리 signal
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
act.sa_handler = SIG_IGN;
sigaction( SIGCHLD, &act, NULL );
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SignalWorkerSendTerminate;
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
// 나머지 신호는 default 처리.
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask( SIG_SETMASK, &set, NULL );
}
// System 수집 정보의 RCTS 로 전송을 처리할 Thread
void * WorkerSendSystemThread( void * arg )
{
// 메인 함수에서 이 스레드가 종료되기를 기다리지 않게 분리
pthread_detach( pthread_self() );
_LOG( LINF, "[Send:%d] system info send thread start.", getpid() );
// RCTS 와 통신을 담당할 객체 생성 및 초기화.
CRctsSocket rcts;
if( rcts.Init( CProcessConfig::GetInstance()->GetRctsServer(),
CProcessConfig::GetInstance()->GetRctsSystemInfoPort(),
CProcessConfig::GetInstance()->GetRcId() ) == false )
{
// RCTS 소켓 초기화 실패시..
// - 로깅 후..
// - 전역 flag 에 오류 설정.
// - thread 종료 처리.
LOG( LERR, "[Send:%d] system info send thread error. rcts socket init fail", getpid());
g_bThreadInitError = true;
// Thread 종료 관련 처리.
return NULL;
}
// 시스템 수집 정보를 저장할 변수.
struct SystemInfo stSystem;
// 마지막 시스템 정보 수집 시간 정보를 저장할 변수
time_t timePrevSystemCheck = 0;
time_t timeCurrentSystemCheck = 0;
// 초기 기동시... Service 상태 check 정보 전송 후... System 정보가 전송되도록
// 약 2 sec 대기 후 전송 시작
sleep( 2 );
// 공유메모리에 저장된 System 수집 정보를 RCTS 에 주기적으로 전송.
while( 1 )
{
// 2018-02-02 CHG huibong
// - system 정보 수집시 hang 등이 발생한 경우 RCTS 로 과거 정보 전송하지 않는다. (#31701)
// -- 즉 공유메모리 상의 last check 시간 정보를 기록했다가... 해당 정보가 바뀐 경우에만 RCTS 로 전송 처리
timeCurrentSystemCheck = g_pFhsShm->GetTimeSystemCheck();
if( timeCurrentSystemCheck == 0 )
{
// 아직 초기화 중인 상태
// - 전송하지 말고.. 1 sec 정도 대기 후 다시 시도
sleep( 1 );
continue;
}
// 현재 시간 정보와 이전 시간 정보가 동일한 경우.. 전송하지 말고
if( timeCurrentSystemCheck == timePrevSystemCheck )
{
_LOG( LERR, "[RCTS send system] system collect time not changed. prev[%ld] current[%ld]. RCTS not send."
, timePrevSystemCheck, timeCurrentSystemCheck );
// 2 sec 대기 후 재시도
sleep( 2 );
continue;
}
else
{
timePrevSystemCheck = timeCurrentSystemCheck;
}
// 임시변수 초기화.
memset( &stSystem, 0x00, sizeof( struct SystemInfo ) );
// 공유메모리에 저장된 시스템 수집 정보 복사.
memcpy( &stSystem, g_pFhsShm->GetSystemInfo(), sizeof( struct SystemInfo ) );
//_LOG( LINF, "[Send:%d] system info send: mem_usage[%d] storage_avail[%ju] tcp80_est[%d]"
// , getpid(), stSystem.memory_usage, stSystem.storage_avail, stSystem.tcp_80_establish );
// System 수집 정보를 RCTS 로 전송.
// - 실패 관련 로깅은 전송 모듈에서 처리.
// - 실패했다고 해서 딱히 할일 없으므로.. 반환값 처리 안함.
rcts.SendSystemInfo( &stSystem);
// 지정된 주기마다 전송 처리.
sleep( SEND_INTERVAL_SYSTEM_INFO );
}
// Thread 종료 관련 처리.
rcts.Close();
return NULL;
}
// service 상태 정보의 RCTS 로 전송을 처리할 Thread
void * WorkerSendServiceThread( void * arg )
{
// 메인 함수에서 이 스레드가 종료되기를 기다리지 않게 분리
pthread_detach( pthread_self() );
_LOG( LINF, "[Send:%d] service status send thread start.", getpid() );
// RCTS 와 통신을 담당할 객체 생성 및 초기화.
CRctsSocket rcts;
if( rcts.Init( CProcessConfig::GetInstance()->GetRctsServer(),
CProcessConfig::GetInstance()->GetRctsServiceInfoPort(),
CProcessConfig::GetInstance()->GetRcId() ) == false )
{
// RCTS 소켓 초기화 실패시..
// - 로깅 후..
// - 전역 flag 에 오류 설정.
// - thread 종료 처리.
LOG( LERR, "[Send:%d] service status send thread error. rcts socket init fail", getpid() );
g_bThreadInitError = true;
// Thread 종료 관련 처리.
return NULL;
}
// Hostname 정보를 저장할 변수.
std::string strHostname;
// 서비스 상태 정보를 저장할 변수.
struct ServiceStatus stService;
// Disk 최대 사용률 정보를 저장할 변수.
int iStorageMaxUsage;
// 공유메모리에 저장된 Service Check start time 정보를 저장할 변수
time_t timeServiceCheck = 0;
struct timespec currentClock;
// 공유메모리에 저장된 Service 상태 정보를 RCTS 에 주기적으로 전송.
while( 1 )
{
// 2018-02-05 NEW huibong service check 관련 last check 시작 시간 timeout 기능 추가 (#31701)
// - service check 시작시 공유메모리에 시간 정보 기록
// - service check Hang 발생으로 인한 timeout 발생시 서비스 상태를 Disable 상태로 변경하여 전송
timeServiceCheck = g_pFhsShm->GetTimeServiceCheck();
if( timeServiceCheck == 0 )
{
// 아직 초기화 중인 상태
// - 전송하지 말고.. 1 sec 정도 대기 후 다시 시도
sleep( 1 );
continue;
}
else
{
// 그 외의 경우는 현재 시간을 추출하여 timeout 발생 여부 check 한다.
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
if( timeServiceCheck < currentClock.tv_sec - TIMEOUT_SERVICE_CHECK )
{
// timeout 발생시 서비스 Disable 상태로 변경 처리
g_pFhsShm->SetServiceStat( SERVICE_STAT_DISABLE );
_LOG( LERR, "[RCTS send service] service check timeout[%d] last[%ld], current[%ld]. service stat set: %d (%s)"
, TIMEOUT_SERVICE_CHECK, timeServiceCheck, currentClock.tv_sec
, g_pFhsShm->GetServiceStat(), g_pFhsShm->GetServiceStatString() );
}
}
// 임시변수 초기화.
memset( &stService, 0x00, sizeof( struct ServiceStatus ) );
iStorageMaxUsage = 0;
strHostname.clear();
// hostname 정보 저장.
strHostname = g_pFhsShm->GetHostName();
// 공유메모리에 저장된 서비스 상태 관련 정보 복사.
memcpy( &stService, g_pFhsShm->GetServiceStatus(), sizeof( struct ServiceStatus ) );
// 공유메모리에 저장된 Storage 최대 사용률 정보 복사.
iStorageMaxUsage = g_pFhsShm->GetStorageMaxUsage();
//_LOG( LINF, "[Send:%d] service status send: hostname[%s] service[%d] max_usage[%d]"
// , getpid(), strHostname.c_str(), stService.stat, iStorageMaxUsage );
// Service 상태 정보를 RCTS 로 전송.
// - 실패 관련 로깅은 전송 모듈에서 처리.
// - 실패했다고 해서 딱히 할일 없으므로.. 반환값 처리 안함.
rcts.SendServiceStatus( strHostname, &stService, iStorageMaxUsage );
// 지정된 주기마다 전송 처리.
sleep( SEND_INTERVAL_SERVICE_STATUS );
}
// Thread 종료 관련 처리.
rcts.Close();
return NULL;
}
+41
View File
@@ -0,0 +1,41 @@
/****************************************************************************
Worker::Send process main
-----------------------------------------
begin : 2015/04/22
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __WORKER_SEND_H__
#define __WORKER_SEND_H__
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
// Worker::Send 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerSendMain( void );
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerSend( void );
// Worker::Send Process 의 signal 처리기...
void SetWorkerSendSignalHandler( void );
#ifdef __cplusplus
}
#endif
#endif /* __WORKER_SEND_H__ */
+151
View File
@@ -0,0 +1,151 @@
#include "WorkerServiceCheck.h"
#include "ProcessConfig.h"
#include "Logger.h"
#include "FhsShm.h"
#include "ServiceCheck.h"
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <time.h>
// 서비스 Check 주기 (sec)
#define SERVICE_CHECK_INTERVAL 4
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
// Main 프로세스에서 생성 처리하며... 전역변수로 설정되어 있다.
extern CFhsShm * g_pFhsShm;
// Worker::ServiceCheck 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerServiceCheckMain()
{
setproctitle( "ServiceCheck [initialize]" );
// Set Signal Handler
SetWorkerServiceCheckSignalHandler();
// Main Process 에서 생성한 공유메모리 접근 객체 유효성 확인
// NULL 인 경우... 초기화 실패로 처리한다.
if( g_pFhsShm == NULL )
{
// 객체 생성 실패시
LOG( LERR, "[ServiceCheck:%d] Shared memory object not valid. process exit", getpid() );
ReadyToExitWorkerServiceCheck();
return EXIT_FAILURE;
}
// Service 상태 Check를 담당할 객체 생성 및 초기화.
CServiceCheck serviceCheck( g_pFhsShm );
if( serviceCheck.Init( CProcessConfig::GetInstance()->GetSvcNic()
, CProcessConfig::GetInstance()->GetCheckDns()
, CProcessConfig::GetInstance()->GetFimngdCheckPort() ) == false )
{
// 객체 초기화 실패시
LOG( LERR, "[ServiceCheck:%d] service check module init fail. process exit", getpid() );
ReadyToExitWorkerServiceCheck();
return EXIT_FAILURE;
}
// 전체 프로세스의 생성이 완료될때까지 대기 후 작업 시작
sleep( 1 );
setproctitle( "ServiceCheck" );
// 최초 기동시 서비스 상태는 수동 중지(1) 상태로 설정한다.
// - Main 프로세스에서 공유메모리 초기화 작업시 처리함.
// g_pFhsShm->SetServiceStat( SERVICE_STAT_OUT );
// 주기적으로 Service 상태를 점검 처리한다.
while( 1 )
{
// Service Check Start time 정보를 공유 메모리에 업데이트 (#31701)
// - Check 시 Hang 발생을 탐지할 수 있도록 expire 처리를 위한 시간값 업데이트 기능 추가
g_pFhsShm->UpdateTimeServiceCheck();
// Service 상태 Check 수행.
serviceCheck.Check();
// 지정된 시간동안 sleep
sleep( SERVICE_CHECK_INTERVAL );
}
// 종료시 정리 작업 수행
ReadyToExitWorkerServiceCheck();
return EXIT_SUCCESS;
}
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerServiceCheck()
{
// Logger 객체 종료 처리.
CLogger::Exit();
return;
}
// Worker ServiceCheck 프로세스에 대한 대한 종료 처리 수신시.
static void SignalWorkerServiceCheckTerminate( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LINF, "[ServiceCheck:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
}
else
{
_LOG( LWAR, "[ServiceCheck:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
}
ReadyToExitWorkerServiceCheck();
// 종료전 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
// Worker::ServiceCheck Process 의 signal 처리기...
void SetWorkerServiceCheckSignalHandler()
{
sigset_t set;
struct sigaction act;
memset( &act, 0x00, sizeof( act ) );
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
sigfillset( &act.sa_mask );
// 무시 처리 signal
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
act.sa_handler = SIG_IGN;
sigaction( SIGCHLD, &act, NULL );
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SignalWorkerServiceCheckTerminate;
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
// 나머지 신호는 default 처리.
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask( SIG_SETMASK, &set, NULL );
}
+42
View File
@@ -0,0 +1,42 @@
/****************************************************************************
Worker::ServiceCheck process main
-----------------------------------------
begin : 2015/04/22
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __WORKER_SERVICE_CHECK_H__
#define __WORKER_SERVICE_CHECK_H__
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
// Worker::ServiceCheck 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerServiceCheckMain( void );
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerServiceCheck( void );
// Worker::ServiceCheck Process 의 signal 처리기...
void SetWorkerServiceCheckSignalHandler( void );
#ifdef __cplusplus
}
#endif
#endif /* __WORKER_SERVICE_CHECK_H__ */
+156
View File
@@ -0,0 +1,156 @@
#include "WorkerStorageCheck.h"
#include "ProcessConfig.h"
#include "Logger.h"
#include "FhsShm.h"
#include "StorageCheck.h"
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <time.h>
// Storage status Check 주기 (sec)
// - service check 모듈에서 30 sec timeout 처리
// - 1회 Check 당 sleep 등으로 인해 2 sec 미만 시간 소요
// - 따라서 8 sec 마다 check 하도록 설정함.
#define STORAGE_CHECK_INTERVAL 8
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
// Main 프로세스에서 생성 처리하며... 전역변수로 설정되어 있다.
extern CFhsShm * g_pFhsShm;
// Worker::StorageCheck 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerStorageCheckMain()
{
setproctitle( "StorageCheck [initialize]" );
// Set Signal Handler
SetWorkerStorageCheckSignalHandler();
// Main Process 에서 생성한 공유메모리 접근 객체 유효성 확인
// NULL 인 경우... 초기화 실패로 처리한다.
if( g_pFhsShm == NULL )
{
// 객체 생성 실패시
LOG( LERR, "[StorageCheck:%d] Shared memory object not valid. process exit", getpid() );
ReadyToExitWorkerStorageCheck();
return EXIT_FAILURE;
}
// Storage status check 작업을 수행할 객체 생성 및 초기화
CStorageCheck storageCheck( g_pFhsShm );
if( storageCheck.Init( CProcessConfig::GetInstance()->GetStorageRoot() ) == false )
{
// 객체 생성 실패시
LOG( LERR, "[StorageCheck:%d] storage check module init fail. process exit", getpid() );
ReadyToExitWorkerStorageCheck();
return EXIT_FAILURE;
}
// 전체 프로세스의 생성이 완료될때까지 대기 후 작업 시작
sleep( 1 );
setproctitle( "StorageCheck" );
struct timespec sleepLoop;
sleepLoop.tv_sec = STORAGE_CHECK_INTERVAL;
sleepLoop.tv_nsec = 0;
// 실제 Storage Check 수행 전 공유메모리 값에 현재 시간 정보 기록 처리
// - timeout 처리시 사용할 수 있도록 초기화 시키기 위함
g_pFhsShm->UpdateTimeStorageCheck( true );
// Check 결과 정보 저장을 위한 변수.
bool bCheckResult;
// 주기적으로 Storage 상태를 점검 처리한다.
while( 1 )
{
// Storage 상태 Check 수행.
bCheckResult = storageCheck.Check( CProcessConfig::GetInstance()->GetStorageRoot() );
// Check 결과에 따른 공유메모리 업데이트 작업 수행
// - 위의 check() 함수가 hang 걸릴 경우 아래 시간 업데이트 못하므로.. expire 기능 필요.
g_pFhsShm->UpdateTimeStorageCheck( bCheckResult );
// 지정된 시간동안 sleep
nanosleep( &sleepLoop, NULL );
}
// 종료시 정리 작업 수행
ReadyToExitWorkerStorageCheck();
return EXIT_SUCCESS;
}
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerStorageCheck()
{
// Logger 객체 종료 처리.
CLogger::Exit();
return;
}
// Worker StorageCheck 프로세스에 대한 대한 종료 처리 수신시.
static void SignalWorkerStorageCheckTerminate( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LINF, "[StorageCheck:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
}
else
{
_LOG( LWAR, "[StorageCheck:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
}
ReadyToExitWorkerStorageCheck();
// 종료전 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
// Worker::StorageCheck Process 의 signal 처리기...
void SetWorkerStorageCheckSignalHandler()
{
sigset_t set;
struct sigaction act;
memset( &act, 0x00, sizeof( act ) );
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
sigfillset( &act.sa_mask );
// 무시 처리 signal
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
act.sa_handler = SIG_IGN;
sigaction( SIGCHLD, &act, NULL );
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SignalWorkerStorageCheckTerminate;
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
// 나머지 신호는 default 처리.
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask( SIG_SETMASK, &set, NULL );
}
+41
View File
@@ -0,0 +1,41 @@
/****************************************************************************
Worker::StorageCheck process main
-----------------------------------------
begin : 2018/01/29
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __WORKER_STORAGE_CHECK_H__
#define __WORKER_STORAGE_CHECK_H__
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
// Worker::StorageCheck 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerStorageCheckMain( void );
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerStorageCheck( void );
// Worker::StorageCheck Process 의 signal 처리기...
void SetWorkerStorageCheckSignalHandler( void );
#ifdef __cplusplus
}
#endif
#endif /* __WORKER_STORAGE_CHECK_H__ */
+237
View File
@@ -0,0 +1,237 @@
#include "WorkerSystemCollect.h"
#include "ProcessConfig.h"
#include "Logger.h"
#include "FhsShm.h"
#include "SystemInfo.h"
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <time.h>
// 시스템 정보 추출 주기 (sec)
#define SYSTEM_COLLECT_INTERVAL 10
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
// Main 프로세스에서 생성 처리하며... 전역변수로 설정되어 있다.
extern CFhsShm * g_pFhsShm;
// Worker::SystemCollect 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerSystemCollectMain()
{
setproctitle( "SystemCollect [initialize]" );
// Set Signal Handler
SetWorkerSystemCollectSignalHandler();
// Main Process 에서 생성한 공유메모리 접근 객체 유효성 확인
// NULL 인 경우... 초기화 실패로 처리한다.
if( g_pFhsShm == NULL )
{
// 객체 생성 실패시
LOG( LERR, "[SystemCollect:%d] Shared memory object not valid. process exit", getpid() );
ReadyToExitWorkerSystemCollect();
return EXIT_FAILURE;
}
// system info 수집을 담당할 객체 생성 및 초기화.
CSystemInfo systemInfo( g_pFhsShm );
if( systemInfo.Init() == false )
{
// 객체 초기화 실패시
LOG( LERR, "[SystemCollect:%d] system info collect module init fail. process exit", getpid() );
ReadyToExitWorkerSystemCollect();
return EXIT_FAILURE;
}
// 전체 프로세스의 생성이 완료될때까지 대기 후 작업 시작
sleep( 1 );
setproctitle( "SystemCollect" );
// 최초 기동인지 여부
bool bFirstLoop = true;
struct timespec timeStart; // 소요시간 측정을 위한 멤버변수
struct timespec timeEnd; // 소요시간 측정을 위한 멤버변수
double dElapsedTime; // 소요시간 측정을 위한 멤버변수
// 주기적으로 시스템 정보를 추출한다.
while( 1 )
{
// check start time
clock_gettime( CLOCK_MONOTONIC, &timeStart );
// System Check Start time 정보를 공유 메모리에 업데이트 (#31701)
// - 정보 수집 Hang 발생을 탐지할 수 있도록 expire 처리를 위한 시간값 업데이트 기능 추가
g_pFhsShm->UpdateTimeSystemCheck();
// hostname
// - 추출 실패시.. 업무 규약에 따라 프로세스 종료 처리
// - shared memory 설정 실패시.. 업무 규약에 따라 프로세스 종료 처리
if( systemInfo.GetHostname() == false )
{
LOG( LERR, "[System] hostname collect fail. => Process exit" );
ReadyToExitWorkerSystemCollect();
return EXIT_FAILURE;
}
_LOG( LINF, "[System] hostname collect passed." );
// load average
systemInfo.GetLoadAverage();
_LOG( LINF, "[System] load average collect passed." );
// total memory
// - 최초 loop 시에만 정보 수집 ( 오류발생시 프로세스 종료 처리)
if( bFirstLoop == true )
{
if( systemInfo.GetMemoryTotal() == false )
{
LOG( LERR, "[System] total memory collect fail. => Process exit" );
ReadyToExitWorkerSystemCollect();
return EXIT_FAILURE;
}
_LOG( LINF, "[System] total memory collect passed." );
}
// free memory
systemInfo.GetMemoryFree();
_LOG( LINF, "[System] free memory collect passed." );
// swap
systemInfo.GetSwap();
_LOG( LINF, "[System] swap memory collect passed." );
// mount
systemInfo.GetMount( CProcessConfig::GetInstance()->GetStorageRoot() );
_LOG( LINF, "[System] storage mount & size info collect passed." );
// disk status
// - queue length, busy
systemInfo.GetDiskStatus();
_LOG( LINF, "[System] disk busy info collect passed." );
// network status
systemInfo.GetNetworkStatus();
_LOG( LINF, "[System] network status collect passed." );
// tcp session count
systemInfo.GetTcpSession();
_LOG( LINF, "[System] tcp session collect passed." );
// Debug 인 경우에만.. 로그상에 shared memory 내역 출력 처리
//if( CLogger::GetInstance()->GetLogLevel() == LDBG )
// g_pFhsShm->Print();
/////////////////////////////////////
// check end time
clock_gettime( CLOCK_MONOTONIC, &timeEnd );
// 작업 소요 시간 계산
dElapsedTime = timeEnd.tv_sec - timeStart.tv_sec;
dElapsedTime += ( timeEnd.tv_nsec - timeStart.tv_nsec ) * 1e-9;
_LOG( LINF, "[System] collect end. total elapsed time: %.3lf sec.", dElapsedTime );
// 공유메모리 설정 내역을 로그 파일에 기록 처리한다.
// - 본 루프가 SYSTEM_COLLECT_INTERVAL 간격으로 동작하므로.. 로깅 처리하기에 가장 적당하다고 판단됨.
g_pFhsShm->Print();
// loop 1회 실행했으므로.. 최초 loop 플래그를 false 로 변경.
if( bFirstLoop == true )
bFirstLoop = false;
// 지정된 시간동안 sleep
sleep( SYSTEM_COLLECT_INTERVAL );
}
// 종료시 정리 작업 수행
ReadyToExitWorkerSystemCollect();
return EXIT_SUCCESS;
}
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerSystemCollect()
{
// Logger 객체 종료 처리.
CLogger::Exit();
return;
}
// Worker SystemCollect 프로세스에 대한 대한 종료 처리 수신시.
static void SignalWorkerSystemCollectTerminate( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LINF, "[SystemCollect:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
}
else
{
_LOG( LWAR, "[SystemCollect:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
}
ReadyToExitWorkerSystemCollect();
// 종료전 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
// Worker::SystemCollect Process 의 signal 처리기...
void SetWorkerSystemCollectSignalHandler()
{
sigset_t set;
struct sigaction act;
memset( &act, 0x00, sizeof( act ) );
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
sigfillset( &act.sa_mask );
// 무시 처리 signal
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
act.sa_handler = SIG_IGN;
sigaction( SIGCHLD, &act, NULL );
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SignalWorkerSystemCollectTerminate;
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
// 나머지 신호는 default 처리.
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask( SIG_SETMASK, &set, NULL );
}
+42
View File
@@ -0,0 +1,42 @@
/****************************************************************************
Worker::SystemCollect process main
-----------------------------------------
begin : 2015/04/22
copyright : (C) 2005 Solbox Inc.
author : Dev Storage Team
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __WORKER_SYSTEM_COLLECT_H__
#define __WORKER_SYSTEM_COLLECT_H__
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
// Worker::SystemCollect 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerSystemCollectMain( void );
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerSystemCollect( void );
// Worker::SystemCollect Process 의 signal 처리기...
void SetWorkerSystemCollectSignalHandler( void );
#ifdef __cplusplus
}
#endif
#endif /* __WORKER_SYSTEM_COLLECT_H__ */
+225
View File
@@ -0,0 +1,225 @@
#include "WorkerTelegrafControl.h"
#include "Logger.h"
#include "TelegrafControl.h"
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <syslog.h>
// Telegraf check 주기 (sec)
#define TELEGRAF_CHECK_INTERVAL 60
// telegraf 미기동 상태가 지정된 횟수 이상인 경우.. 기동 처리 수행
// - 운영자 요청으로 10분 초과 미기동 상태인 경우.. 자동 기동 처리
#define TELEGRAF_NO_ACTIVE_COUNT_MAX 10
// telegraf 가 hang 상태 관련 지정된 횟수 이상인 경우.. 재기동 처리 수행
#define TELEGRAF_HANG_COUNT_MAX 2
// telegraf 의 MAX 기동 시간 (sec)
// - telegraf 기동 후 elapsed time 이 현재 설정값을 초과하는 경우.. 재기동 처리를 수행한다.
// - 이는 telegraf 장기 운영시.. 삭제된 log 파일을 tail 에서 붙잡고 있어.... OS Disk full 상황을 방지하기 위함
// - 운영자 의견 수렴 결과.. 2일 단위로 재기동 요청.
#define TELEGRAF_ELAPSED_TIME_MAX 172800LL
// Worker::TelegrafControl 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerTelegrafControlMain( void )
{
setproctitle( "TelegrafControl [initialize]" );
// Set signal handler
SetWorkerTelegrafControlSignalHandler();
// telegraf control 객체 생성
CTelegrafControl telegraf;
// 전체 프로세스의 생성이 완료될때까지 대기 후 작업 시작
sleep( 2 );
setproctitle( "TelegrafControl" );
int iProcessId = 0;
int iProcessNotActiveCount = 0;
int iProcessHangCount = 0;
long long llProcessElapsedSec = 0;
// 주기적으로 telegraf 상태를 점검한다.
while( 1 )
{
// 지정된 시간동안 sleep 처리
sleep( TELEGRAF_CHECK_INTERVAL );
_LOG( LDBG, "[TelegrafControl:%d] check start.", getpid() );
// 1. process 기동 여부 check
iProcessId = telegraf.GetProcessId();
if( iProcessId == 0 )
{
// 미기동 상태인 경우
// - 패치 및 설정 등의 작업으로 인해 미기동 상태일 수 있으므로......
// - 미기동 상태가 지정된 횟수 이상인 경우에만.. 기동 처리를 시도한다.
++iProcessNotActiveCount;
if( iProcessNotActiveCount > TELEGRAF_NO_ACTIVE_COUNT_MAX )
{
_LOG( LINF, "[TelegrafControl:%d] telegraf process not found. try starting.", getpid() );
// 지정 횟수 초과의 미기동 상태인 경우... 기동 처리 try...
telegraf.ServiceStart();
// telegraf 기동을 시도했으므로... count 는 초기화 처리한다.
iProcessNotActiveCount = 0;
}
else
{
_LOG( LINF, "[TelegrafControl:%d] telegraf process not found. count[%d]", getpid(), iProcessNotActiveCount );
}
// telegraf 상태 처음부터 다시 check.
continue;
}
// telegraf 기동 중인 상태인 경우 not active count 초기화
iProcessNotActiveCount = 0;
// 2. process hang check
// - hang 상황인 경우... 재기동 처리
if( telegraf.IsHang() == true )
{
// telegraf hang 상황인 경우...
++iProcessHangCount;
if( iProcessHangCount > TELEGRAF_HANG_COUNT_MAX )
{
_LOG( LINF, "[TelegrafControl:%d] telegraf[%d] hang detected. try restarting.", getpid(), iProcessId );
// 지정 횟수 초과의 hang 상태인 경우... 재기동 처리 try...
telegraf.ServiceQuit();
// telegraf 재기동을 시도했으므로... count 는 초기화 처리한다.
iProcessHangCount = 0;
// 관련 사항은 /var/log/message 상에 기록해 둔다.
openlog( PROG_NAME, LOG_PID, LOG_USER );
syslog( LOG_WARNING, "telegraf[%d] hang detected. SIGQUIT send for telegraf restart.", iProcessId );
closelog();
}
else
{
_LOG( LINF, "[TelegrafControl:%d] telegraf[%d] is hang. count[%d]", getpid(), iProcessId, iProcessHangCount );
}
// telegraf 상태 처음부터 다시 check.
continue;
}
// telegraf hang count 초기화
iProcessHangCount = 0;
// 3. process 기동 후 지정된 시간 이상 되었는지 check
// - 지정된 시간 초과시 재기동 처리
// - ps -o etimes= -p `pgrep telegraf`
// - sec 단위
llProcessElapsedSec = telegraf.GetProcessElapsedSec();
if( llProcessElapsedSec > TELEGRAF_ELAPSED_TIME_MAX )
{
_LOG( LINF, "[TelegrafControl:%d] telegraf[%d] elapsed time too long [%lld / %lld sec]. try restarting."
, getpid(), iProcessId, llProcessElapsedSec, TELEGRAF_ELAPSED_TIME_MAX );
// 재기동 처리 시도
telegraf.ServiceRestart();
// telegraf 상태 처음부터 다시 check.
continue;
}
// 4. 기타
}
// 종료시 정리 작업 수행
ReadyToExitWorkerTelegrafControl();
return EXIT_SUCCESS;
}
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerTelegrafControl( void )
{
// Logger 객체 종료 처리
CLogger::Exit();
return;
}
// Worker TelegrafControl 프로세스에 대한 종료 처리 수신시
static void SignalWorkerTelegrafControlTerminate( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LINF, "[TelegrafControl:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
}
else
{
_LOG( LWAR, "[TelegrafControl:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
}
ReadyToExitWorkerTelegrafControl();
// 종료전 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
// Worker::TelegrafControl Process 의 signal 처리기...
void SetWorkerTelegrafControlSignalHandler( void )
{
sigset_t set;
struct sigaction act;
memset( &act, 0x00, sizeof( act ) );
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
sigfillset( &act.sa_mask );
// 무시 처리 signal
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
act.sa_handler = SIG_IGN;
sigaction( SIGCHLD, &act, NULL );
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SignalWorkerTelegrafControlTerminate;
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
// 나머지 신호는 default 처리.
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask( SIG_SETMASK, &set, NULL );
}
+42
View File
@@ -0,0 +1,42 @@
/****************************************************************************
Worker::TelegrafControl process main
-----------------------------------------
begin : 2021/05/07
copyright : (C) 2005 Solbox Inc.
author : huibong
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __WORKER_TELEGRAF_CONTROL_H__
#define __WORKER_TELEGRAF_CONTROL_H__
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
// Worker::TelegrafControl 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerTelegrafControlMain( void );
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerTelegrafControl( void );
// Worker::TelegrafControl Process 의 signal 처리기...
void SetWorkerTelegrafControlSignalHandler( void );
#ifdef __cplusplus
}
#endif
#endif /* __WORKER_TELEGRAF_CONTROL_H__ */
+5
View File
@@ -0,0 +1,5 @@
// sample 소스 파일
#include ""
+32
View File
@@ -0,0 +1,32 @@
/****************************************************************************
rc_apid header
-----------------------------------------
begin : 2021/03/09
copyright : (C) 2005 Solbox Inc.
author : huibong
email : huibong@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __APID_DATA_H__
#define __APID_DATA_H__
#include <>
// class 설명
class C
{
};
#endif /* __APID_DATA_H__ */
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
#
# Description : process compile test by huibong
#
PROG_NAME=csagentd
killall $PROG_NAME
gmake clean
killall $PROG_NAME
gmake
sleep 1
#./$PROG_NAME -c ../fhs.conf
./$PROG_NAME
sleep 1
ps aux | grep $PROG_NAME | grep -v grep | grep -v tail