Ruby/Grape required parameters on a certain condition - ruby

For one of my methods the following isn't working. I pretty much copied everything straight out of the official documentation:
params do
requires :authenticationType, type: Array[String], values: ['LOCAL', 'AD']
given authenticationType: ->(val) { val == 'LOCAL' } do
requires :admin, type: String, allow_blank: false, regexp: /^[\w\.\#-]{1,64}$/
requires :password, type: String, allow_blank: false, regexp: /^[\w\.\#-]{1,64}$/
end
end
It is giving an error on the "given" line. Anyone know what is wrong. My goal: ONLY if 'authenticationType' == 'LOCAL' should the user provide 'admin' and 'password'
error:
[ 2017-03-03 00:39:18.4848 14970/7f5d0603f700
age/Cor/App/Implementation.cpp:304 ]: Could not spawn process for
application /vagrant/masterapi: An error occurred while starting up
the preloader. Error ID: 0bd79149 Error details saved to:
/tmp/passenger-error-3OYsdJ.html Message from application:
Grape::Exceptions::UnknownParameter
(Grape::Exceptions::UnknownParameter)
/usr/local/lib/ruby/gems/2.3.0/gems/grape-0.16.2/lib/grape/dsl/parameters.rb:170:in
block in given'
/usr/local/lib/ruby/gems/2.3.0/gems/grape-0.16.2/lib/grape/dsl/parameters.rb:169:in
each'
/usr/local/lib/ruby/gems/2.3.0/gems/grape-0.16.2/lib/grape/dsl/parameters.rb:169:in
given' /vagrant/masterapi/controllers/papi_controller.rb:93:in
block in '

The 'given' accepts proc only since grape version 0.17, implemented in merge request (MR) 1443. So you should either update, or if that's not feasible, try back-porting this MR to 0.16.2.
Here's the README for your version.
Also, in your example, authenticationType param is of type Array[String], so (at least in grape 0.17), the proc will receive a Hashie::Array.
This means:
->(val) { val == 'LOCAL' }
should be
->(val) { val.first == 'LOCAL' }

Related

The "error_marshaling_enabled" setting seems to be always enabled

When I run this code:
$client->evaluate('
box.session.settings.error_marshaling_enabled = false
box.error{code = 42, reason = "Foobar", type = "MyError"}
');
regardless of the value of error_marshaling_enabled I always get a response with a new (extended) error format:
[
49 => 'Foobar',
82 => [
0 => [
0 => [
0 => 'CustomError',
2 => 3,
1 => 'eval',
3 => 'Foobar',
4 => 0,
5 => 42,
6 => [
'custom_type' => 'MyError',
],
],
],
],
],
Why is that?
Short answer.
error_marshaling_enabled option affects only how error objects are encoded in response body (48, IPROTO_DATA). It does not affect how they are returned as exceptions, in the response header (82, IPROTO_ERROR).
Long answer.
In Tarantool an error object can be returned in 2 ways: as an exception and as an object. For example, this is how to throw an error as exception:
function throw_error()
box.error({code = 1000, reason = "Error message"})
-- Or
error('Some error string')
end
This is how to return it as an object:
function return_error()
return box.error.new({code = 1000, reason = "Error message"})
end
If the function was called remotely, using IPROTO protocol via a connector like netbox, or PHP connector, or any other one, the error return way affects how it is encoded into MessagePack response packet. When the function throws, and the error reaches the top stack frame without being caught, it is encoded as IPROTO_ERROR (82) and IPROTO_ERROR_24 (49).
When the error object is returned as a regular value, not as an exception, it is encoded also as a regular value, inside IPROTO_DATA (48). Just like a string, a number, a tuple, etc.
With encoding as IPROTO_ERROR/IPROTO_ERROR_24 there is no much of a configuration space. Format of these values can't be changed. IPROTO_ERROR is always returned as a MessagePack map, with a stack of errors in it. IPROTO_ERROR_24 is always an error message. The IPROTO_ERROR_24 field is kept for compatibility with connectors to Tarantool versions < 2.4.1.
With encoding as a part of IPROTO_DATA you can choose serialization way using error_marshaling_enabled option. When it is true, errors are encoded as MessagePack extension type MP_EXT, and contain the whole error stack, encoded exactly like IPROTO_ERROR value. When the option is false (default behaviour in 2.4.1), the error is encoded as a string, MP_STR, which is the error's message. If there is a stack of errors, only the newest error is encoded.
error_marshaling_enabled option exists for backward compatibility, in case your application on Tarantool wants to be compatible with old connectors, which don't support MP_EXT encoded errors.
In Tarantool < 2.4.1 errors were encoded into result MessagePack as a string with error message, and error stacks didn't exist at all. So when the new format and the error stacks feature were introduced, making the new format default would be a too radical change breaking the old connectors.
Consider these examples of how error marshaling affects results. I use Tarantool 2.4.1 console here, and built-in netbox connector. The code below can be copy pasted into the console.
First instance:
box.cfg{listen = 3313}
box.schema.user.grant('guest', 'super')
function throw_error()
box.error({code = 1000, reason = "Error message"})
end
function return_error()
return box.error.new({code = 1000, reason = "Error message"})
end
Second instance:
netbox = require('net.box')
c = netbox.connect(3313)
Now I try to call the function on the second instance:
tarantool> c:call('throw_error')
---
- error: Error message
...
The c:call('throw_error') threw an exception. If I catch it using pcall() Lua function, I will see the error object.
tarantool> ok, err = pcall(c.call, c, 'throw_error')
tarantool> err:unpack()
---
- code: 1000
base_type: ClientError
type: ClientError
message: Error message
trace:
- file: '[string "function throw_error()..."]'
line: 2
...
As you can see, I didn't set error_marshaling_enabled, but got the full error. Now I will call the other function, without exceptions. But the error object won't be full.
tarantool> err = c:call('return_error')
tarantool> err
---
- Error message
...
tarantool> err:unpack()
---
- error: '[string "return err:unpack()"]:1: attempt to call method ''unpack'' (a nil
value)'
...
The error was returned as a mere string, error message. Not as an error object. Now I will turn on the marshaling:
tarantool> c:eval('box.session.settings.error_marshaling_enabled = true')
---
...
tarantool> err = c:call('return_error')
---
...
tarantool> err:unpack()
---
- code: 1000
base_type: ClientError
type: ClientError
message: Error message
trace:
- file: '[C]'
line: 4294967295
...
Now the same function returned the error in the new format, more featured.
On the summary: error_marshaling_enabled affects only returned errors. Not thrown errors.

Why does puppet think my custom fact is a string?

I am trying to create a custom fact I can use as the value for a class parameter in a hiera yaml file.
I am using the openstack/puppet-keystone module and I want to use fernet-keys.
According to the comments in the module I can use this parameter.
# [*fernet_keys*]
# (Optional) Hash of Keystone fernet keys
# If you enable this parameter, make sure enable_fernet_setup is set to True.
# Example of valid value:
# fernet_keys:
# /etc/keystone/fernet-keys/0:
# content: c_aJfy6At9y-toNS9SF1NQMTSkSzQ-OBYeYulTqKsWU=
# /etc/keystone/fernet-keys/1:
# content: zx0hNG7CStxFz5KXZRsf7sE4lju0dLYvXdGDIKGcd7k=
# Puppet will create a file per key in $fernet_key_repository.
# Note: defaults to false so keystone-manage fernet_setup will be executed.
# Otherwise Puppet will manage keys with File resource.
# Defaults to false
So wrote this custom fact ...
[root#puppetmaster modules]# cat keystone_fernet/lib/facter/fernet_keys.rb
Facter.add(:fernet_keys) do
setcode do
fernet_keys = {}
puts ( 'Debug keyrepo is /etc/keystone/fernet-keys' )
Dir.glob('/etc/keystone/fernet-keys/*').each do |fernet_file|
data = File.read(fernet_file)
if data
content = {}
puts ( "Debug Key file #{fernet_file} contains #{data}" )
fernet_keys[fernet_file] = { 'content' => data }
end
end
fernet_keys
end
end
Then in my keystone.yaml file I have this line:
keystone::fernet_keys: '%{::fernet_keys}'
But when I run puppet agent -t on my node I get this error:
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Evaluation Error: Error while evaluating a Function Call, "{\"/etc/keystone/fernet-keys/1\"=>{\"content\"=>\"xxxxxxxxxxxxxxxxxxxx=\"}, \"/etc/keystone/fernet-keys/0\"=>{\"content\"=>\"xxxxxxxxxxxxxxxxxxxx=\"}}" is not a Hash. It looks to be a String at /etc/puppetlabs/code/environments/production/modules/keystone/manifests/init.pp:1144:7 on node mgmt-01
I had assumed that I had formatted the hash correctly because facter -p fernet_keys output this on the agent:
{
/etc/keystone/fernet-keys/1 => {
content => "xxxxxxxxxxxxxxxxxxxx="
},
/etc/keystone/fernet-keys/0 => {
content => "xxxxxxxxxxxxxxxxxxxx="
}
}
The code in the keystone module looks like this (with line numbers)
1142
1143 if $fernet_keys {
1144 validate_hash($fernet_keys)
1145 create_resources('file', $fernet_keys, {
1146 'owner' => $keystone_user,
1147 'group' => $keystone_group,
1148 'subscribe' => 'Anchor[keystone::install::end]',
1149 }
1150 )
1151 } else {
Puppet does not necessarily think your fact value is a string -- it might do, if the client is set to stringify facts, but that's actually beside the point. The bottom line is that Hiera interpolation tokens don't work the way you think. Specifically:
Hiera can interpolate values of any of Puppet’s data types, but the
value will be converted to a string.
(Emphasis added.)

Getting error Aws::S3::Errors::InvalidBucketName when creating bucket

I am trying to create a bucket, with help of aws-sdk-ruby from ruby console. Following is the code I am running in my console:
Aws.config.update({
:region => "myRegion",
:credentials => Aws::Credentials.new("access_key", "secret_key"),
:endpoint => "http://Ip",
:force_path_style => true
})
bucket_name = "abc"
bucket = s3.bucket(bucket_name)
bucket.create({ acl: "authenticated-read", grant_full_control: "GrantFullControl"})
Last line gives this error:
Aws::S3::Errors::InvalidBucketName:
I dont see this error in the documentation here. When can one get such error and how to resolve this?
I was also getting this error.. the main reason why was getting this error because my bucket name was starting with capital letter.. Bucket name always starts with lowercase ..

Can't use RubyPress gem gives getaddrinfo: No such host is known. (SocketError)

I am trying to use a gem called RubyPress which allows to use Wordpress' xml-rpc api from ruby. But it always gives me this error:
getaddrinfo: No such host is known. (SocketError)
Here's my code:
require 'rubypress'
wp = Rubypress::Client.new(:host => "localhost/wordpress",
:username => "admin",
:password => "admin")
p wp.getOptions
I am able to connect fine using another gem called wp_rpc but rubypress doesn't seem to work. Rubypress seems to be maintained so i want to use it, it also seems to have more features.
Also, even when i try connecting to a real site, it gives a 403 error which is very strange.
I am running the server using XAMPP on Windows 7. How can I get it to work?
UPDATE:
Here's the code i used for posting, now it doesn't seem to post. Not sure where i went wrong.
wp.newPost( :blog_id => 0, # 0 unless using WP Multi-Site, then use the blog id
:content => {
:post_status => "publish",
:post_date => Time.now,
:post_content => "This is the body",
:post_title => "RubyPress is the best!",
:post_name => "/rubypress-is-the-best",
:post_author => 1, # 1 if there is only the admin user, otherwise the user's id
:terms_names => {
:category => ['Category One','Category Two','Category Three'],
:post_tag => ['Tag One','Tag Two', 'Tag Three']
}
}
)
Note: This is from the rubypress github page. Those categories and tags are not present on the blog, is that the reason?
host must be a host name (e.g. "localhost" in this particular case, or, say, "google.com"):
require 'rubypress'
wp = Rubypress::Client.new(host: "localhost",
username: "admin",
password: "admin",
path: "/wordpress/xmlrpc.php")
Probably, you might need to tune the path parameter up to point exactly to where WP’s RPC endpoint is to be found.

How to iterate over a string to construct nagios_service check as exported resource?

I wrote a custom fact, which returns a comma separated list of addr:port, like this:
sb_intl_conn => sbcms-t:22,sbsql05-wvuk-inst5:1434,sborc07-uk-t:1533,..,..,..
The number of elements in the string varies from node to node. I need to do a Nagios tcp-port-check on each of them. I think sb_intl_conn.split(",") will turn this string into an array and then how can I iterate over it to do something like this?
##nagios_service { "check_stat_${::fqdn}_${addr}_${port}":
use => 'generic-service',
check_command => "remote-nrpe-tcp-check!${addr}!${port}",
service_description => "V2::CON: ${addr} [Palms]",
display_name => "Connection check: ${addr}:${port}",
servicegroups => 'batch-worker',
hostgroup_name => 'batch-job',
}
Any help would be greatly appreciated. Cheers!!
Update: 1
I was tying to simulator iamauser's suggestion but not been able to get my head around it yet. This is what I did: in my foo.pp:
class test::foo {
define bar {
$var1 = inline_template("<%= scope.lookupvar($name).split(':').first.to_s.chomp %>")
$var2 = inline_template("<%= scope.lookupvar($name).split(':').last.to_s.chomp %>")
notify {"${var1}_${var2}": }
}
}
and then in my node.pp:
$ifs = ['abc.com:80','xyz.co.uk:1512']
test::foo::bar {$ifs:}
which throws in these error on the node:
err: Could not retrieve catalog from remote server: Error 400 on SERVER: Failed to parse inline template: Could not find value for 'abc' in 65 at /etc/puppet/services/test/manifests/foo.pp:4 on node jobserver-01.local.cloud.uk
warning: Not using cache on failed catalog
err: Could not retrieve catalog; skipping run
Don't understand what I'm doing wrong. And why is Could not find value for 'abc'; not abc.com? Any idea?? Cheers!!
Update: 2
I ended up using heira and decided to give a try to the original "array of hashes" idea and having some problem implementing:
This is what I have in heira:
hiera -d -c /etc/puppet/hiera.yaml nag_chk m_env=talend s_env=local
[ ... ]
DEBUG: Thu Mar 21 12:28:02 +0000 2013: Got answer for key nagi_chk, final answer
DEBUG: Thu Mar 21 12:28:02 +0000 2013: Answer after outer loop = archimedes-db-02.svc.ft.com:1521 ftftp01-uvln-uk-p:22 www.google.com:80 ftaps01-lvpr-uk-local:8080
archimedes-db-02:1521 ftftp01-uvln-uk-p:22 google.com:80
Then, in my foo.pp
class test::foo {
define bar2 () {
$var1 = $name['addr']
$var2 = $name['port']
notify {"*** ${var1}_${var2} *********": }
}
}
and my node.pp:
$array_chk = hiera('nag_chk')
$urls = inline_template("<%= '$array_chk'.split(' ').map{|kv| v1,v2 = kv.split(':'); {'addr' => v1, 'port' => v2}} -%>")
test::foo::bar2 {$urls:}
and as usual, I get an error:
err: Could not retrieve catalog from remote server: Error 400 on
SERVER: name is not an hash or array when accessing it with 0 at
/etc/puppet/services/talend/talend/manifests/foo.pp:10 on node
talend-jobserver-01.local.cloud.ft.com warning: Not using cache on
failed catalog err: Could not retrieve catalog; skipping run
What's am I doing wrong? As far as I can see, the "array of hash" in right format in the irb console:
irb(main):001:0> STRING = "archimedes-db-02:1521 ftftp01-uvln-uk-p:22 google.com:80"
=> "archimedes-db-02:1521 ftftp01-uvln-uk-p:22 google.com:80"
irb(main):003:0>
irb(main):002:0> STRING.split(' ').map{|kv| v1,v2 = kv.split(':'); {'addr' => v1, 'port' => v2}}
=> [{"addr"=>"archimedes-db-02", "port"=>"1521"}, {"addr"=>"ftftp01-uvln-uk-p", "port"=>"22"}, {"addr"=>"google.com", "port"=>"80"}]
any further thought(s)? Cheers!!
This example may help solve your particular case.
$foo = [{"addr" => "bar", "port" => "1"},
{"addr" => "bat", "port" => "2"}]
testmod::bar {$foo:}
define testmod::bar () {
$var1 = $name["addr"]
$var2 = $name["port"]
notify {"${var1}_${var2}": }
}
Put the nagios type inside the define type. You may have to change the csv to a hash.
UPDATE: Added after #MacUsers update. The following works for me :
$foo = ["abc.com:80","xyz.co.uk:1512"]
testmod::bar {$foo:}
define testmod::bar () {
$var1 = inline_template("<%= '$name'.split(':').first.to_s.chomp %>")
$var2 = inline_template("<%= '$name'.split(':').last.to_s.chomp %>")
notify {"${var1}_${var2}": }
}
Running puppet agent gives me this :
Notice: /Stage[main]/Testmodule/Testmodule::Testmod::Bar[abc.com:80]/Notify[abc.com_80]/message: defined 'message' as 'abc.com_80'
Notice: xyz.co.uk_1512
Notice: /Stage[main]/Testmodule/Testmodule::Testmod::Bar[xyz.co.uk:1512]/Notify[xyz.co.uk_1512]/message: defined 'message' as 'xyz.co.uk_1512'

Resources