Coder Social home page Coder Social logo

taste-tester's Introduction

Taste Tester

Continuous Integration

Intro

Ohai!

Welcome to Taste Tester, software to manage a chef-zero instance and use it to test changes on production servers.

At its core, Taste Tester starts up a chef-zero server on localhost, uploads a repository to it, ssh's to a remote server and points its configs to your new chef-zero instance.

Further, it keeps track of where in git you were when that happened so future uploads will do the right thing, even as you switch branches.

Taste Tester can be controlled via a variety of config-file options, and can be further customized by writing a plugin.

Synopsis

Typical usage is:

vi cookbooks/...             # Make your changes and commit locally
taste-tester impact          # Check where your changes are used
taste-tester test -s [host]  # Put host in Taste Tester mode
ssh root@[host]              # Log in to host
  # Run chef and watch it break
vi cookbooks/...             # Fix your cookbooks
taste-tester upload          # Upload the diff
ssh root@[host]
  # Run chef and watch it succeed
<Verify your changes were actually applied as intended!>
taste-tester untest [host]   # Put host back in production
                             #   (optional - will revert itself after 1 hour)

See the help for further information.

Prerequisites

  • Taste Tester assumes that /etc/chef/client.rb and /etc/chef/client.pem on your servers is a symlink and that your real config is /etc/chef/client-prod.rb and /etc/chef/client-prod.pem, respectively.

  • Taste Tester assumes that it's generally safe to "go back" to production. I.e. We set things up so you can set a cronjob to un-taste-test a server after the desired amount of time, which means it must be (relatively) safe to revert back.

  • Taste Tester assumes you use a setup similar to grocery-delivery in production. Specifically that you don't use versions or environments.

  • Taste Tester assumes you have password-less SSH authentication to the hosts you want to test on, i.e. SSH public/private keys, SSH certificates, Kerberos

Dependencies

  • Mixlib::Config
  • Colorize
  • BetweenMeals
  • Minitar
  • Chef

Automatic Untesting

Taste Tester touches /etc/chef/test_timestamp on the remote server as far into the future as the user wants to test (default is 1h). You should have a cronjob to check the timestamp of this file, and if it is old, remove it and put the symlinks for /etc/chef/client.rb back to where they belong.

A small shell script to do this is included called taste-untester. We recommend running this at least every 15 minutes.

If you let Taste Tester setup reverse-SSH tunnels, make sure your untester is also killing the ssh tunnel whose PID is in /etc/chef/test_timestamp (taste-untester will do this for you).

Config file

The default config file is /etc/taste-tester-config.rb but you may use -c to specify another. The config file works the same as client.rb does for Chef - there are a series of keywords that take an argument and anything else is just standard Ruby.

All command-line options are available in the config file:

  • debug (bool, default: false)
  • timestamp (bool, default: false)
  • config_file (string, default: /etc/taste-tester-config.rb)
  • plugin_path (string, no default)
  • repo (string, default: #{ENV['HOME']}/ops)
  • testing_time (int, default: 3600)
  • chef_client_command (string, default: chef-client)
  • json (bool, default: false)
  • skip_repo_checks (bool, default: false)
  • skip_pre_upload_hook (bool, default: false)
  • skip_post_upload_hook (bool, default: false)
  • skip_pre_test_hook (bool, default: false)
  • skip_post_test_hook (bool, default: false)
  • skip_repo_checks_hook (bool, default: false)

The following options are also available:

  • base_dir - The directory in the repo under which to find chef configs. Default: chef
  • cookbook_dirs - An array of cookbook directories relative to base_dir. Default: ['cookbooks']
  • role_dir - A directory of roles, relative to base_dir. Default: roles
  • databag_dir - A directory of databags, relative to base_dir. Default: databags
  • ref_file - The file to store the last git revision we uploaded in. Default: #{ENV['HOME']}/.chef/taste-tester-ref.txt
  • checksum_dir - The checksum directory to put in knife.conf for users. Default: #{ENV['HOME']}/.chef/checksums
  • bundle - use a single tar.gz file for transporting cookbooks, roles and databags to clients. Experimental. Value is tri-state:
    • false - server uses knife upload, client uses chef_server
    • :compatible - make server support both methods, client uses tar.gz
    • true - server only creates tar.gz, client uses tar.gz Default: false
  • impact - analyze local changes to determine which hosts/roles to test. Default: false
  • ssh_cmd_gen_template - Provide a command to run, whose stdout will be a vanilla ssh command Taste Tester will invoke to access test nodes. The command should be a template and will be passed the following variables:
    • jumps - any jumphost arguments supplied via -J option
    • host - the host to SSH to
    • user - the user to SSH as For example: ssh_gen %{jumps} --user %{user} %{host} Default: nil

Plugin

The plugin should be a ruby file which defines several class methods. It is class_eval()d into a Hooks class.

The following functions can optionally be defined:

  • self.pre_upload(dryrun, repo, last_ref, cur_ref)

Stuff to do before we upload anything to chef-zero. Repo is a BetweenMeals::Repo object. last_ref is the last git ref we uploaded and cur_ref is the git ref the repo is currently at,

  • self.post_upload(dryrun, repo, last_ref, cur_ref)

Stuff to do after we upload to chef-zero.

  • self.pre_test(dryrun, repo, hosts)

Stuff to do before we put machines in test mode. hosts is an array of hostnames.

  • self.test_remote_cmds(dryrun, hostname)

Additional commands to run on the remote host when putting it in test mode. Should return an array of strings. hostname is the hostname.

  • self.test_remote_client_rb_extra_code(hostname)

Should return a string of additional code to include in the remote client.rb. Example uses: defining json_attribs

  • self.post_test(dryrun, repo, hosts)

Stuff to do after putting all hosts in test mode.

  • self.repo_checks(dryrun, repo)

Additional checks you want to do on the repo as sanity checks.

  • self.find_impact(changes)

Custom implementation of impact analysis. Uses knife deps by default. May return any data structure, provided one or both of self.post_impact or self.print_impact are defined.

  • self.post_impact(basic_impact)

Stuff to do after preliminary impact analysis. May be used to extend the information generated by self.find_impact, reformat the data structure, etc.

  • self.print_impact(final_impact)

Custom output of calculated impact, useful if defining either of the other impact hooks. Must return a truthy value to prevent the default output from printing.

  • self.post_error(dryrun, exception, mode, hostname)

A hook which will be called just before taste-tester throws an exception/exits. Passes down the exception object and the mode taste-tester was invoked with for further analysis and doing any additional logging, output, or cleanup.

Plugin example

This is an example /etc/taste-tester-plugin.rb to add a user-defined string to client-taste-tester.rb on the remote system:

Hooks.class_eval do
  def self.test_remote_client_rb_extra_code(_hostname)
    %(
      # This comment gets added to client-taste-tester.rb
      # This one too.
      )
  end
end

Be sure to pass this plugin file with -p on the command line or set it as plugin_path in your taste-tester-config.rb file.

License

See the LICENSE file.

taste-tester's People

Contributors

babar avatar bwann avatar chantra avatar dafyddcrosby avatar davide125 avatar dkaplan1 avatar dtheyer avatar emroch avatar epilatow avatar get9 avatar ifel avatar jaymzh avatar joshuamiller01 avatar malmond77 avatar mikedodge04 avatar naomireeves avatar natacado avatar natewalck avatar nikitakoshikov avatar nishchintraina avatar nobikik9 avatar odcinek avatar omribahumi avatar patcox avatar pavlo-fb avatar richard-commits avatar scottruss avatar steelcowboy avatar williamtheaker avatar zealws avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

taste-tester's Issues

When running master, cyclic include detected is thrown

When using master, the following error is thrown upon upload:

/opt/tastetester/bin/taste-tester upload -vvv
Using /Users/nate/chef
Trying to detect repo type
Repo found to be Git
Last commit: a82e9d2e13252b225fcb10c8c5e720f3be82104e 's' by [email protected]
Doing differential upload from a82e9d2e13252b225fcb10c8c5e720f3be82104e
Running "git diff --name-status a82e9d2e13252b225fcb10c8c5e720f3be82104e "
Nothing to upload!
Executed in 0.04s
Traceback (most recent call last):
    3: from /opt/tastetester/bin/taste-tester:32:in `<main>'
    2: from /opt/tastetester/bin/taste-tester:427:in `<module:TasteTester>'
    1: from /opt/tastetester/bin/taste-tester:427:in `include'
/opt/tastetester/bin/taste-tester:427:in `append_features': cyclic include detected (ArgumentError)

Support Sapling repos

This is sad:

Loading plugin at /home/phil/src/git/scale-chef/taste-tester-plugin.rb
Starting taste-tester server
Using /home/phil/src/git/scale-chef
Failed detecting repo type at /home/phil/src/git/scale-chef

The repo is a sapling repo.

taste-tester logging crash: undefined local variable or method 'logger' for #<TasteTester::State>

I just ran into this stacktrace when testing on macOS

I thought I'd report it since we should probably never end up in this "undefined local variable or method" situation:

DEBUG: Executing: USER=kickstart /opt/chefdk/embedded/bin/taste-tester test -vv -m server.x.y.com:5376 --transport locallink --linkonly --really -s localhost -y -p /opt/facebook/ops/scripts/chef/taste-tester-hooks.rb -t 1d
DEBUG: ERR: /opt/chefdk/embedded/lib/ruby/gems/2.4.0/gems/taste_tester-0.0.13/lib/taste_tester/state.rb:39:in `rescue in initialize':
DEBUG: ERR: undefined local variable or method `logger' for #<TasteTester::State:0x00007f9589b20658> (NameError)
DEBUG: ERR: Did you mean?  @@logger
DEBUG: ERR:  from /opt/chefdk/embedded/lib/ruby/gems/2.4.0/gems/taste_tester-0.0.13/lib/taste_tester/state.rb:36:in `initialize'
DEBUG: ERR:  from /opt/chefdk/embedded/lib/ruby/gems/2.4.0/gems/taste_tester-0.0.13/lib/taste_tester/server.rb:36:in `new'
DEBUG: ERR:  from /opt/chefdk/embedded/lib/ruby/gems/2.4.0/gems/taste_tester-0.0.13/lib/taste_tester/server.rb:36:in `initialize'
DEBUG: ERR:  from /opt/chefdk/embedded/lib/ruby/gems/2.4.0/gems/taste_tester-0.0.13/lib/taste_tester/commands.rb:80:in `new'
DEBUG: ERR:  from /opt/chefdk/embedded/lib/ruby/gems/2.4.0/gems/taste_tester-0.0.13/lib/taste_tester/commands.rb:80:in `test'
DEBUG: ERR:  from /opt/chefdk/embedded/lib/ruby/gems/2.4.0/gems/taste_tester-0.0.13/bin/taste-tester:400:in `<module:TasteTester>'
DEBUG: ERR:  from /opt/chefdk/embedded/lib/ruby/gems/2.4.0/gems/taste_tester-0.0.13/bin/taste-tester:32:in `<top (required)>'
DEBUG: ERR:  from /opt/chefdk/embedded/bin/taste-tester:23:in `load'
DEBUG: ERR:  from /opt/chefdk/embedded/bin/taste-tester:23:in `<main>'
DEBUG: OUT: Loading plugin at /opt/facebook/ops/scripts/chef/taste-tester-hooks.rb
DEBUG: OUT: Skipping upload at user request... potentially dangerous!

taste-tester logging crash: undefined local variable or method 'logger' for #<TasteTester::State> #156

I had already reported this in #156 , but we were on an ancient taste-tester version.

Now we upgraded and it turns out: still an issue.

It seems to be failing to call 'logger' when the initialize method tanks:
https://github.com/facebook/taste-tester/blob/master/lib/taste_tester/state.rb#L38

DEBUG: ERR: /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/taste_tester-0.0.19/lib/taste_tester/state.rb:38:in `rescue in initialize': undefined local variable or method `logger' for #<TasteTester::State:0x00007fac3644cfc0> (NameError)
DEBUG: ERR: Did you mean?  @@logger
DEBUG: ERR:     from /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/taste_tester-0.0.19/lib/taste_tester/state.rb:35:in `initialize'
DEBUG: ERR:     from /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/taste_tester-0.0.19/lib/taste_tester/server.rb:35:in `new'
DEBUG: ERR:     from /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/taste_tester-0.0.19/lib/taste_tester/server.rb:35:in `initialize'
DEBUG: ERR:     from /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/taste_tester-0.0.19/lib/taste_tester/commands.rb:85:in `new'
DEBUG: ERR:     from /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/taste_tester-0.0.19/lib/taste_tester/commands.rb:85:in `test'
DEBUG: ERR:     from /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/taste_tester-0.0.19/bin/taste-tester:450:in `<module:TasteTester>'
DEBUG: ERR:     from /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/taste_tester-0.0.19/bin/taste-tester:32:in `<top (required)>'
DEBUG: ERR:     from /opt/chefdk/embedded/bin/taste-tester:23:in `load'
DEBUG: ERR:     from /opt/chefdk/embedded/bin/taste-tester:23:in `<main>'

I think the problem is that the ref_file it tries to create by default is:

ref_file "#{ENV['HOME']}/.chef/taste-tester-ref.json"

and since we run this on macs as part of a launch daemon, "HOME" is not set.
So it fails, tries to log, can't. I think it might have to do with the order of events from 'initialize a class" and "execute the inheritance / extend code".

I guess the right thing would be:

  1. Don't use logger in the initializer, it's not available
  2. Possibly check if HOME is even set. But I think that's more of a macOS + launch daemon problem rather than a taste tester problem.

As to why we never noticed: up until recently, our root volume was writable. so writing to /.chef/ was not an issue. As of Big Sur, the root volume is mounted read only.

/cc @ttmgraham since he ran into this

databags uploaded incorrectly in bundle mode

Per https://github.com/chef/chef/blob/61a11902ab814aad3625eb4da7e3345d63ee7c09/knife/lib/chef/knife/data_bag_from_file.rb#L64, the local folder should be called data_bags.

However, here we are uploading it as databag:

populate(
stream, writer, TasteTester::Config.relative_databag_dir,
'databag'
)

This causes fetching databags with the library to fail: https://github.com/chef/chef/blob/61a11902ab814aad3625eb4da7e3345d63ee7c09/lib/chef/data_bag.rb#L140

state file gets confused

the state file gets the same key in it twice, sometimes;

{"port":5257,"ssl":false,"ssh":true,"logging":true,"ref":null,"ref":"426f245cc96aeaf4ef2aa8c274294db91566417c"}

Note 'ref' is there twice... in my case I think this is one of 2 problems causing tt to restart itself all the time.

`-v` should pass `-V` to knife... or something

When taste-tester upload calls knife and knife finds a syntax error on a file in a cookbook it doesn't tell you what cookbook or what file. To debug you have to take the knife command from the output and then run it with -VV which is a bit cumbersome.

I'll probably send a PR for this, I'm just making the Issue so I don't forget.

Plugin Example

Is there any chance someone can upload a plugin sample? This repo is just different enough from chefctl that I'm configuring something incorrectly.

This is what I'm attempting to add as a plugin.

module TasteTesterCustom
    def test_remote_client_rb_extra_code(_hostname)
      # Append to client.rb
      return "json_attribs '/etc/chef/run-list.json'"
  end
end

TasteTester::Hooks.register TasteTesterCustom

Thanks!

taste-tester-ref.json overrides command line port configuration

I attempted to launch taste-tester with the --chef-port-range argument, but it appeared to ignore my specified port entirely. It turns out it was reading the port from the taste-tester-ref.json file in the chef-cache directory, which presumably came from the previous taste-tester run.

I would expect the command line to override the old json file.

taste-tester needs an option for customizing errors when ssh fails

The SSH Util code deals with building a vanilla ssh command for logging into a host, where the user gets to customize the command options using hooks:

jumps = TasteTester::Config.jumps ?
"-J #{TasteTester::Config.jumps}" : ''
"#{TasteTester::Config.ssh_command} #{jumps} -T -o BatchMode=yes " +
'-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ' +
"-o ConnectTimeout=#{TasteTester::Config.ssh_connect_timeout}"

The building blocks of this vanilla ssh command could be generated out of a "config specific" command which is more user-friendly for the context for which the config is made. Example custom config:

ssh_cmd_prefix =  Mixlib::ShellOut.new("ssh_cmd_prefix generator command").run_command.stdout.chomp
ssh_command ssh_cmd_prefix

When a taste-tester test run fails because of ssh authentication failing, it spews out the vanilla command directly:

error = <<~ERRORMESSAGE
SSH returned error while connecting to #{TasteTester::Config.user}@#{@host}
The host might be broken or your SSH access is not working properly
Try doing
#{ssh_base_cmd} -v #{ssh_target}
to see if ssh connection is good.
If ssh works, add '-v' key to taste-tester to see the list of commands it's
trying to execute, and try to run them manually on destination host
ERRORMESSAGE

This might be vastly different from the actual custom command ("ssh_cmd_prefix generator command") the owner of the config might want to display during the failure so the developer running taste-tester has a command to run directly to validate the ssh connection first.

There is no place in taste-tester code to customize this behavior. An idea here was to try this in post_test hook but that doesn't fire when there is an ssh failure.

Hence what we need here is some sort of mechanism, hook or just a simple config variable - which can be configured to display the appropriate "ssh_cmd_prefix generator command".

taste-tester prints ssh banner to stdout

If the server we're testing against has a banner enabled (Banner option in sshd_config), taste-tester will print it to stdout at the very beginning (before Taste-tester type:). Not a big deal, but we should probably silence this by default.

Consider using "this repo" as the repo directory

Specifying a repo in the config requires everyone in an organization to use the same path to their chef repo.

At facebook it standard to symlink ~/chef etc. to wherever you check it out, but this isn't all that common elsewhere.

Instead it makes sense to see if we're in a repo and use the current repo if a repo isn't specified.

tt assumes all machines are in the same timezone

TT calculates what the test-timestamp should be on the local machine and then passes the result through to the remote machine in a literal format.

If the remote machine is in a timezone more than an hour ahead, then the host will immediately be un-taste-tested.

Chat panel

There is a bug in facebook in chat, there is a chat panel in right side of facebook page, when there are lots of people are online and that time, if we scroll the scroll bar, then last user are not showing properly.

see the attachment..

screenshot 100
screenshot 100 _3

combine tunnel.rb ssh_util.rb and ssh.rb

There's a lot of repeated code here. The worst offenders got factored into ssh_util.rb, but still they should all be one module and just take an option for tunnel (which ssh.rb already does, but ignores).

taste-tester ssh_generator code doesn't handle tunnel extra_options

Like the vanilla command does:

@extra_options.to_s +

This makes taste-tester tunnel break when use_ssh_tunnel is set to True. It also takes forever to test.

Might have to think about what stance we are taking here, either:

  1. We throw in the tunnel extra_options inside the ssh_generator code - in which case I will pull a PR
  2. We take the stance that the generator command is supposed to handle tunnels, although that is probably clunky.

auto generated knife config file should include hostname

taste-tester will build a knife config file to point at the local chef-zero instance in ~/.chef/ . If multiple instances of taste-tester are invoked and the home directories are on shared storage you can have conflicts. Possible easy fix is to change the config file name to include the local hostname (considering it's already writing that into said file anyways).

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.