chef-tlc-workflow 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +7 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +93 -0
  5. data/Rakefile +110 -0
  6. data/Vagrantfile +33 -0
  7. data/chef-tlc-workflow.gemspec +52 -0
  8. data/docs/ApplicationVsLibraryVsForkedCookbooks.md +20 -0
  9. data/docs/TmpLibrarianHelpers.md +21 -0
  10. data/docs/TmpWorkflowTasks.md +80 -0
  11. data/lib/chef-tlc-workflow.rb +5 -0
  12. data/lib/chef-tlc-workflow/helpers.rb +126 -0
  13. data/lib/chef-tlc-workflow/version.rb +3 -0
  14. data/lib/chef-workflow/tasks/tlc.rb +4 -0
  15. data/lib/chef-workflow/tasks/tlc/deps.rb +100 -0
  16. data/lib/chef-workflow/tasks/tlc/test.rb +15 -0
  17. data/test/Gemfile +7 -0
  18. data/test/ec2-bootstrap/.chef/bootstrap/omnibus-chef.sh +34 -0
  19. data/test/ec2-bootstrap/.gitignore +3 -0
  20. data/test/ec2-bootstrap/Mccloudfile +60 -0
  21. data/test/ec2-bootstrap/Rakefile +57 -0
  22. data/test/ec2-bootstrap/app_cookbooks.yml +12 -0
  23. data/test/esx-bootstrap/.chef/knife.rb +7 -0
  24. data/test/esx-bootstrap/.gitignore +4 -0
  25. data/test/esx-bootstrap/Rakefile +64 -0
  26. data/test/esx-bootstrap/app_cookbooks.yml +12 -0
  27. data/test/esx-bootstrap/nodes/33.33.77.10.json +6 -0
  28. data/test/local-bootstrap/.gitignore +4 -0
  29. data/test/local-bootstrap/Rakefile +50 -0
  30. data/test/local-bootstrap/Vagrantfile +31 -0
  31. data/test/local-bootstrap/app_cookbooks.yml +12 -0
  32. data/test/sample-app/CHANGELOG.md +12 -0
  33. data/test/sample-app/Cheffile +15 -0
  34. data/test/sample-app/README.md +20 -0
  35. data/test/sample-app/attributes/default.rb +2 -0
  36. data/test/sample-app/metadata.rb +10 -0
  37. data/test/sample-app/recipes/default.rb +27 -0
  38. data/test/sample-app/templates/default/sample.html.erb +10 -0
  39. metadata +331 -0
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .vagrant
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ source 'https://gems.gemfury.com/hUe8s8nSyzxs7JMMSZV8/' # vagrant-1.0.5.1
4
+ source 'https://gems.gemfury.com/psBbdHx94zqZrvxpiVmm/' # librarian-0.0.26.2
5
+
6
+ # Specify your gem's dependencies in chef-tlc-workflow.gemspec
7
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Torben
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # TLC Chef Workflow
2
+
3
+ The `chef-tlc-workflow` aims to make our workflow for developing with Chef more explict.
4
+
5
+ First of all, it provides templates for three different deployment environments (esx, ec2 and local). The templates contain among others a `Rakefile` for interacting with the deployment environment as well as a description of the nodes in these environments.
6
+
7
+ Other than the templates it provides helper methods to use the dependencies defined in `metadata.rb` from within [librarian](https://github.com/applicationsonline/librarian) `Cheffile`s. This ensures consistency between the dependencies specified in metadata and resolved via librarian.
8
+
9
+ Finally, it ensures a consistent gem set by declaring all the gems we use in our workflow in its own gemspec, i.e. `chef-tlc-workflow` is the only gem you need to depend on - everything else (like vagrant, mcloud, etc..) comes in as transitive dependencies.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'chef-tlc-workflow'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install chef-tlc-workflow
24
+
25
+
26
+ ## Usage
27
+
28
+ See valid usages below.
29
+
30
+ ### Templates for Deployment Environments
31
+
32
+ As of TLC Project Infrastructure v1 we support three different deployment environments:
33
+
34
+ * `esx` - VMs on our ESX infrastructure where we have ssh access but no control over the VMs (provisioned via [knife-solo](http://matschaffer.github.com/knife-solo/))
35
+ * `ec2` - ec2 instances in the amazon cloud (managed and provisioned via [mccloud](https://github.com/jedi4ever/mccloud))
36
+ * `local` - local VirtualBox VMs for development and testing (managed and provisioned via [vagrant](http://vagrantup.com))
37
+
38
+ This project contains "templates" for each of these deployment environments in the `test/` directory. For now, you have to copy the directories - there is no scaffolding yet.
39
+
40
+ Each of the deployment environments in the `test/` directory provides a `Rakefile` with a similar interface (i.e. similar rake tasks) to interact with. See the integration tests in the top level `Rakefile` for an example.
41
+
42
+ In addition, it provides a place for describing the nodes within that deployment environment. Depending on the environment this might be a `Vagrantfile`, `Mccloudfile` or `<node>.json` file. Again, see the examples in the `test/` directory.
43
+
44
+ ### Librarian Helper
45
+
46
+ Since librarian does not support reading the cookbook dependencies from `metadata.rb`, the `ChefTLCWorkflow::Helpers` module adds this functionality.
47
+
48
+ In the trivial case you can use it in your cookbook project's `Cheffile` like so:
49
+
50
+ require 'chef-tlc-workflow/helpers'
51
+
52
+ ChefTLCWorkflow::Helpers::from_metadata.each do |cb_name, cb_version|
53
+ cookbook cb_name, cb_version
54
+ end
55
+
56
+ If some of the cookbooks defined in metadata.rb are not available from the community site, you can define your overrides like so:
57
+
58
+ ...
59
+ @overrides = {
60
+ 'tlc-base' => { :git => 'https://github.com/tknerr/cookbook-tlc-base.git', :ref => 'master' },
61
+ }
62
+
63
+ ChefTLCWorkflow::Helpers::from_metadata.each do |cb_name, cb_version|
64
+ cookbook cb_name, cb_version, @overrides[cb_name]
65
+ end
66
+
67
+
68
+ ### Single Gemfile Dependency
69
+
70
+ It references all gems we need for our Chef workflow, this means that your `Gemfile` basically looks like this:
71
+
72
+ ```
73
+ source :rubygems
74
+
75
+ # additional sources for patched gems
76
+ source 'https://gems.gemfury.com/hUe8s8nSyzxs7JMMSZV8/' # vagrant-1.0.5.1
77
+ source 'https://gems.gemfury.com/psBbdHx94zqZrvxpiVmm/' # librarian-0.0.26.2
78
+
79
+ gem "chef-tlc-workflow", "0.1.0"
80
+ ```
81
+
82
+ This brings in all the transitive gem dependencies as defined in the `chef-tlc-workflow.gemspec`, e.g. vagrant, librarian, chef, mccloud etc...
83
+
84
+ While this is not ideal in terms of keeping the LOAD_PATH as small as possible, it's a tradeoff in favor of convenience and consistency.
85
+
86
+
87
+ ## Contributing
88
+
89
+ 1. Fork it
90
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
91
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
92
+ 4. Push to the branch (`git push origin my-new-feature`)
93
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,110 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc "run all tests"
4
+ task :test => [
5
+ :test_esx_bootstrap,
6
+ :test_ec2_bootstrap,
7
+ :test_local_bootstrap
8
+ ]
9
+
10
+ #
11
+ # TODO:
12
+ # * rewrite as cucumber feature
13
+ # * check for apache default page
14
+ # * more realistic scenario: e.g. scaffold infra, create Cheffile and node.json on the fly, etc...
15
+ #
16
+ desc "tests bootstrapping with knife-solo in an esx-like environment"
17
+ task :test_esx_bootstrap do
18
+
19
+ app = 'sample-app@0.1.0'
20
+ user = 'vagrant'
21
+ host = '33.33.77.10'
22
+ ssh_key = 'W:/home/.vagrant.d/insecure_private_key'
23
+
24
+ begin
25
+ # simulate esx-like environment using vagrant and a bare-os basebox
26
+ sh "vagrant destroy esx_like_vm -f"
27
+ sh "vagrant up esx_like_vm" do |ok, res|
28
+ puts "ok: #{ok}\nres: #{res}" # ignore vagrant error for bare-os vm
29
+ end
30
+
31
+ # resolve deps and provision node
32
+ run_cmd_esx "rake resolve_deps"
33
+ # bootstrap node with chef
34
+ run_cmd_esx "rake bootstrap[#{host},#{user},#{ssh_key}]"
35
+ # provision node with app
36
+ run_cmd_esx "rake provision[#{app},#{host},#{user},#{ssh_key}]"
37
+ # remove chef-solo traces from node
38
+ run_cmd_esx "rake cleanup[#{host},#{user},#{ssh_key}]"
39
+
40
+ # TODO: test if sample app works
41
+ ensure
42
+ # cleanup
43
+ sh "vagrant destroy esx_like_vm -f"
44
+ end
45
+ end
46
+
47
+
48
+ desc "tests bootstrapping with mccloud in ec2 (requires ec2 credentials)"
49
+ task :test_ec2_bootstrap do
50
+
51
+ vm_name = 'sample-app'
52
+
53
+ begin
54
+ # resolve deps
55
+ run_cmd_ec2 "rake resolve_deps"
56
+ # bring up ec2 instance, bootstrap with chef and provision
57
+ run_cmd_ec2 "rake up[#{vm_name}]"
58
+ # re-provison ec2 instance
59
+ run_cmd_ec2 "rake provision[#{vm_name}]"
60
+ # show status of ec2 instances
61
+ run_cmd_ec2 "rake status"
62
+
63
+
64
+ # TODO: test if sample app works
65
+ ensure
66
+ # destroy ec2 instance
67
+ run_cmd_ec2 "rake destroy[#{vm_name}]"
68
+ end
69
+ end
70
+
71
+
72
+ desc "tests bootstrapping with local Vagrant VMs"
73
+ task :test_local_bootstrap do
74
+
75
+ vm_name = 'sample-app'
76
+
77
+ begin
78
+ # resolve deps
79
+ run_cmd_local "rake resolve_deps"
80
+ # bring up vagrant vm, bootstrap with chef and provision
81
+ run_cmd_local "rake up[#{vm_name}]"
82
+ # re-provison vagrant vm
83
+ run_cmd_local "rake provision[#{vm_name}]"
84
+ # show status of vagrant vms
85
+ run_cmd_local "rake status"
86
+
87
+ # TODO: test if sample app works
88
+ ensure
89
+ # destroy vagrant vm
90
+ run_cmd_local "rake destroy[#{vm_name}]"
91
+ end
92
+ end
93
+
94
+
95
+ def run_cmd_esx(command)
96
+ run_cmd command, "test/esx-bootstrap"
97
+ end
98
+
99
+ def run_cmd_ec2(command)
100
+ run_cmd command, "test/ec2-bootstrap"
101
+ end
102
+
103
+ def run_cmd_local(command)
104
+ run_cmd command, "test/local-bootstrap"
105
+ end
106
+
107
+ def run_cmd(command, cwd)
108
+ fail "need #{cwd}/Gemfile for a clean environment" unless File.exist? "#{cwd}/Gemfile"
109
+ sh "cd #{cwd} && bundle exec #{command}"
110
+ end
data/Vagrantfile ADDED
@@ -0,0 +1,33 @@
1
+ #
2
+ # Vagrantfile simulating an ESX-like environment for testing purposes:
3
+ #
4
+ # * assume ssh root access as the only prerequisite
5
+ # * using bare OS baseboxes with no Chef installed
6
+ #
7
+ Vagrant::Config.run do |config|
8
+
9
+ # use bare os baseboxes
10
+ config.vm.box = "ubuntu-12.04-server-amd64-bare-os"
11
+ config.vm.box_url = "http://dl.dropbox.com/u/13494216/ubuntu-12.04-server-amd64-bare-os.box"
12
+
13
+ config.vm.define :esx_like_vm do | esx_like_vm_config |
14
+ esx_like_vm_config.vm.customize ["modifyvm", :id,
15
+ "--memory", "1024",
16
+ "--name", "chef-tlc-workflow-esx-like-vm"]
17
+ esx_like_vm_config.vm.host_name = "chef-tlc-workflow-esx-like-vm.local"
18
+ esx_like_vm_config.vm.network :hostonly, "33.33.77.10"
19
+ end
20
+
21
+ #
22
+ # dummy vm in the same network, keeping it on so that no additional
23
+ # user elevation dialogs appear for the other VMs
24
+ #
25
+ config.vm.define :dummy do | dummy_vm_config |
26
+ dummy_vm_config.vm.customize ["modifyvm", :id,
27
+ "--memory", "256",
28
+ "--name", "chef-tlc-workflow-dummy-vm"]
29
+ dummy_vm_config.vm.host_name = "chef-tlc-workflow-dummy-vm.local"
30
+ dummy_vm_config.vm.network :hostonly, "33.33.77.2"
31
+ end
32
+
33
+ end
@@ -0,0 +1,52 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'chef-tlc-workflow/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "chef-tlc-workflow"
8
+ gem.version = ChefTLCWorkflow::VERSION
9
+ gem.authors = ["Torben Knerr"]
10
+ gem.email = ["tkn@zuehlke.com"]
11
+ gem.description = %q{makes our workflow for developing with Chef explict by adding a set of Rake tasks embodying the workflow}
12
+ gem.summary = %q{makes our workflow for developing with Chef explict by adding a set of Rake tasks embodying the workflow}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ # lock down dependencies
21
+ #
22
+ gem.add_dependency 'chef-workflow-tasklib', '0.2.2'
23
+ gem.add_dependency 'chef', '10.18.2'
24
+ gem.add_dependency 'librarian', '0.0.26.2'
25
+
26
+ #
27
+ # further dependencies that are not `require`d here but we pull in for convenience
28
+ # so that the only dependency one needs in the `Gemfile` is `chef-tlc-workflow`
29
+ #
30
+
31
+ # for interaction with nodes in local/esx/ec2 environments
32
+ gem.add_dependency 'vagrant', '1.0.5.1'
33
+ gem.add_dependency 'knife-solo', '0.3.0.pre2'
34
+ gem.add_dependency 'mccloud', '0.0.18'
35
+
36
+ # testing related
37
+ gem.add_dependency 'foodcritic', '1.7.0'
38
+ gem.add_dependency 'chefspec', '0.9.0'
39
+ gem.add_dependency 'fauxhai', '0.1.1'
40
+
41
+ # others
42
+ gem.add_dependency 'rake', '0.9.6'
43
+ gem.add_dependency 'sahara', '0.0.13'
44
+ gem.add_dependency 'knife-solo_data_bag', '0.3.1'
45
+
46
+ # need these on windows only
47
+ if RUBY_PLATFORM =~ /mswin|mingw/
48
+ gem.add_dependency 'ruby-wmi', '0.4.0'
49
+ gem.add_dependency 'win32-service', '0.7.2'
50
+ end
51
+
52
+ end
@@ -0,0 +1,20 @@
1
+ ## Application vs Library vs Forked Cookbooks
2
+
3
+ [Application cookbooks](http://devopsanywhere.blogspot.ch/2012/11/how-to-write-reusable-chef-cookbooks.html) contain everything required for setting up a machine (1:1 relation) with the desired application/service. They are based on library cookbooks but add the "glue" to make the installation as simple as including just the application cookbook in the node's run_list.
4
+
5
+ Why application cookbooks? Because:
6
+
7
+ * they can be properly versioned and dependency managed (in contrast to roles)
8
+ * they lock down dependency versions in their `metadata.rb` thus make the installation robust and reliable
9
+ * they hide all the glue code (and configuration inderdependencies) when assembling multiple cookbooks
10
+ * they set sensible configuration defaults and expose only the minimum necessary configuration to the user
11
+ * they document how to use/administer the application in their README
12
+
13
+ Sometimes there is no suitable [community cookbook](http://community.opscode.com/cookbooks) available or an available cookbook suffers from a bug or a missing feature we urgently need. In this case we resort to either writing our own (maybe internally hosted) library cookbook or to fork the community cookbook and fix the bugs or provide outstanding features.
14
+
15
+ This is how we handle forked community cookbooks:
16
+
17
+ * host them internally on our Gitlab
18
+ * `master` branch is the master from the upstream version
19
+ * all our changes are done in the `zuehlke_master` branch
20
+ * bug fixes / useful features should be contributed back to the community via pull requests
@@ -0,0 +1,21 @@
1
+
2
+ ## Librarian Helpers
3
+
4
+ Since librarian does not support reading the cookbook dependencies from `metadata.rb`,
5
+ the `ChefTLCWorkflow::Helpers` module adds this functionality.
6
+
7
+ In the trivial case you can use it in your cookbook project's `Cheffile` like so:
8
+
9
+ require 'chef-tlc-workflow/helpers'
10
+
11
+ ChefTLCWorkflow::Helpers::from_metadata.each do |cb_name, cb_version|
12
+ cookbook cb_name, cb_version
13
+ end
14
+
15
+ If some of the cookbooks defined in metadata.rb are not available from the community site,
16
+ you can provide a .yml file with custom location mappings and pass it to the helper method:
17
+
18
+ ...
19
+ ChefTLCWorkflow::Helpers::from_metadata('../../locations.yml').each do |cb_name, cb_version, location|
20
+ cookbook cb_name, cb_version, location
21
+ end
@@ -0,0 +1,80 @@
1
+ The `chef-tlc-workflow` makes our workflow for developing with Chef explict by adding a set of Rake tasks embodying the workflow. It's an extension of [chef-workflow](https://github.com/chef-workflow/chef-workflow) providing the additional workflow-encapsulating Rake tasks in the `tlc` namespace.
2
+
3
+ ## Workflow Tasks
4
+
5
+ -------------------------
6
+
7
+ *!!! CAUTION: the text below about workflow tasks is not accurate anymore !!!*
8
+
9
+ Why? Because I believe its better to provide a Rakefile via Scaffolding mechanism.
10
+ This is more transparent and easier to adapt than providing prebaked Rake tasks
11
+ in a gem library.
12
+
13
+ Right now we still have the Rake tasks mentioned below, but we treat them as internal
14
+ Rake tasks that we invoke from the scaffolded Rakefiles. They don't show up when
15
+ running `rake -T` because they have now `desc`ription (but `rake -T -A` still shows them).
16
+
17
+ Even if we keep them, the namespaces are likely to change so they are structured
18
+ per-project-type (e.g. library cookbook project, application cookbook project or
19
+ infrastructure project), e.g:
20
+
21
+ * lib
22
+ * create
23
+ * release
24
+ * resolve_deps
25
+ * validate (Cheffile in .gitignore)
26
+ * test (u.a. => test:converge, ggf. chef-workflow testlib?)
27
+ * app
28
+ * create
29
+ * release
30
+ * resolve_deps
31
+ * validate (=> u.a. deps:check, Cheffile nicht in .gitignore)
32
+ * test (was auch immer das heisst)
33
+ * infra
34
+ * create
35
+ * resolve_deps (= app cookbooks)
36
+ * validate
37
+ * test (was auch immer das heisst)
38
+
39
+ Furthermore, the scaffolding tasks should be rather implemented as a knife plugin,
40
+ because when we use them there is no Rakefile yet (chicken-egg problem).
41
+
42
+ -------------------------
43
+
44
+ Once you installed the gem or added it to your `Gemfile` as shown above, simply add the following to your project's `Rakefile` to have all TLC workflow tasks available:
45
+
46
+ # first, chef-workflow-tasklib must be required
47
+ require 'chef-workflow-tasklib'
48
+
49
+ # then you can include _all_ tlc tasks like this
50
+ chef_workflow_task 'tlc'
51
+
52
+ Or, if you need only specific workflow tasks, they can be included separately:
53
+
54
+ ...
55
+ # include dependency management related tasks
56
+ chef_workflow_task 'tlc/deps'
57
+
58
+ You should then have the TLC workflow tasks available:
59
+
60
+ $ bundle exec rake -T
61
+ rake tlc:deps:check # check if dependencies in metadata.rb and Cheffi...
62
+ rake tlc:deps:resolve # resolve dependencies using librarian
63
+ rake tlc:test:converge # destroy the Vagrant VM, resolve dependencies an...
64
+
65
+ ### Available Workflow Tasks
66
+
67
+ Currently available are these tasks.
68
+
69
+ #### Cookbook Dependency Management
70
+
71
+ The `deps` namespace embodies the workflow concerning cookbook dependency management
72
+
73
+ * `tlc:deps:resolve` - resolve dependencies using [librarian](https://github.com/applicationsonline/librarian)
74
+ * `tlc:deps:check` - check if dependencies in `metadata.rb` and `Cheffile` are consistent
75
+
76
+ #### Cookbook Testing
77
+
78
+ The `test` namespace represents the workflow for testing of individual cookbook projects
79
+
80
+ * `tlc:test:converge` - destroy the default Vagrant VM first, then resolve dependencies and converge the default Vagrant VM