Esempio n. 1
0
    def all(self, api_version=None):
        """Queries the 'ListView' of a given endpoint.

        Returns all objects from an endpoint.

        :arg str,optional api_version: Override default or globally-set Nautobot REST API
            version for this single request.

        :Returns: List of :py:class:`.Record` objects.

        :Examples:

        >>> nb.dcim.devices.all()
        [test1-a3-oobsw2, test1-a3-oobsw3, test1-a3-oobsw4]
        >>>
        """

        api_version = api_version or self.api.api_version
        req = Request(
            base="{}/".format(self.url),
            token=self.token,
            http_session=self.api.http_session,
            threading=self.api.threading,
            api_version=api_version,
        )

        return response_loader(req.get(), self.return_obj, self)
Esempio n. 2
0
 def test_get_count(self):
     test_obj = Request(
         http_session=Mock(),
         base="http://localhost:8001/api/dcim/devices",
         filters={"q": "abcd"},
     )
     test_obj.http_session.get.return_value.json.return_value = {
         "count": 42,
         "next":
         "http://localhost:8001/api/dcim/devices?limit=1&offset=1&q=abcd",
         "previous": False,
         "results": [],
     }
     call(
         "http://localhost:8001/api/dcim/devices/",
         params={
             "q": "abcd",
             "limit": 1
         },
         headers={"accept": "application/json;"},
     )
     test_obj.http_session.get.ok = True
     test = test_obj.get_count()
     self.assertEqual(test, 42)
     test_obj.http_session.get.assert_called_with(
         "http://localhost:8001/api/dcim/devices/",
         params={
             "q": "abcd",
             "limit": 1
         },
         headers={"accept": "application/json;"},
         json=None,
     )
Esempio n. 3
0
    def save(self):
        """Saves changes to an existing object.

        Takes a diff between the objects current state and its state at init
        and sends them as a dictionary to Request.patch().

        :returns: True if PATCH request was successful.
        :example:

        >>> x = nb.dcim.devices.get(name='test1-a3-tor1b')
        >>> x.serial
        u''
        >>> x.serial = '1234'
        >>> x.save()
        True
        >>>
        """
        if self.id:
            diff = self._diff()
            if diff:
                serialized = self.serialize()
                req = Request(
                    key=self.id,
                    base=self.endpoint.url,
                    token=self.api.token,
                    http_session=self.api.http_session,
                )
                if req.patch({i: serialized[i] for i in diff}):
                    return True

        return False
Esempio n. 4
0
 def test_get_openapi(self):
     test = Request("http://localhost:8080/api", Mock())
     test.get_openapi()
     test.http_session.get.assert_called_with(
         "http://localhost:8080/api/docs/?format=openapi",
         headers={"Content-Type": "application/json;"},
     )
Esempio n. 5
0
    def config(self):
        """Returns config response from app

        :Returns: Raw response from Nautobot's config endpoint.
        :Raises: :py:class:`.RequestError` if called for an invalid endpoint.
        :Example:

        >>> pprint.pprint(nb.users.config())
        {'tables': {'DeviceTable': {'columns': ['name',
                                                'status',
                                                'tenant',
                                                'device_role',
                                                'site',
                                                'primary_ip',
                                                'tags']}}}
        """
        config = Request(
            base="{}/{}/config/".format(
                self.api.base_url,
                self.name,
            ),
            token=self.api.token,
            http_session=self.api.http_session,
        ).get()
        return config
Esempio n. 6
0
    def create(self, *args, api_version=None, **kwargs):
        r"""Creates an object on an endpoint.

        Allows for the creation of new objects on an endpoint. Named
        arguments are converted to json properties, and a single object
        is created. Nautobot's bulk creation capabilities can be used by
        passing a list of dictionaries as the first argument.

        .. note:

            Any positional arguments will supercede named ones.

        :arg list \*args: A list of dictionaries containing the
            properties of the objects to be created.
        :arg str \**kwargs: key/value strings representing
            properties on a json object.
        :arg str,optional api_version: Override default or globally-set
            Nautobot REST API version for this single request.

        :returns: A list or single :py:class:`.Record` object depending
            on whether a bulk creation was requested.

        :Examples:

        Creating an object on the `devices` endpoint you can lookup a
        device_role's name with:

        >>> nautobot.dcim.devices.create(
        ...    name='test',
        ...    device_role=1,
        ... )
        >>>

        Use bulk creation by passing a list of dictionaries:

        >>> nb.dcim.devices.create([
        ...     {
        ...         "name": "test1-core3",
        ...         "device_role": 3,
        ...         "site": 1,
        ...         "device_type": 1,
        ...         "status": 1
        ...     },
        ...     {
        ...         "name": "test1-core4",
        ...         "device_role": 3,
        ...         "site": 1,
        ...         "device_type": 1,
        ...         "status": 1
        ...     }
        ... ])
        """

        api_version = api_version or self.api.api_version

        req = Request(
            base=self.url, token=self.token, http_session=self.api.http_session, api_version=api_version,
        ).post(args[0] if args else kwargs)

        return response_loader(req, self.return_obj, self)
Esempio n. 7
0
    def status(self):
        """Gets the status information from Nautobot.

        Available in Nautobot 2.10.0 or newer.

        :Returns: Dictionary as returned by Nautobot.
        :Raises: :py:class:`.RequestError` if the request is not successful.
        :Example:

        >>> pprint.pprint(nb.status())
        {'django-version': '3.1.3',
         'installed-apps': {'cacheops': '5.0.1',
                            'debug_toolbar': '3.1.1',
                            'django_filters': '2.4.0',
                            'django_prometheus': '2.1.0',
                            'django_rq': '2.4.0',
                            'django_tables2': '2.3.3',
                            'drf_yasg': '1.20.0',
                            'mptt': '0.11.0',
                            'rest_framework': '3.12.2',
                            'taggit': '1.3.0',
                            'timezone_field': '4.0'},
         'nautobot-version': '1.0.0',
         'plugins': {},
         'python-version': '3.7.3',
         'rq-workers-running': 1}
        >>>
        """
        status = Request(base=self.base_url, token=self.token, http_session=self.http_session,).get_status()
        return status
Esempio n. 8
0
    def count(self, *args, **kwargs):
        r"""Returns the count of objects in a query.

        Takes named arguments that match the usable filters on a
        given endpoint. If an argument is passed then it's used as a
        freeform search argument if the endpoint supports it. If no
        arguments are passed the count for all objects on an endpoint
        are returned.

        :arg str,optional \*args: Freeform search string that's
            accepted on given endpoint.
        :arg str,optional \**kwargs: Any search argument the
            endpoint accepts can be added as a keyword arg.

        :Returns: Integer with count of objects returns by query.

        :Examples:

        To return a count of objects matching a named argument filter.

        >>> nb.dcim.devices.count(site='tst1')
        5827
        >>>

        To return a count of objects on an entire endpoint.

        >>> nb.dcim.devices.count()
        87382
        >>>
        """

        if args:
            kwargs.update({"q": args[0]})

        if any(i in RESERVED_KWARGS for i in kwargs):
            raise ValueError(
                "A reserved {} kwarg was passed. Please remove it "
                "try again.".format(RESERVED_KWARGS))

        ret = Request(
            filters=kwargs,
            base=self.url,
            token=self.token,
            http_session=self.api.http_session,
        )

        return ret.get_count()
Esempio n. 9
0
    def delete(self):
        """Deletes an existing object.

        :returns: True if DELETE operation was successful.
        :example:

        >>> x = nb.dcim.devices.get(name='test1-a3-tor1b')
        >>> x.delete()
        True
        >>>
        """
        req = Request(
            key=self.id,
            base=self.endpoint.url,
            token=self.api.token,
            http_session=self.api.http_session,
        )
        return True if req.delete() else False
Esempio n. 10
0
    def full_details(self):
        """Queries the hyperlinked endpoint if 'url' is defined.

        This method will populate the attributes from the detail
        endpoint when it's called. Sets the class-level `has_details`
        attribute when it's called to prevent being called more
        than once.

        :returns: True
        """
        if self.url:
            req = Request(
                base=self.url,
                token=self.api.token,
                http_session=self.api.http_session,
            )
            self._parse_values(req.get())
            self.has_details = True
            return True
        return False
Esempio n. 11
0
    def all(self):
        """Queries the 'ListView' of a given endpoint.

        Returns all objects from an endpoint.

        :Returns: List of :py:class:`.Record` objects.

        :Examples:

        >>> nb.dcim.devices.all()
        [test1-a3-oobsw2, test1-a3-oobsw3, test1-a3-oobsw4]
        >>>
        """
        req = Request(
            base="{}/".format(self.url),
            token=self.token,
            http_session=self.api.http_session,
            threading=self.api.threading,
        )

        return response_loader(req.get(), self.return_obj, self)
Esempio n. 12
0
    def trace(self):
        req = Request(
            key=str(self.id) + "/trace",
            base=self.endpoint.url,
            token=self.api.token,
            http_session=self.api.http_session,
        )
        uri_to_obj_class_map = {
            "dcim/cables": Cables,
            "dcim/front-ports": FrontPorts,
            "dcim/interfaces": Interfaces,
            "dcim/rear-ports": RearPorts,
        }
        ret = []
        for (termination_a_data, cable_data, termination_b_data) in req.get():
            this_hop_ret = []
            for hop_item_data in (termination_a_data, cable_data,
                                  termination_b_data):
                # if not fully terminated then some items will be None
                if not hop_item_data:
                    this_hop_ret.append(hop_item_data)
                    continue

                # TODO: Move this to a more general function.
                app_endpoint = "/".join(
                    urlparse(hop_item_data["url"]
                             [len(self.api.base_url):]).path.split("/")[1:3])

                return_obj_class = uri_to_obj_class_map.get(
                    app_endpoint,
                    Record,
                )

                this_hop_ret.append(
                    return_obj_class(hop_item_data, self.endpoint.api,
                                     self.endpoint))

            ret.append(this_hop_ret)

        return ret
Esempio n. 13
0
    def choices(self, api_version=None):
        """Returns all choices from the endpoint.

        The returned dict is also saved in the endpoint object (in
        ``_choices`` attribute) so that later calls will return the same data
        without recurring requests to Nautobot. When using ``.choices()`` in
        long-running applications, consider restarting them whenever Nautobot is
        upgraded, to prevent using stale choices data.

        :arg str,optional api_version: Override default or globally-set
            Nautobot REST API version for this single request.

        :Returns: Dict containing the available choices.

        :Example (from Nautobot 2.8.x):

        >>> from pprint import pprint
        >>> pprint(nb.ipam.ip_addresses.choices())
        {'role': [{'display_name': 'Loopback', 'value': 'loopback'},
                  {'display_name': 'Secondary', 'value': 'secondary'},
                  {'display_name': 'Anycast', 'value': 'anycast'},
                  {'display_name': 'VIP', 'value': 'vip'},
                  {'display_name': 'VRRP', 'value': 'vrrp'},
                  {'display_name': 'HSRP', 'value': 'hsrp'},
                  {'display_name': 'GLBP', 'value': 'glbp'},
                  {'display_name': 'CARP', 'value': 'carp'}],
         'status': [{'display_name': 'Active', 'value': 'active'},
                    {'display_name': 'Reserved', 'value': 'reserved'},
                    {'display_name': 'Deprecated', 'value': 'deprecated'},
                    {'display_name': 'DHCP', 'value': 'dhcp'}]}
        >>>
        """
        if self._choices:
            return self._choices

        api_version = api_version or self.api.api_version

        req = Request(
            base=self.url, token=self.api.token, http_session=self.api.http_session, api_version=api_version,
        ).options()
        try:
            post_data = req["actions"]["POST"]
        except KeyError:
            raise ValueError("Unexpected format in the OPTIONS response at {}".format(self.url))
        self._choices = {}
        for prop in post_data:
            if "choices" in post_data[prop]:
                self._choices[prop] = post_data[prop]["choices"]

        return self._choices
Esempio n. 14
0
    def openapi(self):
        """Returns the OpenAPI spec.

        Quick helper function to pull down the entire OpenAPI spec.

        :Returns: dict
        :Example:

        >>> import pynautobot
        >>> nb = pynautobot.api(
        ...     'http://localhost:8000',
        ...     token='d6f4e314a5b5fefd164995169f28ae32d987704f'
        ... )
        >>> nb.openapi()
        {...}
        >>>
        """
        return Request(base=self.base_url, http_session=self.http_session,).get_openapi()
Esempio n. 15
0
    def list(self, **kwargs):
        r"""The view operation for a detail endpoint

        Returns the response from Nautobot for a detail endpoint.

        Args:
            **kwargs: key/value pairs that get converted into url parameters when passed to the endpoint.
                E.g. ``.list(method='get_facts')`` would be converted to ``.../?method=get_facts``.

        :returns: A dictionary or list of dictionaries retrieved from
            Nautobot.
        """
        req = Request(**self.request_kwargs).get(add_params=kwargs)

        if self.custom_return:
            return response_loader(req, self.custom_return,
                                   self.parent_obj.endpoint)
        return req
Esempio n. 16
0
    def create(self, data=None):
        """The write operation for a detail endpoint.

        Creates objects on a detail endpoint in Nautobot.

        :arg dict/list,optional data: A dictionary containing the
            key/value pair of the items you're creating on the parent
            object. Defaults to empty dict which will create a single
            item with default values.

        :returns: A dictionary or list of dictionaries its created in
            Nautobot.
        """
        data = data or {}
        req = Request(**self.request_kwargs).post(data)
        if self.custom_return:
            return response_loader(req, self.custom_return,
                                   self.parent_obj.endpoint)
        return req
Esempio n. 17
0
    def version(self):
        """Gets the API version of Nautobot.

        Can be used to check the Nautobot API version if there are
        version-dependent features or syntaxes in the API.

        :Returns: Version number as a string.
        :Example:

        >>> import pynautobot
        >>> nb = pynautobot.api(
        ...     'http://localhost:8000',
        ...     token='d6f4e314a5b5fefd164995169f28ae32d987704f'
        ... )
        >>> nb.version
        '1.0'
        >>>
        """
        version = Request(base=self.base_url, http_session=self.http_session,).get_version()
        return version
Esempio n. 18
0
    def custom_choices(self):
        """Returns custom-fields response from app

        :Returns: Raw response from Nautobot's custom-fields endpoint.
        :Raises: :py:class:`.RequestError` if called for an invalid endpoint.
        :Example:

        >>> nb.extras.custom_choices()
        {'Testfield1': {'Testvalue2': 2, 'Testvalue1': 1},
         'Testfield2': {'Othervalue2': 4, 'Othervalue1': 3}}
        """
        custom_fields = Request(
            base="{}/{}/custom-fields/".format(
                self.api.base_url,
                self.name,
            ),
            token=self.api.token,
            http_session=self.api.http_session,
        ).get()
        return custom_fields
Esempio n. 19
0
    def list(self, api_version=None, **kwargs):
        r"""The view operation for a detail endpoint

        Returns the response from Nautobot for a detail endpoint.

        Args:
            :arg str,optional api_version: Override default or globally set Nautobot REST API version for this single request.
            **kwargs: key/value pairs that get converted into url parameters when passed to the endpoint.
                E.g. ``.list(method='get_facts')`` would be converted to ``.../?method=get_facts``.

        :returns: A dictionary or list of dictionaries retrieved from
            Nautobot.
        """
        api_version = api_version or self.parent_obj.api.api_version

        req = Request(api_version=api_version, **self.request_kwargs).get(add_params=kwargs)

        if self.custom_return:
            return response_loader(req, self.custom_return, self.parent_obj.endpoint)
        return req
Esempio n. 20
0
    def installed_plugins(self):
        """Returns raw response with installed plugins

        :returns: Raw response Nautobot's installed plugins.
        :Example:

        >>> nb.plugins.installed_plugins()
        [{
            'name': 'test_plugin',
            'package': 'test_plugin',
            'author': 'Dmitry',
            'description': 'Nautobot test plugin',
            'verison': '0.10'
        }]
        """
        installed_plugins = Request(
            base="{}/plugins/installed-plugins".format(self.api.base_url, ),
            token=self.api.token,
            http_session=self.api.http_session,
        ).get()
        return installed_plugins
Esempio n. 21
0
    def choices(self):
        """Returns _choices response from App

        .. note::

            This method is deprecated and only works with Nautobot version 2.7.x
            or older. The ``choices()`` method in :py:class:`.Endpoint` is
            compatible with all Nautobot versions.

        :Returns: Raw response from Nautobot's _choices endpoint.
        """
        if self._choices:
            return self._choices

        self._choices = Request(
            base="{}/{}/_choices/".format(self.api.base_url, self.name),
            token=self.api.token,
            http_session=self.api.http_session,
        ).get()

        return self._choices
Esempio n. 22
0
    def create(self, data=None, api_version=None):
        """The write operation for a detail endpoint.

        Creates objects on a detail endpoint in Nautobot.

        :arg dict/list,optional data: A dictionary containing the
            key/value pair of the items you're creating on the parent
            object. Defaults to empty dict which will create a single
            item with default values.
        :args str,optional api_version: Override default or globally set
            Nautobot REST API version for this single request.

        :returns: A dictionary or list of dictionaries its created in
            Nautobot.
        """
        data = data or {}
        api_version = api_version or self.parent_obj.api.api_version

        req = Request(api_version=api_version, **self.request_kwargs).post(data)
        if self.custom_return:
            return response_loader(req, self.custom_return, self.parent_obj.endpoint)
        return req
Esempio n. 23
0
    def filter(self, *args, **kwargs):
        r"""Queries the 'ListView' of a given endpoint.

        Takes named arguments that match the usable filters on a
        given endpoint. If an argument is passed then it's used as a
        freeform search argument if the endpoint supports it.

        :arg str,optional \*args: Freeform search string that's
            accepted on given endpoint.
        :arg str,optional \**kwargs: Any search argument the
            endpoint accepts can be added as a keyword arg.

        :Returns: A list of :py:class:`.Record` objects.

        :Examples:

        To return a list of objects matching a named argument filter.

        >>> nb.dcim.devices.filter(role='leaf-switch')
        [test1-a3-tor1b, test1-a3-tor1c, test1-a3-tor1d, test1-a3-tor2a]
        >>>

        Using a freeform query along with a named argument.

        >>> nb.dcim.devices.filter('a3', role='leaf-switch')
        [test1-a3-tor1b, test1-a3-tor1c, test1-a3-tor1d, test1-a3-tor2a]
        >>>

        Chaining multiple named arguments.

        >>> nb.dcim.devices.filter(role='leaf-switch', status=True)
        [test1-leaf2]
        >>>

        Passing a list as a named argument adds multiple filters of the
        same value.

        >>> nb.dcim.devices.filter(role=['leaf-switch', 'spine-switch'])
        [test1-a3-spine1, test1-a3-spine2, test1-a3-leaf1]
        >>>
        """

        if args:
            kwargs.update({"q": args[0]})

        if not kwargs:
            raise ValueError(
                "filter must be passed kwargs. Perhaps use all() instead.")
        if any(i in RESERVED_KWARGS for i in kwargs):
            raise ValueError(
                "A reserved {} kwarg was passed. Please remove it "
                "try again.".format(RESERVED_KWARGS))

        req = Request(
            filters=kwargs,
            base=self.url,
            token=self.token,
            http_session=self.api.http_session,
            threading=self.api.threading,
        )

        return response_loader(req.get(), self.return_obj, self)
Esempio n. 24
0
    def get(self, *args, **kwargs):
        r"""Queries the DetailsView of a given endpoint.

        :arg int,optional key: id for the item to be
            retrieved.

        :arg str,optional \**kwargs: Accepts the same keyword args as
            filter(). Any search argument the endpoint accepts can
            be added as a keyword arg.

        :returns: A single :py:class:`.Record` object or None

        :raises ValueError: if kwarg search return more than one value.

        :Examples:

        Referencing with a kwarg that only returns one value.

        >>> nb.dcim.devices.get(name='test1-a3-tor1b')
        test1-a3-tor1b
        >>>

        Referencing with an id.

        >>> nb.dcim.devices.get(1)
        test1-edge1
        >>>
        """

        try:
            key = args[0]
        except IndexError:
            key = None

        if not key:
            filter_lookup = self.filter(**kwargs)
            if filter_lookup:
                if len(filter_lookup) > 1:
                    raise ValueError(
                        "get() returned more than one result. "
                        "Check that the kwarg(s) passed are valid for this "
                        "endpoint or use filter() or all() instead.")
                else:
                    return filter_lookup[0]
            return None

        req = Request(
            key=key,
            base=self.url,
            token=self.token,
            http_session=self.api.http_session,
        )

        try:
            resp = req.get()
        except RequestError as e:
            if e.req.status_code == 404:
                return None
            else:
                raise e

        return response_loader(resp, self.return_obj, self)