Can verigy test methods' params, aliases and methods' be defined at different times? - origen-sdk

I am importing all of my Verigy 93k test methods' parameters based on an ASCII file I received from Verigy. At the time of import, the test method attribute aliases and methods won't be known. Can they be created statically at a later time, by various developers? The code below is just a snippet of the test method param hash I am trying to auto-create.
thx
add_tml :my93k,
class_name: 'my93k',
Functional: {
class_name: 'Functional',
'ErrorMap.DutCyclesPerTesterCycles' => [:string, '1'],
'ErrorMap.EdgesPerTesterCycle' => [:string, '4'],
'ErrorMap.Location' => [:string, 'RAM'],
# Attribute aliases can be defined like this:
aliases: {
},
# Define any methods you want the test method to have
methods: {
}
},
my_other_test: {
# Define another test in exactly the same way...
}
end

There is no way to do that today, but I don't think it would be hard to add that capability if you want.
From your example above, test_methods.my93k.Functional will return an instance of OrigenTesters::SmartestBasedTester::Base::TestMethod, which is defined here: https://github.com/Origen-SDK/origen_testers/blob/5b89bf287b3d307bd6708c878666f3609a5fd3af/lib/origen_testers/smartest_based_tester/base/test_method.rb
The contents of the hash assigned to :Functional above are passed in as the initialization options when the TestMethod instance is instantiated.
If you look at the implementation of the initialize method, you will see where it defines the aliases and methods.
You could expose that same functionality via some new methods to provide an API for developers to add additional aliases and methods later in the process. e.g. test_methods.my93k.Functional.add_alias(:blah).

Related

Puppet data array

I got a module that creating some directories depending of server:
class linux_sftp::sftp_mount ($sftp_mount_ip, $sftp_mount_username, $sftp_mount_password, $sftp_mount_point) {
file { "/mnt/${sftp_mount_point}":
ensure => directory,
subscribe => Exec['sftp_remount'],
}
in data.yml
sftp_mount_point: "stcontent1"
I want to add to data more folders like: stcontent2, stcontent3. Is it a way to add this and loop thru data?
sftp_mount_point:
- "stcontent1"
- "stcontent2" ...
Yes you can use lambda method (can also be invoked as functions if desired) iteration to accomplish this task. The most common for your use case is each. It can be easily invoked on type Array[String] like you have in your question.
$sftp_mount_point.each |String $mount| {
file { "/mnt/${mount}":
ensure => directory,
}
}
Note that the file type does not have a subscribable property, so subscribe is not a valid attribute and I therefore removed it above.

Puppet assign class parameters in multiple places

I'm learning puppet (v6), and trying to understand how to set class parameters when a specific node needs an additional parameter, but uses the same class. Maybe a little fuzzy on the terminology, but here's what I'm working on:
MyNode1 needs sshd configured to use a banner and timeout, so using ghoneycutt-ssh, I include the ssh class with parameters:
/modules/MyModule/manifests/MySSH.pp
# Configures SSH
class MyModule::MySSH {
# Using ssh module
class { '::ssh':
sshd_client_alive_count_max => 0,
sshd_client_alive_interval => 900,
sshd_config_banner => '/etc/MyBanner.txt',
}
}
Now I have a second node MyNode2, which requires MySSH above, and also needs to disable forwarding. I started with something like this, where I define only the additional parameter in its own class:
/modules/MyModule/manifests/MySSH_Node2.pp
class MyModule::MySSH_Node2 {
class { '::ssh':
sshd_allow_tcp_forwarding => 'no',
}
}
Then define MyNode2 to include both in my site definition, hoping that puppet merges my ::ssh definitions:
/manifests/site.pp
node MyNode1 {
include MyModule::MySSH
}
node MyNode2 {
include MyModule::MySSH
include MyModule::MySSH_Node2
}
I understand that the above example doesn't work due to error Duplicate declaration: Class[Ssh]. I also tried overriding the class with a new parameter:
class MyModule::MySSH_Node2 {
Class[ssh] {
sshd_allow_tcp_forwarding => 'no',
}
}
But it seems this is not allowed either: Error: Resource Override can only operate on resources, got: Class[ssh]-Type
I'm not sure what the best way to add parameters is. I know I can create a manifest that includes all the parameters needed for this node and apply that instead, but then I end up with duplicate code everywhere.
Is there a reasonable way in modern puppet to assign and merge class parameters like this in puppet?

How do you access private methods or attributes from outside the type they belong to?

In some rare cases where this would actually be acceptable, like in unit tests, you may want to get or set the value of a private attribute, or call a private method of a type where it shouldn't be possible. Is it really impossible? If not, how can you do it?
There are two ways you can access a private method of a type, and one way to get private attributes. All require meta-programming except for the first way to invoke private methods, whose explanation still involves meta-programming anyway.
As an example, we will be implementing a Hidden class that hides a value using a private attribute, and a Password class that uses Hidden to store a password. Do not copy this example to your own code. This is not how you would reasonably handle passwords; this is solely for example's sake.
Calling private methods
Trusting other classes
Metamodel::Trusting is the meta-role that implements the behaviour needed for higher-order workings (types of types, or kinds, referred to from hereon out as HOWs) to be able to trust other types. Metamodel::ClassHOW (classes, and by extension, grammars) is the only HOW that's builtin to Rakudo that does this role.
trusts is a keyword that can be used from within packages to permit another package to call its private methods (this does not include private attributes). For example, a rough implementation of a password container class could look like this using trusts:
class Password { ... }
class Hidden {
trusts Password;
has $!value;
submethod BUILD(Hidden:D: :$!value) {}
method new(Hidden:_: $value) {
self.bless: :$value
}
method !dump(Hidden:D: --> Str:D) {
$!value.perl
}
}
class Password {
has Hidden:_ $!value;
submethod BUILD(Password:D: Hidden:D :$!value) {}
method new(Password:_: Str:D $password) {
my Hidden:D $value .= new: $password;
self.bless: :$value
}
method !dump(Password:D: --> Str:D) {
qc:to/END/;
{self.^name}:
$!value: {$!value!Hidden::dump}
END
}
method say(Password:D: --> Nil) {
say self!dump;
}
}
my Password $insecure .= new: 'qwerty';
$insecure.say;
# OUTPUT:
# Password:
# $!value: "qwerty"
#
Using the ^find_private_method meta-method
Metamodel::PrivateMethodContainer is a meta-role that implements the behaviour for HOWs that should be able to contain private methods. Metamodel::MethodContainer and Metamodel::MultiMethodContainer are the other meta-roles that implement the behaviour for methods, but those won't be discussed here. Metamodel::ClassHOW (classes, and by extension, grammars), Metamodel::ParametricRoleHOW and Metamodel::ConcreteRoleHOW (roles), and Metamodel::EnumHOW (enums) are the HOWs builtin to Rakudo that do this role. One of Metamodel::PrivateMethodContainer's methods is find_private_method, which takes an object and a method name as parameters and either returns Mu when none is found, or the Method instance representing the method you're looking up.
The password example can be rewritten not to use the trusts keyword by removing the line that makes Hidden trust Password and changing Password!dump to this:
method !dump(Password:D: --> Str:D) {
my Method:D $dump = $!value.^find_private_method: 'dump';
qc:to/END/;
{self.^name}:
$!value: {$dump($!value)}
END
}
Getting and setting private attributes
Metamodel::AttributeContainer is the meta-role that implements the behaviour for types that should contain attributes. Unlike with methods, this is the only meta-role needed to handle all types of attributes. Of the HOWs builtin to Rakudo, Metamodel::ClassHOW (classes, and by extension, grammars), Metamodel::ParametricRoleHOW and Metamodel::ConcreteRoleHOW (roles), Metamodel::EnumHOW (enums), and Metamodel::DefiniteHOW (used internally as the value self is bound to in accessor methods for public attributes) do this role.
One of the meta-methods Metamodel::AttributeContainer adds to a HOW is get_attribute_for_usage, which given an object and an attribute name, throws if no attribute is found, otherwise returns the Attribute instance representing the attribute you're looking up.
Attribute is how attributes are stored internally by Rakudo. The two methods of Attribute we care about here are get_value, which takes an object that contains the Attribute instance and returns its value, and set_value, which takes an object that contains the Attribute instance and a value, and sets its value.
The password example can be rewritten so Hidden doesn't implement a dump private method like so:
class Hidden {
has $!value;
submethod BUILD(Hidden:D: :$!value) {}
method new(Hidden:_: $value) {
self.bless: :$value;
}
}
class Password {
has Hidden:_ $!value;
submethod BUILD(Password:D: Hidden:D :$!value) {}
method new(Password:_: Str:D $password) {
my Hidden:D $value .= new: $password;
self.bless: :$value
}
method !dump(Password:D: --> Str:D) {
my Attribute:D $value-attr = $!value.^get_attribute_for_usage: '$!value';
my Str:D $password = $value-attr.get_value: $!value;
qc:to/END/;
{self.^name}:
$!value: {$password.perl}
END
}
method say(Password:D: --> Nil) {
say self!dump;
}
}
my Password:D $secure .= new: 'APrettyLongPhrase,DifficultToCrack';
$secure.say;
# OUTPUT:
# Password:
# $!value: "APrettyLongPhrase,DifficultToCrack"
#
F.A.Q.
What does { ... } do?
This stubs a package, allowing you to declare it before you actually define it.
What does qc:to/END/ do?
You've probably seen q:to/END/ before, which allows you to write a multiline string. Adding c before :to allows closures to be embedded in the string.
Why are grammars classes by extension?
Grammars use Metamodel::GrammarHOW, which is a subclass of Metamodel::ClassHOW.
You say ^find_private_method and ^get_attribute_for_usage take an object as their first parameter, but you omit it in the example. Why?
Calling a meta-method on an object passes itself as the first parameter implicitly. If we were calling them directly on the object's HOW, we would be passing the object as the first parameter.

Graphql Dataloader File Structure and Context

Let me preface this by saying I am not a javascript developer, so I'm probably missing something very obvious. I'm a data warehouse developer and creating a graphql server that can communicate with our DW got dropped in my lap.
I've been trying to get dataloaders to work on my graphql server by using a single object in the context, containing multiple dataloaders. I'm then trying to call the appropriate dataloader in the resolver. However, I've been unable to get this to work correctly. The consolidated dataloader object only works if I individually reference the dataloaders in the server context.
I'm trying to follow a similar pattern with the loaders as I have with my models, which is each broken out into a separate file, then consolidated for use as a single object via recursion through the file structure.
Example is I have an object called loaders which contains two loaders: countryLoader and marketsectorLoader, each of which is defined in a separate file under the "loaders" directory. In my server context, the following works
import * as loaders from "./loaders"
graphQLServer.use('/graphql', bodyParser.json(),
graphqlExpress({
schema,
context: {
countryLoader: loaders.countryLoader()
I can then call this in my resolver:
StateProvince: {
Country: (parent, args, {countryLoader}) => {
countryLoader.load(parent.Country_fkey) }},
This functions correctly, batching and returning the correct query result, but I'd prefer not to have to declare each specific dataloader from the loaders object as part of the context. However, I've been unable to figure out the syntax to use the loaders object in the context and call the appropriate
individual dataloader in the appropriate resolver.
I've tried several variants of the following example:
https://github.com/relay-tools/react-relay-network-layer/blob/master/examples/dataLoaderPerBatchRequest.js
which seems to be using the type of technique I'm trying to leverage:
//context snippet:
context: {
request: req, // just for example, pass request to context
dataLoaders: initDataLoaders(),
},
However, no luck. I suspect the issue is with my resolver syntax, but I'm not sure, and I haven't been able to find working examples with multiple dataloaders.
If I'm reading your code correctly, importing your loaders using a wildcard import like this:
import * as loaders from './loaders'
results in an object wherein each property is a function that creates an instance of a particular DataLoader. So we just need to iterate through each property. For example:
// Using forEach
const dataLoaders = {}
Object.keys(loaders).forEach(loaderName => {
dataLoaders[loaderName] = loaders[loaderName]()
})
// Or using reduce
const dataLoaders = Object.keys(loaders).reduce((result, loaderName) => {
result[loaderName] = loaders[loaderName]()
return result
}, {})
Using lodash, you can also just do something like:
const dataLoaders = _.mapValues(loaders, loader => loader())

When I use definition instead of class in puppet, what's the best practice for parameters?

I realise that it's generally a good idea to create params.pp in the module with modulename::params class and inherit that in modulename class to handle parameters in a separate file. How do I do that if instead of class, I am creating a definition?
Just to clarify, I'm using a definition to be able to install multiple versions of the same application on the server.
Good question. Since there is no inheritance available for defined types in Puppet the params.pp patterns can not be reproduced in the exact same way for defined types as for classes. There is another way though.
The following code outputs 'hello world' via the Foo['bar'] defined type:
class params {
$msg = 'hello world'
}
define foo($msg = $params::msg ) {
notify{ $msg: }
}
foo { 'bar': }
include params
Now, for the above to function it is necessary for params to be included. Otherwise the Puppet parser will complain that the class params has not been evaluated and therefore the $params::msg variable can not be resolved.
It is not necessary to provide ordering between the inclusion of params and the definition of bar, since in Puppet classes are always evaluated before defined types. If this would not be so the above would likely cause the same evaluation problem and you would have to write:
foo { 'bar':
require => Class['params'] # <- not necessary
}
include params
So for this to work in a module foo you can simply add a params class as you are used to and start your init.pp with:
include foo::params
define foo($x = $foo::params::x, $y = $foo::params::y, ...)
One important note
Before you happily proceed with the params.pp pattern I advise you to read this blog post: the problem with params.pp

Resources