Ruby cannot get Azure VM metadata from Azure Instance Metadata service - ruby

According to MS documentation https://learn.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service
Azure provide instance metadata service at "http://169.254.169.254/metadata/instance?api-version=2017-08-01" .
But I failed to get the metadata on one of my VMs with ruby. While, I can get the metadata with PowerShell.
OS Environment: Windows Server 2012R2.
Ruby version: ruby 2.5.3p105 (2018-10-18 revision 65156) [x64-mingw32]
PowerShell version: 4.0
PowerShell code:
Invoke-WebRequest -Headers #{"Metadata"="true"} -URI "http://169.254.169.254/metadata/instance?api-version=2017-08-01"
response from powershell code:
StatusCode : 200
StatusDescription : OK
...
Ruby Code:
require 'net/http'
AZURE_METADATA_ADDR = "169.254.169.254".freeze unless defined?(AZURE_METADATA_ADDR)
AZURE_METADATA_URL = "/metadata/instance?api-version=2017-08-01".freeze unless defined?(AZURE_METADATA_URL)
def http_get(uri)
conn = Net::HTTP.start(AZURE_METADATA_ADDR)
conn.read_timeout = 6
conn.get(uri, { "Metadata" => "true" })
end
puts "Fetching metadata from host #{AZURE_METADATA_ADDR} at #{AZURE_METADATA_URL}"
response = http_get(AZURE_METADATA_URL)
puts response
Response from Ruby code:
Fetching metadata from host 169.254.169.254 at /metadata/instance?api-version=2017-08-01
#<Net::HTTPNotFound:0x0000000002372128>
Anyone can advice how to continue troubleshooting this issue? Is the problem inside Ruby?
PS. this is an embedded Ruby provided by chef client

So, this worked for me:
require 'net/http'
require 'json'
http = Net::HTTP.new('169.254.169.254', '80')
request = Net::HTTP::Get.new('/metadata/instance?api-version=2020-06-01')
request['Metadata'] = 'true'
response = http.request(request)
JSON.parse(response.body)
... on Ruby 2.5.5. The only obvious difference I see is the explicit port setting to '80'.

It turned out to be an environment variable "http_proxy" is preventing ruby from accessing the endpoint. The resolution is to set "no_proxy" environment variable and set '169.254.169.254' in the list of "no_proxy".
Ruby honors "http_proxy" while other languages like powershell and java don't honor it.

Related

Can't create new RavenDB database with Ruby rest_client

I'm trying to create a new RavenDb using the Ruby rest_client but I continually get 400 errors. Below is my simple script which I'm running on the local machine. I have also tried the PUTS command but it results in the same error. Thank you for your help!
Windows Server 2012
RavenDB version 2261
require 'rest_client'
require 'json'
config = Hash.new
config["Settings"] = Hash.new
config["Settings"]["Raven/DataDir"] = "~\\Databases\\TempWebState2"
config["Settings"]["Raven/ActiveBundles"] = "PeriodicBackup;DocumentExpiration"
RestClient.post "http://localhost:8081/Raven/Databases/TempWebState2", config.to_json
To fix this I had to change the RestClient command to put and change the URL to admin/databases/. Also Raven/AnonymousAccess had to be set to Admin
RestClient.put "http://localhost:8081/admin/databases/TempWebState2", config.to_json

Ruby 2.0p0 and XMLRPC::Client

I am experiencing issues with Ruby 2.0p0 and XMLRPC::Client. When I run the code below in 2 different versions of ruby, I get a correct response on 1.9.3 but an error with 2.0.0. Anyone with the same issues? Is the solution just not to use the newest version of ruby or is there a workaround?
require "xmlrpc/client"
server = XMLRPC::Client.new2('http://api.flickr.com/services/xmlrpc/')
begin
res = server.call('flickr.test.echo')
puts res
rescue XMLRPC::FaultException => e
puts e.faultCode
puts e.faultString
end
Using ruby-1.9.3-p392 [ x86_64 ]
I get the correct response from flickr, since I didn't supply an API key:
100
Invalid API Key (Key has invalid format)
Using ruby-2.0.0-p0 [ x86_64 ]
I get an error from ruby saying "Wrong size. Was 365, should be 207 (RuntimeError)"
/home/luisramalho/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/xmlrpc/client.rb:506:in `do_rpc': Wrong size. Was 365, should be 207 (RuntimeError)
from /home/luisramalho/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/xmlrpc/client.rb:281:in `call2'
from /home/luisramalho/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/xmlrpc/client.rb:262:in `call'
from xmlrpc.rb:5:in `<main>'
I had a similar problem accessing a different xml rpc api (upcdatabase.com's) (seriously, who still uses xml rpc apis?) with ruby2.
My solution was to use a different xmlrpc library than ruby's default. LibXML-XMLRPC. It uses c extentions and is supposed to be faster than the standard library one, but it was last updated in 2008, so who knows how true that statement is today.
This is what my code ended up being that worked.
require 'xml/libxml/xmlrpc'
require 'net/http'
net = Net::HTTP.new("www.upcdatabase.com", 80)
server = XML::XMLRPC::Client.new(net, "/xmlrpc")
result = server.call('lookup', 'rpc_key' => "YOLOSWAG", 'upc' => "071160055506")
Hope this helps.
I proposed a patch for this. Lets see what the team thinks about it.
https://github.com/ruby/ruby/pull/308

Ruby http client with "native" ntlm proxy support

I am looking for a ruby HTTP client gem that supports NTLM proxy authentication "natively" - not through cntlm or similar local proxies.
Any hints appreciated.
A little digging unearthed Typhoeus:
require 'typhoeus'
e=Typhoeus::Easy.new
e.url="http://www.google.com/"
e.proxy = {:server => "1.2.3.4:80"}
e.proxy_auth={:username => "user", :password => 'password'}
e.perform
Typhoeus seems to have been repurposed. The libcurl wrapper is now Ethon (https://github.com/typhoeus/ethon).
I've successfully authenticated with an NTLM proxy using Curb (https://github.com/taf2/curb), another libcurl wrapper:
require 'spec_helper'
require 'curl'
describe Curl do
it 'should connect via an ISA proxy' do
c = Curl::Easy.new('http://example.com/') do |curl|
curl.proxy_url = 'http://username:password#localhost:8080'
curl.proxy_auth_types = Curl::CURLAUTH_NTLM
end
c.perform
headers = c.header_str.split("\r\n")
#puts headers.inspect
headers.should include 'X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.19'
end
end
Change your settings and assertion as required.
You can do ntlm with Typhoeus and Ethon - depending how many features you need. Typhoeus has more than Ethon, but Ethon is more powerful as it is more low level.
require 'ethon'
easy = Ethon::Easy.new(
url: "http://www.google.com/",
proxy: "1.2.3.4:80",
proxyuserpwd: "user:password",
proxyauth: "ntlm"
)
easy.perform
Typhoeus accepts the same options:
require 'typhoeus'
request = Typhoeus::Request.new(
"http://www.google.com/",
proxy: "1.2.3.4:80",
proxyuserpwd: "user:password",
proxyauth: "ntlm"
)
request.run
I wrote both code examples without testing them b/c I lack a proxy and with the latest Typhoeus/Ethon versions (which you don't have already according to your example).

Automatically adding proxy to all HTTP connections in ruby

I have an application that initiates multiple HTTP connections and I would like to add a proxy to all connections.
The application is using net/HTTP, TCP sockets and open-uri so ideally I would like to be able to patch all connections initiated from those libraries instead of adding it manually to each and every location in the code that initiates a connection.
Is there a way to accomplish that (on Ruby 1.9.2)?
Open URI uses the HTTP_PROXY environment variable
Here is an article on how to use it on both windows and unix variants.
http://kaamka.blogspot.com/2009/06/httpproxy-environment-variable.html
you can also set it directly in ruby using the ENV hash
ENV['HTTP_PROXY'] = 'http://username:password#hostname:port'
the net/http documentation says not to rely on the environment and set it each time
require 'net/http'
require 'uri'
proxy_host = 'your.proxy.host'
proxy_port = 8080
uri = URI.parse(ENV['http_proxy'])
proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo
Net::HTTP::Proxy(proxy_host, proxy_port,
proxy_user, proxy_pass).start('www.example.com') {|http|
# always connect to your.proxy.addr:8080 using specified username and password
:
}
from http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTP.html
Yes and mechanize does too (this is for the 1.0.0 verison)
require 'mechanize'
url = 'http://www.example.com'
agent = Mechanize.new
agent.user_agent_alias = 'Mac Safari'
agent.set_proxy('127.0.0.1', '3128')
#page = agent.get(:url => url)

SOAP - Need to understand the error I get

I'm trying to initialize a variable called proxy like this:
proxy = Savon::Client.new "http://192.168.1.1:8080"
The thing is, when I run my code, I only get the error:
NameError: uninitialized constant NameOfTheClass::Savon
Thanks for any help!
PD: I'm using Ruby 1.9.2
PD2: I'm trying to run this from console.
You found probably the documentation for versions < 0.8.x.
Unfortunately the syntax has changed! Have a look here: https://github.com/rubiii/savon/blob/master/README.md
Savon works with blocks now.
Your example should now look like this
require 'savon'
require 'pp'
proxy = Savon::Client.new do
wsdl.document = "http://my.webservices.net/service?wsdl"
end
pp proxy.wsdl.soap_actions

Resources