1

I have written a custom resource sshd_allow_groups that it's actions change a few of the node's attributes, and those are used in the creation of the template for /etc/sshd_config in the default recipe (in which the custom resource is hosted). However, since the custom resource is usually called from other cookbooks, there is no way for me to guarantee that the template resource will be called after the changes to the attributes are made, producing a situation in which it takes 2 chef runs to get the desired change.

I'm looking for a way to trigger the template resource after the resource are being called and to be run at the end (in case the resource is called several times). notifies does not work because the action for the template is not :nothing, nor it should be, because if for a certain node that resource is not required, the template still needs to be written.

my custom resource:

resource_name :sshd_allow_groups
property :group, String, name_property: true

default_action :append

action :append do
  currently = node['tom-ssh']['allow_groups']
  if currently
    if !currently.include?(group)
      node.normal['tom-ssh']['allow_groups'] = currently | [group]
    end
  else
    node.normal['tom-ssh']['allow_groups'] = [group]
  end
end

action :remove do
  currently = node['tom-ssh']['allow_groups']
  if currently && currently.include?(group)
    node.normal['tom-ssh']['allow_groups'] = currently - [group]
  end
end

another recipe should call it like this:

sshd_allow_groups "bob" do
  action :append
end
Tom Klino
  • 2,358
  • 5
  • 35
  • 60
  • Just notify delayed from your custom resource call, it will render the template twice eventually, but still get the correct file at end. That said, don't use normal level unless you know exactly what you're doing or you'll get surprises when you'll wish to remove someone from the group. All in all this sounds like a [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) where you're asking for a fix to a not effective solution to your real problem. – Tensibai Apr 19 '17 at 12:19
  • The `notifies` didn't work (I eventually figured that I need to use this to fix: http://stackoverflow.com/questions/21176576/how-to-i-get-a-chef-custom-lwrp-to-implement-notifies-and-not-if). What I really want to happen is not to need `notifies` at all, so that the resource itself will take care of (a more DRY code). And why is this an XY problem in your opinion? what do you think my X is? – Tom Klino Apr 19 '17 at 13:08
  • As far as I can tell, you wish to manage the sshd_config file. You're splitting this between a custom resource to update attributes and a template somewhere else, If the goal is to ease the attributes update, then go for a helper library, it will be available for every cookbook at compile time, fixing your compile vs converge actual problem where attributes are computed too late. – Tensibai Apr 19 '17 at 13:12
  • I deliberately did not ask directly about managing sshd attributes because there are a lot of existing solutions our there that appear easier but in our setting I cannot use them. About helper libraries, can you give an example to how I might use them to ease the attributes update? I've never did that before and from the documentation I don't see an easy way to even access them from a library (also I don't know how I would call it from a recipe if I needed it) – Tom Klino Apr 19 '17 at 13:21
  • I'd still be curious of why you're enforced to use this way of attributes overriding from recipe code for this use case btw. – Tensibai Apr 19 '17 at 13:52
  • It is just that we already have a lot of other definitions done by this template in other way. Using another way to change the sshd attributes, let say for example the sshd community cookbook, will overwrite the template we already have so ALL the existing definitions will now have to be done with the new method. Not to mention a lot of angry people that don't like it when too many things change – Tom Klino Apr 19 '17 at 13:59
  • I was just speaking of maybe using `lazy` evaluation as template attributes, or maybe other way, if you'd show how your template is made and ask about the most effective way to add this group management into it while keeping the existing things around, that won't be a XY problem anymore, here we're working around twisting attributes, which I don't think is an optimal manner, but I can't give advice without an idea of your actual recipe and template code – Tensibai Apr 19 '17 at 14:02

2 Answers2

0

In your cookbook libraries directory, in a helpers.rb file (doc and a blog post):

module Sshd_allow_groups
  module Helpers
    def append(group)
      node.normal['tom-ssh']['allow_groups'] = node['tom-ssh']['allow_groups'] | [group]
    end

    def remove(group)
        node.normal['tom-ssh']['allow_groups'] = node['tom-ssh']['allow_groups'] - [group]
    end
  end
end

In your recipe call it as:

Sshd_allow_group::Helpers.append("new_group")

Or if your are absolutely sure (and a such should rename the methods) you can include your helpers methods into the Recipe DSL:

::Chef::Recipe.send(:include, sshd_allow_groups::Helpers)

I've simplified a little your code as I don't feel the extra checks necessary, you may still have an exception raised if tom-ssh attribute doesn't exist.

I would try to get away of node.normal as it stays on the node, even if you remove a recipe adding a group later. More details about attributes here

Tensibai
  • 15,557
  • 1
  • 37
  • 57
0

Can't comment yet so need to post as an answer.. just a little nit I found while trying to follow examples tensibai gave in answer. Calling the helper method directly will not work with helper method defined in modules. You need to make the append/remove methods class instances. Add self. in front of append/remove. Then this call will work:

Sshd_allow_group::Helpers.append("new_group")

Or you can define the helper methods in a class to use instance methods, or use helpers in a class.

loafdog
  • 101
  • 7