Tcl passing value of a variable - syntax

I have a procedure which reads a register from a specified address:
"rd_addr $jtag_master 0x00"
I'd like to remove the "$jtag_master" input, and instead use a global variable declared at the beginning of the script, which I can then use in other procedures. The initial declaration is currently implemented through use of another procedure, "set_dev".
global device_path
# Establish the device_path as specified by "device"
proc set_dev {device} {
set jtag_master [lindex [get_service_paths master] $device];
set device_path $jtag_master
}
proc rd_addr {address {size 1}} {
set read_data [master_read_32 $device_path $address $size];
puts "$read_data"
}
# Init
set_dev 0
puts "jtag: $jtag_master"; # Returns proper path
puts "device_path: $device_path"; # Returns proper path
rd_addr 0x00
My current implementation of rd_addr returns:
error: can't read "device_path": no such variable
I've also tried implementing defaults, attempting defaults, which result in their own errors:
proc rd_addr {address {size 1} {device_path $device_path}} {
-> error: master_read_32: Error: The given path is not valid - $device_path
proc rd_addr { {device_path $device_path} address {size 1} } {
-> error: wrong # args: should be "rd_addr ?device_path? address ?size?"
Thanks in advance!

From the global documentation:
This command has no effect unless executed in the context of a proc body. If the global command is executed in the context of a proc body, it creates local variables linked to the corresponding global variables
Basically, global variable_name needs to be used inside each proc that wants to refer to the global variable of that name.
proc set_dev {device} {
global device_path
set jtag_master [lindex [get_service_paths master] $device];
set device_path $jtag_master
}
proc rd_addr {address {size 1}} {
global device_path
set read_data [master_read_32 $device_path $address $size];
puts "$read_data"
}
Without it, set_dev sets a variable local to the proc with that name, and as you've seen rd_addr can't find any variable with that name. Global variables in tcl are not visible at proc scope without this or a few other approaches (A fully qualified $::device_path for example)

Related

terraform: lambda invocation during destroy

I have lambda invocation in our terraform-built environment:
data "aws_lambda_invocation" "this" {
count = var.invocation == "true" ? 1 : 0
function_name = aws_lambda_function.this.function_name
input = <<JSON
{
"Name": "Invocation"
}
JSON
}
The problem: the function is invoked not only during creation ("apply") but deletion ("destroy") too. How to invoke it during creation only? I thought about checking environment variables in the lambda (perhaps TF adds name of the process here or something like that) but I hope there's a better way.
Worth checking if you can use the -var 'lambda_xxx=execute' option while running the terraform command to check if the lambda code needs to be executed or not terraform docs
Using that variable lambda_xxx passed in via the command line while executing the command, you can check in the terraform code whether you want to run the lambda code or not.
Below code creates a waf only if the count is 1
resource "aws_waf_rule" "wafrule" {
depends_on = ["aws_waf_ipset.ipset"]
name = "${var.environment}-WAFRule"
metric_name = "${replace(var.environment, "-", "")}WAFRule"
count = "${var.is_waf_enabled == "true" ? 1 : 0}"
predicates {
data_id = "${aws_waf_ipset.ipset.id}"
negated = false
type = "IPMatch"
}
}
Variable declared in variables.tf file
variable "is_waf_enabled" {
type = "string"
default = "false"
description = "String value to indicate if WAF/API KEY is turned on or off (true/any_value)"
}
When you run the command any value other than true is considered false as we are just checking for string true.
Similarly you can do this for your lambda.
There are better alternative solutions for this problem now, which weren't available at the time the question was asked.
Lambda Invocation Resource in AWS provider: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_invocation
Lambda Based Resource in LambdaBased provider: https://registry.terraform.io/providers/thetradedesk/lambdabased/latest/docs/resources/lambdabased_resource
With the disclaimer that I'm the developer of the latter one: If the underlying problem is managing a resource through lambda functions, the lambda based resource has some good features tailored specifically to accomplish that with the obvious drawback of adding another provider dependency.

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.)

tk_optionMenu error "can't read "a": no such variable"

I am trying to execute a simple code
global a
eval tk_optionMenu .qt.oc a [list 1 2 4 8 16]
proc Run {} {
puts "$a"
}
I have a button that associated to Run proc , when i press pres on Run button
I receive the following error:
can't read "a": no such variable
can't read "a": no such variable
while executing
"puts "$a""
(procedure "Run" line 2)
invoked from within
"Run"
invoked from within
".top.run invoke"
("uplevel" body line 1)
invoked from within
"uplevel #0 [list $w invoke]"
(procedure "tk::ButtonUp" line 22)
invoked from within
"tk::ButtonUp .top.run"
(command bound to event)
any suggestions?
global must be used inside the scope where you are trying to access a global variable. For example:
proc Run {} {
global a
puts "$a"
}
Here's an excerpt from the global man page:
This command has no effect unless executed in the context of a proc
body.

Erlang gives syntax error on record construction

I have the following code in a module:
-module(my_server).
-record(server_opts,
{port, ip = "127.0.0.1", max_connections = 10}).
Opts1 = #server_opts{port=80}.
When I try to compile it in Erlang shell it gives an error like
syntax error before Opts1. Any idea what could be the problem with the code above. Please note that the code is taken from the following website:
Record example in Erlang.
The following line:
Opts1 = #server_opts{port=80}.
Should be contained within a function body:
foo() ->
Opts1 = #server_opts{port=80},
...
Remember to export the function, so that you can call it from outside the module:
-export([test_records/0]).
A complete example follows:
-module(my_server).
-export([test_records/0]).
-record(server_opts, {port,
ip = "127.0.0.1",
max_connections = 10}).
test_records() ->
Opts1 = #server_opts{port=80},
Opts1#server_opts.port.
Maybe, you've thought that Opts1 is a global constant, but there are no global variables in erlang.
You may use macro definitions to have something like global constants (which are actually replaced in compile time):
-module(my_server).
-record(server_opts,
{port,
ip="127.0.0.1",
max_connections=10}).
%% macro definition:
-define(Opts1, #server_opts{port=80}).
%% and use it anywhere in your code:
my_func() ->
io:format("~p~n",[?Opts1]).
P.S.
Using records from shell. Assume - you've created file my_server.hrl which contain definition of record server_opts. First of all you're have to load record definition, using function rr("name_of_file_with_record_definition"), after this you're ready to work with records in shell:
1> rr("my_record.hrl").
[server_opts]
2>
2> Opts1 = #server_opts{port=80}.
#server_opts{port = 80,ip = "127.0.0.1",
max_connections = 10}
3>
3> Opts1.
#server_opts{port = 80,ip = "127.0.0.1",
max_connections = 10}
4>

Invalid command name in Tcl when using format

I'm running the following commands
set full_pin_name [format "%s %s" $top_cell $encoded_name]
puts "full_pin_name is $full_pin_name"
and I get the following error:
full_pin_name is invalid command name "A" B
when top_cell equals A and encoded_name equals B.
Why is this happening?
I suspect the problem is with your $top_cell variable, which has the value invalid command name "A". To check, try the following line before your format line:
puts ">$top_cell<"
If indeed, $top_cell value has a problem, you can then trace back to the last set command. Let us know if it fixes your problem, or we might try some other approaches.
Try repeating this in a plain Tcl shell, it works. Something is different in your Tcl shell.
Try
info body set
and
info body format
If either report something other than set isn't a procedure or format isn't a procedure then you have your culprit.
May be this code runs in a namespace which has the set command defined in it?
To demonstrate:
% namespace eval foo {
proc set args {
puts hey!
}
proc whatever {top_cell encoded_name} {
set full_pin_name [format "%s %s" $top_cell $encoded_name]
puts "full_pin_name is $full_pin_name"
}
}
% ::foo::whatever A B
hey!
can't read "full_pin_name": no such variable
%
As far as I can tell without a TCL interpreter here it should work assuming a normal interpreter with format defined. so it looks like maybe format has been renamed or doesn't exist as a command in the interpreter you are using?
To get you going you don't really need format to join strings anyway
set fill_pin_name "$top_cell $encoded_name"
should so what you need
Maybe your code looks like this:
set encoded_name B
if { [catch {[A]} top_cell]} {
set full_pin_name [format "%s %s" $top_cell $encoded_name]
puts "full_pin_name is $full_pin_name"
}
The result is:
full_pin_name is invalid command name "A" B

Resources