kaigara 0.0.3 → 0.0.4
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/.travis.yml +3 -0
- data/README.md +2 -0
- data/app/controllers/sysops.rb +24 -1
- data/app/models/sysops/environment.rb +12 -6
- data/app/models/sysops/operation.rb +101 -18
- data/app/models/sysops/package.rb +15 -2
- data/app/models/sysops/spec.rb +3 -0
- data/lib/kaigara/application.rb +0 -1
- data/lib/kaigara/base_controller.rb +4 -0
- data/lib/kaigara/client.rb +3 -0
- data/lib/kaigara/metadata.rb +17 -4
- data/lib/kaigara/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27b2d14abab4ae27f1ff469bdc05ff998cf23b82
|
4
|
+
data.tar.gz: a65cda128d283f4092df23e47fbf369b2b1b7a4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4248c5a01785e3f72c7479f2e22d12a463232c3b7efa69e579c1a841cb64ebb362eb5e297d1fb0792feab4da61d52d075fa83ec76bc485135d004c4e502e839c
|
7
|
+
data.tar.gz: e38727d87078ff6dce24177fb2a2bfc2bc1ea2abbbdaf44acf572d701057f954bc6d60c86851367e8c3dc7b793bb06bfb0bb2a2b308da3225ce0b2cf60c9876a
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Kaigara
|
2
2
|
|
3
|
+
[](https://travis-ci.org/helios-technologies/kaigara) [](https://badge.fury.io/rb/kaigara)
|
4
|
+
|
3
5
|
Kaigara is an extendable shell command line for managing simple devops tasks.
|
4
6
|
|
5
7
|
## Installation
|
data/app/controllers/sysops.rb
CHANGED
@@ -4,9 +4,20 @@ require 'models/sysops/environment'
|
|
4
4
|
require 'models/sysops/spec'
|
5
5
|
|
6
6
|
module Kaigara
|
7
|
+
|
8
|
+
#
|
9
|
+
# A plugin to manage system operations
|
10
|
+
#
|
7
11
|
class Sysops < BaseController
|
8
12
|
|
9
13
|
desc 'create NAME', 'Create a new sysops project'
|
14
|
+
#
|
15
|
+
# Creates an folder with kaigara project. It includes:
|
16
|
+
# * +operations/+ - directory for future kaigara scripts
|
17
|
+
# * +resources/+ - directory for any sources (scripts to template, etc.)
|
18
|
+
# * +metadata.rb+ - file where you should store all your variables (including environment)
|
19
|
+
# * +Vagrantfile+ - if you use Vagrant, you know what is it
|
20
|
+
#
|
10
21
|
def create(name)
|
11
22
|
package = Package.new(name)
|
12
23
|
package.name = name
|
@@ -19,18 +30,30 @@ module Kaigara
|
|
19
30
|
end
|
20
31
|
|
21
32
|
desc 'generate <name>', 'Generate a new operation'
|
33
|
+
#
|
34
|
+
# Generates new kaigara script in +operations/+ dir. You can use any ruby code in it.
|
35
|
+
#
|
22
36
|
def generate(label)
|
23
37
|
package = Package.new
|
24
38
|
package.load!
|
25
39
|
filename = File.join(package.operations_dir, package.operation_name(label))
|
26
40
|
template('operation.rb.erb', filename)
|
41
|
+
|
42
|
+
rescue Package::MetadataNotFound
|
43
|
+
say "#{package.script_path} not found", :red
|
44
|
+
say "You may want to create a new sysops project first"
|
45
|
+
exit 1
|
27
46
|
end
|
28
47
|
|
29
48
|
desc 'exec', 'Execute a package'
|
30
49
|
method_option :path, aliases: '-p', desc: 'Project path', default: '.'
|
50
|
+
#
|
51
|
+
# Executes every script in +operations/+
|
52
|
+
# <tt>-p</tt> <i>[path]</i>:: set project path
|
53
|
+
#
|
31
54
|
def exec
|
32
55
|
package = Package.new(options[:path])
|
33
|
-
say "Executing #{package.
|
56
|
+
say "Executing #{package.full_name}...", :yellow
|
34
57
|
package.load!
|
35
58
|
package.run!
|
36
59
|
end
|
@@ -1,12 +1,18 @@
|
|
1
1
|
module Kaigara
|
2
|
+
|
3
|
+
#
|
4
|
+
# This class is for managing variables and configurations.
|
5
|
+
#
|
2
6
|
class Environment
|
3
|
-
|
4
|
-
|
5
|
-
|
7
|
+
attr_accessor :vars
|
8
|
+
|
9
|
+
# Loads variables to class +op+
|
10
|
+
def self.load_variables(op)
|
11
|
+
pkg = Package.new
|
12
|
+
@vars = pkg.load!
|
6
13
|
@vars.data.each_pair do |k, v|
|
7
|
-
|
8
|
-
|
9
|
-
end unless @vars.empty?
|
14
|
+
op.instance_variable_set("@#{k}".to_sym, v)
|
15
|
+
end if @vars
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|
@@ -1,20 +1,19 @@
|
|
1
1
|
require 'open3'
|
2
2
|
|
3
3
|
module Kaigara
|
4
|
+
|
5
|
+
#
|
6
|
+
# A script that +Sysops+ executes
|
7
|
+
#
|
4
8
|
class Operation
|
9
|
+
|
10
|
+
#
|
11
|
+
# A proxy class for Thor
|
12
|
+
#
|
5
13
|
class ThorShell
|
6
14
|
include Thor::Base
|
7
15
|
include Thor::Actions
|
8
16
|
include Thor::Shell
|
9
|
-
|
10
|
-
no_commands do
|
11
|
-
def inject(opts = {})
|
12
|
-
opts.each do |k,v|
|
13
|
-
instance_eval { class << self; self end }.send(:attr_accessor, k)
|
14
|
-
send("#{k}=", v)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
17
|
end
|
19
18
|
|
20
19
|
attr_accessor :work_dir
|
@@ -25,29 +24,109 @@ module Kaigara
|
|
25
24
|
@shell = ThorShell.new
|
26
25
|
@name = File.basename(path)
|
27
26
|
@content = File.read(path)
|
27
|
+
Environment.load_variables(self) # We loads variables to both shell and operation classes.
|
28
|
+
Environment.load_variables(@shell) # So it's available from your ruby code in +operations/+ and from our DSL.
|
28
29
|
end
|
29
30
|
|
31
|
+
# Executes operation content
|
30
32
|
def apply!
|
31
33
|
@shell.say "Applying #{@name}\n--------------------", :yellow
|
32
34
|
instance_eval @content
|
33
35
|
end
|
34
36
|
|
37
|
+
# One of the most important parts of DSL. You can use it directly in your operations.
|
35
38
|
def execute(cmd)
|
36
|
-
Environment.load_variables
|
37
39
|
@shell.say "Running: #{cmd}", :yellow
|
38
|
-
stdin, stdout, stderr, wait_thr = Open3.popen3({},
|
39
|
-
|
40
|
-
|
40
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3({}, "bash -e")
|
41
|
+
stdin.puts(cmd)
|
42
|
+
Thread.new do
|
43
|
+
stdout.each { |l| @shell.say(l, :green) }
|
44
|
+
end
|
45
|
+
Thread.new do
|
46
|
+
stderr.each { |l| @shell.say(l, :red) }
|
47
|
+
end
|
41
48
|
stdin.close
|
42
|
-
stdout.close
|
43
|
-
stderr.close
|
44
49
|
|
45
|
-
exit_status = wait_thr.value
|
46
|
-
|
50
|
+
exit_status = wait_thr.value.exitstatus
|
51
|
+
if exit_status != 0
|
52
|
+
raise "Command `#{ cmd }` returned status code #{ exit_status }"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Return true if the `file` exists? and the content matches the `match`
|
58
|
+
# If a block is given it's executed if the statement is true
|
59
|
+
#
|
60
|
+
def file_matches?(file, match)
|
61
|
+
if File.exists?(file)
|
62
|
+
if File.read(file).match(match)
|
63
|
+
yield if block_given?
|
64
|
+
return true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Return true if the OS is Ubuntu or Debian
|
72
|
+
# If a block is given it's executed if the statement is true
|
73
|
+
#
|
74
|
+
def debian_family?
|
75
|
+
file_matches?("/etc/issue", /Ubuntu|Debian/i) do
|
76
|
+
yield if block_given?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Return true if the OS is CentOS or RedHat
|
82
|
+
# If a block is given it's executed if the statement is true
|
83
|
+
#
|
84
|
+
def redhat_family?
|
85
|
+
file_matches?("/etc/redhat-release", /CentOS|Red Hat/i) do
|
86
|
+
yield if block_given?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Add common additional repositories
|
92
|
+
#
|
93
|
+
def repo_extended
|
94
|
+
redhat_family? do
|
95
|
+
package("epel-release")
|
96
|
+
package_update
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Update the local repository cache
|
102
|
+
#
|
103
|
+
def package_update
|
104
|
+
if debian_family?
|
105
|
+
execute("apt-get update")
|
106
|
+
elsif redhat_family?
|
107
|
+
execute("yum update")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Install the package depending on OS
|
113
|
+
#
|
114
|
+
def package(name, version = nil)
|
115
|
+
if debian_family?
|
116
|
+
execute("apt-get install -y #{ name }")
|
117
|
+
elsif redhat_family?
|
118
|
+
execute("yum install -y #{ name }")
|
119
|
+
else
|
120
|
+
raise "OS not supported"
|
121
|
+
end
|
47
122
|
end
|
48
123
|
|
124
|
+
#
|
125
|
+
# Templates ERB template. You can use variables from metadata.rb in your templates.
|
126
|
+
# <tt>name</tt> - template name, without '.erb'
|
127
|
+
# <tt>-p</tt> - destination file. If you don't use it, the file renders to +/path-in-resources/+
|
128
|
+
#
|
49
129
|
def template(name, target = nil)
|
50
|
-
Environment.load_variables
|
51
130
|
tpl_file = name + '.erb'
|
52
131
|
destination = target
|
53
132
|
destination = "/#{tpl_file}" if destination.nil?
|
@@ -60,6 +139,10 @@ module Kaigara
|
|
60
139
|
return destination
|
61
140
|
end
|
62
141
|
|
142
|
+
#
|
143
|
+
# Renders a template, then executes the script.
|
144
|
+
# You should add shebang to your script.
|
145
|
+
#
|
63
146
|
def script(name, path = nil)
|
64
147
|
target = template(name, File.join( (path.nil? ? "" : path), name))
|
65
148
|
@shell.chmod(target, 0755)
|
@@ -1,18 +1,27 @@
|
|
1
1
|
module Kaigara
|
2
2
|
class Package
|
3
3
|
|
4
|
+
#
|
5
|
+
# The base project files and directories
|
6
|
+
#
|
4
7
|
METADATA_FILE_NAME = 'metadata.rb'
|
5
8
|
VAGRANT_FILE_NAME = 'Vagrantfile'
|
6
9
|
OPERATIONS_DIR_NAME = 'operations'
|
7
10
|
RESOURCES_DIR_NAME = 'resources'
|
8
11
|
|
12
|
+
# Project directory
|
9
13
|
attr_accessor :work_dir
|
10
|
-
|
14
|
+
|
15
|
+
# metadata.rb path
|
11
16
|
attr_accessor :script_path
|
17
|
+
|
18
|
+
attr_accessor :operations_dir
|
12
19
|
attr_accessor :dependencies
|
13
20
|
attr_accessor :version
|
14
21
|
attr_accessor :name
|
15
22
|
|
23
|
+
class MetadataNotFound < RuntimeError; end
|
24
|
+
|
16
25
|
def initialize(path = '.')
|
17
26
|
@options = {}
|
18
27
|
@work_dir = path ? File.expand_path(path) : '.'
|
@@ -22,8 +31,13 @@ module Kaigara
|
|
22
31
|
@spec = Spec.new(self)
|
23
32
|
end
|
24
33
|
|
34
|
+
def full_name
|
35
|
+
@full_name ||= [name, version].compact.join("/")
|
36
|
+
end
|
37
|
+
|
25
38
|
# Read and execute metadata.rb
|
26
39
|
def load!
|
40
|
+
raise MetadataNotFound.new unless File.exist?(@script_path)
|
27
41
|
script = File.read(@script_path)
|
28
42
|
@spec.instance_eval(script)
|
29
43
|
end
|
@@ -49,4 +63,3 @@ module Kaigara
|
|
49
63
|
end
|
50
64
|
end
|
51
65
|
end
|
52
|
-
|
data/app/models/sysops/spec.rb
CHANGED
data/lib/kaigara/application.rb
CHANGED
data/lib/kaigara/client.rb
CHANGED
data/lib/kaigara/metadata.rb
CHANGED
@@ -4,7 +4,13 @@ require 'ostruct'
|
|
4
4
|
module Kaigara
|
5
5
|
class Metadata
|
6
6
|
|
7
|
+
#
|
8
|
+
# Storage for nested hashes
|
9
|
+
#
|
7
10
|
class DeepHash < Hash
|
11
|
+
#
|
12
|
+
# Add new variable to a hash, even if it's in nested one.
|
13
|
+
#
|
8
14
|
def method_missing(name, *args, &block)
|
9
15
|
if name[-1] == '='
|
10
16
|
key = name[0...-1]
|
@@ -19,15 +25,22 @@ module Kaigara
|
|
19
25
|
end
|
20
26
|
end
|
21
27
|
|
28
|
+
# Here are all variables from metadata.rb
|
22
29
|
attr_reader :data
|
23
30
|
|
31
|
+
#
|
32
|
+
# You can see how it works in +metadata.rb+
|
33
|
+
#
|
24
34
|
def initialize(&block)
|
25
|
-
hash = DeepHash.new
|
26
|
-
block.call(hash)
|
27
|
-
json = hash.to_json
|
28
|
-
@data = JSON.parse(json, object_class: OpenStruct)
|
35
|
+
hash = DeepHash.new # Here's a hook that changes variables storage class.
|
36
|
+
block.call(hash) # We're passing this hash to initialize block (see metadata.rb example)
|
37
|
+
json = hash.to_json # Then we changes the type of it to json, then to OpenStruct.
|
38
|
+
@data = JSON.parse(json, object_class: OpenStruct) # Now we can use any variable as @var.l1.l2.l3.l4.l5 and so on
|
29
39
|
end
|
30
40
|
|
41
|
+
#
|
42
|
+
# Returns a variable from @data
|
43
|
+
#
|
31
44
|
def method_missing(name, *args, &block)
|
32
45
|
return @data.send(name)
|
33
46
|
end
|
data/lib/kaigara/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kaigara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Helios Technologies
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|