示例#1
0
    def test_devices_configs(self):
        devices_list = self.space.device_management.devices.get(
                            filter_={'managedStatus': 'In Sync'})
        assert len(devices_list) > 1, "Not enough devices on Space"

        for d in devices_list:
            configs = d.configurations.get()
            assert len(configs) == 2
            for c in configs:
                xml_config = c.get()
                xml_config = xmlutil.xml2obj(xml_config.configuration.text)
                assert xml_config.version[:7] == d.OSVersion[:7]
示例#2
0
    def get(self, attr=None, accept=None):
        """
        This is an overloaded method that does two things: If the ``attr``
        parameter is passed, it returns the corresponding XML attribute from
        the top level XML data element contained by this resource. If the
        ``attr`` parameter is not passed, it performs an HTTP GET for
        this resource and get its current state.

        :param str attr: The name of the XML attribute in the top-level
            element of the XML state of the resource. Defaults to ``None``.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the GET request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :returns:
            - Value of the named XML attribute. OR
            - The current state of this resource fetched from Space and
              represented as a Python object. You can access the fields of the
              resource's state directly as attributes of this object.

        :raises: ``jnpr.space.rest.RestException`` if the GET method results in an
            error response. The exception's ``response`` attribute will have the
            full response from Space.

        """
        if attr is not None:
            return self._get_xml_attr(attr)

        if accept is not None:
            mtype = accept
        else:
            mtype = self._meta_object.get_media_type(None)

        if mtype is not None:
            if not self._meta_object.retain_charset_in_accept:
                end = mtype.find(';charset=')
                if end > 0:
                    mtype = mtype[0:end]
            headers = {'accept' : mtype}
        else:
            headers = {}

        response = self._rest_end_point.get(self.get_href(), headers)
        if response.status_code != 200:
            raise rest.RestException("GET failed on %s" % self.get_href(),
                                     response)

        #r = response.text
        resp_txt = xmlutil.get_text_from_response(response)
        return xmlutil.xml2obj(resp_txt)
示例#3
0
    def get(self, attr=None, accept=None):
        """
        This is an overloaded method that does two things: If the ``attr``
        parameter is passed, it returns the corresponding XML attribute from
        the top level XML data element contained by this resource. If the
        ``attr`` parameter is not passed, it performs an HTTP GET for
        this resource and get its current state.

        :param str attr: The name of the XML attribute in the top-level
            element of the XML state of the resource. Defaults to ``None``.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the GET request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :returns:
            - Value of the named XML attribute. OR
            - The current state of this resource fetched from Space and
              represented as a Python object. You can access the fields of the
              resource's state directly as attributes of this object.

        :raises: ``jnpr.space.rest.RestException`` if the GET method results in an
            error response. The exception's ``response`` attribute will have the
            full response from Space.

        """
        if attr is not None:
            return self._get_xml_attr(attr)

        if accept is not None:
            mtype = accept
        else:
            mtype = self._meta_object.get_media_type(None)

        if mtype is not None:
            if not self._meta_object.retain_charset_in_accept:
                end = mtype.find(';charset=')
                if end > 0:
                    mtype = mtype[0:end]
            headers = {'accept': mtype}
        else:
            headers = {}

        response = self._rest_end_point.get(self.get_href(), headers)
        if response.status_code != 200:
            raise rest.RestException("GET failed on %s" % self.get_href(),
                                     response)

        #r = response.text
        resp_txt = xmlutil.get_text_from_response(response)
        return xmlutil.xml2obj(resp_txt)
示例#4
0
 def _create_resource(self, xml_data):
     """
     Helper method to create a resource under this collection. This is used
     to populate entries in the list returned by the get() method of this
     collection.
     """
     if self._meta_object.resource_type:
         from jnpr.space import resource
         return resource.Resource(type_name=self._meta_object.resource_type,
                                  rest_end_point=self._rest_end_point,
                                  xml_data=xml_data,
                                  parent=self)
     else:
         xml_str = etree.tostring(xml_data, encoding='unicode')
         return xmlutil.xml2obj(xml_str)
示例#5
0
 def get_final_progress_update(self, pu_message):
     """
     Gets the final progress-update message for a job, based on the href
     inside the ``pu_message`` argument supplied. The ``pu_message`` arg
     is the last progress-update message obtained from a hornet-q and it
     does not contain the full result of the job. The progress-update
     message fetched and returned by this method will contain the full
     result inside the ``data`` field.
     """
     job_pu_href = '/'.join([pu_message.job.get('href'), 'progress-update'])
     response = self._rest_end_point.get(job_pu_href)
     if response.status_code != 200:
         raise Exception("Failed in GET on %s" % job_pu_href)
     response_txt = xmlutil.get_text_from_response(response)
     return xmlutil.xml2obj(response_txt)
示例#6
0
    def test_devices_raw_config(self):
        devices_list = self.space.device_management.devices.get(
                            filter_={'managedStatus': 'In Sync'})
        assert len(devices_list) > 1, "Not enough devices on Space"

        for d in devices_list:
            raw = d.configurations.raw.get()
            assert raw is not None
            raw_config = xmlutil.xml2obj(raw.configuration.text)

            assert raw_config.version[:7] == d.OSVersion[:7]

            if hasattr(raw_config, 'groups'):
                for g in raw_config.groups:
                    print("Found config group %s on device %s" % (g.name, d.name))
示例#7
0
    def test_devices_expanded_config(self):
        devices_list = self.space.device_management.devices.get(
                            filter_={'managedStatus': 'In Sync'})
        assert len(devices_list) > 1, "Not enough devices on Space"

        for d in devices_list:
            exp = d.configurations.expanded.get()
            assert exp
            exp_config = xmlutil.xml2obj(exp.configuration.text)

            import pytest
            with pytest.raises(AttributeError):
                assert exp_config.groups is None

            assert exp_config.version[:7] == d.OSVersion[:7]
示例#8
0
 def _create_resource(self, xml_data):
     """
     Helper method to create a resource under this collection. This is used
     to populate entries in the list returned by the get() method of this
     collection.
     """
     if self._meta_object.resource_type:
         from jnpr.space import resource
         return resource.Resource(type_name=self._meta_object.resource_type,
                                  rest_end_point=self._rest_end_point,
                                  xml_data=xml_data,
                                  parent=self)
     else:
         xml_str = etree.tostring(xml_data, encoding='unicode')
         return xmlutil.xml2obj(xml_str)
示例#9
0
    def __init__(self,
                 type_name,
                 rest_end_point,
                 xml_data=None,
                 attributes=None,
                 parent=None):
        """Initializes a Resource object.

        :param str type_name: Fully qualified type name for the Resource to be
            created. It is of the format ``<service_name>.<resource_type>`` or
            ``<app-name>.<service_name>.<resource_type>``
            Some examples are:

            * ``device_management.device``
            * ``user_management.user``
            * ``servicenow.device_management.device``

        :param rest_end_point: A *Space* object encapsulating the Junos
            Space cluster which contains this resource.
        :type rest_end_point: jnpr.space.rest.Space

        :param lxml.etree.Element xml_data:  The state of the resource as an
            XML object. This defaults to ``None``.

        :param dict attributes:  The state of the resource as a dict where the
            keys are attribute names and values are attribute values.
            This defaults to ``None``.

        :param parent: The parent object of this resource. This defaults to
            ``None``.
        :type parent: jnpr.space.collection.Collection

        """
        self._type_name = type_name
        self._rest_end_point = rest_end_point
        self._xml_data = xml_data
        self._attributes = attributes
        self._parent = parent
        self._collections = {}
        self._methods = {}
        self._init_meta_data(rest_end_point, type_name)
        if xml_data is not None:
            if self._meta_object.xml_name != xml_data.tag:
                exc = Exception('Invalid xml object for this resource!')
                exc.ignore = True
                raise exc
            self._xml_data = xmlutil.xml2obj(
                etree.tostring(xml_data, encoding='unicode'))
示例#10
0
 def get_final_progress_update(self, pu_message):
     """
     Gets the final progress-update message for a job, based on the href
     inside the ``pu_message`` argument supplied. The ``pu_message`` arg
     is the last progress-update message obtained from a hornet-q and it
     does not contain the full result of the job. The progress-update
     message fetched and returned by this method will contain the full
     result inside the ``data`` field.
     """
     job_pu_href = '/'.join([pu_message.job.get('href'),
                             'progress-update'])
     response = self._rest_end_point.get(job_pu_href)
     if response.status_code != 200:
         raise Exception("Failed in GET on %s" % job_pu_href)
     response_txt = xmlutil.get_text_from_response(response)
     response_txt = xmlutil.cleanup(response_txt)
     return xmlutil.xml2obj(response_txt)
示例#11
0
    def __init__(self, type_name, rest_end_point,
                 xml_data=None, attributes=None, parent=None):
        """Initializes a Resource object.

        :param str type_name: Fully qualified type name for the Resource to be
            created. It is of the format ``<service_name>.<resource_type>`` or
            ``<app-name>.<service_name>.<resource_type>``
            Some examples are:

            * ``device_management.device``
            * ``user_management.user``
            * ``servicenow.device_management.device``

        :param rest_end_point: A *Space* object encapsulating the Junos
            Space cluster which contains this resource.
        :type rest_end_point: jnpr.space.rest.Space

        :param lxml.etree.Element xml_data:  The state of the resource as an
            XML object. This defaults to ``None``.

        :param dict attributes:  The state of the resource as a dict where the
            keys are attribute names and values are attribute values.
            This defaults to ``None``.

        :param parent: The parent object of this resource. This defaults to
            ``None``.
        :type parent: jnpr.space.collection.Collection

        """
        self._type_name = type_name
        self._rest_end_point = rest_end_point
        self._xml_data = xml_data
        self._attributes = attributes
        self._parent = parent
        self._collections = {}
        self._methods = {}
        self._init_meta_data(rest_end_point, type_name)
        if xml_data is not None:
            if self._meta_object.xml_name != xml_data.tag:
                exc = Exception('Invalid xml object for this resource!')
                exc.ignore = True
                raise exc
            self._xml_data = xmlutil.xml2obj(etree.tostring(xml_data, encoding='unicode'))
示例#12
0
    def pull_message(self):
        """
        Pull the next message from the hornet-q. It specifies an ``accept-wait``
        header with the value that was given as the ``wait_time`` argument in
        the constructor so that the pull waits for this many seconds on the
        server side waiting for a message.

        :returns:  If a message is pulled, it is parsed into a Python object
            and returned. If no message was pulled, returns ``None``.

        """

        headers = {"accept-wait": self.wait_time}
        response = self._rest_end_point.post(self.next_msg_url, headers, body=None)
        next_msg = response.headers["msg-consume-next"]
        if len(next_msg) > 0:
            self.next_msg_url = self._strip_uri(next_msg)

        if response.status_code == 200:
            xml = xmlutil.get_text_from_response(response)
            return xmlutil.xml2obj(xml)
示例#13
0
    def get(self, accept=None):
        """Performs a GET corresponding to the Method object.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the GET request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :returns: A Python object constructed from the response body that Space
            returned for the GET request.

        :raises: ``jnpr.space.rest.RestException`` if the GET results in an
            error response. The exception's ``response`` attribute will have the
            full response from Space.

        """

        if accept is not None:
            mtype = accept
        else:
            mtype = self._meta_object.get_media_type(None)

        if mtype is not None:
            if not self._meta_object.retain_charset_in_accept:
                end = mtype.find(';charset=')
                if end > 0:
                    mtype = mtype[0:end]
            headers = {'accept' : mtype}
        else:
            headers = {}

        response = self._rest_end_point.get(self.get_href(), headers)
        if response.status_code != 200:
            raise rest.RestException("GET failed on %s " % self.get_href(),
                                     response)

        resp_text = xmlutil.get_text_from_response(response)
        return xmlutil.xml2obj(resp_text)
示例#14
0
    def get(self, accept=None):
        """Performs a GET corresponding to the Method object.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the GET request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :returns: A Python object constructed from the response body that Space
            returned for the GET request.

        :raises: ``jnpr.space.rest.RestException`` if the GET results in an
            error response. The exception's ``response`` attribute will have the
            full response from Space.

        """

        if accept is not None:
            mtype = accept
        else:
            mtype = self._meta_object.get_media_type(None)

        if mtype is not None:
            if not self._meta_object.retain_charset_in_accept:
                end = mtype.find(';charset=')
                if end > 0:
                    mtype = mtype[0:end]
            headers = {'accept': mtype}
        else:
            headers = {}

        response = self._rest_end_point.get(self.get_href(), headers)
        if response.status_code != 200:
            raise rest.RestException("GET failed on %s " % self.get_href(),
                                     response)

        resp_text = xmlutil.get_text_from_response(response)
        return xmlutil.xml2obj(resp_text)
示例#15
0
    def pull_message(self):
        """
        Pull the next message from the hornet-q. It specifies an ``accept-wait``
        header with the value that was given as the ``wait_time`` argument in
        the constructor so that the pull waits for this many seconds on the
        server side waiting for a message.

        :returns:  If a message is pulled, it is parsed into a Python object
            and returned. If no message was pulled, returns ``None``.

        """

        headers = {"accept-wait": self.wait_time}
        response = self._rest_end_point.post(self.next_msg_url,
                                             headers,
                                             body=None)
        next_msg = response.headers["msg-consume-next"]
        if len(next_msg) > 0:
            self.next_msg_url = self._strip_uri(next_msg)

        if response.status_code == 200:
            xml = xmlutil.get_text_from_response(response)
            return xmlutil.xml2obj(xml)
示例#16
0
    def _get_info(self):
        url = '/api/info?uri=' + self.get_href()
        response = self._rest_end_point.get(url)
        if response.status_code != 200:
            from . import rest
            raise rest.RestException("GET failed on %s" % url, response)

        obj = xmlutil.xml2obj(xmlutil.get_text_from_response(response))
        """
        Create a dict such as this:
        {
          methods: {
            DELETE: {}
            GET: {
              Accept: [header1, header2]
            }
            PUT: {
              Media-type Combinations: {
                  1: {
                    Accept: header3
                    Content-Type: header4
                  }
                  2: {
                    Accept: header5
                    Content-Type: header6
                  }
              }
            }
            POST: {
              Media-type Combinations: [
                  {
                    Accept: header3
                    Content-Type: header4
                  }
                  {
                    Accept: header5
                    Content-Type: header6
                  }
              ]
            }
          }
        }
        """
        info = {}
        methods = {}
        info['HTTP Methods'] = methods
        for m in obj['http-methods']['http-method']:
            method_name = m.get('type')
            if method_name in methods:
                method = methods[method_name]
            else:
                method = {}
                methods[method_name] = method

            if method_name in ['GET', 'DELETE']:
                for h in m.headers.header:
                    header_name = h.get('type')
                    if header_name in method:
                        headers = method[header_name]
                    else:
                        headers = []
                        method[header_name] = headers

                    for r in h.representations.representation:
                        if '+xml' in r.text:
                            headers.append(r.text)

            elif method_name in ['PUT', 'POST', 'PATCH']:
                if 'Media-type Combinations' not in method:
                    combs = []
                    method['Media-type Combinations'] = combs
                else:
                    combs = method['Media-type Combinations']

                comb = {}
                combs.append(comb)
                for h in m.headers.header:
                    header_name = h.get('type')
                    header_val = ''
                    for r in h.representations.representation:
                        if '+xml' in r.text:
                            header_val = r.text
                            break

                    comb[header_name] = header_val

        return info
示例#17
0
    def _get_info(self):
        url = '/api/info?uri=' + self.get_href()
        response = self._rest_end_point.get(url)
        if response.status_code != 200:
            from . import rest
            raise rest.RestException("GET failed on %s" % url, response)

        obj = xmlutil.xml2obj(xmlutil.get_text_from_response(response))
        """
        Create a dict such as this:
        {
          methods: {
            DELETE: {}
            GET: {
              Accept: [header1, header2]
            }
            PUT: {
              Media-type Combinations: {
                  1: {
                    Accept: header3
                    Content-Type: header4
                  }
                  2: {
                    Accept: header5
                    Content-Type: header6
                  }
              }
            }
            POST: {
              Media-type Combinations: [
                  {
                    Accept: header3
                    Content-Type: header4
                  }
                  {
                    Accept: header5
                    Content-Type: header6
                  }
              ]
            }
          }
        }
        """
        info = {}
        methods = {}
        info['HTTP Methods'] = methods
        for m in obj['http-methods']['http-method']:
            method_name = m.get('type')
            if method_name in methods:
                method = methods[method_name]
            else:
                method = {}
                methods[method_name] = method

            if method_name in ['GET', 'DELETE']:
                for h in m.headers.header:
                    header_name = h.get('type')
                    if header_name in method:
                        headers = method[header_name]
                    else:
                        headers = []
                        method[header_name] = headers

                    for r in h.representations.representation:
                        if '+xml' in r.text:
                            headers.append(r.text)

            elif method_name in ['PUT', 'POST', 'PATCH']:
                if 'Media-type Combinations' not in method:
                    combs = []
                    method['Media-type Combinations'] = combs
                else:
                    combs = method['Media-type Combinations']

                comb = {}
                combs.append(comb)
                for h in m.headers.header:
                    header_name = h.get('type')
                    header_val = ''
                    for r in h.representations.representation:
                        if '+xml' in r.text:
                            header_val = r.text
                            break

                    comb[header_name] = header_val

        return info
示例#18
0
    def post(self,
             new_obj=None,
             accept=None,
             content_type=None,
             request_body=None,
             xml_name=None,
             task_monitor=None):
        """
        Sends a POST request to the Space server to create a new Resource in
        this collection.

        :param new_obj: The new Resource that needs to be created as a member
            of this collection. This can be omitted in which case the caller
            must supply a request body for the POST request as the
            ``request_body`` argument.
        :type new_obj: A single ``jnpr.space.resource.Resource`` instance
            or a list of them.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str content_type: This can be used to supply a media-type that must
            be used as the Content-Type header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str request_body: This can be used to supply a string that must
            be used as the request body in the request. This defaults to
            ``None`` and in this case the caller must supply the ``new_obj``
            argument from which the request body will be formed.

        :param str xml_name: Can be used to override the name of the top-level
            XML element in the generated request body. This is useful in some
            cases such as creating a quick config template.
            This parameter defaults to ``None``.

        :param task_monitor: A TaskMonitor object that can be used to monitor
            the progress of the POST request, in case of asynchronous
            invocations. You need to check Junos Space API documentation to
            see if the POST invocation on this resource has asynchronous
            semantics and supply the task_monitor parameter only if it is
            asynchronous. Otherwise, this will default to ``None`` and the
            method will behave with synchronous semantics.
        :type task_monitor: jnpr.space.async.TaskMonitor

        :returns: If the new_obj parameter is a list, then the same list is
            returned. Otherwise, this method creates a new Resource object
            based on the state of the newly created resource, as extracted from
            the POST response body. In the case of asynchronous
            invocation, this will represent a Task object and will contain the
            unique id of the Task executing the POST request in Space.

        :raises: ``jnpr.space.rest.RestException`` if the POST method results in
            an error response. The exception's ``response`` attribute will have
            the full response from Space.

        """
        if content_type is not None:
            media_type = content_type
        elif isinstance(new_obj, list):
            if self._meta_object.content_type is not None:
                media_type = self._meta_object.content_type
            else:
                media_type = self._meta_object.get_media_type(None)
        else:
            if new_obj is None:
                raise ValueError(
                    'Must provide content_type when providing request_body')
            media_type = new_obj.get_meta_object().get_media_type(None)

        headers = {'content-type': media_type}
        if accept is not None:
            headers['accept'] = accept

        if request_body is not None:
            body = request_body
            saved_root_tag = None
            if new_obj is not None:
                raise ValueError('Cannot use both request_body and new_obj!')
        else:
            if new_obj is None:
                raise ValueError('Cannot omit both request_body and new_obj!')

            xml_obj = None
            if isinstance(new_obj, list):
                xml_obj = etree.Element(self._meta_object.xml_name)
                for obj in new_obj:
                    xml_obj.append(obj.form_xml())
            else:
                xml_obj = new_obj.form_xml()

            saved_root_tag = xml_obj.tag

            if xml_name is not None:
                xml_obj.tag = xml_name

            body = xmlutil.cleanup(etree.tostring(xml_obj, encoding='unicode'))

        url = self.get_href()
        if task_monitor is not None:
            url = '?queue='.join([url, task_monitor.get_queue_url()])

        response = self._rest_end_point.post(url, headers, body)

        if response.status_code == 204:  # Special case of post with null response
            return new_obj

        if response.status_code not in [200, 202]:
            raise rest.RestException("POST failed on %s" % self.get_href(),
                                     response)

        if task_monitor is not None:
            resp_str = xmlutil.get_text_from_response(response)
            return xmlutil.xml2obj(resp_str)

        if not isinstance(new_obj, list):
            # Fixing issue #17
            #r = response.text
            # Skip the <?xml> line to avoid encoding errors in lxml
            #start = r.index('?><') + 2
            #root = etree.fromstring(r[start:])
            root = xmlutil.get_xml_obj_from_response(response)
            #new_obj._xml_data = root
            #new_obj._rest_end_point = self._rest_end_point
            if saved_root_tag is not None:
                root.tag = saved_root_tag
            new_obj = self._create_resource(root)

        return new_obj
示例#19
0
    def put(self, new_val_obj=None, request_body=None,
            accept=None, content_type=None):
        """Modifies the state of this resource on Space by sending a PUT request
        with the new state. The attributes of *new_val_obj* are
        formatted to form the XML request body for the PUT request. If the
        parameter *new_val_obj* is ``None``, then the argument *request_body*,
        if present, is used as the request body. If this is also ``None``, then
        the attributes of this object itself are formatted to form the XML
        request body. Once the PUT request successfully completes, it
        re-initializes the state of this Resource object based on the XML
        response from Space.

        :param new_val_obj: A Resource object with the newly desired state for
            the resource. This defaults to ``None``.
        :type new_val_obj: jnpr.space.resource.Resource

        :param str request_body: This can be used to supply a string that must
            be used as the request body in the request. This defaults to
            ``None`` and in this case SpaceEZ will create the request body
            using the supplied ``new_val_obj`` argument or from the current
            state of this object.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str content_type: This can be used to supply a media-type that must
            be used as the Content-Type header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :returns: ``None``
        :raises: ``jnpr.space.rest.RestException`` if the PUT method results in
            an error response. The exception's ``response`` attribute will have
            the full response from Space.

        """
        if request_body is not None:
            body = request_body
            if new_val_obj is not None:
                raise ValueError('Cannot use both request_body and new_val_obj')
        elif new_val_obj is not None:
            body = etree.tostring(new_val_obj.form_xml(), encoding='unicode')
        else:
            body = etree.tostring(self.form_xml(), encoding='unicode')

        if content_type is not None:
            mtype = content_type
        else:
            mtype = self.get_meta_object().get_media_type(None)

        headers = {'content-type': mtype}

        if accept is not None:
            headers['accept'] = accept

        response = self._rest_end_point.put(self.get_href(),
                                            headers,
                                            body)
        if response.status_code != 200:
            raise rest.RestException("PUT failed on %s" % self.get_href(),
                                     response)

        # Fixing issue #17
        #r = response.text
        # Skip the <?xml> line to avoid encoding errors in lxml
        #start = r.index('?><') + 2
        #root = etree.fromstring(r[start:])
        #root = etree.fromstring(response.content)

        # Fixing issue #19 self._xml_data = root
        resp_text = xmlutil.get_text_from_response(response)
        self._xml_data = xmlutil.xml2obj(resp_text)
示例#20
0
    def post(self, accept=None, content_type=None, request_body=None,
             task_monitor=None, schedule=None, *args, **kwargs):
        """
        Some resources support the POST method. For example, the configuration
        of a device supports the POST method which can be used to fetch
        selected portions of the configuration based on xpath expressions.
        On such resources, this method can be used to send the POST request.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str content_type: This can be used to supply a media-type that must
            be used as the Content-Type header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str request_body: This can be used to supply a string that must
            be used as the request body in the request. This defaults to
            ``None`` and in this case SpaceEZ will create the request body
            using the modeled template, replacing variables with kwargs.

        :param task_monitor: A TaskMonitor object that can be used to monitor
            the progress of the POST request, in case of asynchronous
            invocations. You need to check Junos Space API documentation to
            see if the POST invocation on this resource has asynchronous
            semantics and supply the task_monitor parameter only if it is
            asynchronous. Otherwise, this will default to ``None`` and the
            method will behave with synchronous semantics.
        :type task_monitor: jnpr.space.async.TaskMonitor

        :param str schedule: A string specifying a cron expression for
            scheduling the execution of the request on the Space server side.
            This is applicable only if the POST invocation on this resource
            has asynchronous semantics and you want to schedule the execution.
            Otherwise, this will default to ``None``.

        :param kwargs: Keyword args of the form name=value which will be used
            to substitute variables in a pre-defined template (if applicable)
            to form the request body.
        :type kwargs: A variable list of name=value arguments.

        :returns: A Python object constructed from the response body that Space
            returned for the POST method invocation. In the case of asynchronous
            invocation, this will represent a Task object and will contain the
            unique id of the Task executing the POST request in Space.

        :raises: ``jnpr.space.rest.RestException`` if the POST method results in
            an error response. The exception's ``response`` attribute will have
            the full response from Space.

        """
        url = self.get_href()
        if task_monitor is not None:
            url = '?queue='.join([url, task_monitor.get_queue_url()])
            if schedule is not None:
                url = '&schedule='.join([url, schedule])

        headers = {}
        if accept is not None:
            headers['accept'] = accept
        elif self._meta_object.response_type is not None:
            headers['accept'] = self._meta_object.response_type

        if content_type is not None:
            headers['content-type'] = content_type
        elif self._meta_object.request_type is not None:
            headers['content-type'] = self._meta_object.request_type

        if request_body is not None:
            body = request_body
        elif self._meta_object.request_template is not None:
            body = self._meta_object.request_template.render(**kwargs)
        else:
            body = None

        response = self._rest_end_point.post(url, headers, body)
        if (response.status_code != 202) and (response.status_code != 200):
            raise rest.RestException("POST failed on %s" % url, response)

        resp_text = xmlutil.get_text_from_response(response)
        resp_text = xmlutil.cleanup(resp_text)
        if self._meta_object.remove_junos_group:
            resp_text = xmlutil.remove_junos_group(resp_text)
        return xmlutil.xml2obj(resp_text)
示例#21
0
    def post(self, new_obj=None, accept=None, content_type=None,
             request_body=None, xml_name=None, task_monitor=None):
        """
        Sends a POST request to the Space server to create a new Resource in
        this collection.

        :param new_obj: The new Resource that needs to be created as a member
            of this collection. This can be omitted in which case the caller
            must supply a request body for the POST request as the
            ``request_body`` argument.
        :type new_obj: A single ``jnpr.space.resource.Resource`` instance
            or a list of them.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str content_type: This can be used to supply a media-type that must
            be used as the Content-Type header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str request_body: This can be used to supply a string that must
            be used as the request body in the request. This defaults to
            ``None`` and in this case the caller must supply the ``new_obj``
            argument from which the request body will be formed.

        :param str xml_name: Can be used to override the name of the top-level
            XML element in the generated request body. This is useful in some
            cases such as creating a quick config template.
            This parameter defaults to ``None``.

        :param task_monitor: A TaskMonitor object that can be used to monitor
            the progress of the POST request, in case of asynchronous
            invocations. You need to check Junos Space API documentation to
            see if the POST invocation on this resource has asynchronous
            semantics and supply the task_monitor parameter only if it is
            asynchronous. Otherwise, this will default to ``None`` and the
            method will behave with synchronous semantics.
        :type task_monitor: jnpr.space.async.TaskMonitor

        :returns: If the new_obj parameter is a list, then the same list is
            returned. Otherwise, this method creates a new Resource object
            based on the state of the newly created resource, as extracted from
            the POST response body. In the case of asynchronous
            invocation, this will represent a Task object and will contain the
            unique id of the Task executing the POST request in Space.

        :raises: ``jnpr.space.rest.RestException`` if the POST method results in
            an error response. The exception's ``response`` attribute will have
            the full response from Space.

        """
        if content_type is not None:
            media_type = content_type
        elif isinstance(new_obj, list):
            if self._meta_object.content_type is not None:
                media_type = self._meta_object.content_type
            else:
                media_type = self._meta_object.get_media_type(None)
        else:
            if new_obj is None:
                raise ValueError('Must provide content_type when providing request_body')
            media_type = new_obj.get_meta_object().get_media_type(None)

        headers = {'content-type': media_type}
        if accept is not None:
            headers['accept'] = accept

        if request_body is not None:
            body = request_body
            saved_root_tag = None
            if new_obj is not None:
                raise ValueError('Cannot use both request_body and new_obj!')
        else:
            if new_obj is None:
                raise ValueError('Cannot omit both request_body and new_obj!')

            xml_obj = None
            if isinstance(new_obj, list):
                xml_obj = etree.Element(self._meta_object.xml_name)
                for obj in new_obj:
                    xml_obj.append(obj.form_xml())
            else:
                xml_obj = new_obj.form_xml()

            saved_root_tag = xml_obj.tag

            if xml_name is not None:
                xml_obj.tag = xml_name

            body = xmlutil.cleanup(etree.tostring(xml_obj, encoding='unicode'))

        url = self.get_href()
        if task_monitor is not None:
            url = '?queue='.join([url, task_monitor.get_queue_url()])

        response = self._rest_end_point.post(url,
                                             headers,
                                             body)

        if response.status_code == 204: # Special case of post with null response
            return new_obj

        if response.status_code not in [200, 202]:
            raise rest.RestException("POST failed on %s" % self.get_href(),
                                     response)

        if task_monitor is not None:
            resp_str = xmlutil.get_text_from_response(response)
            return xmlutil.xml2obj(resp_str)

        if not isinstance(new_obj, list):
            # Fixing issue #17
            #r = response.text
            # Skip the <?xml> line to avoid encoding errors in lxml
            #start = r.index('?><') + 2
            #root = etree.fromstring(r[start:])
            root = xmlutil.get_xml_obj_from_response(response)
            #new_obj._xml_data = root
            #new_obj._rest_end_point = self._rest_end_point
            if saved_root_tag is not None:
                root.tag = saved_root_tag
            new_obj = self._create_resource(root)

        return new_obj
示例#22
0
    def post(self,
             accept=None,
             content_type=None,
             request_body=None,
             task_monitor=None,
             schedule=None,
             *args,
             **kwargs):
        """
        Some resources support the POST method. For example, the configuration
        of a device supports the POST method which can be used to fetch
        selected portions of the configuration based on xpath expressions.
        On such resources, this method can be used to send the POST request.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str content_type: This can be used to supply a media-type that must
            be used as the Content-Type header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str request_body: This can be used to supply a string that must
            be used as the request body in the request. This defaults to
            ``None`` and in this case SpaceEZ will create the request body
            using the modeled template, replacing variables with kwargs.

        :param task_monitor: A TaskMonitor object that can be used to monitor
            the progress of the POST request, in case of asynchronous
            invocations. You need to check Junos Space API documentation to
            see if the POST invocation on this resource has asynchronous
            semantics and supply the task_monitor parameter only if it is
            asynchronous. Otherwise, this will default to ``None`` and the
            method will behave with synchronous semantics.
        :type task_monitor: jnpr.space.async.TaskMonitor

        :param str schedule: A string specifying a cron expression for
            scheduling the execution of the request on the Space server side.
            This is applicable only if the POST invocation on this resource
            has asynchronous semantics and you want to schedule the execution.
            Otherwise, this will default to ``None``.

        :param kwargs: Keyword args of the form name=value which will be used
            to substitute variables in a pre-defined template (if applicable)
            to form the request body.
        :type kwargs: A variable list of name=value arguments.

        :returns: A Python object constructed from the response body that Space
            returned for the POST method invocation. In the case of asynchronous
            invocation, this will represent a Task object and will contain the
            unique id of the Task executing the POST request in Space.

        :raises: ``jnpr.space.rest.RestException`` if the POST method results in
            an error response. The exception's ``response`` attribute will have
            the full response from Space.

        """
        url = self.get_href()
        if task_monitor is not None:
            url = '?queue='.join([url, task_monitor.get_queue_url()])
            if schedule is not None:
                url = '&schedule='.join([url, schedule])

        headers = {}
        if accept is not None:
            headers['accept'] = accept
        elif self._meta_object.response_type is not None:
            headers['accept'] = self._meta_object.response_type

        if content_type is not None:
            headers['content-type'] = content_type
        elif self._meta_object.request_type is not None:
            headers['content-type'] = self._meta_object.request_type

        if request_body is not None:
            body = request_body
        elif self._meta_object.request_template is not None:
            body = self._meta_object.request_template.render(**kwargs)
        else:
            body = None

        response = self._rest_end_point.post(url, headers, body)
        if (response.status_code != 202) and (response.status_code != 200):
            raise rest.RestException("POST failed on %s" % url, response)

        resp_text = xmlutil.get_text_from_response(response)
        resp_text = xmlutil.cleanup(resp_text)
        if self._meta_object.remove_junos_group:
            resp_text = xmlutil.remove_junos_group(resp_text)
        return xmlutil.xml2obj(resp_text)
示例#23
0
    def put(self,
            new_val_obj=None,
            request_body=None,
            accept=None,
            content_type=None):
        """Modifies the state of this resource on Space by sending a PUT request
        with the new state. The attributes of *new_val_obj* are
        formatted to form the XML request body for the PUT request. If the
        parameter *new_val_obj* is ``None``, then the argument *request_body*,
        if present, is used as the request body. If this is also ``None``, then
        the attributes of this object itself are formatted to form the XML
        request body. Once the PUT request successfully completes, it
        re-initializes the state of this Resource object based on the XML
        response from Space.

        :param new_val_obj: A Resource object with the newly desired state for
            the resource. This defaults to ``None``.
        :type new_val_obj: jnpr.space.resource.Resource

        :param str request_body: This can be used to supply a string that must
            be used as the request body in the request. This defaults to
            ``None`` and in this case SpaceEZ will create the request body
            using the supplied ``new_val_obj`` argument or from the current
            state of this object.

        :param str accept: This can be used to supply a media-type that must
            be used as the Accept header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :param str content_type: This can be used to supply a media-type that must
            be used as the Content-Type header in the request. This defaults to
            ``None`` and in this case SpaceEZ will use the media-type modeled
            in the description file.

        :returns: ``None``
        :raises: ``jnpr.space.rest.RestException`` if the PUT method results in
            an error response. The exception's ``response`` attribute will have
            the full response from Space.

        """
        if request_body is not None:
            body = request_body
            if new_val_obj is not None:
                raise ValueError(
                    'Cannot use both request_body and new_val_obj')
        elif new_val_obj is not None:
            body = etree.tostring(new_val_obj.form_xml(), encoding='unicode')
        else:
            body = etree.tostring(self.form_xml(), encoding='unicode')

        if content_type is not None:
            mtype = content_type
        else:
            mtype = self.get_meta_object().get_media_type(None)

        headers = {'content-type': mtype}

        if accept is not None:
            headers['accept'] = accept

        response = self._rest_end_point.put(self.get_href(), headers, body)
        if response.status_code != 200:
            raise rest.RestException("PUT failed on %s" % self.get_href(),
                                     response)

        # Fixing issue #17
        #r = response.text
        # Skip the <?xml> line to avoid encoding errors in lxml
        #start = r.index('?><') + 2
        #root = etree.fromstring(r[start:])
        #root = etree.fromstring(response.content)

        # Fixing issue #19 self._xml_data = root
        resp_text = xmlutil.get_text_from_response(response)
        self._xml_data = xmlutil.xml2obj(resp_text)