itamae-template 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []