jisota 0.0.1 → 0.0.2
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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +21 -0
- data/README.md +106 -2
- data/Rakefile +10 -0
- data/jisota.gemspec +1 -0
- data/lib/jisota.rb +4 -2
- data/lib/jisota/collection.rb +2 -4
- data/lib/jisota/command_script.rb +3 -2
- data/lib/jisota/composite_script.rb +2 -2
- data/lib/jisota/configuration.rb +3 -3
- data/lib/jisota/dsl_base.rb +12 -0
- data/lib/jisota/file_script.rb +107 -9
- data/lib/jisota/nil_output.rb +14 -0
- data/lib/jisota/{logger.rb → output.rb} +16 -35
- data/lib/jisota/package.rb +2 -2
- data/lib/jisota/package_script.rb +28 -20
- data/lib/jisota/packages/gem_install.rb +17 -0
- data/lib/jisota/packages/nginx_passenger.rb +34 -0
- data/lib/jisota/packages/ruby.rb +2 -2
- data/lib/jisota/param_parser.rb +30 -19
- data/lib/jisota/provisioner.rb +7 -3
- data/lib/jisota/script_block.rb +13 -14
- data/lib/jisota/script_context.rb +24 -0
- data/lib/jisota/server.rb +2 -1
- data/lib/jisota/ssh_engine.rb +6 -2
- data/lib/jisota/ssh_session.rb +10 -15
- data/lib/jisota/version.rb +1 -1
- data/package_files/nginx_passenger/nginx_service +65 -0
- data/spec/acceptance/ruby_passenger_nginx_spec.rb +24 -0
- data/spec/acceptance/simple_script_spec.rb +8 -24
- data/spec/acceptance/upload_blocks_spec.rb +34 -0
- data/spec/lib/jisota/collection_spec.rb +10 -0
- data/spec/lib/jisota/command_script_spec.rb +4 -3
- data/spec/lib/jisota/composite_script_spec.rb +8 -6
- data/spec/lib/jisota/configuration_spec.rb +1 -3
- data/spec/lib/jisota/dsl_base_spec.rb +37 -0
- data/spec/lib/jisota/file_script_spec.rb +63 -8
- data/spec/lib/jisota/output_spec.rb +84 -0
- data/spec/lib/jisota/package_script_spec.rb +20 -8
- data/spec/lib/jisota/package_spec.rb +2 -6
- data/spec/lib/jisota/packages/apt_spec.rb +7 -4
- data/spec/lib/jisota/packages/gem_install_spec.rb +18 -0
- data/spec/lib/jisota/packages/nginx_passenger_spec.rb +17 -0
- data/spec/lib/jisota/packages/ruby_spec.rb +6 -3
- data/spec/lib/jisota/param_parser_spec.rb +105 -0
- data/spec/lib/jisota/provisioner_spec.rb +30 -0
- data/spec/lib/jisota/role_spec.rb +1 -3
- data/spec/lib/jisota/script_block_spec.rb +7 -4
- data/spec/lib/jisota/ssh_engine_spec.rb +26 -0
- data/spec/lib/jisota/ssh_session_spec.rb +53 -0
- data/spec/spec_helper.rb +11 -1
- data/spec/support/acceptance_helpers.rb +45 -0
- data/spec/test_files/nginx_default.conf +121 -0
- data/spec/vagrant/Vagrantfile +118 -0
- data/spec/vagrant/ssh_key +27 -0
- metadata +55 -7
- data/lib/jisota/upload_file.rb +0 -3
- data/spec/lib/jisota/logger_spec.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d30b81b24cc0fc7e8bb04cc88f243fc83983dd25
|
4
|
+
data.tar.gz: 5b94aabed9dcb6f17c89e03bd2092d73d79067ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d75af1889780c695a60813c9fd8613f60ca0149151e24d39f5ebbdb27ae172eb797c5c570fd92fee1f5de4d877a466ca3079b9affc477ee241ca16168710269
|
7
|
+
data.tar.gz: 6ad96e33cbd4c23b673d075b1b6efd8944218ba7cb2c28756a692d5151c45265f67018b3ebc661bfbc0285a7169544c0c92cef1197a0ece52c51475f05363e4f
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Jisota changelog
|
2
|
+
|
3
|
+
## 0.0.2 (current)
|
4
|
+
|
5
|
+
### Features
|
6
|
+
* Create and Update actions on file upload
|
7
|
+
* Params have scope of the entire package, allowing e.g. upload action blocks to access package params
|
8
|
+
* Can now specify a private ssh key to use
|
9
|
+
|
10
|
+
### Improvements
|
11
|
+
* Better DSL blocks.
|
12
|
+
* Stuff parsed from script to script are now wrapped in a ScriptContext object
|
13
|
+
* Fixed ruby package by ensuring build-essential is installed
|
14
|
+
* Runs acceptance tests inside a vagrant
|
15
|
+
|
16
|
+
### Packages
|
17
|
+
* gem_install
|
18
|
+
* nginx_passenger
|
19
|
+
|
20
|
+
## 0.0.1
|
21
|
+
Initial version with basic functionality
|
data/README.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
[](http://badge.fury.io/rb/jisota)
|
2
|
+
[](https://codeclimate.com/github/lasseebert/jisota)
|
3
|
+
[](https://codeclimate.com/github/lasseebert/jisota)
|
4
|
+
[](https://travis-ci.org/lasseebert/jisota)
|
5
|
+
[](https://gemnasium.com/lasseebert/jisota)
|
6
|
+
|
1
7
|
# Jisota
|
2
8
|
|
3
9
|
Jisota is a simple provisioning tool meant for smaller projects.
|
@@ -5,6 +11,8 @@ Jisota is a simple provisioning tool meant for smaller projects.
|
|
5
11
|
Provisioning, in this context, is the act of turning an empty server
|
6
12
|
into a working machine tailored to your needs.
|
7
13
|
|
14
|
+
***Note: Jisota is still considered unstable. Breaking changes may occur in patch version updates.***
|
15
|
+
|
8
16
|
## Installation
|
9
17
|
|
10
18
|
Add this line to your application's Gemfile:
|
@@ -41,6 +49,10 @@ Run the script with the ruby executable:
|
|
41
49
|
|
42
50
|
$ ruby config/provision.rb
|
43
51
|
|
52
|
+
## Ruby version
|
53
|
+
|
54
|
+
Jisota is cutting edge and requires Ruby 2.1.0 or later.
|
55
|
+
|
44
56
|
## Defining a package
|
45
57
|
|
46
58
|
Inside a `Jisota.config` block, use the `package` method to define a package.
|
@@ -133,6 +145,15 @@ Example:
|
|
133
145
|
apt :vim, :git, command: "sudo apt-get install -y :package"
|
134
146
|
end
|
135
147
|
|
148
|
+
## Defining a server
|
149
|
+
|
150
|
+
A server needs at least a host, a user and a role:
|
151
|
+
|
152
|
+
server "mydomain.com", user: "john", roles: :app
|
153
|
+
|
154
|
+
Other options:
|
155
|
+
|
156
|
+
* `key`: File path to ssh private key
|
136
157
|
|
137
158
|
## Atomic script operations
|
138
159
|
|
@@ -151,6 +172,43 @@ Uploads the file to the server. Example:
|
|
151
172
|
|
152
173
|
upload from: "path/to/nginx.conf", to: "/etc/nginx.conf"
|
153
174
|
|
175
|
+
You can register script blocks to be called if the file was created or updated.
|
176
|
+
If the file on the server is identical with the uploaded file, no action is
|
177
|
+
done and the file will not be overwritten.
|
178
|
+
|
179
|
+
upload from: "foo", to: "bar" do
|
180
|
+
create { cmd 'echo "File was created!"' }
|
181
|
+
update { cmd 'echo "File was updated!"' }
|
182
|
+
end
|
183
|
+
|
184
|
+
You can disable creation or update of the file:
|
185
|
+
|
186
|
+
upload from: "foo", to: "bar" do
|
187
|
+
create false # Only update is allowed. File will not be created if it does not exists
|
188
|
+
end
|
189
|
+
|
190
|
+
- OR -
|
191
|
+
|
192
|
+
upload from: "foo", to: "bar", create: false
|
193
|
+
|
194
|
+
You can also use package params and call packages inside these blocks:
|
195
|
+
|
196
|
+
package :nginx_config do
|
197
|
+
param :config_file, require: true
|
198
|
+
run do
|
199
|
+
upload from: config_file, to: "/etc/nginx.conf" do
|
200
|
+
update do
|
201
|
+
cmd %q{echo "#{config_file} was updated. Restarting nginx..."}
|
202
|
+
nginx_restart
|
203
|
+
end
|
204
|
+
create do
|
205
|
+
cmd %q{echo "#{config_file} was started. Starting nginx..."}
|
206
|
+
nginx_start
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
154
212
|
## Complete list of build-in packages
|
155
213
|
|
156
214
|
### ruby
|
@@ -164,6 +222,17 @@ Uploads the file to the server. Example:
|
|
164
222
|
description "Installs packages with apt-get"
|
165
223
|
param :packages, required: true, splat: true
|
166
224
|
|
225
|
+
### gem_install
|
226
|
+
|
227
|
+
description "Installs a gem"
|
228
|
+
param :gem_name, required: true
|
229
|
+
param :sudo, default: true
|
230
|
+
|
231
|
+
### nginx_passenger
|
232
|
+
|
233
|
+
description "Install nginx with passenger module"
|
234
|
+
param :config_file, required: true
|
235
|
+
|
167
236
|
### More packages?
|
168
237
|
|
169
238
|
Jisota is a young gem. Please contribute with any packages that you think
|
@@ -193,7 +262,11 @@ is equivalent to:
|
|
193
262
|
|
194
263
|
## Full example
|
195
264
|
|
196
|
-
An example using most of the features of Jisota
|
265
|
+
An example using most of the features of Jisota.
|
266
|
+
|
267
|
+
Note: This was not tested and probably won't make sense in a real application.
|
268
|
+
This is just meant to show some features. A good place to look for examples are
|
269
|
+
in the build-in packages
|
197
270
|
|
198
271
|
require 'jisota'
|
199
272
|
|
@@ -220,7 +293,10 @@ An example using most of the features of Jisota:
|
|
220
293
|
param :config_file, required: true
|
221
294
|
run do
|
222
295
|
cmd "sudo apt get install nginx"
|
223
|
-
upload from: config_file, to: /etc/nginx.conf
|
296
|
+
upload from: config_file, to: /etc/nginx.conf do
|
297
|
+
update { cmd "sudo service nginx restart" }
|
298
|
+
create { cmd "sudo service nginx start" }
|
299
|
+
end
|
224
300
|
end
|
225
301
|
end
|
226
302
|
|
@@ -243,6 +319,34 @@ An example using most of the features of Jisota:
|
|
243
319
|
|
244
320
|
Jisota.run(config)
|
245
321
|
|
322
|
+
## Testing
|
323
|
+
|
324
|
+
### Unit tests
|
325
|
+
|
326
|
+
Run with `rake`
|
327
|
+
|
328
|
+
### Acceptance tests
|
329
|
+
|
330
|
+
Acceptance tests are not meant to be run regularly. Some of them might take a
|
331
|
+
long time to finish. They are a way to run Jisota and the build-in packages in
|
332
|
+
a near-real environment that is easy to destroy and rebuild.
|
333
|
+
|
334
|
+
Start the vagrant:
|
335
|
+
|
336
|
+
$ (cd spec/vagrant && vagrant up)
|
337
|
+
|
338
|
+
Then run acceptance specs
|
339
|
+
|
340
|
+
$ rake spec:acceptance
|
341
|
+
|
342
|
+
Or run individual specs. Some of them might take a while:
|
343
|
+
|
344
|
+
$ rspec --tag type:acceptance spec/acceptance/some_spec.rb
|
345
|
+
|
346
|
+
To kill vagrant and start with a fresh machine:
|
347
|
+
|
348
|
+
$ (cd spec/vagrant && vagrant destroy --force && vagrant up)
|
349
|
+
|
246
350
|
## Contributing
|
247
351
|
|
248
352
|
Any pull requests, suggestions, bug reports and feedback are most welcome :)
|
data/Rakefile
CHANGED
data/jisota.gemspec
CHANGED
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency "byebug"
|
28
28
|
spec.add_development_dependency "rspec", "~> 3.0.0.beta2"
|
29
29
|
spec.add_development_dependency "guard-rspec", "~> 4.2.8"
|
30
|
+
spec.add_development_dependency "codeclimate-test-reporter"
|
30
31
|
end
|
data/lib/jisota.rb
CHANGED
@@ -5,11 +5,11 @@ module Jisota
|
|
5
5
|
#
|
6
6
|
# Options allow default depenedencies to be overridden. Example:
|
7
7
|
#
|
8
|
-
# Jisota.run(config, logger: Jisota::
|
8
|
+
# Jisota.run(config, logger: Jisota::Output.new(verbose: true))
|
9
9
|
#
|
10
10
|
def self.run(configuration, options = {})
|
11
11
|
provisioner = options.fetch(:provisioner) { Provisioner.new }
|
12
|
-
logger = options.fetch(:logger) {
|
12
|
+
logger = options.fetch(:logger) { Output.new }
|
13
13
|
provisioner.run(configuration, logger)
|
14
14
|
end
|
15
15
|
|
@@ -59,5 +59,7 @@ module Jisota
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
require_relative 'jisota/dsl_base'
|
63
|
+
require_relative 'jisota/output'
|
62
64
|
Dir[File.expand_path("../jisota/*.rb", __FILE__)].each { |file| require file }
|
63
65
|
Dir[File.expand_path("../jisota/packages/*.rb", __FILE__)].each { |file| require file }
|
data/lib/jisota/collection.rb
CHANGED
@@ -12,9 +12,9 @@ module Jisota
|
|
12
12
|
@scripts = []
|
13
13
|
end
|
14
14
|
|
15
|
-
def execute(
|
15
|
+
def execute(context)
|
16
16
|
scripts.each do |inner|
|
17
|
-
result = inner.execute(
|
17
|
+
result = inner.execute(context)
|
18
18
|
return false unless result
|
19
19
|
end
|
20
20
|
true
|
data/lib/jisota/configuration.rb
CHANGED
@@ -11,8 +11,8 @@ module Jisota
|
|
11
11
|
@packages = options.fetch(:packages) { Collection.new }
|
12
12
|
@roles = options.fetch(:role) { Collection.new }
|
13
13
|
@servers = options.fetch(:servers) { [] }
|
14
|
-
@ssh_engine = options.fetch(:ssh_engine) { SSHEngine }
|
15
|
-
DSL.new(self).
|
14
|
+
@ssh_engine = options.fetch(:ssh_engine) { SSHEngine.new }
|
15
|
+
DSL.new(self).evaluate(&block) if block_given?
|
16
16
|
end
|
17
17
|
|
18
18
|
def add_package(package)
|
@@ -39,7 +39,7 @@ module Jisota
|
|
39
39
|
servers.each(&block)
|
40
40
|
end
|
41
41
|
|
42
|
-
class DSL
|
42
|
+
class DSL < DSLBase
|
43
43
|
def initialize(target)
|
44
44
|
@target = target
|
45
45
|
end
|
data/lib/jisota/file_script.rb
CHANGED
@@ -1,21 +1,119 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
module Jisota
|
2
4
|
##
|
3
5
|
# Part of the Script duck type
|
4
6
|
#
|
5
7
|
# Uploads a file on execution
|
6
8
|
class FileScript
|
7
|
-
attr_accessor :
|
9
|
+
attr_accessor :from, :to, :create, :update
|
10
|
+
|
11
|
+
def initialize(from: , to: , create: true, update: true, &block)
|
12
|
+
@from = from
|
13
|
+
@to = to
|
14
|
+
@create = create
|
15
|
+
@update = update
|
16
|
+
if block_given?
|
17
|
+
dsl = DSL.new(self)
|
18
|
+
dsl.evaluate(&block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute(context)
|
23
|
+
Executor.new(script: self, context: context).run
|
24
|
+
end
|
25
|
+
|
26
|
+
class DSL < DSLBase
|
27
|
+
def initialize(target)
|
28
|
+
@target = target
|
29
|
+
end
|
30
|
+
|
31
|
+
def create(value = nil, &block)
|
32
|
+
set_callback(:create=, value, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def update(value = nil, &block)
|
36
|
+
set_callback(:update=, value, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
8
40
|
|
9
|
-
|
10
|
-
|
41
|
+
def set_callback(method, value, &block)
|
42
|
+
raise "Can not use both a value and block on create or update" if !value.nil? && block_given?
|
43
|
+
if value.nil?
|
44
|
+
@target.send(method, ScriptBlock.new(&block))
|
45
|
+
else
|
46
|
+
@target.send(method, value)
|
47
|
+
end
|
48
|
+
end
|
11
49
|
end
|
12
50
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
51
|
+
class Executor
|
52
|
+
extend Forwardable
|
53
|
+
attr_reader :script, :context
|
54
|
+
def_delegators :script, :from, :to, :create, :update
|
55
|
+
def_delegators :context, :ssh_session, :logger
|
56
|
+
|
57
|
+
def initialize(script: , context: )
|
58
|
+
@script = script
|
59
|
+
@context = context
|
60
|
+
end
|
61
|
+
|
62
|
+
def tmp_file
|
63
|
+
@tmp_file ||= "#{tmp_dir}/#{SecureRandom.hex}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def tmp_dir
|
67
|
+
"tmp/jisota"
|
68
|
+
end
|
69
|
+
|
70
|
+
def run
|
71
|
+
logger.system_message("File #{from} -> #{to}") do
|
72
|
+
make_temp_dir
|
73
|
+
upload
|
74
|
+
handle_file_move
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def make_temp_dir
|
79
|
+
ssh_session.command("mkdir -p #{tmp_dir}", logger)
|
80
|
+
end
|
81
|
+
|
82
|
+
def upload
|
83
|
+
logger.system_message("Uploading #{from} -> #{tmp_file}")
|
84
|
+
ssh_session.upload(from: from, to: tmp_file)
|
85
|
+
end
|
86
|
+
|
87
|
+
def handle_file_move
|
88
|
+
result = ssh_session.command("cmp -s #{tmp_file} #{to}")
|
89
|
+
case result
|
90
|
+
when 0 then same_file
|
91
|
+
when 1 then move_with_callback(update, "File exists and update is not allowed. Skipping.")
|
92
|
+
when 2 then move_with_callback(create, "File does not exist and create is not allowed. Skipping.")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def same_file
|
97
|
+
logger.system_message("Files are the same. Skipping move.")
|
98
|
+
true
|
99
|
+
end
|
100
|
+
|
101
|
+
def move_with_callback(callback, callback_not_found_message)
|
102
|
+
if callback
|
103
|
+
result = ssh_session.command("sudo mkdir -p `dirname #{to}` && sudo mv #{tmp_file} #{to}", logger)
|
104
|
+
if result == 0
|
105
|
+
if callback.is_a?(ScriptBlock)
|
106
|
+
callback_script = callback.evaluate(context)
|
107
|
+
callback_script.execute(context)
|
108
|
+
else
|
109
|
+
true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
else
|
113
|
+
logger.system_message(callback_not_found_message)
|
114
|
+
true
|
115
|
+
end
|
116
|
+
end
|
19
117
|
end
|
20
118
|
end
|
21
119
|
end
|