gecoscc/api/computers.py
#
# Copyright 2013, Junta de Andalucia
# http://www.juntadeandalucia.es/
#
# Authors:
# Emilio Sanchez <emilio.sanchez@gmail.com>
# Pablo Martin <goinnn@gmail.com>
#
# All rights reserved - EUPL License V 1.1
# https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
#
from builtins import next
from future import standard_library
standard_library.install_aliases()
from builtins import str
from builtins import map
import urllib.request, urllib.error, urllib.parse
from pyramid.httpexceptions import HTTPForbidden, HTTPFound
from bson import ObjectId
import pymongo
from cornice.resource import resource
from chef import Node as ChefNode
from chef import ChefError
from chef.exceptions import ChefServerError
from gecoscc.utils import get_chef_api, get_inheritance_tree_policies_list
from gecoscc.api import TreeLeafResourcePaginated
from gecoscc.models import Computer, Computers
from gecoscc.permissions import api_login_required
from gecoscc.utils import to_deep_dict
from gecoscc.i18n import gettext as _
from pyramid.threadlocal import get_current_request
import locale
import datetime
import re
import traceback
import logging
logger = logging.getLogger(__name__)
DEBUG_MODE_ENABLE_ATTR_PATH = 'gecos_ws_mgmt.single_node.debug_mode_res.enable_debug'
@resource(collection_path='/api/computers/',
path='/api/computers/{oid}/',
description='Computers resource',
validators=(api_login_required))
class ComputerResource(TreeLeafResourcePaginated):
schema_collection = Computers
schema_detail = Computer
objtype = 'computer'
mongo_filter = {
'type': objtype,
}
collection_name = 'nodes'
def get(self):
result = super(ComputerResource, self).get()
node_collection = self.request.db.nodes
if not result.get('node_chef_id', None):
return result
logger.info("/api/computers/: node_chef_id: %s" % (str(result.get('node_chef_id', None))))
try:
api = get_chef_api(self.request.registry.settings, self.request.user)
computer_node = ChefNode(result['node_chef_id'], api)
ohai = to_deep_dict(computer_node.attributes)
nodeid = result.get('_id',None)
usernames = [i['username'] for i in ohai.get('ohai_gecos', {}).get('users', [])]
users = list(node_collection.find({
"$and": [
{ "$or": [{"name": {"$in": usernames}}] },
{ "type":"user"},
{ "computers": {"$elemMatch": {"$eq": ObjectId(nodeid)}}}
]
},{'_id':1,'name':1,'path':1}))
# ObjectId to string for JSON serialize
[d.update({'_id': str(d['_id'])}) for d in users]
# Create a list of users that provides at least one user policy to this computer
users_inheritance_pre = list(node_collection.find({
"$and": [
{ "$or": [{"name": {"$in": usernames}}] },
{ "type":"user"},
{ "computers": {"$elemMatch": {"$eq": ObjectId(nodeid)}}}
]
},{'_id':1,'name':1,'path':1, 'inheritance': 1}))
[d.update({'_id': str(d['_id'])}) for d in users_inheritance_pre]
users_inheritance = []
for usr_inh in users_inheritance_pre:
if 'inheritance' in usr_inh:
policies_list = get_inheritance_tree_policies_list(usr_inh['inheritance'], [])
if len(policies_list) > 0:
users_inheritance.append(usr_inh)
cpu = ohai.get('cpu', {}).get('0', {})
dmi = ohai.get('dmi', {})
# debug_mode flag for logs tab
debug_mode = False
try:
debug_mode = computer_node.attributes.get_dotted(DEBUG_MODE_ENABLE_ATTR_PATH)
except KeyError:
pass
# Get logs info
logs_data = node_collection.find_one({"type": "computer", "_id": ObjectId(nodeid)}, {"logs": True})
logs = {}
if logs_data is not None and 'logs' in logs_data:
logs_data = logs_data['logs']
date_format = locale.nl_langinfo(locale.D_T_FMT)
date = datetime.datetime(*list(map(int, re.split('[^\d]', logs_data['date'])[:-1])))
localename = locale.normalize(get_current_request().locale_name+'.UTF-8')
logger.debug("/api/computers/: localename: %s" % (str(localename)))
locale.setlocale(locale.LC_TIME, localename)
logs['date'] = date.strftime(date_format)
logger.debug("/api/computers/: date: %s" % (str(logs['date'])))
logs['files'] = logs_data['files']
for filedata in logs_data['files']:
# Do not send file contents
del filedata['content']
# Get Help Channel info
help_channel_enabled = True
helpchannel_data = self.request.db.helpchannel.find(
{"computer_node_id" : result['node_chef_id']}).sort(
[("last_modified", pymongo.DESCENDING)]).limit(6)
helpchannel = {}
helpchannel['current'] = None
helpchannel['last'] = []
if helpchannel_data is not None:
c = 0
for hcdata in helpchannel_data:
# Format date
date_format = locale.nl_langinfo(locale.D_T_FMT)
logger.info("last_modified: {0}".format( hcdata['last_modified']))
last_mod = re.split('[^\d]', str(hcdata['last_modified']))
logger.info("last_mod: {0}".format(last_mod))
date = datetime.datetime(*list(map(int, last_mod[:-2])))
localename = locale.normalize(get_current_request().locale_name+'.UTF-8')
logger.debug("/api/computers/: localename: %s" % (str(localename)))
locale.setlocale(locale.LC_TIME, localename)
hcdata['last_modified'] = date.strftime(date_format)
if hcdata['user_node_id']:
# Format user
user_data = node_collection.find_one({"type": "user", "_id": ObjectId(hcdata['user_node_id'])})
if user_data:
hcdata['user'] = user_data['name']
else:
logger.error("User not found: {0}".format(hcdata['user_node_id']))
else:
hcdata['user'] = ''
if hcdata['adminuser_id']:
# Format user
user_data = self.request.db.adminusers.find_one({"_id": ObjectId(hcdata['adminuser_id'])})
if user_data:
hcdata['admin'] = user_data['username']
else:
logger.error("Admin user not found: {0}".format(hcdata['adminuser_id']))
else:
hcdata['admin'] = ''
# Translate status info
hcdata['status'] = _('Unknown status')
if hcdata['action'] == 'request':
hcdata['status'] = _('User is requesting support')
elif hcdata['action'] == 'accepted':
hcdata['status'] = _('User is requesting support')
elif hcdata['action'] == 'finished user':
hcdata['status'] = _('Terminated by user')
elif hcdata['action'] == 'finished tech':
hcdata['status'] = _('Terminated by technician')
elif hcdata['action'] == 'finished error':
hcdata['status'] = _('Terminated because of a communication error')
elif hcdata['action'] == 'giving support':
hcdata['status'] = _('The technician is giving support to the user')
hcdata['_id'] = str(hcdata['_id'])
if (c==0 and hcdata['action']=='accepted'):
helpchannel['current'] = hcdata
else:
helpchannel['last'].append(hcdata)
c = c + 1
result.update({'ohai': ohai,
'users': users, # Users related with this computer
'users_inheritance': users_inheritance, # Users related with this computer that provides at least one user policy
'uptime': ohai.get('uptime', ''),
#'gcc_link': ohai.get('gcc_link',True),
'ipaddress': ohai.get('ipaddress', ''),
'cpu': '%s %s' % (cpu.get('vendor_id', ''), cpu.get('model_name', '')),
'product_name': dmi.get('system', {}).get('product_name', ''),
'manufacturer': dmi.get('system', {}).get('manufacturer', ''),
'ram': ohai.get('memory', {}).get('total', ''),
'lsb': ohai.get('lsb', {}),
'kernel': ohai.get('kernel', {}),
'filesystem': ohai.get('filesystem', {}),
'debug_mode': debug_mode,
'logs': logs,
'helpchannel': helpchannel,
'help_channel_enabled': help_channel_enabled
})
except (urllib.error.URLError, ChefError, ChefServerError):
logger.error("/api/computers/: error getting data: node_chef_id: %s " % (str(result.get('node_chef_id', None))))
logger.error(traceback.format_exc())
return result
def put(self):
if ('action' in self.request.GET and
self.request.GET['action'] == 'refresh_policies'):
# Refresh policies
return super(ComputerResource, self).refresh_policies()
else:
# Save object
return super(ComputerResource, self).put()
@resource(collection_path='/api/computers/',
path='/api/computers/support/{oid}/',
description='Computers resource',
validators=(api_login_required))
class ComputerSupportResource(TreeLeafResourcePaginated):
schema_collection = Computers
schema_detail = Computer
objtype = 'computer'
mongo_filter = {
'type': objtype,
}
collection_name = 'nodes'
def get(self):
result = super(ComputerSupportResource, self).get()
if not result.get('node_chef_id', None):
return result
helpchannel_data = self.request.db.helpchannel.find(
{"computer_node_id" : result['node_chef_id']}).sort(
[("last_modified", pymongo.DESCENDING)]).limit(1)
if helpchannel_data is None:
logger.error("/api/computers/support/: There is no support request for this computer!")
raise HTTPForbidden()
hcdata = next(helpchannel_data)
if hcdata is None or hcdata['action'] != 'accepted':
logger.error("/api/computers/support/: There is no support request for this computer!")
raise HTTPForbidden()
else:
# Set this user as the technician that gives support
admin = self.request.user
logger.debug("user = {0}".format(self.request.user))
ou_managed = False
if 'ou_managed' in admin:
ou_managed = admin['ou_managed']
if 'ou_remote' in admin:
ou_managed += admin['ou_remote']
is_superuser = False
if 'is_superuser' in admin:
is_superuser = admin['is_superuser']
self.request.db.helpchannel.update_one({
'_id': hcdata['_id']
}, {
'$set': {
'action': 'giving support',
'adminuser_id': str(admin['_id']),
'adminuser_ou_managed': ou_managed,
'adminuser_is_superuser': is_superuser
}
})
# Redirect to suppor NoVNC page
url = hcdata['helpchannel_server'].replace('wss://', 'https://')
url = url.replace('/wsServer', '/')
url = url + '?repeaterID=ID:' + hcdata['token']
raise HTTPFound(location=url)