I'm using a very basic example for testing my MassTransit connection to rabbitMq through C#. Whenever I run this code to connect to my rabbitMq endpoint, it works fine whenever I have a wildcard set as permission. However, when I add the permissions in the rabbitMq admin to only allow this user to access the test event, this code will fail.
For some reason it will first try to connect to an exchange name that I guess is generated (by MassTransit?):
RabbitMQ.Client.Exceptions.OperationInterruptedException: 'The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=403, text="ACCESS_REFUSED - access to exchange '*ComputerName*_dotnet_bus_73451gfsgerqwrefxfddgf' in vhost '/' refused for user 'user'", classId=40, methodId=10, cause='
So the exchange *ComputerName*_dotnet_bus_73451gfsgerqwrefxfddgf, after that it will try to connect to the test exchange. Of course I can add the ComputerName.... exchange to the permissions but then this would need to be done for each computer trying to run this code. Why is MassTransit trying to connect to this exchange? Is the code incorrect or is this just how MassTransit works?
This is the code for the test application (I altered this a bit so it might not run right of the bat, but, in general the code runs fine):
using System;
using MassTransit;
namespace Test
{
public class Testing
{
public string Id { get; set; }
}
}
namespace Consumer
{
class Program
{
static void Main(string[] args)
{
var bus = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
var host = sbc.Host(new Uri("rabbitmq://servername"), h =>
{
h.Username("user");
h.Password("user");
});
sbc.ReceiveEndpoint(host, "test", ep =>
{
ep.Handler<Testing>(context =>
{
return Console.Out.WriteLineAsync($"Received: {context.Message.Id}");
});
});
});
bus.Start();
// For testing purposes, we send a message ourselves.
bus.Publish(new Testing { Id = "X" });
Console.WriteLine("Waiting for messages. Press any key to exit");
Console.ReadKey();
bus.Stop();
}
}
}
Image of the rabbitMq admin user permission:
Is the code incorrect or is this just how MassTransit works?
More than likely this is just how MassTransit works. See this other question: Prevent MassTransit from creating a RabbitMQ exchange for a consumer host
Strangely enough I could not find this information anywhere in the MassTransit docs.
You'll have to grant the configure permission for exchanges containing the string dotnet_bus. More than likely other permissions like read and write will be required.
NOTE: the RabbitMQ team monitors the rabbitmq-users mailing list and only sometimes answers questions on StackOverflow.
Related
I try to generate a new device and publish some random data to it via MQTT.
I follow this official example:
https://cumulocity.com/guides/device-sdk/mqtt-examples/#hello-mqtt-cs
All operations are executed without any error. Even establishing connection. But when I try to publish a message to the device I get the following error
"Connecting with MQTT server failed (ConnectionRefusedNotAuthorized)"
Here is my info to connect to the server
const string serverUrl = "mytenant.eu-latest.cumulocity.com";
const string clientId = "d:testdevice4";
const string device_name = "testdevice4";
const string user = "<mytenant>.eu-latest/<myusername>";
const string password = "XXXXXXXX";
And here are the operations that are executed without throwing any exception or ConnectionFailed event:
Establish Connection
await client.EstablishConnectionAsync();
Create Device
string topic = "s/us";
string payload = $"100,{device_name}, c8y_MQTTDevice";
var message = new MqttMessageRequestBuilder()
.WithTopicName(topic)
.WithQoS(QoS.EXACTLY_ONCE)
.WithMessageContent(payload)
.Build();
The other operations on Cumulocity Example
// set device's hardware information
var deviceMessage = new MqttMessageRequestBuilder()
.WithTopicName("s/us")
.WithQoS(QoS.EXACTLY_ONCE)
.WithMessageContent($"110, {device_name}, MQTT test model, Rev0.1")
.Build();
await client.PublishAsync(deviceMessage);
// add restart operation
await client.SubscribeAsync(new MqttMessageRequest() { TopicName = "s/ds" });
await client.SubscribeAsync(new MqttMessageRequest() { TopicName = "s/e" });
await client.PublishAsync(new MqttMessageRequestBuilder()
.WithTopicName("s/us")
.WithQoS(QoS.EXACTLY_ONCE)
.WithMessageContent("114,c8y_Restart")
.Build());
But when I try to publish a message to the device as follows, ConnectionFailed event is invoked with the error:
"Connecting with MQTT server failed (ConnectionRefusedNotAuthorized)"
Random rnd = new Random();
while (!cToken.IsCancellationRequested)
{
int temp = rnd.Next(10, 20);
Console.WriteLine("Sending temperature measurement (" + temp + "º) ...");
var xx = client.ConnectionDetails;
await client.PublishAsync(new MqttMessageRequestBuilder()
.WithTopicName("s/us")
.WithQoS(QoS.EXACTLY_ONCE)
.WithMessageContent("211," + temp)
.Build());
Thread.Sleep(1000);
}
You get a ConnectionRefusedNotAuthorized error because your credentials are not correct. To be precise, the user:
const string user = "<mytenant>.eu-latest/<myusername>";
The user is formed as tenantID/username
Your tenant domain (<mytenant>.eu-latest) is not the tenant ID. Tenant IDs – in most of the cases – are a number preceded by the letter t, e.g. t123123.
so your string should look like:
const string user = "t123123/mytenant";
More details can be found in the public documentation:
Tenant ID and Tenant domain
GET the current tenant details
There could be more reasons than just authorization issues, as per
https://cumulocity.com/guides/device-sdk/mqtt/
which states for return code 5 - "Connection refused, not authorized"
Mostly a device side related problem, used when the device doesn’t
have permissions or is doing something forbidden. For example, if the
client sends malformed messages or tries to execute an operation
without authenticating first, such as publishing a message. Thrown on
any issue with certificate authentication (for example, wrong common
name, failed auto registration). Also thrown on general issues with
receiving device data or some other authorization problem related to
the device state on the platform. For example, device managed object
problems, or the sudden removal of permissions. In this situation it
may be required to take action on the platform to investigate and
apply a fix. When clientId is too long the user can receive this error
when using 3.1 version of MQTT. This can happen if clientId has 24
characters or more. Lastly, it can also be thrown on unexpected
exceptions like performance issues, especially during connection.
Therefore it is a good approach to repeat the connection a few times
to overcome temporary performance issues.
I had the same issue where all my coded attempts (C#, Node.js) were failing with this same error.
In my case I am using a trial Cumulocity environment where the tenant id differs from all the Cumulocity documentation (which says the tenant id starts with a 't' followed by a number of digits. In my trial environment, the Tenant ID is shown in the Cumulocity Cockpit under the user details (top right), and this is in the format "ENVxxxxxx".
To try to troubleshoot the issue I began testing with an online MQTT client http://www.emqx.io/online-mqtt-client and through this process I mistakenly typed the username with lower case "env" and this resolved my issue. Hope that helps others.
I'm creating a client application with the idea of publish new messages to a remote RabbitMQ queue. I'm using MassTransit to create this client, and my code looks this way:
static IBusControl CreateBus()
{
return Bus.Factory.CreateUsingRabbitMq(x =>
{
var host = x.Host(new Uri(ConfigurationManager.AppSettings["RabbitMQHost"]), h =>
{
h.Username("user");
h.Password("password");
});
});
}
static IRequestClient<ISyncProject, IProjectSynced> CreateRequestClient(IBusControl busControl)
{
var serviceAddress = new Uri(ConfigurationManager.AppSettings["ServiceAddress"]);
IRequestClient<ISyncProject, IProjectSynced> client =
busControl.CreateRequestClient<ISyncProject, IProjectSynced>(serviceAddress, TimeSpan.FromDays(1));
return client;
}
private static async Task MainLogic(IBusControl busControl)
{
IRequestClient<ISyncProject, IProjectSynced> client = CreateRequestClient(busControl);
//I'm using the client here as I show below, this part is not important it works with localhost
IProjectSynced response = await client.Request(new ProjecToSync() { OriginalOOMID = OriginalOOMID });
}
And the config file looks like this:
<appSettings>
<add key="RabbitMQHost" value="rabbitmq://ServerName" />
<add key="ServiceQueueName" value="queueName" />
<add key="ServiceAddress" value="rabbitmq://ServerName/queueName" />
</appSettings>
I'm not using guest user, I created a new one and I added all the rights as administrator.
Now this code works if I run the client application in the same server where is running RabbitMQ and also changing ServerName by localhost. If I run the client in my local machine using whatever ServerName or IP address of server, RabbitMQ is blocking my connection:
I presume this is has to be with some configuration that I need to do in the server but I have not found it so far.
One thing I noticed now is disk space is in red and and a big amount of generic exchanges have been created
As your question shows, down at the bottom you have a connection, but it is blocked.
The RabbitMQ documentation lists some conditions where a connection is blocked. These generally have to do with resource limitations on the broker machine itself. In this case, we've managed to get a clear picture that the free disk space available to the broker is below its low-water mark. Thus, all connections will be blocked until this condition is resolved (either lower the mark - not recommended, or increase the available free space).
I want to do black-box testing of a messaging client library that uses the WindowsAzure.ServiceBus nuget package nuget package (docs) to send and receive messages to/from Microsoft ServiceBus queues.
My goal is to create integration tests for the messaging client library, but not communicate with an actual Microsoft Service Bus server.
Looking at the amqplite library, I was hoping that I could create an AMQP host using amqplite, and configure the messaging client library to communicate with this host, instead of an actual Microsoft Service Bus.
Here is my custom AMQP host, using amqplite:
public class LinkProcessor : ILinkProcessor
{
public void Process(AttachContext attachContext)
{
Console.WriteLine("LinkProcessor.Attach!");
}
}
var containerHost = new ContainerHost(new Uri("amqp://localhost:9876/"));
containerHost.RegisterLinkProcessor(new LinkProcessor());
containerHost.Open();
I register a ILinkProcessor on the containerHost so I can see on the console any connection attempts (based on my limited understanding of AMQP/AMQPlite this is what I believe a ILinkProcessor does).
The AMQP client below can connect, the server process outputs "LinkProcessor.Attach!" on the console.
async Task Main()
{
await SendMessage("q2", "hello world");
}
async Task SendMessage(string queue, string message)
{
var connection = await Connection.Factory.CreateAsync(new Address("amqp://localhost:9876/"));
var session = new Session(connection);
var msg = new Message(message);
var sender = new SenderLink(session, "sender-link", queue);
await sender.SendAsync(msg);
await sender.CloseAsync();
await session.CloseAsync();
await connection.CloseAsync();
}
Back to the messaging client library that I want to test:
The library is configured using a connection string, a working connection string looks like this (I assume the connection string format is one defined by WindowsAzure.ServiceBus):
Endpoint=sb://xxx/yyy;StsEndpoint=https://nnn:NNNN/xxx;RuntimePort=NNNN;ManagementPort=NNNN;OAuthUsername=xxx;OAuthPassword=yyy
I changed the config string to the following:
Endpoint=amqp://localhost:9876/q2
When I run the test client, the following happens:
The client throws an exception: You have tried to create a channel to a service that does not support .Net Framing.
I see no activity on the AMQPlite host end, i.e. no "LinkProcessor.Attach!" message on the console.
Question:
Is what I'm trying to accomplish possible? I.e. is there a way to configure a AMQPlite host so that it can accept connections from a WindowsAzure.ServiceBus client ?
I have a distributed system of actors, some on Windows, and some on Linux machine. Sometimes one actor may need to connect other actor and make some communications. Of course, there are cases when one of them is on Windows, and other is on Linux system.
Actors connect each other via ActorSelection. There problem is, that when Windows actor is trying to communicate with Linux one, all works fine. But when Linux actor initiating communication, the ActorSelection.ResolveOne failes.
I've made a little sample here:
static void Main(string[] args)
{
ActorSystem system = ActorSystem.Create("TestSystem");
system.ActorOf(Props.Create(() => new ConnectActor()), "test");
while (true)
{
var address = Console.ReadLine();
if (string.IsNullOrEmpty(address))
{
system.Terminate();
return;
}
var remoteAddress = $"akka.tcp://{system.Name}#{address}/user/test";
try
{
var actor = system.ActorSelection(remoteAddress).ResolveOne(TimeSpan.FromMilliseconds(5000)).Result;
Console.WriteLine("Resolved: " + actor.Path);
}
catch (Exception ex)
{
Console.WriteLine("Failed: " + ex.Message);
}
}
}
Configuration in app.config is the following:
akka {
loggers = ["Akka.Logger.NLog.NLogLogger, Akka.Logger.NLog"]
suppress-json-serializer-warning = on
loglevel = "DEBUG"
log-config-on-start = on
actor {
provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote"
debug {
receive = on
autoreceive = on
lifecycle = on
event-stream = on
unhandled = on
}
}
remote {
log-remote-lifecycle-events = DEBUG
log-received-messages = on
helios.tcp {
transport-class = "Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote"
transport-protocol = tcp
applied-adapters = []
port = 9000
hostname = "0.0.0.0"
public-hostname = "192.168.0.251" // This is different for different hosts, of course
}
}
}
The public-hostname is publicly available ip address.
So, here are the cases:
When running Windows/Windows, both instances see each other (I give them remote address - they output "Resolved ")
When running Windows/Linux, and give linux actor's address to windows actor, it outputs "Resolved". So windows connects linux with no problem. After that giving windows actor's address to linux actor also gives "Resolved" - I suppose, the connection is already established and there is no real handshakes passing
BUT when running Windiws/Linux and give windows actor's address to linux actor, it gives "Failed". No messages about any errors or dropping packages. At the end of the log there is the following:
Akka.Remote.Transport.AkkaProtocolManager|now supervising akka://TestSystem/system/transports/akkaprotocolmanager.tcp.0/akkaProtocol-tcp%3A%2F%2FTestSystem%40%5B%3A%3Affff%3A192.168.0.252%5D%3A36983-1||||
13:20:08.3766|DEBUGAkka.Remote.Transport.ProtocolStateActor|Started (Akka.Remote.Transport.ProtocolStateActor)||||
13:20:08.3922|DEBUG|Akka.Remote.Transport.ProtocolStateActor|Stopped||||
The issue with similar logs is described here: Akka.net starting and stopping with no activity
The reason there is that system protocols are not compatible. Is this the same issue? As I got from Akka.NET docs and release notes, it has full linux support...
So, am I missing something in configuration? Can anybody make this sample work with Linux -> Windows connection?
The issue here appears to be that Mono is using an IPV6 address mapped to IPV4 in its bound address for some reason.
akka://TestSystem/system/transports/akkaprotocolmanager.tcp.0/akkaProtocol-tcp%3A%2F%2FTestSystem%40%5B%3A%3Affff%3A192.168.0.252%5D%3A36983-1
If you decode this URL that gets translated to
akkaProtocol-tcp://TestSystem#[::ffff:192.168.0.252]:36983-
So I think what is happening here is that outbound address Helios is supposed to parse from that is getting screwed up on the Linux side, so it attempts to connect to a mal-formed address that isn't the same as the one Windows listens on. Something platform-specific in the actor selection URI parsing code is incorrect I suspect.
I've filed a bug here: https://github.com/akkadotnet/akka.net/issues/2254
When i have 2000 messages in an import queue, when i read it through get like this
MQQueue mqQueue = null;
MQQueueManager mqQMgr=null;
try
{
//Create connection to queue manager
mqQMgr = new MQQueueManager("Queue Manager name", properties);
//Access the queue
mqQueue = mqQMgr.AccessQueue(QueueName, MQC.MQOO_FAIL_IF_QUIESCING | MQC.MQOO_INPUT_SHARED | MQC.MQOO_BROWSE);
for(int i=1;i<2000;i++)
{
//read the messages
mqMsg=new MQMessage();
mqQueue.Get(mqMsg);
}
}
catch(MQException mqe)
{
//If no messages in the queue , break. (if not, catch any error)
}
finally
{
mqQueue.Close(); //Close the MQ Queue
mqQMgr.Disconnect(); //Disconnect the MQ Manager
}
The manager processes randomly everytime when i read, for example first 800 messages and then it throws back
"MQRC_HANDLE_NOT_AVAILABLE" (comp code:2 , reason code:2017).
Am I not closing the queue/manager in the above piece of code ? Please share your thoughts, so that, all the messages can be processed. I am using 7.5 MQ client via MQ.net classes. The log file contains this below info.
AMQ9051: WebSphere MQ could not find the security policy definition.
Compcode 2 : reason 2017 EXPLANATION: The security policy definition
is not defined. ACTION: Security policy definition must be defined
before this action.
I tried your sample code snippet and works fine for me. I don't see 2017 error.
The entry in error log may have a relation to your problem. Have you set security policy for the queue and expecting signed/signed&encrypted messages to be put/get to/from queue? It may be worth opening a ticket/PMR with IBM.