<commit_before>import Utils, Data, numpy as np, scipy.sparse as sp

class BaseProblem(object):
    """
        Problem is the base class for all geophysical forward problems in SimPEG.

        The problem is a partial differential equation of the form:

        .. math::
            c(m, u) = 0

        Here, m is the model and u is the field (or fields).
        Given the model, m, we can calculate the fields u(m),
        however, the data we collect is a subset of the fields,
        and can be defined by a linear projection, P.

        .. math::
            d_\\text{pred} = Pu(m)

        We are interested in how changing the model transforms the data,
        as such we can take write the Taylor expansion:

        .. math::
            Pu(m + hv) = Pu(m) + hP\\frac{\partial u(m)}{\partial m} v + \mathcal{O}(h^2 \left\| v \\right\| )

        We can linearize and define the sensitivity matrix as:

        .. math::
            J = P\\frac{\partial u}{\partial m}

        The sensitivity matrix, and it's transpose will be used in the inverse problem
        to (locally) find how model parameters change the data, and optimize!
    """

    __metaclass__ = Utils.SimPEGMetaClass

    counter = None   #: A SimPEG.Utils.Counter object

    dataPair = Data.BaseData

    def __init__(self, mesh, model, *args, **kwargs):
        Utils.setKwargs(self, **kwargs)
        self.mesh = mesh
        self.model = model

    @property
    def data(self):
        """
        The data object for this problem.
        """
        return getattr(self, '_data', None)

    def pair(self, d):
        """Bind a data to this problem instance using pointers."""
        assert isinstance(d, self.dataPair), "Data object must be an instance of a %s class."%(self.dataPair.__name__)
        if d.ispaired:
            raise Exception("The data object is already paired to a problem. Use data.unpair()")
        self._data = d
        d._prob = self

    def unpair(self):
        """Unbind a data from this problem instance."""
        if not self.ispaired: return
        self.data._prob = None
        self._data = None

    @property
    def ispaired(self): return self.data is not None

    @Utils.timeIt
    def Jvec(self, m, v, u=None):
        """
            :param numpy.array m: model
            :param numpy.array v: vector to multiply
            :param numpy.array u: fields
            :rtype: numpy.array
            :return: Jv

            Working with the general PDE, c(m, u) = 0, where m is the model and u is the field,
            the sensitivity is defined as:

            .. math::
                J = P\\frac{\partial u}{\partial m}

            We can take the derivative of the PDE:

            .. math::
                \\nabla_m c(m, u) \delta m + \\nabla_u c(m, u) \delta u = 0

            If the forward problem is invertible, then we can rearrange for du/dm:

            .. math::
                J = - P \left( \\nabla_u c(m, u) \\right)^{-1} \\nabla_m c(m, u)

            This can often be computed given a vector (i.e. J(v)) rather than stored, as J is a large dense matrix.

        """
        raise NotImplementedError('J is not yet implemented.')

    @Utils.timeIt
    def Jtvec(self, m, v, u=None):
        """
            :param numpy.array m: model
            :param numpy.array v: vector to multiply
            :param numpy.array u: fields
            :rtype: numpy.array
            :return: JTv

            Effect of transpose of J on a vector v.
        """
        raise NotImplementedError('Jt is not yet implemented.')

    @Utils.timeIt
    def Jvec_approx(self, m, v, u=None):
        """

            :param numpy.array m: model
            :param numpy.array v: vector to multiply
            :param numpy.array u: fields
            :rtype: numpy.array
            :return: Jv

            Approximate effect of J on a vector v

        """
        return self.Jvec(m, v, u)

    @Utils.timeIt
    def Jtvec_approx(self, m, v, u=None):
        """
            :param numpy.array m: model
            :param numpy.array v: vector to multiply
            :param numpy.array u: fields
            :rtype: numpy.array
            :return: JTv

            Approximate transpose of J*v

        """
        return self.Jtvec(m, v, u)

    def fields(self, m):
        """
            The field given the model.

            .. math::
                u(m)

        """
        pass

    def createSyntheticData(self, m, std=0.05, u=None, **geometry_kwargs):
        """
            Create synthetic data given a model, and a standard deviation.

            :param numpy.array m: geophysical model
            :param numpy.array std: standard deviation
            :rtype: numpy.array, numpy.array
            :return: dobs, Wd

            Returns the observed data with random Gaussian noise
            and Wd which is the same size as data, and can be used to weight the inversion.
        """
        data = self.dataPair(mtrue=m, **geometry_kwargs)
        data.pair(self)
        data.dtrue = data.dpred(m, u=u)
        noise = std*abs(data.dtrue)*np.random.randn(*data.dtrue.shape)
        data.dobs = data.dtrue+noise
        data.std = data.dobs*0 + std
        return data

<commit_msg>Added check on modelPair in Problem.<commit_after>import Utils, Data, numpy as np, scipy.sparse as sp
import Model

class BaseProblem(object):
    """
        Problem is the base class for all geophysical forward problems in SimPEG.

        The problem is a partial differential equation of the form:

        .. math::
            c(m, u) = 0

        Here, m is the model and u is the field (or fields).
        Given the model, m, we can calculate the fields u(m),
        however, the data we collect is a subset of the fields,
        and can be defined by a linear projection, P.

        .. math::
            d_\\text{pred} = Pu(m)

        We are interested in how changing the model transforms the data,
        as such we can take write the Taylor expansion:

        .. math::
            Pu(m + hv) = Pu(m) + hP\\frac{\partial u(m)}{\partial m} v + \mathcal{O}(h^2 \left\| v \\right\| )

        We can linearize and define the sensitivity matrix as:

        .. math::
            J = P\\frac{\partial u}{\partial m}

        The sensitivity matrix, and it's transpose will be used in the inverse problem
        to (locally) find how model parameters change the data, and optimize!
    """

    __metaclass__ = Utils.SimPEGMetaClass

    counter = None   #: A SimPEG.Utils.Counter object

    dataPair = Data.BaseData
    modelPair = Model.BaseModel

    def __init__(self, mesh, model, *args, **kwargs):
        Utils.setKwargs(self, **kwargs)
        self.mesh = mesh
        assert isinstance(d, self.modelPair), "Model object must be an instance of a %s class."%(self.modelPair.__name__)
        self.model = model

    @property
    def data(self):
        """
        The data object for this problem.
        """
        return getattr(self, '_data', None)

    def pair(self, d):
        """Bind a data to this problem instance using pointers."""
        assert isinstance(d, self.dataPair), "Data object must be an instance of a %s class."%(self.dataPair.__name__)
        if d.ispaired:
            raise Exception("The data object is already paired to a problem. Use data.unpair()")
        self._data = d
        d._prob = self

    def unpair(self):
        """Unbind a data from this problem instance."""
        if not self.ispaired: return
        self.data._prob = None
        self._data = None

    @property
    def ispaired(self): return self.data is not None

    @Utils.timeIt
    def Jvec(self, m, v, u=None):
        """
            :param numpy.array m: model
            :param numpy.array v: vector to multiply
            :param numpy.array u: fields
            :rtype: numpy.array
            :return: Jv

            Working with the general PDE, c(m, u) = 0, where m is the model and u is the field,
            the sensitivity is defined as:

            .. math::
                J = P\\frac{\partial u}{\partial m}

            We can take the derivative of the PDE:

            .. math::
                \\nabla_m c(m, u) \delta m + \\nabla_u c(m, u) \delta u = 0

            If the forward problem is invertible, then we can rearrange for du/dm:

            .. math::
                J = - P \left( \\nabla_u c(m, u) \\right)^{-1} \\nabla_m c(m, u)

            This can often be computed given a vector (i.e. J(v)) rather than stored, as J is a large dense matrix.

        """
        raise NotImplementedError('J is not yet implemented.')

    @Utils.timeIt
    def Jtvec(self, m, v, u=None):
        """
            :param numpy.array m: model
            :param numpy.array v: vector to multiply
            :param numpy.array u: fields
            :rtype: numpy.array
            :return: JTv

            Effect of transpose of J on a vector v.
        """
        raise NotImplementedError('Jt is not yet implemented.')

    @Utils.timeIt
    def Jvec_approx(self, m, v, u=None):
        """

            :param numpy.array m: model
            :param numpy.array v: vector to multiply
            :param numpy.array u: fields
            :rtype: numpy.array
            :return: Jv

            Approximate effect of J on a vector v

        """
        return self.Jvec(m, v, u)

    @Utils.timeIt
    def Jtvec_approx(self, m, v, u=None):
        """
            :param numpy.array m: model
            :param numpy.array v: vector to multiply
            :param numpy.array u: fields
            :rtype: numpy.array
            :return: JTv

            Approximate transpose of J*v

        """
        return self.Jtvec(m, v, u)

    def fields(self, m):
        """
            The field given the model.

            .. math::
                u(m)

        """
        pass

    def createSyntheticData(self, m, std=0.05, u=None, **geometry_kwargs):
        """
            Create synthetic data given a model, and a standard deviation.

            :param numpy.array m: geophysical model
            :param numpy.array std: standard deviation
            :rtype: numpy.array, numpy.array
            :return: dobs, Wd

            Returns the observed data with random Gaussian noise
            and Wd which is the same size as data, and can be used to weight the inversion.
        """
        data = self.dataPair(mtrue=m, **geometry_kwargs)
        data.pair(self)
        data.dtrue = data.dpred(m, u=u)
        noise = std*abs(data.dtrue)*np.random.randn(*data.dtrue.shape)
        data.dobs = data.dtrue+noise
        data.std = data.dobs*0 + std
        return data

<|endoftext|>


<commit_before><commit_msg>pytorch data loaders<commit_after><|endoftext|>


<commit_before># Copyright 2014 - Mirantis, 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.

from ceilometerclient.v2 import client as ceilometerclient
from cinderclient.v2 import client as cinderclient
from glanceclient.v2 import client as glanceclient
from heatclient.v1 import client as heatclient
from ironic_inspector_client import v1 as ironic_inspector_client
from ironicclient.v1 import client as ironicclient
from keystoneclient import httpclient
from keystoneclient.v3 import client as keystoneclient
from neutronclient.v2_0 import client as neutronclient
from novaclient import client as novaclient
from oslo_config import cfg
from oslo_log import log
from swiftclient import client as swift_client
from troveclient import client as troveclient

from mistral.actions.openstack import base
from mistral import context
from mistral.utils.openstack import keystone as keystone_utils

LOG = log.getLogger(__name__)

CONF = cfg.CONF

class NovaAction(base.OpenStackAction):
    _client_class = novaclient.get_client_class(2)

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Nova action security context: %s" % ctx)

        keystone_endpoint = keystone_utils.get_keystone_endpoint_v2()
        nova_endpoint = keystone_utils.get_endpoint_for_project('nova')

        client = self._client_class(
            username=None,
            api_key=None,
            endpoint_type='publicURL',
            service_type='compute',
            auth_token=ctx.auth_token,
            tenant_id=ctx.project_id,
            region_name=keystone_endpoint.region,
            auth_url=keystone_endpoint.url
        )

        client.client.management_url = keystone_utils.format_url(
            nova_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        return client

class GlanceAction(base.OpenStackAction):
    _client_class = glanceclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Glance action security context: %s" % ctx)

        glance_endpoint = keystone_utils.get_endpoint_for_project('glance')

        return self._client_class(
            glance_endpoint.url,
            region_name=glance_endpoint.region,
            token=ctx.auth_token
        )

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class("")

class KeystoneAction(base.OpenStackAction):
    _client_class = keystoneclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Keystone action security context: %s" % ctx)

        kwargs = {
            'token': ctx.auth_token,
            'auth_url': CONF.keystone_authtoken.auth_uri,
            'project_id': ctx.project_id,
            'cacert': CONF.keystone_authtoken.cafile,
        }

        # In case of trust-scoped token explicitly pass endpoint parameter.
        if (ctx.is_trust_scoped
                or keystone_utils.is_token_trust_scoped(ctx.auth_token)):
            kwargs['endpoint'] = CONF.keystone_authtoken.auth_uri

        client = self._client_class(**kwargs)

        client.management_url = CONF.keystone_authtoken.auth_uri

        return client

    @classmethod
    def _get_fake_client(cls):
        # Here we need to replace httpclient authenticate method temporarily
        authenticate = httpclient.HTTPClient.authenticate

        httpclient.HTTPClient.authenticate = lambda x: True
        fake_client = cls._client_class()

        # Once we get fake client, return back authenticate method
        httpclient.HTTPClient.authenticate = authenticate

        return fake_client

class CeilometerAction(base.OpenStackAction):
    _client_class = ceilometerclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Ceilometer action security context: %s" % ctx)

        ceilometer_endpoint = keystone_utils.get_endpoint_for_project(
            'ceilometer'
        )

        endpoint_url = keystone_utils.format_url(
            ceilometer_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        return self._client_class(
            endpoint_url,
            region_name=ceilometer_endpoint.region,
            token=ctx.auth_token,
            username=ctx.user_name
        )

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class("")

class HeatAction(base.OpenStackAction):
    _client_class = heatclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Heat action security context: %s" % ctx)

        heat_endpoint = keystone_utils.get_endpoint_for_project('heat')

        endpoint_url = keystone_utils.format_url(
            heat_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        return self._client_class(
            endpoint_url,
            region_name=heat_endpoint.region,
            token=ctx.auth_token,
            username=ctx.user_name
        )

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class("")

class NeutronAction(base.OpenStackAction):
    _client_class = neutronclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Neutron action security context: %s" % ctx)

        neutron_endpoint = keystone_utils.get_endpoint_for_project('neutron')

        return self._client_class(
            endpoint_url=neutron_endpoint.url,
            region_name=neutron_endpoint.region,
            token=ctx.auth_token,
            auth_url=CONF.keystone_authtoken.auth_uri
        )

class CinderAction(base.OpenStackAction):
    _client_class = cinderclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Cinder action security context: %s" % ctx)

        cinder_endpoint = keystone_utils.get_endpoint_for_project(
            service_type='volumev2'
        )

        cinder_url = keystone_utils.format_url(
            cinder_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        client = self._client_class(
            ctx.user_name,
            ctx.auth_token,
            project_id=ctx.project_id,
            auth_url=cinder_url,
            region_name=cinder_endpoint.region
        )

        client.client.auth_token = ctx.auth_token
        client.client.management_url = cinder_url

        return client

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class()

class TroveAction(base.OpenStackAction):
    _client_class = troveclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Trove action security context: %s" % ctx)

        trove_endpoint = keystone_utils.get_endpoint_for_project(
            service_type='database'
        )

        trove_url = keystone_utils.format_url(
            trove_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        client = self._client_class(
            ctx.user_name,
            ctx.auth_token,
            project_id=ctx.project_id,
            auth_url=trove_url,
            region_name=trove_endpoint.region
        )

        client.client.auth_token = ctx.auth_token
        client.client.management_url = trove_url

        return client

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class()

class IronicAction(base.OpenStackAction):
    _client_class = ironicclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Ironic action security context: %s" % ctx)

        ironic_endpoint = keystone_utils.get_endpoint_for_project('ironic')

        return self._client_class(
            ironic_endpoint.url,
            token=ctx.auth_token,
            region_name=ironic_endpoint.region
        )

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class("http://127.0.0.1:6385/")

class BaremetalIntrospectionAction(base.OpenStackAction):
    _client_class = ironic_inspector_client.ClientV1

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Baremetal introspection action security context: %s" % ctx)

        inspector_endpoint = keystone_utils.get_endpoint_for_project(
            'baremetal-introspection')

        return self._client_class(
            api_version=1,
            inspector_url=inspector_endpoint.url,
            auth_token=ctx.auth_token,
        )

class SwiftAction(base.OpenStackAction):
    _client_class = swift_client.Connection

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Swift action security context: %s" % ctx)

        swift_endpoint = keystone_utils.get_endpoint_for_project('swift')

        kwargs = {
            'preauthurl': swift_endpoint.url % {'tenant_id': ctx.project_id},
            'preauthtoken': ctx.auth_token
        }

        return self._client_class(**kwargs)
<commit_msg>BaremetalIntrospectionAction get endpoint by service_type<commit_after># Copyright 2014 - Mirantis, 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.

from ceilometerclient.v2 import client as ceilometerclient
from cinderclient.v2 import client as cinderclient
from glanceclient.v2 import client as glanceclient
from heatclient.v1 import client as heatclient
from ironic_inspector_client import v1 as ironic_inspector_client
from ironicclient.v1 import client as ironicclient
from keystoneclient import httpclient
from keystoneclient.v3 import client as keystoneclient
from neutronclient.v2_0 import client as neutronclient
from novaclient import client as novaclient
from oslo_config import cfg
from oslo_log import log
from swiftclient import client as swift_client
from troveclient import client as troveclient

from mistral.actions.openstack import base
from mistral import context
from mistral.utils.openstack import keystone as keystone_utils

LOG = log.getLogger(__name__)

CONF = cfg.CONF

class NovaAction(base.OpenStackAction):
    _client_class = novaclient.get_client_class(2)

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Nova action security context: %s" % ctx)

        keystone_endpoint = keystone_utils.get_keystone_endpoint_v2()
        nova_endpoint = keystone_utils.get_endpoint_for_project('nova')

        client = self._client_class(
            username=None,
            api_key=None,
            endpoint_type='publicURL',
            service_type='compute',
            auth_token=ctx.auth_token,
            tenant_id=ctx.project_id,
            region_name=keystone_endpoint.region,
            auth_url=keystone_endpoint.url
        )

        client.client.management_url = keystone_utils.format_url(
            nova_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        return client

class GlanceAction(base.OpenStackAction):
    _client_class = glanceclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Glance action security context: %s" % ctx)

        glance_endpoint = keystone_utils.get_endpoint_for_project('glance')

        return self._client_class(
            glance_endpoint.url,
            region_name=glance_endpoint.region,
            token=ctx.auth_token
        )

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class("")

class KeystoneAction(base.OpenStackAction):
    _client_class = keystoneclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Keystone action security context: %s" % ctx)

        kwargs = {
            'token': ctx.auth_token,
            'auth_url': CONF.keystone_authtoken.auth_uri,
            'project_id': ctx.project_id,
            'cacert': CONF.keystone_authtoken.cafile,
        }

        # In case of trust-scoped token explicitly pass endpoint parameter.
        if (ctx.is_trust_scoped
                or keystone_utils.is_token_trust_scoped(ctx.auth_token)):
            kwargs['endpoint'] = CONF.keystone_authtoken.auth_uri

        client = self._client_class(**kwargs)

        client.management_url = CONF.keystone_authtoken.auth_uri

        return client

    @classmethod
    def _get_fake_client(cls):
        # Here we need to replace httpclient authenticate method temporarily
        authenticate = httpclient.HTTPClient.authenticate

        httpclient.HTTPClient.authenticate = lambda x: True
        fake_client = cls._client_class()

        # Once we get fake client, return back authenticate method
        httpclient.HTTPClient.authenticate = authenticate

        return fake_client

class CeilometerAction(base.OpenStackAction):
    _client_class = ceilometerclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Ceilometer action security context: %s" % ctx)

        ceilometer_endpoint = keystone_utils.get_endpoint_for_project(
            'ceilometer'
        )

        endpoint_url = keystone_utils.format_url(
            ceilometer_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        return self._client_class(
            endpoint_url,
            region_name=ceilometer_endpoint.region,
            token=ctx.auth_token,
            username=ctx.user_name
        )

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class("")

class HeatAction(base.OpenStackAction):
    _client_class = heatclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Heat action security context: %s" % ctx)

        heat_endpoint = keystone_utils.get_endpoint_for_project('heat')

        endpoint_url = keystone_utils.format_url(
            heat_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        return self._client_class(
            endpoint_url,
            region_name=heat_endpoint.region,
            token=ctx.auth_token,
            username=ctx.user_name
        )

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class("")

class NeutronAction(base.OpenStackAction):
    _client_class = neutronclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Neutron action security context: %s" % ctx)

        neutron_endpoint = keystone_utils.get_endpoint_for_project('neutron')

        return self._client_class(
            endpoint_url=neutron_endpoint.url,
            region_name=neutron_endpoint.region,
            token=ctx.auth_token,
            auth_url=CONF.keystone_authtoken.auth_uri
        )

class CinderAction(base.OpenStackAction):
    _client_class = cinderclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Cinder action security context: %s" % ctx)

        cinder_endpoint = keystone_utils.get_endpoint_for_project(
            service_type='volumev2'
        )

        cinder_url = keystone_utils.format_url(
            cinder_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        client = self._client_class(
            ctx.user_name,
            ctx.auth_token,
            project_id=ctx.project_id,
            auth_url=cinder_url,
            region_name=cinder_endpoint.region
        )

        client.client.auth_token = ctx.auth_token
        client.client.management_url = cinder_url

        return client

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class()

class TroveAction(base.OpenStackAction):
    _client_class = troveclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Trove action security context: %s" % ctx)

        trove_endpoint = keystone_utils.get_endpoint_for_project(
            service_type='database'
        )

        trove_url = keystone_utils.format_url(
            trove_endpoint.url,
            {'tenant_id': ctx.project_id}
        )

        client = self._client_class(
            ctx.user_name,
            ctx.auth_token,
            project_id=ctx.project_id,
            auth_url=trove_url,
            region_name=trove_endpoint.region
        )

        client.client.auth_token = ctx.auth_token
        client.client.management_url = trove_url

        return client

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class()

class IronicAction(base.OpenStackAction):
    _client_class = ironicclient.Client

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Ironic action security context: %s" % ctx)

        ironic_endpoint = keystone_utils.get_endpoint_for_project('ironic')

        return self._client_class(
            ironic_endpoint.url,
            token=ctx.auth_token,
            region_name=ironic_endpoint.region
        )

    @classmethod
    def _get_fake_client(cls):
        return cls._client_class("http://127.0.0.1:6385/")

class BaremetalIntrospectionAction(base.OpenStackAction):
    _client_class = ironic_inspector_client.ClientV1

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Baremetal introspection action security context: %s" % ctx)

        inspector_endpoint = keystone_utils.get_endpoint_for_project(
            service_type='baremetal-introspection'
        )

        return self._client_class(
            api_version=1,
            inspector_url=inspector_endpoint.url,
            auth_token=ctx.auth_token,
        )

class SwiftAction(base.OpenStackAction):
    _client_class = swift_client.Connection

    def _get_client(self):
        ctx = context.ctx()

        LOG.debug("Swift action security context: %s" % ctx)

        swift_endpoint = keystone_utils.get_endpoint_for_project('swift')

        kwargs = {
            'preauthurl': swift_endpoint.url % {'tenant_id': ctx.project_id},
            'preauthtoken': ctx.auth_token
        }

        return self._client_class(**kwargs)
<|endoftext|>


<commit_before># Spec: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#asset

import json
import numpy
import os

from OpenGL import GL
from OpenGL.arrays.vbo import VBO

from pyrr import matrix44, Matrix44, quaternion

from demosys.opengl import VAO
from demosys.opengl.constants import TYPE_INFO
from demosys.scene import (
    Node,
    Mesh,
    Material,
)

# Supported buffer targets
BUFFER_TARGETS = {
    34962: "GL_ARRAY_BUFFER",
    34963: "GL_ELEMENT_ARRAY_BUFFER",
}

# numpy dtype mapping
NP_COMPONENT_DTYPE = {
    5121: numpy.dtype(numpy.uint8),  # GL_UNSIGNED_BYTE
    5123: numpy.dtype(numpy.uint16),  # GL_UNSIGNED_SHORT
    5125: numpy.dtype(numpy.uint32),  # GL_UNSIGNED_INT
    5126: numpy.dtype(numpy.float32),  # GL_FLOAT

}

ACCESSOR_TYPE = {
    "SCALAR": 1,
    "VEC2": 2,
    "VEC3": 3,
    "VEC4": 4,
}

class GLTF2:
    """
    Represents a GLTF 2.0 file
    """
    def __init__(self, file_path):
        """
        Parse the json file and validate its contents.
        No actual data loading will happen.

        Supported formats:
        - gltf json format with external resources
        - gltf embedded buffers
        - glb Binary format
        """
        self.scenes = []
        self.nodes = []
        self.meshes = []
        self.materials = []

        self.meta = None
        self.file = file_path
        self.path = ""
        self.scene = None

    def load(self, scene, file=None):
        """
        Deferred loading of the scene

        :param scene: The scene object
        :param file: Resolved path if changed by finder
        """
        print("Loading", self.file)
        self.scene = scene
        if file:
            self.file = file
        self.path = os.path.dirname(self.file)

        # Load gltf json file
        if self.file.endswith('.gltf'):
            self.load_gltf()

        # Load binary gltf file
        if self.file.endswith('.glb'):
            self.load_glb()

        self.meta.check_version()
        self.load_images()
        self.load_meshes()
        self.load_materials()
        self.load_nodes()

    def load_gltf(self):
        """Loads a gltf json file"""
        with open(self.file) as fd:
            self.meta = GLTFMeta(self.file, json.load(fd))

    def load_glb(self):
        """Loads a binary gltf file"""
        pass

    def load_images(self):
        for image in self.meta.images:
            pass

    def load_meshes(self):
        for mesh in self.meta.meshes:
            m = mesh.load()
            self.meshes.append(m)

    def load_materials(self):
        # Create material objects
        for mat in self.meta.materials:
            m = Material(mat.name)
            m.color = mat.baseColorFactor
            self.materials.append(m)

        # Map to meshes
        for i, mesh in enumerate(self.meta.meshes):
            if mesh.primitives[0].material is not None:
                self.meshes[i].material = self.materials[mesh.primitives[0].material]

    def load_nodes(self):
        # Start with root nodes in the scene
        for node_id in self.meta.scenes[0].nodes:
            node = self.load_node(self.meta.nodes[node_id])
            self.scene.add_node(node)

    def load_node(self, meta, parent=None):
        # Create the node
        node = Node()

        if meta.matrix is not None:
            node.matrix = Matrix44(value=meta.matrix)

        # FIXME: check for quaternions

        if meta.mesh is not None:
            node.mesh = self.meshes[meta.mesh]

        if meta.camera is not None:
            # FIXME: Use a proper camera class
            node.camera = self.meta.cameras[meta.camera]

        if parent:
            parent.add_child(node)

        # Follow children
        if meta.has_children:
            for node_id in meta.children:
                self.load_node(self.meta.nodes[node_id], parent=node)

        return node

class GLTFMeta:
    """Container for gltf metadata"""
    def __init__(self, file, data):
        self.file = file
        self.path = os.path.dirname(self.file)
        self.asset = GLTFAsset(data['asset'])
        self.materials = [GLTFMaterial(m) for m in data['materials']] if data.get('materials') else []
        self.images = [GLTFImage(i) for i in data['images']] if data.get('images') else []
        self.samplers = [GLTFSampler(s) for s in data['samplers']] if data.get('samplers') else []
        self.textures = [GLTFTexture(t) for t in data['textures']] if data.get('textures') else []
        self.scenes = [GLTFScene(s) for s in data['scenes']] if data.get('scenes') else []
        self.nodes = [GLTFNode(n) for n in data['nodes']] if data.get('nodes') else []
        self.meshes = [GLTFMesh(m) for m in data['meshes']] if data.get('meshes') else []
        self.cameras = [GLTFCamera(c) for c in data['cameras']] if data.get('cameras') else []
        self.bufferViews = [GLTFBufferView(v) for v in data['bufferViews']] if data.get('bufferViews') else []
        self.buffers = [GLTFBuffer(b, self.path) for b in data['buffers']] if data.get('buffers') else []
        self.accessors = [GLTFAccessor(a) for a in data['accessors']] if data.get('accessors') else []

        self._link_data()

        self.buffers_exist()
        self.images_exist()

    def _link_data(self):
        """Add references"""
        # accessors -> bufferViews -> buffers
        for acc in self.accessors:
            acc.bufferView = self.bufferViews[acc.bufferViewId]
        for bv in self.bufferViews:
            bv.buffer = self.buffers[bv.bufferId]

        # Meshes
        for mesh in self.meshes:
            for p in mesh.primitives:
                p.indices = self.accessors[p.indices]
                for name, value in p.attributes.items():
                    p.attributes[name] = self.accessors[value]

    @property
    def version(self):
        return self.asset.version

    def check_version(self, required='2.0'):
        if not self.version == required:
            msg = "GLTF Format version is not 2.0. Version states '{}' in file {}".format(
                self.version,
                self.file
            )
            raise ValueError(msg)

    def buffers_exist(self):
        """Checks if the bin files referenced exist"""
        for buff in self.buffers:
            path = os.path.join(self.path, buff.uri)
            if not os.path.exists(path):
                raise FileNotFoundError("Buffer %s referenced in %s not found", path, self.file)

    def images_exist(self):
        """checks if the images references in textures exist"""
        pass

class GLTFAsset:
    """Asset Information"""
    def __init__(self, data):
        self.version = data.get('version')
        self.generator = data.get('generator')
        self.copyright = data.get('copyright')

class GLTFMesh:

    def __init__(self, data):
        class Primitives:
            def __init__(self, data):
                self.attributes = data.get('attributes')
                self.indices = data.get('indices')
                self.mode = data.get('mode')
                self.material = data.get('material')

        self.name = data.get('name')
        self.primitives = [Primitives(p) for p in data.get('primitives')]

    def load(self):
        component_type, index_vbo = self.load_indices()
        attribs = self.load_attributes()

        name_map = {
            'POSITION': 'in_position',
            'NORMAL': 'in_normal',
            'TEXCOORD_0': 'in_uv',
            'TANGENT': 'in_tangent',
            'JOINTS_0': 'in_joints',
            'WEIGHTS_0': 'in_heights',
            'COLOR_0': 'in_color0',
        }

        vao = VAO(self.name, mode=self.primitives[0].mode or GL.GL_TRIANGLES)
        vao.set_element_buffer(component_type.value, index_vbo)
        for name, components, component_type, vbo in attribs:
            vao.add_array_buffer(component_type.value, vbo)
            vao.map_buffer(vbo, name_map[name], components)

        vao.build()
        return Mesh(self.name, vao=vao)

    def load_indices(self):
        """Loads the index buffer / polygon list"""
        _, component_type, vbo = self.primitives[0].indices.read(target=GL.GL_ELEMENT_ARRAY_BUFFER)
        # print("vbo", vbo.__dict__)
        return component_type, vbo

    def load_attributes(self):
        # figure out what buffers are interleaved
        attribs = []
        for name, accessor in self.primitives[0].attributes.items():
            components, component_type, vbo = accessor.read(target=GL.GL_ARRAY_BUFFER)
            attribs.append((name, components, component_type, vbo))

        return attribs

    def is_interleaved(self):
        pass

    def get_bbox(self):
        """Get the bounding box for the mesh"""
        accessor = self.primitives[0].attributes.get('POSITION')
        return accessor.min, accessor.max

class GLTFAccessor:
    def __init__(self, data):
        self.bufferViewId = data.get('bufferView')
        self.bufferView = None
        self.byteOffset = data.get('byteOffset') or 0
        self.componentType = TYPE_INFO[data['componentType']]
        self.count = data.get('count')
        self.max = data.get('max')
        self.min = data.get('min')
        self.type = data.get('type')

    def read(self, target=None):
        """
        Reads buffer data
        :return: component count, component type, data
        """
        # ComponentType helps us determine the datatype
        dtype = NP_COMPONENT_DTYPE[self.componentType.value]
        return ACCESSOR_TYPE[self.type], self.componentType, self.bufferView.read(
            target=target,
            byte_offset=self.byteOffset,
            dtype=dtype,
            count=self.count * ACCESSOR_TYPE[self.type],
        )

class GLTFBufferView:
    def __init__(self, data):
        self.bufferId = data.get('buffer')
        self.buffer = None
        self.byteOffset = data.get('byteOffset') or 0
        self.byteLength = data.get('byteLength')
        self.byteStride = data.get('byteStride') or 0
        # Valid: 34962 (ARRAY_BUFFER) and 34963 (ELEMENT_ARRAY_BUFFER) or None
        self.target = data.get('target')

    def read(self, byte_offset=0, dtype=None, count=0, target=None):
        data = self.buffer.read(
            byte_offset=byte_offset + self.byteOffset,
            byte_length=self.byteLength,
        )
        vbo = VBO(numpy.frombuffer(data, count=count, dtype=dtype),
                  target=BUFFER_TARGETS[target])
        return vbo

class GLTFBuffer:
    def __init__(self, data, path):
        self.path = path
        self.byteLength = data.get('byteLength')
        self.uri = data.get('uri')
        self.data = None

    @property
    def has_data_uri(self):
        return self.uri.startswith("data:")

    def open(self):
        if self.data:
            return

        if self.has_data_uri:
            raise NotImplemented("data-uri resource loading not implemented")

        with open(os.path.join(self.path, self.uri), 'rb') as fd:
            self.data = fd.read()

    def read(self, byte_offset=0, byte_length=0):
        self.open()
        return self.data[byte_offset:byte_offset + byte_length]

class GLTFScene:
    def __init__(self, data):
        self.nodes = data['nodes']

class GLTFNode:
    def __init__(self, data):
        self.children = data.get('children')
        self.matrix = data.get('matrix')
        self.mesh = data.get('mesh')
        self.camera = data.get('camera')

        self.translation = data.get('translation')
        self.rotation = data.get('rotation')
        self.scale = data.get('scale')

        if self.matrix is None:
            self.matrix = matrix44.create_identity()
        if self.translation is not None:
            self.matrix = matrix44.create_from_translation(self.translation)
        if self.rotation is not None:
            q = quaternion.create(self.rotation[0], self.rotation[1], self.rotation[2], self.rotation[3])
            m = matrix44.create_from_quaternion(q)
            self.matrix = matrix44.multiply(m, self.matrix)
        if self.scale is not None:
            self.matrix = matrix44.multiply(matrix44.create_from_scale(self.scale), self.matrix)

    @property
    def has_children(self):
        return self.children is not None and len(self.children) > 0

    @property
    def is_resource_node(self):
        """Is this just a reference node to a resource?"""
        return self.camera is not None or self.mesh is not None

class GLTFMaterial:
    def __init__(self, data):
        self.name = data.get('name')
        self.baseColorFactor = None
        self.metallicFactor = None
        self.emissiveFactor = None

        pbr = data.get('pbrMetallicRoughness')
        if pbr:
            self.baseColorFactor = pbr.get('baseColorFactor')
            self.metallicFactor = pbr.get('metallicFactor')

        self.emissiveFactor = data.get('emissiveFactor')

class GLTFImage:
    def __init__(self, data):
        self.uri = data['uri']

class GLTFTexture:
    def __init__(self, data):
        self.sampler = data.get('sampler')
        self.source = data.get('source')

class GLTFSampler:
    def __init__(self, data):
        self.magFilter = data.get('magFilter')
        self.minFilter = data.get('minFilter')
        self.wrapS = data.get('wrapS')
        self.wrapT = data.get('wrapT')

class GLTFCamera:
    def __init__(self, data):
        self.data = data
        # "perspective": {
        #     "aspectRatio": 1.0,
        #     "yfov": 0.266482561826706,
        #     "zfar": 1000000.0,
        #     "znear": 0.04999999701976776
        # },
        # "type": "perspective"
<commit_msg>Simplify attribute buffer loading<commit_after># Spec: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#asset

import json
import numpy
import os

from OpenGL import GL
from OpenGL.arrays.vbo import VBO

from pyrr import matrix44, Matrix44, quaternion

from demosys.opengl import VAO
from demosys.opengl.constants import TYPE_INFO
from demosys.scene import (
    Node,
    Mesh,
    Material,
)

# Supported buffer targets
BUFFER_TARGETS = {
    34962: "GL_ARRAY_BUFFER",
    34963: "GL_ELEMENT_ARRAY_BUFFER",
}

# numpy dtype mapping
NP_COMPONENT_DTYPE = {
    5121: numpy.dtype(numpy.uint8),  # GL_UNSIGNED_BYTE
    5123: numpy.dtype(numpy.uint16),  # GL_UNSIGNED_SHORT
    5125: numpy.dtype(numpy.uint32),  # GL_UNSIGNED_INT
    5126: numpy.dtype(numpy.float32),  # GL_FLOAT

}

ACCESSOR_TYPE = {
    "SCALAR": 1,
    "VEC2": 2,
    "VEC3": 3,
    "VEC4": 4,
}

class GLTF2:
    """
    Represents a GLTF 2.0 file
    """
    def __init__(self, file_path):
        """
        Parse the json file and validate its contents.
        No actual data loading will happen.

        Supported formats:
        - gltf json format with external resources
        - gltf embedded buffers
        - glb Binary format
        """
        self.scenes = []
        self.nodes = []
        self.meshes = []
        self.materials = []

        self.meta = None
        self.file = file_path
        self.path = ""
        self.scene = None

    def load(self, scene, file=None):
        """
        Deferred loading of the scene

        :param scene: The scene object
        :param file: Resolved path if changed by finder
        """
        print("Loading", self.file)
        self.scene = scene
        if file:
            self.file = file
        self.path = os.path.dirname(self.file)

        # Load gltf json file
        if self.file.endswith('.gltf'):
            self.load_gltf()

        # Load binary gltf file
        if self.file.endswith('.glb'):
            self.load_glb()

        self.meta.check_version()
        self.load_images()
        self.load_meshes()
        self.load_materials()
        self.load_nodes()

    def load_gltf(self):
        """Loads a gltf json file"""
        with open(self.file) as fd:
            self.meta = GLTFMeta(self.file, json.load(fd))

    def load_glb(self):
        """Loads a binary gltf file"""
        pass

    def load_images(self):
        for image in self.meta.images:
            pass

    def load_meshes(self):
        for mesh in self.meta.meshes:
            m = mesh.load()
            self.meshes.append(m)

    def load_materials(self):
        # Create material objects
        for mat in self.meta.materials:
            m = Material(mat.name)
            m.color = mat.baseColorFactor
            self.materials.append(m)

        # Map to meshes
        for i, mesh in enumerate(self.meta.meshes):
            if mesh.primitives[0].material is not None:
                self.meshes[i].material = self.materials[mesh.primitives[0].material]

    def load_nodes(self):
        # Start with root nodes in the scene
        for node_id in self.meta.scenes[0].nodes:
            node = self.load_node(self.meta.nodes[node_id])
            self.scene.add_node(node)

    def load_node(self, meta, parent=None):
        # Create the node
        node = Node()

        if meta.matrix is not None:
            node.matrix = Matrix44(value=meta.matrix)

        if meta.mesh is not None:
            node.mesh = self.meshes[meta.mesh]

        if meta.camera is not None:
            # FIXME: Use a proper camera class
            node.camera = self.meta.cameras[meta.camera]

        if parent:
            parent.add_child(node)

        # Follow children
        if meta.has_children:
            for node_id in meta.children:
                self.load_node(self.meta.nodes[node_id], parent=node)

        return node

class GLTFMeta:
    """Container for gltf metadata"""
    def __init__(self, file, data):
        self.file = file
        self.path = os.path.dirname(self.file)
        self.asset = GLTFAsset(data['asset'])
        self.materials = [GLTFMaterial(m) for m in data['materials']] if data.get('materials') else []
        self.images = [GLTFImage(i) for i in data['images']] if data.get('images') else []
        self.samplers = [GLTFSampler(s) for s in data['samplers']] if data.get('samplers') else []
        self.textures = [GLTFTexture(t) for t in data['textures']] if data.get('textures') else []
        self.scenes = [GLTFScene(s) for s in data['scenes']] if data.get('scenes') else []
        self.nodes = [GLTFNode(n) for n in data['nodes']] if data.get('nodes') else []
        self.meshes = [GLTFMesh(m) for m in data['meshes']] if data.get('meshes') else []
        self.cameras = [GLTFCamera(c) for c in data['cameras']] if data.get('cameras') else []
        self.bufferViews = [GLTFBufferView(i, v) for i, v in enumerate(data['bufferViews'])] \
            if data.get('bufferViews') else []
        self.buffers = [GLTFBuffer(i, b, self.path) for i, b in enumerate(data['buffers'])] \
            if data.get('buffers') else []
        self.accessors = [GLTFAccessor(i, a) for i, a in enumerate(data['accessors'])] \
            if data.get('accessors') else []

        self._link_data()

        self.buffers_exist()
        self.images_exist()

    def _link_data(self):
        """Add references"""
        # accessors -> bufferViews -> buffers
        for acc in self.accessors:
            acc.bufferView = self.bufferViews[acc.bufferViewId]
        for bv in self.bufferViews:
            bv.buffer = self.buffers[bv.bufferId]

        # Meshes
        for mesh in self.meshes:
            for p in mesh.primitives:
                p.indices = self.accessors[p.indices]
                for name, value in p.attributes.items():
                    p.attributes[name] = self.accessors[value]

    @property
    def version(self):
        return self.asset.version

    def check_version(self, required='2.0'):
        if not self.version == required:
            msg = "GLTF Format version is not 2.0. Version states '{}' in file {}".format(
                self.version,
                self.file
            )
            raise ValueError(msg)

    def buffers_exist(self):
        """Checks if the bin files referenced exist"""
        for buff in self.buffers:
            path = os.path.join(self.path, buff.uri)
            if not os.path.exists(path):
                raise FileNotFoundError("Buffer %s referenced in %s not found", path, self.file)

    def images_exist(self):
        """checks if the images references in textures exist"""
        pass

class GLTFAsset:
    """Asset Information"""
    def __init__(self, data):
        self.version = data.get('version')
        self.generator = data.get('generator')
        self.copyright = data.get('copyright')

class GLTFMesh:

    def __init__(self, data):
        class Primitives:
            def __init__(self, data):
                self.attributes = data.get('attributes')
                self.indices = data.get('indices')
                self.mode = data.get('mode')
                self.material = data.get('material')

        self.name = data.get('name')
        self.primitives = [Primitives(p) for p in data.get('primitives')]

    def load(self):
        self.prepare_attrib_mapping()
        component_type, index_vbo = self.load_indices()

        name_map = {
            'POSITION': 'in_position',
            'NORMAL': 'in_normal',
            'TEXCOORD_0': 'in_uv',
            'TANGENT': 'in_tangent',
            'JOINTS_0': 'in_joints',
            'WEIGHTS_0': 'in_heights',
            'COLOR_0': 'in_color0',
        }

        vbos = self.prepare_attrib_mapping()
        vao = VAO(self.name, mode=self.primitives[0].mode or GL.GL_TRIANGLES)
        vao.set_element_buffer(component_type.value, index_vbo)

        for vbo_info in vbos:
            vbo = vbo_info.create()
            vao.add_array_buffer(vbo_info.component_type.value, vbo)
            for attr in vbo_info.attributes:
                vao.map_buffer(vbo, name_map[attr[0]], attr[1])

        vao.build()
        return Mesh(self.name, vao=vao)

    def load_indices(self):
        """Loads the index buffer / polygon list"""
        _, component_type, vbo = self.primitives[0].indices.read(target=GL.GL_ELEMENT_ARRAY_BUFFER)
        # print("vbo", vbo.__dict__)
        return component_type, vbo

    def prepare_attrib_mapping(self):
        buffer_info = []
        """Pre-parse buffer mappings for each VBO to detect interleaved data"""
        for name, accessor in self.primitives[0].attributes.items():
            info = VBOInfo(*accessor.info(target=GL.GL_ARRAY_BUFFER))
            # Check interleaved here
            info.attributes.append((name, info.components))
            print(name, info)
            buffer_info.append(info)

        return buffer_info

    def get_bbox(self):
        """Get the bounding box for the mesh"""
        accessor = self.primitives[0].attributes.get('POSITION')
        return accessor.min, accessor.max

class VBOInfo:
    """Resolved data about each VBO"""
    def __init__(self, buffer=None, buffer_view=None, target=None,
                 byte_length=None, byte_offset=None,
                 component_type=None, components=None, count=None):
        self.buffer = buffer  # reference to the buffer
        self.buffer_view = buffer_view
        self.target = target
        self.byte_length = byte_length  # Raw byte buffer length
        self.byte_offset = byte_offset  # Raw byte offset
        self.component_type = component_type  # Datatype of each component
        self.components = components
        self.count = count  # number of elements of the component type size
        # list of (name, components) tuples
        self.attributes = []

    def create(self):
        """Create the VBO"""
        dtype = NP_COMPONENT_DTYPE[self.component_type.value]
        data = self.buffer.read(byte_length=self.byte_length, byte_offset=self.byte_offset)
        return VBO(numpy.frombuffer(data, count=self.count * self.components, dtype=dtype),
                   target=self.target)

    def __str__(self):
        return "VBOInfo<buffer={}, buffer_view={}, target={}, \n" \
               "        length={}, offset={}, \n" \
               "        component_type={}, components={}, count={}, \n" \
               "        attribs={}".format(
                            self.buffer.id, self.buffer_view.id, self.target,
                            self.byte_length, self.byte_offset,
                            self.component_type.value, self.components, self.count,
                            self.attributes)

    def __repr__(self):
        return str(self)

class GLTFAccessor:
    def __init__(self, accessor_id, data):
        self.id = accessor_id
        self.bufferViewId = data.get('bufferView')
        self.bufferView = None
        self.byteOffset = data.get('byteOffset') or 0
        self.componentType = TYPE_INFO[data['componentType']]
        self.count = data.get('count')
        self.max = data.get('max')
        self.min = data.get('min')
        self.type = data.get('type')

    def read(self, target=None):
        """
        Reads buffer data
        :return: component count, component type, data
        """
        # ComponentType helps us determine the datatype
        dtype = NP_COMPONENT_DTYPE[self.componentType.value]
        return ACCESSOR_TYPE[self.type], self.componentType, self.bufferView.read(
            target=target,
            byte_offset=self.byteOffset,
            dtype=dtype,
            count=self.count * ACCESSOR_TYPE[self.type],
        )

    def info(self, target=None):
        """
        Get underlying buffer info for this accessor
        :return: buffer, byte_length, byte_offset, component_type, count
        """
        buffer, target, byte_length, byte_offset = self.bufferView.info(byte_offset=self.byteOffset, target=target)
        return buffer, self.bufferView, target, \
               byte_length, byte_offset, \
               self.componentType, ACCESSOR_TYPE[self.type], self.count

class GLTFBufferView:
    def __init__(self, view_id, data):
        self.id = view_id
        self.bufferId = data.get('buffer')
        self.buffer = None
        self.byteOffset = data.get('byteOffset') or 0
        self.byteLength = data.get('byteLength')
        self.byteStride = data.get('byteStride') or 0
        # Valid: 34962 (ARRAY_BUFFER) and 34963 (ELEMENT_ARRAY_BUFFER) or None
        self.target = data.get('target')

    def read(self, byte_offset=0, dtype=None, count=0, target=None):
        data = self.buffer.read(
            byte_offset=byte_offset + self.byteOffset,
            byte_length=self.byteLength,
        )
        vbo = VBO(numpy.frombuffer(data, count=count, dtype=dtype),
                  target=BUFFER_TARGETS[target])
        return vbo

    def info(self, byte_offset=0, target=None):
        """
        Get the underlying buffer info
        :param byte_offset: byte offset from accessor
        :param target: buffer target (elements or data array)
        :return: buffer, target, byte_length, byte_offset
        """
        return self.buffer, BUFFER_TARGETS[target], self.byteLength, byte_offset + self.byteOffset

class GLTFBuffer:
    def __init__(self, buffer_id, data, path):
        self.id = buffer_id
        self.path = path
        self.byteLength = data.get('byteLength')
        self.uri = data.get('uri')
        self.data = None

    @property
    def has_data_uri(self):
        return self.uri.startswith("data:")

    def open(self):
        if self.data:
            return

        if self.has_data_uri:
            raise NotImplemented("data-uri resource loading not implemented")

        with open(os.path.join(self.path, self.uri), 'rb') as fd:
            self.data = fd.read()

    def read(self, byte_offset=0, byte_length=0):
        self.open()
        return self.data[byte_offset:byte_offset + byte_length]

class GLTFScene:
    def __init__(self, data):
        self.nodes = data['nodes']

class GLTFNode:
    def __init__(self, data):
        self.children = data.get('children')
        self.matrix = data.get('matrix')
        self.mesh = data.get('mesh')
        self.camera = data.get('camera')

        self.translation = data.get('translation')
        self.rotation = data.get('rotation')
        self.scale = data.get('scale')

        if self.matrix is None:
            self.matrix = matrix44.create_identity()
        if self.translation is not None:
            self.matrix = matrix44.create_from_translation(self.translation)
        if self.rotation is not None:
            q = quaternion.create(self.rotation[0], self.rotation[1], self.rotation[2], self.rotation[3])
            m = matrix44.create_from_quaternion(q)
            self.matrix = matrix44.multiply(m, self.matrix)
        if self.scale is not None:
            self.matrix = matrix44.multiply(matrix44.create_from_scale(self.scale), self.matrix)

    @property
    def has_children(self):
        return self.children is not None and len(self.children) > 0

    @property
    def is_resource_node(self):
        """Is this just a reference node to a resource?"""
        return self.camera is not None or self.mesh is not None

class GLTFMaterial:
    def __init__(self, data):
        self.name = data.get('name')
        self.baseColorFactor = None
        self.metallicFactor = None
        self.emissiveFactor = None

        pbr = data.get('pbrMetallicRoughness')
        if pbr:
            self.baseColorFactor = pbr.get('baseColorFactor')
            self.metallicFactor = pbr.get('metallicFactor')

        self.emissiveFactor = data.get('emissiveFactor')

class GLTFImage:
    def __init__(self, data):
        self.uri = data['uri']

class GLTFTexture:
    def __init__(self, data):
        self.sampler = data.get('sampler')
        self.source = data.get('source')

class GLTFSampler:
    def __init__(self, data):
        self.magFilter = data.get('magFilter')
        self.minFilter = data.get('minFilter')
        self.wrapS = data.get('wrapS')
        self.wrapT = data.get('wrapT')

class GLTFCamera:
    def __init__(self, data):
        self.data = data
        # "perspective": {
        #     "aspectRatio": 1.0,
        #     "yfov": 0.266482561826706,
        #     "zfar": 1000000.0,
        #     "znear": 0.04999999701976776
        # },
        # "type": "perspective"
<|endoftext|>


<commit_before>#!/usr/bin/env python
import logging
import os
import time
import string
import subprocess
import sys
import re
import socket
from collections import OrderedDict

import requests

logger = logging.getLogger(__name__)

# Config ENV
BACKEND_PORT = os.getenv("BACKEND_PORT", os.getenv("PORT", "80"))
FRONTEND_PORT = os.getenv("FRONTEND_PORT", "80")
MODE = os.getenv("MODE", "http")
BALANCE = os.getenv("BALANCE", "roundrobin")
MAXCONN = os.getenv("MAXCONN", "4096")
SSL = os.getenv("SSL", "")
SSL_BIND_OPTIONS = os.getenv("SSL_BIND_OPTIONS", None)
SSL_BIND_CIPHERS = os.getenv("SSL_BIND_CIPHERS", None)
SESSION_COOKIE = os.getenv("SESSION_COOKIE")
OPTION = os.getenv("OPTION", "redispatch, httplog, dontlognull, forwardfor").split(",")
TIMEOUT = os.getenv("TIMEOUT", "connect 5000, client 50000, server 50000").split(",")
VIRTUAL_HOST = os.getenv("VIRTUAL_HOST", None)
TUTUM_CONTAINER_API_URL = os.getenv("TUTUM_CONTAINER_API_URL", None)
POLLING_PERIOD = max(int(os.getenv("POLLING_PERIOD", 30)), 5)

TUTUM_AUTH = os.getenv("TUTUM_AUTH")
DEBUG = os.getenv("DEBUG", False)

# Const var
CONFIG_FILE = '/etc/haproxy/haproxy.cfg'
HAPROXY_CMD = ['/usr/sbin/haproxy', '-f', CONFIG_FILE, '-db']
LINK_ENV_PATTERN = "_PORT_%s_TCP" % BACKEND_PORT
LINK_ADDR_SUFFIX = LINK_ENV_PATTERN + "_ADDR"
LINK_PORT_SUFFIX = LINK_ENV_PATTERN + "_PORT"
TUTUM_URL_SUFFIX = "_TUTUM_API_URL"
VIRTUAL_HOST_SUFFIX = "_ENV_VIRTUAL_HOST"

# Global Var
HAPROXY_CURRENT_SUBPROCESS = None

endpoint_match = re.compile(r"(?P<proto>tcp|udp):\/\/(?P<addr>[^:]*):(?P<port>.*)")

def get_cfg_text(cfg):
    text = ""
    for section, contents in cfg.items():
        text += "%s\n" % section
        for content in contents:
            text += "  %s\n" % content
    return text.strip()

def create_default_cfg(maxconn, mode):
    cfg = OrderedDict({
        "global": ["log 127.0.0.1 local0",
                   "log 127.0.0.1 local1 notice",
                   "maxconn %s" % maxconn,
                   "pidfile /var/run/haproxy.pid",
                   "user haproxy",
                   "group haproxy",
                   "daemon",
                   "stats socket /var/run/haproxy.stats level admin"],
        "defaults": ["log global",
                     "mode %s" % mode]})
    for option in OPTION:
        if option:
            cfg["defaults"].append("option %s" % option.strip())
    for timeout in TIMEOUT:
        if timeout:
            cfg["defaults"].append("timeout %s" % timeout.strip())
    if SSL_BIND_OPTIONS:
        cfg["global"].append("ssl-default-bind-options %s" % SSL_BIND_OPTIONS)
    if SSL_BIND_CIPHERS:
        cfg["global"].append("ssl-default-bind-ciphers %s" % SSL_BIND_CIPHERS)

    return cfg

def get_backend_routes(dict_var):
    # Return sth like: {'HELLO_WORLD_1': {'addr': '172.17.0.103', 'port': '80'},
    # 'HELLO_WORLD_2': {'addr': '172.17.0.95', 'port': '80'}}
    addr_port_dict = {}
    for name, value in dict_var.iteritems():
        position = string.find(name, LINK_ENV_PATTERN)
        if position != -1:
            container_name = name[:position]
            add_port = addr_port_dict.get(container_name, {'addr': "", 'port': ""})
            try:
                add_port['addr'] = socket.gethostbyname(container_name.lower())
            except socket.gaierror:
                add_port['addr'] = socket.gethostbyname(container_name.lower().replace("_", "-"))
            if name.endswith(LINK_PORT_SUFFIX):
                add_port['port'] = value
            addr_port_dict[container_name] = add_port

    return addr_port_dict

def update_cfg(cfg, backend_routes, vhost):
    logger.debug("Updating cfg: \n old cfg: %s\n backend_routes: %s\n vhost: %s", cfg, backend_routes, vhost)
    # Set frontend
    frontend = []
    frontend.append("bind 0.0.0.0:%s" % FRONTEND_PORT)
    if SSL:
        frontend.append("redirect scheme https code 301 if !{ ssl_fc }"),
        frontend.append("bind 0.0.0.0:443 %s" % SSL)
        frontend.append("reqadd X-Forwarded-Proto:\ https")
    if vhost:
        added_vhost = {}
        for _, domain_name in vhost.iteritems():
            if not added_vhost.has_key(domain_name):
                domain_str = domain_name.upper().replace(".", "_")
                frontend.append("acl host_%s hdr(host) -i %s" % (domain_str, domain_name))
                frontend.append("use_backend %s_cluster if host_%s" % (domain_str, domain_str))
                added_vhost[domain_name] = domain_str
    else:
        frontend.append("default_backend default_service")
    cfg["frontend default_frontend"] = frontend

    # Set backend
    if vhost:
        added_vhost = {}
        for service_name, domain_name in vhost.iteritems():
            domain_str = domain_name.upper().replace(".", "_")
            service_name = service_name.upper()
            if added_vhost.has_key(domain_name):
                backend = cfg.get("backend %s_cluster" % domain_str, [])
                for container_name, addr_port in backend_routes.iteritems():
                    if container_name.startswith(service_name):
                        server_string = "server %s %s:%s" % (container_name, addr_port["addr"], addr_port["port"])
                        if SESSION_COOKIE:
                            server_string += " cookie check"

                        # Do not add duplicate backend routes
                        duplicated = False
                        for server_str in backend:
                            if "%s:%s" % (addr_port["addr"], addr_port["port"]) in server_str:
                                duplicated = True
                                break
                        if not duplicated:
                            backend.append(server_string)
                cfg["backend %s_cluster" % domain_str] = sorted(backend)
            else:
                backend = []
                if SESSION_COOKIE:
                    backend.append("appsession %s len 64 timeout 3h request-learn prefix" % (SESSION_COOKIE, ))

                backend.append("balance %s" % BALANCE)
                for container_name, addr_port in backend_routes.iteritems():
                    if container_name.startswith(service_name):
                        server_string = "server %s %s:%s" % (container_name, addr_port["addr"], addr_port["port"])
                        if SESSION_COOKIE:
                            server_string += " cookie check"

                        # Do not add duplicate backend routes
                        duplicated = False
                        for server_str in backend:
                            if "%s:%s" % (addr_port["addr"], addr_port["port"]) in server_str:
                                duplicated = True
                                break
                        if not duplicated:
                            backend.append(server_string)
            if backend:
                cfg["backend %s_cluster" % domain_name.upper().replace(".", "_")] = sorted(backend)
                added_vhost[domain_name] = domain_name.upper().replace(".", "_")

    else:
        backend = []
        if SESSION_COOKIE:
            backend.append("appsession %s len 64 timeout 3h request-learn prefix" % (SESSION_COOKIE, ))

        backend.append("balance %s" % BALANCE)
        for container_name, addr_port in backend_routes.iteritems():
            server_string = "server %s %s:%s" % (container_name, addr_port["addr"], addr_port["port"])
            if SESSION_COOKIE:
                server_string += " cookie check"

            # Do not add duplicate backend routes
            duplicated = False
            for server_str in backend:
                if "%s:%s" % (addr_port["addr"], addr_port["port"]) in server_str:
                    duplicated = True
                    break
            if not duplicated:
                backend.append(server_string)

        cfg["backend default_service"] = sorted(backend)

    logger.debug("New cfg: %s", cfg)

def save_config_file(cfg_text, config_file):
    try:
        directory = os.path.dirname(config_file)
        if not os.path.exists(directory):
            os.makedirs(directory)
        f = open(config_file, 'w')
    except Exception as e:
        logger.error(e)
    else:
        f.write(cfg_text)
        logger.info("Config file is updated")
        f.close()

def reload_haproxy():
    global HAPROXY_CURRENT_SUBPROCESS
    if HAPROXY_CURRENT_SUBPROCESS:
        # Reload haproxy
        logger.info("Reloading haproxy")
        process = subprocess.Popen(HAPROXY_CMD + ["-sf", str(HAPROXY_CURRENT_SUBPROCESS.pid)])
        HAPROXY_CURRENT_SUBPROCESS.wait()
        HAPROXY_CURRENT_SUBPROCESS = process
    else:
        # Launch haproxy
        logger.info("Launching haproxy")
        HAPROXY_CURRENT_SUBPROCESS = subprocess.Popen(HAPROXY_CMD)

def update_virtualhost(vhost):
    if VIRTUAL_HOST:
        # vhost specified using environment variables
        for host in VIRTUAL_HOST.split(","):
            tmp = host.split("=", 2)
            if len(tmp) == 2:
                vhost[tmp[0].strip()] = tmp[1].strip()
    else:
        # vhost specified in the linked containers
        for name, value in os.environ.iteritems():
            position = string.find(name, VIRTUAL_HOST_SUFFIX)
            if position != -1 and value != "**None**":
                hostname = name[:position]
                vhost[hostname] = value

if __name__ == "__main__":
    logging.basicConfig(stream=sys.stdout)
    logging.getLogger(__name__).setLevel(logging.DEBUG if DEBUG else logging.INFO)

    cfg = create_default_cfg(MAXCONN, MODE)
    vhost = {}

    # Tell the user the mode of autoupdate we are using, if any
    if TUTUM_CONTAINER_API_URL:
        if TUTUM_AUTH:
            logger.info("HAproxy has access to Tutum API - will reload list of backends every %d seconds",
                        POLLING_PERIOD)
        else:
            logger.warning(
                "HAproxy doesn't have access to Tutum API and it's running in Tutum - you might want to give "
                "an API role to this service for automatic backend reconfiguration")
    else:
        logger.info("HAproxy is not running in Tutum")
    session = requests.Session()
    headers = {"Authorization": TUTUM_AUTH}

    # Main loop
    old_text = ""
    while True:
        try:
            if TUTUM_CONTAINER_API_URL and TUTUM_AUTH:
                # Running on Tutum with API access - fetch updated list of environment variables
                r = session.get(TUTUM_CONTAINER_API_URL, headers=headers)
                r.raise_for_status()
                container_details = r.json()

                backend_routes = {}
                for link in container_details.get("linked_to_container", []):
                    for port, endpoint in link.get("endpoints", {}).iteritems():
                        if port == "%s/tcp" % BACKEND_PORT:
                            backend_routes[link["name"]] = endpoint_match.match(endpoint).groupdict()
            else:
                # No Tutum API access - configuring backends based on static environment variables
                backend_routes = get_backend_routes(os.environ)

            # Update backend routes
            update_virtualhost(vhost)
            update_cfg(cfg, backend_routes, vhost)
            cfg_text = get_cfg_text(cfg)

            # If cfg changes, write to file
            if old_text != cfg_text:
                logger.info("HAProxy configuration has been changed:\n%s" % cfg_text)
                save_config_file(cfg_text, CONFIG_FILE)
                reload_haproxy()
                old_text = cfg_text
        except Exception as e:
            logger.exception("Error: %s" % e)

        time.sleep(POLLING_PERIOD)
<commit_msg>fix reqadd warnings<commit_after>#!/usr/bin/env python
import logging
import os
import time
import string
import subprocess
import sys
import re
import socket
from collections import OrderedDict

import requests

logger = logging.getLogger(__name__)

# Config ENV
BACKEND_PORT = os.getenv("BACKEND_PORT", os.getenv("PORT", "80"))
FRONTEND_PORT = os.getenv("FRONTEND_PORT", "80")
MODE = os.getenv("MODE", "http")
BALANCE = os.getenv("BALANCE", "roundrobin")
MAXCONN = os.getenv("MAXCONN", "4096")
SSL = os.getenv("SSL", "")
SSL_BIND_OPTIONS = os.getenv("SSL_BIND_OPTIONS", None)
SSL_BIND_CIPHERS = os.getenv("SSL_BIND_CIPHERS", None)
SESSION_COOKIE = os.getenv("SESSION_COOKIE")
OPTION = os.getenv("OPTION", "redispatch, httplog, dontlognull, forwardfor").split(",")
TIMEOUT = os.getenv("TIMEOUT", "connect 5000, client 50000, server 50000").split(",")
VIRTUAL_HOST = os.getenv("VIRTUAL_HOST", None)
TUTUM_CONTAINER_API_URL = os.getenv("TUTUM_CONTAINER_API_URL", None)
POLLING_PERIOD = max(int(os.getenv("POLLING_PERIOD", 30)), 5)

TUTUM_AUTH = os.getenv("TUTUM_AUTH")
DEBUG = os.getenv("DEBUG", False)

# Const var
CONFIG_FILE = '/etc/haproxy/haproxy.cfg'
HAPROXY_CMD = ['/usr/sbin/haproxy', '-f', CONFIG_FILE, '-db']
LINK_ENV_PATTERN = "_PORT_%s_TCP" % BACKEND_PORT
LINK_ADDR_SUFFIX = LINK_ENV_PATTERN + "_ADDR"
LINK_PORT_SUFFIX = LINK_ENV_PATTERN + "_PORT"
TUTUM_URL_SUFFIX = "_TUTUM_API_URL"
VIRTUAL_HOST_SUFFIX = "_ENV_VIRTUAL_HOST"

# Global Var
HAPROXY_CURRENT_SUBPROCESS = None

endpoint_match = re.compile(r"(?P<proto>tcp|udp):\/\/(?P<addr>[^:]*):(?P<port>.*)")

def get_cfg_text(cfg):
    text = ""
    for section, contents in cfg.items():
        text += "%s\n" % section
        for content in contents:
            text += "  %s\n" % content
    return text.strip()

def create_default_cfg(maxconn, mode):
    cfg = OrderedDict({
        "global": ["log 127.0.0.1 local0",
                   "log 127.0.0.1 local1 notice",
                   "maxconn %s" % maxconn,
                   "pidfile /var/run/haproxy.pid",
                   "user haproxy",
                   "group haproxy",
                   "daemon",
                   "stats socket /var/run/haproxy.stats level admin"],
        "defaults": ["log global",
                     "mode %s" % mode]})
    for option in OPTION:
        if option:
            cfg["defaults"].append("option %s" % option.strip())
    for timeout in TIMEOUT:
        if timeout:
            cfg["defaults"].append("timeout %s" % timeout.strip())
    if SSL_BIND_OPTIONS:
        cfg["global"].append("ssl-default-bind-options %s" % SSL_BIND_OPTIONS)
    if SSL_BIND_CIPHERS:
        cfg["global"].append("ssl-default-bind-ciphers %s" % SSL_BIND_CIPHERS)

    return cfg

def get_backend_routes(dict_var):
    # Return sth like: {'HELLO_WORLD_1': {'addr': '172.17.0.103', 'port': '80'},
    # 'HELLO_WORLD_2': {'addr': '172.17.0.95', 'port': '80'}}
    addr_port_dict = {}
    for name, value in dict_var.iteritems():
        position = string.find(name, LINK_ENV_PATTERN)
        if position != -1:
            container_name = name[:position]
            add_port = addr_port_dict.get(container_name, {'addr': "", 'port': ""})
            try:
                add_port['addr'] = socket.gethostbyname(container_name.lower())
            except socket.gaierror:
                add_port['addr'] = socket.gethostbyname(container_name.lower().replace("_", "-"))
            if name.endswith(LINK_PORT_SUFFIX):
                add_port['port'] = value
            addr_port_dict[container_name] = add_port

    return addr_port_dict

def update_cfg(cfg, backend_routes, vhost):
    logger.debug("Updating cfg: \n old cfg: %s\n backend_routes: %s\n vhost: %s", cfg, backend_routes, vhost)
    # Set frontend
    frontend = []
    frontend.append("bind 0.0.0.0:%s" % FRONTEND_PORT)
    if SSL:
        frontend.append("reqadd X-Forwarded-Proto:\ https")
        frontend.append("redirect scheme https code 301 if !{ ssl_fc }"),
        frontend.append("bind 0.0.0.0:443 %s" % SSL)
    if vhost:
        added_vhost = {}
        for _, domain_name in vhost.iteritems():
            if not added_vhost.has_key(domain_name):
                domain_str = domain_name.upper().replace(".", "_")
                frontend.append("acl host_%s hdr(host) -i %s" % (domain_str, domain_name))
                frontend.append("use_backend %s_cluster if host_%s" % (domain_str, domain_str))
                added_vhost[domain_name] = domain_str
    else:
        frontend.append("default_backend default_service")
    cfg["frontend default_frontend"] = frontend

    # Set backend
    if vhost:
        added_vhost = {}
        for service_name, domain_name in vhost.iteritems():
            domain_str = domain_name.upper().replace(".", "_")
            service_name = service_name.upper()
            if added_vhost.has_key(domain_name):
                backend = cfg.get("backend %s_cluster" % domain_str, [])
                for container_name, addr_port in backend_routes.iteritems():
                    if container_name.startswith(service_name):
                        server_string = "server %s %s:%s" % (container_name, addr_port["addr"], addr_port["port"])
                        if SESSION_COOKIE:
                            server_string += " cookie check"

                        # Do not add duplicate backend routes
                        duplicated = False
                        for server_str in backend:
                            if "%s:%s" % (addr_port["addr"], addr_port["port"]) in server_str:
                                duplicated = True
                                break
                        if not duplicated:
                            backend.append(server_string)
                cfg["backend %s_cluster" % domain_str] = sorted(backend)
            else:
                backend = []
                if SESSION_COOKIE:
                    backend.append("appsession %s len 64 timeout 3h request-learn prefix" % (SESSION_COOKIE, ))

                backend.append("balance %s" % BALANCE)
                for container_name, addr_port in backend_routes.iteritems():
                    if container_name.startswith(service_name):
                        server_string = "server %s %s:%s" % (container_name, addr_port["addr"], addr_port["port"])
                        if SESSION_COOKIE:
                            server_string += " cookie check"

                        # Do not add duplicate backend routes
                        duplicated = False
                        for server_str in backend:
                            if "%s:%s" % (addr_port["addr"], addr_port["port"]) in server_str:
                                duplicated = True
                                break
                        if not duplicated:
                            backend.append(server_string)
            if backend:
                cfg["backend %s_cluster" % domain_name.upper().replace(".", "_")] = sorted(backend)
                added_vhost[domain_name] = domain_name.upper().replace(".", "_")

    else:
        backend = []
        if SESSION_COOKIE:
            backend.append("appsession %s len 64 timeout 3h request-learn prefix" % (SESSION_COOKIE, ))

        backend.append("balance %s" % BALANCE)
        for container_name, addr_port in backend_routes.iteritems():
            server_string = "server %s %s:%s" % (container_name, addr_port["addr"], addr_port["port"])
            if SESSION_COOKIE:
                server_string += " cookie check"

            # Do not add duplicate backend routes
            duplicated = False
            for server_str in backend:
                if "%s:%s" % (addr_port["addr"], addr_port["port"]) in server_str:
                    duplicated = True
                    break
            if not duplicated:
                backend.append(server_string)

        cfg["backend default_service"] = sorted(backend)

    logger.debug("New cfg: %s", cfg)

def save_config_file(cfg_text, config_file):
    try:
        directory = os.path.dirname(config_file)
        if not os.path.exists(directory):
            os.makedirs(directory)
        f = open(config_file, 'w')
    except Exception as e:
        logger.error(e)
    else:
        f.write(cfg_text)
        logger.info("Config file is updated")
        f.close()

def reload_haproxy():
    global HAPROXY_CURRENT_SUBPROCESS
    if HAPROXY_CURRENT_SUBPROCESS:
        # Reload haproxy
        logger.info("Reloading haproxy")
        process = subprocess.Popen(HAPROXY_CMD + ["-sf", str(HAPROXY_CURRENT_SUBPROCESS.pid)])
        HAPROXY_CURRENT_SUBPROCESS.wait()
        HAPROXY_CURRENT_SUBPROCESS = process
    else:
        # Launch haproxy
        logger.info("Launching haproxy")
        HAPROXY_CURRENT_SUBPROCESS = subprocess.Popen(HAPROXY_CMD)

def update_virtualhost(vhost):
    if VIRTUAL_HOST:
        # vhost specified using environment variables
        for host in VIRTUAL_HOST.split(","):
            tmp = host.split("=", 2)
            if len(tmp) == 2:
                vhost[tmp[0].strip()] = tmp[1].strip()
    else:
        # vhost specified in the linked containers
        for name, value in os.environ.iteritems():
            position = string.find(name, VIRTUAL_HOST_SUFFIX)
            if position != -1 and value != "**None**":
                hostname = name[:position]
                vhost[hostname] = value

if __name__ == "__main__":
    logging.basicConfig(stream=sys.stdout)
    logging.getLogger(__name__).setLevel(logging.DEBUG if DEBUG else logging.INFO)

    cfg = create_default_cfg(MAXCONN, MODE)
    vhost = {}

    # Tell the user the mode of autoupdate we are using, if any
    if TUTUM_CONTAINER_API_URL:
        if TUTUM_AUTH:
            logger.info("HAproxy has access to Tutum API - will reload list of backends every %d seconds",
                        POLLING_PERIOD)
        else:
            logger.warning(
                "HAproxy doesn't have access to Tutum API and it's running in Tutum - you might want to give "
                "an API role to this service for automatic backend reconfiguration")
    else:
        logger.info("HAproxy is not running in Tutum")
    session = requests.Session()
    headers = {"Authorization": TUTUM_AUTH}

    # Main loop
    old_text = ""
    while True:
        try:
            if TUTUM_CONTAINER_API_URL and TUTUM_AUTH:
                # Running on Tutum with API access - fetch updated list of environment variables
                r = session.get(TUTUM_CONTAINER_API_URL, headers=headers)
                r.raise_for_status()
                container_details = r.json()

                backend_routes = {}
                for link in container_details.get("linked_to_container", []):
                    for port, endpoint in link.get("endpoints", {}).iteritems():
                        if port == "%s/tcp" % BACKEND_PORT:
                            backend_routes[link["name"]] = endpoint_match.match(endpoint).groupdict()
            else:
                # No Tutum API access - configuring backends based on static environment variables
                backend_routes = get_backend_routes(os.environ)

            # Update backend routes
            update_virtualhost(vhost)
            update_cfg(cfg, backend_routes, vhost)
            cfg_text = get_cfg_text(cfg)

            # If cfg changes, write to file
            if old_text != cfg_text:
                logger.info("HAProxy configuration has been changed:\n%s" % cfg_text)
                save_config_file(cfg_text, CONFIG_FILE)
                reload_haproxy()
                old_text = cfg_text
        except Exception as e:
            logger.exception("Error: %s" % e)

        time.sleep(POLLING_PERIOD)
<|endoftext|>