| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- from jinja2.exceptions import TemplateError
- from rest_framework.decorators import action
- from rest_framework.renderers import JSONRenderer
- from rest_framework.response import Response
- from rest_framework.status import HTTP_400_BAD_REQUEST
- from netbox.api.renderers import TextRenderer
- from .nested_serializers import NestedConfigTemplateSerializer
- __all__ = (
- 'ConfigContextQuerySetMixin',
- 'ConfigTemplateRenderMixin',
- 'RenderConfigMixin',
- )
- class ConfigContextQuerySetMixin:
- """
- Used by views that work with config context models (device and virtual machine).
- Provides a get_queryset() method which deals with adding the config context
- data annotation or not.
- """
- def get_queryset(self):
- """
- Build the proper queryset based on the request context
- If the `brief` query param equates to True or the `exclude` query param
- includes `config_context` as a value, return the base queryset.
- Else, return the queryset annotated with config context data
- """
- queryset = super().get_queryset()
- request = self.get_serializer_context()['request']
- if self.brief or 'config_context' in request.query_params.get('exclude', []):
- return queryset
- return queryset.annotate_config_context_data()
- class ConfigTemplateRenderMixin:
- """
- Provides a method to return a rendered ConfigTemplate as REST API data.
- """
- def render_configtemplate(self, request, configtemplate, context):
- try:
- output = configtemplate.render(context=context)
- except TemplateError as e:
- return Response({
- 'detail': f"An error occurred while rendering the template (line {e.lineno}): {e}"
- }, status=500)
- # If the client has requested "text/plain", return the raw content.
- if request.accepted_renderer.format == 'txt':
- return Response(output)
- template_serializer = NestedConfigTemplateSerializer(configtemplate, context={'request': request})
- return Response({
- 'configtemplate': template_serializer.data,
- 'content': output
- })
- class RenderConfigMixin(ConfigTemplateRenderMixin):
- """
- Provides a /render-config/ endpoint for REST API views whose model may have a ConfigTemplate assigned.
- """
- @action(detail=True, methods=['post'], url_path='render-config', renderer_classes=[JSONRenderer, TextRenderer])
- def render_config(self, request, pk):
- """
- Resolve and render the preferred ConfigTemplate for this Device.
- """
- instance = self.get_object()
- object_type = instance._meta.model_name
- configtemplate = instance.get_config_template()
- if not configtemplate:
- return Response({
- 'error': f'No config template found for this {object_type}.'
- }, status=HTTP_400_BAD_REQUEST)
- # Compile context data
- context_data = instance.get_config_context()
- context_data.update(request.data)
- context_data.update({object_type: instance})
- return self.render_configtemplate(request, configtemplate, context_data)
|