Exemplo n.º 1
0
def process_request(connection, request, cfm, authdata, authname, skipauth):
    if isinstance(request, tlvdata.ClientFile):
        cfm.add_client_file(request)
        return
    if not isinstance(request, dict):
        raise exc.InvalidArgumentException
    operation = request['operation']
    path = request['path']
    params = request.get('parameters', {})
    hdlr = None
    auditmsg = {
        'operation': operation,
        'target': path,
    }
    if not skipauth:
        authdata = auth.authorize(authdata[2], path, authdata[3], operation)
        if not authdata:
            auditmsg['allowed'] = False
            auditlog.log(auditmsg)
            raise exc.ForbiddenRequest()
        auditmsg['user'] = authdata[2]
        if authdata[3] is not None:
            auditmsg['tenant'] = authdata[3]
    auditmsg['allowed'] = True
    if _should_authlog(path, operation):
        tlvdata.unicode_dictvalues(auditmsg)
        auditlog.log(auditmsg)
    try:
        if operation == 'start':
            return start_term(authname, cfm, connection, params, path,
                              authdata, skipauth)
        elif operation == 'shutdown' and skipauth:
            configmanager.ConfigManager.shutdown()
        else:
            hdlr = pluginapi.handle_path(path, operation, cfm, params)
    except exc.NotFoundException as e:
        send_data(connection, {
            "errorcode": 404,
            "error": "Target not found - " + str(e)
        })
        send_data(connection, {"_requestdone": 1})
    except exc.InvalidArgumentException as e:
        send_data(connection, {
            "errorcode": 400,
            "error": "Bad Request - " + str(e)
        })
        send_data(connection, {"_requestdone": 1})
    send_response(hdlr, connection)
    return
Exemplo n.º 2
0
def update(nodes, element, configmanager, inputdata):
    emebs = configmanager.get_node_attributes(
        nodes, (u'enclosure.manager', u'enclosure.bay'))
    for node in nodes:
        try:
            em = emebs[node]['enclosure.manager']['value']
            eb = emebs[node]['enclosure.bay']['value']
        except KeyError:
            yield msg.ConfluentNodeError(
                node,
                'Reseat is only supported on servers in an enclosure, and '
                'with enclosure.manager and enclosure.bay defined')
            continue
        try:
            for rsp in core.handle_path(
                    '/nodes/{0}/_enclosure/reseat_bay'.format(em),
                    'update', configmanager,
                    inputdata={'reseat': int(eb)}):
                yield rsp
        except pygexc.UnsupportedFunctionality as uf:
            yield msg.ConfluentNodeError(node, str(uf))
Exemplo n.º 3
0
def update(nodes, element, configmanager, inputdata):
    emebs = configmanager.get_node_attributes(
        nodes, (u'enclosure.manager', u'enclosure.bay'))
    for node in nodes:
        try:
            em = emebs[node]['enclosure.manager']['value']
            eb = emebs[node]['enclosure.bay']['value']
        except KeyError:
            em = node
            eb = -1
        try:
            for rsp in core.handle_path(
                    '/nodes/{0}/_enclosure/reseat_bay'.format(em),
                    'update',
                    configmanager,
                    inputdata={'reseat': int(eb)}):
                yield rsp
        except pygexc.UnsupportedFunctionality as uf:
            yield msg.ConfluentNodeError(node, str(uf))
        except exc.TargetEndpointUnreachable as uf:
            yield msg.ConfluentNodeError(node, str(uf))
Exemplo n.º 4
0
def process_request(connection, request, cfm, authdata, authname, skipauth):
    if not isinstance(request, dict):
        raise exc.InvalidArgumentException
    operation = request['operation']
    path = request['path']
    params = request.get('parameters', {})
    hdlr = None
    if not skipauth:
        authdata = auth.authorize(authdata[2], path, authdata[3], operation)
        auditmsg = {
            'operation': operation,
            'target': path,
        }
        if authdata is None:
            auditmsg['allowed'] = False
            auditlog.log(auditmsg)
            raise exc.ForbiddenRequest()
        auditmsg['user'] = authdata[2]
        if authdata[3] is not None:
            auditmsg['tenant'] = authdata[3]
        auditmsg['allowed'] = True
        auditlog.log(auditmsg)
    try:
        if operation == 'start':
            return start_term(authname, cfm, connection, params, path)
        elif operation == 'shutdown':
            configmanager.ConfigManager.shutdown()
        else:
            hdlr = pluginapi.handle_path(path, operation, cfm, params)
    except exc.NotFoundException as e:
        send_data(connection, {"errorcode": 404,
                                  "error": "Target not found - " + str(e)})
        send_data(connection, {"_requestdone": 1})
    except exc.InvalidArgumentException as e:
        send_data(connection, {"errorcode": 400,
                                  "error": "Bad Request - " + str(e)})
        send_data(connection, {"_requestdone": 1})
    send_response(hdlr, connection)
    return
Exemplo n.º 5
0
def resourcehandler_backend(env, start_response):
    """Function to handle new wsgi requests
    """
    mimetype, extension = _pick_mimetype(env)
    headers = [('Content-Type', mimetype), ('Cache-Control', 'no-store'),
               ('Pragma', 'no-cache'), ('X-Content-Type-Options', 'nosniff'),
               ('Content-Security-Policy', "default-src 'self'"),
               ('X-XSS-Protection', '1; mode=block'),
               ('X-Frame-Options', 'deny'),
               ('Strict-Transport-Security', 'max-age=86400'),
               ('X-Permitted-Cross-Domain-Policies', 'none')]
    reqbody = None
    reqtype = None
    if 'CONTENT_LENGTH' in env and int(env['CONTENT_LENGTH']) > 0:
        reqbody = env['wsgi.input'].read(int(env['CONTENT_LENGTH']))
        reqtype = env['CONTENT_TYPE']
    operation = opmap[env['REQUEST_METHOD']]
    querydict = _get_query_dict(env, reqbody, reqtype)
    if 'restexplorerop' in querydict:
        operation = querydict['restexplorerop']
        del querydict['restexplorerop']
    authorized = _authorize_request(env, operation)
    if 'logout' in authorized:
        start_response('200 Successful logout', headers)
        yield ('{"result": "200 - Successful logout"}')
        return
    if 'HTTP_SUPPRESSAUTHHEADER' in env or 'HTTP_CONFLUENTAUTHTOKEN' in env:
        badauth = [('Content-type', 'text/plain')]
    else:
        badauth = [('Content-type', 'text/plain'),
                   ('WWW-Authenticate', 'Basic realm="confluent"')]
    if authorized['code'] == 401:
        start_response('401 Authentication Required', badauth)
        yield 'authentication required'
        return
    if authorized['code'] == 403:
        start_response('403 Forbidden', badauth)
        yield 'authorization failed'
        return
    if authorized['code'] != 200:
        raise Exception("Unrecognized code from auth engine")
    headers.extend(("Set-Cookie", m.OutputString())
                   for m in authorized['cookie'].values())
    cfgmgr = authorized['cfgmgr']
    if (operation
            == 'create') and env['PATH_INFO'] == '/sessions/current/async':
        pagecontent = ""
        try:
            for rsp in _assemble_json(
                    confluent.asynchttp.handle_async(
                        env, querydict,
                        httpsessions[authorized['sessionid']]['inflight'])):
                pagecontent += rsp
            start_response("200 OK", headers)
            yield pagecontent
            return
        except exc.ConfluentException as e:
            if e.apierrorcode == 500:
                # raise generics to trigger the tracelog
                raise
            start_response('{0} {1}'.format(e.apierrorcode, e.apierrorstr),
                           headers)
            yield e.get_error_body()
    elif (env['PATH_INFO'].endswith('/forward/web')
          and env['PATH_INFO'].startswith('/nodes/')):
        prefix, _, _ = env['PATH_INFO'].partition('/forward/web')
        _, _, nodename = prefix.rpartition('/')
        hm = cfgmgr.get_node_attributes(nodename, 'hardwaremanagement.manager')
        targip = hm.get(nodename, {}).get('hardwaremanagement.manager',
                                          {}).get('value', None)
        if not targip:
            start_response('404 Not Found', headers)
            yield 'No hardwaremanagemnet.manager defined for node'
            return
        funport = forwarder.get_port(targip, env['HTTP_X_FORWARDED_FOR'],
                                     authorized['sessionid'])
        host = env['HTTP_X_FORWARDED_HOST']
        url = 'https://{0}:{1}/'.format(host, funport)
        start_response('302', [('Location', url)])
        yield 'Our princess is in another castle!'
        return
    elif (operation == 'create'
          and ('/console/session' in env['PATH_INFO']
               or '/shell/sessions/' in env['PATH_INFO'])):
        #hard bake JSON into this path, do not support other incarnations
        if '/console/session' in env['PATH_INFO']:
            prefix, _, _ = env['PATH_INFO'].partition('/console/session')
            shellsession = False
        elif '/shell/sessions/' in env['PATH_INFO']:
            prefix, _, _ = env['PATH_INFO'].partition('/shell/sessions')
            shellsession = True
        _, _, nodename = prefix.rpartition('/')
        if 'session' not in querydict.keys() or not querydict['session']:
            auditmsg = {
                'operation': 'start',
                'target': env['PATH_INFO'],
                'user': authorized['username'],
            }
            if 'tenant' in authorized:
                auditmsg['tenant'] = authorized['tenant']
            auditlog.log(auditmsg)
            # Request for new session
            skipreplay = False
            if 'skipreplay' in querydict and querydict['skipreplay']:
                skipreplay = True
            datacallback = None
            async = None
            if 'HTTP_CONFLUENTASYNCID' in env:
                async = confluent.asynchttp.get_async(env, querydict)
                termrel = async .set_term_relation(env)
                datacallback = termrel.got_data
            try:
                if shellsession:
                    consession = shellserver.ShellSession(
                        node=nodename,
                        configmanager=cfgmgr,
                        username=authorized['username'],
                        skipreplay=skipreplay,
                        datacallback=datacallback)
                else:
                    consession = consoleserver.ConsoleSession(
                        node=nodename,
                        configmanager=cfgmgr,
                        username=authorized['username'],
                        skipreplay=skipreplay,
                        datacallback=datacallback)
            except exc.NotFoundException:
                start_response("404 Not found", headers)
                yield "404 - Request Path not recognized"
                return
            if not consession:
                start_response("500 Internal Server Error", headers)
                return
            sessid = _assign_consessionid(consession)
            if async:
                async .add_console_session(sessid)
            start_response('200 OK', headers)
            yield '{"session":"%s","data":""}' % sessid
            return
        elif 'bytes' in querydict.keys():  # not keycodes...
            myinput = querydict['bytes']
            sessid = querydict['session']
            if sessid not in consolesessions:
                start_response('400 Expired Session', headers)
                return
            consolesessions[sessid]['expiry'] = time.time() + 90
            consolesessions[sessid]['session'].write(myinput)
            start_response('200 OK', headers)
            yield json.dumps({'session': querydict['session']})
            return  # client has requests to send or receive, not both...
        elif 'closesession' in querydict:
            consolesessions[querydict['session']]['session'].destroy()
            del consolesessions[querydict['session']]
            start_response('200 OK', headers)
            yield '{"sessionclosed": true}'
            return
        elif 'action' in querydict:
            if querydict['action'] == 'break':
                consolesessions[querydict['session']]['session'].send_break()
            elif querydict['action'] == 'reopen':
                consolesessions[querydict['session']]['session'].reopen()
            else:
                start_response('400 Bad Request')
                yield 'Unrecognized action ' + querydict['action']
                return
            start_response('200 OK', headers)
            yield json.dumps({'session': querydict['session']})
        else:  # no keys, but a session, means it's hooking to receive data
            sessid = querydict['session']
            if sessid not in consolesessions:
                start_response('400 Expired Session', headers)
                yield ''
                return
            consolesessions[sessid]['expiry'] = time.time() + 90
            # add our thread to the 'inflight' to have a hook to terminate
            # a long polling request
            loggedout = None
            mythreadid = greenlet.getcurrent()
            httpsessions[authorized['sessionid']]['inflight'].add(mythreadid)
            try:
                outdata = consolesessions[sessid]['session'].get_next_output(
                    timeout=25)
            except greenlet.GreenletExit as ge:
                loggedout = ge
            httpsessions[authorized['sessionid']]['inflight'].discard(
                mythreadid)
            if sessid not in consolesessions:
                start_response('400 Expired Session', headers)
                yield ''
                return
            if loggedout is not None:
                consolesessions[sessid]['session'].destroy()
                start_response('401 Logged out', headers)
                yield '{"loggedout": 1}'
                return
            bufferage = False
            if 'stampsent' not in consolesessions[sessid]:
                consolesessions[sessid]['stampsent'] = True
                bufferage = consolesessions[sessid]['session'].get_buffer_age()
            if isinstance(outdata, dict):
                rspdata = outdata
                rspdata['session'] = querydict['session']
            else:
                rspdata = {'session': querydict['session'], 'data': outdata}
            if bufferage is not False:
                rspdata['bufferage'] = bufferage
            try:
                rsp = json.dumps(rspdata)
            except UnicodeDecodeError:
                try:
                    rsp = json.dumps(rspdata, encoding='cp437')
                except UnicodeDecodeError:
                    rsp = json.dumps({
                        'session': querydict['session'],
                        'data': 'DECODEERROR'
                    })
            start_response('200 OK', headers)
            yield rsp
            return
    else:
        # normal request
        url = env['PATH_INFO']
        url = url.replace('.json', '')
        url = url.replace('.html', '')
        if url == '/sessions/current/info':
            start_response('200 OK', headers)
            sessinfo = {'username': authorized['username']}
            if 'authtoken' in authorized:
                sessinfo['authtoken'] = authorized['authtoken']
            yield json.dumps(sessinfo)
            return
        resource = '.' + url[url.rindex('/'):]
        lquerydict = copy.deepcopy(querydict)
        try:
            hdlr = pluginapi.handle_path(url, operation, cfgmgr, querydict)
            if 'HTTP_CONFLUENTASYNCID' in env:
                confluent.asynchttp.run_handler(hdlr, env)
                start_response('202 Accepted', headers)
                yield 'Request queued'
                return
            pagecontent = ""
            if mimetype == 'text/html':
                for datum in _assemble_html(hdlr, resource, lquerydict, url,
                                            extension):
                    pagecontent += datum
            else:
                for datum in _assemble_json(hdlr, resource, url, extension):
                    pagecontent += datum
            start_response('200 OK', headers)
            yield pagecontent
        except exc.ConfluentException as e:
            if ((not isinstance(e, exc.LockedCredentials))
                    and e.apierrorcode == 500):
                # raise generics to trigger the tracelog
                raise
            start_response('{0} {1}'.format(e.apierrorcode, e.apierrorstr),
                           headers)
            yield e.get_error_body()
Exemplo n.º 6
0
 def _connect_backend(self):
     if self._console:
         self._console.close()
         self._console = None
     self.connectstate = 'connecting'
     self._send_rcpts({'connectstate': self.connectstate})
     if self.reconnect:
         self.reconnect.cancel()
         self.reconnect = None
     try:
         self._console = plugin.handle_path(
             self._plugin_path.format(self.node),
             "create", self.cfgmgr)
     except exc.NotImplementedException:
         self._console = None
     except:
         _tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event,
                       event=log.Events.stacktrace)
     if not isinstance(self._console, conapi.Console):
         self.connectstate = 'unconnected'
         self.error = 'misconfigured'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         return
     self.send_break = self._console.send_break
     if self._attribwatcher:
         self.cfgmgr.remove_watcher(self._attribwatcher)
         self._attribwatcher = None
     if hasattr(self._console, "configattributes"):
         attribstowatch = self._console.configattributes | self._genwatchattribs
     else:
         attribstowatch = self._genwatchattribs
     if self._genwatchattribs:
         self._attribwatcher = self.cfgmgr.watch_attributes(
             (self.node,), attribstowatch, self._attribschanged)
     try:
         self._console.connect(self.get_console_output)
     except exc.TargetEndpointBadCredentials:
         self.error = 'badcredentials'
         self.connectstate = 'unconnected'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         retrytime = 120 + (120 * random.random())
         if not self.reconnect:
             self.reconnect = eventlet.spawn_after(retrytime, self._connect)
         return
     except exc.TargetEndpointUnreachable:
         self.error = 'unreachable'
         self.connectstate = 'unconnected'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         retrytime = 120 + (120 * random.random())
         if not self.reconnect:
             self.reconnect = eventlet.spawn_after(retrytime, self._connect)
         return
     except Exception:
         _tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event,
                       event=log.Events.stacktrace)
         self.error = 'unknown'
         self.connectstate = 'unconnected'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         retrytime = 120 + (120 * random.random())
         if not self.reconnect:
             self.reconnect = eventlet.spawn_after(retrytime, self._connect)
         return
     self._got_connected()
Exemplo n.º 7
0
 def _connect_backend(self):
     if self._console:
         self._console.close()
         self._console = None
     self.connectstate = 'connecting'
     self._send_rcpts({'connectstate': self.connectstate})
     if self.reconnect:
         self.reconnect.cancel()
         self.reconnect = None
     try:
         self._console = plugin.handle_path(
             self._plugin_path.format(self.node),
             "create", self.cfgmgr)
     except:
         _tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event,
                       event=log.Events.stacktrace)
     if not isinstance(self._console, conapi.Console):
         self.connectstate = 'unconnected'
         self.error = 'misconfigured'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         return
     self.send_break = self._console.send_break
     if self._attribwatcher:
         self.cfgmgr.remove_watcher(self._attribwatcher)
         self._attribwatcher = None
     if hasattr(self._console, "configattributes"):
         attribstowatch = self._console.configattributes | self._genwatchattribs
     else:
         attribstowatch = self._genwatchattribs
     if self._genwatchattribs:
         self._attribwatcher = self.cfgmgr.watch_attributes(
             (self.node,), attribstowatch, self._attribschanged)
     try:
         self._console.connect(self.get_console_output)
     except exc.TargetEndpointBadCredentials:
         self.error = 'badcredentials'
         self.connectstate = 'unconnected'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         retrytime = 120 + (120 * random.random())
         if not self.reconnect:
             self.reconnect = eventlet.spawn_after(retrytime, self._connect)
         return
     except exc.TargetEndpointUnreachable:
         self.error = 'unreachable'
         self.connectstate = 'unconnected'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         retrytime = 120 + (120 * random.random())
         if not self.reconnect:
             self.reconnect = eventlet.spawn_after(retrytime, self._connect)
         return
     except Exception:
         _tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event,
                       event=log.Events.stacktrace)
         self.error = 'unknown'
         self.connectstate = 'unconnected'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         retrytime = 120 + (120 * random.random())
         if not self.reconnect:
             self.reconnect = eventlet.spawn_after(retrytime, self._connect)
         return
     self._got_connected()
Exemplo n.º 8
0
def resourcehandler_backend(env, start_response):
    """Function to handle new wsgi requests
    """
    mimetype, extension = _pick_mimetype(env)
    headers = [('Content-Type', mimetype), ('Cache-Control', 'no-store'),
               ('Pragma', 'no-cache'),
               ('X-Content-Type-Options', 'nosniff'),
               ('Content-Security-Policy', "default-src 'self'"),
               ('X-XSS-Protection', '1'), ('X-Frame-Options', 'deny'),
               ('Strict-Transport-Security', 'max-age=86400'),
               ('X-Permitted-Cross-Domain-Policies', 'none')]
    reqbody = None
    reqtype = None
    if 'CONTENT_LENGTH' in env and int(env['CONTENT_LENGTH']) > 0:
        reqbody = env['wsgi.input'].read(int(env['CONTENT_LENGTH']))
        reqtype = env['CONTENT_TYPE']
    operation = opmap[env['REQUEST_METHOD']]
    querydict = _get_query_dict(env, reqbody, reqtype)
    if 'restexplorerop' in querydict:
        operation = querydict['restexplorerop']
        del querydict['restexplorerop']
    authorized = _authorize_request(env, operation)
    if 'logout' in authorized:
        start_response('200 Successful logout', headers)
        yield('{"result": "200 - Successful logout"}')
        return
    if 'HTTP_SUPPRESSAUTHHEADER' in env or 'HTTP_CONFLUENTAUTHTOKEN' in env:
        badauth = [('Content-type', 'text/plain')]
    else:
        badauth = [('Content-type', 'text/plain'),
                   ('WWW-Authenticate', 'Basic realm="confluent"')]
    if authorized['code'] == 401:
        start_response('401 Authentication Required', badauth)
        yield 'authentication required'
        return
    if authorized['code'] == 403:
        start_response('403 Forbidden', badauth)
        yield 'authorization failed'
        return
    if authorized['code'] != 200:
        raise Exception("Unrecognized code from auth engine")
    headers.extend(
        ("Set-Cookie", m.OutputString())
        for m in authorized['cookie'].values())
    cfgmgr = authorized['cfgmgr']
    if (operation == 'create') and env['PATH_INFO'] == '/sessions/current/async':
        pagecontent = ""
        try:
            for rsp in _assemble_json(
                    confluent.asynchttp.handle_async(
                            env, querydict,
                            httpsessions[authorized['sessionid']]['inflight'])):
                pagecontent += rsp
            start_response("200 OK", headers)
            yield pagecontent
            return
        except exc.ConfluentException as e:
            if e.apierrorcode == 500:
                # raise generics to trigger the tracelog
                raise
            start_response('{0} {1}'.format(e.apierrorcode, e.apierrorstr),
                           headers)
            yield e.get_error_body()
    elif (operation == 'create' and ('/console/session' in env['PATH_INFO'] or
            '/shell/sessions/' in env['PATH_INFO'])):
        #hard bake JSON into this path, do not support other incarnations
        if '/console/session' in env['PATH_INFO']:
            prefix, _, _ = env['PATH_INFO'].partition('/console/session')
            shellsession = False
        elif '/shell/sessions/' in env['PATH_INFO']:
            prefix, _, _ = env['PATH_INFO'].partition('/shell/sessions')
            shellsession = True
        _, _, nodename = prefix.rpartition('/')
        if 'session' not in querydict.keys() or not querydict['session']:
            auditmsg = {
                'operation': 'start',
                'target': env['PATH_INFO'],
                'user': authorized['username'],
            }
            if 'tenant' in authorized:
                auditmsg['tenant'] = authorized['tenant']
            auditlog.log(auditmsg)
            # Request for new session
            skipreplay = False
            if 'skipreplay' in querydict and querydict['skipreplay']:
                skipreplay = True
            datacallback = None
            async = None
            if 'HTTP_CONFLUENTASYNCID' in env:
                async = confluent.asynchttp.get_async(env, querydict)
                termrel = async.set_term_relation(env)
                datacallback = termrel.got_data
            try:
                if shellsession:
                    consession = shellserver.ShellSession(
                        node=nodename, configmanager=cfgmgr,
                        username=authorized['username'], skipreplay=skipreplay,
                        datacallback=datacallback
                    )
                else:
                    consession = consoleserver.ConsoleSession(
                        node=nodename, configmanager=cfgmgr,
                        username=authorized['username'], skipreplay=skipreplay,
                        datacallback=datacallback
                    )
            except exc.NotFoundException:
                start_response("404 Not found", headers)
                yield "404 - Request Path not recognized"
                return
            if not consession:
                start_response("500 Internal Server Error", headers)
                return
            sessid = _assign_consessionid(consession)
            if async:
                async.add_console_session(sessid)
            start_response('200 OK', headers)
            yield '{"session":"%s","data":""}' % sessid
            return
        elif 'bytes' in querydict.keys():  # not keycodes...
            myinput = querydict['bytes']
            sessid = querydict['session']
            if sessid not in consolesessions:
                start_response('400 Expired Session', headers)
                return
            consolesessions[sessid]['expiry'] = time.time() + 90
            consolesessions[sessid]['session'].write(myinput)
            start_response('200 OK', headers)
            yield json.dumps({'session': querydict['session']})
            return  # client has requests to send or receive, not both...
        elif 'closesession' in querydict:
            consolesessions[querydict['session']]['session'].destroy()
            del consolesessions[querydict['session']]
            start_response('200 OK', headers)
            yield '{"sessionclosed": true}'
            return
        elif 'action' in querydict:
            if querydict['action'] == 'break':
                consolesessions[querydict['session']]['session'].send_break()
            elif querydict['action'] == 'reopen':
                consolesessions[querydict['session']]['session'].reopen()
            else:
                start_response('400 Bad Request')
                yield 'Unrecognized action ' + querydict['action']
                return
            start_response('200 OK', headers)
            yield json.dumps({'session': querydict['session']})
        else:  # no keys, but a session, means it's hooking to receive data
            sessid = querydict['session']
            if sessid not in consolesessions:
                start_response('400 Expired Session', headers)
                yield ''
                return
            consolesessions[sessid]['expiry'] = time.time() + 90
            # add our thread to the 'inflight' to have a hook to terminate
            # a long polling request
            loggedout = None
            mythreadid = greenlet.getcurrent()
            httpsessions[authorized['sessionid']]['inflight'].add(mythreadid)
            try:
                outdata = consolesessions[sessid]['session'].get_next_output(
                    timeout=25)
            except greenlet.GreenletExit as ge:
                loggedout = ge
            httpsessions[authorized['sessionid']]['inflight'].discard(
                    mythreadid)
            if sessid not in consolesessions:
                start_response('400 Expired Session', headers)
                yield ''
                return
            if loggedout is not None:
                consolesessions[sessid]['session'].destroy()
                start_response('401 Logged out', headers)
                yield '{"loggedout": 1}'
                return
            bufferage = False
            if 'stampsent' not in consolesessions[sessid]:
                consolesessions[sessid]['stampsent'] = True
                bufferage = consolesessions[sessid]['session'].get_buffer_age()
            if isinstance(outdata, dict):
                rspdata = outdata
                rspdata['session'] = querydict['session']
            else:
                rspdata = {'session': querydict['session'],
                           'data': outdata}
            if bufferage is not False:
                rspdata['bufferage'] = bufferage
            try:
                rsp = json.dumps(rspdata)
            except UnicodeDecodeError:
                try:
                    rsp = json.dumps(rspdata, encoding='cp437')
                except UnicodeDecodeError:
                    rsp = json.dumps({'session': querydict['session'],
                                      'data': 'DECODEERROR'})
            start_response('200 OK', headers)
            yield rsp
            return
    else:
        # normal request
        url = env['PATH_INFO']
        url = url.replace('.json', '')
        url = url.replace('.html', '')
        if url == '/sessions/current/info':
            start_response('200 OK', headers)
            sessinfo = {'username': authorized['username']}
            if 'authtoken' in authorized:
                sessinfo['authtoken'] = authorized['authtoken']
            yield json.dumps(sessinfo)
            return
        resource = '.' + url[url.rindex('/'):]
        lquerydict = copy.deepcopy(querydict)
        try:
            hdlr = pluginapi.handle_path(url, operation,
                                         cfgmgr, querydict)
            if 'HTTP_CONFLUENTASYNCID' in env:
                confluent.asynchttp.run_handler(hdlr, env)
                start_response('202 Accepted', headers)
                yield 'Request queued'
                return
            pagecontent = ""
            if mimetype == 'text/html':
                for datum in _assemble_html(hdlr, resource, lquerydict, url,
                                            extension):
                    pagecontent += datum
            else:
                for datum in _assemble_json(hdlr, resource, url, extension):
                    pagecontent += datum
            start_response('200 OK', headers)
            yield pagecontent
        except exc.ConfluentException as e:
            if ((not isinstance(e, exc.LockedCredentials)) and
                    e.apierrorcode == 500):
                # raise generics to trigger the tracelog
                raise
            start_response('{0} {1}'.format(e.apierrorcode, e.apierrorstr),
                           headers)
            yield e.get_error_body()
Exemplo n.º 9
0
def process_request(connection, request, cfm, authdata, authname, skipauth):
    if not isinstance(request, dict):
        raise ValueError
    operation = request['operation']
    path = request['path']
    params = request.get('parameters', None)
    hdlr = None
    if not skipauth:
        authdata = auth.authorize(authdata[2], path, authdata[3], operation)
        auditmsg = {
            'operation': operation,
            'user': authdata[2],
            'target': path,
        }
        if authdata[3] is not None:
            auditmsg['tenant'] = authdata[3]
        if authdata is None:
            auditmsg['allowed'] = False
            auditlog.log(auditmsg)
            raise exc.ForbiddenRequest()
        auditmsg['allowed'] = True
        auditlog.log(auditmsg)
    try:
        if operation == 'start':
            elems = path.split('/')
            if elems[3] != "console":
                raise exc.InvalidArgumentException()
            node = elems[2]
            ccons = ClientConsole(connection)
            skipreplay = False
            if params and 'skipreplay' in params and params['skipreplay']:
                skipreplay = True
            consession = consoleserver.ConsoleSession(
                node=node, configmanager=cfm, username=authname,
                datacallback=ccons.sendall, skipreplay=skipreplay)
            if consession is None:
                raise Exception("TODO")
            send_data(connection, {'started': 1})
            ccons.startsending()
            bufferage = consession.get_buffer_age()
            if bufferage is not False:
                send_data(connection, {'bufferage': bufferage})
            while consession is not None:
                data = tlvdata.recv(connection)
                if type(data) == dict:
                    if data['operation'] == 'stop':
                        consession.destroy()
                        return
                    elif data['operation'] == 'break':
                        consession.send_break()
                        continue
                    elif data['operation'] == 'reopen':
                        consession.reopen()
                        continue
                    else:
                        raise Exception("TODO")
                if not data:
                    consession.destroy()
                    return
                consession.write(data)
        elif operation == 'shutdown':
            configmanager.ConfigManager.shutdown()
        else:
            hdlr = pluginapi.handle_path(path, operation, cfm, params)
    except exc.NotFoundException as e:
        send_data(connection, {"errorcode": 404,
                                  "error": "Target not found - " + str(e)})
        send_data(connection, {"_requestdone": 1})
    except exc.InvalidArgumentException as e:
        send_data(connection, {"errorcode": 400,
                                  "error": "Bad Request - " + str(e)})
        send_data(connection, {"_requestdone": 1})
    send_response(hdlr, connection)
    return
Exemplo n.º 10
0
 def _connect_backend(self):
     if self._console:
         self._console.close()
         self._console = None
     self.connectstate = 'connecting'
     self._send_rcpts({'connectstate': self.connectstate})
     if self.reconnect:
         self.reconnect.cancel()
         self.reconnect = None
     try:
         self._console = list(plugin.handle_path(
             self._plugin_path.format(self.node),
             "create", self.cfgmgr))[0]
     except (exc.NotImplementedException, exc.NotFoundException):
         self._console = None
     except:
         if _tracelog:
             _tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event,
                           event=log.Events.stacktrace)
         else:
             print(traceback.format_exc())
     if not isinstance(self._console, conapi.Console):
         self.clearbuffer()
         self.connectstate = 'unconnected'
         self.error = 'misconfigured'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         self.feedbuffer(
             '\x1bc\x1b[2J\x1b[1;1H[The console.method attribute for this node is '
             'not configured,\r\nset it to a valid value for console '
             'function]')
         self._send_rcpts(
             '\x1bc\x1b[2J\x1b[1;1H[The console.method attribute for this node is '
             'not configured,\r\nset it to a valid value for console '
             'function]')
         self.clearerror = True
         return
     if self.clearerror:
         self.clearerror = False
         self.clearbuffer()
         self._send_rcpts(b'\x1bc\x1b[2J\x1b[1;1H')
     self.send_break = self._console.send_break
     self.resize = self._console.resize
     if self._attribwatcher:
         self.cfgmgr.remove_watcher(self._attribwatcher)
         self._attribwatcher = None
     if hasattr(self._console, "configattributes"):
         attribstowatch = self._console.configattributes | self._genwatchattribs
     else:
         attribstowatch = self._genwatchattribs
     if self._genwatchattribs:
         self._attribwatcher = self.cfgmgr.watch_attributes(
             (self.node,), attribstowatch, self._attribschanged)
     try:
         self.resize(width=self.initsize[0], height=self.initsize[1])
         self._console.connect(self.get_console_output)
     except exc.TargetEndpointBadCredentials:
         self.clearbuffer()
         self.error = 'badcredentials'
         self.connectstate = 'unconnected'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         retrytime = self._get_retry_time()
         if not self.reconnect:
             self.reconnect = eventlet.spawn_after(retrytime, self._connect)
         return
     except exc.TargetEndpointUnreachable:
         self.clearbuffer()
         self.error = 'unreachable'
         self.connectstate = 'unconnected'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         retrytime = self._get_retry_time()
         if not self.reconnect:
             self.reconnect = eventlet.spawn_after(retrytime, self._connect)
         return
     except Exception:
         self.clearbuffer()
         _tracelog.log(traceback.format_exc(), ltype=log.DataTypes.event,
                       event=log.Events.stacktrace)
         self.error = 'unknown'
         self.connectstate = 'unconnected'
         self._send_rcpts({'connectstate': self.connectstate,
                           'error': self.error})
         retrytime = self._get_retry_time()
         if not self.reconnect:
             self.reconnect = eventlet.spawn_after(retrytime, self._connect)
         return
     self._got_connected()