serverless / serverless-azure-functions

Serverless Azure Functions Plugin – Add Azure Functions support to the Serverless Framework
MIT License
267 stars 162 forks source link

Incorrect Service Bus Out binding #352

Open stout01 opened 5 years ago

stout01 commented 5 years ago

This is a Bug Report

Description

Similar or dependent issues:

Additional Data

bartlomiejlazarczyk commented 3 years ago

Could you tell me what is the current status of this bug and when do you plan to fix this?

According to the Azure Servicebus output binding docs you can provide either queueName or topicName in function.json. If both of them are provided, then queue has bigger priority. That makes sending messages through out binding impossible for topic out binding. The only workaround that I have found so far is to create a queue that will forward those messages to topic but it seems to be too excessive.

I've taken a quick look into the source code and it seems that the problem lies in the missing ValidateIf logic for serviceBus out binding(required value is either queueName or topicName+ subscription). Also a quick fix might be probably done by changing true required flag in queueName and topicName for serviceBus in bindings.json. I am not sure why in the serviceBusTrigger those two values are false but as a consequence it may result in not having those values function.json unless they are provided in serverless.yml.

Nonetheless this issue is pretty serious and IMO should be fixed any time soon.

majezanu commented 3 years ago

I have the same issue. There is a workaround or fix?

majezanu commented 3 years ago

Hello, I have a workaround, I created a plugin with the following code:

'use strict';

const path = require('path');
const fs = require('fs');

class ServerlessPlugin {
  constructor(serverless, options) {
    this.serverless = serverless;
    this.options = options;

    this.hooks = {
      'after:package:setupProviderConfiguration': this.bindingCleanup.bind(this),
      'before:deploy:function:packageFunction': this.bindingCleanup.bind(this),
      'before:deploy:deploy': this.bindingCleanup.bind(this),
      'after:offline:build': this.bindingCleanup.bind(this),
    };
  }

  bindingCleanup() {
    this.serverless.cli.log('Hello from ServiceBus Binding Cleanup!');

    const parsedFunctions = this.serverless.service.getAllFunctions();

    parsedFunctions.forEach((parseFunction) => {
      this.serverless.cli.log('checking binding in -> ' + parseFunction);
      this.serverless.cli.log(this.serverless.config.servicePath);
      const functionJSON = JSON.parse(fs.readFileSync(path.join(this.serverless.config.servicePath, parseFunction,'function.json')).toString());
      const bindings = functionJSON.bindings;
      let update = false;
      bindings.forEach((binding, index) => {
        if (binding.queueName === false) {
          this.serverless.cli.log('    Found serviceBus with default queueName, updating ...');

          delete binding.queueName;

          functionJSON.bindings[index] = binding;
          update = true;
        }
      });
      if (update) {
        this.serverless.cli.log('    ... updated to ' + JSON.stringify(functionJSON));
        fs.writeFileSync(path.join(this.serverless.config.servicePath, parseFunction,'function.json'), JSON.stringify(functionJSON, null, 4));
      }
    });

    this.serverless.cli.log('All cleanup done, please check the binding in function.json!');
  }

}

module.exports = ServerlessPlugin;

With this, you only need to put queueName: false in your serverless.yml function