serverkit 0.0.3 → 0.0.4

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