<commit_before>"""
 SlipStream Client
 =====
 Copyright (C) 2013 SixSq Sarl (sixsq.com)
 =====
 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.
"""
from __future__ import print_function

import os
from collections import defaultdict

import slipstream.util as util
import slipstream.exceptions.Exceptions as Exceptions

from slipstream.UserInfo import UserInfo
from slipstream.HttpClient import HttpClient
from slipstream.NodeInstance import NodeInstance
from slipstream.NodeDecorator import NodeDecorator

etree = util.importETree()


class SlipStreamHttpClient(object):
    URL_IGNORE_ABORT_ATTRIBUTE_QUERY = '?ignoreabort=true'

    def __init__(self, configHolder):
        self.category = None
        self.run_dom = None
        self.ignoreAbort = False
        self.username = ''
        self.password = ''
        self.diid = ''
        self.node_instance_name = ''
        self.serviceurl = ''
        self.verboseLevel = None
        self.retry = True

        configHolder.assign(self)
        self._assemble_endpoints()
        self.httpClient = HttpClient(configHolder=configHolder)

    def set_retry(self, retry):
        self.retry = retry

    def _assemble_endpoints(self):
        self.runEndpoint = self.serviceurl + util.RUN_RESOURCE_PATH
        self.run_url = self.runEndpoint + '/' + self.diid

        self.authnServiceUrl = self.serviceurl + '/api/session'

        self.runReportEndpoint = '%s/reports/%s' % (self.serviceurl,
                                                    self.diid)

        self.userEndpoint = '%s/user/%s' % (self.serviceurl,
                                            self.username)

        self.configuration_endpoint = '%s%s' % (self.serviceurl,
                                                util.CONFIGURATION_RESOURCE_PATH)

    def get_user_info(self, cloud_qualifier):

        dom = self._getUserElement()

        userInfo = UserInfo(cloud_qualifier)

        userInfo['User.firstName'] = dom.attrib['firstName']
        userInfo['User.lastName'] = dom.attrib['lastName']
        userInfo['User.email'] = dom.attrib['email']

        parameters = dom.findall('parameters/entry/parameter')
        for param in parameters:
            if param.attrib['category'] in ['General', cloud_qualifier]:
                name = param.attrib['name']
                userInfo[name] = param.findtext('value', '')

        return userInfo

    def _getUserElement(self):
        content = self._getUserContent()

        return etree.fromstring(content.encode('utf-8'))

    def _getUserContent(self):
        url = self.userEndpoint
        _, content = self._httpGet(url, 'application/xml')
        return content

    def _extractModuleResourceUri(self, run):
        rootElement = etree.fromstring(run.encode('utf-8'))
        return rootElement.attrib[NodeDecorator.MODULE_RESOURCE_URI]

    def get_nodes_instances(self, cloud_service_name=None):
        '''Return dict {<node_instance_name>: NodeInstance, }
        '''
        nodes_instances = {}

        self._retrieveAndSetRun()

        nodes_instances_runtime_parameters = \
            DomExtractor.extract_nodes_instances_runtime_parameters(self.run_dom, cloud_service_name)

        nodes_runtime_parameters = DomExtractor.extract_nodes_runtime_parameters(self.run_dom)

        for node_instance_name, node_instance_runtime_parameters in nodes_instances_runtime_parameters.items():

            node_instance = NodeInstance(node_instance_runtime_parameters)
            node_name = node_instance.get_node_name()

            if nodes_runtime_parameters:
                node_runtime_parameters = nodes_runtime_parameters.get(node_name, {})
                if node_runtime_parameters:
                    node_instance.set_parameter(NodeDecorator.MAX_PROVISIONING_FAILURES_KEY,
                        node_runtime_parameters.get(NodeDecorator.MAX_PROVISIONING_FAILURES_KEY, '0'))

            image_attributes = DomExtractor.extract_node_image_attributes(self.run_dom, node_name)
            node_instance.set_image_attributes(image_attributes)

            image_targets = DomExtractor.extract_node_image_targets(self.run_dom, node_name)
            node_instance.set_image_targets(image_targets)

            build_state = DomExtractor.extract_node_image_build_state(self.run_dom, node_name)
            node_instance.set_build_state(build_state)

            nodes_instances[node_instance_name] = node_instance

        return nodes_instances

    def _get_nodename(self):
        'Node name derived from the node instance name.'
        return self.node_instance_name.split(
            NodeDecorator.NODE_MULTIPLICITY_SEPARATOR)[0]

    def get_run_category(self):
        self._retrieveAndSetRun()
        return DomExtractor.extractCategoryFromRun(self.run_dom)

    def get_run_type(self):
        self._retrieveAndSetRun()
        return DomExtractor.extractTypeFromRun(self.run_dom)

    def get_run_mutable(self):
        self._retrieveAndSetRun()
        return DomExtractor.extract_mutable_from_run(self.run_dom)

    def discard_run(self):
        self.run_dom = None

    def _retrieveAndSetRun(self):
        if self.run_dom is None:
            url = self.run_url
            _, run = self._retrieve(url)
            self.run_dom = etree.fromstring(run.encode('utf-8'))

    def _retrieve(self, url):
        return self._httpGet(url, 'application/xml')

    def execute(self, resourceUri):
        url = self.runEndpoint
        return self._httpPost(url, resourceUri, 'text/plain')

    def complete_state(self, node_instance_name):
        url = '%s/%s:%s' % (self.run_url, node_instance_name,
                            NodeDecorator.COMPLETE_KEY)
        url += SlipStreamHttpClient.URL_IGNORE_ABORT_ATTRIBUTE_QUERY
        return self._httpPost(url, 'reset', 'text/plain')

    def terminate_run(self):
        return self._httpDelete(self.run_url)

    def _fail(self, message):
        self.setRuntimeParameter(
            NodeDecorator.globalNamespacePrefix + NodeDecorator.ABORT_KEY, message)

    def sendReport(self, report):
        self._uploadReport(self.runReportEndpoint, report)

    def _uploadReport(self, url, report):
        print('Uploading report to: %s' % url)

        body = open(report, 'rb').read()
        url += '/' + os.path.basename(report)

        self._httpPut(url, body, '', accept="*/*")

    def isAbort(self):
        return self.getGlobalAbortMessage() != ''

    def getGlobalAbortMessage(self):
        url = '%s/%s%s' % (self.run_url,
                           NodeDecorator.globalNamespacePrefix,
                           NodeDecorator.ABORT_KEY)
        url += SlipStreamHttpClient.URL_IGNORE_ABORT_ATTRIBUTE_QUERY
        _, content = self._httpGet(url, accept='text/plain')
        return content.strip().strip('"').strip("'")

    def get_run_parameters(self):
        self._retrieveAndSetRun()
        return DomExtractor.extract_run_parameters_from_run(self.run_dom)

    def getRuntimeParameter(self, key, ignoreAbort=False):
<commit_msg>add cimi report upload but missing ss python api<commit_after>"""
 SlipStream Client
 =====
 Copyright (C) 2013 SixSq Sarl (sixsq.com)
 =====
 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.
"""
from __future__ import print_function

import os
from collections import defaultdict

import slipstream.util as util
import slipstream.exceptions.Exceptions as Exceptions

from slipstream.UserInfo import UserInfo
from slipstream.HttpClient import HttpClient
from slipstream.NodeInstance import NodeInstance
from slipstream.NodeDecorator import NodeDecorator

etree = util.importETree()


class SlipStreamHttpClient(object):
    URL_IGNORE_ABORT_ATTRIBUTE_QUERY = '?ignoreabort=true'

    def __init__(self, configHolder):
        self.category = None
        self.run_dom = None
        self.ignoreAbort = False
        self.username = ''
        self.password = ''
        self.diid = ''
        self.node_instance_name = ''
        self.serviceurl = ''
        self.verboseLevel = None
        self.retry = True

        configHolder.assign(self)
        self._assemble_endpoints()
        self.httpClient = HttpClient(configHolder=configHolder)

    def set_retry(self, retry):
        self.retry = retry

    def _assemble_endpoints(self):
        self.runEndpoint = self.serviceurl + util.RUN_RESOURCE_PATH
        self.run_url = self.runEndpoint + '/' + self.diid

        self.authnServiceUrl = self.serviceurl + '/api/session'

        self.externalObjectUrl = self.serviceurl + '/api/external-object'

        self.runReportEndpoint = '%s/reports/%s' % (self.serviceurl,
                                                    self.diid)

        self.userEndpoint = '%s/user/%s' % (self.serviceurl,
                                            self.username)

        self.configuration_endpoint = '%s%s' % (self.serviceurl,
                                                util.CONFIGURATION_RESOURCE_PATH)

    def get_user_info(self, cloud_qualifier):

        dom = self._getUserElement()

        userInfo = UserInfo(cloud_qualifier)

        userInfo['User.firstName'] = dom.attrib['firstName']
        userInfo['User.lastName'] = dom.attrib['lastName']
        userInfo['User.email'] = dom.attrib['email']

        parameters = dom.findall('parameters/entry/parameter')
        for param in parameters:
            if param.attrib['category'] in ['General', cloud_qualifier]:
                name = param.attrib['name']
                userInfo[name] = param.findtext('value', '')

        return userInfo

    def _getUserElement(self):
        content = self._getUserContent()

        return etree.fromstring(content.encode('utf-8'))

    def _getUserContent(self):
        url = self.userEndpoint
        _, content = self._httpGet(url, 'application/xml')
        return content

    def _extractModuleResourceUri(self, run):
        rootElement = etree.fromstring(run.encode('utf-8'))
        return rootElement.attrib[NodeDecorator.MODULE_RESOURCE_URI]

    def get_nodes_instances(self, cloud_service_name=None):
        '''Return dict {<node_instance_name>: NodeInstance, }
        '''
        nodes_instances = {}

        self._retrieveAndSetRun()

        nodes_instances_runtime_parameters = \
            DomExtractor.extract_nodes_instances_runtime_parameters(self.run_dom, cloud_service_name)

        nodes_runtime_parameters = DomExtractor.extract_nodes_runtime_parameters(self.run_dom)

        for node_instance_name, node_instance_runtime_parameters in nodes_instances_runtime_parameters.items():

            node_instance = NodeInstance(node_instance_runtime_parameters)
            node_name = node_instance.get_node_name()

            if nodes_runtime_parameters:
                node_runtime_parameters = nodes_runtime_parameters.get(node_name, {})
                if node_runtime_parameters:
                    node_instance.set_parameter(NodeDecorator.MAX_PROVISIONING_FAILURES_KEY,
                        node_runtime_parameters.get(NodeDecorator.MAX_PROVISIONING_FAILURES_KEY, '0'))

            image_attributes = DomExtractor.extract_node_image_attributes(self.run_dom, node_name)
            node_instance.set_image_attributes(image_attributes)

            image_targets = DomExtractor.extract_node_image_targets(self.run_dom, node_name)
            node_instance.set_image_targets(image_targets)

            build_state = DomExtractor.extract_node_image_build_state(self.run_dom, node_name)
            node_instance.set_build_state(build_state)

            nodes_instances[node_instance_name] = node_instance

        return nodes_instances

    def _get_nodename(self):
        'Node name derived from the node instance name.'
        return self.node_instance_name.split(
            NodeDecorator.NODE_MULTIPLICITY_SEPARATOR)[0]

    def get_run_category(self):
        self._retrieveAndSetRun()
        return DomExtractor.extractCategoryFromRun(self.run_dom)

    def get_run_type(self):
        self._retrieveAndSetRun()
        return DomExtractor.extractTypeFromRun(self.run_dom)

    def get_run_mutable(self):
        self._retrieveAndSetRun()
        return DomExtractor.extract_mutable_from_run(self.run_dom)

    def discard_run(self):
        self.run_dom = None

    def _retrieveAndSetRun(self):
        if self.run_dom is None:
            url = self.run_url
            _, run = self._retrieve(url)
            self.run_dom = etree.fromstring(run.encode('utf-8'))

    def _retrieve(self, url):
        return self._httpGet(url, 'application/xml')

    def execute(self, resourceUri):
        url = self.runEndpoint
        return self._httpPost(url, resourceUri, 'text/plain')

    def complete_state(self, node_instance_name):
        url = '%s/%s:%s' % (self.run_url, node_instance_name,
                            NodeDecorator.COMPLETE_KEY)
        url += SlipStreamHttpClient.URL_IGNORE_ABORT_ATTRIBUTE_QUERY
        return self._httpPost(url, 'reset', 'text/plain')

    def terminate_run(self):
        return self._httpDelete(self.run_url)

    def _fail(self, message):
        self.setRuntimeParameter(
            NodeDecorator.globalNamespacePrefix + NodeDecorator.ABORT_KEY, message)

    def sendReport(self, report):
        resource_id = self._createExternalObjectReport()
        upload_url = self._generateUploadUrlExternalObjectReport(resource_id)
        self._uploadReport(upload_url, report)

    def _createExternalObjectReport(self):
        # FIXME !!!! ss is the python api client
        resp = ss.cimi_add('externalObjects',
                           {'externalObjectTemplate': {'href': 'external-object-template/report',
                                                       'runUUID': self.diid,
                                                       'component': self.node_instance_name}})
        return resp.json['resource-id']

    def _generateUploadUrlExternalObjectReport(self, resource_id):
        # FIXME !!!! ss is the python api client
        resp = ss.cimi_operation(resource_id, "http://sixsq.com/slipstream/1/action/upload", {'ttl': 5})
        return resp.json['uri']

    def _uploadReport(self, url, report):
        print('Uploading report to: %s' % url)

        body = open(report, 'rb').read()
        url += '/' + os.path.basename(report)

        self._httpPut(url, body, '', accept="*/*")

    def isAbort(self):
        return self.getGlobalAbortMessage() != ''

    def getGlobalAbortMessage(self):
        url = '%s/%s%s' % (self.run_url,
                           NodeDecorator.globalNamespacePrefix,
                           NodeDecorator.ABORT_KEY)
        url += SlipStreamHttpClient.URL_IGNORE_ABORT_ATTRIBUTE_QUERY
        _, content = self._httpGet(url, accept='text/plain')
        return content.strip().strip('"').strip("'")

    def get_run_parameters(self):
        self._retrieveAndSetRun()
        return DomExtractor.extract_run_parameters_from_run(self.run_dom)

    def getRuntimeParameter(self, key, ignoreAbort=False):

{'fraction_non_alphanumeric': 0.09148403256105198, 'fraction_numerical': 0.0017532874139010645, 'mean_word_length': 2.7720831365139347, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6436940', 'n_tokens_mistral': 4575, 'n_tokens_neox': 4447, 'n_words': 872}