Reusing code in modules

Currently, modules are independent, standalone Python scripts. This is good because we transfer them to remote nodes and can run them without dependencies. However, it leads to a lot of copy-and-pasted code between modules, because there are some common things modules do (e.g., parsing arguments). When fixes are made, they need to be made several times, and it’s easy to miss one. For instance, I just fixed the md5 code and had to copy and paste it four times.

So, I’d like to solicit ideas on how to enable code re-use in modules, but still keep them easy to run remotely. I’ll get the ball rolling:

#1. Add a common module that houses all shared code, and copy it over with every module.

#2. Autogenerate modules at build time from templates that include the common code.

Thoughts?

#1. Add a common module that houses all shared code, and copy it over with every module.

Don’t like this.

#2. Autogenerate modules at build time from templates that include the common code.

Really hate this.

Thoughts?

Not interested and discussed previously, we could template magic in each module but that makes them hard to debug.

There aren’t that many functions, my advice is you learn to tolerate it, especially as you don’t send that many pull requests for modules anyway.

–Michael

I mostly side with MDH on this and think a strict no-dependencies is preferable to spawning library that tries to do everything.

But I press back a bit regarding a minimalist library when I see that even in core modules there have been some inconsistencies and gotchas. I think for the rudimentary cases of reading params, interpreting yes and no, logging, error and success return data, we’ll either fall into: editor inheritance (cut and paste), falling for the same gotchas repeatedly, or a very minimal ansiblelib.py.

I prefer the latter, think you should consider liking it, Michael, but can live with the others. But maybe there’s some sour experience from func you’re bringing to this. Can you articulate why you don’t like it?

Respectfully,
–b

I mostly side with MDH on this and think a strict no-dependencies is preferable to spawning library that tries to do everything.

Invalid abbreviation of my name, FWIW.

Not really interested in the discussion too much here – I’ll say, most anything we do will make debugging hard or can potentially break people by making the things we include in modules part of an API.

I am not willing to do that yet, nor do I want to require a “bootstrap” step of transferring a helper module in order to get Ansible to work.

Things are pretty consistent now.

–Michael

I am not willing to do that yet, nor do I want to require a “bootstrap” step of transferring a helper module in order to get Ansible to work.

Fair enough. Apologies about the abbreviation, Michael. I appreciate hearing your take on it.

Perhaps an optional code builder utility would satisfy those concerned with code maintenance.

I’m imagining something optional and simple that would assemble an Ansible module by replacing markers with standard functions in a source file.

To save the core from any complexity or dependencies, the developer would run this assembly process over their code before deploying the module for use in an Ansible system.

Don’t need it or like it? Don’t use it. Cut and paste your code and use search and replace to modify it. Ansible doesn’t know the difference.

Basically all you need a “ping” module (wait, we already have one) with the functions at the top, and tell people to copy
ping when starting new modules.

–Michael

I see what you mean but that’s not entirely fair statement.

As I’m developing some of my own modules I’ve written a few functions that are not in the ping module that I’ve reused a few times already. I’ve also had to make a change to one that required I go through each module and update the same code. It’s a drag.

I doubt I am alone nor will I be the last to reach this point.

So I was trying to make a suggestion to what could address this issue in the spirit of how you designed Ansible. I don’t think such a sarcastic remark was necessary.

As I’m developing some of my own modules I’ve written a few functions that are not in the ping module that I’ve reused a few times already. I’ve also had to make a change to one that required I go through each module and update the same code. It’s a drag.

I’m saying we should add them.

I doubt I am alone nor will I be the last to reach this point.

So I was trying to make a suggestion to what could address this issue in the spirit of how you designed Ansible. I don’t think such a sarcastic remark was necessary.

I don’t think you calling me sarcastic when I wasn’t was necessary.

As I'm developing some of my own modules I've written a few functions that are not in the ping module that I've reused a few times already. I've also had to make a change to one that required I go through each module and update the same code. It's a drag.

I'm saying we should add them.

They're specific to my company's unorthodox architecture.

I don't think you calling me sarcastic when I wasn't was necessary.

Then I don't get what you were saying with your ping module comment.

<tim/>

Then I don't get what you were saying with your ping module comment.

What I am saying is thus.

Since ping is a super minimal module, take all of our "good" best
practices functions, put them in that module, and commit it.

When people want to write a module, we say "go look at ping and extend
it, it has the building blocks you want"

Right now I would typically point someone at user or group, but it's
not exactly minimal, so between seeing how that one works, and the
basic primatives, it should be a good start.

If we were to write a stub program to generate a module, that *could*
in fact work, though I tend to think it wouldn't be much more than
"cat"... though it might put in the part that loads the arguments and
yells at you if they are not there, possibly.

Not opposed to that, it could live in examples/scripts.

--Michael