Basically, I'm trying to create a get method for a tcl class that I have so that I can access data inside that class within a proc that isn't inside a class. For example, it would look like this:
itcl::class foo {
set list []
proc getFilterList {} {
return $list
}
}
proc bar {} {
set list itcl::foo::getFilterList
}
But hilariously the the list contains the phrase "itcl::foo::getFilterList" so I'm obviously doing something wrong. Sorry if this is an obvious one, I just can't seem to figure it out.
In addition to following the selected answer, I also made my variable available at a global scale which works for me seeing as how from creation to manipulation I know exactly when my variable is being modified and when I can access it's values.
Use
proc bar {} {
set list [itcl::foo::getFilterList]
}
Related
I'm trying to tell data.github_ip_ranges to what name to use so I could create a list of CIDRs and my code look cleaner. I was trying to find answers, but no luck so far.
And I'm trying to see if there is a way of passing my variables to it...
variable "git_services" {
default = ["hooks_ipv4", "dependabot_ipv4", "dependabot_ipv6", "git_ipv4", "hooks_ipv6"]
}
locals {
github_ips = concat(data.github_ip_ranges.git.name) # name is my custom variable
}
Here is my original approach
locals {
github_ips = concat(data.github_ip_ranges.git.hooks_ipv4, data.github_ip_ranges.git.hooks_ipv6,
data.github_ip_ranges.git.dependabot_ipv4, data.github_ip_ranges.git.dependabot_ipv6)
}
Please help if you could. Thank you!
I think I understand what you're trying to accomplish. You would do it like so:
variable "git_services" {
default = ["hooks_ipv4", "dependabot_ipv4", "dependabot_ipv6", "git_ipv4", "hooks_ipv6"]
}
locals {
github_ips = distinct(flatten([
for service in var.git_services:
data.github_ip_ranges.git[service]
]))
}
What this is doing is creating a list of lists, where each element in the first level is for a service, and each element in the second level is a CIDR bock for that service. The flatten function turns this list of lists into a flat list of CIDR blocks. Since the same CIDR might be used for multiple services, and we probably don't want duplicates if we're using this for something like security group rules, we use the distinct function to remove any duplicate CIDR blocks.
hiera data
ae::namespace_by_fqdn_pattern:
'((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((client))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com': '/test/blah/regression/client'
'((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((server))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com': '/test/blah/regression/server'
class
class ae {
$namespace = hiera('ae::namespace')
$target_host_patterns = hiera('ae::target_host_patterns')
hiera_hash('ae::namespace_by_fqdn_pattern').each |String $pattern, String $ns| {
if $facts['networking']['fqdn'].match($pattern) {
$ae::namespace = "${ns}"
}
}
<snip>
... yields
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Illegal attempt to assign to 'ae::enforcerd_namespace'. Cannot assign to variables in other namespaces (file: /etc/puppetlabs/code/environments/ar/modules/ae/manifests/init.pp, line: 21, column: 13) on node dfw-ubuntu1604-client02.pp-devcos.us-central1.gcp.dev.blah.com
... anyone here know how to do this correctly? trying to conditionally override that $ae::namespace variable but i'm too puppet-ignorant to know how to get it working : (
the loop and the pattern matching bits work. just can't figure out how to correctly set that class variable from within the hiera_hash().each loop.
How to set a puppet class variable from within a hiera_hash each loop?
You cannot. The associated block of an each() call establishes a local scope for each iteration. Variable assignments within apply to that local scope, and therefore last only for the duration of one execution of the block. You cannot anyway assign a new value to a variable during its lifetime, so even if you could assign to a class variable from within an each() call, it would be difficult to use that capability (and your approach would not work).
There are several ways you could approach the problem without modifying the form of the data. You could leverage the filter() function, for example, but my personal recommendation would be to use the reduce() function, something like this:
$namespace = lookup('ae::target_host_patterns').reduce(lookup('ae::namespace')) |$ns, $entry| {
$facts['networking']['fqdn'].match($entry[0]) ? { true => $entry[1], default => $ns }
}
That does pretty much exactly what your original code seems to be trying to do, except that the selected namespace is returned by the reduce() call, to be assigned to a variable by code at class scope, instead of the lambda trying to assign it directly. Note also that it takes care not only of testing the patterns but of assigning the default namespace when none of the patterns match, as it needs to do because you can only assign to the namespace variable once.
so the solution i landed on was to change the hiera data to:
ae::namespace : '/test/blah/regression'
ae::namespace_patterns: ['((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((client))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com', '((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((server))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com']
ae::namespace_by_pattern:
'((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((client))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com': '/test/paypal/regression/client'
'((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((server))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com': '/test/paypal/regression/server'
then the class code to:
$pattern = hiera_hash('ae::namespace_patterns').filter |$pattern| {
$facts['networking']['fqdn'] =~ $pattern
}
if length($pattern) {
$namespace = hiera('ae::namespace_by_pattern')[$pattern[0]]
} else {
$namespace = hiera('ae::namespace')
}
definitely still open to better answers. just what my own hacking produced as workable so far through much trial and error.
I try to create an attribute trait. The use case is to mark some attributes of a class as "crudable" in the context of an objects-to-documents-mapping while other are not.
role crud {
has Bool $.crud is default(True);
}
multi trait_mod:<is>(Attribute $a, crud, $arg) {
$a.container.VAR does crud($arg);
}
class Foo {
has $.bar is rw;
# Provide an extra nested information
has $.baz is rw is crud(True);
}
By reading and adapting some example code, I managed to get something that seems to do what I want. Here is a snippet with test case.
When I instantiate a new Foo object and set the $.bar attribute (that is not crud), it looks like that:
.Foo #0
โ $.bar is rw = 123456789
โ $.baz is rw = .Scalar+{crud} #1
โ $.crud +{crud} = True
What I understand from this is that the $.baz attribute got what I call a meta-attribute that is independent from its potential value.
It looks good to me (if I understood correctly what I did here and that my traits use is not a dirty hack). It is possible to reach $foo.baz.crud that is True. Though, I don't understand very well what .Scalar+{crud} means, and if I can set something there and how.
When I try to set the $.baz instance attribute, this error is returned:
Cannot modify an immutable Scalar+{crud} (Scalar+{crud}.new(crud => Bool::True))
in block <unit> at t/08-attribute-trait.t line 30
Note: This is the closest thing to a working solution I managed to get. I don't need different crud settings for different instances of instantiated Foo classes.
I never want to change the value of the boolean, in fact, once the object instantiated, just providing it to attributes with is crud. I am not even interested to pass a True or False value as an argument: if it would be possible to just set the boolean trait attribute to True by default, it would be enough. I didn't manage to do this though, like:
multi trait_mod:<is>(Attribute $a, :$crud!) {
# Something like this
$a.container.VAR does set-crud;
}
class Foo {
has $.bar is rw;
has $.baz is rw is crud;
}
Am I trying to do something impossible? How could I adapt this code to achieve this use case?
There are several things going on here. First of all, the signature of the trait_mod looks to be wrong. Secondly, there appears to be a bad interaction when the name of a trait is the same as an existing role. I believe this should be an NYI exception, but apparently it either goes wrong in parsing, or it goes wrong in trying to produce the error message.
Anyways, I think this is what you want:
role CRUD {}; # since CRUD is used as an acronym, I chose to use uppercase here
multi trait_mod:<is>(Attribute:D $a, :$crud!) { # note required named attribute!
$a.^mixin: CRUD if $crud; # mixin the CRUD role if a True value was given
}
class A {
has $.a is crud(False); # too bad "is !crud" is invalid syntax
has $.b is crud;
}
say "$_.name(): { $_ ~~ CRUD }" for A.^attributes; # $!a: False, $!b: True
Hope this helps.
I struck to pass multiple arguments in define.
The following is my code. I would like to pass two array inside the define, But I'm able to pass only one as like the following.
class test {
$path = [$path1,$path2]
$filename = [$name1,$name2]
define testscript { $filename: } // Can able to pass one value.
}
define testscript () {
file {"/etc/init.d/${title}": //Can able to receive the file name.
ensure => file,
content => template('test/test.conf.erb'),
}
From my above code, I could retrieve the filename inside the define resource. I also need path to set the value in the template. I`m not able to send / retrieve second argument in template.
Is there any way to improve my code to pass two values ( $path and $filename ) inside define resource ?
Any help is much appreciated.
Is there any way to improve my code to pass the two values ( $path and $filename ) inside define resource ?
Puppet has good documentation, which covers this area well.
To begin, you need to appreciate that a defined type is a resource type, in almost every way analogous to any built-in or extension type. If your defined type accepts parameters, then you bind values to those parameters just as you would in any other resource declaration. For example:
class mymodule::test {
mymodule::testscript { $name1: path => $path1 }
mymodule::testscript { $name2: path => $path2 }
}
define mymodule::testscript ($path) {
file {"${path}/${title}":
ensure => 'file',
content => template('test/test.conf.erb')
}
}
Additionally, because defined types are resource types, you should discard the concept of "passing" values as to them as if they were instead functions. That mental model is likely to betray you. In particular, it will certainly give you the wrong expectation about what would happen if you specify an array or a hash as your resource title.
In particular, you need to understand that in any resource declaration, if you give the resource title as an array, then that means a separate resource for each array member, with the array member as that resource's title. In that case, every one of those resources receives the same parameter values, as declared in the body of the declaration. Moreover, resource titles are always strings. Except for one level of arrays, as described above, if you give anything else as a resource title then it will be converted to a string.
I want to remove the breadcrumb when it's just one entry ("Home"). I'm in my theme's theme_preprocess_page(&$vars) function. $vars['breadcrumb'] is available, but it's just HTML. This is a bit to clumsy to work with. I'd rather get it as an array of items in the breadcrumb list, and do something like this:
if (count($breadcrumb) == 1) {
unset($breadcrumb);
}
Where does $vars come from? How can I override the code creating it originally?
A $vars array is passed on between all preprocess functions. In case of the _preprocess_page functions, most of the values in $vars are created in template_preprocess_page (see http://api.drupal.org/api/function/template_preprocess_page/6). In that function, you'll see:
$variables['breadcrumb'] = theme('breadcrumb', drupal_get_breadcrumb());
Here, drupal_get_breacrumb returns an array of breadcrumb elements, which is then themed by the theme_breadcrumb() function (or its override).
The easiest way to get what you want is to override the theme_breadcrumb function. To do that, you take the original theme_breadcrumb function (http://api.drupal.org/api/function/theme_breadcrumb/6), copy it to your template.php, replace 'theme' in the function name with the name of your theme and alter the code so it looks like this:
function THEMENAME_breadcrumb($breadcrumb) {
if (count($breadcrumb) > 1) { // This was: if (!empty($breadcrumb))
return '<div class="breadcrumb">'. implode(' ยป ', $breadcrumb) .'</div>';
}
}
For a better understanding of Drupal theme overrides and preprocess functions, see About overriding themable output and Setting up variables for use in a template (preprocess functions).