itamae-template 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 571d1c929a677f2384ac2e7195a07904d17d52eb
4
+ data.tar.gz: a45d20547bb367b16294efb0f98b8fc5e07c82ce
5
+ SHA512:
6
+ metadata.gz: 97501a028fc505e71f6b5a13a567f07046cf046fc548f896482532692bff4400ecc2ac3a3572979159b34bacd2440a77d0db47bef320b43cae41a43a3f2a0033
7
+ data.tar.gz: d260ef531325cc406a54f2fe4874758c8e5311a9f61acdc1b5f4d09feb6581a449f83999bb45d4e9937c5670f95a8033807c58ff08d16a659d689169fd174ef0
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in itamae-template.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # Itamae::Template
2
+
3
+ Itamae template generator for roles and cookbooks, based on the
4
+ [Best Practice](https://github.com/itamae-kitchen/itamae/wiki/Best-Practice)
5
+ of [Itamae](https://github.com/itamae-kitchen/itamae/).
6
+
7
+ ## Features
8
+
9
+ | command | description |
10
+ |:-----|:--------|
11
+ | `itamae-template init` | Initialize repository to use cookbooks and roles |
12
+ | `itamae-template g role [name]` | Generate roles/[name]/default.rb |
13
+ | `itamae-template g cookbook [name]` | Generate cookbooks/[name]/default.rb |
14
+ | `itamae-template d role [name]` | Destroy roles/[name]/default.rb |
15
+ | `itamae-template d cookbook [name]` | Destroy cookbooks/[name]/default.rb |
16
+
17
+ And you can include those recipes by `include_cookbook` or `include_role`.
18
+
19
+ ### Capistrano tasks
20
+
21
+ The initialized repository includes following capistrano tasks.
22
+
23
+ NOTE: Because `itamae ssh` is slow, itamae-template installs itamae remotely and
24
+ execute recipes via `itamae local`.
25
+
26
+ | command | description |
27
+ |:-----|:--------|
28
+ | `cap itamae prepare` | Install ruby to execute itamae remotely |
29
+ | `cap itamae dry-run` | Check what will be executed |
30
+ | `cap itamae apply` | Apply recipes |
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ $ gem install itamae-template
36
+ ```
37
+
38
+ ## Get started
39
+
40
+ This is a tutorial of `itamae-template`.
41
+
42
+ ```bash
43
+ # Create repository to add itamae recipes.
44
+ $ mkdir infra
45
+ $ cd infra
46
+ $ git init
47
+
48
+ # Initialize itamae helpers.
49
+ $ gem install itamae-template
50
+ $ itamae-template init
51
+
52
+ # Specify hosts to provision. If you can ssh to the host by `ssh foo`,
53
+ # edit: `role :production, %w[foo]`
54
+ $ vim config/deploy.rb
55
+
56
+ # Install ruby and bundler to the production role, i.e. "foo" host.
57
+ # It will be installed to /opt/itamae/bin/ruby, not system-widely.
58
+ $ bundle install
59
+ $ bundle exec cap itamae prepare
60
+
61
+ # Test execution of the recipes.
62
+ $ bundle exec cap itamae dry-run
63
+
64
+ # Apply recipes. It just prints hello.
65
+ $ bundle exec cap itamae apply
66
+ ```
67
+
68
+ ### Cookbook
69
+
70
+ ```bash
71
+ # Drop hello cookbook.
72
+ $ itamae-template d cookbook hello
73
+
74
+ # Create new cookbook. "default.rb" will be loaded by
75
+ # `include_cookbook "nginx"`
76
+ $ itamae-template g cookbook nginx
77
+ $ vim cookbooks/nginx/default.rb
78
+ $ vim roles/production/default.rb
79
+ ```
80
+
81
+ ### Role
82
+
83
+ ```bash
84
+ # Create new role.
85
+ $ itamae-template g role staging
86
+ $ vim roles/staging/default.rb
87
+
88
+ # Specify hosts to apply staging recipes.
89
+ # Edit: `role :staging, %w[bar]`
90
+ $ vim config/deploy.rb
91
+
92
+ # Apply recipes only for staging by the capistrano way.
93
+ $ ROLES=staging bundle exec cap itamae apply
94
+ ```
95
+
96
+ ## Shorthand
97
+
98
+ You can use :sushi: instead of `itamae-template`.
99
+
100
+ ```bash
101
+ $ sushi init
102
+ $ sushi g role [name]
103
+ $ sushi g cookbook [name]
104
+ $ sushi d role [name]
105
+ $ sushi d cookbook [name]
106
+ ```
107
+
108
+ ## License
109
+
110
+ MIT License
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "itamae/template"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path('../lib', __dir__)
4
+ require 'itamae/template/cli'
5
+
6
+ Itamae::Template::CLI.start(ARGV)
data/exe/sushi ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Just a shorthand for itamae-template.
4
+
5
+ $:.unshift File.expand_path('../lib', __dir__)
6
+ require 'itamae/template/cli'
7
+
8
+ Itamae::Template::CLI.start(ARGV)
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'itamae/template/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "itamae-template"
8
+ spec.version = Itamae::Template::VERSION
9
+ spec.authors = ["Takashi Kokubun"]
10
+ spec.email = ["takashi-kokubun@cookpad.com"]
11
+
12
+ spec.summary = %q{The best practice for itamae}
13
+ spec.description = %q{Itamae template generater for roles and cookbooks.}
14
+ spec.homepage = "https://github.com/k0kubun/itamae-template"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "thor"
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ end
@@ -0,0 +1,95 @@
1
+ require 'fileutils'
2
+ require 'pathname'
3
+ require 'thor'
4
+
5
+ module Itamae
6
+ module Template
7
+ class CLI < Thor
8
+ AVAILABLE_TARGETS = %w[role cookbook].freeze
9
+ TEMPLATE_PATH = Pathname.new(File.expand_path('../../../template', __dir__))
10
+ COLOR_MAP = {
11
+ red: 31, # remove
12
+ green: 32, # create
13
+ blue: 34, # identical
14
+ white: 37, # invoke
15
+ }
16
+
17
+ desc 'init', 'Initialize itamae repository'
18
+ def init
19
+ Dir.glob(TEMPLATE_PATH.join('**/*')).sort.each do |path|
20
+ copy_template(path)
21
+ end
22
+ end
23
+
24
+ desc 'generate [role|cookbook] [NAME]', 'Generate role or cookbook'
25
+ def generate(target, name)
26
+ validate_target!(target)
27
+
28
+ create_directory(File.join("#{target}s", name))
29
+ create_file(File.join("#{target}s", name, 'default.rb'), "# noop\n")
30
+ create_file(File.join("#{target}s", name, 'node.yml'), "# No variables\n")
31
+ end
32
+ method_option :generate, aliases: :g
33
+
34
+ desc 'destroy [role|cookbook] [NAME]', 'Destroy role or cookbook'
35
+ def destroy(target, name)
36
+ validate_target!(target)
37
+
38
+ recursive_remove(File.join("#{target}s", name))
39
+ recursive_remove(File.join("#{target}s", name, 'default.rb'))
40
+ recursive_remove(File.join("#{target}s", name, 'node.yml'))
41
+ end
42
+ method_option :destroy, aliases: :d
43
+
44
+ private
45
+
46
+ def validate_target!(target)
47
+ unless AVAILABLE_TARGETS.include?(target)
48
+ abort "Unexpected target '#{target}' is given.\n Allowed: #{AVAILABLE_TARGETS.join(', ')}"
49
+ end
50
+ end
51
+
52
+ def copy_template(path)
53
+ relative_path = Pathname.new(path).relative_path_from(TEMPLATE_PATH)
54
+
55
+ if File.file?(path)
56
+ create_file(relative_path, File.read(path))
57
+ else
58
+ create_directory(relative_path)
59
+ end
60
+ end
61
+
62
+ def create_file(relative_path, content)
63
+ target_path = Pathname.new(Dir.pwd).join(relative_path)
64
+
65
+ if File.exist?(target_path)
66
+ puts "#{colorize('identical', code: :blue)} #{relative_path}"
67
+ else
68
+ File.write(target_path, content)
69
+ puts "#{colorize('create', code: :green)} #{relative_path}"
70
+ end
71
+ end
72
+
73
+ def create_directory(relative_path)
74
+ target_path = Pathname.new(Dir.pwd).join(relative_path)
75
+
76
+ if File.exist?(target_path)
77
+ puts "#{colorize('identical', code: :blue)} #{relative_path}"
78
+ else
79
+ FileUtils.mkdir(target_path)
80
+ puts "#{colorize('create', code: :green)} #{relative_path}"
81
+ end
82
+ end
83
+
84
+ def recursive_remove(relative_path)
85
+ target_path = Pathname.new(Dir.pwd).join(relative_path)
86
+ FileUtils.rm_rf(target_path)
87
+ puts "#{colorize('remove', code: :red)} #{relative_path}"
88
+ end
89
+
90
+ def colorize(text, code: :red)
91
+ "\e[1m\e[#{COLOR_MAP[code]}m#{'%12s' % text}\e[0m"
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,5 @@
1
+ module Itamae
2
+ module Template
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ require 'itamae/template/cli'
2
+ require 'itamae/template/version'
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ tmp
data/template/Capfile ADDED
@@ -0,0 +1,14 @@
1
+ # Load DSL and set up stages
2
+ require 'capistrano/setup'
3
+
4
+ # Enable sudo
5
+ require 'sshkit/sudo'
6
+
7
+ # You can send password with $SUDO_PASSWORD
8
+ if ENV['SUDO_PASSWORD']
9
+ module SSHKit
10
+ def Sudo.password_cache
11
+ Hash.new { "#{ENV['SUDO_PASSWORD']}\n" }
12
+ end
13
+ end
14
+ end
data/template/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Install itamae and its plugins.
4
+ gem 'itamae', '>= 1.5'
5
+
6
+ # This group is only used by client and not installed on remote host.
7
+ group :cap do
8
+ gem 'capistrano', '~> 3.4'
9
+ gem 'sshkit-sudo', '0.0.4'
10
+ end
@@ -0,0 +1,108 @@
1
+ task 'apply' => %w[rsync itamae:bundle_install itamae:apply]
2
+ task 'dry-run' => %w[rsync itamae:bundle_install itamae:dry_run]
3
+ task 'prepare' => %w[prepare:ruby prepare:bundler]
4
+
5
+ # Ruby to execute itamae is installed to /opt/itamae.
6
+ EMBEDDED_RUBY_DIR = '/opt/itamae'
7
+ def bin_path(*paths)
8
+ File.join(EMBEDDED_RUBY_DIR, 'bin', *paths)
9
+ end
10
+
11
+ # This repository is rsynced to /tmp/itamae-cache.
12
+ def cache_path(*paths)
13
+ File.join('/tmp/itamae-cache', *paths)
14
+ end
15
+
16
+ task :rsync do
17
+ on roles(:all) do |srv|
18
+ run_locally do
19
+ execute(*%W[
20
+ rsync -az --copy-links --copy-unsafe-links --delete
21
+ --exclude=.git* --exclude=.bundle*
22
+ . #{srv}:#{cache_path}
23
+ ])
24
+ end
25
+ end
26
+ end
27
+
28
+ namespace :itamae do
29
+ def run_itamae(role, dry_run: false)
30
+ local_yaml = File.join(File.expand_path('../../roles', __dir__), role.to_s, 'node.yml')
31
+ sudo(*%W[
32
+ PATH=#{bin_path}:${PATH} BUNDLE_GEMFILE=#{cache_path('Gemfile')}
33
+ #{bin_path('bundle')} exec itamae local
34
+ #{cache_path('recipe_helper.rb')} #{cache_path('roles', role.to_s, 'default.rb')}
35
+ --no-color #{'--dry-run' if dry_run}
36
+ #{"--node-yaml=#{cache_path('roles', role.to_s, 'node.yml')}" if File.exist?(local_yaml)}
37
+ ])
38
+ end
39
+
40
+ task :bundle_install do
41
+ on roles(:all) do
42
+ sudo(*%W[
43
+ BUNDLE_GEMFILE=#{cache_path('Gemfile')}
44
+ #{bin_path('bundle')} install --jobs `nproc` --without cap --quiet
45
+ ])
46
+ end
47
+ end
48
+
49
+ task :dry_run do
50
+ on roles(:all) do |srv|
51
+ srv.roles.each do |role|
52
+ run_itamae(role, dry_run: true)
53
+ end
54
+ end
55
+ end
56
+
57
+ task :apply do
58
+ on roles(:all) do |srv|
59
+ srv.roles.each do |role|
60
+ run_itamae(role)
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ namespace :prepare do
67
+ task :ruby do
68
+ on roles(:all) do
69
+ def install_ruby(platform, version)
70
+ return if capture("test -e #{bin_path('ruby')}; echo $?") == '0'
71
+
72
+ sudo :mkdir, '-p', EMBEDDED_RUBY_DIR
73
+ begin
74
+ cache_url = "https://s3.amazonaws.com/pkgr-buildpack-ruby/current/#{platform}/ruby-#{version}.tgz"
75
+ sudo(*%W[curl -s #{cache_url} -o /tmp/ruby.tgz])
76
+ rescue SSHKit::Command::Failed
77
+ # TODO: build ruby with ruby-build.
78
+ abort "'#{platform}' is not supported now. Please update config/deploy/itamae.rb"
79
+ end
80
+ sudo(*%W[tar xzf /tmp/ruby.tgz -C #{EMBEDDED_RUBY_DIR}])
81
+ end
82
+
83
+ # FIXME: support more OSs or versions. Basically this is using:
84
+ # http://blog.packager.io/post/101342252191/one-liner-to-get-a-precompiled-ruby-on-your-own
85
+ os = capture('head -n1 /etc/issue')
86
+ case os
87
+ when /^Ubuntu/
88
+ install_ruby('ubuntu-14.04', '2.1.4')
89
+ when /^CentOS release (\d)/
90
+ install_ruby("centos-#{$1}", '2.1.4')
91
+ when /Red Hat Enterprise Linux/
92
+ install_ruby('centos-6', '2.1.4')
93
+ when /Debian/
94
+ install_ruby('debian-7', '2.1.4')
95
+ when /Fedora/
96
+ install_ruby('fedora-20', '2.1.4')
97
+ else
98
+ abort "'#{os}' is not supported now. Please update config/deploy/itamae.rb"
99
+ end
100
+ end
101
+ end
102
+
103
+ task :bundler do
104
+ on roles(:all) do
105
+ execute!(*%W[test -e #{bin_path('bundle')} || sudo #{bin_path('gem')} install bundler --no-ri --no-rdoc])
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,8 @@
1
+ # You can filter roles by ROLES env variable.
2
+ # $ ROLES=role1,role2 bundle exec cap itamae apply
3
+ #
4
+ # With following example, you can apply recipes to production role by:
5
+ # $ ROLES=production bundle exec cap itamae apply
6
+ #
7
+ # TODO: Configure hosts to apply recipes.
8
+ role :production, %w[example-host.com]
@@ -0,0 +1 @@
1
+ execute "echo #{node[:hello].join(' ')}"
@@ -0,0 +1,19 @@
1
+ require 'pathname'
2
+
3
+ module RecipeHelper
4
+ ROOT_DIR = Pathname.new(File.expand_path(__dir__))
5
+
6
+ def include_role(name)
7
+ path = ROOT_DIR.join('roles', *name.split('::'))
8
+ path = path.relative_path_from(Pathname.new(@recipe.path).parent)
9
+ include_recipe(path.to_s)
10
+ end
11
+
12
+ def include_cookbook(name)
13
+ path = ROOT_DIR.join('cookbooks', *name.split('::'))
14
+ path = path.relative_path_from(Pathname.new(@recipe.path).parent)
15
+ include_recipe(path.to_s)
16
+ end
17
+ end
18
+
19
+ Itamae::Recipe::EvalContext.send(:include, RecipeHelper)
@@ -0,0 +1 @@
1
+ include_cookbook 'hello'
@@ -0,0 +1,4 @@
1
+ # These variables are available as `node`
2
+ hello:
3
+ - hello
4
+ - world
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itamae-template
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Takashi Kokubun
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-09-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: Itamae template generater for roles and cookbooks.
56
+ email:
57
+ - takashi-kokubun@cookpad.com
58
+ executables:
59
+ - itamae-template
60
+ - sushi
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - README.md
68
+ - Rakefile
69
+ - bin/console
70
+ - bin/setup
71
+ - exe/itamae-template
72
+ - exe/sushi
73
+ - itamae-template.gemspec
74
+ - lib/itamae/template.rb
75
+ - lib/itamae/template/cli.rb
76
+ - lib/itamae/template/version.rb
77
+ - template/.gitignore
78
+ - template/Capfile
79
+ - template/Gemfile
80
+ - template/config/deploy.rb
81
+ - template/config/deploy/itamae.rb
82
+ - template/cookbooks/hello/default.rb
83
+ - template/recipe_helper.rb
84
+ - template/roles/production/default.rb
85
+ - template/roles/production/node.yml
86
+ homepage: https://github.com/k0kubun/itamae-template
87
+ licenses: []
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.5.0
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: The best practice for itamae
109
+ test_files: []