<commit_before>import datetime
import hashlib
import logging
import sys

from ceilometerclient import client as ceilometer_client
from ceilometerclient import exc as ceilometer_exceptions
from cinderclient import exceptions as cinder_exceptions
from cinderclient.v2 import client as cinder_client
from django.core.cache import cache
from django.db import transaction
from django.utils import timezone
from glanceclient import exc as glance_exceptions
from glanceclient.v2 import client as glance_client
from keystoneauth1 import session as keystone_session
from keystoneauth1.identity import v3
from keystoneclient import exceptions as keystone_exceptions
from keystoneclient.v3 import client as keystone_client
from neutronclient.client import exceptions as neutron_exceptions
from neutronclient.v2_0 import client as neutron_client
from novaclient import client as nova_client
from novaclient import exceptions as nova_exceptions
from requests import ConnectionError
import six

from waldur_core.structure import ServiceBackend
from waldur_core.structure.exceptions import SerializableBackendError
from waldur_openstack.openstack.models import Tenant

logger = logging.getLogger(__name__)


class OpenStackBackendError(SerializableBackendError):
    pass


class OpenStackSessionExpired(OpenStackBackendError):
    pass


class OpenStackAuthorizationFailed(OpenStackBackendError):
    pass


def reraise(exc):
    """
    Reraise OpenStackBackendError while maintaining traceback.
    """
    six.reraise(OpenStackBackendError, exc, sys.exc_info()[2])


class OpenStackSession(dict):
    """ Serializable session """

    def __init__(self, ks_session=None, verify_ssl=False, **credentials):
        self.keystone_session = ks_session
        if not self.keystone_session:
            auth_plugin = v3.Password(**credentials)
            self.keystone_session = keystone_session.Session(auth=auth_plugin, verify=verify_ssl)

        try:
            # This will eagerly sign in throwing AuthorizationFailure on bad credentials
            self.keystone_session.get_auth_headers()
        except keystone_exceptions.ClientException as e:
            six.reraise(OpenStackAuthorizationFailed, e)

        for opt in ('auth_ref', 'auth_url', 'project_id', 'project_name', 'project_domain_name'):
            self[opt] = getattr(self.auth, opt)

    def __getattr__(self, name):
        return getattr(self.keystone_session, name)

    @classmethod
    def recover(cls, session, verify_ssl=False):
        if not isinstance(session, dict) or not session.get('auth_ref'):
            raise OpenStackBackendError('Invalid OpenStack session')

        args = {
            'auth_url': session['auth_url'],
            'token': session['auth_ref'].auth_token,
        }
        if session.get('project_id'):
            args['project_id'] = session['project_id']
        elif session.get('project_name') and session.get('project_domain_name'):
            args['project_name'] = session['project_name']
            args['project_domain_name'] = session['project_domain_name']

        ks_session = keystone_session.Session(auth=v3.Token(**args), verify=verify_ssl)
        return cls(ks_session=ks_session)

    def validate(self):
        if self.auth.auth_ref.expires > timezone.now() + datetime.timedelta(minutes=10):
            return True

        raise OpenStackSessionExpired('OpenStack session is expired')

    def __str__(self):
        return str({k: v if k != 'password' else '***' for k, v in self.items()})


class OpenStackClient(object):
    """ Generic OpenStack client. """

    def __init__(self, session=None, verify_ssl=False, **credentials):
        self.verify_ssl = verify_ssl
        if session:
            if isinstance(session, dict):
                logger.debug('Trying to recover OpenStack session.')
                self.session = OpenStackSession.recover(session, verify_ssl=verify_ssl)
                self.session.validate()
            else:
                self.session = session
        else:
            try:<commit_msg>Fix OpenStack Keystone session cache [WAL-2234]<commit_after>import datetime
import hashlib
import json
import logging
import sys

from ceilometerclient import client as ceilometer_client
from ceilometerclient import exc as ceilometer_exceptions
from cinderclient import exceptions as cinder_exceptions
from cinderclient.v2 import client as cinder_client
from django.core.cache import cache
from django.db import transaction
from django.utils import timezone
from glanceclient import exc as glance_exceptions
from glanceclient.v2 import client as glance_client
from keystoneauth1 import session as keystone_session
from keystoneauth1.identity import v3
from keystoneclient import exceptions as keystone_exceptions
from keystoneclient.v3 import client as keystone_client
from neutronclient.client import exceptions as neutron_exceptions
from neutronclient.v2_0 import client as neutron_client
from novaclient import client as nova_client
from novaclient import exceptions as nova_exceptions
from requests import ConnectionError
import six

from waldur_core.structure import ServiceBackend
from waldur_core.structure.exceptions import SerializableBackendError
from waldur_openstack.openstack.models import Tenant

logger = logging.getLogger(__name__)


class OpenStackBackendError(SerializableBackendError):
    pass


class OpenStackSessionExpired(OpenStackBackendError):
    pass


class OpenStackAuthorizationFailed(OpenStackBackendError):
    pass


def reraise(exc):
    """
    Reraise OpenStackBackendError while maintaining traceback.
    """
    six.reraise(OpenStackBackendError, exc, sys.exc_info()[2])


class OpenStackSession(dict):
    """ Serializable session """

    def __init__(self, ks_session=None, verify_ssl=False, **credentials):
        self.keystone_session = ks_session
        if not self.keystone_session:
            auth_plugin = v3.Password(**credentials)
            self.keystone_session = keystone_session.Session(auth=auth_plugin, verify=verify_ssl)

        try:
            # This will eagerly sign in throwing AuthorizationFailure on bad credentials
            self.keystone_session.get_auth_headers()
        except keystone_exceptions.ClientException as e:
            six.reraise(OpenStackAuthorizationFailed, e)

        for opt in ('auth_ref', 'auth_url', 'project_id', 'project_name', 'project_domain_name'):
            self[opt] = getattr(self.auth, opt)

    def __getattr__(self, name):
        return getattr(self.keystone_session, name)

    @classmethod
    def recover(cls, session, verify_ssl=False):
        if not isinstance(session, dict) or not session.get('auth_ref'):
            raise OpenStackBackendError('Invalid OpenStack session')

        args = {
            'auth_url': session['auth_url'],
            'token': session['auth_ref'].auth_token,
        }
        if session.get('project_id'):
            args['project_id'] = session['project_id']
        elif session.get('project_name') and session.get('project_domain_name'):
            args['project_name'] = session['project_name']
            args['project_domain_name'] = session['project_domain_name']

        auth_method = v3.Token(**args)
        auth_data = {
            'auth_token': session['auth_ref'].auth_token,
            'body': session['auth_ref']._data
        }
        auth_state = json.dumps(auth_data)
        auth_method.set_auth_state(auth_state)
        ks_session = keystone_session.Session(auth=auth_method, verify=verify_ssl)
        return cls(ks_session=ks_session)

    def validate(self):
        if self.auth.auth_ref.expires > timezone.now() + datetime.timedelta(minutes=10):
            return True

        raise OpenStackSessionExpired('OpenStack session is expired')

    def __str__(self):
        return str({k: v if k != 'password' else '***' for k, v in self.items()})


class OpenStackClient(object):
    """ Generic OpenStack client. """

    def __init__(self, session=None, verify_ssl=False, **credentials):
        self.verify_ssl = verify_ssl
        if session:
            if isinstance(session, dict):
                logger.debug('Trying to recover OpenStack session.')
                self.session = OpenStackSession.recover(session, verify_ssl=verify_ssl)
                self.session.validate()
            else:
                self.session = session
        else:
            try:
{'fraction_non_alphanumeric': 0.07998573805562158, 'fraction_numerical': 0.0035654860946042312, 'mean_word_length': 3.6134868421052633, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2132475', 'n_tokens_mistral': 2342, 'n_tokens_neox': 2258, 'n_words': 598}