How to specify custom host for connection in RabbitMQ? - rabbitmq

How can I specify my custom host in send.exs file if my app which has receive.exs is hosted somewhere? I have one elixir app with send.exs and another app with receive.exs which is Phoenix app and is hosted.
send.exs
{:ok, connection} = AMQP.Connection.open
{:ok, channel} = AMQP.Channel.open(connection)
AMQP.Queue.declare(channel, "hello")
AMQP.Basic.publish(channel, "", "hello", msg)
IO.puts " [x] Sent everything"
AMQP.Connection.close(connection)
receive.exs
...
{:ok, connection} = AMQP.Connection.open
{:ok, channel} = AMQP.Channel.open(connection)
AMQP.Queue.declare(channel, "hello")
AMQP.Basic.consume(channel, "hello", nil, no_ack: true)
IO.puts " [*] Waiting for messages. To exit press CTRL+C, CTRL+C"
...

There are a few different forms of Connection.open.
The first, which you're using, takes no arguments, and uses some default settings (localhost, "guest" username, "guest" password, etc.).
The second takes a Keyword list of options, including host, port, virtual_host, and others. You may use Connection.open(host: your_host). Any settings which you don't provide will use the default setting.
The third form takes a well-formed RabbitMQ URI as a String, which is formed using a combination of host, port, username, password, and virtual host. Note that some of these values are optional in the URI.

Related

erlang: receive response from ssl

I added a new module (-behavior(gen_mod)) inside ejabberd and I was able to open a ssl connection to a server and send a message directly using the ssl connection(ssl:send() function). However, I am unable to receive response after this.
I tried using the receive option in erlang to catch messages, and still no luck.
I tried changing the module to be a stateful module by using the gen_server behavior and I still don't observe any handle_info calls with any message.
I could not get any response using ssl:recv/2 either.
Am I missing something? How do I asynchronously receive the response from the ssl socket in erlang?
Any pointers would be really appreciated. Thank you!
code: Adding only relevant parts of the code.
sendPacketToServer() ->
case ssl:connect(Gateway, Port, Options, ?SSL_TIMEOUT) of
{ok, Socket} ->
ssl:controlling_process(Socket, self()),
Packet = .....,
Result = ssl:send(Socket, Packet),
receiveMessage(),
ssl:close(Socket),
?INFO_MSG("~n~n~n~n Successfully sent payload to the server, result: ~p for the user: ~p", [Result, Username]);
{error, Reason} = Err ->
?ERROR_MSG("Unable to connect to the server: ~s for the user: ~p", [ssl:format_error(Reason), Username]),
Err
end
...
....
receiveMessage() ->
receive ->
{ssl, Msg, Data} -> % incoming msg from SSL, send it to process
......
{ssl_closed, Msg} -> % incoming msg from SSL, send it to process
.....
{ssl_error, Msg} -> % incoming msg from SSL, send it to process
.....
{ssl_passive, Msg} -> % incoming msg from SSL, send it to process
....
end.
Added the following code for gen_server: (when doing the following, i do not close the socket immediately, but it still does not work).
start(Host, Opts) ->
gen_mod:start_child(?MODULE, Host, Opts).
stop(Host) ->
gen_mod:stop_child(?MODULE, Host).
init([ServerHost|_]) ->
Opts = gen_mod:get_module_opts(ServerHost, ?MODULE),
start(ServerHost, Opts),
{ok, #state{host = ServerHost}}.
handle_call(Request, From, State) ->
?WARNING_MSG("Unexpected call from ~p: ~p", [From, Request]),
{noreply, State}.
handle_cast(Msg, State) ->
?WARNING_MSG("Unexpected cast: ~p", [Msg]),
{noreply, State}.
handle_info(Info, State) ->
?WARNING_MSG("Unexpected info: ~p", [Info]),
{noreply, State}.
terminate(_Reason, State) ->
ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.
I was able to overcome the problem by using a gen_server module, since it has explicit callbacks for any messages.

How to execute a command via SSH in Elixir?

I know I can open a ssh connection to a remote server:
:ssh.start
:ssh.connect("11.22.33.44", 22, user: "my_login123")
But how can I actually send a command and receive a response from it? I don't mean the interactive mode, I want to just send a command and receive a reply.
It might just be easier to use an Elixir library such as SSHex as this actually uses the erlang :ssh library but provides a much nicer interface as well as making it simpler to accomplish what you are after.
E.g. From the readme
{:ok, conn} = SSHEx.connect ip: '123.123.123.123', user: 'myuser'
SSHEx.cmd! conn, 'mkdir -p /path/to/newdir'
res = SSHEx.cmd! conn, 'ls /some/path'
Where the value of res will be the response from the command
EDIT
However, if you are set on using :ssh. Then you would need to use the :ssh_connection modules exec command which takes in the :ssh connection as a parameter.
See this link here for more detail on how to do this.
Here is an example that uses only :ssh and no external libraries. To run it you will need to have public key login set up on your target host. For more information, read the Erlang SSH User's Guide.
ssh-connect.exs
#! /usr/bin/env elixir
:ssh.start()
{:ok, conn} = :ssh.connect('raspi', 22,
silently_accept_hosts: true,
user: System.get_env("USER") |> to_charlist(),
user_dir: Path.join(System.user_home!(), ".ssh") |> to_charlist(),
user_interaction: false,
)
{:ok, chan} = :ssh_connection.session_channel(conn, :infinity)
:success = :ssh_connection.exec(conn, chan, 'uname -a', :infinity)
for _ <- 0..3 do
receive do
{:ssh_cm, ^conn, value} -> IO.inspect(value)
end
end
:ok = :ssh.close(conn)
Sample output
{:data, 0, 0, "Linux raspberrypi 4.4.50+ #970 Mon Feb 20 19:12:50 GMT 2017 armv6l GNU/Linux\n"}
{:eof, 0}
{:exit_status, 0, 0}
{:closed, 0}
Use SSHex library can very convenient to build SSH connection.
Here is example below:
defmodule SshDemo do
#moduledoc false
def connect do
{:ok, conn} = SSHEx.connect ip: 'xxx.xxx.xxx.xxx', user: 'root', password: 'xxxxx'
SSHEx.cmd! conn, 'mkdir -p newdir'
end
end
If you use mix to create your project. You just add dependency in mix.exs file and run-- "mix deps.get"
defp deps do
[{:sshex, "2.1.2"}]
end
Then, you may compile this module. use -- "mix deps.compile".
Run above example will make a folder named newdir in ~/ path

How to add Friend auth to Chestnut template

I've struggled for a few days trying to get a simple use of the security library, Friend, to work with the Chestnut clj/cljs template.
A POST request to the the /login uri is supposed log me in and allow access the protected routes like /role-user. But for some reason I am not able to login, the POST returns a 303 and routes me back to the root page.
I added the Friend middleware inside the http-handler function. Is this the correct place to apply this sort of middleware? I thought maybe the reload or api-defaults middleware could be messing up friend middleware? However, removing them does not fix things.
(def http-handler
(if is-dev?
(-> #'routes
(reload/wrap-reload)
(friend/authenticate
{:allow-anon? true
:login-uri "/login"
:default-landing-uri "/"
:unauthorized-handler #(-> (h/html5 [:h2 "You do not have sufficient privileges to access " (:uri %)])
resp/response
(resp/status 401))
:credential-fn (fn [x]
(let [res (creds/bcrypt-credential-fn #users x)]
(log/info x)
(log/info res)
res))
:workflows [(workflows/interactive-form)]})
(wrap-defaults api-defaults))
(wrap-defaults routes api-defaults)))
Based on the print statements I was able to figure out that the credential-fn function does get called on the POST request, with the correct params, and the function returns the correct (authenticated) result.
This http-handler is used as such
(defn run-web-server [& [port]]
(let [port (Integer. (or port (env :port) 10555))]
(print "Starting web server on port" port ".\n")
(run-jetty http-handler {:port port :join? false})))
(defn run-auto-reload [& [port]]
(auto-reload *ns*)
(start-figwheel))
(defn run [& [port]]
(when is-dev?
(run-auto-reload))
(run-web-server port))
For what it's worth, here are my routes.
(defroutes routes
(GET "/" req
(h/html5
misc/pretty-head
(misc/pretty-body
(misc/github-link req)
[:h3 "Current Status " [:small "(this will change when you log in/out)"]]
[:p (if-let [identity (friend/identity req)]
(apply str "Logged in, with these roles: "
(-> identity friend/current-authentication :roles))
"anonymous user")]
login-form
[:h3 "Authorization demos"]
[:ul
[:li (e/link-to (misc/context-uri req "role-user") "Requires the `user` role")]]
[:p (e/link-to (misc/context-uri req "logout") "Click here to log out") "."])))
(GET "/login" req
(h/html5 misc/pretty-head (misc/pretty-body login-form)))
(GET "/logout" req
(friend/logout* (resp/redirect (str (:context req) "/"))))
(GET "/role-user" req
(friend/authorize #{::users/user} "You're a user!")))
I figured it out. (wrap api-defaults) does not allow sessions and Friend is trying to use them. I should be using site-defaults instead. See ring middleware for more info.

logstash rabbitmq output never posts to exchange

I've got logstash running, and successfully reading in a file
rabbitmq is running, I'm watching the log, and I can see the web interface
I've configured logstash to output to a rabbitmq exchange... I think!
Here's the problem: nothing ever gets posted to the exchange, as seen in the web interface.
Any ideas?
My output config:
output {
rabbitmq {
codec => plain
host => localhost
exchange => yomtvraps
exchange_type => direct
}
file { path => "/tmp/heartbeat-from-logstash.log" }
}
UPDATE: I'm watching the rabbit log with
tail -F /usr/local/var/log/rabbitmq/rabbit\#localhost.log
As it turns out, the problem was that there was no routing key set for the exchange and queue.
A working config is:
output {
rabbitmq {
codec => plain
host => localhost
exchange => yomtvraps
exchange_type => direct
key => yomtvraps
# these are defaults but you never know...
durable => true
port => 5672
user => "guest"
password => "guest"
}
}
Here's a sample receiver code (using ruby "Bunny")
require "bunny"
conn = Bunny.new(:automatically_recover => false)
conn.start
ch = conn.create_channel
q = ch.queue("yomtvraps")
exchange = ch.direct("yomtvraps", :durable => true)
begin
puts " [*] Waiting for messages. To exit press CTRL+C"
q.bind(exchange, :routing_key => "yomtvraps").subscribe(:block => true) do |delivery_info, properties, body|
puts " [x] Received #{body}"
end
rescue Interrupt => _
conn.close
exit(0)
end
you rabbitmq's parameter seems not enough, username,password and port have not been configured.
You can configure two outputs, one is to rabbitmq, the other is to file for vertifying the log's creation and log stash is ok.
pay attention to the logstash's version(log stash, rabbitmq plugin), it gave me lots of trouble in my trial before (log stash to another redis server etc).
You could debug rabbitmq's log.
ps -ef|grep erl you could find the log file's path in the arguments.
Be sure that rabbitmq's web manager plugin is enabled, and firewall is rightly configured, then open rabbitmq's web manager, ipaddress:15672
check the exchange's type is ok (in this case 'direct' may be a correct choice), your message consumer is configured ok, and your consumer's queue has been been bound to the exchange correctly.
try to post the message to your consumer through web manager and ensure consumer work well.
Monitor your queue when log stash push log into your consumer.

net/http.rb:560:in `initialize': getaddrinfo: Name or service not known (SocketError)

##timestamp = nil
def generate_oauth_url
##timestamp = timestamp
url = CONNECT_URL + REQUEST_TOKEN_PATH + "&oauth_callback=#{OAUTH_CALLBACK}&oauth_consumer_key=#{OAUTH_CONSUMER_KEY}&oauth_nonce=#{NONCE} &oauth_signature_method=#{OAUTH_SIGNATURE_METHOD}&oauth_timestamp=#{##timestamp}&oauth_version=#{OAUTH_VERSION}"
puts url
url
end
def sign(url)
Base64.encode64(HMAC::SHA1.digest((NONCE + url), OAUTH_CONSUMER_SECRET)).strip
end
def get_request_token
url = generate_oauth_url
signed_url = sign(url)
request = Net::HTTP.new((CONNECT_URL + REQUEST_TOKEN_PATH),80)
puts request.inspect
headers = { "Authorization" => "Authorization: OAuth oauth_nonce = #{NONCE}, oauth_callback = #{OAUTH_CALLBACK}, oauth_signature_meth od = #{OAUTH_SIGNATURE_METHOD}, oauth_timestamp=#{##timestamp}, oauth_consumer_key = #{OAUTH_CONSUMER_KEY}, oauth_signature = #{signed_url}, oauth_versio n = #{OAUTH_VERSION}" }
request.post(url, nil,headers)
end
def timestamp
Time.now.to_i
end
I am trying to do what oauth does in an attempt to understand how to use the Authorization headers. I am also getting the following error. I am trying to connect to the linkedin API.
/usr/lib/ruby/1.8/net/http.rb:560:in 'initialize': getaddrinfo: Name or service not known (SocketError)
I would really appreciate it if someone could nudge me in the right direction.
"Name or service not known" is a socket-level error which usually points to either an invalid IP address/DNS hostname, or an unregistered port name (e.g. telnet the.host.name service where service is not a registered service name.)
Check that CONNECT_URL holds a valid URL.
EDIT: I'm not a Ruby programmer, but I wouldn't mind betting that Net::HTTP.new requires a hostname (e.g. www.facebook.com) as the first argument, not a complete URL (e.g. www.facebook.com/login.php?method=oauth).
You also get this error when you have no internet connection since a DNS lookup is often the first thing that happens when establishing a TCP connection using a hostname.
Unplug your network cable and try:
Socket.getaddrinfo("www.example.com", "http")
# => SocketError: getaddrinfo: nodename nor servname provided, or not known