Hi I would like to do something like this...
DEV_HOST = "some hostname"
DEV_INST = "2"
DEV_TEST_HOST = "some other hostname"
DEV_TEST_INST = "3"
get_values(DEV_TEST_HOST)
def get_values(environment) {
println environment
println ${environment}_INST
}
Desired output should be:
some other hostname
3
Is it even possible?
Thanks!
You can not pass the value to a function and then introspect what the
variable was named when calling that function (or let's say, if it's
possible, then it's just so many levels of overkill).
Assuming you have some sort of map (e.g. the environment), you pass in
the key you are interested instead. Then do all the transformations on
the key and then ask the environment for the key. E.g.
def env = [
DEV_TEST_HOST: "some other hostname" ,
DEV_TEST_INST: "3",
]
get_values(env, "DEV_TEST_HOST")
def get_values(env, key) {
println env[key]
println env[key.replace('HOST', 'INST')]
}
In case you want to reorganize you map in more clear way, you can use this:
env = [
DEV: [
HOST: "some hostname",
INST: "2"
],
DEV_TEST: [
HOST: "some other hostname",
INST: "3"
]
]
def get_values(v) {
println env[v].HOST
println env[v]."HOST"
println env[v].INST
println env[v]."INST"
}
get_values("DEV")
get_values("DEV_TEST")
Related
I need to deploy a bash script using aws_imagebuilder_component resource; I am using a template_file to populate an array inside my script. I am trying to figure out the correct way to render the template inside the imagebuilder_component resource.
I am pretty sure that the formatting of my script is the main issue :(
This is the error that I keep getting, seems like an issue with the way I am formatting the script inside the yml, can you please assist? I have not worked with image builder previously or with yamlencode.
Error: error creating Image Builder Component: InvalidParameterValueException: The value supplied for parameter 'data' is not valid. Failed to parse document. Error: line 1: cannot unmarshal string phases:... into Document.
# Image builder component
resource "aws_imagebuilder_component" "devmaps" {
name = "devmaps"
platform = "Linux"
data = yamlencode(data.template_file.init.rendered)
version = "1.0.0"
}
# template_file
data "template_file" "init" {
template = "${file("${path.module}/myscript.yml")}"
vars = {
devnames= join(" ", local.devnames)
}
}
# myscript.yml
schemaVersion: 1.0
phases:
- name: build
steps:
- name: pre-requirements
action: ExecuteBash
inputs:
commands: |
#!/bin/bash
for i in `seq 0 6`; do
nvdev="/dev/nvm${i}n1"
if [ -e $nvdev ]; then
mapdev="${devnames[i]}"
if [[ -z "$mapdev" ]]; then
mapdev="${devnames[i]}"
fi
else
ln -s $nvdev $mapdev
echo "symlink created: ${nvdev} to ${mapdev}"
fi
fi
done
#Marko
# tfvars
vols = {
data01 = {
devname = "/dev/xvde"
size = "200"
}
data01 = {
devname = "/dev/xvdf"
size = "300"
}
}
Variables.tf: populating this list "devnames" from the map object "vols", shown above
locals {
devnames = ([ for key, value in var.vols: value.devname ])
}
main: template_file is using the list "devnames" to assign its values to devnames variable; devnames variables is used inside myscript.yml
devnames = join(" ", local.devnames)
At this point, everything is working w/o issues
But when this is executed, it fails and complains about the formatting of the template that was rendered using myscript.yml.
I am doing something wrong here that I cannot figure it out
## Image builder component
resource "aws_imagebuilder_component" "devmaps" {
name = "devmaps"
platform = "Linux"
data = yamlencode(data.template_file.init.rendered)
version = "1.0.0"
}
For various reasons I have a chef recipe that I want to use add multiple groups to a system with. I've defined a data bag with a key / value structure that provides the group name as the key and the guid as the value eg:
{
"id": "default_groups",
"group": {
"sales": "200",
"marketing": "800",
"csr": "1000",
"devel": "9000",
"scientists": "500"
}
}
I was wanting to use the group resource in a for each loop but I don't seem to be referencing the data in the data bag correctly:
user_groups = data_bag_item('groups', 'default_groups')
%w{"#{user_groups['group']}"}.each do |usr|
group "#{usr}.key" do
action :create
gid "#{usr}.value"
end
end
Can anyone explain what I'm doing wrong with my syntax?
The error output from the chef run is as follows:
ERROR: group["#{user_groups['group']}".key] (cookbook_groups::recipe_groups line 10) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '3'
---- Begin output of ["groupadd", "-g", "\"\#{user_groups['group']}\".value", "\"\#{user_groups['group']}\".key"] ----
STDOUT:
STDERR: groupadd: invalid group ID '"#{user_groups['group']}".value'
---- End output of ["groupadd", "-g", "\"\#{user_groups['group']}\".value", "\"\#{user_groups['group']}\".key"] ----
Ran ["groupadd", "-g", "\"\#{user_groups['group']}\".value", "\"\#{user_groups['group']}\".key"] returned 3
You cannot combine string interpolation, word arrays and array/hash access like that.
This might work:
user_groups = data_bag_item('groups', 'default_groups')
user_groups['group'].each do |key, value|
group key do
action :create
gid value
end
end
Apparently, %w does not do what you think:
▶ %w{"#{user_groups['group']}"}
#⇒ ["\"\#{user_groups['group']}\""]
You probably need just:
user_groups['group'].each
or like.
I'm trying to pass attributes to my recipe at run-time of chef client.
following is my default.rb attribute file:
if node['os'] == 'windows'
if node.attribute?('temp')
default['param']['name'] = node['temp']['tempname']
else node.attribute?('base')
default['param']['name'] = node['base']['nodename']
end
end
I first ran the chef-client with only the base attribute defined in the node.json file. My node.json looked like :
{
"base": {
"nodename": "John"
}
}
Chef-client run was successfull and the attribute was set accordingly. i.e.
default['param']['name'] = "John"
Than I ran chef-client with both base and temp attribute defined in the node.json.
And here is my node.json file :
{
"base": {
"nodename": "John"
},
"temp": {
"tempname": "Mike"
}
}
Chef-client again ran successfully and the attribute was set accordingly.
default['param']['name'] = "Mike"
The problem is when I run the chef-client again and pass only base attribute from the node.json file(see below for the file), the code doesn't seem to enter the else loop. It just runs the `if' loop with old value for temp attribute(Mike).
{
"base": {
"nodename": "John-2"
}
}
Any ideas to where I'm going wrong.
The second time you ran chef-client, it saved the node[:temp][:nodename] attribute to the node object on the Chef server.
When you ran chef-client again, it loaded the node's attributes back from the server before reaching the attributes/default.rb file, so node[:temp][:nodename] was set when it reached the conditions.
I'm not sure what you're trying to achieve, but it would probably be best to explicitly tell which attribute you want to use through another attribute (and maybe assume a default for it), such as:
default[:name_attribute] = 'temp'
then,
if node['os'] == 'windows'
if node['name_attribute'] == 'temp'
default['param']['name'] = node['temp']['tempname']
else
default['param']['name'] = node['base']['nodename']
end
end
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'
I want to know how to use
NSScriptCommandDescription initWithSuiteName:commandName:dictionary:, esp. how the dictionary is supposed to look like.
It would be nice to see a simple example for a command with a single parameter of type NSString and a return value of type NSString.
I think the documentation about how the dictionary should look like can be found here, esp in "Table B-8, Command dictionary".
However, I am trying with this example and it doesn't work (returns nil):
cmdDesc = NSScriptCommandDescription.alloc().initWithSuiteName_commandName_dictionary_(
"Standard Suite",
"execPython",
{
"CommandClass": "NSScriptCommand", # default behavior
"AppleEventCode": "expy", # 4-char code
"Type": "text", # return-type
"ResultAppleEventCode": "NSString", # return-type
"Arguments": [{
"Type": "NSString",
"AppleEventCode": "data"
}]
}
)
(Note: I really want to know exactly that here; I don't want to know how to register scripting definitions or do other stuff with this question.)
I know this is a VERY old questions but I have stumble upon this and it seems that the this statckoverflow question is the most common result when doing a google search on how to use the NSScriptCommandDescription with arguments.
The code from the accepted answer is correct EXCEPT on how the arguments value is created. The arguments value must be a dictionary that maps argument names with argument descriptions. Using the accepted answer code as an example, in order to pass arguments, our dictionary should look as follows:
cmdDesc = NSScriptCommandDescription.alloc().initWithSuiteName_commandName_dictionary_(
"Chromium Suite",
"exec Python",
{
"Name": "exec Python",
"CommandClass": "NSScriptCommand", # default behavior
"AppleEventCode": "ExPy", # 4-char code
"AppleEventClassCode": "CrSu",
"Type": "NSString", # return-type
"ResultAppleEventCode": "ctxt", # return-type
"Arguments": {
"firstArg": {
"Type": "NSString",
"AppleEventCode": "comm"
}
}
}
)
The above dictionary works on ObjectC (I don't know if the python code does work).
The only thing I can see there that disagrees with the documentation is your value for "Type"; while the documentation doesn't show an example for "Type" in the context of a command, its value in the documentation's examples for other contexts is "NSString", not "text". So, try the Cocoa class name instead of the AppleScript class name.
The "Arguments" section still doesn't really work correct for me (I got strange crashs) but I can also just omit that and still get an argument passed at runtime.
This is the code:
import objc
NSObject = objc.lookUpClass("NSObject")
sharedScriptSuiteReg = objc.lookUpClass("NSScriptSuiteRegistry").sharedScriptSuiteRegistry()
NSScriptCommandDescription = objc.lookUpClass("NSScriptCommandDescription")
sharedAppleEventMgr = objc.lookUpClass("NSAppleEventManager").sharedAppleEventManager()
NSAppleEventDescriptor = objc.lookUpClass("NSAppleEventDescriptor")
from PyObjCTools.TestSupport import fourcc
def register_scripting():
cmdDesc = NSScriptCommandDescription.alloc().initWithSuiteName_commandName_dictionary_(
"Chromium Suite",
"exec Python",
{
"Name": "exec Python",
"CommandClass": "NSScriptCommand", # default behavior
"AppleEventCode": "ExPy", # 4-char code
"AppleEventClassCode": "CrSu",
"Type": "NSString", # return-type
"ResultAppleEventCode": "ctxt", # return-type
"Arguments": {
#"----": {
# "Type": "NSString",
# "AppleEventCode": "comm"
#}
}
}
)
assert cmdDesc is not None
sharedScriptSuiteReg.registerCommandDescription_(cmdDesc)
sharedAppleEventMgr.setEventHandler_andSelector_forEventClass_andEventID_(
appScriptHandler, appScriptHandler.handleExecPy,
fourcc("CrSu"), fourcc("ExPy"))
def handleExecPy(self, ev, replyEv):
print "execPython called,",
cmd = ev.descriptorForKeyword_(fourcc("comm")).stringValue()
print "cmd:", repr(cmd)
res = eval(cmd)
res = unicode(res)
replyEv.setDescriptor_forKeyword_(NSAppleEventDescriptor.descriptorWithString_(res), fourcc("----"))
return True
try:
class AppScriptHandler(NSObject):
def handleExecPy(self, ev, replyEv):
try: return handleExecPy(self, ev, replyEv)
except: traceback.print_exc()
return
except:
AppScriptHandler = objc.lookUpClass("AppScriptHandler")
appScriptHandler = AppScriptHandler.alloc().init()
This works together with this simple client demo:
#!/usr/bin/python
import aem
fullpath = aem.findapp.byname("Google Chrome")
app = aem.Application(fullpath)
def execPy(cmd):
return app.event("CrSuExPy", {"comm": cmd}).send()
print execPy("app.bundle()")
def simple_shell():
import sys
try: import readline
except: pass # ignore
while True:
try:
s = raw_input("> ")
except:
print "breaked debug shell:", sys.exc_info()[0].__name__
break
s = s.strip()
if s: print execPy(s)
simple_shell()
The full code can be seen here and in action here.