serverkit 0.0.3 → 0.0.4

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: 0cb2f4173299cf4eec3b5b1004d1f006c0d211e0
4
- data.tar.gz: 851e865ea88715d4eeaf697a7c053e6a5500b379
3
+ metadata.gz: 10080848f2805e6c3836073587e6be22407c01e6
4
+ data.tar.gz: 0867ac71a5aa865f8448aa12afbb513ed7c99db8
5
5
  SHA512:
6
- metadata.gz: 23cb9453fdd628b6b87448b94a075826ca9d14367e2fe49b17d237cff832665a9b9be0fc90d112883da2e494772292516327e6d41aeffb1955f33e9b7b819b65
7
- data.tar.gz: 12382244676a0ea0749f9f15577352cfd3ab9df973393d7a970ae7facdc1a3f942d875830ca092d5c62dab9e0f976d65fdd7eda05785901f616aaa404cc39424
6
+ metadata.gz: d69a3bf329a1cad28e178f10a3767aac3c2b2b03dbb6b431d71827e8883e9628e0543ca4e7633dc9e80a32a9c206cfad4f8d5466e480f68036a70bb04b5ac649
7
+ data.tar.gz: 353146a60c1c4fe93439b205bba7750073459ffdcdd891ecfaa2f165bfddacab863692d2eb041d667c5caa22c18ee7b925ea9cb2f78f82db5a5ef3af1571d93a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 0.0.4
2
+ - Support ERB recipe and variables injection
3
+
1
4
  ## 0.0.3
2
5
  - Support JSON, executable, and directory recipe
3
6
  - Support service resource experimentally
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Serverkit [![Build Status](https://travis-ci.org/r7kamura/serverkit.svg)](https://travis-ci.org/r7kamura/serverkit) [![Code Climate](https://codeclimate.com/github/r7kamura/serverkit/badges/gpa.svg)](https://codeclimate.com/github/r7kamura/serverkit)
2
- Configuration management toolkit for your infrastructure.
2
+ Configuration management toolkit for IT automation.
3
3
 
4
4
  ## Usage
5
5
  This gem provides `serverkit` executable with 3 actions.
@@ -14,29 +14,49 @@ serverkit apply --recipe=recipe.yml
14
14
  ```
15
15
 
16
16
  ## Recipe
17
- A recipe is the most fundamental configuration which defines the desired state of your server.
17
+ A recipe describes the desired state of your server.
18
18
  It is mostly a collection of resources, defined using certain patterns.
19
19
 
20
20
  ### Format
21
- A recipe can be specified as a path to one of:
21
+ A recipe can be specified as a path to one of the following patterns:
22
22
 
23
23
  - JSON file
24
24
  - YAML file named with \*.yaml or \*.yml
25
+ - ERB file named with \*.json.erb or \*.yml.erb
25
26
  - Executable to output JSON
26
27
  - Directory including recipe files recursively
27
28
 
28
29
  ```sh
29
- serverkit apply --recipe=recipe.yml
30
- serverkit apply --recipe=recipe.json
31
30
  serverkit apply --recipe=recipe
31
+ serverkit apply --recipe=recipe.json
32
+ serverkit apply --recipe=recipe.json.erb
33
+ serverkit apply --recipe=recipe.json.erb --variables=variables
34
+ serverkit apply --recipe=recipe.json.erb --variables=variables.json
35
+ serverkit apply --recipe=recipe.json.erb --variables=variables.json.erb
36
+ serverkit apply --recipe=recipe.json.erb --variables=variables.yml
37
+ serverkit apply --recipe=recipe.json.erb --variables=variables.yml.erb
38
+ serverkit apply --recipe=recipe.yml
39
+ serverkit apply --recipe=recipe.yml.erb
32
40
  serverkit apply --recipe=recipes/
33
41
  ```
34
42
 
43
+ ### Variables
44
+ When using ERB recipe, you can also give optional variables file
45
+ that defines configurations in a Hash object for ERB template.
46
+ It supports similar format variation with Recipe.
47
+ In ERB template, you can refer given variables via `variables` method.
48
+
35
49
  ### Example
36
50
  This is an example recipe to install some packages, clone a git repository, and create a symlink.
37
51
 
38
52
  ```yaml
39
- # recipe.yml
53
+ # variables.yml
54
+ dotfiles_repository: r7kamura/dotfiles
55
+ user: r7kamura
56
+ ```
57
+
58
+ ```yaml
59
+ # recipe.yml.erb
40
60
  resources:
41
61
  - id: install_mysql
42
62
  type: package
@@ -46,12 +66,12 @@ resources:
46
66
  name: redis
47
67
  - id: clone_dotfiles
48
68
  type: git
49
- repository: git@github.com:r7kamura/dotfiles.git
50
- path: /Users/r7kamura/src/github.com/r7kamura/dotfiles
69
+ repository: git@github.com:<%= variables["dotfiles_repository"] %>.git
70
+ path: /Users/<%= variables["user"] %>/src/github.com/<%= variables["dotfiles_repository"] %>
51
71
  - id: symlink_zshrc
52
72
  type: symlink
53
- source: /Users/r7kamura/.zshrc
54
- destination: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
73
+ source: /Users/<%= variables["user"] %>/.zshrc
74
+ destination: /Users/<%= variables["user"] %>/src/github.com/<%= variables["dotfiles_repository"] %>/.zshrc
55
75
  ```
56
76
 
57
77
  ## Resource
@@ -73,7 +93,7 @@ An example package resource that has id, type, and name attributes.
73
93
 
74
94
  ```yaml
75
95
  resources:
76
- - id: install_mysql # id attirbute (This resource is identified by this unique id)
96
+ - id: install_mysql # id attirbute (This resource is identified by this unique id)
77
97
  type: package # type attribute (Serverkit::Resources::Package class is used for this)
78
98
  name: mysql # name attribute (package resource requires name attribute)
79
99
  ```
@@ -1,8 +1,4 @@
1
1
  {
2
- "hosts": [
3
- "localhost"
4
- ],
5
- "ssh": false,
6
2
  "resources": [
7
3
  {
8
4
  "id": "install_mysql",
@@ -35,14 +31,6 @@
35
31
  "type": "symlink",
36
32
  "source": "/Users/r7kamura/.zshrc",
37
33
  "destination": "/Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc"
38
- },
39
- {
40
- "id": "put_zshrc",
41
- "type": "file",
42
- "source": "/Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc",
43
- "destination": "/Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc",
44
- "user": "r7kamura",
45
- "group": "staff"
46
34
  }
47
35
  ]
48
- }
36
+ }
File without changes
@@ -1,6 +1,3 @@
1
- hosts:
2
- - localhost
3
- ssh: false
4
1
  resources:
5
2
  - id: install_mysql
6
3
  type: homebrew
@@ -22,9 +19,3 @@ resources:
22
19
  type: symlink
23
20
  source: /Users/r7kamura/.zshrc
24
21
  destination: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
25
- - id: put_zshrc
26
- type: file
27
- source: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
28
- destination: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
29
- user: r7kamura
30
- group: staff
@@ -0,0 +1,21 @@
1
+ resources:
2
+ - id: install_mysql
3
+ type: homebrew
4
+ name: mysql
5
+ - id: install_redis
6
+ type: homebrew
7
+ name: redis
8
+ - id: install_licecap
9
+ type: homebrew_cask
10
+ name: licecap
11
+ - id: install_alfred
12
+ type: homebrew_cask
13
+ name: alfred
14
+ - id: clone_dotfiles
15
+ type: git
16
+ repository: git@github.com:<%= variables["dotfiles_github_repository"] %>.git
17
+ path: /Users/<%= variables["user"] %>/src/github.com/<%= variables["dotfiles_github_repository"] %>
18
+ - id: symlink_zshrc
19
+ type: symlink
20
+ source: /Users/<%= variables["user"] %>/.zshrc
21
+ destination: /Users/<%= variables["user"] %>/src/github.com/<%= variables["dotfiles_github_repository"] %>/linked/.zshrc
@@ -0,0 +1,2 @@
1
+ dotfiles_github_repository: r7kamura/dotfiles
2
+ user: r7kamura
@@ -1,5 +1,5 @@
1
+ require "serverkit/loaders/recipe_loader"
1
2
  require "serverkit/recipe"
2
- require "serverkit/recipe_loader"
3
3
  require "specinfra"
4
4
 
5
5
  module Serverkit
@@ -18,21 +18,12 @@ module Serverkit
18
18
 
19
19
  # @return [Specinfra::Backend::Base]
20
20
  def backend
21
- @backend ||= backend_class.new
22
- end
23
-
24
- # @return [Class]
25
- def backend_class
26
- if recipe.ssh?
27
- Specinfra::Backend::Ssh
28
- else
29
- Specinfra::Backend::Exec
30
- end
21
+ @backend ||= Specinfra::Backend::Exec.new
31
22
  end
32
23
 
33
24
  # @return [Serverkit::Recipe]
34
25
  def recipe
35
- @recipe ||= RecipeLoader.new(@options[:recipe]).load
26
+ @recipe ||= Loaders::RecipeLoader.new(@options[:recipe], variables_path: @options[:variables]).load
36
27
  end
37
28
  end
38
29
  end
@@ -69,6 +69,7 @@ module Serverkit
69
69
  @options ||= Slop.parse!(@argv) do
70
70
  banner "Usage: serverkit ACTION [options]"
71
71
  on "-r", "--recipe=", "Path to recipe file", required: true
72
+ on "--variables=", "Path to variables file for ERB recipe"
72
73
  end
73
74
  end
74
75
 
@@ -0,0 +1,130 @@
1
+ require "erb"
2
+ require "json"
3
+ require "pathname"
4
+ require "tempfile"
5
+ require "yaml"
6
+
7
+ module Serverkit
8
+ module Loaders
9
+ class BaseLoader
10
+ YAML_EXTNAMES = [".yaml", ".yml"]
11
+
12
+ # @param [String] path
13
+ def initialize(path)
14
+ @path = path
15
+ end
16
+
17
+ # @todo Rescue Error::ENOENT error
18
+ # @return [Serverkit::Recipe]
19
+ def load
20
+ case
21
+ when has_directory_path?
22
+ load_from_directory
23
+ when has_erb_path?
24
+ load_from_erb
25
+ else
26
+ loaded_class.new(load_data)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ # @return [Binding]
33
+ def binding_for_erb
34
+ TOPLEVEL_BINDING
35
+ end
36
+
37
+ # @return [String]
38
+ def expand_erb
39
+ ERB.new(pathname.read).result(binding_for_erb)
40
+ end
41
+
42
+ # @return [String]
43
+ def expanded_erb_path_suffix
44
+ "." + pathname.basename(".erb").to_s.split(".", 2).last
45
+ end
46
+
47
+ # @note Memoizing to prevent GC
48
+ # @return [Tempfile]
49
+ def expanded_erb_tempfile
50
+ @expanded_erb_tempfile ||= Tempfile.new(["", expanded_erb_path_suffix]).tap do |tempfile|
51
+ tempfile << expand_erb
52
+ tempfile.close
53
+ tempfile
54
+ end
55
+ end
56
+
57
+ # @return [String]
58
+ def execute
59
+ `#{pathname}`
60
+ end
61
+
62
+ def has_directory_path?
63
+ pathname.directory?
64
+ end
65
+
66
+ def has_erb_path?
67
+ pathname.extname == ".erb"
68
+ end
69
+
70
+ def has_executable_path?
71
+ pathname.executable?
72
+ end
73
+
74
+ def has_yaml_path?
75
+ YAML_EXTNAMES.include?(pathname.extname)
76
+ end
77
+
78
+ # @return [Hash]
79
+ def load_data
80
+ case
81
+ when has_executable_path?
82
+ load_data_from_executable
83
+ when has_erb_path?
84
+ load_data_from_erb
85
+ when has_yaml_path?
86
+ load_data_from_yaml
87
+ else
88
+ load_data_from_json
89
+ end
90
+ end
91
+
92
+ # @return [Serverkit::Recipe]
93
+ def load_from_directory
94
+ loads_from_directory.inject(loaded_class.new, :merge)
95
+ end
96
+
97
+ # @return [Serverkit::Recipe]
98
+ def load_from_erb
99
+ self.class.new(expanded_erb_tempfile.path).load
100
+ end
101
+
102
+ # @return [Array<Serverkit::Recipe>]
103
+ def loads_from_directory
104
+ Dir.glob(pathname.join("*")).sort.flat_map do |path|
105
+ self.class.new(path).load
106
+ end
107
+ end
108
+
109
+ # @return [Hash]
110
+ def load_data_from_executable
111
+ JSON.parse(execute)
112
+ end
113
+
114
+ # @return [Hash]
115
+ def load_data_from_json
116
+ JSON.parse(pathname.read)
117
+ end
118
+
119
+ # @return [Hash]
120
+ def load_data_from_yaml
121
+ YAML.load_file(pathname)
122
+ end
123
+
124
+ # @return [Pathname]
125
+ def pathname
126
+ @pathname ||= Pathname.new(@path)
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,64 @@
1
+ require "serverkit/loaders/base_loader"
2
+ require "serverkit/loaders/variables_loader"
3
+ require "serverkit/recipe"
4
+
5
+ module Serverkit
6
+ module Loaders
7
+ class RecipeLoader < BaseLoader
8
+ DEFAULT_VARIABLES = {}
9
+
10
+ # @param [String] path
11
+ # @param [String, nil] variables_path
12
+ def initialize(path, variables_path: nil)
13
+ super(path)
14
+ @variables_path = variables_path
15
+ end
16
+
17
+ private
18
+
19
+ # @note Override
20
+ def binding_for_erb
21
+ ErbBindingContext.new(variables_data).binding
22
+ end
23
+
24
+ def has_variables_path?
25
+ !@variables_path.nil?
26
+ end
27
+
28
+ # @return [Serverkit::Variables]
29
+ def load_variables
30
+ Loaders::VariablesLoader.new(@variables_path).load
31
+ end
32
+
33
+ # @note Implementation
34
+ def loaded_class
35
+ Serverkit::Recipe
36
+ end
37
+
38
+ # @return [Hash]
39
+ def variables_data
40
+ @variables ||= begin
41
+ if has_variables_path?
42
+ load_variables.to_hash
43
+ else
44
+ DEFAULT_VARIABLES.dup
45
+ end
46
+ end
47
+ end
48
+
49
+ class ErbBindingContext
50
+ attr_reader :variables
51
+
52
+ # @param [hash] variables
53
+ def initialize(variables)
54
+ @variables = variables
55
+ end
56
+
57
+ # @note Change method visibility to public
58
+ def binding
59
+ super
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,15 @@
1
+ require "serverkit/loaders/base_loader"
2
+ require "serverkit/variables"
3
+
4
+ module Serverkit
5
+ module Loaders
6
+ class VariablesLoader < BaseLoader
7
+ private
8
+
9
+ # @note Implementation
10
+ def loaded_class
11
+ Serverkit::Variables
12
+ end
13
+ end
14
+ end
15
+ end
@@ -8,7 +8,6 @@ require "serverkit/resources/homebrew"
8
8
  require "serverkit/resources/homebrew_cask"
9
9
  require "serverkit/resources/service"
10
10
  require "serverkit/resources/symlink"
11
- require "yaml"
12
11
 
13
12
  module Serverkit
14
13
  class Recipe
@@ -60,11 +59,6 @@ module Serverkit
60
59
  end
61
60
  end
62
61
 
63
- # @return [true, false] Flag to use SSH (default: true)
64
- def ssh?
65
- @recipe_data["ssh"] != false
66
- end
67
-
68
62
  def valid?
69
63
  errors.empty?
70
64
  end
@@ -0,0 +1,31 @@
1
+ require "active_support/core_ext/hash/deep_merge"
2
+
3
+ module Serverkit
4
+ class Variables
5
+ attr_reader :variables_data
6
+
7
+ # @param [Hash] variables_data
8
+ def initialize(variables_data = {})
9
+ @variables_data = variables_data
10
+ end
11
+
12
+ # @param [Serverkit::Variables] variables
13
+ # @return [Serverkit::Variables]
14
+ def merge(variables)
15
+ self.class.new(
16
+ variables_data.deep_merge(variables.variables_data) do |key, a, b|
17
+ if a.is_a?(Array)
18
+ a | b
19
+ else
20
+ b
21
+ end
22
+ end
23
+ )
24
+ end
25
+
26
+ # @return [Hash]
27
+ def to_hash
28
+ @variables_data.dup
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module Serverkit
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/serverkit.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.version = Serverkit::VERSION
8
8
  spec.authors = ["Ryo Nakamura"]
9
9
  spec.email = ["r7kamura@gmail.com"]
10
- spec.summary = "Configuration management toolkit for your infrastructure."
10
+ spec.summary = "Configuration management toolkit for IT automation."
11
11
  spec.homepage = "https://github.com/r7kamura/serverkit"
12
12
  spec.license = "MIT"
13
13
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serverkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Nakamura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-31 00:00:00.000000000 Z
11
+ date: 2015-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -154,9 +154,11 @@ files:
154
154
  - README.md
155
155
  - Rakefile
156
156
  - bin/serverkit
157
- - examples/recipe.json
158
- - examples/recipe.rb
159
- - examples/recipe.yml
157
+ - example/recipes/recipe.json
158
+ - example/recipes/recipe.rb
159
+ - example/recipes/recipe.yml
160
+ - example/recipes/recipe.yml.erb
161
+ - example/variables/variables.yml
160
162
  - lib/readable_validator.rb
161
163
  - lib/required_validator.rb
162
164
  - lib/serverkit.rb
@@ -168,8 +170,10 @@ files:
168
170
  - lib/serverkit/errors/base.rb
169
171
  - lib/serverkit/errors/invalid_recipe_type.rb
170
172
  - lib/serverkit/errors/invalid_resources_type.rb
173
+ - lib/serverkit/loaders/base_loader.rb
174
+ - lib/serverkit/loaders/recipe_loader.rb
175
+ - lib/serverkit/loaders/variables_loader.rb
171
176
  - lib/serverkit/recipe.rb
172
- - lib/serverkit/recipe_loader.rb
173
177
  - lib/serverkit/resources/base.rb
174
178
  - lib/serverkit/resources/file.rb
175
179
  - lib/serverkit/resources/git.rb
@@ -178,6 +182,7 @@ files:
178
182
  - lib/serverkit/resources/package.rb
179
183
  - lib/serverkit/resources/service.rb
180
184
  - lib/serverkit/resources/symlink.rb
185
+ - lib/serverkit/variables.rb
181
186
  - lib/serverkit/version.rb
182
187
  - lib/type_validator.rb
183
188
  - serverkit.gemspec
@@ -204,6 +209,6 @@ rubyforge_project:
204
209
  rubygems_version: 2.4.5
205
210
  signing_key:
206
211
  specification_version: 4
207
- summary: Configuration management toolkit for your infrastructure.
212
+ summary: Configuration management toolkit for IT automation.
208
213
  test_files: []
209
214
  has_rdoc:
@@ -1,79 +0,0 @@
1
- require "json"
2
-
3
- module Serverkit
4
- class RecipeLoader
5
- YAML_EXTNAMES = [".yaml", ".yml"]
6
-
7
- # @param [String] path
8
- def initialize(path)
9
- @path = path
10
- end
11
-
12
- # @todo Care Error::ENOENT error
13
- # @return [Serverkit::Recipe]
14
- def load
15
- if has_directory_path?
16
- load_recipe_from_directory
17
- else
18
- Recipe.new(load_data)
19
- end
20
- end
21
-
22
- private
23
-
24
- # @return [String] This executable must print reicpe in JSON format into standard output
25
- def execute
26
- `#{@path}`
27
- end
28
-
29
- # @return [String]
30
- def extname
31
- @extname ||= File.extname(@path)
32
- end
33
-
34
- def has_directory_path?
35
- File.directory?(@path)
36
- end
37
-
38
- def has_executable_path?
39
- File.executable?(@path)
40
- end
41
-
42
- def has_yaml_path?
43
- YAML_EXTNAMES.include?(extname)
44
- end
45
-
46
- def load_data
47
- case
48
- when has_executable_path?
49
- load_data_from_executable
50
- when has_yaml_path?
51
- load_data_from_yaml
52
- else
53
- load_data_from_json
54
- end
55
- end
56
-
57
- def load_recipe_from_directory
58
- load_recipes_from_directory.inject(Recipe.new, :merge)
59
- end
60
-
61
- def load_recipes_from_directory
62
- Dir.glob(File.join(@path, "*")).sort.flat_map do |path|
63
- self.class.new(path).load
64
- end
65
- end
66
-
67
- def load_data_from_executable
68
- JSON.parse(execute)
69
- end
70
-
71
- def load_data_from_json
72
- JSON.parse(File.read(@path))
73
- end
74
-
75
- def load_data_from_yaml
76
- YAML.load_file(@path)
77
- end
78
- end
79
- end