serverkit 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e7d32c86ed73e992891971d99e1f5fed1c3d20e9
4
- data.tar.gz: 53173d404b9a4b86e7d0c84f6717531ab73e290c
3
+ metadata.gz: 612a45453d00dd4da8b327be21c8513dfb920292
4
+ data.tar.gz: 4beb20763b868203c302697f114b508c5f5f4cd8
5
5
  SHA512:
6
- metadata.gz: 3063377dafa07b971082c048a1795aa16a0b0e0c714f9779f599c2caced4a2486eec5fe27d5510b5df203a8748f736fa3b5cfeda23a5eebbb499ede87d76c042
7
- data.tar.gz: 2193c293ed47692cccfb58b0221086c5fb6cef4f232e61d7a64e69c35e3195c719f3fb4dbe337369bdd283754f9096848c8190dae087fc69f8146aaaeb3decad
6
+ metadata.gz: 4172b07769a11c4002e67caff3cb009262912e188b583893e4a9bf00a3a9432934088ae1c2c4df5bcf433a9e8621eaa1e33c122aab7547d03f118b39d0511ae6
7
+ data.tar.gz: 5068bbb81ac75922f293ff2061a41a22de161acfadf5fb64efd3100906e37014202fedec6604ecd748d1a5b716e3834e303e113be12b27c78ccee969d5610093
@@ -1,3 +1,9 @@
1
+ ## 0.2.0
2
+ - Support multiple hosts
3
+ - Change `--host=` option to `--hosts=`
4
+ - Change variables use on ERB template
5
+ - Force recipe validation on all actions
6
+
1
7
  ## 0.1.0
2
8
  - Support execution over SSH with --host option
3
9
  - Remove --recipe=... option and require recipe path in 2nd command-line argument
data/README.md CHANGED
@@ -62,12 +62,12 @@ Shows the difference between your recipe and the state of the target host.
62
62
 
63
63
  ```
64
64
  $ serverkit check recipe.yml
65
- [OK] install_mysql
66
- [OK] install_redis
67
- [OK] install_licecap
68
- [OK] install_alfred
69
- [NG] clone_dotfiles
70
- [NG] symlink_zshrc
65
+ [ OK ] install_mysql
66
+ [ OK ] install_redis
67
+ [ OK ] install_licecap
68
+ [ OK ] install_alfred
69
+ [ NG ] clone_dotfiles
70
+ [ NG ] symlink_zshrc
71
71
  ```
72
72
 
73
73
  ### serverkit apply
@@ -83,6 +83,16 @@ $ serverkit apply recipe.yml
83
83
  [DONE] symlink_zshrc
84
84
  ```
85
85
 
86
+ ### SSH support
87
+ Use `--hosts=` option to execute serverkit over SSH.
88
+ Serverkit does not require any installation on server-side.
89
+ If you want to specify SSH configuration, write it into your ~/.ssh/config.
90
+
91
+ ```
92
+ $ serverkit apply recipe.yml --hosts=alpha.example.com
93
+ $ serverkit apply recipe.yml --hosts=alpha.example.com,bravo.example.com
94
+ ```
95
+
86
96
  ## Recipe
87
97
  A recipe describes the desired state of your server.
88
98
  It is mostly a collection of resources, defined using certain patterns.
@@ -115,7 +125,7 @@ $ serverkit apply recipes/
115
125
  When using ERB recipe, you can also give optional variables file
116
126
  that defines configurations in a Hash object for ERB template.
117
127
  It supports similar format variation with Recipe.
118
- In ERB template, you can use given variables via `variables` method.
128
+ In ERB template, you can use given variables via methods named after its keys.
119
129
 
120
130
  ### Example
121
131
  This is an example recipe to install some packages, clone a git repository, and create a symlink.
@@ -137,12 +147,12 @@ resources:
137
147
  name: redis
138
148
  - id: clone_dotfiles
139
149
  type: git
140
- repository: git@github.com:<%= variables["dotfiles_repository"] %>.git
141
- path: /Users/<%= variables["user"] %>/src/github.com/<%= variables["dotfiles_repository"] %>
150
+ repository: git@github.com:<%= dotfiles_repository %>.git
151
+ path: /Users/<%= user %>/src/github.com/<%= dotfiles_repository %>
142
152
  - id: symlink_zshrc
143
153
  type: symlink
144
- source: /Users/<%= variables["user"] %>/.zshrc
145
- destination: /Users/<%= variables["user"] %>/src/github.com/<%= variables["dotfiles_repository"] %>/.zshrc
154
+ source: /Users/<%= user %>/.zshrc
155
+ destination: /Users/<%= user %>/src/github.com/<%= dotfiles_repository %>/.zshrc
146
156
  ```
147
157
 
148
158
  ## Resource
@@ -1,9 +1,9 @@
1
1
  resources:
2
2
  - id: clone_dotfiles
3
3
  type: git
4
- repository: git@github.com:<%= variables["dotfiles_github_repository"] %>.git
5
- path: /Users/<%= variables["user"] %>/src/github.com/<%= variables["dotfiles_github_repository"] %>
4
+ repository: git@github.com:<%= dotfiles_github_repository %>.git
5
+ path: /Users/<%= user %>/src/github.com/<%= dotfiles_github_repository %>
6
6
  - id: symlink_zshrc
7
7
  type: symlink
8
- source: /Users/<%= variables["user"] %>/.zshrc
9
- destination: /Users/<%= variables["user"] %>/src/github.com/<%= variables["dotfiles_github_repository"] %>/linked/.zshrc
8
+ source: /Users/<%= user %>/.zshrc
9
+ destination: /Users/<%= user %>/src/github.com/<%= dotfiles_github_repository %>/linked/.zshrc
@@ -2,7 +2,7 @@ require "active_model"
2
2
 
3
3
  class ReadableValidator < ActiveModel::EachValidator
4
4
  def validate_each(record, attribute, value)
5
- unless File.readable?(value)
5
+ if !value.nil? && !File.readable?(value)
6
6
  record.errors.add(attribute, "can't be unreadable path")
7
7
  end
8
8
  end
@@ -1,22 +1,24 @@
1
1
  require "serverkit/actions/base"
2
+ require "thread"
2
3
 
3
4
  module Serverkit
4
5
  module Actions
5
6
  class Apply < Base
6
- def call
7
- recipe.resources.each do |resource|
8
- resource.backend = backend
9
- if resource.check
10
- puts "[SKIP] #{resource.id}"
11
- else
12
- resource.apply
13
- if resource.check
14
- puts "[DONE] #{resource.id}"
15
- else
16
- puts "[FAIL] #{resource.id}"
7
+ def run
8
+ backends.map do |backend|
9
+ Thread.new do
10
+ recipe.resources.map(&:dup).each do |resource|
11
+ resource.backend = backend
12
+ if resource.check
13
+ puts "[SKIP] #{resource.id} on #{host_for(backend)}"
14
+ else
15
+ resource.apply
16
+ result = resource.check ? "DONE" : "FAIL"
17
+ puts "[#{result}] #{resource.id} on #{host_for(backend)}"
18
+ end
17
19
  end
18
20
  end
19
- end
21
+ end.each(&:join)
20
22
  end
21
23
  end
22
24
  end
@@ -14,48 +14,65 @@ module Serverkit
14
14
  @argv = argv
15
15
  end
16
16
 
17
+ def call
18
+ setup
19
+ run
20
+ end
21
+
17
22
  private
18
23
 
19
24
  def abort_with_errors
20
25
  abort recipe.errors.map { |error| "Error: #{error}" }.join("\n")
21
26
  end
22
27
 
23
- # @return [Specinfra::Backend::Base]
24
- def backend
25
- @backend ||= backend_class.new(backend_options)
28
+ # @return [Array<Specinfra::Backend::Base>]
29
+ def backends
30
+ if options[:hosts]
31
+ hosts.map do |host|
32
+ backend_class.new(
33
+ disable_sudo: true,
34
+ host: host,
35
+ ssh_options: {
36
+ user: ssh_user_for(host),
37
+ },
38
+ )
39
+ end
40
+ else
41
+ [backend_class.new]
42
+ end
26
43
  end
27
44
 
28
45
  def backend_class
29
- if host
46
+ if options[:hosts]
30
47
  Specinfra::Backend::Ssh
31
48
  else
32
49
  Specinfra::Backend::Exec
33
50
  end
34
51
  end
35
52
 
36
- def backend_options
37
- {
38
- disable_sudo: true,
39
- host: host,
40
- ssh_options: {
41
- user: ssh_user,
42
- },
43
- }
53
+ def hosts
54
+ options[:hosts].split(",")
44
55
  end
45
56
 
46
- def host
47
- options[:host]
57
+ # @param [Specinfra::Backend::Base]
58
+ # @return [String]
59
+ def host_for(backend)
60
+ backend.get_config(:host) || "localhost"
48
61
  end
49
62
 
50
63
  # @return [Slop] Command-line options
51
64
  def options
52
65
  @options ||= Slop.parse!(@argv, help: true) do
53
66
  banner "Usage: serverkit ACTION [options]"
54
- on "--host=", "Pass hostname to use SSH"
67
+ on "--hosts=", "Pass hostname to execute command over SSH"
55
68
  on "--variables=", "Path to variables file for ERB recipe"
56
69
  end
57
70
  end
58
71
 
72
+ def setup
73
+ abort_with_errors unless recipe.valid?
74
+ end
75
+
59
76
  # @return [Serverkit::Recipe]
60
77
  def recipe
61
78
  @recipe ||= Loaders::RecipeLoader.new(recipe_path, variables_path: options[:variables]).load
@@ -66,8 +83,9 @@ module Serverkit
66
83
  @argv[1] or raise Errors::MissingRecipePathArgumentError
67
84
  end
68
85
 
86
+ # @param [String] host
69
87
  # @return [String] User name used on SSH
70
- def ssh_user
88
+ def ssh_user_for(host)
71
89
  Net::SSH::Config.for(host)[:user] || Etc.getlogin
72
90
  end
73
91
  end
@@ -1,17 +1,19 @@
1
1
  require "serverkit/actions/base"
2
+ require "thread"
2
3
 
3
4
  module Serverkit
4
5
  module Actions
5
6
  class Check < Base
6
- def call
7
- recipe.resources.each do |resource|
8
- resource.backend = backend
9
- if resource.check
10
- puts "[OK] #{resource.id}"
11
- else
12
- puts "[NG] #{resource.id}"
7
+ def run
8
+ backends.map do |backend|
9
+ Thread.new do
10
+ recipe.resources.map(&:dup).each do |resource|
11
+ resource.backend = backend
12
+ result = resource.check ? "OK" : "NG"
13
+ puts "[ #{result} ] #{resource.id} on #{host_for(backend)}"
14
+ end
13
15
  end
14
- end
16
+ end.each(&:join)
15
17
  end
16
18
  end
17
19
  end
@@ -1,15 +1,10 @@
1
1
  require "serverkit/actions/base"
2
- require "yaml"
3
2
 
4
3
  module Serverkit
5
4
  module Actions
6
5
  class Inspect < Base
7
- def call
8
- if recipe.valid?
9
- puts JSON.pretty_generate(recipe.to_hash)
10
- else
11
- abort_with_errors
12
- end
6
+ def run
7
+ puts JSON.pretty_generate(recipe.to_hash)
13
8
  end
14
9
  end
15
10
  end
@@ -3,12 +3,8 @@ require "serverkit/actions/base"
3
3
  module Serverkit
4
4
  module Actions
5
5
  class Validate < Base
6
- def call
7
- if recipe.valid?
8
- puts "Success"
9
- else
10
- abort_with_errors
11
- end
6
+ def run
7
+ puts "Success"
12
8
  end
13
9
  end
14
10
  end
@@ -28,7 +28,7 @@ module Serverkit
28
28
  else
29
29
  raise Errors::UnknownActionNameError
30
30
  end
31
- rescue Errors::Base, Slop::MissingOptionError => exception
31
+ rescue Errors::Base, Slop::MissingArgumentError, Slop::MissingOptionError => exception
32
32
  abort "Error: #{exception}"
33
33
  end
34
34
 
@@ -15,7 +15,6 @@ module Serverkit
15
15
  @path = path
16
16
  end
17
17
 
18
- # @todo Rescue Error::ENOENT error
19
18
  def load
20
19
  case
21
20
  when !pathname.exist?
@@ -5,7 +5,7 @@ require "serverkit/recipe"
5
5
  module Serverkit
6
6
  module Loaders
7
7
  class RecipeLoader < BaseLoader
8
- DEFAULT_VARIABLES = {}
8
+ DEFAULT_VARIABLES_DATA = {}
9
9
 
10
10
  # @param [String] path
11
11
  # @param [String, nil] variables_path
@@ -17,8 +17,9 @@ module Serverkit
17
17
  private
18
18
 
19
19
  # @note Override
20
+ # @return [Binding]
20
21
  def binding_for_erb
21
- ErbBindingContext.new(variables_data).binding
22
+ variables.to_mash.binding
22
23
  end
23
24
 
24
25
  # @note Override to pass @variables_path
@@ -45,30 +46,16 @@ module Serverkit
45
46
  Serverkit::Recipe
46
47
  end
47
48
 
48
- # @return [Hash]
49
- def variables_data
49
+ # @return [Serverkit::Variables]
50
+ def variables
50
51
  @variables ||= begin
51
52
  if has_variables_path?
52
- load_variables.to_hash
53
+ load_variables
53
54
  else
54
- DEFAULT_VARIABLES.dup
55
+ Variables.new(DEFAULT_VARIABLES_DATA.dup)
55
56
  end
56
57
  end
57
58
  end
58
-
59
- class ErbBindingContext
60
- attr_reader :variables
61
-
62
- # @param [hash] variables
63
- def initialize(variables)
64
- @variables = variables
65
- end
66
-
67
- # @note Change method visibility to public
68
- def binding
69
- super
70
- end
71
- end
72
59
  end
73
60
  end
74
61
  end
@@ -1,4 +1,5 @@
1
1
  require "active_support/core_ext/hash/deep_merge"
2
+ require "hashie/mash"
2
3
 
3
4
  module Serverkit
4
5
  class Variables
@@ -23,9 +24,16 @@ module Serverkit
23
24
  )
24
25
  end
25
26
 
26
- # @return [Hash]
27
- def to_hash
28
- @variables_data.dup
27
+ # @return [Hashie::Mash]
28
+ def to_mash
29
+ BindableMash.new(@variables_data.dup)
30
+ end
31
+
32
+ class BindableMash < Hashie::Mash
33
+ # @note Override visibility from private to public
34
+ def binding
35
+ super
36
+ end
29
37
  end
30
38
  end
31
39
  end
@@ -1,3 +1,3 @@
1
1
  module Serverkit
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.add_runtime_dependency "activemodel"
20
20
  spec.add_runtime_dependency "activesupport"
21
+ spec.add_runtime_dependency "hashie"
21
22
  spec.add_runtime_dependency "highline"
22
23
  spec.add_runtime_dependency "slop", "~> 3.4"
23
24
  spec.add_runtime_dependency "specinfra"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serverkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Nakamura
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: hashie
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: highline
43
57
  requirement: !ruby/object:Gem::Requirement