From 62992c1a0e04e60dd7ca2f51252e30fc79ac760e Mon Sep 17 00:00:00 2001 From: Deon George Date: Mon, 6 Oct 2014 21:57:54 +1100 Subject: [PATCH] Initial commit --- .gitmodules | 6 + .htaccess | 21 + application/bootstrap.php | 187 ++++ application/classes/Config.php | 65 ++ .../classes/Controller/User/Welcome.php | 71 ++ application/classes/Controller/Welcome.php | 19 + application/classes/Cookie.php | 15 + application/classes/Model/Setup.php | 150 ++++ application/classes/Site.php | 21 + application/config/config.php | 8 + application/config/database.php | 31 + application/config/session.php | 18 + application/views/account/user/edit.php | 61 ++ application/views/pages/welcome.php | 11 + includes/kohana | 1 + index.php | 131 +++ modules/lnapp | 1 + modules/tsm/classes/Database/Result.php | 4 + modules/tsm/classes/Database/TSM.php | 4 + modules/tsm/classes/Database/TSM/Result.php | 4 + modules/tsm/classes/Database/Tsm/dsmadmc.php | 4 + modules/tsm/classes/Model/ADMIN.php | 4 + modules/tsm/classes/Model/NODE.php | 4 + modules/tsm/classes/ORM/TSM.php | 174 ++++ modules/tsm/classes/SystemMessage.php | 21 + modules/tsm/classes/TSM.php | 4 + modules/tsm/classes/lnApp/Database/Result.php | 62 ++ modules/tsm/classes/lnApp/Database/TSM.php | 113 +++ .../tsm/classes/lnApp/Database/TSM/Result.php | 48 ++ .../classes/lnApp/Database/Tsm/dsmadmc.php | 185 ++++ modules/tsm/classes/lnApp/Model/ADMIN.php | 32 + modules/tsm/classes/lnApp/Model/NODE.php | 798 ++++++++++++++++++ modules/tsm/classes/lnApp/TSM.php | 38 + modules/tsm/config/database.php | 78 ++ modules/tsm/config/tsm.php | 18 + 35 files changed, 2412 insertions(+) create mode 100644 .gitmodules create mode 100644 .htaccess create mode 100644 application/bootstrap.php create mode 100644 application/classes/Config.php create mode 100644 application/classes/Controller/User/Welcome.php create mode 100644 application/classes/Controller/Welcome.php create mode 100644 application/classes/Cookie.php create mode 100644 application/classes/Model/Setup.php create mode 100644 application/classes/Site.php create mode 100644 application/config/config.php create mode 100644 application/config/database.php create mode 100644 application/config/session.php create mode 100644 application/views/account/user/edit.php create mode 100644 application/views/pages/welcome.php create mode 160000 includes/kohana create mode 100644 index.php create mode 160000 modules/lnapp create mode 100644 modules/tsm/classes/Database/Result.php create mode 100644 modules/tsm/classes/Database/TSM.php create mode 100644 modules/tsm/classes/Database/TSM/Result.php create mode 100644 modules/tsm/classes/Database/Tsm/dsmadmc.php create mode 100644 modules/tsm/classes/Model/ADMIN.php create mode 100644 modules/tsm/classes/Model/NODE.php create mode 100644 modules/tsm/classes/ORM/TSM.php create mode 100644 modules/tsm/classes/SystemMessage.php create mode 100644 modules/tsm/classes/TSM.php create mode 100644 modules/tsm/classes/lnApp/Database/Result.php create mode 100644 modules/tsm/classes/lnApp/Database/TSM.php create mode 100644 modules/tsm/classes/lnApp/Database/TSM/Result.php create mode 100644 modules/tsm/classes/lnApp/Database/Tsm/dsmadmc.php create mode 100644 modules/tsm/classes/lnApp/Model/ADMIN.php create mode 100644 modules/tsm/classes/lnApp/Model/NODE.php create mode 100644 modules/tsm/classes/lnApp/TSM.php create mode 100644 modules/tsm/config/database.php create mode 100644 modules/tsm/config/tsm.php diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e049bb7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "includes/kohana"] + path = includes/kohana + url = /afs/local/git/lnkohana +[submodule "modules/lnapp"] + path = modules/lnapp + url = /afs/local/git/lnapp diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..79d1513 --- /dev/null +++ b/.htaccess @@ -0,0 +1,21 @@ +# Turn on URL rewriting +RewriteEngine On + +# Installation directory +RewriteBase /tsmac + +# Protect hidden files from being viewed + + Order Deny,Allow + Deny From All + + +# Protect application and system files from being viewed +RewriteRule ^(?:application|modules|includes/kohana)\b.* index.php/$0 [L] + +# Allow any files or directories that exist to be displayed directly +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d + +# Rewrite all other URLs to index.php/URL +RewriteRule .* index.php/$0 [PT] diff --git a/application/bootstrap.php b/application/bootstrap.php new file mode 100644 index 0000000..3a060c4 --- /dev/null +++ b/application/bootstrap.php @@ -0,0 +1,187 @@ +" + */ + +/** + * Set the environment status by the domain. + */ +Kohana::$environment = (! isset($_SERVER['SERVER_NAME']) OR in_array($_SERVER['SERVER_NAME'],$SERVER_NAMES)) ? Kohana::PRODUCTION : Kohana::DEVELOPMENT; + +if (isset($_SERVER['KOHANA_ENV'])) +{ + Kohana::$environment = constant('Kohana::'.strtoupper($_SERVER['KOHANA_ENV'])); +} + +/** + * Initialize Kohana, setting the default options. + * + * The following options are available: + * + * - string base_url path, and optionally domain, of your application NULL + * - string index_file name of your index file, usually "index.php" index.php + * - string charset internal character set used for input and output utf-8 + * - string cache_dir set the internal cache directory APPPATH/cache + * - integer cache_life lifetime, in seconds, of items cached 60 + * - boolean errors enable or disable error handling TRUE + * - boolean profile enable or disable internal profiling TRUE + * - boolean caching enable or disable internal caching FALSE + * - boolean expose set the X-Powered-By header FALSE + */ +Kohana::init(array( + 'base_url' => Kohana::$environment === Kohana::PRODUCTION ? '/tsmac' : '/tsmac', + 'caching' => Kohana::$environment === Kohana::PRODUCTION, + 'profile' => Kohana::$environment !== Kohana::PRODUCTION, + 'index_file' => FALSE, +)); + +/** + * Attach the file write to logging. Multiple writers are supported. + */ +Kohana::$log->attach(new Log_File(APPPATH.'logs')); + +/** + * Attach a file reader to config. Multiple readers are supported. + */ +Kohana::$config->attach(new Config_File); + +/** + * Enable modules. Modules are referenced by a relative or absolute path. + */ +Kohana::modules(array( + 'tsm' => MODPATH.'tsm', // TSM Module + // 'lnauth' => MODPATH.'lnauth', // lnAuth Base Authentication Tools + 'lnapp' => MODPATH.'lnapp', // lnApp Base Application Tools + // 'oauth' => MODPATH.'oauth', // OAuth Module for External Authentication + 'auth' => SMDPATH.'auth', // Basic authentication + // 'cache' => SMDPATH.'cache', // Caching with multiple backends + // 'cron' => SMDPATH.'cron', // Kohana Cron Module + // 'codebench' => SMDPATH.'codebench', // Benchmarking tool + 'database' => SMDPATH.'database', // Database access + // 'gchart' => MODPATH.'gchart', // Google Chart Module + // 'highchart' => MODPATH.'highchart', // Highcharts Chart Module + // 'image' => SMDPATH.'image', // Image manipulation + 'khemail' => SMDPATH.'khemail', // Email module for Kohana 3 PHP Framework + // 'minion' => SMDPATH.'minion', // CLI Tasks + 'orm' => SMDPATH.'orm', // Object Relationship Mapping + // 'pagination' => SMDPATH.'pagination', // Kohana Pagination module for Kohana 3 PHP Framework + // 'unittest' => SMDPATH.'unittest', // Unit testing + // 'userguide' => SMDPATH.'userguide', // User guide and API documentation + // 'xml' => SMDPATH.'xml', // XML module for Kohana 3 PHP Framework + )); + +/** + * Load our modules defined in the DB + */ +#Kohana::modules(array_merge(Kohana::modules(),Config::modules())); + +/** + * Enable specalised interfaces + */ +Route::set('sections', '/(/(/(/)))', + array( + 'directory' => '('.implode('|',array_values(URL::$method_directory)).')' + )) + ->defaults(array( + 'action' => 'index', + )); + +// Static file serving (CSS, JS, images) +Route::set('default/media', 'media(/)', array('file' => '.+')) + ->defaults(array( + 'controller' => 'media', + 'action' => 'get', + )); + +/** + * Set the routes. Each route must have a minimum of a name, a URI and a set of + * defaults for the URI. + */ +Route::set('default', '((/(/)))', array('id'=>'[a-zA-Z0-9_.-]+')) + ->defaults(array( + 'controller' => 'welcome', + 'action' => 'index', + )); + +/** + * If APC is enabled, and we need to clear the cache + */ +if (file_exists(APPPATH.'cache/CLEAR_APC_CACHE') AND function_exists('apc_clear_cache') AND (PHP_SAPI !== 'cli')) { + if (! apc_clear_cache() OR ! unlink(APPPATH.'cache/CLEAR_APC_CACHE')) + throw new Kohana_Exception('Unable to clear the APC cache.'); +} + +// If we are a CLI, set our session dir +if (PHP_SAPI === 'cli') + session_save_path('tmp/'); +?> diff --git a/application/classes/Config.php b/application/classes/Config.php new file mode 100644 index 0000000..e66aba2 --- /dev/null +++ b/application/classes/Config.php @@ -0,0 +1,65 @@ +load('debug')->email_admin_only; + + if (is_null($config) OR ! is_array($config) OR empty($config[$template])) + return FALSE; + else + return $config[$template]; + } +} +?> diff --git a/application/classes/Controller/User/Welcome.php b/application/classes/Controller/User/Welcome.php new file mode 100644 index 0000000..68af41d --- /dev/null +++ b/application/classes/Controller/User/Welcome.php @@ -0,0 +1,71 @@ +where('EMAIL_ADDRESS','=',$this->ao->email)->find_all(); + if (! $n->count()) + $output = 'You have no currently registered ADMINs, would you like to '.HTML::anchor(URL::link('user','admin/add'),'Register').' one?'; + else + $output = Table::factory() + ->data($n) + ->columns(array( + 'ADMIN_NAME'=>'Admin', + 'REG_TIME'=>'Registered', + 'PWSET_TIME'=>'PW Reset', + 'LASTACC_TIME'=>'Last Access', + 'LOCKED'=>'Locked', + )) + ->prepend(array( + 'id'=>array('url'=>URL::link('user','admin/edit/')), + )); + + Block::factory() + ->title(sprintf('Your ADMINs in TSMs : %s',$this->ao->name())) + ->title_icon('icon-info-sign') + ->span(9) + ->body($output); + + $n = ORM::factory('NODE')->where('EMAIL_ADDRESS','=',$this->ao->email)->find_all(); + if (! $n->count()) + $output = 'You have no currently registered NODES, would you like to '.HTML::anchor(URL::link('user','node/add'),'Register').' one?'; + else + $output = Table::factory() + ->data($n) + ->columns(array( + 'NODE_NAME'=>'Node', + 'REG_TIME'=>'Registered', + 'version()'=>'Version', + 'PWSET_TIME'=>'PW Reset', + 'LASTACC_TIME'=>'Last Access', + )) + ->prepend(array( + 'id'=>array('url'=>URL::link('user','node/edit/')), + )); + + Block::factory() + ->title(sprintf('Your NODES in TSMs : %s',$this->ao->name())) + ->title_icon('icon-info-sign') + ->span(9) + ->body($output); + +/* + Block::factory() + ->title('Quick Shortcuts') + ->title_icon('icon-bookmark') + ->span(3) + ->body(View::factory('welcome/user/shortcuts')); +*/ + } +} +?> diff --git a/application/classes/Controller/Welcome.php b/application/classes/Controller/Welcome.php new file mode 100644 index 0000000..9e82ace --- /dev/null +++ b/application/classes/Controller/Welcome.php @@ -0,0 +1,19 @@ +load('config')->appname) + throw HTTP_Exception::factory(500,'Site not setup!'); + + $output = ''; + + $output = View::factory('pages/welcome'); + Style::factory() + ->type('file') + ->data('media/css/pages/welcome.css'); + + $this->template->content = $output; + } +} // End Welcome diff --git a/application/classes/Cookie.php b/application/classes/Cookie.php new file mode 100644 index 0000000..0350ddd --- /dev/null +++ b/application/classes/Cookie.php @@ -0,0 +1,15 @@ + diff --git a/application/classes/Model/Setup.php b/application/classes/Model/Setup.php new file mode 100644 index 0000000..9d3f232 --- /dev/null +++ b/application/classes/Model/Setup.php @@ -0,0 +1,150 @@ +array('foreign_key'=>'id','far_key'=>'admin_id'), + 'country'=>array('foreign_key'=>'id','far_key'=>'country_id'), + 'language'=>array('foreign_key'=>'id','far_key'=>'language_id'), + ); + + protected $_has_many = array( + 'dates'=>array('model'=>'Site_Dates','far_key'=>'id','foreign_key'=>'site_id'), + 'rooms'=>array('far_key'=>'id','foreign_key'=>'site_id'), + ); + + protected $_compress_column = array( + 'module_config', + 'site_details', + ); + + // Validation rules + public function rules() { + $x = Arr::merge(parent::rules(), array( + 'url' => array( + array('not_empty'), + array('min_length', array(':value', 8)), + array('max_length', array(':value', 127)), + array('url'), + ), + )); + + // This module doesnt use site_id. + unset($x['site_id']); + + return $x; + } + + /** + * Get/Set Module Configuration + * + * @param $key Module name. + * @param $value Values to store. If NULL, retrieves the value stored, otherwise stores value. + */ + public function module_config($key,array $value=NULL) { + // If we are not loaded, we dont have any config. + if (! $this->loaded() OR (is_null($value) AND ! $this->module_config)) + return array(); + + $mo = ORM::factory('Module',array('name'=>$key)); + + if (! $mo->loaded()) + throw new Kohana_Exception('Unknown module :name',array(':name'=>$key)); + + $mc = $this->module_config ? $this->module_config : array(); + + // If $value is NULL, we are a getter + if ($value === NULL) + return empty($mc[$mo->id]) ? array() : $mc[$mo->id]; + + // Store new value + $mc[$mo->id] = $value; + $this->module_config = $mc; + + return $this; + } + + public function module_config_id($key=NULL) { + $result = array(); + + foreach (array_keys($this->module_config) as $mid) { + if (is_null($key) OR $key == $mid) { + $result[$mid] = array( + 'object'=>ORM::factory('Module',$mid), + 'data'=>$this->module_config[$mid], + ); + + // If we are just after our key, we can continue here + if ($key AND $key==$mid) + break; + } + } + + return $result; + } + + public function open_dates($date,$days=0) { + $result = array(); + + $date_end = $date+$days*86400; + foreach ($this->dates->where('code','=','O')->where_startstop($date,$date_end)->find_all() as $o) + while ($date<$date_end) { + // If we havent made the start date yet, we need to advance + if ($o->date_start > $date AND $o->date_stop > $date_end) { + $result[$date] = FALSE; + $date += 86400; + continue; + } + + // Check that this record covers our current date + if ($o->date_stop < $date) + break; + + $result[$date] = $o->open(date('w',$date)) ? TRUE : FALSE; + $date += 86400; + } + + // If we broke out and our date $days hasnt ben evaluated, we are closed + while ($date<$date_end) { + $result[$date] = FALSE; + $date += 86400; + } + + return $result; + } + + /** + * Get/Set our Site Configuration from the DB + * + * @param $key Key + * @param $value Values to store. If NULL, retrieves the value stored, otherwise stores value. + */ + public function site_details($key,array $value=NULL) { + if (! in_array($key,array('name','address1','address2','city','state','pcode','phone','fax','email','faqurl'))) + throw new Kohana_Exception('Unknown Site Configuration Key :key',array(':key'=>$key)); + + // If $value is NULL, we are a getter + if ($value === NULL) + return empty($this->site_details[$key]) ? '' : $this->site_details[$key]; + + // Store new value + $sc[$key] = $value; + + return $this; + } +} +?> diff --git a/application/classes/Site.php b/application/classes/Site.php new file mode 100644 index 0000000..e5d8699 --- /dev/null +++ b/application/classes/Site.php @@ -0,0 +1,21 @@ +load('config')->theme_admin : Kohana::$config->load('config')->theme); + } +} +?> diff --git a/application/config/config.php b/application/config/config.php new file mode 100644 index 0000000..014c986 --- /dev/null +++ b/application/config/config.php @@ -0,0 +1,8 @@ + 'TSM Access Request', + 'theme' => 'bootstrap', + 'theme_admin' => 'baseadmin', +); diff --git a/application/config/database.php b/application/config/database.php new file mode 100644 index 0000000..7e20bc6 --- /dev/null +++ b/application/config/database.php @@ -0,0 +1,31 @@ + array + ( + 'type' => 'MySQL', + 'connection' => array( + /** + * The following options are available for MySQL: + * + * string hostname server hostname, or socket + * string database database name + * string username database username + * string password database password + * boolean persistent use persistent connections? + * array variables system variables as "key => value" pairs + * + * Ports and sockets may be appended to the hostname. + */ + 'hostname' => 'mysql.leenooks.vpn', + 'database' => 'weblntsmac', + 'username' => 'ln-tsmac', + 'password' => 'TSM', + 'persistent' => TRUE, + ), + 'table_prefix' => 'tac_', + 'charset' => 'utf8', + 'caching' => TRUE, + ), +); diff --git a/application/config/session.php b/application/config/session.php new file mode 100644 index 0000000..b936724 --- /dev/null +++ b/application/config/session.php @@ -0,0 +1,18 @@ + array( + 'name'=>'TSMAC', + ), +); +?> diff --git a/application/views/account/user/edit.php b/application/views/account/user/edit.php new file mode 100644 index 0000000..285a635 --- /dev/null +++ b/application/views/account/user/edit.php @@ -0,0 +1,61 @@ +
+ Account Details + + display('email'),array('label'=>'Email','class'=>'col-md-3','placeholder'=>'Email Address','type'=>'email','required','data-error'=>'Invalid EMAIL address')); ?> + + display('company'),array('label'=>'Company','class'=>'col-md-3','placeholder'=>'Company Name','required')); ?> + +
+ +
+
+ display('title'),array('class'=>'form-control','required','nocg'=>TRUE)); ?> +
+
+ display('first_name'),array('class'=>'form-control col-md-2','placeholder'=>'First Name','required','nocg'=>TRUE)); ?> +
+
+ display('last_name'),array('class'=>'form-control col-md-2','placeholder'=>'Last Name','required','nocg'=>TRUE)); ?> +
+
+
+ +
+ + display('address1'),array('class'=>'col-md-6','placeholder'=>'Address Line 1','required')); ?> + + + display('address2'),array('class'=>'col-md-6','placeholder'=>'Address Line 2')); ?> + + +
+
+ display('city'),array('label'=>'City','placeholder'=>'City','required','nocg'=>TRUE)); ?> +
+ +
+ display('state'),array('label'=>'','class'=>'input-mini','placeholder'=>'State','required','nocg'=>TRUE)); ?> +
+ +
+ display('zip'),array('label'=>'','class'=>'input-mini','placeholder'=>'Post Code','required','nocg'=>TRUE)); ?> +
+
+
+ +
+ +
+ list_select(),$o->country_id,array('class'=>'form-control','required','nocg'=>TRUE)); ?> +
+
+ + +
+ +
+
+ + +
+
diff --git a/application/views/pages/welcome.php b/application/views/pages/welcome.php new file mode 100644 index 0000000..64f5442 --- /dev/null +++ b/application/views/pages/welcome.php @@ -0,0 +1,11 @@ + +
+
+ +
+

Request Access

+

To be able to use this server, you need to request access. Once your access is activated, you will be able to use this TSM server with your TSM client.

+

Login ยป

+
+ +
diff --git a/includes/kohana b/includes/kohana new file mode 160000 index 0000000..3291c7d --- /dev/null +++ b/includes/kohana @@ -0,0 +1 @@ +Subproject commit 3291c7d850d9d031a367f24523255d2ec5e96e0b diff --git a/index.php b/index.php new file mode 100644 index 0000000..c7bb26f --- /dev/null +++ b/index.php @@ -0,0 +1,131 @@ += 5.3, it is recommended to disable + * deprecated notices. Disable with: E_ALL & ~E_DEPRECATED + */ +error_reporting(E_ALL | E_STRICT); + +/** + * End of standard configuration! Changing any of the code below should only be + * attempted by those with a working knowledge of Kohana internals. + * + * @link http://kohanaframework.org/guide/using.configuration + */ + +// Set the full path to the docroot +define('DOCROOT', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR); + +// Make the application relative to the docroot, for symlink'd index.php +if ( ! is_dir($application) AND is_dir(DOCROOT.$application)) + $application = DOCROOT.$application; + +// Make the modules relative to the docroot, for symlink'd index.php +if ( ! is_dir($modules) AND is_dir(DOCROOT.$modules)) + $modules = DOCROOT.$modules; + +// Make the system relative to the docroot, for symlink'd index.php +if ( ! is_dir($sysmodules) AND is_dir(DOCROOT.$sysmodules)) + $sysmodules = DOCROOT.$sysmodules; + +// Make the system relative to the docroot, for symlink'd index.php +if ( ! is_dir($system) AND is_dir(DOCROOT.$system)) + $system = DOCROOT.$system; + +// Define the absolute paths for configured directories +define('APPPATH', realpath($application).DIRECTORY_SEPARATOR); +define('MODPATH', realpath($modules).DIRECTORY_SEPARATOR); +define('SMDPATH', realpath($sysmodules).DIRECTORY_SEPARATOR); +define('SYSPATH', realpath($system).DIRECTORY_SEPARATOR); + +// Clean up the configuration vars +unset($application, $modules, $sysmodules, $system); + +if (file_exists('install'.EXT)) +{ + // Load the installation check + return include 'install'.EXT; +} + +/** + * Define the start time of the application, used for profiling. + */ +if ( ! defined('KOHANA_START_TIME')) +{ + define('KOHANA_START_TIME', microtime(TRUE)); +} + +/** + * Define the memory usage at the start of the application, used for profiling. + */ +if ( ! defined('KOHANA_START_MEMORY')) +{ + define('KOHANA_START_MEMORY', memory_get_usage()); +} + +// Bootstrap the application +require APPPATH.'bootstrap'.EXT; + +if (PHP_SAPI == 'cli') // Try and load minion +{ + class_exists('Minion_Task') OR die('Please enable the Minion module for CLI support.'); + set_exception_handler(array('Minion_Exception', 'handler')); + + Minion_Task::factory(Minion_CLI::options())->execute(); +} +else +{ + /** + * Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO']. + * If no source is specified, the URI will be automatically detected. + */ + echo Request::factory(TRUE, array(), FALSE) + ->execute() + ->send_headers(TRUE) + ->body(); +} diff --git a/modules/lnapp b/modules/lnapp new file mode 160000 index 0000000..a7ed667 --- /dev/null +++ b/modules/lnapp @@ -0,0 +1 @@ +Subproject commit a7ed6672e18773ff07eb1c01fcf8e38b4828de11 diff --git a/modules/tsm/classes/Database/Result.php b/modules/tsm/classes/Database/Result.php new file mode 100644 index 0000000..9076c33 --- /dev/null +++ b/modules/tsm/classes/Database/Result.php @@ -0,0 +1,4 @@ + diff --git a/modules/tsm/classes/Database/TSM.php b/modules/tsm/classes/Database/TSM.php new file mode 100644 index 0000000..04289e9 --- /dev/null +++ b/modules/tsm/classes/Database/TSM.php @@ -0,0 +1,4 @@ + diff --git a/modules/tsm/classes/Database/TSM/Result.php b/modules/tsm/classes/Database/TSM/Result.php new file mode 100644 index 0000000..3797fc3 --- /dev/null +++ b/modules/tsm/classes/Database/TSM/Result.php @@ -0,0 +1,4 @@ + diff --git a/modules/tsm/classes/Database/Tsm/dsmadmc.php b/modules/tsm/classes/Database/Tsm/dsmadmc.php new file mode 100644 index 0000000..4e2dfc9 --- /dev/null +++ b/modules/tsm/classes/Database/Tsm/dsmadmc.php @@ -0,0 +1,4 @@ + diff --git a/modules/tsm/classes/Model/ADMIN.php b/modules/tsm/classes/Model/ADMIN.php new file mode 100644 index 0000000..ebfa484 --- /dev/null +++ b/modules/tsm/classes/Model/ADMIN.php @@ -0,0 +1,4 @@ + diff --git a/modules/tsm/classes/Model/NODE.php b/modules/tsm/classes/Model/NODE.php new file mode 100644 index 0000000..5bd69d1 --- /dev/null +++ b/modules/tsm/classes/Model/NODE.php @@ -0,0 +1,4 @@ + diff --git a/modules/tsm/classes/ORM/TSM.php b/modules/tsm/classes/ORM/TSM.php new file mode 100644 index 0000000..1e52f38 --- /dev/null +++ b/modules/tsm/classes/ORM/TSM.php @@ -0,0 +1,174 @@ +.* + protected $_disable_wild_select = TRUE; + // Suppress ORMs inclusion of . to column joins + protected $_disable_join_table_name = TRUE; + // Suppress ORMs use of limit + protected $_disable_limit = TRUE; + // To enable effective caching, this must disabled. + protected $_reload_on_wakeup = FALSE; + + // Enable the formating of columns + protected $_object_formated = array(); + protected $_formated = FALSE; + protected $_formats = array(); + + protected $_tsm = array(); + + /** + * + * Configuration to enable PLA to work with DSMADMC & DB2 connections + * This is required, because the schema is different between each + * connection? + */ + protected function _initialize() { + // Set out DB connection configuration. + $this->_db_group = Kohana::$config->load('tsm')->client_type; + + // Adjustments for DSMADMC or DB2 connections + if (array_key_exists($this->_db_group,$this->_tsm)) + foreach ($this->_tsm[$this->_db_group] as $k => $v) + if (preg_match('/^_/',$k)) + $this->{$k} = $v; + + if ($this->_db_group == 'db2') + $this->_disable_join_table_name = FALSE; + + parent::_initialize(); + } + + public function __get($column) { + // Get a substited column name - need for DB2/DSMADMC schema differences + if (isset($this->_tsm[$this->_db_group]['translate']) AND array_key_exists($column,$this->_tsm[$this->_db_group]['translate'])) + return is_null($c=$this->_tsm[$this->_db_group]['translate'][$column]) ? NULL : parent::__get($c); + else + return parent::__get($column); + } + + public function find() { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + Log::instance()->add(LOG::DEBUG,'METHOD :method: isCacheable: :cable, table: :table',array(':method'=>__METHOD__,':cable'=>($x=$this->isCacheable()) ? $x : 'N',':table'=>$this->_table_name)); + // Check if we can preload our data and havent already done it + // Kohana uses Kohana::cache here, instead of Cache() + if ($time = $this->isCacheable() AND is_null(Kohana::cache($cache_key = 'PRELOAD:'.$this->_table_name))) { + Log::instance()->add(LOG::DEBUG,'PRELOADING :method: table: :table',array(':method'=>__METHOD__,':table'=>$this->_table_name)); + + // Firstly set our cache, so that we dont get in a loop + Kohana::cache($cache_key,TRUE,$time-1); + + // Find all records of this type + $c = get_class($this); + $x = new $c; + + foreach ($x->find_all() as $record) { + // Simulate loading the record so that we can get the SQL to use as our cache key + $y = new $c; + $y->where($y->_primary_key,'=',(string)$record); + + // Code, as extracted from ORM to complete building the SQL + $y->_build(Database::SELECT); + $y->_db_builder->from(array($y->_table_name,$y->_object_name)); + if (! isset($y->_db_applied['order_by']) AND ! empty($y->_sorting)) + foreach ($y->_sorting as $column => $direction) { + if (strpos($column, '.') === FALSE) + // Sorting column for use in JOINs + $column = ($y->_disable_join_table_name ? '' : $y->_table_name.'.').$column; + + $y->_db_builder->order_by($column, $direction); + } + + // Set the cache key based on the database instance name and SQL + $cache_key = 'Database::query("'.$y->_db.'", "'.(string)$y->_db_builder.'")'; + unset($y); + + // Cache the record, our subsequent find should get a cache hit now. + Kohana::cache($cache_key, array($record->as_array()), $time); + Log::instance()->add(LOG::DEBUG,'Cache SET for TIME: :time, KEY: :cache_key',array(':cache_key'=>$cache_key,':time'=>$time)); + } + + unset($x); + } + + Log::instance()->add(LOG::DEBUG,'LEAVE :method',array(':method'=>__METHOD__)); + + // Contiue as normal + return parent::find(); + } + + private function isCacheable() { + $config = Kohana::$config->load('database')->{Kohana::$config->load('tsm')->client_type}; + + if ($config['caching'] AND isset($config['cachepreload'][$this->_table_name]) AND count($this->_db_pending) == 1 AND $this->_db_pending[0]['name'] == 'where' AND $this->_db_pending[0]['args'][0] == $this->_primary_key AND $this->_db_pending[0]['args'][1] == '=') + return $config['cachepreload'][$this->_table_name]; + else + return FALSE; + } + + protected function _load_result($multiple = FALSE) { + // We'll cache our query results + if ($c = $this->_db->caching($this->_table_name)) + $this->_db_builder->cached($c); + + return parent::_load_result($multiple); + } + + /** + * Proxy method to Database list_columns. + * This enables caching of the list_columns queries. Since this doesnt + * we hard code the cache to 7 days. + * + * @return array + * @todo This cache time needs to be better integrated with other caching times. + */ + public function list_columns() { + // We'll cache our query results + if ($this->_db->caching('SCHEMA')) { + // Set the cache key based on the database instance name and SQL + $cache_key = 'Database::query(LC:'.$this->_table_name.')'; + + if (! is_null($result = Cache::instance()->get($cache_key))) + // Return a cached result + return $result; + } + + // Proxy to database + $result = $this->_db->list_columns($this->_table_name); + + // Cache the result array + if (isset($cache_key)) + Cache::instance()->set($cache_key, $result, 604800); + + return $result; + } + + // Load our values into the ORM object + public function load_object(array $values) { + return parent::_load_values($values); + } + + public static function date($date,$format) { + return $date ? date($format,strtotime($date)) : ''; + } + + protected function datatypemap($type) { + $x = Kohana::$config->load('tsm')->datatypes; + + return array_key_exists($type,$x) ? $x[$type] : $x; + } +} +?> diff --git a/modules/tsm/classes/SystemMessage.php b/modules/tsm/classes/SystemMessage.php new file mode 100644 index 0000000..a39b985 --- /dev/null +++ b/modules/tsm/classes/SystemMessage.php @@ -0,0 +1,21 @@ +_('While talking to TSM'), + 'body'=>($sql ? _('Running SQL').': '.$sql.'

' : '').(is_array($error) ? implode('
',$error) : $error), + 'type'=>$type, + )); + } +} +?> diff --git a/modules/tsm/classes/TSM.php b/modules/tsm/classes/TSM.php new file mode 100644 index 0000000..2cd3d6b --- /dev/null +++ b/modules/tsm/classes/TSM.php @@ -0,0 +1,4 @@ + diff --git a/modules/tsm/classes/lnApp/Database/Result.php b/modules/tsm/classes/lnApp/Database/Result.php new file mode 100644 index 0000000..fb4a07c --- /dev/null +++ b/modules/tsm/classes/lnApp/Database/Result.php @@ -0,0 +1,62 @@ +offsetExists($offset)) { + // Set the current row to the offset + $this->_current_row = $this->_internal_row = $offset; + + return TRUE; + + } else { + return FALSE; + } + } + + public function current() { + if ($this->_current_row !== $this->_internal_row AND ! $this->seek($this->_current_row)) + return FALSE; + + // Return an stdClass + if ($this->_as_object === TRUE) { + return $this; + + } elseif (is_string($this->_as_object)) { + // Return an object of given class name + $o = new $this->_as_object; + + return $o->load_object($this->_rows[$this->_current_row]); + + // Return an array of the row + } else { + return $this->_rows[$this->_current_row]; + } + } + + /** + * Get a row value from the query + * + * TSM returns all columns in upper case + */ + public function get($name, $default = NULL) { + $name = strtoupper($name); + + return parent::get($name,$default); + } +} +?> diff --git a/modules/tsm/classes/lnApp/Database/TSM.php b/modules/tsm/classes/lnApp/Database/TSM.php new file mode 100644 index 0000000..d449646 --- /dev/null +++ b/modules/tsm/classes/lnApp/Database/TSM.php @@ -0,0 +1,113 @@ +caching("table"); + * + * @return string + */ + public function caching($table) { + return (array_key_exists('cache',Kohana::modules()) AND $this->_config['caching'] AND isset($this->_config['cache'][$table])) ? $this->_config['cache'][$table] : FALSE; + } + + private function clear() { + $this->_query_msg_codes = array(); + } + + public function escape($value) { + // SQL standard is to use single-quotes for all values + return "'$value'"; + } + + public function query($type, $sql, $as_object = FALSE, array $params = NULL) { + // Make sure the database is connected + if (! $this->_connection && ! $this->connect()) + return new Database_TSM_Result(array(),'',$as_object,$params); + + $this->clear(); + + if ( ! empty($this->_config['profiling'])) + // Benchmark this query for the current instance + $benchmark = Profiler::start("Database ({$this->_instance})", $sql); + + // Execute the query + $result = $this->execute($sql); + + if ($this->execute_stderr AND $this->execute_rc) { + // This benchmark is worthless + if (isset($benchmark)) + Profiler::delete($benchmark); + + SystemMessage::TSM('error',sprintf('%s (%s)',$this->execute_stdout,$this->execute_stderr),$sql); + } + + if (isset($benchmark)) + Profiler::stop($benchmark); + + // Set the last query + $this->last_query = $sql; + + if ($type === Database::SELECT) + // Return an iterator of results + return new Database_TSM_Result($result, $sql, $as_object, $params); + elseif ($type === Database::INSERT) + throw new Kohana_Exception('Database INSERTS are not supported'); + elseif ($type === Database::SHOW) + return new Database_TSM_Show($result, $sql, $as_object, $params); + elseif ($type === Database::SET) + return new Database_TSM_Set($result, $sql, $as_object, $params); + } +} +?> diff --git a/modules/tsm/classes/lnApp/Database/TSM/Result.php b/modules/tsm/classes/lnApp/Database/TSM/Result.php new file mode 100644 index 0000000..39cf0f0 --- /dev/null +++ b/modules/tsm/classes/lnApp/Database/TSM/Result.php @@ -0,0 +1,48 @@ +_rows[$this->_internal_row++] = (array)$r; + + // Is this an DSMADMC result? + } elseif (is_array($result)) + foreach ($result as $line) { + if (! trim($line)) { + if ($start) + $this->_internal_row++; + + continue; + } + + list($k,$v) = explode(':',$line,2); + + $this->_rows[$this->_internal_row][trim($k)] = trim($v); + $start = TRUE; + } + else + throw new Kohana_Exception('Unknown result :result',array(':result'=>$result)); + + $this->_total_rows = $this->_internal_row; + $this->_internal_row = 0; + } +} +?> diff --git a/modules/tsm/classes/lnApp/Database/Tsm/dsmadmc.php b/modules/tsm/classes/lnApp/Database/Tsm/dsmadmc.php new file mode 100644 index 0000000..120fb1f --- /dev/null +++ b/modules/tsm/classes/lnApp/Database/Tsm/dsmadmc.php @@ -0,0 +1,185 @@ +_config['connection'] + array( + 'database' => '', + 'hostname' => '', + 'username' => '', + 'password' => '', + 'persistent' => FALSE, + )); + + // Get user login details from user session - these are set by login + if (! $username) + $username = Session::instance()->get_once(Kohana::$config->load('auth')->session_key); + if (! $password) + $password = Session::instance()->get_once('password'); + + // Prevent this information from showing up in traces + unset($this->_config['connection']['username'], $this->_config['connection']['password']); + + if (! file_exists(Kohana::$config->load('tsm')->client)) { + SystemMessage::TSM('error',sprintf('Unable to find the dsmadmc at %s',Kohana::$config->load('tsm')->client),''); + + return FALSE; + } + + if (! $username OR ! $password) + HTTP::redirect('login'); + + try { + if ($persistent) { + // Create a persistent connection + throw new Kohana_Exception('Cant do persistant connections'); + + } else { + // Create a connection and force it to be a new link + $this->_connection = sprintf('%s %s -id=%s -password=%s -displ=list -editor=no -dataonly=YES %s %s ', + Kohana::$config->load('tsm')->client, + $database ? '-server='.$database : '', + $username, + $password, + Kohana::$config->load('tsm')->client_errorlogname ? sprintf('-errorlogname=%s',Kohana::$config->load('tsm')->client_errorlogname) : '', + $database ? sprintf('-se=%s',$database) : '' + ); + + $result = $this->query(Database::SELECT,'SELECT server_name,platform,version,release,level,sublevel FROM status'); + + if ($result->count()) { + return TSM::instance()->set($username,$password,$result); + + } else { + $this->_connection = FALSE; + + // @todo Get ANS8034E (ID not recognised), or ??????E (invalid password) + SystemMessage::add(array( + 'title'=>_('Login Failed'), + 'type'=>'error', + 'body'=>_('Invalid Username and/or Password.') + )); + + return FALSE; + } + } + + } catch (ErrorException $e) { + // No connection exists + $this->_connection = NULL; + + throw new Database_Exception(':error', array( + ':error' => sprintf('%s error in %s (%s)',$e->getMessage(),$e->getFile(),$e->getLine()), + ), + $e->getCode()); + } + } + + protected function execute($sql) { + $this->execute_stdout = ''; + + // We need to escape any back slashes, since the exec will transpose them + // @todo Is there a better way of doing this? + $sql = str_replace('\\','\\\\',$sql); + + $this->execute_stderr = exec($this->_connection.'"'.$sql.'"',$this->execute_stdout,$this->execute_rc); + if (Kohana::$config->load('config.site.mode') == Kohana::DEVELOPMENT) + SystemMessage::TSM('info',sprintf('%s (%s) [%s]',$this->_connection.'"'.$sql.'"',join("\n",$this->execute_stdout),$this->execute_rc),$sql); + + // Work out our message codes + $result = array(); + foreach ($this->execute_stdout as $line) + if (! preg_match('/^('.$this->msg_format.')\s+/',$line,$matches)) + array_push($result,$line); + elseif (! in_array($matches[1],$this->ignore_codes)) + array_push($this->_query_msg_codes,$matches[1]); + + // If we got a no data code + if (array_intersect($this->_query_msg_codes,$this->nodata_codes)) { + $result = array(); + $this->execute_rc = 0; + } + + return $result; + } + + public function list_columns($table, $like = NULL, $add_prefix = TRUE) { + // Quote the table name + $table = ($add_prefix === TRUE) ? $this->quote_table($table) : $table; + + if (is_string($like)) + // Search for column names + throw new Kohana_Exception('Like queries not implemented'); + else + // Find all column names + $result = $this->query(Database::SELECT, sprintf('SELECT * FROM SYSCAT.COLUMNS WHERE TABNAME=\'%s\'',$table), FALSE); + + $count = 0; + $columns = array(); + foreach ($result as $row) { + list($type, $length) = $this->_parse_type($row['TYPENAME']); + + $column = $this->datatype($type); + + $column['column_name'] = $row['COLNAME']; + $column['data_type'] = $type; + $column['is_nullable'] = ($row['NULLS'] == 'TRUE'); + $column['ordinal_position'] = ++$count; + + switch (strtolower($column['data_type'])) { + case 'float': + if (isset($length)) + list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length); + break; + + case 'int': + if (isset($length)) + // MySQL attribute + $column['display'] = $length; + break; + + case 'string': + switch ($column['data_type']) { + case 'binary': + case 'varbinary': + $column['character_maximum_length'] = $length; + break; + + case 'char': + case 'varchar': + $column['character_maximum_length'] = $length; + case 'text': + case 'tinytext': + case 'mediumtext': + case 'longtext': + $column['collation_name'] = $row['Collation']; + break; + + case 'enum': + case 'set': + $column['collation_name'] = $row['Collation']; + $column['options'] = explode('\',\'', substr($length, 1, -1)); + break; + } + + break; + } + + // TSM attributes + $column['comment'] = $row['REMARKS']; + $columns[$row['COLNAME']] = $column; + } + + return $columns ? $columns : array(''); + } +} +?> diff --git a/modules/tsm/classes/lnApp/Model/ADMIN.php b/modules/tsm/classes/lnApp/Model/ADMIN.php new file mode 100644 index 0000000..21e5a1d --- /dev/null +++ b/modules/tsm/classes/lnApp/Model/ADMIN.php @@ -0,0 +1,32 @@ +array( + array('ORM_TSM::Date',array(':value','d-M-Y')), + ), + 'PWSET_TIME'=>array( + array('ORM_TSM::Date',array(':value','d-M-Y')), + ), + 'REG_TIME'=>array( + array('ORM_TSM::Date',array(':value','d-M-Y')), + ), + ); + + public function name() { + return $this->ADMIN_NAME; + } +} +?> diff --git a/modules/tsm/classes/lnApp/Model/NODE.php b/modules/tsm/classes/lnApp/Model/NODE.php new file mode 100644 index 0000000..204ae1d --- /dev/null +++ b/modules/tsm/classes/lnApp/Model/NODE.php @@ -0,0 +1,798 @@ +'ASC', + ); + + protected $_has_one = array( + 'DOMAIN'=>array('foreign_key'=>'DOMAIN_NAME','far_key'=>'DOMAIN_NAME'), + ); + protected $_has_many = array( + 'ACTLOG'=>array('foreign_key'=>'NODENAME','far_key'=>'NODE_NAME'), + 'FILESPACE'=>array('foreign_key'=>'NODE_NAME','far_key'=>'NODE_NAME'), + 'VOLUMEUSAGE'=>array('foreign_key'=>'NODE_NAME','far_key'=>'NODE_NAME'), + 'ASSOCIATION'=>array('foreign_key'=>'NODE_NAME','far_key'=>'NODE_NAME'), + 'MGMTCLASS'=>array('foreign_key'=>'DOMAIN_NAME','far_key'=>'DOMAIN_NAME'), + 'CLIENTOPT'=>array('foreign_key'=>'OPTIONSET_NAME','far_key'=>'OPTION_SET'), + 'SUMMARY'=>array('foreign_key'=>'ENTITY','far_key'=>'NODE_NAME'), + 'EVENT'=>array('foreign_key'=>'NODE_NAME','far_key'=>'NODE_NAME'), + 'OCC'=>array('foreign_key'=>'NODE_NAME','far_key'=>'NODE_NAME'), + ); + + protected $_display_filters = array( + 'REG_TIME'=>array( + array('ORM_TSM::Date',array(':value','d-M-Y')), + ), + 'PWSET_TIME'=>array( + array('ORM_TSM::Date',array(':value','d-M-Y')), + ), + 'LASTACC_TIME'=>array( + array('ORM_TSM::Date',array(':value','d-M-Y')), + ), + 'LASTSESS_SENT'=>array( + array('number_format',array(':value',0)), + ), + 'LASTSESS_RECVD'=>array( + array('number_format',array(':value',0)), + ), + 'LASTSESS_DURATION'=>array( + array('number_format',array(':value',2)), + ), + 'LASTSESS_IDLEWAIT'=>array( + array('number_format',array(':value',2)), + ), + 'LASTSESS_COMMWAIT'=>array( + array('number_format',array(':value',2)), + ), + 'LASTSESS_MEDIAWAIT'=>array( + array('number_format',array(':value',2)), + ), + ); + + /** + * Get all the ACTIVITIY LOG for this NODE + */ + private function _actlog() { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s',__METHOD__,$this->NODE_NAME); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + // We cant load all records here, like we do with the others, there is too much data! + $result = $this->ACTLOG->find_all(); + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Get all the ACTIVITY SUMMARY for this NODE + */ + private function _actsum() { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s',__METHOD__,$this->NODE_NAME); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + // In the interest of performance, we load all the records and get PHP to process it. + // Our ORM caching we reduce the hit on TSM. + foreach (ORM::factory('ACTSUM')->find_all() as $o) + if ($o->ENTITY == $this->NODE_NAME) + array_push($result,$o); + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Get all the FILESPACES for this NODE + */ + private function _filespaces() { + $result = array(); + + // In the interest of performance, we load all the records and get PHP to process it. + // Our ORM caching we reduce the hit on TSM. + foreach (ORM::factory('FILESPACE')->find_all() as $o) + if ($o->NODE_NAME == $this->NODE_NAME) + array_push($result,$o); + + return $result; + } + + /** + * Get all the OCCUPANCY for this NODE + */ + private function _occupancy() { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s',__METHOD__,$this->NODE_NAME); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + // In the interest of performance, we load all the records and get PHP to process it. + // Our ORM caching we reduce the hit on TSM. + foreach (ORM::factory('OCC')->find_all() as $o) + if ($o->NODE_NAME == $this->NODE_NAME) + array_push($result,$o); + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Get all the VOLUMES for this NODE + */ + private function _volumeusage() { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s',__METHOD__,$this->NODE_NAME); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + // In the interest of performance, we load all the records and get PHP to process it. + // Our ORM caching we reduce the hit on TSM. + foreach (ORM::factory('VOLUMEUSAGE')->find_all() as $o) + if ($o->NODE_NAME == $this->NODE_NAME) + array_push($result,$o); + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the version of the TSM client + */ + public function version() { + if ($this->CLIENT_VERSION) + return sprintf('%s.%s.%s.%s',$this->CLIENT_VERSION,$this->CLIENT_RELEASE,$this->CLIENT_LEVEL,$this->CLIENT_SUBLEVEL); + else + return ''; + } + + /** + * Return the OS version for the TSM client + */ + public function platform() { + return sprintf('%s %s',$this->PLATFORM_NAME,$this->CLIENT_OS_LEVEL ? '('.$this->CLIENT_OS_LEVEL.')' : ''); + } + + // @todo This needs to return the global configuration. + public function passexp() { + if ($this->PASSEXP) + return 'TBA'; + else + return _('No Set'); + } + + // @todo This needs to be validated as a correct calculation + public function lasttransferpercent() { + $x = 100-($this->LASTSESS_IDLEWAIT+$this->LASTSESS_COMMWAIT+$this->LASTSESS_MEDIAWAIT); + return $x < 0 ? 0 : $x; + } + + // @todo This needs to be validated as a correct calculation + public function lasttransfertime() { + if ($this->LASTSESS_DURATION) + return $this->LASTSESS_DURATION*($this->lasttransferpercent()/100); + else + return 0; + } + + // @todo This needs to be validated as a correct calculation + public function lastsendperformance() { + if ($this->lasttransfertime()) + return $this->LASTSESS_SENT/$this->lasttransfertime()/1024/1024; + else + return 0; + } + + // @todo This needs to be validated as a correct calculation + public function lastreceiveperformance() { + if ($this->lasttransfertime()) + return $this->LASTSESS_RECVD/$this->lasttransfertime()/1024/1024; + else + return 0; + } + + /** + * The last sent aggregate performance + */ + public function lastsendaggperformance() { + if ((real)$this->LASTSESS_DURATION) + return $this->LASTSESS_SENT/$this->LASTSESS_DURATION/1024/1024; + else + return 0; + } + + /** + * The last receive aggregate performance + */ + public function lastreceiveaggperformance() { + if ((real)$this->LASTSESS_DURATION) + return $this->LASTSESS_RECVD/$this->LASTSESS_DURATION/1024/1024; + else + return 0; + } + + // @todo This should return the system setting (cloptset), if the node setting is not configured. + public function txngroupmax() { + return $this->TXNGROUPMAX; + } + + // Test to see if a node has any data of type + // @param $type is BACKUP/ARCHIVE/SPACE MANAGED + public function hasData($type) { + return $this->vols_byctype($type) ? TRUE : FALSE; + } + + public function activity() { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s',__METHOD__,$this->NODE_NAME); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + $result = $this->ACTLOG->ExcludeBA()->find_all(); + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Get all the ACTIVITY LOG information for a SESSION + * @param $sid Session ID + * @param $start Session Start Time (to illiminate any duplication session data) + */ + public function actlog_session($sid,$start) { + $result = array(); + + foreach ($this->_actlog() as $alo) + if ($alo->SESSION == $sid AND $alo->start() >= $start) + array_push($result,$alo); + + return $result; + } + + /** + * Return the ACTIVITY of this NODE + * @param $type is Bkup/Arch/SpMg + */ + public function act_bybtype($type) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s-%s',__METHOD__,$this->NODE_NAME,$type); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + foreach ($this->_actsum() as $aso) + if ($aso->ACTIVITY == $this->datatypemap($type)) + array_push($result,$aso); + + Sort::MASort($result,'SCHEDULE_NAME,START_TIME'); + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the Schedules used for all activites of type + * @param $type is Bkup/Arch/SpMg + */ + public function act_schedules($type) { + $result = array(); + + foreach ($this->act_bybtype($type) as $ao) + if (! in_array($ao->SCHEDULE_NAME,$result)) + array_push($result,$ao->SCHEDULE_NAME); + + return $result; + } + + /** + * Return the BACKUP TYPES used by this NODE + * ie: Bkup/Arch/SpMg + */ + public function btypes() { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s',__METHOD__,$this->NODE_NAME); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + foreach ($this->_occupancy() as $oo) + if (! in_array($oo->TYPE,$result)) + array_push($result,$oo->TYPE); + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the total of a field for this NODE has by backup TYPE + * @param $field the field to check + * @param $data the value of that field to match + * @param $metric is metric of the storpage pool, eg: NUM_FILES + */ + private function _data_int($field,$data,$metric) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s-%s-%s-%s',__METHOD__,$this->NODE_NAME,$field,$data,$metric); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = 0; + + foreach ($this->_occupancy() as $oo) + if ($oo->{$field} == $data) + $result += $oo->{$metric}; + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the data that this NODE has in a STORAGE POOL by backup TYPE + * @param $pool is STORAGE POOL NAME + * @param $metric is metric of the storpage pool, eg: NUM_FILES + * @param $type is Bkup/Arch/SpMg + */ + private function _data_bypoolbybtype($pool,$metric,$type) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s-%s-%s-%s',__METHOD__,$this->NODE_NAME,$pool,$metric,$type); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = 0; + + foreach ($this->_occupancy() as $oo) + if ($oo->STGPOOL_NAME == $pool AND $oo->TYPE == $type) + $result += $oo->{$metric}; + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the FILES that this NODE has by backup TYPE + * @param $type is Bkup/Arch/SpMg + */ + public function file_bybtype($type) { + Log::instance()->add(LOG::DEBUG,'FLYBY :method',array(':method'=>__METHOD__)); + return $this->_data_int('TYPE',$type,'NUM_FILES'); + } + + /** + * Return the FILES that this NODE has in a STORAGE POOL + * @param $pool is STORAGE POOL NAME + */ + public function file_bypool($pool) { + Log::instance()->add(LOG::DEBUG,'FLYBY :method',array(':method'=>__METHOD__)); + return $this->_data_int('STGPOOL_NAME',$pool,'NUM_FILES'); + } + + public function file_bypoolbybtype($pool,$type) { + Log::instance()->add(LOG::DEBUG,'FLYBY :method',array(':method'=>__METHOD__)); + return $this->_data_bypoolbybtype($pool,'NUM_FILES',$type); + } + + /** + * Return the FILES that this NODE has in a STORAGE POOL TYPE + * @param $type is ACTIVEDATA/PRIMARY/COPY + */ + public function file_byptype($type) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $result = 0; + + foreach ($this->stgpools_byptype($type) as $spo) + $result += $this->file_bypool($spo); + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + public function file_active() { + return $this->file_byptype('ACTIVE') == 0 ? 'Unknown' : (int)$this->file_byptype('ACTIVE')/(int)$this->file_byptype('PRIMARY'); + } + + public function file_mediaprotection() { + return number_format((int)$this->file_byptype('COPY')/(int)$this->file_byptype('PRIMARY')*100,2); + } + + public function fs() { + return $this->_filespaces(); + } + + public function fs_capacity() { + $result = 0; + + foreach ($this->_filespaces() as $fso) + $result += $fso->CAPACITY; + + return (int)$result; + } + + public function fs_data() { + $result = 0; + + foreach ($this->_filespaces() as $fso) + $result += $fso->utilsation(); + + return (int)$result; + } + + public function fs_logical() { + $result = 0; + + foreach ($this->_filespaces() as $fso) + $result += $fso->data_logical(); + + return (int)$result; + } + + public function fs_utilisation() { + return round($this->fs_data()/$this->fs_capacity()*100,2); + } + + public function fs_vol($vol) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s-%s',__METHOD__,$this->NODE_NAME,$vol); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + foreach ($this->_volumeusage() as $vuo) + if ($vuo->VOLUME_NAME == $vol AND ! in_array($vuo->FILESPACE_NAME,$result)) + array_push($result,$vuo->FILESPACE); + + Sort::MASort($result,'FILESPACE_NAME'); + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return a Graph of the BA Client Sessions + * @param $type is Bkup/Arch/SpMg + * @see [node/ajaxjson_basessions] + */ + public function graph_basessions($type='Bkup',$schedule='') { + $chart = 'ComboChart'; + + $google = GoogleChart::factory($chart) + ->div(sprintf('bas_%s_%s',$type,$schedule)) + ->dataurl(URL::site(sprintf('node/ajaxjson_basessions/%s?c=%s&s=%s&t=%s',$this->NODE_NAME,$chart,$schedule,$type))); + + return (string)$google; + } + + /** + * Return a Graph of the Schedule Backup Activity + * @param $type is Bkup/Arch/SpMg + * @see [node/ajaxjson_schedules] + */ + public function graph_schedules($type='Bkup',$schedule='') { + $chart = 'ComboChart'; + + $google = GoogleChart::factory($chart) + ->div(sprintf('sch_%s_%s',$type,$schedule)) + ->dataurl(URL::site(sprintf('node/ajaxjson_schedules/%s?c=%s&s=%s&t=%s',$this->NODE_NAME,$chart,$schedule,$type))); + + return (string)$google; + } + + /** + * Return the LOGICAL_MB that this NODE has by backup TYPE + * @param $type is Bkup/Arch/SpMg + */ + public function logmb_bybtype($type) { + Log::instance()->add(LOG::DEBUG,'FLYBY :method',array(':method'=>__METHOD__)); + return $this->_data_int('TYPE',$type,'LOGICAL_MB'); + } + + /** + * Return the LOGICAL_MB that this NODE has in a STORAGE POOL + * @param $pool is STORAGE POOL NAME + */ + public function logmb_bypool($pool) { + Log::instance()->add(LOG::DEBUG,'FLYBY :method',array(':method'=>__METHOD__)); + return $this->_data_int('STGPOOL_NAME',$pool,'LOGICAL_MB'); + } + + public function logmb_bypoolbybtype($pool,$type) { + Log::instance()->add(LOG::DEBUG,'FLYBY :method',array(':method'=>__METHOD__)); + return $this->_data_bypoolbybtype($pool,'LOGICAL_MB',$type); + } + + /** + * Return the FILES that this NODE has in a STORAGE POOL TYPE + * @param $type is ACTIVEDATA/PRIMARY/COPY + */ + public function logmb_byptype($type) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $result = 0; + + foreach ($this->stgpools_byptype($type) as $spo) + $result += $this->logmb_bypool($spo); + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + public function occupancy() { + return $this->_occupancy(); + } + + /** + * Return the STORAGE POOLS this NODE has data in + */ + public function stgpools() { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s',__METHOD__,$this->NODE_NAME); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $x = $result = array(); + + foreach ($this->_occupancy() as $oo) + if (! in_array($oo->STGPOOL_NAME,$x)) { + array_push($result,$oo->STGPOOL); + array_push($x,$oo->STGPOOL_NAME); + } + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the STORAGE POOL TYPES used by this NODE + * ie: ACTIVE/PRIMARY/COPY + * @todo This should be sorted by PRIMARY/ACTIVE/COPY + */ + public function stgpooltypes() { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s',__METHOD__,$this->NODE_NAME); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + foreach ($this->stgpools() as $spo) + if (! in_array($spo->POOLTYPE,$result)) + array_push($result,$spo->POOLTYPE); + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the STORAGE POOLS that this NODE uses by BACKUP TYPE + * @param $type is Bkup/Arch/SpMg + */ + public function stgpools_bybtype($type) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s-%s',__METHOD__,$this->NODE_NAME,$type); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $x = $result = array(); + + foreach ($this->_occupancy() as $oo) + if ($oo->TYPE == $type AND ! in_array($oo->STGPOOL_NAME,$x)) { + array_push($result,$oo->STGPOOL); + array_push($x,$oo->STGPOOL_NAME); + } + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the STORAGE POOLS that this NODE uses by BACKUP TYPE + * @param $type is ACTIVEDATA/PRIMARY/COPY + */ + public function stgpools_byptype($type) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s-%s',__METHOD__,$this->NODE_NAME,$type); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + foreach ($this->stgpools() as $spo) + if ($spo->POOLTYPE == $type) + array_push($result,$spo); + + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + public function vols_bybtype($type) { + return $this->vols_byctype($this->datatypemap($type)); + } + + private function _vols_metric($metric,$data) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s-%s-%s',__METHOD__,$this->NODE_NAME,$metric,$data); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $x = $result = array(); + + foreach ($this->_volumeusage() as $vuo) + if ($vuo->{$metric} == $data AND ! in_array($vuo->VOLUME_NAME,$x)) { + array_push($result,$vuo->VOLUME); + array_push($x,$vuo->VOLUME_NAME); + } + + Sort::MASort($result,'VOLUME_NAME'); + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the VOLUMES that this NODE uses by BACKUP TYPE + * @param $type is BACKUP/ARCHIVE/SPACE MANAGED + */ + public function vols_byctype($type) { + return $this->_vols_metric('COPY_TYPE',$type); + } + + /** + * Return the VOLUMES that this NODE uses + * @param $pool is STORAGE POOL NAME + */ + public function vols_bypool($pool) { + return $this->_vols_metric('STGPOOL_NAME',$pool); + } + + /** + * Return the VOLUMES that this NODE has in a STORAGE POOL TYPE + * @param $type is ACTIVEDATA/PRIMARY/COPY + */ + public function vols_byptype($type) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $result = array(); + + foreach ($this->stgpools_byptype($type) as $spo) + $result = array_merge($result,$this->vols_bypool($spo)); + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + /** + * Return the VOLUMES that this NODE uses by POOL and BACKUP TYPE + * @param $pool is STORAGE POOL NAME + * @param $type is Bkup/Arch/SpMg + */ + public function vols_bypoolbybtype($pool,$type) { + return $this->vols_bypoolbyctype($pool,$this->datatypemap($type)); + } + + /** + * Return the VOLUMES that this NODE uses by POOL and BACKUP TYPE + * @param $pool is STORAGE POOL NAME + * @param $type is BACKUP/ARCHIVE/SPACE MANAGED + */ + public function vols_bypoolbyctype($pool,$type) { + Log::instance()->add(LOG::DEBUG,'ENTER :method',array(':method'=>__METHOD__)); + + $k = sprintf('%s-%s-%s-%s',__METHOD__,$this->NODE_NAME,$pool,$type); + $c = Kohana::$config->load('tsm')->cache; + + if (is_null($result = Cache::instance($c)->get($k))) { + $result = array(); + + foreach ($this->_volumeusage() as $vuo) + if ($vuo->STGPOOL_NAME == $pool AND $vuo->COPY_TYPE == $type AND ! in_array($vuo->VOLUME_NAME,$result)) + array_push($result,$vuo->VOLUME); + + Sort::MASort($result,'VOLUME_NAME'); + // @todo Cache time should be configurble + Cache::instance($c)->set($k,$result,300); + } + + Log::instance()->add(LOG::DEBUG,'EXIT :method',array(':method'=>__METHOD__)); + return $result; + } + + public function volumeusage() { + return $this->_volumeusage(); + } +} +?> diff --git a/modules/tsm/classes/lnApp/TSM.php b/modules/tsm/classes/lnApp/TSM.php new file mode 100644 index 0000000..aa1ff3a --- /dev/null +++ b/modules/tsm/classes/lnApp/TSM.php @@ -0,0 +1,38 @@ +get('SERVER')->get('SERVER_NAME'); + } + + public static function version() { + $s = Session::instance()->get('SERVER')->rewind()->as_array(); + $s = array_pop($s); + + return sprintf('%s.%s.%s.%s',$s['VERSION'],$s['RELEASE'],$s['LEVEL'],$s['SUBLEVEL']); + } +} +?> diff --git a/modules/tsm/config/database.php b/modules/tsm/config/database.php new file mode 100644 index 0000000..125f69c --- /dev/null +++ b/modules/tsm/config/database.php @@ -0,0 +1,78 @@ + array + ( + 'type' => 'tsm_dsmadmc', + 'connection' => array( + /** + * The following options are available for MySQL: + * + * string hostname server hostname, or socket + * string database database name + * string username database username + * string password database password + * boolean persistent use persistent connections? + * + * Ports and sockets may be appended to the hostname. + */ + //'hostname' => 'localhost', // Unused + 'username' => 'admin', + 'password' => 'tsm0593lx', + //'persistent' => FALSE, // Unused + ), + 'table_prefix' => '', + 'charset' => 'utf8', + 'caching' => TRUE, + 'cache' => array( + 'ASSOCIATIONS' => 1200, + 'AR_COPYGROUPS' => 1200, + 'BU_COPYGROUPS' => 1200, + 'CLIENT_SCHEDULES' => 1200, + 'CLIENTOPTS' => 1200, + 'DEVCLASSES' => 1200, + 'DOMAINS' => 1200, + 'DRIVES' => 1200, + 'EVENTS' => 1200, + 'FILESPACES' => 1200, + 'LIBRARIES' => 1200, + 'LIBVOLUMES' => 1200, + 'MEDIA' => 1200, + 'MGMTCLASSES' => 1200, + 'NODES' => 1200, + 'OCCUPANCY' => 1200, + 'PATHS' => 1200, + 'SCHEMA' => 604800, + 'STGPOOLS' => 1200, + 'SUMMARY' => 180, + 'VOLHISTORY' => 1200, + 'VOLUMES' => 1200, + 'VOLUMEUSAGE' => 1200, + ), + 'cachepreload' => array( + 'DEVCLASSES' => 1200, + 'DOMAINS' => 1200, + 'DRIVES' => 1200, + 'LIBVOLUMES' => 1200, + 'LIBRARIES' => 1200, + 'MEDIA' => 1200, + 'NODES' => 1200, + 'STGPOOLS' => 1200, + 'VOLHISTORY' => 1200, + 'VOLUMES' => 1200, + ), + 'profiling' => TRUE, + ), +); +?> diff --git a/modules/tsm/config/tsm.php b/modules/tsm/config/tsm.php new file mode 100644 index 0000000..743d17f --- /dev/null +++ b/modules/tsm/config/tsm.php @@ -0,0 +1,18 @@ + '/opt/tivoli/tsm/client/ba/bin/dsmadmc', + 'client_type' => 'dsmadmc', + 'client_errorlogname' => '/tmp/tsm-errorlog.log', +); +?>