예제 #1
0
    def publish(cls, event):
        if event.name in WEBSOCKET_EVENT_TYPE_BLOCKLIST:
            return

        if len(cls.listeners) > 0:
            message = SchemaParser.serialize(event, to_string=True)

            for listener in cls.listeners:
                if _auth_enabled():
                    user = listener.get_current_user()

                    if user is None:
                        listener.request_authorization("Valid access token required")
                        continue

                    if not _user_can_receive_messages_for_event(user, event):
                        logger.debug(
                            "Skipping websocket publish of event %s to user %s due to "
                            "lack of access",
                            event.name,
                            user.username,
                        )
                        continue

                listener.write_message(message)
예제 #2
0
def websocket_publish(item):
    """Will serialize an event and publish it to all event websocket endpoints"""
    try:
        beer_garden.api.http.io_loop.add_callback(
            EventSocket.publish, SchemaParser.serialize(item, to_string=True))
    except Exception as ex:
        logger.exception(f"Error publishing event to websocket: {ex}")
예제 #3
0
    async def post(self):
        """
        ---
        summary: Create a new File
        parameters:
          - name: body
            in: body
            required: true
            description: The data
        responses:
          201:
            description: A new File is created
            schema:
              $ref: '#/definitions/FileStatus'
          400:
            $ref: '#/definitions/400Error'
          50x:
            $ref: '#/definitions/50xError'
        tags:
          - Files
        """
        db_file = RawFile()
        db_file.file.put(io.BytesIO(self.request.body))
        db_file.save()

        resolvable = Resolvable(id=str(db_file.id), type="bytes", storage="gridfs")
        response = SchemaParser.serialize(resolvable, to_string=True)

        self.set_header("Content-Type", "application/json; charset=UTF-8")
        self.write(response)
예제 #4
0
def process(body) -> Tuple[str, dict]:
    """Processes a message body prior to sending

    We always want to send Operations. So if the given message is an Event we'll wrap
    it in an Operation.

    Args:
        body: the message body to process

    Returns:
        Tuple of the serialized message and headers dict

    """
    many = isinstance(body, list)

    if body.__class__.__name__ == "Event":
        body = Operation(operation_type="PUBLISH_EVENT",
                         model=body,
                         model_type="Event")

    model_class = (body[0] if many else body).__class__.__name__

    if not isinstance(body, str):
        body = SchemaParser.serialize(body, to_string=True, many=many)

    return body, {"model_class": model_class, "many": many}
예제 #5
0
 def test_parsed_start(self, model, assertion, data):
     assertion(
         SchemaParser.parse(SchemaParser.serialize(data, to_string=False),
                            model,
                            from_string=False),
         data,
     )
예제 #6
0
    async def post(self):
        """
        ---
        summary: Exports a list of Jobs from a list of IDs.
        description: |
          Jobs will be scheduled from a provided list to run on the intervals
          set in their trigger arguments.
        parameters:
          - name: ids
            in: body
            description: A list of the Jobs IDs whose job definitions should be \
            exported. Omitting this parameter or providing an empty map will export \
            all jobs.
            schema:
              $ref: '#/definitions/JobExport'
        responses:
          201:
            description: A list of jobs has been exported.
            schema:
              type: array
              items:
                $ref: '#/definitions/JobImport'
          400:
            $ref: '#/definitions/400Error'
          50x:
            $ref: '#/definitions/50xError'
        tags:
          - Jobs
        """
        filter_params_dict = {}
        permitted_objects_filter = self.permitted_objects_filter(Job, JOB_READ)

        # self.request_body is designed to return a 400 on a completely absent body
        # but we want to return all jobs if that's the case
        if len(self.request.body) > 0:
            decoded_body_as_dict = self.request_body

            if len(decoded_body_as_dict) > 0:  # i.e. it has keys
                input_schema = JobExportInputSchema()
                validated_input_data_dict = input_schema.load(
                    decoded_body_as_dict).data
                filter_params_dict["id__in"] = validated_input_data_dict["ids"]

        response_objects = await self.client(
            Operation(
                operation_type="JOB_READ_ALL",
                kwargs={
                    "q_filter": permitted_objects_filter,
                    "filter_params": filter_params_dict,
                },
            ),
            serialize_kwargs={"return_raw": True},
        )
        response = SchemaParser.serialize(response_objects,
                                          to_string=True,
                                          schema_name="JobExportSchema")

        self.set_header("Content-Type", "application/json; charset=UTF-8")
        self.write(response)
예제 #7
0
    def test_patch_serialized_start(self, patch_dict_no_envelop):
        """Patches are always parsed into a list, so they need a tweak to test"""
        serialized = SchemaParser.serialize(
            SchemaParser.parse_patch(patch_dict_no_envelop, from_string=False),
            to_string=False,
        )

        assert len(serialized) == 1
        assert serialized[0] == patch_dict_no_envelop
예제 #8
0
    def test_patch_model_start(self, bg_patch):
        """Patches are always parsed into a list, so they need a tweak to test"""
        parsed = SchemaParser.parse(
            SchemaParser.serialize(bg_patch, to_string=False),
            brewtils.models.PatchOperation,
            from_string=False,
        )

        assert len(parsed) == 1
        assert_patch_equal(parsed[0], bg_patch)
예제 #9
0
    def test_post_creates_only_valid_jobs(self, base_url, http_client, bg_job):
        url = f"{base_url}/api/v1/import/jobs"
        headers = {"Content-Type": "application/json"}

        valid_job = SchemaParser.serialize(bg_job)
        valid_job["id"] = None
        invalid_job = SchemaParser.serialize(bg_job)
        invalid_job["name"] = None

        post_body = json.dumps([valid_job, invalid_job])

        response = yield http_client.fetch(url,
                                           method="POST",
                                           headers=headers,
                                           body=post_body)
        response_body = json.loads(response.body.decode("utf-8"))

        assert response.code == 201
        assert len(response_body["ids"]) == 1
        assert len(Job.objects.all()) == 1
예제 #10
0
def from_brewtils(obj: ModelItem) -> MongoModel:
    """Convert an item from its Brewtils model to its Mongo one.

    Args:
        obj: The Brewtils model item

    Returns:
        The Mongo model item

    """
    model_dict = SchemaParser.serialize(obj, to_string=False)
    mongo_obj = MongoParser.parse(model_dict, type(obj), from_string=False)
    return mongo_obj
예제 #11
0
    async def get(self, system_id):
        """
        ---
        summary: Retrieve a specific System
        parameters:
          - name: system_id
            in: path
            required: true
            description: The ID of the System
            type: string
          - name: include_commands
            in: query
            required: false
            description: Include the System's commands in the response
            type: boolean
            default: true
        responses:
          200:
            description: System with the given ID
            schema:
              $ref: '#/definitions/System'
          404:
            $ref: '#/definitions/404Error'
          50x:
            $ref: '#/definitions/50xError'
        tags:
          - Systems
        """
        response = await self.client(
            Operation(operation_type="SYSTEM_READ", args=[system_id])
        )

        # This is only here because of backwards compatibility
        include_commands = (
            self.get_query_argument("include_commands", default="").lower() != "false"
        )

        if not include_commands:
            system = SchemaParser.parse_system(response, from_string=True)
            system.commands = []
            response = SchemaParser.serialize(system)

        self.set_header("Content-Type", "application/json; charset=UTF-8")
        self.write(response)
예제 #12
0
    async def __call__(self, *args, serialize_kwargs=None, **kwargs):
        result = beer_garden.router.route(*args, **kwargs)

        # Await any coroutines
        if isawaitable(result):
            result = await result

        # Handlers overwhelmingly just write the response so default to serializing
        serialize_kwargs = serialize_kwargs or {}
        if "to_string" not in serialize_kwargs:
            serialize_kwargs["to_string"] = True

        # Don't serialize if that's not desired
        if serialize_kwargs.get("return_raw") or isinstance(result, six.string_types):
            return result

        if self.json_dump(result):
            return json.dumps(result) if serialize_kwargs["to_string"] else result

        return SchemaParser.serialize(result, **(serialize_kwargs or {}))
예제 #13
0
    async def get(self):
        """
        ---
        summary: Reserve a file ID for a new file.
        parameters:
          - name: file_name
            in: query
            required: true
            description: The name of the file being sent.
          - name: chunk_size
            in: query
            required: true
            description: The size of chunks the file is being broken into (in bytes).
            type: integer
          - name: file_size
            in: query
            required: true
            description: The total size of the file (in bytes).
            type: integer
          - name: file_id
            in: query
            required: false
            description: Attempt to set the file's ID. Must be a 24-character hex string.
            type: string
          - name: upsert
            in: query
            required: false
            description: Update an already-existing File, otherwise make a new one.
            type: boolean
          - name: owner_id
            in: query
            required: false
            description: Used to set ownership of the file so it isn't deleted.
            type: string
          - name: owner_type
            in: query
            required: false
            description: Describes the type of owner.
                This may be any value, or a pre-set one (e.g. JOB, REQUEST, MyCustomOwnerType)
            type: string
        responses:
          200:
            description: The File ID
            schema:
              $ref: '#/definitions/FileStatus'
          404:
            $ref: '#/definitions/404Error'
          50x:
            $ref: '#/definitions/50xError'
        tags:
          - Files
        """
        file_name = self.get_argument("file_name", default="")
        file_size = self.get_argument("file_size", default=None)
        chunk_size = self.get_argument("chunk_size", default=None)
        file_id = self.get_argument("file_id", default=None)
        owner_id = self.get_argument("owner_id", default=None)
        owner_type = self.get_argument("owner_type", default=None)
        upsert = self.get_argument("upsert", default="").lower() == "true"

        if chunk_size is None:
            raise ModelValidationError(
                f"No chunk_size sent with file {file_name}.")
        if file_size is None:
            raise ModelValidationError(
                f"No file_size sent with file {file_name}.")

        file_status = await self.client(
            Operation(
                operation_type="FILE_CREATE",
                args=[file_name, int(file_size),
                      int(chunk_size)],
                kwargs={
                    "file_id": file_id,
                    "upsert": upsert,
                    "owner_id": owner_id,
                    "owner_type": owner_type,
                },
            ),
            serialize_kwargs={"to_string": False},
        )

        resolvable = Resolvable(
            id=file_status["file_id"],
            type="chunk",
            storage="gridfs",
            details=file_status,
        )
        response = SchemaParser.serialize(resolvable, to_string=True)

        self.set_header("Content-Type", "application/json; charset=UTF-8")
        self.write(response)
예제 #14
0
    def resolve(self, values, definitions=None, upload=True):
        # type: (Mapping[str, Any], List[Parameter], bool) -> Dict[str, Any]
        """Iterate through parameters, resolving as necessary

        Args:
            values: Dictionary of request parameter values
            definitions: Parameter definitions
            upload: Controls which methods will be called on resolvers

        Returns:
            The resolved parameter dict
        """
        resolved_parameters = {}

        for key, value in values.items():
            # First find the matching Parameter definition, if possible
            definition = Parameter()
            for param_def in definitions or []:
                if param_def.key == key:
                    definition = param_def
                    break

            # Check to see if this is a nested parameter
            if isinstance(value, CollectionsMapping) and definition.parameters:
                resolved = self.resolve(value,
                                        definitions=definition.parameters,
                                        upload=upload)

            # See if this is a multi parameter
            elif isinstance(value, list):
                # This is kind of gross because multi-parameters are kind of gross
                # We have to wrap everything into the correct form and pull it out
                resolved = []

                for item in value:
                    resolved_item = self.resolve({key: item},
                                                 definitions=definitions,
                                                 upload=upload)
                    resolved.append(resolved_item[key])

            # This is a simple parameter
            else:
                # See if this is a parameter that needs to be resolved
                for resolver in self.resolvers:
                    if upload and resolver.should_upload(value, definition):
                        resolvable = resolver.upload(value, definition)
                        resolved = SchemaParser.serialize(resolvable,
                                                          to_string=False)
                        break
                    elif (not upload
                          and resolver.should_download(value, definition)
                          and isinstance(value, Mapping)):
                        resolvable = Resolvable(**value)
                        resolved = resolver.download(resolvable, definition)
                        break

                # Just a normal parameter
                else:
                    resolved = value

            resolved_parameters[key] = resolved

        return resolved_parameters
예제 #15
0
 def test_single(self, model, expected):
     assert SchemaParser.serialize(model, to_string=False) == expected
예제 #16
0
 def test_many(self, model, expected):
     assert SchemaParser.serialize([model] * 2,
                                   to_string=False) == [expected] * 2
예제 #17
0
 def test_serialized_start(self, model, data):
     assert (SchemaParser.serialize(SchemaParser.parse(data,
                                                       model,
                                                       from_string=False),
                                    to_string=False) == data)
예제 #18
0
 def test_double_nested(self, bg_system, system_dict):
     model_list = [bg_system, [bg_system, bg_system]]
     expected = [system_dict, [system_dict, system_dict]]
     assert SchemaParser.serialize(model_list, to_string=False) == expected
     assert SchemaParser.serialize_system(model_list,
                                          to_string=False) == expected