serverkit 0.0.1 → 0.0.2

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: a46215c909742a449201656305440413650b941f
4
- data.tar.gz: 1e23e1ae21759a680affbdf69389e1900d59e8d7
3
+ metadata.gz: 3973baadffe8fb3a024c183ff1736bce8f48c719
4
+ data.tar.gz: aac29f5ee26cc9c77d644b9c6dd7f2cd9c22eebd
5
5
  SHA512:
6
- metadata.gz: ea78669c98502fea368c1f8c9042249190b988c8a12e82400276f82c396c9edc38db5fd4d3f4dc6a791091d07fd172bb57fcd16bb7349ee7d6030cb4ac910ec3
7
- data.tar.gz: 1d4a29c33da839040b7ce029047a7f2f14d1d64663cd028505e98051c0b3f58b9695b661c52079376d97e26250edfad0e0c511b5d8502aec14598fd4ae7fd6ca
6
+ metadata.gz: 6e93dd18c08bb32e80d57ea3b59e28b1eece1e0d93a438e51bcfbb3d8aae8c2fe17cfb7a36e1a279bd46b648bc40365d3f540b2dfe3c8668402f7701b64b606e
7
+ data.tar.gz: 33152a234df68bcd557b6ef38f0df5a58b29d0ac192315ab7b87cd87c2aa69449e1893ad91b19bab124b623c9d5137a2e8e02987f84d9794138bc0a1f509ea1f
data/.rubocop.yml CHANGED
@@ -31,6 +31,12 @@ Style/DoubleNegation:
31
31
  Style/FormatString:
32
32
  Enabled: false
33
33
 
34
+ Style/GuardClause:
35
+ Enabled: false
36
+
37
+ Style/IfUnlessModifier:
38
+ Enabled: false
39
+
34
40
  Style/MultilineBlockChain:
35
41
  Enabled: false
36
42
 
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ ## 0.0.2
2
+ - Add `serverkit validate` action
3
+
4
+ ## 0.0.1
5
+ - 1st Release on 2015-03-30
6
+ - Support `serverkit check` and `serverkit apply` actions
data/README.md CHANGED
@@ -1,16 +1,19 @@
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 building servers.
2
+ Configuration management toolkit for your infrastructure.
3
3
 
4
4
  ## Usage
5
5
  ```sh
6
6
  # Write your recipe
7
7
  vi recipe.yml
8
8
 
9
- # Check
10
- bundle exec serverkit check --recipe=recipe.yml
9
+ # Validate recipe
10
+ serverkit validate --recipe=recipe.yml
11
11
 
12
- # Apply
13
- bundle exec serverkit apply --recipe=recipe.yml
12
+ # Check differences
13
+ serverkit check --recipe=recipe.yml
14
+
15
+ # Apply migration
16
+ serverkit apply --recipe=recipe.yml
14
17
  ```
15
18
 
16
19
  ### Example
@@ -0,0 +1,9 @@
1
+ require "active_model"
2
+
3
+ class ReadableValidator < ActiveModel::EachValidator
4
+ def validate_each(record, attribute, value)
5
+ unless File.readable?(value)
6
+ record.errors.add(attribute, "is unreadable")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require "active_model"
2
+
3
+ class RequiredValidator < ActiveModel::EachValidator
4
+ def validate_each(record, attribute, value)
5
+ if value.nil?
6
+ record.errors.add(attribute, "is required")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ require "serverkit/actions/base"
2
+
3
+ module Serverkit
4
+ module Actions
5
+ class Validate < Base
6
+ def call
7
+ if recipe.valid?
8
+ puts "Success"
9
+ else
10
+ abort recipe.errors.map { |error| "Error: #{error}" }.join("\n")
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,6 @@
1
1
  require "serverkit/actions/apply"
2
2
  require "serverkit/actions/check"
3
+ require "serverkit/actions/validate"
3
4
  require "slop"
4
5
 
5
6
  module Serverkit
@@ -7,6 +8,7 @@ module Serverkit
7
8
  ACTION_NAMES = %w(
8
9
  apply
9
10
  check
11
+ validate
10
12
  )
11
13
 
12
14
  # @param [Array<String>] argv
@@ -24,6 +26,8 @@ module Serverkit
24
26
  apply
25
27
  when action_name == "check"
26
28
  check
29
+ when action_name == "validate"
30
+ validate
27
31
  end
28
32
  rescue Slop::MissingOptionError => exception
29
33
  abort "Error: #{exception}"
@@ -67,5 +71,9 @@ module Serverkit
67
71
  on "-r", "--recipe=", "Path to recipe file", required: true
68
72
  end
69
73
  end
74
+
75
+ def validate
76
+ Actions::Validate.new(options).call
77
+ end
70
78
  end
71
79
  end
@@ -0,0 +1,6 @@
1
+ module Serverkit
2
+ module Errors
3
+ class Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,16 @@
1
+ require "serverkit/errors/base"
2
+
3
+ module Serverkit
4
+ module Errors
5
+ class InvalidRecipeType < Base
6
+ # @param [Class] type
7
+ def initialize(type)
8
+ @type = type
9
+ end
10
+
11
+ def to_s
12
+ "Recipe data must be a Hash, not #{@type}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require "serverkit/errors/base"
2
+
3
+ module Serverkit
4
+ module Errors
5
+ class InvalidResourcesType < Base
6
+ # @param [Class] type
7
+ def initialize(type)
8
+ @type = type
9
+ end
10
+
11
+ def to_s
12
+ "resources property must be an Array, not #{@type}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,4 +1,6 @@
1
1
  require "active_support/core_ext/string/inflections"
2
+ require "serverkit/errors/invalid_recipe_type"
3
+ require "serverkit/errors/invalid_resources_type"
2
4
  require "serverkit/resources/file"
3
5
  require "serverkit/resources/git"
4
6
  require "serverkit/resources/homebrew"
@@ -11,39 +13,85 @@ module Serverkit
11
13
  class << self
12
14
  # @param [String] path
13
15
  def load_from_path(path)
14
- raw_recipe = YAML.load_file(path)
15
- new(raw_recipe)
16
+ recipe_data = YAML.load_file(path)
17
+ new(recipe_data)
16
18
  end
17
19
  end
18
20
 
19
- # @param [Hash] raw_recipe
20
- def initialize(raw_recipe)
21
- @raw_recipe = raw_recipe
21
+ attr_reader :recipe_data
22
+
23
+ # @param [Hash] recipe_data
24
+ def initialize(recipe_data)
25
+ @recipe_data = recipe_data
22
26
  end
23
27
 
24
- # @return [Array<Serverkit::Resources::Base>]
25
- # @todo Delegate to resource builder
26
- def resources
27
- @resources ||= resource_properties.map do |properties|
28
- Resources.const_get(properties["type"].camelize, false).new(properties)
28
+ # @return [Array<Serverkit::Errors::Base>]
29
+ def errors
30
+ @errors ||= begin
31
+ case
32
+ when !has_valid_typed_recipe_data?
33
+ errors_for_invalid_typed_recipe_data
34
+ when !has_valid_typed_resources_property?
35
+ errors_for_invalid_typed_resources_property
36
+ else
37
+ errors_in_resources
38
+ end
29
39
  end
30
40
  end
31
41
 
32
42
  # @return [Array<String>]
33
43
  def hosts
34
- @raw_recipe["hosts"]
44
+ @recipe_data["hosts"]
45
+ end
46
+
47
+ # @return [Array<Serverkit::Resources::Base>]
48
+ # @todo Delegate to resource builder
49
+ def resources
50
+ @resources ||= resources_property.map do |attributes|
51
+ Resources.const_get(attributes["type"].camelize, false).new(attributes)
52
+ end
35
53
  end
36
54
 
37
55
  # @return [true, false] Flag to use SSH (default: true)
38
56
  def ssh?
39
- @raw_recipe["ssh"] != false
57
+ @recipe_data["ssh"] != false
58
+ end
59
+
60
+ def valid?
61
+ errors.empty?
40
62
  end
41
63
 
42
64
  private
43
65
 
66
+ # @return [Array<Serverkit::Errors::Base>]
67
+ def errors_for_invalid_typed_recipe_data
68
+ [Errors::InvalidRecipeType.new(@recipe_data.class)]
69
+ end
70
+
71
+ # @return [Array<Serverkit::Errors::Base>]
72
+ def errors_for_invalid_typed_resources_property
73
+ [Errors::InvalidResourcesType.new(resources_property.class)]
74
+ end
75
+
76
+ # @return [Array<Serverkit::Errors::Base>]
77
+ def errors_in_resources
78
+ resources.flat_map do |resource|
79
+ resource.validate
80
+ resource.errors.to_a
81
+ end
82
+ end
83
+
84
+ def has_valid_typed_resources_property?
85
+ resources_property.is_a?(Array)
86
+ end
87
+
88
+ def has_valid_typed_recipe_data?
89
+ @recipe_data.is_a?(Hash)
90
+ end
91
+
44
92
  # @return [Array<String>]
45
- def resource_properties
46
- @raw_recipe["resources"] || []
93
+ def resources_property
94
+ @recipe_data["resources"] || []
47
95
  end
48
96
  end
49
97
  end
@@ -1,16 +1,28 @@
1
+ require "active_model"
2
+
1
3
  module Serverkit
2
4
  module Resources
3
5
  class Base
6
+ class << self
7
+ # @note DSL method to define attribute with its validations
8
+ def attribute(name, options = {})
9
+ default = options.delete(:default)
10
+ define_method(name) do
11
+ @attributes[name.to_s] || default
12
+ end
13
+ validates name, options unless options.empty?
14
+ end
15
+ end
16
+
17
+ include ActiveModel::Validations
18
+
4
19
  attr_accessor :backend
5
20
 
6
- # @param [Hash] properties
7
- def initialize(properties)
8
- @properties = properties
9
- end
21
+ attribute :name, required: true
10
22
 
11
- # @return [String]
12
- def name
13
- @properties["name"]
23
+ # @param [Hash] attributes
24
+ def initialize(attributes)
25
+ @attributes = attributes
14
26
  end
15
27
 
16
28
  private
@@ -1,9 +1,16 @@
1
1
  require "digest"
2
+ require "readable_validator"
3
+ require "required_validator"
2
4
  require "serverkit/resources/base"
3
5
 
4
6
  module Serverkit
5
7
  module Resources
6
8
  class File < Base
9
+ attribute :destination, required: true
10
+ attribute :group
11
+ attribute :owner
12
+ attribute :source, readable: true, required: true
13
+
7
14
  def apply
8
15
  send_file if file_sendable?
9
16
  change_group unless has_valid_group?
@@ -25,20 +32,10 @@ module Serverkit
25
32
  run_command_from_identifier(:change_file_owner, destination, owner)
26
33
  end
27
34
 
28
- # @return [String]
29
- def destination
30
- @properties["destination"]
31
- end
32
-
33
35
  def file_sendable?
34
36
  !has_file? || !has_same_content?
35
37
  end
36
38
 
37
- # @return [String]
38
- def group
39
- @properties["group"]
40
- end
41
-
42
39
  def has_file?
43
40
  check_command_from_identifier(:check_file_is_file, destination)
44
41
  end
@@ -55,17 +52,11 @@ module Serverkit
55
52
  owner.nil? || check_command_from_identifier(:check_file_is_owned_by, destination, owner)
56
53
  end
57
54
 
58
- # @todo Rescue Errno::ENOENT from File.read
59
55
  # @return [String]
60
56
  def local_file_sha256sum
61
57
  ::Digest::SHA256.hexdigest(::File.read(source))
62
58
  end
63
59
 
64
- # @return [String]
65
- def owner
66
- @properties["owner"]
67
- end
68
-
69
60
  # @return [String]
70
61
  def remote_file_sha256sum
71
62
  run_command_from_identifier(:get_file_sha256sum, destination).stdout.rstrip
@@ -74,11 +65,6 @@ module Serverkit
74
65
  def send_file
75
66
  run_command_from_identifier(:send_file, source, destination)
76
67
  end
77
-
78
- # @return [String]
79
- def source
80
- @properties["source"]
81
- end
82
68
  end
83
69
  end
84
70
  end
@@ -5,6 +5,10 @@ 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
11
+
8
12
  def apply
9
13
  clone if clonable?
10
14
  update if updatable?
@@ -48,21 +52,6 @@ module Serverkit
48
52
  run_command("cd #{path} && git ls-remote origin HEAD").stdout.split.first
49
53
  end
50
54
 
51
- # @return [String] Where to locate cloned repository
52
- def path
53
- @properties["path"]
54
- end
55
-
56
- # @return [String] Git repository URL
57
- def repository
58
- @properties["repository"]
59
- end
60
-
61
- # @return [String]
62
- def status
63
- @properties["status"] || DEFAULT_STATUS
64
- end
65
-
66
55
  def updatable?
67
56
  status == "updated" && !updated?
68
57
  end
@@ -3,6 +3,8 @@ require "serverkit/resources/base"
3
3
  module Serverkit
4
4
  module Resources
5
5
  class HomebrewCask < Base
6
+ attribute :package, required: true
7
+
6
8
  def apply
7
9
  run_command("brew cask install #{package}")
8
10
  end
@@ -11,13 +13,6 @@ module Serverkit
11
13
  def check
12
14
  check_command("/usr/local/bin/brew cask list -1 | grep -E '^#{package}$'")
13
15
  end
14
-
15
- private
16
-
17
- # @return [String]
18
- def package
19
- @properties["package"]
20
- end
21
16
  end
22
17
  end
23
18
  end
@@ -3,6 +3,8 @@ require "serverkit/resources/base"
3
3
  module Serverkit
4
4
  module Resources
5
5
  class Package < Base
6
+ attribute :package, required: true
7
+
6
8
  def apply
7
9
  run_command_from_identifier(:install, package)
8
10
  end
@@ -11,13 +13,6 @@ module Serverkit
11
13
  def check
12
14
  check_command_from_identifier(:check_package_is_installed, package)
13
15
  end
14
-
15
- private
16
-
17
- # @return [String]
18
- def package
19
- @properties["package"]
20
- end
21
16
  end
22
17
  end
23
18
  end
@@ -3,6 +3,9 @@ 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
8
+
6
9
  def apply
7
10
  run_command_from_identifier(:link_file_to, source, destination)
8
11
  end
@@ -11,18 +14,6 @@ module Serverkit
11
14
  def check
12
15
  check_command_from_identifier(:check_file_is_linked_to, source, destination)
13
16
  end
14
-
15
- private
16
-
17
- # @return [String]
18
- def destination
19
- @properties["destination"]
20
- end
21
-
22
- # @return [String]
23
- def source
24
- @properties["source"]
25
- end
26
17
  end
27
18
  end
28
19
  end
@@ -1,3 +1,3 @@
1
1
  module Serverkit
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
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 building servers."
10
+ spec.summary = "Configuration management toolkit for your infrastructure."
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)/}) }
@@ -15,6 +15,7 @@ Gem::Specification.new do |spec|
15
15
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
16
  spec.require_paths = ["lib"]
17
17
 
18
+ spec.add_runtime_dependency "activemodel"
18
19
  spec.add_runtime_dependency "activesupport"
19
20
  spec.add_runtime_dependency "slop", "~> 3.4"
20
21
  spec.add_runtime_dependency "specinfra"
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serverkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
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-29 00:00:00.000000000 Z
11
+ date: 2015-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: activesupport
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -134,17 +148,24 @@ files:
134
148
  - ".rspec"
135
149
  - ".rubocop.yml"
136
150
  - ".travis.yml"
151
+ - CHANGELOG.md
137
152
  - Gemfile
138
153
  - LICENSE.txt
139
154
  - README.md
140
155
  - Rakefile
141
156
  - bin/serverkit
142
157
  - examples/recipe.yml
158
+ - lib/readable_validator.rb
159
+ - lib/required_validator.rb
143
160
  - lib/serverkit.rb
144
161
  - lib/serverkit/actions/apply.rb
145
162
  - lib/serverkit/actions/base.rb
146
163
  - lib/serverkit/actions/check.rb
164
+ - lib/serverkit/actions/validate.rb
147
165
  - lib/serverkit/command.rb
166
+ - lib/serverkit/errors/base.rb
167
+ - lib/serverkit/errors/invalid_recipe_type.rb
168
+ - lib/serverkit/errors/invalid_resources_type.rb
148
169
  - lib/serverkit/recipe.rb
149
170
  - lib/serverkit/resources/base.rb
150
171
  - lib/serverkit/resources/file.rb
@@ -178,6 +199,6 @@ rubyforge_project:
178
199
  rubygems_version: 2.4.5
179
200
  signing_key:
180
201
  specification_version: 4
181
- summary: Configuration management toolkit for building servers.
202
+ summary: Configuration management toolkit for your infrastructure.
182
203
  test_files: []
183
204
  has_rdoc: