serverkit 0.0.2 → 0.0.3

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: 3973baadffe8fb3a024c183ff1736bce8f48c719
4
- data.tar.gz: aac29f5ee26cc9c77d644b9c6dd7f2cd9c22eebd
3
+ metadata.gz: 0cb2f4173299cf4eec3b5b1004d1f006c0d211e0
4
+ data.tar.gz: 851e865ea88715d4eeaf697a7c053e6a5500b379
5
5
  SHA512:
6
- metadata.gz: 6e93dd18c08bb32e80d57ea3b59e28b1eece1e0d93a438e51bcfbb3d8aae8c2fe17cfb7a36e1a279bd46b648bc40365d3f540b2dfe3c8668402f7701b64b606e
7
- data.tar.gz: 33152a234df68bcd557b6ef38f0df5a58b29d0ac192315ab7b87cd87c2aa69449e1893ad91b19bab124b623c9d5137a2e8e02987f84d9794138bc0a1f509ea1f
6
+ metadata.gz: 23cb9453fdd628b6b87448b94a075826ca9d14367e2fe49b17d237cff832665a9b9be0fc90d112883da2e494772292516327e6d41aeffb1955f33e9b7b819b65
7
+ data.tar.gz: 12382244676a0ea0749f9f15577352cfd3ab9df973393d7a970ae7facdc1a3f942d875830ca092d5c62dab9e0f976d65fdd7eda05785901f616aaa404cc39424
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.0.3
2
+ - Support JSON, executable, and directory recipe
3
+ - Support service resource experimentally
4
+ - Validate attribute type
5
+ - Validate no resources recipe
6
+ - Rename resource.name with resource.id
7
+ - Rename package.package with package.name
8
+
1
9
  ## 0.0.2
2
10
  - Add `serverkit validate` action
3
11
 
data/README.md CHANGED
@@ -2,42 +2,78 @@
2
2
  Configuration management toolkit for your infrastructure.
3
3
 
4
4
  ## Usage
5
- ```sh
6
- # Write your recipe
7
- vi recipe.yml
5
+ This gem provides `serverkit` executable with 3 actions.
6
+ `validate` action validates your recipe format.
7
+ `check` action shows the difference between your recipe and the state of the target host.
8
+ `apply` action executes migration programs to fill-in the gaps.
8
9
 
9
- # Validate recipe
10
+ ```sh
10
11
  serverkit validate --recipe=recipe.yml
11
-
12
- # Check differences
13
12
  serverkit check --recipe=recipe.yml
13
+ serverkit apply --recipe=recipe.yml
14
+ ```
14
15
 
15
- # Apply migration
16
+ ## Recipe
17
+ A recipe is the most fundamental configuration which defines the desired state of your server.
18
+ It is mostly a collection of resources, defined using certain patterns.
19
+
20
+ ### Format
21
+ A recipe can be specified as a path to one of:
22
+
23
+ - JSON file
24
+ - YAML file named with \*.yaml or \*.yml
25
+ - Executable to output JSON
26
+ - Directory including recipe files recursively
27
+
28
+ ```sh
16
29
  serverkit apply --recipe=recipe.yml
30
+ serverkit apply --recipe=recipe.json
31
+ serverkit apply --recipe=recipe
32
+ serverkit apply --recipe=recipes/
17
33
  ```
18
34
 
19
35
  ### Example
36
+ This is an example recipe to install some packages, clone a git repository, and create a symlink.
37
+
20
38
  ```yaml
21
39
  # recipe.yml
22
40
  resources:
23
- - name: install_mysql
24
- type: homebrew
25
- package: mysql
26
- - name: install_redis
27
- type: homebrew
28
- package: redis
29
- - name: install_licecap
30
- type: homebrew_cask
31
- package: licecap
32
- - name: install_alfred
33
- type: homebrew_cask
34
- package: alfred
35
- - name: clone_dotfiles
41
+ - id: install_mysql
42
+ type: package
43
+ name: mysql
44
+ - id: install_redis
45
+ type: package
46
+ name: redis
47
+ - id: clone_dotfiles
36
48
  type: git
37
49
  repository: git@github.com:r7kamura/dotfiles.git
38
50
  path: /Users/r7kamura/src/github.com/r7kamura/dotfiles
39
- - name: symlink_zshrc
51
+ - id: symlink_zshrc
40
52
  type: symlink
41
53
  source: /Users/r7kamura/.zshrc
42
54
  destination: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
43
55
  ```
56
+
57
+ ## Resource
58
+ A resource is a statement of configuration policy that describes the desired state for an item.
59
+
60
+ ### Type
61
+ A resource must have a type property. Currently the following types are available:
62
+
63
+ - file
64
+ - git
65
+ - homebrew_cask
66
+ - homebrew
67
+ - package
68
+ - service
69
+ - symlink
70
+
71
+ ### Example
72
+ An example package resource that has id, type, and name attributes.
73
+
74
+ ```yaml
75
+ resources:
76
+ - id: install_mysql # id attirbute (This resource is identified by this unique id)
77
+ type: package # type attribute (Serverkit::Resources::Package class is used for this)
78
+ name: mysql # name attribute (package resource requires name attribute)
79
+ ```
@@ -0,0 +1,48 @@
1
+ {
2
+ "hosts": [
3
+ "localhost"
4
+ ],
5
+ "ssh": false,
6
+ "resources": [
7
+ {
8
+ "id": "install_mysql",
9
+ "type": "homebrew",
10
+ "name": "mysql"
11
+ },
12
+ {
13
+ "id": "install_redis",
14
+ "type": "homebrew",
15
+ "name": "redis"
16
+ },
17
+ {
18
+ "id": "install_licecap",
19
+ "type": "homebrew_cask",
20
+ "name": "licecap"
21
+ },
22
+ {
23
+ "id": "install_alfred",
24
+ "type": "homebrew_cask",
25
+ "name": "alfred"
26
+ },
27
+ {
28
+ "id": "clone_dotfiles",
29
+ "type": "git",
30
+ "repository": "git@github.com:r7kamura/dotfiles.git",
31
+ "path": "/Users/r7kamura/src/github.com/r7kamura/dotfiles"
32
+ },
33
+ {
34
+ "id": "symlink_zshrc",
35
+ "type": "symlink",
36
+ "source": "/Users/r7kamura/.zshrc",
37
+ "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
+ }
47
+ ]
48
+ }
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require "json"
3
+ require "yaml"
4
+
5
+ puts YAML.load_file(File.expand_path("../recipe.yml", __FILE__)).to_json
data/examples/recipe.yml CHANGED
@@ -2,27 +2,27 @@ hosts:
2
2
  - localhost
3
3
  ssh: false
4
4
  resources:
5
- - name: install_mysql
5
+ - id: install_mysql
6
6
  type: homebrew
7
- package: mysql
8
- - name: install_redis
7
+ name: mysql
8
+ - id: install_redis
9
9
  type: homebrew
10
- package: redis
11
- - name: install_licecap
10
+ name: redis
11
+ - id: install_licecap
12
12
  type: homebrew_cask
13
- package: licecap
14
- - name: install_alfred
13
+ name: licecap
14
+ - id: install_alfred
15
15
  type: homebrew_cask
16
- package: alfred
17
- - name: clone_dotfiles
16
+ name: alfred
17
+ - id: clone_dotfiles
18
18
  type: git
19
19
  repository: git@github.com:r7kamura/dotfiles.git
20
20
  path: /Users/r7kamura/src/github.com/r7kamura/dotfiles
21
- - name: symlink_zshrc
21
+ - id: symlink_zshrc
22
22
  type: symlink
23
23
  source: /Users/r7kamura/.zshrc
24
24
  destination: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
25
- - name: put_zshrc
25
+ - id: put_zshrc
26
26
  type: file
27
27
  source: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
28
28
  destination: /Users/r7kamura/src/github.com/r7kamura/dotfiles/linked/.zshrc
@@ -7,13 +7,13 @@ module Serverkit
7
7
  recipe.resources.each do |resource|
8
8
  resource.backend = backend
9
9
  if resource.check
10
- puts "[SKIP] #{resource.name}"
10
+ puts "[SKIP] #{resource.id}"
11
11
  else
12
12
  resource.apply
13
13
  if resource.check
14
- puts "[DONE] #{resource.name}"
14
+ puts "[DONE] #{resource.id}"
15
15
  else
16
- puts "[FAIL] #{resource.name}"
16
+ puts "[FAIL] #{resource.id}"
17
17
  end
18
18
  end
19
19
  end
@@ -1,4 +1,5 @@
1
1
  require "serverkit/recipe"
2
+ require "serverkit/recipe_loader"
2
3
  require "specinfra"
3
4
 
4
5
  module Serverkit
@@ -31,7 +32,7 @@ module Serverkit
31
32
 
32
33
  # @return [Serverkit::Recipe]
33
34
  def recipe
34
- @recipe ||= Recipe.load_from_path(@options[:recipe])
35
+ @recipe ||= RecipeLoader.new(@options[:recipe]).load
35
36
  end
36
37
  end
37
38
  end
@@ -7,9 +7,9 @@ module Serverkit
7
7
  recipe.resources.each do |resource|
8
8
  resource.backend = backend
9
9
  if resource.check
10
- puts "[OK] #{resource.name}"
10
+ puts "[OK] #{resource.id}"
11
11
  else
12
- puts "[NG] #{resource.name}"
12
+ puts "[NG] #{resource.id}"
13
13
  end
14
14
  end
15
15
  end
@@ -1,3 +1,4 @@
1
+ require "active_support/core_ext/hash/deep_merge"
1
2
  require "active_support/core_ext/string/inflections"
2
3
  require "serverkit/errors/invalid_recipe_type"
3
4
  require "serverkit/errors/invalid_resources_type"
@@ -5,23 +6,16 @@ require "serverkit/resources/file"
5
6
  require "serverkit/resources/git"
6
7
  require "serverkit/resources/homebrew"
7
8
  require "serverkit/resources/homebrew_cask"
9
+ require "serverkit/resources/service"
8
10
  require "serverkit/resources/symlink"
9
11
  require "yaml"
10
12
 
11
13
  module Serverkit
12
14
  class Recipe
13
- class << self
14
- # @param [String] path
15
- def load_from_path(path)
16
- recipe_data = YAML.load_file(path)
17
- new(recipe_data)
18
- end
19
- end
20
-
21
15
  attr_reader :recipe_data
22
16
 
23
17
  # @param [Hash] recipe_data
24
- def initialize(recipe_data)
18
+ def initialize(recipe_data = {})
25
19
  @recipe_data = recipe_data
26
20
  end
27
21
 
@@ -44,6 +38,20 @@ module Serverkit
44
38
  @recipe_data["hosts"]
45
39
  end
46
40
 
41
+ # @param [Serverkit::Recipe] recipe
42
+ # @return [Serverkit::Recipe]
43
+ def merge(recipe)
44
+ self.class.new(
45
+ recipe_data.deep_merge(recipe.recipe_data) do |key, a, b|
46
+ if a.is_a?(Array)
47
+ a | b
48
+ else
49
+ b
50
+ end
51
+ end
52
+ )
53
+ end
54
+
47
55
  # @return [Array<Serverkit::Resources::Base>]
48
56
  # @todo Delegate to resource builder
49
57
  def resources
@@ -89,9 +97,9 @@ module Serverkit
89
97
  @recipe_data.is_a?(Hash)
90
98
  end
91
99
 
92
- # @return [Array<String>]
100
+ # @return [Array<String>, nil]
93
101
  def resources_property
94
- @recipe_data["resources"] || []
102
+ @recipe_data["resources"]
95
103
  end
96
104
  end
97
105
  end
@@ -0,0 +1,79 @@
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
@@ -1,4 +1,7 @@
1
1
  require "active_model"
2
+ require "readable_validator"
3
+ require "required_validator"
4
+ require "type_validator"
2
5
 
3
6
  module Serverkit
4
7
  module Resources
@@ -18,7 +21,7 @@ module Serverkit
18
21
 
19
22
  attr_accessor :backend
20
23
 
21
- attribute :name, required: true
24
+ attribute :id, required: true, type: String
22
25
 
23
26
  # @param [Hash] attributes
24
27
  def initialize(attributes)
@@ -1,15 +1,13 @@
1
1
  require "digest"
2
- require "readable_validator"
3
- require "required_validator"
4
2
  require "serverkit/resources/base"
5
3
 
6
4
  module Serverkit
7
5
  module Resources
8
6
  class File < Base
9
- attribute :destination, required: true
10
- attribute :group
11
- attribute :owner
12
- attribute :source, readable: true, required: true
7
+ attribute :destination, required: true, type: String
8
+ attribute :group, type: String
9
+ attribute :owner, type: String
10
+ attribute :source, readable: true, required: true, type: String
13
11
 
14
12
  def apply
15
13
  send_file if file_sendable?
@@ -5,9 +5,9 @@ module Serverkit
5
5
  class Git < Base
6
6
  DEFAULT_STATUS = "cloned"
7
7
 
8
- attribute :path, required: true
9
- attribute :repository, required: true
10
- attribute :status, default: DEFAULT_STATUS
8
+ attribute :path, required: true, type: String
9
+ attribute :repository, required: true, type: String
10
+ attribute :status, default: DEFAULT_STATUS, type: String
11
11
 
12
12
  def apply
13
13
  clone if clonable?
@@ -3,15 +3,15 @@ require "serverkit/resources/base"
3
3
  module Serverkit
4
4
  module Resources
5
5
  class HomebrewCask < Base
6
- attribute :package, required: true
6
+ attribute :name, required: true, type: String
7
7
 
8
8
  def apply
9
- run_command("brew cask install #{package}")
9
+ run_command("brew cask install #{name}")
10
10
  end
11
11
 
12
12
  # @return [true, false]
13
13
  def check
14
- check_command("/usr/local/bin/brew cask list -1 | grep -E '^#{package}$'")
14
+ check_command("/usr/local/bin/brew cask list -1 | grep -E '^#{name}$'")
15
15
  end
16
16
  end
17
17
  end
@@ -3,15 +3,15 @@ require "serverkit/resources/base"
3
3
  module Serverkit
4
4
  module Resources
5
5
  class Package < Base
6
- attribute :package, required: true
6
+ attribute :name, required: true, type: String
7
7
 
8
8
  def apply
9
- run_command_from_identifier(:install, package)
9
+ run_command_from_identifier(:install, name)
10
10
  end
11
11
 
12
12
  # @return [true, false]
13
13
  def check
14
- check_command_from_identifier(:check_package_is_installed, package)
14
+ check_command_from_identifier(:check_package_is_installed, name)
15
15
  end
16
16
  end
17
17
  end
@@ -0,0 +1,17 @@
1
+ require "serverkit/resources/base"
2
+
3
+ module Serverkit
4
+ module Resources
5
+ class Service < Base
6
+ attribute :name, required: true, type: String
7
+
8
+ def apply
9
+ run_command_from_identifier(:start, name)
10
+ end
11
+
12
+ def check
13
+ check_command_from_identifier(:check_service_is_running, name)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -3,8 +3,8 @@ require "serverkit/resources/base"
3
3
  module Serverkit
4
4
  module Resources
5
5
  class Symlink < Base
6
- attribute :destination, required: true
7
- attribute :source, required: true
6
+ attribute :destination, required: true, type: String
7
+ attribute :source, required: true, type: String
8
8
 
9
9
  def apply
10
10
  run_command_from_identifier(:link_file_to, source, destination)
@@ -1,3 +1,3 @@
1
1
  module Serverkit
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,13 @@
1
+ require "active_model"
2
+
3
+ class TypeValidator < ActiveModel::EachValidator
4
+ def options
5
+ super.merge(allow_nil: true)
6
+ end
7
+
8
+ def validate_each(record, attribute, value)
9
+ unless value.is_a?(options[:with])
10
+ record.errors.add(attribute, "must be a #{options[:with]}, not #{value.class}")
11
+ end
12
+ end
13
+ end
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.2
4
+ version: 0.0.3
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-30 00:00:00.000000000 Z
11
+ date: 2015-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -154,6 +154,8 @@ files:
154
154
  - README.md
155
155
  - Rakefile
156
156
  - bin/serverkit
157
+ - examples/recipe.json
158
+ - examples/recipe.rb
157
159
  - examples/recipe.yml
158
160
  - lib/readable_validator.rb
159
161
  - lib/required_validator.rb
@@ -167,14 +169,17 @@ files:
167
169
  - lib/serverkit/errors/invalid_recipe_type.rb
168
170
  - lib/serverkit/errors/invalid_resources_type.rb
169
171
  - lib/serverkit/recipe.rb
172
+ - lib/serverkit/recipe_loader.rb
170
173
  - lib/serverkit/resources/base.rb
171
174
  - lib/serverkit/resources/file.rb
172
175
  - lib/serverkit/resources/git.rb
173
176
  - lib/serverkit/resources/homebrew.rb
174
177
  - lib/serverkit/resources/homebrew_cask.rb
175
178
  - lib/serverkit/resources/package.rb
179
+ - lib/serverkit/resources/service.rb
176
180
  - lib/serverkit/resources/symlink.rb
177
181
  - lib/serverkit/version.rb
182
+ - lib/type_validator.rb
178
183
  - serverkit.gemspec
179
184
  homepage: https://github.com/r7kamura/serverkit
180
185
  licenses: