Where is the better place for this code?

Hi :slight_smile:

I’m quite new here, but I really love the project and the community.
You all are great :slight_smile:

Well, I was writting a couple of new cookbooks for a project[1] where
I’m working on and I found that I need very often to check if some
string is in a file and replace just one string keepking the rest of
the file as it was.

For example a file that a user (or app) can write and usually does.
Maybe we like to be sure that specific value for a key is always the
right one, but not to change the part of the file where the user (or
app) has already changed.

I wrote some code for this (which is currently working), but I don’t
know if I did in the right place and in the right way. I love to have
it at Chef, but I guess it need to be proven useful and the community
agree. By now I put it in my cookbooks at:
cookbooks/the_cookbook/libraries/file.rb

Here is the actual code and example or recipe using it:

But I’ll write down here a simplier version:

def include?(str)
file_content = ::File.open(@path).read
return true if file_content =~ /#{str}/
return false
end

def replace(str, str2)
old_content = ::File.open(@path).read
content old_content.gsub(str, str2)
end

These methods are Chef::Resource::File’s methods. I wrote like that
because was the only way I got them working, but it seems to me that
it should be a Providers’ instead… I don’t know…

I hope you guy could give me some light about it. And also tell me if
you find this interesting enough to have it at Chef itself. I’m pretty
sure that I gonna use them a lot for my recipes…

Thanks a lot for your time.
Cheers

[1] http://www.guadalinex.org
http://goo.gl/WSoU2 (google treanslated version of the actual project)

Juanje

Hi Juan,

I am also new at this, so bear with me... And hope others will correct me
if I am giving the wrong advice.

I think you should use the "Template" resource... here is an example of its
usage to change the config file of the NTP server

template "/etc/ntp.conf" do
source "ntp.conf.erb"
variables( :ntp_server => "time.nist.gov" )
end

Note the template file is the ntp.conf.erb ( erb for embedded ruby as
in Rails *.erb ), and the file that would be produced as a result of
ERB substitution is /etc/ntp.conf...

The article below helped me a lot...

http://blog.afistfulofservers.net/post/3902042503/a-brief-chef-tutorial-from-concentrate

Look at Step 3... And please note that I have used it successfully.

Good luck

Hani Elabed

2011/11/15 Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com

Hi :slight_smile:

I'm quite new here, but I really love the project and the community.
You all are great :slight_smile:

Well, I was writting a couple of new cookbooks for a project[1] where
I'm working on and I found that I need very often to check if some
string is in a file and replace just one string keepking the rest of
the file as it was.

For example a file that a user (or app) can write and usually does.
Maybe we like to be sure that specific value for a key is always the
right one, but not to change the part of the file where the user (or
app) has already changed.

I wrote some code for this (which is currently working), but I don't
know if I did in the right place and in the right way. I love to have
it at Chef, but I guess it need to be proven useful and the community
agree. By now I put it in my cookbooks at:
cookbooks/the_cookbook/libraries/file.rb

Here is the actual code and example or recipe using it:
Add include? and replace(str, str2) to Chef::Resource::File · GitHub

But I'll write down here a simplier version:

def include?(str)
file_content = ::File.open(@path).read
return true if file_content =~ /#{str}/
return false
end

def replace(str, str2)
old_content = ::File.open(@path).read
content old_content.gsub(str, str2)
end

These methods are Chef::Resource::File's methods. I wrote like that
because was the only way I got them working, but it seems to me that
it should be a Providers' instead... I don't know...

I hope you guy could give me some light about it. And also tell me if
you find this interesting enough to have it at Chef itself. I'm pretty
sure that I gonna use them a lot for my recipes...

Thanks a lot for your time.
Cheers

[1] http://www.guadalinex.org
http://goo.gl/WSoU2 (google treanslated version of the actual project)

Juanje

Hi Hani,

On Wed, Nov 16, 2011 at 3:58 AM, hani elabed hani.elabed@gmail.com wrote:

Hi Juan,

I am also new at this, so bear with me... And hope others will correct me if
I am giving the wrong advice.
I think you should use the "Template" resource... here is an example of its
usage to change the config file of the NTP server

template "/etc/ntp.conf" do
source "ntp.conf.erb"
variables( :ntp_server => "time.nist.gov" )
end

Note the template file is the ntp.conf.erb ( erb for embedded ruby as in
Rails *.erb ), and the file that would be produced as a result of ERB
substitution is /etc/ntp.conf...

I know about the .erb templates but (AFAIK) it will create a new file
to replace the old one, but that's exactly what try to avoid.
I want to keep the old file because is a file that will contain
settings changed by the user (or app) that I want to keep. I just want
to change a single string from the current file, not create a new one.

Thans for the answer a nd your time anyway :slight_smile:

[...]

2011/11/15 Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com

Hi :slight_smile:

I'm quite new here, but I really love the project and the community.
You all are great :slight_smile:

Well, I was writting a couple of new cookbooks for a project[1] where
I'm working on and I found that I need very often to check if some
string is in a file and replace just one string keepking the rest of
the file as it was.

For example a file that a user (or app) can write and usually does.
Maybe we like to be sure that specific value for a key is always the
right one, but not to change the part of the file where the user (or
app) has already changed.

I wrote some code for this (which is currently working), but I don't
know if I did in the right place and in the right way. I love to have
it at Chef, but I guess it need to be proven useful and the community
agree. By now I put it in my cookbooks at:
cookbooks/the_cookbook/libraries/file.rb

Here is the actual code and example or recipe using it:
Add include? and replace(str, str2) to Chef::Resource::File · GitHub

But I'll write down here a simplier version:

def include?(str)
file_content = ::File.open(@path).read
return true if file_content =~ /#{str}/
return false
end

def replace(str, str2)
old_content = ::File.open(@path).read
content old_content.gsub(str, str2)
end

These methods are Chef::Resource::File's methods. I wrote like that
because was the only way I got them working, but it seems to me that
it should be a Providers' instead... I don't know...

I hope you guy could give me some light about it. And also tell me if
you find this interesting enough to have it at Chef itself. I'm pretty
sure that I gonna use them a lot for my recipes...

Thanks a lot for your time.
Cheers

[1] http://www.guadalinex.org
http://goo.gl/WSoU2 (google treanslated version of the actual project)

Juanje

--
Juanje

There are a few examples of this pattern in some providers in the base Chef. The service provider for FreeBSD should be an example.
This should probably be factored out into a common class or mixin for easier reuse in custom cookbooks.

On Nov 16, 2011, at 12:41 AM, Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com wrote:

Hi :slight_smile:

I'm quite new here, but I really love the project and the community.
You all are great :slight_smile:

Well, I was writting a couple of new cookbooks for a project[1] where
I'm working on and I found that I need very often to check if some
string is in a file and replace just one string keepking the rest of
the file as it was.

For example a file that a user (or app) can write and usually does.
Maybe we like to be sure that specific value for a key is always the
right one, but not to change the part of the file where the user (or
app) has already changed.

I wrote some code for this (which is currently working), but I don't
know if I did in the right place and in the right way. I love to have
it at Chef, but I guess it need to be proven useful and the community
agree. By now I put it in my cookbooks at:
cookbooks/the_cookbook/libraries/file.rb

Here is the actual code and example or recipe using it:
Add include? and replace(str, str2) to Chef::Resource::File · GitHub

But I'll write down here a simplier version:

def include?(str)
file_content = ::File.open(@path).read
return true if file_content =~ /#{str}/
return false
end

def replace(str, str2)
old_content = ::File.open(@path).read
content old_content.gsub(str, str2)
end

These methods are Chef::Resource::File's methods. I wrote like that
because was the only way I got them working, but it seems to me that
it should be a Providers' instead... I don't know...

Looking only at your gist it's a wash, but in general yes, I would use an LWRP. Keep the library, but put the "file" resource in an LWRP.

I hope you guy could give me some light about it. And also tell me if
you find this interesting enough to have it at Chef itself. I'm pretty
sure that I gonna use them a lot for my recipes...

Thanks a lot for your time.
Cheers

[1] http://www.guadalinex.org
http://goo.gl/WSoU2 (google treanslated version of the actual project)

Juanje

On Wed, Nov 16, 2011 at 9:19 AM, Andrea Campi
andrea.campi@zephirworks.com wrote:

There are a few examples of this pattern in some providers in the base Chef. The service provider for FreeBSD should be an example.
This should probably be factored out into a common class or mixin for easier reuse in custom cookbooks.

Yep, I think so. I could be nice to have this kind of methods
availables from cookbooks or even other parts of Chef.

Actually the check, enable and disable of Freebsd services is quite
useful to manage other conffiles.

On Nov 16, 2011, at 12:41 AM, Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com wrote:
[...]

I wrote some code for this (which is currently working), but I don't
know if I did in the right place and in the right way. I love to have
it at Chef, but I guess it need to be proven useful and the community
agree. By now I put it in my cookbooks at:
cookbooks/the_cookbook/libraries/file.rb

Here is the actual code and example or recipe using it:
Add include? and replace(str, str2) to Chef::Resource::File · GitHub

But I'll write down here a simplier version:

def include?(str)
file_content = ::File.open(@path).read
return true if file_content =~ /#{str}/
return false
end

def replace(str, str2)
old_content = ::File.open(@path).read
content old_content.gsub(str, str2)
end

These methods are Chef::Resource::File's methods. I wrote like that
because was the only way I got them working, but it seems to me that
it should be a Providers' instead... I don't know...

Looking only at your gist it's a wash, but in general yes, I would use an LWRP. Keep the library, but put the "file" resource in an LWRP.

Sorry, but I don't get what you are saying :-/ I thing my English is
not as good as I thought. What do you mean by 'wash'?
Could you explain to me what do you mean by keep the library but
putting the 'file' resource in an LWRP? I'm a bit confuse, sorry.

Thanks a lot for your answer.

--
Juanje

2011/11/16 Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com:

On Wed, Nov 16, 2011 at 9:19 AM, Andrea Campi

On Nov 16, 2011, at 12:41 AM, Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com wrote:
[...]

I wrote some code for this (which is currently working), but I don't
know if I did in the right place and in the right way. I love to have
it at Chef, but I guess it need to be proven useful and the community
agree. By now I put it in my cookbooks at:
cookbooks/the_cookbook/libraries/file.rb

Here is the actual code and example or recipe using it:
Add include? and replace(str, str2) to Chef::Resource::File · GitHub

But I'll write down here a simplier version:

def include?(str)
file_content = ::File.open(@path).read
return true if file_content =~ /#{str}/
return false
end

def replace(str, str2)
old_content = ::File.open(@path).read
content old_content.gsub(str, str2)
end

These methods are Chef::Resource::File's methods. I wrote like that
because was the only way I got them working, but it seems to me that
it should be a Providers' instead... I don't know...

Looking only at your gist it's a wash, but in general yes, I would use an LWRP. Keep the library, but put the "file" resource in an LWRP.

Sorry, but I don't get what you are saying :-/ I thing my English is
not as good as I thought. What do you mean by 'wash'?

Ah, sorry, it's kind of idiomatic—I meant "you can do it either way,
each has pros and cons".

Could you explain to me what do you mean by keep the library but
putting the 'file' resource in an LWRP? I'm a bit confuse, sorry.

Sure.
In your gist, I wouldn't change anything in the library; I would
remove the recipe and replace it with an LWRP:

resources/gtk_bookmarks.rb

action :replace # and possibly more

attribute :name, :kind_of => String, :name_attribute => true
attribute :owner, :kind_of => String
attribute :group, :kind_of => String
attribute :before, :kind_of => String
attribute :after, :kind_of => String

providers/gtk_bookmarks.rb

action :replace do
file new_resource.name do
replace(new_resource.before, new_resource.after) if
include?(new_resource.before)
owner new_resource.owner
group new_resource.group
mode "0644"
action :create_if_missing
end
end

This way you can call it with:

<cookbook_name>_gtk_bookmarks "/home/#{node.user}/.gtk-bookmarks" do
before "smb"
after "smb"
owner node.user
group node.user
action :replace
end

Makes more sense?

Just for completeness: in this case it would probably be easier/faster
to use a definition instead. But the LWRP is useful in case you want
to add other actions (:add, :replace, :gsub come to mind).

definitions/gtk_bookmarks.rb

define :gtk_bookmarks_replace do
file params[:name] do
replace(params[:before], params[:after]) if include?(params[:before])
owner params[:owner]
group params[:group]
mode "0644"
action :create_if_missing
end
end

You would call this in the exact same way.

One more thing to keep in mind in all cases, even your first:
resources are unique per run, so if you try to modify this same file
twice in a run, that's going to be a problem. That's true in general,
but when you introduce LWRPs and definitions it may become hard to
diagnose.
The solution here would be something like:

filename = "/path/to/your/file"
file "#{filename} (replace)" do
path filename

and then everything else

end

Basically this will just make give the resource a unique name (which
will show up in logs), and then set the "real" path.

Hope it helps.

Andrea

On Wed, Nov 16, 2011 at 1:25 PM, Andrea Campi
andrea.campi@zephirworks.com wrote:

2011/11/16 Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com:

On Wed, Nov 16, 2011 at 9:19 AM, Andrea Campi

On Nov 16, 2011, at 12:41 AM, Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com wrote:
[...]

I wrote some code for this (which is currently working), but I don't
know if I did in the right place and in the right way. I love to have
it at Chef, but I guess it need to be proven useful and the community
agree. By now I put it in my cookbooks at:
cookbooks/the_cookbook/libraries/file.rb

Here is the actual code and example or recipe using it:
Add include? and replace(str, str2) to Chef::Resource::File · GitHub

But I'll write down here a simplier version:

def include?(str)
file_content = ::File.open(@path).read
return true if file_content =~ /#{str}/
return false
end

def replace(str, str2)
old_content = ::File.open(@path).read
content old_content.gsub(str, str2)
end

These methods are Chef::Resource::File's methods. I wrote like that
because was the only way I got them working, but it seems to me that
it should be a Providers' instead... I don't know...

Looking only at your gist it's a wash, but in general yes, I would use an LWRP. Keep the library, but put the "file" resource in an LWRP.

Sorry, but I don't get what you are saying :-/ I thing my English is
not as good as I thought. What do you mean by 'wash'?

Ah, sorry, it's kind of idiomatic—I meant "you can do it either way,
each has pros and cons".

Thanks, I learn something every day :slight_smile:

Could you explain to me what do you mean by keep the library but
putting the 'file' resource in an LWRP? I'm a bit confuse, sorry.

Sure.
In your gist, I wouldn't change anything in the library; I would
remove the recipe and replace it with an LWRP:

resources/gtk_bookmarks.rb

action :replace # and possibly more

attribute :name, :kind_of => String, :name_attribute => true
attribute :owner, :kind_of => String
attribute :group, :kind_of => String
attribute :before, :kind_of => String
attribute :after, :kind_of => String

providers/gtk_bookmarks.rb

action :replace do
file new_resource.name do
replace(new_resource.before, new_resource.after) if
include?(new_resource.before)
owner new_resource.owner
group new_resource.group
mode "0644"
action :create_if_missing
end
end

This way you can call it with:

<cookbook_name>_gtk_bookmarks "/home/#{node.user}/.gtk-bookmarks" do
before "smb"
after "smb"
owner node.user
group node.user
action :replace
end

Makes more sense?

Makes a lot of sense :slight_smile:
You actually give me some light about how to use LWRP. I think I
have't get fully right before.

Just for completeness: in this case it would probably be easier/faster
to use a definition instead. But the LWRP is useful in case you want
to add other actions (:add, :replace, :gsub come to mind).

definitions/gtk_bookmarks.rb

define :gtk_bookmarks_replace do
file params[:name] do
replace(params[:before], params[:after]) if include?(params[:before])
owner params[:owner]
group params[:group]
mode "0644"
action :create_if_missing
end
end

You would call this in the exact same way.

Another piece of light, thanks :slight_smile:

One more thing to keep in mind in all cases, even your first:
resources are unique per run, so if you try to modify this same file
twice in a run, that's going to be a problem. That's true in general,
but when you introduce LWRPs and definitions it may become hard to
diagnose.
The solution here would be something like:

filename = "/path/to/your/file"
file "#{filename} (replace)" do
path filename

and then everything else

end

Basically this will just make give the resource a unique name (which
will show up in logs), and then set the "real" path.

That's really good to know. Thanks again :slight_smile:

Hope it helps.

It does, indeed.

I'll try with the LWRP.
Anyway, I'd love to have methods like those availables from all the
cookbooks wich are going to manage files. Also a provider for
conffiles (as the FreeBSD service) would be nice, don't you think?
Maybe I look into that after I finish this...

Thank you so much for your help. I really appreciate it.

--
Juanje

2011/11/16 Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com:

I'll try with the LWRP.
Anyway, I'd love to have methods like those availables from all the
cookbooks wich are going to manage files. Also a provider for
conffiles (as the FreeBSD service) would be nice, don't you think?
Maybe I look into that after I finish this...

Would be useful indeed.
We use FreeBSD a lot, and since we started using Chef I moved away
from a monolithic /etc/rc.conf to one file per service in
/etc/rc.conf.d
This somewhat reduces our need for in-place editing of files, but here
and there the requirements comes out again.

Given it's not FreeBSD-specific, I keep hoping someone will beat me to
it—otherwise at some point I'll sit down and look at it.
Maybe on the flight to the Chef Summit :slight_smile:

Andrea

On Wednesday, November 16, 2011 at 6:29 AM, Andrea Campi wrote:

Would be useful indeed.
We use FreeBSD a lot, and since we started using Chef I moved away
from a monolithic /etc/rc.conf to one file per service in
/etc/rc.conf.d
This somewhat reduces our need for in-place editing of files, but here
and there the requirements comes out again.

Given it's not FreeBSD-specific, I keep hoping someone will beat me to
it—otherwise at some point I'll sit down and look at it.
Maybe on the flight to the Chef Summit :slight_smile:

Andrea
Chef already has code for this: https://github.com/opscode/chef/blob/master/chef/lib/chef/util/file_edit.rb

That said, you really should do whatever you can to avoid using search/replace.

--
Dan DeLeo

On Thu, Nov 17, 2011 at 6:27 PM, Daniel DeLeo dan@kallistec.com wrote:

On Wednesday, November 16, 2011 at 6:29 AM, Andrea Campi wrote:

Would be useful indeed.
We use FreeBSD a lot, and since we started using Chef I moved away
from a monolithic /etc/rc.conf to one file per service in
/etc/rc.conf.d
This somewhat reduces our need for in-place editing of files, but here
and there the requirements comes out again.

Given it's not FreeBSD-specific, I keep hoping someone will beat me to
it—otherwise at some point I'll sit down and look at it.
Maybe on the flight to the Chef Summit :slight_smile:

Andrea
Chef already has code for this: https://github.com/opscode/chef/blob/master/chef/lib/chef/util/file_edit.rb

That said, you really should do whatever you can to avoid using search/replace.

Hummm... I'm curious... why's that?

BTW, thanks for the link :slight_smile:

--
Juanje

2011/11/17 Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com:

Chef already has code for this: https://github.com/opscode/chef/blob/master/chef/lib/chef/util/file_edit.rb

That said, you really should do whatever you can to avoid using search/replace.

Hummm... I'm curious... why's that?

BTW, thanks for the link :slight_smile:

--
Juanje

The proper path is to manage the file with Chef (as a template) or
move the setting/line it needs somewhere that Chef can manage.

Search and replace is fragile.

Depending on the type of file, you can:

  • substitute an environment variable sourced from a file that Chef DOES manage.
  • include another file that chef manages at the head of the file that
    needs the setting
  • merge the contents of that file with another file that chef manages
    as part of the recipe
  • move the setting out of that file into some sort of configuration repository

On Thu, Nov 17, 2011 at 6:41 PM, John E. Vincent (lusis)
lusis.org+chef-list@gmail.com wrote:

2011/11/17 Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com:

Chef already has code for this: https://github.com/opscode/chef/blob/master/chef/lib/chef/util/file_edit.rb

That said, you really should do whatever you can to avoid using search/replace.

Hummm... I'm curious... why's that?

BTW, thanks for the link :slight_smile:

The proper path is to manage the file with Chef (as a template) or
move the setting/line it needs somewhere that Chef can manage.

Search and replace is fragile.

Depending on the type of file, you can:

  • substitute an environment variable sourced from a file that Chef DOES manage.
  • include another file that chef manages at the head of the file that
    needs the setting
  • merge the contents of that file with another file that chef manages
    as part of the recipe
  • move the setting out of that file into some sort of configuration repository

I see... but I'm not sure that none of those are my case. I'll show
you a real example to see if it could be done with one of those
approach:

I need to be sure that the homepage for the Firefox on all the nodes
(Ubuntu based clients) I'm managing with Chef are always the same. The
homepage is defined (after the user launch the first time the Firefox)
at the home: /home/user/.mozilla/firefox/profile/prefs.js

There are some configurations defined like this:
...
user_pref("browser.rights.3.shown", true);
user_pref("browser.startup.homepage", "http://www.google.com");
user_pref("browser.startup.homepage_override.buildID", "20111008085652");
user_pref("browser.startup.homepage_override.mstone", "rv:7.0.1");
...

At my organization I can let the users change others configurations,
but the homepage, so I want to change just that, no using a template
or new file to overwrite the file.

That's why search and replace sounded a good option for me. And this
is just one of the similar files I have to manage in a similar way.
I guess I could try the merge as you said for some of them, but I
don't think that I could for all.

But maybe I didn't get well all the options you give me, it's very
possible. Or I'm missing something at my problem.
Anyway, all the responses are being very enlighten for me, I start to
understand better the whole picture (I think)

Thanks :slight_smile:

--
Juanje

I think what you want to look into is locking
preferenceshttp://kb.mozillazine.org/Lock_Prefs.
That strategy looks like it has the advantage of not touching the
individual users' config files; you create two new files in the Firefox
installation directory instead (these could be templates or cookbook_files):

  • /defaults/pref/local-settings.js
  • /mozilla.cfg

I just tried the setting out on my Mac, and it worked - I could make it so
users were not allowed to change their homepage. It seems like your
mileage may vary depending on your platform; I don't have a Linux desktop
to test it on at the moment.

-Matt Moretti

2011/11/17 Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com

hef are always the same. The
homepage is defined (after the user launch the first time the Firefox)
at the home: /home/user/.mozilla/firefox/profile/pr

On Thu, Nov 17, 2011 at 9:10 PM, Matthew Moretti werebus@gmail.com wrote:

I think what you want to look into is locking preferences. That strategy
looks like it has the advantage of not touching the individual users' config
files; you create two new files in the Firefox installation directory
instead (these could be templates or cookbook_files):

/defaults/pref/local-settings.js
/mozilla.cfg

Thanks for the tip. I knew was something like this, but it was just
the closer example I have of my problem. Anyway, for this case is
better the way you pint out.
Thanks :slight_smile:

I just tried the setting out on my Mac, and it worked - I could make it so
users were not allowed to change their homepage. It seems like your mileage
may vary depending on your platform; I don't have a Linux desktop to test it
on at the moment.

I'll try, but I think that I did before time ago and it did work.
Thanks again :slight_smile:

2011/11/17 Juan Jesús Ojeda Croissier juanje.ojeda@gmail.com

hef are always the same. The
homepage is defined (after the user launch the first time the Firefox)
at the home: /home/user/.mozilla/firefox/profile/pr

--
Juanje

On Thu, Nov 17, 2011 at 6:27 PM, Daniel DeLeo dan@kallistec.com wrote:

On Wednesday, November 16, 2011 at 6:29 AM, Andrea Campi wrote:

Given it's not FreeBSD-specific, I keep hoping someone will beat me to
it—otherwise at some point I'll sit down and look at it.
Maybe on the flight to the Chef Summit :slight_smile:

Andrea
Chef already has code for this: https://github.com/opscode/chef/blob/master/chef/lib/chef/util/file_edit.rb

Fair enough (I hadn't seen that class).

Then I'll rephrase: lib/chef/provider/service/freebsd.rb should be
updated to use FileEdit.
I will do it at some point—I agree search & replace is an
anti-pattern, but we have to rely on it.

The better option here would be to add support for /etc/rc.conf.d; we
could do that out of the box. Chef is opinionated after all :wink:

Andrea