<commit_before># Copyright 2016 Red Hat, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import os
import time
import pprint
import requests
import uuid
import kerberos
import base64
import six
import re

from oslo_config import cfg
from oslo_config import types
from oslo_log import log as logging
from oslo_serialization import jsonutils as json

from nova.i18n import _
from nova.i18n import _LE
from nova.i18n import _LI
from nova.i18n import _LW

NOVACONF = cfg.CONF
CONF = cfg.ConfigOpts()

CONF.register_opts([
    cfg.StrOpt('url', default=None,
               help='IPA JSON RPC URL (e.g. '
                    'https://ipa.host.domain/ipa/json)'),
    cfg.StrOpt('keytab', default='/etc/krb5.keytab',
               help='Kerberos client keytab file'),
    cfg.StrOpt('service_name', default=None,
               help='HTTP IPA Kerberos service name '
                    '(e.g. HTTP@ipa.host.domain)'),
    cfg.StrOpt('cacert', default='/etc/ipa/ca.crt',
               help='CA certificate for use with https to IPA'),
    cfg.StrOpt('domain', default='test',
               help='Domain for new hosts'),
    cfg.IntOpt('connect_retries', default=1,
               help='How many times to attempt to retry '
               'the connection to IPA before giving up'),
    cfg.BoolOpt('project_subdomain', default=False,
                help='Treat the project as a DNS subdomain '
                'so a hostname would take the form: '
                'instance.project.domain'),
    cfg.BoolOpt('normalize_project', default=True,
                help='Normalize the project name to be a valid DNS label'),
    cfg.MultiOpt('inject_files', item_type=types.String(), default=[],
                 help='Files to inject into the new VM. '
                      'Specify as /path/to/file/on/host '
                      '[/path/to/file/in/vm/if/different]')
])

CONF(['--config-file', '/etc/nova/ipaclient.conf'])

LOG = logging.getLogger(__name__)

dns_regex = re.compile('[^0-9a-zA-Z]+')


class IPABaseError(Exception):
    error_code = 500
    error_type = 'unknown_ipa_error'
    error_message = None
    errors = None

    def __init__(self, *args, **kwargs):
        self.errors = kwargs.pop('errors', None)
        self.object = kwargs.pop('object', None)

        super(IPABaseError, self).__init__(*args, **kwargs)

        if len(args) > 0 and isinstance(args[0], six.string_types):
            self.error_message = args[0]


class IPAAuthError(IPABaseError):
    error_type = 'authentication_error'


IPA_INVALID_DATA = 3009
IPA_NOT_FOUND = 4001
IPA_DUPLICATE = 4002
IPA_NO_DNS_RECORD = 4019
IPA_NO_CHANGES = 4202


class IPAUnknownError(IPABaseError):
    pass


class IPACommunicationFailure(IPABaseError):
    error_type = 'communication_failure'


class IPAInvalidData(IPABaseError):
    error_type = 'invalid_data'


class IPADuplicateEntry(IPABaseError):
    error_type = 'duplicate_entry'


ipaerror2exception = {
    IPA_INVALID_DATA: {
        'host': IPAInvalidData,
        'dnsrecord': IPAInvalidData
    },
    IPA_NO_CHANGES: {
        'host': None,
        'dnsrecord': None
    },
    IPA_NO_DNS_RECORD: {
        'host': None,  # ignore - means already added
    },
    IPA_DUPLICATE: {
        'host': IPADuplicateEntry,
        'dnsrecord': IPADuplicateEntry
    }
}


def getvmdomainname():
    rv = NOVACONF.dhcp_domain or CONF.domain
    LOG.debug("getvmdomainname rv = " + rv)
    return rv


class IPAAuth(requests.auth.AuthBase):
    def __init__(self, keytab, service):
        # store the kerberos credentials in memory rather than on disk
        os.environ['KRB5CCNAME'] = "MEMORY:" + str(uuid.uuid4())
        self.token = None
        self.keytab = keytab
        self.service = service
        if self.keytab:
            os.environ['KRB5_CLIENT_KTNAME'] = self.keytab
        else:
            LOG.warn(_LW('No IPA client kerberos keytab file given'))

    def __call__(self, request):
        if not self.token:
            self.refresh_auth()
        request.headers['Authorization'] = 'negotiate ' + self.token
        return request

    def refresh_auth(self):
        flags = kerberos.GSS_C_MUTUAL_FLAG | kerberos.GSS_C_SEQUENCE_FLAG
        try:
            (unused, vc) = kerberos.authGSSClientInit(self.service,
                                                      gssflags=flags)
        except kerberos.GSSError as e:
            LOG.error(_LE("caught kerberos exception %r") % e)
            raise IPAAuthError(str(e))
        try:
            kerberos.authGSSClientStep(vc, "")
        except kerberos.GSSError as e:
            LOG.error(_LE("caught kerberos exception %r") % e)
            raise IPAAuthError(str(e))
        self.token = kerberos.authGSSClientResponse(vc)


class IPANovaHookBase(object):

    session = None
    inject_files = []

    @classmethod
    def start(cls):
        if not cls.session:
            # set up session to share among all instances
            cls.session = requests.Session()
            cls.session.auth = IPAAuth(CONF.keytab, CONF.service_name)
            xtra_hdrs = {'Content-Type': 'application/json',
                         'Referer': CONF.url}
            cls.session.headers.update(xtra_hdrs)
            # sigh. Fix me again. Do I need to call update-ca-certificates?
            cls.session.verify = False
        if not cls.inject_files:
            for fn in CONF.inject_files:
                hostvm = fn.split(' ')
                hostfile = hostvm[0]
                if len(hostvm) > 1:
                    vmfile = hostvm[1]
                else:
                    vmfile = hostfile
                with file(hostfile, 'r') as f:
                    cls.inject_files.append([vmfile,
                                             base64.b64encode(f.read())])<commit_msg>A system-provided python-requests is required for SSL verification<commit_after># Copyright 2016 Red Hat, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import os
import time
import pprint
import requests
import uuid
import kerberos
import base64
import six
import re

from oslo_config import cfg
from oslo_config import types
from oslo_log import log as logging
from oslo_serialization import jsonutils as json

from nova.i18n import _
from nova.i18n import _LE
from nova.i18n import _LI
from nova.i18n import _LW

NOVACONF = cfg.CONF
CONF = cfg.ConfigOpts()

CONF.register_opts([
    cfg.StrOpt('url', default=None,
               help='IPA JSON RPC URL (e.g. '
                    'https://ipa.host.domain/ipa/json)'),
    cfg.StrOpt('keytab', default='/etc/krb5.keytab',
               help='Kerberos client keytab file'),
    cfg.StrOpt('service_name', default=None,
               help='HTTP IPA Kerberos service name '
                    '(e.g. <EMAIL>)'),
    cfg.StrOpt('cacert', default='/etc/ipa/ca.crt',
               help='CA certificate for use with https to IPA'),
    cfg.StrOpt('domain', default='test',
               help='Domain for new hosts'),
    cfg.IntOpt('connect_retries', default=1,
               help='How many times to attempt to retry '
               'the connection to IPA before giving up'),
    cfg.BoolOpt('project_subdomain', default=False,
                help='Treat the project as a DNS subdomain '
                'so a hostname would take the form: '
                'instance.project.domain'),
    cfg.BoolOpt('normalize_project', default=True,
                help='Normalize the project name to be a valid DNS label'),
    cfg.MultiOpt('inject_files', item_type=types.String(), default=[],
                 help='Files to inject into the new VM. '
                      'Specify as /path/to/file/on/host '
                      '[/path/to/file/in/vm/if/different]')
])

CONF(['--config-file', '/etc/nova/ipaclient.conf'])

LOG = logging.getLogger(__name__)

dns_regex = re.compile('[^0-9a-zA-Z]+')


class IPABaseError(Exception):
    error_code = 500
    error_type = 'unknown_ipa_error'
    error_message = None
    errors = None

    def __init__(self, *args, **kwargs):
        self.errors = kwargs.pop('errors', None)
        self.object = kwargs.pop('object', None)

        super(IPABaseError, self).__init__(*args, **kwargs)

        if len(args) > 0 and isinstance(args[0], six.string_types):
            self.error_message = args[0]


class IPAAuthError(IPABaseError):
    error_type = 'authentication_error'


IPA_INVALID_DATA = 3009
IPA_NOT_FOUND = 4001
IPA_DUPLICATE = 4002
IPA_NO_DNS_RECORD = 4019
IPA_NO_CHANGES = 4202


class IPAUnknownError(IPABaseError):
    pass


class IPACommunicationFailure(IPABaseError):
    error_type = 'communication_failure'


class IPAInvalidData(IPABaseError):
    error_type = 'invalid_data'


class IPADuplicateEntry(IPABaseError):
    error_type = 'duplicate_entry'


ipaerror2exception = {
    IPA_INVALID_DATA: {
        'host': IPAInvalidData,
        'dnsrecord': IPAInvalidData
    },
    IPA_NO_CHANGES: {
        'host': None,
        'dnsrecord': None
    },
    IPA_NO_DNS_RECORD: {
        'host': None,  # ignore - means already added
    },
    IPA_DUPLICATE: {
        'host': IPADuplicateEntry,
        'dnsrecord': IPADuplicateEntry
    }
}


def getvmdomainname():
    rv = NOVACONF.dhcp_domain or CONF.domain
    LOG.debug("getvmdomainname rv = " + rv)
    return rv


class IPAAuth(requests.auth.AuthBase):
    def __init__(self, keytab, service):
        # store the kerberos credentials in memory rather than on disk
        os.environ['KRB5CCNAME'] = "MEMORY:" + str(uuid.uuid4())
        self.token = None
        self.keytab = keytab
        self.service = service
        if self.keytab:
            os.environ['KRB5_CLIENT_KTNAME'] = self.keytab
        else:
            LOG.warn(_LW('No IPA client kerberos keytab file given'))

    def __call__(self, request):
        if not self.token:
            self.refresh_auth()
        request.headers['Authorization'] = 'negotiate ' + self.token
        return request

    def refresh_auth(self):
        flags = kerberos.GSS_C_MUTUAL_FLAG | kerberos.GSS_C_SEQUENCE_FLAG
        try:
            (unused, vc) = kerberos.authGSSClientInit(self.service,
                                                      gssflags=flags)
        except kerberos.GSSError as e:
            LOG.error(_LE("caught kerberos exception %r") % e)
            raise IPAAuthError(str(e))
        try:
            kerberos.authGSSClientStep(vc, "")
        except kerberos.GSSError as e:
            LOG.error(_LE("caught kerberos exception %r") % e)
            raise IPAAuthError(str(e))
        self.token = kerberos.authGSSClientResponse(vc)


class IPANovaHookBase(object):

    session = None
    inject_files = []

    @classmethod
    def start(cls):
        if not cls.session:
            # set up session to share among all instances
            cls.session = requests.Session()
            cls.session.auth = IPAAuth(CONF.keytab, CONF.service_name)
            xtra_hdrs = {'Content-Type': 'application/json',
                         'Referer': CONF.url}
            cls.session.headers.update(xtra_hdrs)
            cls.session.verify = True
        if not cls.inject_files:
            for fn in CONF.inject_files:
                hostvm = fn.split(' ')
                hostfile = hostvm[0]
                if len(hostvm) > 1:
                    vmfile = hostvm[1]
                else:
                    vmfile = hostfile
                with file(hostfile, 'r') as f:
                    cls.inject_files.append([vmfile,
                                             base64.b64encode(f.read())])
{'fraction_non_alphanumeric': 0.10087962596085268, 'fraction_numerical': 0.009350978682938426, 'mean_word_length': 2.299346405228758, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 8, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 1, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4356106', 'n_tokens_mistral': 3962, 'n_tokens_neox': 3825, 'n_words': 982}