summaryrefslogtreecommitdiffstats
path: root/build/rpm_specs/opnfv-apex.spec
blob: acc8a53e3ad60966d342fef799beac68a8e53282 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Name:		opnfv-apex
Version:	3.0
Release:	%{release}
Summary:	Overcloud Disk images for OPNFV Apex OpenDaylight deployment

Group:		System Environment
License:	Apache 2.0
URL:		https://gerrit.opnfv.org/gerrit/apex.git
Source0:	opnfv-apex.tar.gz

Provides:       opnfv-apex-sdn
BuildArch:	noarch
Requires:	opnfv-apex-common opnfv-apex-undercloud

%description
Overcloud Disk images for OPNFV Apex OpenDaylight deployment
https://wiki.opnfv.org/apex

%prep
%setup -q

%install
mkdir -p %{buildroot}%{_var}/opt/opnfv/images/
install build/images/overcloud-full-opendaylight.qcow2 %{buildroot}%{_var}/opt/opnfv/images/

%files
%defattr(644, root, root, -)
%{_var}/opt/opnfv/images/overcloud-full-opendaylight.qcow2

%changelog
* Mon Apr 04 2016 Dan Radez <dradez@redhat.com> - 3.0-0
- Version update for Colorado
* Wed Jan 20 2016 Dan Radez <dradez@redhat.com> - 2.1-4
- cleaning out libvirt config files
- replacing instack-virt-setup with direct tripleo calls
* Tue Jan 19 2016 Dan Radez <dradez@redhat.com> - 2.1-3
- Remove conflicts with other SDN controllers, they can co-exist now
- update overcloud image name to specify opendaylight
* Thu Jan 14 2016 Dan Radez <dradez@redhat.com> - 2.1-2
- Package Split
* Wed Jan 13 2016 Dan Radez <dradez@redhat.com> - 2.1-1
- Incrementing Minor for Bramaputra RC release
* Sun Dec 20 2015 Tim Rozet <trozet@redhat.com> - 2.0-8
- Modifies networks to include OPNFV private/storage networks
* Tue Dec 15 2015 Dan Radez <dradez@redhat.com> - 2.0-7
- Added deploy settings for flat network config
- cleaned up files that don't need to be in the rpm
* Wed Dec 09 2015 Dan Radez <dradez@redhat.com> - 2.0-6
- Updating the OpenDaylight Patch
* Sat Dec 05 2015 Dan Radez <dradez@redhat.com> - 2.0-5
- Removing glance images
* Fri Nov 20 2015 Dan Radez <dradez@redhat.com> - 2.0-4
- Adding documentation
* Thu Nov 12 2015 Dan Radez <dradez@redhat.com> - 2.0-3
- OpenDaylight and Network Isolation support
* Wed Oct 21 2015 Dan Radez <dradez@redhat.com> - 2.0-2
- Initial deployment success using RPM packaging
* Fri Sep 25 2015 Dan Radez <dradez@redhat.com> - 2.0-1
- Migrated to RDO Manager
* Fri Apr 24 2015 Dan Radez <dradez@redhat.com> - 0.1-1
- Initial Packaging
/ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
###############################################################################
# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems)   #
# and others                                                                  #
#                                                                             #
# All rights reserved. This program and the accompanying materials            #
# are made available under the terms of the Apache License, Version 2.0       #
# which accompanies this distribution, and is available at                    #
# http://www.apache.org/licenses/LICENSE-2.0                                  #
###############################################################################
import json

import requests

from discover.configuration import Configuration
from discover.fetcher import Fetcher


def aci_config_required(default=None):
    def decorator(func):
        def wrapper(self, *args, **kwargs):
            if not self.aci_enabled:
                return default
            return func(self, *args, **kwargs)
        return wrapper
    return decorator


class AciAccess(Fetcher):

    RESPONSE_FORMAT = "json"
    cookie_token = None

    def __init__(self):
        super().__init__()
        self.configuration = Configuration()
        self.aci_enabled = self.configuration.get_env_config() \
            .get('aci_enabled', False)
        self.aci_configuration = None
        self.host = None
        if self.aci_enabled:
            self.aci_configuration = self.configuration.get("ACI")
            self.host = self.aci_configuration["host"]

    def get_base_url(self):
        return "https://{}/api".format(self.host)

    # Unwrap ACI response payload
    # and return an array of desired fields' values.
    #
    # Parameters
    # ----------
    #
    # payload: dict
    #       Full json response payload returned by ACI
    # *field_names: Tuple[str]
    #       Enumeration of fields that are used to traverse ACI "imdata" array
    #       (order is important)
    #
    # Returns
    # ----------
    # list
    #       List of unwrapped dictionaries (or primitives)
    #
    # Example
    # ----------
    # Given payload:
    #
    #   {
    #       "totalCount": "2",
    #       "imdata": [
    #           {
    #               "aaa": {
    #                   "bbb": {
    #                       "ccc": "value1"
    #                   }
    #               }
    #           },
    #           {
    #               "aaa": {
    #                   "bbb": {
    #                       "ccc": "value2"
    #                   }
    #               }
    #           }
    #       ]
    #   }
    #
    #   Executing get_objects_by_field_names(payload, "aaa", "bbb")
    #   will yield the following result:
    #
    #   >>> [{"ccc": "value1"}, {"ccc": "value2"}]
    #
    #   Executing get_objects_by_field_names(payload, "aaa", "bbb", "ccc")
    #   will yield the following result:
    #
    #   >>> ["value1", "value2"]
    #
    @staticmethod
    def get_objects_by_field_names(payload, *field_names):
        results = payload.get("imdata", [])
        if not results:
            return []

        for field in field_names:
            results = [entry[field] for entry in results]
        return results

    # Set auth tokens in request headers and cookies
    @staticmethod
    def _insert_token_into_request(cookies):
        return dict(cookies, **AciAccess.cookie_token) \
            if cookies \
            else AciAccess.cookie_token

    @staticmethod
    def _set_token(response):
        tokens = AciAccess.get_objects_by_field_names(response.json(), "aaaLogin", "attributes", "token")
        token = tokens[0]

        AciAccess.cookie_token = {"APIC-Cookie": token}

    @aci_config_required()
    def login(self):
        url = "/".join((self.get_base_url(), "aaaLogin.json"))
        payload = {
            "aaaUser": {
                "attributes": {
                    "name": self.aci_configuration["user"],
                    "pwd": self.aci_configuration["pwd"]
                }
            }
        }

        response = requests.post(url, json=payload, verify=False)
        response.raise_for_status()

        AciAccess._set_token(response)

    # Refresh token or login if token has expired
    @aci_config_required()
    def refresh_token(self):
        # First time login
        if not AciAccess.cookie_token:
            self.login()
            return

        url = "/".join((self.get_base_url(), "aaaRefresh.json"))

        response = requests.get(url, verify=False)

        # Login again if the token has expired
        if response.status_code == requests.codes.forbidden:
            self.login()
            return
        # Propagate any other error
        elif response.status_code != requests.codes.ok:
            response.raise_for_status()

        AciAccess._set_token(response)

    @aci_config_required(default={})
    def send_get(self, url, params, headers, cookies):
        self.refresh_token()

        cookies = self._insert_token_into_request(cookies)

        response = requests.get(url, params=params, headers=headers,
                                cookies=cookies, verify=False)
        # Let client handle HTTP errors
        response.raise_for_status()

        return response.json()

    # Search ACI for Managed Objects (MOs) of a specific class
    @aci_config_required(default=[])
    def fetch_objects_by_class(self,
                               class_name: str,
                               params: dict = None,
                               headers: dict = None,
                               cookies: dict = None,
                               response_format: str = RESPONSE_FORMAT):
        url = "/".join((self.get_base_url(),
                        "class", "{cn}.{f}".format(cn=class_name, f=response_format)))

        response_json = self.send_get(url, params, headers, cookies)
        return self.get_objects_by_field_names(response_json, class_name)

    # Fetch data for a specific Managed Object (MO)
    @aci_config_required(default=[])
    def fetch_mo_data(self,
                      dn: str,
                      params: dict = None,
                      headers: dict = None,
                      cookies: dict = None,
                      response_format: str = RESPONSE_FORMAT):
        url = "/".join((self.get_base_url(), "mo", "topology",
                        "{dn}.{f}".format(dn=dn, f=response_format)))

        response_json = self.send_get(url, params, headers, cookies)
        return response_json