Beispiel #1
0
    def __init__(self):

        cors = CORS(allow_all_origins=True)

        super(AuthService, self).__init__(
            middleware=[cors.middleware, ContextMiddleware(), LogMiddleware()]
        )

        self.BASE_PATH = '/api/'  # The url is not complete due to the url mapper from paste

        # Build routes
        resources = [LoginAPI]
        exclude_list = ConfReader().get_list('API', 'exclude_apis')
        if len(exclude_list) > 0:
            resources = list(
                filter(lambda api: api.__name__ not in exclude_list, resources)
            )
        for r in resources:
            r.initialize()
            instance = r()
            for route in r.ROUTES:
                self.add_route(self.BASE_PATH + route, instance)
Beispiel #2
0
    def __init__(self):

        cors = CORS(allow_all_origins=True)

        super(Service, self).__init__(
            middleware=[cors.middleware,
                        ContextMiddleware(),
                        LogMiddleware()])

        self.BASE_PATH = '/nbi/autonomous/api'

        # Build routes
        resources = __find_resources__()
        exclude_list = ConfReader().get_list('API', 'exclude_apis')
        if len(exclude_list) > 0:
            resources = list(
                filter(lambda api: api.__name__ not in exclude_list,
                       resources))
        for r in resources:
            r.initialize()
            instance = r()
            for route in r.ROUTES:
                self.add_route(self.BASE_PATH + route, instance)
Beispiel #3
0
    def on_get(self, req, resp, source, **kwargs):
        """
        Retrieve the list of flows collected on a given SourceIP. Additionally it can be provided the
        DestinationIP and DestinationPort. This method accepts also the start_time and end_time as query parameters
        :param source: SourceIP of the flow.
        :param kwargs: It can be: only DestinationIP or DestinationIP and DestinationPort
        :return: List with flows
        """
        dimensions_query = 'SourceIP:' + source
        if kwargs:
            dimensions_query += ',' + ','.join(['{}:{}'.format(key, value) for key, value in kwargs.items()])

        req.context['query_parameters']['dimensions'] = dimensions_query

        if 'metric' not in req.context['query_parameters']:
            raise HTTPBadRequest(title='Missing Metric', description='Missing metric name to collect metrics',
                                 code='300')

        req.context['query_parameters']['name'] = req.context['query_parameters'].get('metric')
        req.context['query_parameters']['group_by'] = 'SourceIP,DestinationIP,DestinationPort,FlowID'
        req.context['query_parameters']['merge_metrics'] = 'true'

        if 'start_time' not in req.context['query_parameters']:
            d = datetime.now() - timedelta(days=1)
            req.context['query_parameters']['start_time'] = d.isoformat()

        headers = Authenticate.get_header()  # Insert the auth header
        r = request(ConfReader().get('MONASCA', 'url') + Flows.ENDPOINT, params=req.context['query_parameters'],
                    headers=headers)

        req.context['query_parameters'].pop('group_by')
        req.context['query_parameters'].pop('merge_metrics')
        req.context['query_parameters'].pop('name')

        resp.body = self.format_body(Flows.__convert_result__(r.json(), req.uri, req), from_dict=True)
        resp.status = str(r.status_code)
Beispiel #4
0
    def __load_db__(self):
        """
        Function to set the DB connection and tables.
        This uses the sqlalchemy automap to populate the needed tables.
        It is intended to keep maximum abstraction from DB to lower schema changes impact.
        NOTE: This not create models it only refers tables
        :raise EnvironmentError: Whenever the ini file doesn't contain the url on the Database section
        """
        connection = ConfReader().get('TOPOLOGY_DATABASE', 'url')

        if not connection:
            raise EnvironmentError('Missing Database URL connection')
        self.engine = create_engine(connection,
                                    pool_recycle=1800,
                                    connect_args={'connect_timeout': 15})

        # Create model based on DB
        # http://docs.sqlalchemy.org/en/latest/orm/extensions/automap.html
        self.base = automap_base()
        self.base.prepare(self.engine, reflect=True)

        # Load tables
        # Keep maximum abstraction to lower the impact of schema changes
        self.tables = self.base.metadata.tables
Beispiel #5
0
def request_post_patch(endpoint, method, **kwargs):
    """
    Perform POST, PATCH and PUT requests to the given endpoint
    :param endpoint: The endpoint to perform the request
    :param method: The method to use
    :param kwargs:
                    headers: the request headers
                    json: the request object in a dict format
    :return: request response object
    """
    logger.info('Requiring {} for {}, {}'.format(
        method, kwargs.get('service_name', 'Service'), endpoint))
    r_method = REQUEST_METHOD[method]
    r = r_method(
        endpoint,
        json=kwargs.get('json'),
        headers=kwargs.get('headers', {}),
        timeout=ConfReader().get('REQUESTER', 'timeout'),
        files=kwargs.get('files'),
        params=kwargs.get('params', {}),
    )
    logger.debug('Response from {}: {}'.format(
        kwargs.get('service_name', 'Service'), r.text if r.text else None))
    return r
Beispiel #6
0
class LoginAPI(BaseResource):
    """
    API to process the login request.
    """

    ROUTES = [
        'login/',
        'login',
    ]
    KS_ENDPOINT = ConfReader().get('keystone', 'url') + '/auth/tokens'
    SERVICE_NAME = 'AUTH'

    logger = logging.getLogger(__name__)

    def on_options(self, req, resp):
        """
        OPTIONS method for the Login API
        :return:
        204 No Content - An header with the allow and all HTTP methods available
        """
        resp.set_header('Allow', 'OPTIONS, POST')
        resp.status = HTTP_204

    @validate(load_schema('login'))
    def on_post(self, req, resp, parsed):
        """
        Create new token. This will issue a new request to the Keystone service that will launch a new token.
        :return:
        201 Created - When the new token is successfully created and the credentials are correct.
        An object with a JSON session representation is returned containing the issued_at, expires_at and user fields.
        """
        data = parsed.get('auth')

        # Build KS request
        ks_domain = dict(
            name=data.get('tenant'))  # In KS tenants are known as domains
        ks_user = dict(name=data.get('username'),
                       password=data.get('password'),
                       domain=ks_domain)
        ks_pw = dict(user=ks_user)

        ks_identity = dict(methods=['password'], password=ks_pw)
        ks_scope = dict(domain=ks_domain)
        ks_auth = dict(identity=ks_identity, scope=ks_scope)

        # Process request
        r = request_post_patch(LoginAPI.KS_ENDPOINT,
                               method='POST',
                               headers={'Content-Type': 'application/json'},
                               json=dict(auth=ks_auth))

        resp.set_header('X-Subject-Token', r.headers['X-Subject-Token'])
        resp.status = HTTP_201

        data = json.loads(r.text)
        data = data['token']

        user = data['user']
        user['tenant'] = dict(id=user.get('domain').get('id'),
                              name=user.get('domain').get('name'))

        user['role'] = data.pop('roles',
                                None)[0]  # User's will only have one role
        user.pop('domain', None)
        data['user'] = user

        # Pop unwanted keys
        data.pop('catalog', None)
        data.pop('methods', None)
        data.pop('domain', None)

        self.format_body(dict(session=data), from_dict=True)
        LoginAPI.logger.info('User {} successfully logged'.format(
            user.get('id', None)))
Beispiel #7
0
class UserAPI(BaseResource):
    """
    API that allows user management. This API exposes an Option, GET, POST, PATCH and DELETE methods. This converts
    Keystone user objects into simple user objects. All methods translate keystone URI to internal URI.
    """

    KS_ENDPOINT = ConfReader().get('keystone', 'url') + '/users'
    SERVICE_NAME = 'User'

    ROUTES = [
        'tenants/{tenant_id}/users',
        'tenants/{tenant_id}/users/{user_id}',
    ]

    @staticmethod
    def __get_user_role__(req, tenant_id, user):
        """
        Internal method to query the identity service for the role of a specific user.
        This method converts the array roles into a single role object,
        since the user will only have a single role.
        :param req: WSGI request object to get the headers
        :param tenant_id: The tenant id to check user's role
        :param user: user object to request the role
        :return: User object with role key updated.
        """
        endpoint = "{}/{}/users/{}/roles/".format(TenantAPI.KS_ENDPOINT,
                                                  tenant_id, user)

        r = request(endpoint,
                    headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
                    ignore_exception=True,
                    service_name=UserAPI.SERVICE_NAME)

        if r.status_code != 200:
            return None  # If user requires himself without being admin can't see it's roles

        data = json.loads(r.text)
        data = data['roles']
        if data:
            # The user will only have a role in a tenant
            return dict(id=data[0]['id'], name=data[0]['name'])

    @staticmethod
    def convert_ks_user_user(req, specific=True, r=None, user=None):
        """
        Converts a Keystone Object in a user object. Corrects the links and removes the unnecessary keys.
        :param req: The request object to set the result
        :param r: The original request object to keystone with the response. If provided the data is
        loaded from the object.
        :param user: The user to convert. If provided the data is the object itself.
        :return: The user object
        """
        if r:
            data = json.loads(r.text)
            user = data['user']
        else:
            user = user

        role = UserAPI.__get_user_role__(req, user.get('domain_id'),
                                         user.get('id'))
        if role:
            user['role'] = role

        user['links'][
            'self'] = req.uri if specific else req.uri + '/' + user['id']
        user.pop('domain_id', None)  # This field isn't be available in SELFNET
        user.pop('extra', None)  # This field isn't be available in SELFNET
        user.pop('password_expires_at',
                 None)  # This field isn't be available in SELFNET
        user['username'] = user.pop('name', None)

        return user

    def on_options(self, req, resp, **kwargs):
        """
        OPTIONS method for the User API
        :return:
                204 No Content - Header with the allow and all HTTP methods available
        """
        if 'user_id' in kwargs:
            resp.set_header('Allow', 'DELETE, GET, OPTIONS, PATCH')
        else:
            resp.set_header('Allow', 'GET, OPTIONS, POST')
        resp.status = HTTP_204

    def on_get(self, req, resp, **kwargs):
        """
        List users. This method processes the HTTP get request for this API.
        If the user_id is provided the specific get user method is called,
        otherwise the get all users method is retrieved.
        The endpoint only acts upon a single tenant.
        """
        if 'user_id' in kwargs:
            self.get_specific_user(req, resp, kwargs.get('tenant_id', None),
                                   kwargs.get('user_id', None))
        else:
            self.get_all_tenant_users(req, resp, kwargs.get('tenant_id', None))

    def get_all_tenant_users(self, req, resp, tenant_id):
        """
        Method to retrieve all users from the identity service. This endpoint is only accessible to Super ADMIN users
        or tenant admin users.
        :param tenant_id: The tenant the users belong to
        :return:
                200 OK - When all users within a tenant are retrieved with success
        """
        r = request(UserAPI.KS_ENDPOINT,
                    headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
                    params=dict(domain_id=tenant_id),
                    service_name=UserAPI.SERVICE_NAME)

        data = json.loads(r.text)
        users = data['users']
        # Converts keystone user and update the role
        users = list(
            map(
                lambda user: UserAPI.convert_ks_user_user(
                    req, specific=False, user=user), users))
        #users = list(map(lambda user: UserAPI.__get_user_role__(req, tenant_id, user), users))

        resp.body = self.format_body(dict(users=users), from_dict=True)
        resp.status = HTTP_200

    def get_specific_user(self, req, resp, tenant_id, user_id):
        """
        Method to retrieve a single user. This endpoint is accessible to a Super ADMIN and Tenant Admin.
        :param tenant_id: The tenant the user belong to
        :param user_id: The user id to retrieve
        :return:
                200 OK - When the user is found and successfully retrieved
        """
        endpoint = UserAPI.KS_ENDPOINT + '/' + user_id

        # Request the User
        r = request(endpoint,
                    headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
                    service_name=UserAPI.SERVICE_NAME)

        # Converts keystone user and update the role
        user = UserAPI.convert_ks_user_user(req, r=r)

        resp.body = self.format_body(dict(user=user))
        resp.status = HTTP_200

    @enforce(SERVICE_NAME, "create")
    @validate(load_schema('user_create'))
    def on_post(self, req, resp, tenant_id, parsed):
        """
        Method to create new user. This endpoint is accessible to Super Admin and tenant admin.
        The name of each user must be unique within a tenant.
        :return:
                201 Created - When the user is successfully created
        """
        data = parsed.get('user')

        # Validate Role ID
        role_endpoint = RoleAPI.KS_ENDPOINT + '/' + data.get('role').get('id')
        request(role_endpoint,
                headers={
                    'Content-Type': 'application/json',
                    'X-Auth-Token': req.headers['X-AUTH-TOKEN']
                },
                service_name=UserAPI.SERVICE_NAME)

        # Build KS object
        ks_user = dict()
        ks_user['description'] = data.get('description', None)
        ks_user['name'] = data.get('username')
        ks_user['password'] = data.get('password')
        ks_user['enabled'] = data.get('enabled', True)
        ks_user['domain_id'] = tenant_id

        # Request user creation
        r = request_post_patch(UserAPI.KS_ENDPOINT,
                               method='POST',
                               headers={
                                   'Content-Type': 'application/json',
                                   'X-Auth-Token': req.headers['X-AUTH-TOKEN']
                               },
                               json=dict(user=ks_user),
                               service_name=UserAPI.SERVICE_NAME)

        # Get user object
        user = UserAPI.convert_ks_user_user(req, r=r)

        # Add specified role
        endpoint = "{}/{}/users/{}/roles/{}".format(TenantAPI.KS_ENDPOINT,
                                                    tenant_id, user.get('id'),
                                                    data.get('role').get('id'))

        request_post_patch(
            endpoint,
            method='PUT',
            headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
            service_name=UserAPI.SERVICE_NAME)

        user['role'] = dict(id=data.get('role').get('id'))
        resp.status = HTTP_201
        resp.body = self.format_body(dict(user=user))

    @enforce(SERVICE_NAME, "delete")
    def on_delete(self, req, resp, tenant_id, user_id):
        """
        Method to delete a user. This endpoint is only accessible to the Super Admin and tenant admin.
        The user is only deleted if disabled before.
        :param tenant_id: The tenant id where the user belongs to
        :return:
                204 No Content - When the tenant is successfully deleted
        """
        endpoint = UserAPI.KS_ENDPOINT + '/' + user_id

        request(endpoint,
                method='DELETE',
                headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
                service_name=UserAPI.SERVICE_NAME)
        resp.status = HTTP_204

    @enforce(SERVICE_NAME, 'update')
    @validate(load_schema('user_update'))
    def on_patch(self, req, resp, parsed, tenant_id, user_id):
        """
        Method to update a User. This endpoint is only accessible to the Super Admin and tenant admin.
        It's not required the full object only the updated fields.
        :return:
                200 OK - When the user is edited successfully
        """

        print('Im patching')
        # Validate incoming data
        data = parsed.get('user')

        # Build KS object based on user's role
        ks_user = dict()
        ks_user['description'] = data.get('description', None)
        ks_user['name'] = data.get('username', None)
        ks_user['enabled'] = data.get('enabled', None)

        ks_user['password'] = data.get('password', None)
        ks_user = {k: v
                   for k, v in ks_user.items()
                   if v is not None}  # Generator to clear None value keys

        # Patch or get user when only role is updated
        endpoint = UserAPI.KS_ENDPOINT + '/' + user_id

        r = request_post_patch(
            endpoint,
            method='PATCH',
            headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
            json=dict(user=ks_user),
            service_name=UserAPI.SERVICE_NAME)

        # Converts keystone user and update the role
        user = UserAPI.convert_ks_user_user(req, r=r)

        if 'role' not in data:
            resp.status = HTTP_200
            resp.body = self.format_body(dict(user=user))
            return

        # Update role
        # Validate Role ID
        role_endpoint = RoleAPI.KS_ENDPOINT + '/' + data.get('role').get('id')
        request(role_endpoint,
                headers={
                    'Content-Type': 'application/json',
                    'X-Auth-Token': req.headers['X-AUTH-TOKEN']
                },
                service_name=RoleAPI.SERVICE_NAME)

        # Disable current role
        role_id = user.get('role').get('id')

        endpoint = "{}/{}/users/{}/roles/{}".format(TenantAPI.KS_ENDPOINT,
                                                    tenant_id, user_id,
                                                    role_id)

        request(endpoint,
                method='DELETE',
                headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
                service_name=UserAPI.SERVICE_NAME)

        # Set new role
        endpoint = "{}/{}/users/{}/roles/{}".format(TenantAPI.KS_ENDPOINT,
                                                    tenant_id, user_id,
                                                    data.get('role').get('id'))
        request_post_patch(
            endpoint,
            method='PUT',
            headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
            service_name=RoleAPI.SERVICE_NAME)

        user['role'] = dict(id=data.get('role').get('id'))
        resp.status = HTTP_200
        resp.body = self.format_body(dict(user=user))
Beispiel #8
0
import json

from falcon import HTTP_200, HTTP_201, HTTP_204

from service.authz.policy import enforce
from service.conf_reader import ConfReader
from service.requester import request, request_post_patch
from service.resources import BaseResource, validate
from service.resources.role import RoleAPI
from service.resources.tenant import TenantAPI
from service.schema import load_schema

ADMIN_DOMAIN_ID = ConfReader().get('keystone', 'admin_tenant')
ADMIN_ROLE_NAME = 'admin'


class UserAPI(BaseResource):
    """
    API that allows user management. This API exposes an Option, GET, POST, PATCH and DELETE methods. This converts
    Keystone user objects into simple user objects. All methods translate keystone URI to internal URI.
    """

    KS_ENDPOINT = ConfReader().get('keystone', 'url') + '/users'
    SERVICE_NAME = 'User'

    ROUTES = [
        'tenants/{tenant_id}/users',
        'tenants/{tenant_id}/users/{user_id}',
    ]

    @staticmethod
Beispiel #9
0
class TenantAPI(BaseResource):
    """
    API that allows tenant management. This API exposes an Option, GET, POST, PATCH and DELETE Methods. This converts
    Keystone Domain objects into simple Tenant objects. All methods translate keystone URI to internal URI.
    """

    KS_ENDPOINT = ConfReader().get('keystone', 'url') + '/domains'

    ROUTES = [
        'tenants/', 'tenants', 'tenants/{tenant_id}', 'tenants/{tenant_id}/'
    ]

    SERVICE_NAME = 'Tenant'

    @staticmethod
    def convert_domain_tenant(req, specific=True, r=None, domain=None):
        """
        Converts a Keystone Object in a tenant object. Corrects the links and removes the domain keyword.
        :param req: The request object to set the result
        :param specific: The original search was performed for a specific tenant
        :param r: The original request object to keystone with the response. If provided the data is
        loaded from the object.
        :param domain: The domain to convert. If provided the data is the object itself.
        :return: The tenant object
        """
        if r:
            data = json.loads(r.text)
            tenant = data['domain']
        else:
            tenant = domain

        tenant['links'][
            'self'] = req.uri if specific else req.uri + '/' + tenant['id']
        return tenant

    def on_options(self, req, resp, **kargs):
        """
        OPTIONS method for the Tenant API
        :return:
        204 No Content - Header with the allow and all HTTP methods available
        """
        if kargs:
            resp.set_header('Allow', 'DELETE, GET, OPTIONS, PATCH')
        else:
            resp.set_header('Allow', 'GET, OPTIONS, POST')
        resp.status = HTTP_204

    @enforce(SERVICE_NAME, 'default')
    def on_get(self, req, resp, **kwargs):
        """
        List tenants. This method processes the HTTP get request for this API.
        If the tenant_id is provided the specific get tenant method is called,
        otherwise the get all tenants method is retrieved.
        """
        if kwargs:
            self.get_specific_tenant(req, resp, kwargs.get('tenant_id', None))
        else:
            self.get_all_tenants(req, resp)

    def get_all_tenants(self, req, resp):
        """
        Method to retrieve all tenants from the identity service. This endpoint is only accessible to Super ADMIN users.
        :return:
                200 OK - When all tenants are retrieved with success
        """
        r = request(TenantAPI.KS_ENDPOINT,
                    headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
                    service_name=TenantAPI.SERVICE_NAME)
        data = json.loads(r.text)

        # Convert object
        tenants = data.get('domains', None)
        tenants = list(
            map(
                lambda domain: self.convert_domain_tenant(
                    req, specific=False, domain=domain), tenants))
        links = data.get('links', None)
        links["self"] = req.uri

        resp.body = self.format_body(dict(tenants=tenants, links=links),
                                     from_dict=True)

    def get_specific_tenant(self, req, resp, tenant_id):
        """
        Method to retrieve a single tenant. This endpoint is accessible to a Tenant Admin,
        that can only query it's tenant and Super Admin.
        :param tenant_id: Tenant ID to retrieve
        :return:
                200 OK - When the tenant is found and successfully retrieved
        """
        # Configure correct endpoint
        endpoint = TenantAPI.KS_ENDPOINT + '/' + tenant_id

        # Request the tenant
        r = request(endpoint,
                    headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
                    service_name=TenantAPI.SERVICE_NAME)
        tenant = TenantAPI.convert_domain_tenant(req, r=r)
        resp.body = self.format_body(dict(tenant=tenant), from_dict=True)
        resp.status = HTTP_200

    @enforce(SERVICE_NAME, 'default')
    @validate(load_schema('tenant'))
    def on_post(self, req, resp, parsed):
        """
        Method to create new tenant. This endpoint is accessible to Super Admin only.
        The name of each tenant must be unique.
        :return:
                201 Created - When the tenant is successfully created
        """
        data = parsed.get('tenant')

        # Build KS Request
        enabled = True  # By default a domain is enabled
        ks_domain = dict(name=data.get('name'),
                         enabled=enabled,
                         description=data.get('description'))

        # Process request
        r = request_post_patch(TenantAPI.KS_ENDPOINT,
                               method='POST',
                               headers={
                                   'Content-Type': 'application/json',
                                   'X-Auth-Token': req.headers['X-AUTH-TOKEN']
                               },
                               json=dict(domain=ks_domain),
                               service_name=TenantAPI.SERVICE_NAME)

        tenant = TenantAPI.convert_domain_tenant(req, r=r)
        resp.body = self.format_body(dict(tenant=tenant), from_dict=True)
        resp.status = HTTP_201

    @validate(load_schema('tenant_update'))
    @enforce(SERVICE_NAME, 'default')
    def on_patch(self, req, resp, tenant_id, parsed):
        """
        Method to update a Tenant. This endpoint is only accessible to the Super Admin.
        It's not required the full object only the updated fields.
        :param tenant_id: The tenant id to edit
        :return:
                200 OK - When the tenant is edited successfully
        """
        # Configure correct endpoint
        endpoint = TenantAPI.KS_ENDPOINT + '/' + tenant_id

        data = parsed.get('tenant')

        r = request_post_patch(endpoint,
                               method='PATCH',
                               headers={
                                   'Content-Type': 'application/json',
                                   'X-Auth-Token': req.headers['X-AUTH-TOKEN']
                               },
                               json=dict(domain=data),
                               service_name=TenantAPI.SERVICE_NAME)

        tenant = TenantAPI.convert_domain_tenant(req, r=r)
        resp.body = self.format_body(dict(tenant=tenant), from_dict=True)
        resp.status = HTTP_200

    @before(validate_id)
    @enforce(SERVICE_NAME, 'default')
    def on_delete(self, req, resp, tenant_id):
        """
        Method to delete a Tenant. This endpoint is only accessible to the Super Admin.
        Before deleting the tenant the method ensures the tenant is disabled.
        :param tenant_id: The tenant id to delete
        :return:
                204 No Content - When the tenant is successfully deleted
        """
        # Configure correct endpoint
        endpoint = TenantAPI.KS_ENDPOINT + '/' + tenant_id

        # Ensure the tenant is disabled
        ks_domain = dict(enabled=False)
        request_post_patch(endpoint,
                           'PATCH',
                           headers={
                               'Content-Type': 'application/json',
                               'X-Auth-Token': req.headers['X-AUTH-TOKEN']
                           },
                           json=dict(domain=ks_domain),
                           service_name=TenantAPI.SERVICE_NAME)
        request(endpoint,
                method='DELETE',
                headers={
                    'Content-Type': 'application/json',
                    'X-Auth-Token': req.headers['X-AUTH-TOKEN']
                },
                service_name=TenantAPI.SERVICE_NAME)
        resp.status = HTTP_204
Beispiel #10
0
 def __request_service__(s_id):
     endpoint = '{}/{}'.format(ConfReader().get('SERVICE_INVENTORY', 'url'),
                               s_id)
     r = request(endpoint, service_name=SERVICE_NAME)
     return Service.build_from_dict(r.json())
Beispiel #11
0
class Tal(DynamicDocument):
    meta = {
        'collection': 'Tal',
        'queryset_class': DefaultQuerySet,
        'db_alias': ConfReader().get('TAL_DATABASE', 'alias')
    }
Beispiel #12
0
class RoleAPI(BaseResource):
    """
    API that allows querying the identity services for role ids and names.
    """

    KS_ENDPOINT = ConfReader().get('keystone', 'url') + '/roles'

    ROUTES = ['roles/', 'roles', 'roles/{role_id}', 'roles/{role_id}/']

    SERVICE_NAME = 'Role'

    @staticmethod
    def convert_ks_role_role(role):
        """
        Converts a keystone role object in a simple role object
        :param role: The role to convert
        :return: Simple role object
        """
        role.pop('links', None)
        role.pop('domain_id', None)
        return role

    def on_options(self, req, resp):
        """
        OPTIONS method for the Role API
        :return:
        204 No Content - Header with the allow and all HTTP methods available
        """
        resp.set_header('Allow', 'GET, OPTIONS')
        resp.status = HTTP_204

    @enforce(SERVICE_NAME, 'list')
    def on_get(self, req, resp, **kwargs):
        """
        List roles. This method processes the HTTP get request for this API.
        If the role_id is provided the specific get role method is called,
        otherwise the get all roles method is retrieved.
        """
        if kwargs:
            self.get_specific_role(req, resp, kwargs.get('role_id'))
        else:
            self.get_all_roles(req, resp)

    def get_all_roles(self, req, resp):
        """
        Method to retrieve all roles from the identity service. This endpoint is only accessible to Super ADMIN users
        or tenant admin users. Only cross domain roles are shown, since there's no intention in creating special roles
        for each tenant.
        :return:
        200 OK - When all roles are retrieved with success
        Role Process Errors
        """
        r = request(RoleAPI.KS_ENDPOINT,
                    headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
                    service_name=RoleAPI.SERVICE_NAME)

        data = json.loads(r.text)
        data = data['roles']
        # Filter cross domain roles only
        data = list(filter(lambda role: not role.get('domain_id'), data))
        # Convert objects
        data = list(map(lambda role: RoleAPI.convert_ks_role_role(role), data))
        resp.body = self.format_body(dict(roles=data), from_dict=True)
        resp.status = HTTP_200

    def get_specific_role(self, req, resp, role_id):
        """
        Method to retrieve a single role based on its id
        :param role_id: The role id to search for.
        :return:
        200 OK - When all roles are retrieved with success
        404 Not Found - When the provided id don't exist on the identity service
        Role Process Errors
        """
        endpoint = RoleAPI.KS_ENDPOINT + '/' + role_id
        r = request(endpoint,
                    headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
                    service_name=RoleAPI.SERVICE_NAME)

        data = json.loads(r.text)
        role = data.get('role')
        role = RoleAPI.convert_ks_role_role(role)

        resp.body = self.format_body(dict(role=role), from_dict=True)
        resp.status = HTTP_200

    @validate(load_schema('role_create'))
    @enforce(SERVICE_NAME, "default")
    def on_post(self, req, resp, parsed):
        """
        Creates a Role object in a global context, i.e., accessible to all tenants
        :return:
                201 CREATED: Role created with success
        """
        data = parsed.get('role')
        request_post_patch(
            RoleAPI.KS_ENDPOINT,
            method='POST',
            headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']},
            json=dict(role=data))

        resp.status = HTTP_201

    @enforce(SERVICE_NAME, "default")
    def on_delete(self, req, resp, role_id):
        """
        Deletes a given role
        :param role_id: The role id to be deleted
        :return:
            204 NO CONTENT: Role deleted with success
        """

        endpoint = RoleAPI.KS_ENDPOINT + '/' + role_id

        request(endpoint,
                method='DELETE',
                headers={'X-Auth-Token': req.headers['X-AUTH-TOKEN']})

        resp.status = HTTP_204
Beispiel #13
0
 def __get_auth_obj__():
     return json.loads(ConfReader().get('MONASCA_KEYSTONE',
                                        'auth_obj',
                                        raw=True))
Beispiel #14
0
class ABSDao(object):
    """
    Abstract object to access DB models. This class only handles tables and do not map DB models.
    It implements methods that can be used to create messages coming from the database.
    """

    logger = logging.getLogger(__name__)
    DATABASE_NAME = ConfReader().get_section_dict(
        'TOPOLOGY_DATABASE')  # The DB name equals across all tables.

    @staticmethod
    def __clean_dict__(obj):
        """
        Remove keys from dict where the value is None
        :param obj: Dict to clean
        :return: Dict without None values
        """
        return {k: v for k, v in obj.items() if v is not None}

    @classmethod
    def __create_message__(cls, row):
        """
        Creates a message like the real time, with the same structure.
        It also creates the message's inner object.
        :param row: The DB row to transform in real time message.
        :return: Real time message in dict format
        """
        message = dict()
        message['eventtype'] = cls.EVENT_TYPE
        message['type'] = row.pop('state', None)
        inner_obj = dict()
        for key, value in cls.DB_MAP.items():
            inner_obj[key] = row.pop(value)

        message[cls.INNER_OBJ] = cls.__clean_dict__(inner_obj)
        message = cls.__clean_dict__(message)
        return message

    def __init__(self, session):
        """
        Creates an instance of ABSDao
        :param session: The DB connection to use in the queries.
        """
        self.session = session
        self.messages = list()
        self.rows = list()

    def snapshot(self):
        """
        Current topology by the time of the request.
        :return: dict with queried type messages
        """
        # Query the database
        rows = self.query_all()
        self.rows = list()
        for row in rows:
            self.rows.append(dict(zip(type(self).TABLE.columns.keys(), row)))
        # Create the messages
        return [type(self).__create_message__(row) for row in self.rows]

    @handle_topology_exception
    def query_all(self):
        """
        Query all rows from a table.
        :return: Query result as dict object
        """
        return self.session.query(type(self).TABLE).all()

    @handle_topology_exception
    def query_by_filer(self, column_name, value):
        """
        Query a table by a specific filter. This method only filters by a single value in a single column.
        :param column_name: The name of the column to search for
        :param value: The value to search for
        :return: All query result as dict object
        """
        column = getattr(type(self).TABLE.c, column_name)
        return self.session.query(
            type(self).TABLE).filter(column == value).all()
Beispiel #15
0
 def __get_single_app__(self, req, resp, package_id):
     endpoint = "{}/{}".format(ConfReader().get('APP_CATALOGUE', 'url'),
                               package_id)
     r = request(endpoint)
     resp.body = self.format_body(dict(app=json.loads(r.text)),
                                  from_dict=True)