serverkit 0.0.2 → 0.0.3

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: 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: