Coder Social home page Coder Social logo

chef-cookbooks's Introduction

Facebook Cookbooks Suite

Continuous Integration

This repo contains attribute-driven-API cookbooks maintained by Facebook. It's a large chunk of what we refer to as our "core cookbooks."

It's worth reading our Philosophy.md doc before reading this. It covers how we use Chef and is important context before reading this.

It is important to note that these cookbooks are built using a very specific model that's very different from most other cookbooks in the community. Specifically:

  • It assumes an environment in which you want to delegate. The cookbooks are designed to be organized in a "least specific to most specific" order in the run-list. The run-list starts with the "core cookbooks" that setup APIs and enforce a base standard, which can be adjusted by the service owners using cookbooks later in the run-list.
  • It assumes a "run from main" type environment. At Facebook we use Grocery Delivery to sync the main branch of our source control repo with all of our Chef servers. Grocery Delivery is not necessary to use these cookbooks, but since they were built with this model in mind, the versions never change (relatedly: we do not use environments).
  • It assumes you have a testing toolset that allows anyone modifying later cookbooks to ensure that their use of the API worked as expected on a live node before committing. For this, we use Taste Tester.

Cookbooks in this repo all being with fb_ to denote that not only do they use the Facebook Cookbook Model, but that they are maintained in this repo.

Local cookbooks or cookbooks in other repositories that implement this model should not use this prefix, but should reference this document in their docs.

APIs

Unlike other cookbook models, we do not use resources as APIs, we use the node object. Configuration is modeled in arrays and hashes as closely and thinly as possible to the service we are configuring. Ideally, you should only have to read the docs to the service to configure it, not the docs to the cookbook.

For example, if the service we are configuring has a key-value pair configuration file, we will provide a simple hash where keys and values will be directly put into the necessary configuration file.

There are two reasons we use attribute-driven APIs:

  1. Cascading configuration Since our cookbooks are ordered least specific (core team that owns Chef) to most specific (the team that owns this machine or service) it means that the team who cares about this specific instance can always override anything. This enables stacking that is not possible in many other models. For example, you can have a run-list that looks like:

    • Core cookbooks (the ones in this repo)
    • Site/Company cookbooks (site-specific settings)
    • Region cookbooks (overrides for a given region/cluster)
    • Application Category cookbooks (webserver, mail server, etc.)
    • Specific Application cookbook ("internal app1 server")

    So let's say that you want a specific amount of shared memory by default, but in some region you know you have different size machines, so you shrink it, but web servers need a further different setting, and then finally some specific internal webserver needs an even more specific setting... this all just works.

    Further, a cookbook can see the value that was set before it modifies things, so the 'webserver' cookbook could look to see what the value was (small or large) before modifying it and adjust it accordingly (so it could be relative to the size of memory that the 'region' cookbook set).

    Using resources for this does not allow this "cascading", it instead creates "fighting". If you use the cron resource to setup an hourly job, and then someone else creates a cron for that same job but only twice a day, then during each Chef run the cron job gets modified to hourly, then re-modified to twice a day.

  2. Allows for what we refer to as "idempotent systems" instead of "idempotent settings." In other words, if you only manage a specific item in a larger config, and then you stop managing it, it should either revert to a less-specific setting (see #1) or be removed, as necessary.

    For example let's say you want to set a cron job. If you use the internal cron resource, and then delete the recipe code that adds that cronjob, that cron isn't removed from your production environment - it's on all existing nodes, but not on any new nodes.

    For this reason we use templates to take over a whole configuration wherever possible. All cron jobs in our fb_cron API are written to /etc/cron.d/fb_crontab. If you delete the lines adding a cronjob, since they are just entries in a hash, when the template is generated on the next Chef run, those crons go away.

    Alternatively, consider a sysctl set by the "site" cookbook, then overwritten by a later cookbook. When that later code is removed, the entry in the hash falls back to being set again by the next-most-specific value (i.e. the "site" cookbook in this case).

Run-lists

How you formulate your run-lists is up to your site, as long as you follow the basic rule that core cookbooks come first and you order least-specific to most-specific. At Facebook, all of our run-lists are:

recipe[fb_init], recipe[$SERVICE]

Where fb_init is similar to the sample provided in this repo, but with extra "core cookbooks."

We generally think of this way: fb_init should make you a "Facebook server" and the rest should make you a whatever-kind-of-server-you-are.

Getting started

Grab a copy of the repo, rename fb_init_sample to fb_init, and follow the instructions in its README.md (coordinating guidance is in comments in the default recipe).

Other Guidelines

Modules and classes in cookbooks

It is often useful to factor out logic into a library - especially logic that doesn't create resources. Doing so makes this logic easier to unit test and makes the recipe or resource cleaner.

Our standard is that all cookbooks use the top-level container of module FB, and then create a class for their cookbook under that. For example, fb_fstab creates a class Fstab inside of the module FB. We will refer to this as the cookbook class from here.

We require all cookbooks use this model for consistency.

Since we don't put anything other than other classes inside the top-level object, it's clear that a module is the right choice.

While there is no reason that a cookbook class can't be one designed to be instantiated, more often than not it is simply a collection of class methods and constants (i.e. static data and methods that can then be called both from this cookbook and others).

Below the cookbook class, the author is free to make whatever class or methods they desire.

When building a complicated Custom Resource, the recommended pattern is to factor out the majority of the logic into a module, inside of the cookbook class, that can be included in the action_class. This allows the logic to be easily unit tested using standard rspec. It is preferred for this module to be in its own library file, and for its name to end in Provider, ala FB::Thing::ThingProvider.

When more than 1 or 2 methods from this module are called from the custom resource itself, it is highly recommended you include it in a Helper class for clarity, ala:

action_class do
  class ThingHelper
    include FB::Thing::ThingProvider
  end
end

In this way, it is clear where methods come from.

Extending the node vs self-contained classes

You may have noticed that some of our cookbooks will extend the node object, while others have self-contained classes that sometimes require the node be passed as a parameter to some methods.

In general, the only time when extending the node is acceptable is when you are simply making a convenience function around using the node object. So, for example, instead of making people do node['platform_family'] = 'debian', there's a node.debian?. This is simply syntactic sugar on top of data entirely in the node.

In all other cases, one should simply have the node be an argument passed on, so as to not pollute the node namespace. For example, a method that looks at the node attributes, but also does a variety of other logic, should be in a cookbook class and take the node as an argument (per standard programming paradigms about clear dependencies).

Methods in recipes

Sometimes it is convenient to put a method directly in a recipe. It is strongly preferred to put these methods in the cookbook class, however there are some cases where methods directly in recipes make sense. The primary example is a small method which creates a resource based on some input to make a set of loops more readable.

Methods in templates

Methods should not be put into templates. In general, as little logic as possible should be in templates. In general the easiest way to do this is to put the complex logic into methods in your cookbook class and call them from the templates.

Err on the side of fail

Chef is an ordered system and thus is designed to fail a run if a resource cannot be converged. The reason for this is that if one step in an ordered list cannot be completed, it's likely not safe to do at least some of the following steps. For example, if you were not able to write the correct configuration for a service, then starting it may open up a security vulnerability.

Likewise, the Facebook cookbooks will err on the side of failing if something seems wrong. This is both in line with the Chef philosophy we just outlined, but also because this model assumes that code is being tested on real systems before being released using something like taste-tester and that monitoring is in place to know if your machines are successfully running Chef.

Here are some examples of this philosophy in practice:

  • If a cookbook is included on a platform it does not support, we fail. It might seem like returning in this case is reasonable but there is a good indication the run-list isn't as-expected, so it's a great idea to bail out before this machine is mis-configured.
  • If a configuration was passed in that we don't support, rather than ignore it we fail.

Validation of inputs and whyrun_safe_ruby_blocks

Many cookbooks rely on the service underneath and the testing of the user to be the primary validator of inputs. Is the software we just configured, behaving as expected?

However, sometimes it's useful to do our own validation because there are certain configurations we don't want to support, because the software may accepted dangerous configurations we want to catch, or because the user could pass us a combination of configurations that is conflicting or impossible to implement.

In this model, however, this must be done at runtime. If your implementation is done primarily inside of an internally-called resource, then this validation can also be done there. However, if your implementation is primarily a recipe and templates, doing the validation in templates is obviously not desirable. This is where whyrun_safe_ruby_blocks come in.

Using an ordinary ruby_block would suffice to have ruby code run at runtime to validate the attributes, however that means that the error would not be caught in whyrun mode. Since this validation does not change the system, it is safe to execute in whyrun mode, and that's why we use whyrun_safe_ruby_blocks: they are run in whyrun mode.

It is worth noting that this is also where you can take input that perhaps was in a structure convenient for users and build out a different data structure that's more convenient to use in your template.

Implementing runtime-safe APIs

This model intentionally draws the complexity of Chef into the "core cookbooks" (those implementing APIs) so that the user experience of maintaining systems is simple and (usually) requires little more than writing to the node object. However, the trade-off for that simplicity is that implementing the API properly can be quite tricky.

How to do this is a large enough topic that it gets its own document. However, some style guidance is also useful. This section assumes you have read the aforementioned document.

The three main ways that runtime-safety is achieved are lazy, templates, and custom resources. When should you use which?

The template case is fairly straight forward - if you have a template, read the node object from the within the template source instead of using variables on the template resource, and all data read is inherently runtime safe since templates run at runtime.

But what about lazy vs custom resources? For example, in a recipe you might do:

package 'thingy packages' do
  package_name lazy {
    pkgs = 'thingy'
    if node['fb_thingy']['want_devel']
      pkgs << 'thingy-devel'
    end
    pkgs
  }
  action :upgrade
end

Where as inside of a custom resource you could instead do:

pkgs = 'thingy'
if node['fb_thingy']['want_devel']
  pkgs << 'thingy-devel'
end

package pkgs do
  action :upgrade
end

Which one is better? There's not an exact answer, both work, so it's a style consideration. In general, there are two times when we suggest a custom resource:

The first is when you need to loop over the node in order to even know what resources to create. Since this isn't possible to (well, technically it's possible with some ugliness, but by and large not using the standard DSL), this must go into a custom resource. Example might be:

# This MUST be inside of a custom resource!
node['fb_thingy']['instances'].each do |name, config|
  template "/etc/thingy/#{instance}.conf" do
    owner 'root'
    group 'root'
    mode '644'
    variables({:config => config})
  end
end

The second is when you're using lazy on the majority of the resources in your recipe. If your recipe has 15 resources and you've had to pepper all of them with lazy, it's a bit cleaner to make a custom resource that you call in your recipe.

It's important here to reiterate: we're not referring to using a Custom Resource as an API, but simply making an internal custom resource, called only by your own recipe, as a way to simplify runtime safety.

Outside of these two cases, you should default to implementations inside of recipes. This is for a few reasons.

The first reason is that dropping entire implementations in custom resources leads to confusion and sets a bad precedent for how runtime-safety works. For example, consider the custom resource code we saw earlier where you assemble the package list in "naked" ruby:

pkgs = 'thingy'
if node['fb_thingy']['want_devel']
  pkgs << 'thingy-devel'
end

This code works fine in a resource, but serves as a bad reference for others - since this absolutely won't work in a recipe (even though it'll run).

The second reason is that quite often implementations need both compile-time and runtime code, and by blindly dropping the implementation into a custom resource, you can often miss this and create bugs like this:

# only safe because we're in a custom resource
packages = FB::Thingy.determine_packages(node)

package packages do
  action :upgrade
end

if node['fb_thingy']['want_cron']
  node.default['fb_cron']['jobs']['thingy_runner'] = {
    'time' => '* * * * *',
    'command' => '/usr/bin/thingy --quiet',
  }
end

service 'thingy' do
  action [:enable, :start]
end

Note here that while this code all seems reasonable in a custom resource (if statements are runtime safe when inside of a custom resource), that cronjob will never get picked up, because you're using an API at runtime, but APIs must be called at compile time and consumed at runtime. In reality, this needs to be in the recipe in order to work, and should look like this, in a recipe:

package 'thingy packages' do
  package_name lazy { FB::Thingy.determine_packages(node) }
  action :upgrade
end

node.default['fb_cron']['jobs']['thingy_runner'] = {
  'only_if' => proc { node['fb_thingy']['want_cron'] },
  'time' => '* * * * *',
  'command' => '/usr/bin/thingy --quiet',
}

service 'thingy' do
  action [:enable, :start]
end

In general, always start your implementation as a recipe and then escalate to Custom Resources where necessary.

Debugging kitchen runs

You can set up kitchen using the same commands as in .github/workflows/ci.yml, but once Chef runs you won't have access to connect, so modify fb_sudo/attributes/default.rb and uncomment the kitchen block.

Then you can do bundle exec kitchen login <INSTANCE> after a failed run, and sudo will be passwordless so you can debug.

License

See the LICENSE file in this directory

chef-cookbooks's People

Contributors

davide125 avatar jaymzh avatar NaomiReeves avatar joshuamiller01 avatar malmond77 avatar Babar avatar rb2k avatar anitazha avatar claudiozz avatar dafyddcrosby avatar michel-slm avatar gogsbread avatar ifel avatar marksantaniello avatar HeyItsGilbert avatar get9 avatar codwazny avatar patcox avatar kernel-patches-bot avatar ekacnet avatar scottruss avatar nmcspadden avatar srihanfb avatar ChefAustin avatar dschatzberg avatar ImanolBarba avatar steelcowboy avatar adamsb6 avatar epilatow avatar epvergara avatar

Stargazers

Max Kerp avatar Marcin Skarbek avatar Amit Vijairania avatar  avatar  avatar David T. Crosby avatar Jonathan Roemer avatar RXWatcher avatar Anthony Rabbito avatar Neal Gompa (ニール・ゴンパ) avatar theo avatar Diego De Santiago avatar Karim Hammami avatar  avatar Clay Hausen avatar Tina Huynh avatar Chase Jensen avatar Joshua Haupt avatar  avatar Laxman Goswami avatar Reza Eskandari avatar Victor-ray avatar Shanrath avatar Nanda avatar Marco Miduri avatar Ammar Faizi avatar Keith Babinec avatar Michael  Martin avatar Cheesy Muffins avatar Nuno Azevedo avatar  avatar Xinyu Chen avatar Son Ki-Kyun avatar  avatar 南知 avatar Andrew Kapocsi avatar Johnny Martínez avatar  avatar Keany Vy KHUN avatar @GOUAIC avatar Xinhe(Rita) Wang avatar Amit Sharma avatar Abel Sen avatar Miroslav Hadzhiev avatar Kiet Nguyen avatar Codeb Fan avatar Ben Feld avatar Abhishek avatar Neeraj Sehgal avatar Jeket avatar Alhazred II avatar lilkypimp1 avatar  avatar Oliver Fletcher avatar Badre Kabbou avatar Joaquín Mellado Quevedo avatar Gilbert Sanchez avatar Nima avatar Grathium avatar Adithya Krishna avatar Jk Jensen avatar Cloud Xu avatar Wen Yang avatar Eduardo Chavez avatar Taylor Hoff avatar Andrew Jocson avatar W Geng avatar Jonathan Ho avatar Tim Johnson avatar  avatar Andrew Ryan Davis avatar Christo De Lange avatar Bogdan avatar Roman avatar Alexander Lavesson avatar Antoine Dumoulin avatar Julieta Navarro avatar George Kontridze avatar Sergio Galvan avatar Graham MacGregor avatar Gábor Mihálcz avatar zou shengfu avatar Harry Reeder avatar Justin Woodward avatar Sabbir Ahmed avatar Asmo Porma avatar  avatar Francesco 'makevoid' Canessa avatar Stanislav avatar nantian avatar Adam Lane avatar  avatar waskito shidiq avatar  avatar Amin Khoshnood avatar Arystan avatar  avatar Trevor Wood avatar  avatar  avatar

Watchers

Deepak Kannan avatar Robby O'Connor avatar Justin Roth avatar  avatar Scott Bulua avatar Aaron Peterson avatar Jyotsna Chatradhi avatar  avatar  avatar Davide Cavalca avatar Basilio Briceño avatar Afenomamy avatar KC Braunschweig avatar David T. Crosby avatar James Cloos avatar Michael Bishop avatar Phil Dibowitz avatar Sukonkan Santisuwan avatar Aaron Kushner avatar  avatar Chibipond avatar DongQiang avatar Aravind Anbudurai avatar  avatar Edgar Ezequiel Gonzalez Rodriguez avatar  avatar Jéan Thysse avatar Joshua Miller avatar Jason Chodakowski avatar Franciszek Stokowacki avatar  avatar  avatar Kathir Eldush avatar danzamerlot avatar William Herrin avatar Andrew Ryan Davis avatar Facebook Whois Bot avatar  avatar Naomi Reeves avatar Chandra Shekhar avatar  avatar Peter Wayne avatar 曹文忠 avatar Bipin Bachhao avatar  avatar  avatar  avatar  avatar https://api.github.com/_private/junaidfarhan94 avatar Jonathan avatar  avatar  avatar  avatar  avatar Daniel Jakobsson avatar

chef-cookbooks's Issues

fb_storage always ignores override files when '_clowntown_override_file_method' not defined

According to both the docs and the logs, '_clowntown_override_file_method' allows you to add additional restrictions to when override files take effect, but if it's not defined, then they always take effect.

Turns out, this isn't true, we always return false. This is a simple bug, but fixing it it probably requires a slow rollout to FB so I haven't sent a PR.

Docs:

For additional safety, you can define a check method in
`node['fb_storage']['_clowntown_override_file_method']`
that will be invoked whenever override files are evaluated.

Actual code where we say we're ignore the method, but then returnf alse.

      def override_file_applies?(verb, fname, quiet = false)
        if File.exist?(fname)
          base_msg = "fb_storage: System has #{fname} file present"
          if node['fb_storage']['_clowntown_override_file_method']
            ...
          end
          unless quiet
            Chef::Log.warn(
              "#{base_msg} but the override check method is not defined, " +
              'therefore we are ignoring it.',
            )
          end
          return false   # this should be `true`
        end
        return false
      end

Enablement of `unified_mode` for v17+ Chef client compatibility

Describe the Enhancement:

Converging the cookbooks in this repo on a v17+ Chef client result in the following deprecation warning being thrown at the end of the run (using fb_systemd as an example):

  The  resource in the fb_systemd cookbook should declare `unified_mode true` at 2 locations:
    - /var/chef/cache/cookbooks/fb_systemd/resources/loader_entries.rb
    - /var/chef/cache/cookbooks/fb_systemd/resources/reload.rb
   See https://docs.chef.io/deprecations_unified_mode/ for further details.

See: https://docs.chef.io/unified_mode/

Describe the Need:

Anyone using Chef client v17+ will face this deprecation warning until unified_mode true is appended to the first line of each custom resource file.

Current Alternative

Ignore the deprecation warning.

Can We Help You Implement This?:

Should be a relatively easy PR (or series of PR's) to craft.

apt-key does not output short key IDs in debian 9

Hi,

The provider code:

if keys && keyring
installed_keys = []
if ::File.exist?(keyring)
cmd = Mixlib::ShellOut.new("LANG=C apt-key --keyring #{keyring} list")
cmd.run_command
cmd.error!
output = cmd.stdout.split("\n")
Chef::Log.debug("apt-key output: #{output.join("\n")}")
installed_keys = output.select { |x| x.start_with?('pub') }.map do |x|
x[%r{pub./(?[A-Z0-9])}, 'keyid']
end
end

Does not detect the debian 9 apt-key output:

pub rsa4096 2016-10-05 [SC]
72EC F46A 56B4 AD39 C907 BBB7 1646 B01B 86E5 0310
uid [ unknown] Yarn Packaging [email protected]

Every chef pass reinstalls all the keys.

fb_reprepro needs love

I'm leaving it out of my testing PR, but it needs defaults for all it's values in attributes...

Thought to be honest, I would actually pull all that configurability of what it's directories are out to match the rest of the cookbooks that let you put whatever you want in the config, but are strongly opinionated about where that config is laid out.

NoMethodError using fb_fstab on Ubuntu 18.04

Hi there,

I'm having an issue using fb_fstab on Ubuntu 18.04.

My Node looks like this:

{
  "name": "somethingsomething",
  "chef_environment": "prod",
  "normal": {
    "fb_fstab" : {
      "enable_remount": true,
      "enable_unmount": true,
      "mounts" : { 
        "varlog" : { 
          "enable_remount": true,
          "device": "logs-tmpfs",
          "type": "tmpfs",
          "opts": "size=1G",
          "mount_point": "/var/log"
        }
      }
    },
    "tags": [ ]
  },
  "policy_name": null,
  "policy_group": null,
  "run_list": [
  "recipe[fb_fstab::default]"
  ]

}

Running fb_fstab::default gives me a NoMethodError.
(the version Numbers are bumped, because we also use a version of this cookbook from like 2 years ago, this run used the cookbooks from d1e06db )

Starting Chef Client, version 14.10.9
resolving cookbooks for run list: ["fb_fstab::default"]
Synchronizing Cookbooks:
  - fb_helpers (0.1.1)
  - fb_fstab (0.0.2)
Installing Cookbook Gems:
Compiling Cookbooks...
Converging 5 resources
Recipe: fb_fstab::default
  * file[/etc/.fstab.chef] action create
    - change mode from '0644' to '0444'
  * whyrun_safe_ruby_block[validate data] action run
    
    ================================================================================
    Error executing action `run` on resource 'whyrun_safe_ruby_block[validate data]'
    ================================================================================
    
    NoMethodError
    -------------
    undefined method `[]' for nil:NilClass
    
    Cookbook Trace:
    ---------------
    /var/chef/cache/cookbooks/fb_fstab/libraries/default.rb:98:in `get_autofs_points'
    /var/chef/cache/cookbooks/fb_fstab/libraries/default.rb:105:in `autofs_parent'
    /var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:83:in `block (3 levels) in from_file'
    /var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:31:in `each'
    /var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:31:in `block (2 levels) in from_file'
    
    Resource Declaration:
    ---------------------
    # In /var/chef/cache/cookbooks/fb_fstab/recipes/default.rb
    
     28: whyrun_safe_ruby_block 'validate data' do
     29:   block do
     30:     uniq_devs = {}
     31:     node['fb_fstab']['mounts'].to_hash.each do |name, data|
     32:       # Handle only_if
     33:       if data['only_if']
     34:         unless data['only_if'].class == Proc
     35:           fail 'fb_fstab\'s only_if requires a Proc'
     36:         end
     37:         unless data['only_if'].call
     38:           Chef::Log.debug("fb_fstab: Not including #{name} due to only_if")
     39:           node.rm('fb_fstab', 'mounts', name)
     40:           next
     41:         end
     42:       end
     43: 
    
    Compiled Resource:
    ------------------
    # Declared in /var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:28:in `from_file'
    
    whyrun_safe_ruby_block("validate data") do
      action [:run]
      default_guard_interpreter :default
      declared_type :whyrun_safe_ruby_block
      cookbook_name "fb_fstab"
      recipe_name "default"
      block #<Proc:[email protected]/var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:29>
      block_name "validate data"
    end
    
    System Info:
    ------------
    chef_version=14.10.9
    platform=ubuntu
    platform_version=18.04
    ruby=ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]
    program_name=/usr/bin/chef-client
    executable=/opt/chef/bin/chef-client
    

Running handlers:
[2019-02-20T09:21:18+00:00] ERROR: Running exception handlers
Running handlers complete
[2019-02-20T09:21:18+00:00] ERROR: Exception handlers complete
Chef Client failed. 1 resources updated in 04 seconds
[2019-02-20T09:21:18+00:00] FATAL: Stacktrace dumped to /var/chef/cache/chef-stacktrace.out
[2019-02-20T09:21:18+00:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report
[2019-02-20T09:21:18+00:00] FATAL: NoMethodError: whyrun_safe_ruby_block[validate data] (fb_fstab::default line 28) had an error: NoMethodError: undefined method `[]' for nil:NilClass

this is the generated stacktrace:

Generated at 2019-02-20 09:21:52 +0000
NoMethodError: whyrun_safe_ruby_block[validate data] (fb_fstab::default line 28) had an error: NoMethodError: undefined method `[]' for nil:NilClass
/var/chef/cache/cookbooks/fb_fstab/libraries/default.rb:98:in `get_autofs_points'
/var/chef/cache/cookbooks/fb_fstab/libraries/default.rb:105:in `autofs_parent'
/var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:83:in `block (3 levels) in from_file'
/var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:31:in `each'
/var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:31:in `block (2 levels) in from_file'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/provider/whyrun_safe_ruby_block.rb:25:in `action_run'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/provider.rb:182:in `run_action'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource.rb:578:in `run_action'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:70:in `run_action'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:98:in `block (2 levels) in converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:98:in `each'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:98:in `block in converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/resource_list.rb:94:in `block in execute_each_resource'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/stepable_iterator.rb:114:in `call_iterator_block'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/stepable_iterator.rb:85:in `step'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/stepable_iterator.rb:103:in `iterate'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/stepable_iterator.rb:55:in `each_with_index'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/resource_list.rb:92:in `execute_each_resource'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:97:in `converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:720:in `block in converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:715:in `catch'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:715:in `converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:754:in `converge_and_save'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:286:in `run'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:321:in `block in fork_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:309:in `fork'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:309:in `fork_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:274:in `block in run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/local_mode.rb:44:in `with_server_connectivity'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:261:in `run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:479:in `sleep_then_run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:468:in `block in interval_run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:467:in `loop'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:467:in `interval_run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:451:in `run_application'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:66:in `run'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/bin/chef-client:25:in `<top (required)>'
/usr/bin/chef-client:74:in `load'
/usr/bin/chef-client:74:in `<main>'

>>>> Caused by NoMethodError: undefined method `[]' for nil:NilClass
/var/chef/cache/cookbooks/fb_fstab/libraries/default.rb:98:in `get_autofs_points'
/var/chef/cache/cookbooks/fb_fstab/libraries/default.rb:105:in `autofs_parent'
/var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:83:in `block (3 levels) in from_file'
/var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:31:in `each'
/var/chef/cache/cookbooks/fb_fstab/recipes/default.rb:31:in `block (2 levels) in from_file'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/provider/whyrun_safe_ruby_block.rb:25:in `action_run'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/provider.rb:182:in `run_action'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource.rb:578:in `run_action'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:70:in `run_action'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:98:in `block (2 levels) in converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:98:in `each'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:98:in `block in converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/resource_list.rb:94:in `block in execute_each_resource'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/stepable_iterator.rb:114:in `call_iterator_block'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/stepable_iterator.rb:85:in `step'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/stepable_iterator.rb:103:in `iterate'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/stepable_iterator.rb:55:in `each_with_index'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/resource_collection/resource_list.rb:92:in `execute_each_resource'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/runner.rb:97:in `converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:720:in `block in converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:715:in `catch'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:715:in `converge'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:754:in `converge_and_save'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/client.rb:286:in `run'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:321:in `block in fork_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:309:in `fork'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:309:in `fork_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:274:in `block in run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/local_mode.rb:44:in `with_server_connectivity'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:261:in `run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:479:in `sleep_then_run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:468:in `block in interval_run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:467:in `loop'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:467:in `interval_run_chef_client'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application/client.rb:451:in `run_application'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/lib/chef/application.rb:66:in `run'
/opt/chef/embedded/lib/ruby/gems/2.5.0/gems/chef-14.10.9/bin/chef-client:25:in `<top (required)>'
/usr/bin/chef-client:74:in `load'
/usr/bin/chef-client:74:in `<main>

It seems like I'm missing something. Any Idea how I can get this cookbook to work?

Thanks,
-Markus

fb_network_scripts changes should be reflected in /var/chef/backup

fb_network_scripts does some trickery under the hood to in-place modify configs to try and avoid network restarts at much as possible. This is great, but the changes don't get reflected in /var/chef/backups, making troubleshooting harder at times. I'm not entirely sure if this is something we can sanely improve, but filing this for tracking and visibility.

fb_helpers contains namespace collisions with official chef node objects

In chef v17, chef added a lot of built-ins and we are seeing instability with at least one of them

https://github.com/facebook/chef-cookbooks/blob/main/cookbooks/fb_helpers/libraries/node_methods.rb#L146

when we call debian? within a library function, it returns false, so we are now having to do debian? || ubuntu? to workaround this as we consume fb_helpers.

To put this nicely, is Facebook willing to stop doing this? Or at the very least, stop putting so many of these things in node and put it to a FB namespace?

fb_helpers_reboot lies about :now

:now is suppsoed to reboot now (if allowed). But it has an undocumented FB-ism, that if you're in firstboot, it switches to managed reboots:

action :now do
  # TODO (t15830562) - this action should observe required and override the
  # same way as the :deferred action
  if node['fb_helpers']['reboot_allowed']
    if node.firstboot_any_phase?
      set_reboot_override('immediate')
      do_managed_reboot
    else

That's... not cool.

fb_tmpclean doesn't include tmpreaper defaults on debian/ubuntu - breaks /tmp cleanup

default file doesn't run tmpreaper for anything by default and only adds new calls based on what people add to the API. The default API does not include anything in directories (presumably because tmpclean file always does /tmp hardcoded), but the template for tmpreaper drops that. The default file on Ubuntu btw has:

TMPREAPER_TIME=${TMPREAPER_TIME:-7d}
TMPREAPER_PROTECT_EXTRA=${TMPREAPER_PROTECT_EXTRA:-''}
TMPREAPER_DIRS=${TMPREAPER_DIRS:-'/tmp/.'}

nice -n10 tmpreaper --delay=$TMPREAPER_DELAY --mtime-dir --symlinks $TMPREAPER_TIME  \
  $TMPREAPER_ADDITIONALOPTIONS \
  --ctime \
  --protect '/tmp/.X*-{lock,unix,unix/*}' \
  --protect '/tmp/.ICE-{unix,unix/*}' \
  --protect '/tmp/.iroha_{unix,unix/*}' \
  --protect '/tmp/.ki2-{unix,unix/*}' \
  --protect '/tmp/lost+found' \
  --protect '/tmp/journal.dat' \
  --protect '/tmp/quota.{user,group}' \
  `for i in $TMPREAPER_PROTECT_EXTRA; do echo --protect "$i"; done` \
  $TMPREAPER_DIRS

in it.

It's probably better to move away from the templating of calls and instead template /etc/tmpreaper.conf and just populate the right variables.

fb_apt doesn't take into account /etc/apt/trusted.gpg.d/

Debian and ubuntu both allow keys in /etc/apt/trusted.gpg.d

Currently if a key listed in chef is in a file in that directory, which for Ubuntu 18.04 all of the older keys are, then Chef won't find them, it tries to add them, this "succeeds" because it's already there and it tries to do this every time.

To make matters worse, apt-key does not accept more than one --keyring option.

I'm not sure of the best solution, but I suspect it's:

  • Chef should use a keyring like /etc/apt/trusted.gpg.d/fb_keyring.gpg
  • Chef should, by default, cleanup keyrings that dont' match the format of {ubuntu,debian}-keyring-\d{4}-.*.gpg but should leave that and the main trusted.gpg alone as "the package's pervue"
  • Users should then only specify non-OS keys in chef.

Fix CI failures

several shellcheck failures for fb_network_scripts/files/default/ifup-pre-local

kitchen failures for unknown instance:

  • /usr/bin/kitchen test default-debian-10
  • /usr/bin/kitchen test default-ubuntu-2004
  • /usr/bin/kitchen test default-centos-8

kitchen failures for grub:

template[grub2_config_efi] action create
Parent directory /boot/efi/EFI/debian does not exist.

various rubocop failures

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.