diff --git a/app.coffee b/app.coffee index 27a01f0..e5d534c 100755 --- a/app.coffee +++ b/app.coffee @@ -6,6 +6,7 @@ app.libs = _: require 'underscore' async: require 'async' bodyParser: require 'body-parser' + child_process: require 'child_process' cookieParser: require 'cookie-parser' copy: require 'copy-to' csrf: require 'csrf' @@ -21,6 +22,7 @@ app.libs = mongoose: require 'mongoose' morgan: require 'morgan' nodemailer: require 'nodemailer' + os: require 'os' path: require 'path' redis: require 'redis' redisStore: require 'connect-redis' diff --git a/core/billing.coffee b/core/billing.coffee index 1609c7b..8aa541c 100644 --- a/core/billing.coffee +++ b/core/billing.coffee @@ -119,12 +119,12 @@ exports.joinPlan = (req, account, plan_name, callback) -> async.each _.difference(account.billing.services, original_account.billing.services), (service_name, callback) -> async.each pluggable.selectHook(account, "service.#{service_name}.enable"), (hook, callback) -> - hook.action req, callback + hook.filter req, callback , callback , -> unless _.isEqual original_account.resources_limit, account.resources_limit async.each pluggable.selectHook(account, 'account.resources_limit_changed'), (hook, callback) -> - hook.action account, callback + hook.filter account, callback , callback else callback() @@ -155,12 +155,12 @@ exports.leavePlan = (req, account, plan_name, callback) -> async.each leaved_services, (service_name, callback) -> async.each pluggable.selectHook(original_account, "service.#{service_name}.disable"), (hook, callback) -> - hook.action req, callback + hook.filter req, callback , callback , -> unless _.isEqual original_account.resources_limit, account.resources_limit async.each pluggable.selectHook(account, 'account.resources_limit_changed'), (hook, callback) -> - hook.action account, callback + hook.filter account, callback , callback else callback() diff --git a/plugin/linux/index.coffee b/plugin/linux/index.coffee index 615de99..314552f 100644 --- a/plugin/linux/index.coffee +++ b/plugin/linux/index.coffee @@ -1,6 +1,4 @@ -_ = require 'underscore' -async = require 'async' - +{async, _} = app.libs {pluggable, config} = app {requireAuthenticate} = app.middleware {wrapAsync} = app.utils @@ -39,8 +37,7 @@ exports.registerHook 'view.panel.widgets', exports.render 'widget', req, usage: resources_usage - , (html) -> - callback html + , callback exports.registerHook 'account.resources_limit_changed', always_notice: true @@ -49,29 +46,24 @@ exports.registerHook 'account.resources_limit_changed', exports.registerServiceHook 'enable', filter: (req, callback) -> - linux.createUser req.account, -> - linux.setResourceLimit req.account, callback + linux.createUser req.account, callback exports.registerServiceHook 'disable', filter: (req, callback) -> linux.deleteUser req.account, callback -app.get '/public/monitor', requireAuthenticate, (req, res) -> +app.express.get '/public/monitor', requireAuthenticate, (req, res) -> async.parallel resources_usage: (callback) -> linux.getResourceUsageByAccounts (result) -> - console.log result callback null, result system: wrapAsync linux.getSystemInfo storage: wrapAsync linux.getStorageInfo process_list: wrapAsync linux.getProcessList memory: wrapAsync linux.getMemoryInfo - x: (callback) -> - callback null, 'test' , (err, result) -> - console.log arguments - + logger.error err if err exports.render 'monitor', req, result, (html) -> res.send html diff --git a/plugin/linux/linux.coffee b/plugin/linux/linux.coffee index a9b9f60..6bdbfd4 100644 --- a/plugin/linux/linux.coffee +++ b/plugin/linux/linux.coffee @@ -1,10 +1,5 @@ -child_process = require 'child_process' -os = require 'os' -fs = require 'fs' -async = require 'async' -_ = require 'underscore' - -{cache} = app +{child_process, os, fs, async, _} = app.libs +{cache, logger} = app {wrapAsync} = app.utils monitor = require './monitor' @@ -18,7 +13,7 @@ exports.createUser = (account, callback) -> child_process.exec "sudo usermod -G #{account.username} -a www-data", callback ], (err) -> - console.error err if err + logger.error err if err cache.delete 'linux.getPasswdMap', -> callback() @@ -35,7 +30,7 @@ exports.deleteUser = (account, callback) -> child_process.exec "sudo groupdel #{account.username}", callback ], (err) -> - console.error err if err + logger.error err if err cache.delete 'linux.getPasswdMap', -> callback() @@ -50,32 +45,26 @@ exports.setResourceLimit = (account, callback) -> hard_inode_limit = (storage_limit * 64 * 1.2).toFixed() child_process.exec "sudo setquota -u #{account.username} #{soft_limit} #{hard_limit} #{soft_inode_limit} #{hard_inode_limit} -a", (err) -> - console.error err if err + logger.error err if err callback() exports.getPasswdMap = (callback) -> - cache.try 'linux.getPasswdMap', - command: cache.SETEX 120 - is_json: true - , (callback) -> + cache.try 'linux.getPasswdMap', (SETEX) -> fs.readFile '/etc/passwd', (err, content) -> - console.error err if err + logger.error err if err result = {} for line in _.compact(content.toString().split '\n') [username, password, uid] = line.split ':' result[uid] = username - callback result + SETEX result, 120 , callback exports.getMemoryInfo = (callback) -> - cache.try 'linux.getProcessList', - command: cache.SETEX 3 - is_json: true - , (callback) -> + cache.try 'linux.getProcessList', (SETEX) -> fs.readFile '/proc/meminfo', (err, content) -> - console.error err if err + logger.error err if err mapping = {} for line in content.toString().split('\n') @@ -92,7 +81,7 @@ exports.getMemoryInfo = (callback) -> swap_free_per = (mapping['SwapFree'] / mapping['SwapTotal'] * 100).toFixed() swap_used_per = 100 - swap_free_per - callback + SETEX used: used cached: mapping['Cached'] buffers: mapping['Buffers'] @@ -109,52 +98,49 @@ exports.getMemoryInfo = (callback) -> swap_used_per: swap_used_per swap_free_per: swap_free_per + , 3 , callback exports.getProcessList = (callback) -> - cache.try 'linux.getProcessList', - command: cache.SETEX 5 - is_json: true - , (callback) -> + cache.try 'linux.getProcessList', (SETEX) -> exports.getPasswdMap (passwd_map) -> child_process.exec "sudo ps awufxn", (err, stdout) -> - console.error err if err + logger.error err if err - callback _.map stdout.split('\n')[1 ... -1], (item) -> + result = _.map stdout.split('\n')[1 ... -1], (item) -> result = /^\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$/.exec item return { - user: do -> - if passwd_map[result[1]] - return passwd_map[result[1]] - else - return result[1] + user: do -> + if passwd_map[result[1]] + return passwd_map[result[1]] + else + return result[1] - time: do -> - [minute, second] = result[10].split ':' - return parseInt(minute) * 60 + parseInt(second) + time: do -> + [minute, second] = result[10].split ':' + return parseInt(minute) * 60 + parseInt(second) - pid: parseInt result[2] - cpu_per: parseInt result[3] - mem_per: parseInt result[4] - vsz: parseInt result[5] - rss: parseInt result[6] - tty: result[7] - stat: result[8] - start: result[9] - command: result[11] + pid: parseInt result[2] + cpu_per: parseInt result[3] + mem_per: parseInt result[4] + vsz: parseInt result[5] + rss: parseInt result[6] + tty: result[7] + stat: result[8] + start: result[9] + command: result[11] } + SETEX result, 5 + , callback exports.getStorageQuota = (callback) -> - cache.try 'linux.getStorageQuota', - command: cache.SETEX 60 - is_json: true - , (callback) -> + cache.try 'linux.getStorageQuota', (SETEX) -> child_process.exec "sudo repquota -a", (err, stdout) -> - console.error err if err + logger.error err if err lines = _.filter stdout.split('\n')[5...-1], (i) -> i lines = _.map lines, (line) -> @@ -170,15 +156,12 @@ exports.getStorageQuota = (callback) -> inode_used: parseInt inode_used } - callback _.indexBy lines, 'username' + SETEX _.indexBy(lines, 'username'), 60 , callback exports.getSystemInfo = (callback) -> - cache.try 'linux.getSystemInfo', - command: cache.SETEX 30 - is_json: true - , (callback) -> + cache.try 'linux.getSystemInfo', (SETEX) -> async.parallel system: (callback) -> fs.readFile '/etc/issue', (err, content) -> @@ -192,27 +175,26 @@ exports.getSystemInfo = (callback) -> unless item.internal result.push item.address - callback result + callback null, result , (err, result) -> - console.error err if err + logger.error err if err - callback _.extend result, + _.extend result, hostname: os.hostname() cpu: os.cpus()[0]['model'] uptime: os.uptime() loadavg: _.map os.loadavg(), (i) -> parseFloat(i.toFixed(2)) time: new Date() + SETEX result, 30 + , callback exports.getStorageInfo = (callback) -> - cache.try 'linux.getStorageInfo', - command: cache.SETEX 30 - is_json: true - , (callback) -> + cache.try 'linux.getStorageInfo', (SETEX) -> child_process.exec "df -h", (err, stdout) -> - console.error err if err + logger.error err if err disks = {} for line in stdout.split('\n') @@ -234,28 +216,25 @@ exports.getStorageInfo = (callback) -> used_per = (used / total * 100).toFixed() free_per = 100 - used_per - callback + SETEX used: used free: free total: total used_per: used_per free_per: free_per + , 30 , callback exports.getResourceUsageByAccounts = (callback) -> - cache.try 'linux.getStorageInfo', - command: cache.SETEX 20 - is_json: true - , (callback) -> - console.log 'getResourceUsageByAccounts' + cache.try 'linux.getStorageInfo', (SETEX) -> async.parallel storage_quota: wrapAsync exports.getStorageQuota process_list: wrapAsync exports.getProcessList , (err, result) -> - console.error err if err + logger.error err if err resources_usage_by_accounts = [] for username, usage of monitor.resources_usage @@ -266,7 +245,7 @@ exports.getResourceUsageByAccounts = (callback) -> storage: result.storage_quota[username]?.size_used ? 0 process: _.filter(result.process_list, (i) -> i.user == username).length - callback resources_usage_by_accounts + SETEX resources_usage_by_accounts, 20 , callback diff --git a/plugin/linux/monitor.coffee b/plugin/linux/monitor.coffee index 06a9f6a..1fe16d4 100644 --- a/plugin/linux/monitor.coffee +++ b/plugin/linux/monitor.coffee @@ -1,11 +1,6 @@ -child_process = require 'child_process' -os = require 'os' -fs = require 'fs' -async = require 'async' -_ = require 'underscore' - +{child_process, os, fs, async, _} = app.libs {config} = app -{mAccount} = app.models +{Account} = app.models linux = require './linux' @@ -63,7 +58,7 @@ exports.monitoring = (callback) -> usage.memory = parseFloat (usage.memory / base).toFixed(1) async.each _.keys(resources_usage), (username, callback) -> - mAccount.search username, (err, account) -> + Account.search username, (err, account) -> unless account return callback() diff --git a/plugin/linux/test/linux.test.coffee b/plugin/linux/test/linux.test.coffee new file mode 100644 index 0000000..9729e95 --- /dev/null +++ b/plugin/linux/test/linux.test.coffee @@ -0,0 +1,69 @@ +describe 'plugin/linux', -> + linux = null + agent = null + cache = null + redis = null + + before -> + linux = require '../linux' + {cache, redis} = app + {agent} = namespace.accountRouter + + describe 'router', -> + it 'GET monitor', (done) -> + agent.get '/public/monitor' + .expect 200 + .end done + + describe 'createUser', -> + it 'pending' + + describe 'deleteUser', -> + it 'pending' + + describe 'setResourceLimit', -> + it 'pending' + + describe 'getPasswdMap', -> + it 'pending' + + describe 'getMemoryInfo', -> + it 'pending' + + describe 'getProcessList', -> + it 'pending' + + describe 'getStorageQuota', -> + it 'pending' + + describe 'getSystemInfo', -> + before (done) -> + cache.delete 'linux.getSystemInfo', done + + it 'should success', (done) -> + linux.getSystemInfo (system) -> + system.system.should.match /Ubuntu/ + system.hostname.should.be.a 'string' + system.cpu.should.be.a 'string' + system.uptime.should.be.a 'number' + system.loadavg.length.should.be.equal 3 + system.time.should.be.exist + + for address in system.address + expect( + address.match(/\d+\.\d+\.\d+\.\d+/) or + address.match(/::/) + ).to.be.ok + + redis.get 'RP:linux.getSystemInfo', (err, system) -> + system.should.be.exist + done() + + describe 'getStorageInfo', -> + it 'pending' + + describe 'getResourceUsageByAccounts', -> + it 'pending' + + describe 'getResourceUsageByAccount', -> + it 'pending' diff --git a/plugin/linux/view/monitor.jade b/plugin/linux/view/monitor.jade index bec7661..e5dd522 100644 --- a/plugin/linux/view/monitor.jade +++ b/plugin/linux/view/monitor.jade @@ -1,7 +1,7 @@ extends ../../../core/view/layout prepend header - title #{t('server_monitor')} | #{t('app.name')} + title #{t('server_monitor')} | #{t(config.web.t_name)} append header link(rel='stylesheet', href='/plugin/linux/style/monitor.css') diff --git a/sample/rpvhost.config.coffee b/sample/rpvhost.config.coffee index 244ed00..4e6703d 100644 --- a/sample/rpvhost.config.coffee +++ b/sample/rpvhost.config.coffee @@ -15,7 +15,7 @@ module.exports = plugin: available_extensions: ['bitcoin', 'wiki', 'rpvhost'] - available_services: [] + available_services: ['linux'] billing: currency: 'CNY'