How to make sure the running order of puppet classes? - ruby

I am new to puppet deployment. I have two classes defined
class taskname{
exec{ "deploy_script":
command = "cp ${old_path} ${new path}",
user = root,
}
cron{"cron_script2":
command = "pyrhton ${new_path}",
user = root,
require = Exec["deploy_script"]
}
}
class taksname2{
exec{ "deploy_script2":
command = "cp ${old_path} ${new path}",
user = root,
}
cron{"cron_script":
command = "pyrhton ${new_path}",
user = root,
require = Exec["deploy_script2"]
}
}
How do I make sure the running order of these two classes.
I have tried in a new manifest file
init.pp to include these two classes
include taskname
include taskname2
It seems that second task running before the first task. How to I enforce the running order?

Use one of these metaparameters.
So to sum up: whenever a resource depends on another resource, use the
before or require metaparameter or chain the resources with ->.
Whenever a resource needs to refresh when another resource changes,
use the notify or subscribe metaparameter or chain the resources with
~>. Some resources will autorequire other resources if they see them,
which can save you some effort.
Also works for classes declared with a resource-like syntax.
When declared with the resource-like syntax, a class may use any
metaparameter. In such cases, every resource contained in the class
will also have that metaparameter. So if you declare a class with noop
=> true, every resource in the class will also have noop => true,
unless they specifically override it. Metaparameters which can take
more than one value (like the relationship metaparameters) will merge
the values from the container and any specific values from the
individual resource.

Try using the metaparameter -> to specify a dependency relationship between the classes. In init.pp where you declare/instantiate these classes, replace the include statements with parameterized class syntax:
class {"taskname":} ->
class {"taskname2":}
This will ensure taskname is invoked before taskname2. For more information, see http://docs.puppetlabs.com/guides/parameterized_classes.html#declaring-a-parameterized-class

Related

How can I define a global variable or constant using jenkins pipeline shared library?

While I was able to define methods, defining variables using Jenkins Shared library seems to an unresolved quest so far.
I added /vars/True.groovy with this body
def call() {
return true
}
And now inside Jenkinsfile, I tried to test if it works as expected:
println "evaluation ${ true == True }"
But surprise, this fails as it considers true != class True. My impression is that true == True() may work but that's not the point, I need a real variable because that whole purpose was to avoid some errors caused by people using wrong case.
So what is the magic trick?
I've found a way to achieve this, but with a slight caveat: the variables must be defined/wrapped within a class. However, this does have the upside of providing better organization, in order not to pollute the global space too much.
For example, we often reuse four standard "magic strings" for build statuses, which I wanted to save as global constants to facilitate interoperability. So I created a global status class, defined in vars/status.groovy:
class status {
final String STARTED = "STARTED"
final String SUCCESS = "SUCCESS"
final String FAILURE = "FAILURE"
final String ABORTED = "ABORTED"
}
The constants can then be used by referring to their parent class:
echo status.STARTED
echo status.SUCCESS
echo status.FAILURE
echo status.ABORTED
Specials thanks to #mkobit for pointing me in the right direction!
It looks like Global Variables defined in the vars directory must be lower/camel/maybe some other special casing. This isn't stated anywhere in on the Defining global variables section, but there is this note at the top:
The vars directory hosts scripts that define global variables accessible from Pipeline. The basename of each *.groovy file should be a Groovy (~ Java) identifier, conventionally camelCased. The matching *.txt, if present, can contain documentation, processed through the system’s configured markup formatter (so may really be HTML, Markdown, etc., though the txt extension is required).
Here is what I tried:
vars/MyTrue.groovy
class MyTrue implements Serializable {
}
vars/myTrue.groovy
class myTrue implements Serializable {
}
vars/mytrue.groovy
class mytrue implements Serializable {
}
vars/doesCasingMatter.groovy
class DoesCasingMatter implements Serializable {
}
And in my pipeline script to test if they are instances or Class types (no script security enabled here):
echo("MyTrue: ${Class.isInstance(MyTrue)}")
echo("myTrue: ${Class.isInstance(myTrue)}")
echo("mytrue: ${Class.isInstance(mytrue)}")
echo("What bindings are there?: ${binding.variables}")
This prints out:
[Pipeline] echo
MyTrue: true
[Pipeline] echo
myTrue: false
[Pipeline] echo
mytrue: false
[Pipeline] echo
What bindings are there?: [steps:org.jenkinsci.plugins.workflow.cps.DSL#e96256, myTrue:myTrue#8a1ddc5, mytrue:mytrue#392ff649]
Which seems to indicate that something about the class name determines how it gets compiled and created. The first example, which is similar to your vars/True.groovy, is only imported as a class and not instantiated. The other two are compiled and instantiated and are bound to the script with their defined class names. I think you will have to define your classes differently if you want them to be global variables.
Variable True is definitely a variable but it holds a reference to object of type True(that you defined in /vars/True.groovy). You have two options
The good one:
Use it this way
println "evaluation ${ true == True() }"
The strange one:
You can override equals() method in /vars/True.groovy
public boolean equals(obj) {
return obj == true;
}
Then this should work
println "evaluation ${ true == True }"
But it would be really strange and can lead to misunderstandings.

How to do a prophecy for current testing class in PHPUnit?

I have this case that I want to run PHPUnit test and check behaviour of current testing class as follows:
public function it_allows_to_add_items()
{
// Create prophesies
$managerProphecy = $this->getProphet(ListingManager::class);
$listingItemProphecy = $this->getProphet(ListingItemInterface::class);
$listing = factory(\App\Misc\Listings\Listing::class)->create();
$manager = new ListingManager($listing);
$item = factory(\App\Misc\Listings\ListingItem::class)->make(['listing_id' => null]);
$item2 = factory(\App\Misc\Listings\ListingItem::class)->make(['listing_id' => null]);
$manager->addItem($item);
$managerProphecy->validate($listingItemProphecy)->shouldBeCalledTimes(2);
$manager->addItem($item2);
$this->assertTrue(true);
}
is that even possible ?
Of course I'm getting
1) GenericListingManagerTest::it_allows_to_add_items
Some predictions failed:
Double\App\Misc\Listings\ListingManager\P2:
Expected exactly 2 calls that match:
Double\App\Misc\Listings\ListingManager\P2->validate(exact(Double\ListingItemInterface\P1:00000000058d2b7a00007feda4ff3b5f Object (
'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)
)))
but none were made.
I think your way to approach this test is a bit off. If I understand correctly you want to verify that addItem(object $item) works properly, i.e. the manager contains the item and the item is the same you added. For this you should not need prophecies and in fact your test does not actually use the prophecies you created. Depending on what your Manager looks like you could write something like this:
function test_manager_add_items_stores_item_and_increases_count()
{
$manager = new ListingManager(); // (2)
$item = new ListingIem(); // (3)
$initialCount = $manager->countItems(); // (1)
$manager->addItem($item);
$this->assertEquals($initialCount + 1, $manager->countItems());
// Assuming offset equals (item count - 1) just like in a numeric array
$this->assertSame($item, $manager->getItemAtOffset($initialCount));
}
(1) Assuming your manager has a count()-method you can check before and after whether the count increased by the number of added items.
(2) We want to test the real manager - that's why we don't need a mock created by prophecy here - and we can use a real item because it's just a value.
(3) I'm not sure why you have a ListingItemInterface. Are there really different implementations of ListingItem and if so, do you really want a generic ListingManager that possibly contains all of them or do you need a more specific one to make sure that each Manager contains only it's specific kind of item? This really depends on your use case, but it looks like you might violate the I (Interface Segregation Principle) or L (Liskov Substitution Principle) in SOLID.
Depending on your use case you might want to add real items, e.g. 2 different types to make clear that it's intended that you can put 2 different implementations of the interface in there or you can do it like above and just add a ListingItem and verify that each item in the manager implements the interface - I leave finding the assertion for that to you ;). Of course you can use your factory to create the item as well. The important thing is that we test with assertSame() whether the managed object and the one we created initially are the same, meaning reference the exact same object.
You could add additional tests if you want to ensure additional behaviour, such as restricting the kind of items you can put in the manager or how it behaves when you put an invalid object in there.
The important thing is, that you want to test the actual behaviour of the Manager and that's why you don't want to use a mock for it. You could use a mock for the ListingItemInterface should you really require it. In that case the test should probably look something like this:
function test_manager_add_items_stores_item_and_increases_count()
{
$manager = new ListingManager();
$dummyItem = $this->prophecy(ListingIemInterface::class);
$initialCount = $manager->countItems();
$manager->addItem($dummyItem->reveal());
$this->assertEquals($initialCount + 1, $manager->countItems());
$this->assertSame($dummyItem, $manager->getItemAtOffset($initialCount));
}
edit: If addItem checks the validation which you want to skip, e.g. because the empty item you provide is not valid and you don't care. You can use PHPUnit's own mock framework to partially mock the manager like this:
$item = new ListingItem();
$managerMock = $this->getMockBuilder(ListManager::class)
->setMethods(['validate'])
->getMock();
$managerMock
->expects($this->exactly(2))
->method('validate')
->with($this-> identicalTo($item))
->willReturn(true);
$managerMock->addItem($item);
$managerMock->addItem($item);
You don't have to assert anything at the end, because expects() is already asserting something. Your Manager will work normally, except for validate(), meaning you will run the code in addItem() and if in there validate is called (once per item) the test will pass.

how to write puppet-rspec for dependent define?

I have a define like below,
define module::define1 (
$path = undef,
$someparam = undef,
...
) {
unless defined(Define2[$someparam]) {
fail("Please create define2[$someparam] first")
}
file { $path:
ensure => directory,
}
}
When I try to test the existence of file[$path] I am getting error "Please create define2[$someparam] first". But define2 is in another file.
How can I include define2 inside my define1's rspec scope?
I believe that you are hitting a severe limitation of your manifest design. Expressing cross-dependencies through the defined function is very fragile and bound to lead to issues.
Have you considered replacing your checks with constraints? (The module documentation also elaborates a bit on why defined is often a bad idea.)

ipython parallel push custom object

I am unable to send object to direct view workers.
Here is what I want to do:
class Test:
def __init__(self):
self.id = 'ddfdf'
from IPython.parallel import Client
rc = Client()
dv = rc[:]
t = Test()
dv['t'] = t
print dv['t']
NameError: name 't' is not defined
This would work if I try to push pandas object or any of the build in objects.
What is the way to do it with custom object?
I tried:
dv['Test'] = Test
dv['t'] = t
print dv['t']
UnpicklingError: NEWOBJ class argument isn't a type object
For interactively defined classes (in __main__), you do need to push the class definition, or use dill. But even this doesn't appear to work for old-style classes, which is a bug in IPython's handling of old-style classes[1]. This code works fine if you use a new-style class:
class Test(object):
...
instead of on old-style class. Note that old-style classes are not available in Python 3.
It's generally a good idea to always use new-style classes anyway.

Is there a hook for when anonymous classes are assigned to a constant?

I've been practicing some Ruby meta-programming recently, and was wondering about assigning anonymous classes to constants.
In Ruby, it is possible to create an anonymous class as follows:
anonymous_class = Class.new # => #<Class:0x007f9c5afb21d0>
New instances of this class can be created:
an_instance = anonymous_class.new # => #<#<Class:0x007f9c5afb21d0>:0x007f9c5afb0330>
Now, when the anonymous class is assigned to a constant, the class now has a proper name:
Foo = anonymous_class # => Foo
And the previously created instance is now also an instance of that class:
an_instance # => #<Foo:0x007f9c5afb0330>
My question: Is there a hook method for the moment when an anonymous class is assigned to a constant?
There are many hooks methods in Ruby, but I couldn't find this one.
Let's take a look at how constant assignment works internally. The code that follows is extracted from a source tarball of ruby-1.9.3-p0. First we look at the definition of the VM instruction setconstant (which is used to assign constants):
# /insns.def, line 239
DEFINE_INSN
setconstant
(ID id)
(VALUE val, VALUE cbase)
()
{
vm_check_if_namespace(cbase);
rb_const_set(cbase, id, val);
INC_VM_STATE_VERSION();
}
No chance to place a hook in vm_check_if_namespace or INC_VM_STATE_VERSION here. So we look at rb_const_set (variable.c:1886), the function that is called everytime a constant is assigned:
# /variable.c, line 1886
void
rb_const_set(VALUE klass, ID id, VALUE val)
{
rb_const_entry_t *ce;
VALUE visibility = CONST_PUBLIC;
# ...
check_before_mod_set(klass, id, val, "constant");
if (!RCLASS_CONST_TBL(klass)) {
RCLASS_CONST_TBL(klass) = st_init_numtable();
}
else {
# [snip], won't be called on first assignment
}
rb_vm_change_state();
ce = ALLOC(rb_const_entry_t);
ce->flag = (rb_const_flag_t)visibility;
ce->value = val;
st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce);
}
I removed all the code that was not even called the first time a constant was assigned inside a module. I then looked into all the functions called by this one and didn't find a single point where we could place a hook from Ruby code. This means the hard truth is, unless I missed something, that there is no way to hook a constant assignment (at least in MRI).
Update
To clarify: The anonymous class does not magically get a new name as soon as it is assigned (as noted correctly in Andrew's answer). Rather, the constant name along with the object ID of the class is stored in Ruby's internal constant lookup table. If, after that, the name of the class is requested, it can now be resolved to a proper name (and not just Class:0xXXXXXXXX...).
So the best you can do to react to this assignment is to check the name of the class in a loop of a background worker thread until it is non-nil (which is a huge waste of resources, IMHO).
Anonymous classes don't actually get their name when they're assigned to a constant. They actually get it when they're next asked what their name is.
I'll try to find a reference for this. Edit: Can't find one, sorry.

Resources