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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e0a7546c9c6a70c5d81bd6f4caa93af7fcb21d9
4
- data.tar.gz: dabf75ee6daa3970a01581132710badf1ff27f11
3
+ metadata.gz: 27b2d14abab4ae27f1ff469bdc05ff998cf23b82
4
+ data.tar.gz: a65cda128d283f4092df23e47fbf369b2b1b7a4f
5
5
  SHA512:
6
- metadata.gz: 136c3a11b6c01f2bc47392ac5e3d58159505c7c235be1eed28967fc0e33fd27c25e4442c53014d7beb33c69955a6c951d021a171f58c4de555149a68b855abca
7
- data.tar.gz: 72794ea2047d69fd377ecfde7a00af314fc385a690db1c8faeae8661acc38d67c97878db677a9d87697b2abab9e46c53bc7f24db1a189ce2ce81ff1cd2be1548
6
+ metadata.gz: 4248c5a01785e3f72c7479f2e22d12a463232c3b7efa69e579c1a841cb64ebb362eb5e297d1fb0792feab4da61d52d075fa83ec76bc485135d004c4e502e839c
7
+ data.tar.gz: e38727d87078ff6dce24177fb2a2bfc2bc1ea2abbbdaf44acf572d701057f954bc6d60c86851367e8c3dc7b793bb06bfb0bb2a2b308da3225ce0b2cf60c9876a
data/.travis.yml CHANGED
@@ -2,3 +2,6 @@ language: ruby
2
2
  rvm:
3
3
  - 2.2.3
4
4
  before_install: gem install bundler -v 1.11.2
5
+ sudo: required
6
+ services:
7
+ - docker
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Kaigara
2
2
 
3
+ [![Build Status](https://travis-ci.org/helios-technologies/kaigara.svg?branch=master)](https://travis-ci.org/helios-technologies/kaigara) [![Gem Version](https://badge.fury.io/rb/kaigara.svg)](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
@@ -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.name}#{"/#{package.version}" if package.version}...", :yellow
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
- def self.load_variables()
4
- package = Package.new
5
- @vars = package.load!
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
- Operation.send(:define_method, k.to_sym, Proc.new {v})
8
- Operation::ThorShell.send(:define_method, k.to_sym, Proc.new {v})
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({}, cmd)
39
- @shell.say stdout.read(), :green
40
- @shell.say stderr.read(), :red
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
- raise 'Non zero result' if exit_status != 0
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
- attr_accessor :operations_dir
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
-
@@ -1,3 +1,6 @@
1
+ #
2
+ # Specification for a Package (project)
3
+ #
1
4
  class Spec
2
5
  attr_accessor :environment
3
6
  def initialize(parent)
@@ -1,4 +1,3 @@
1
-
2
1
  require 'pathname'
3
2
 
4
3
  module Kaigara
@@ -1,4 +1,8 @@
1
1
  module Kaigara
2
+
3
+ #
4
+ # Base class for all plugins
5
+ #
2
6
  class BaseController < Thor
3
7
  include Thor::Base
4
8
  include Thor::Actions
@@ -1,4 +1,7 @@
1
1
  module Kaigara
2
+ #
3
+ # Kaigara cli
4
+ #
2
5
  class Client < Thor
3
6
 
4
7
  def self.exit_on_failure?
@@ -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
@@ -1,4 +1,4 @@
1
1
  module Kaigara
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
4
4
 
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.3
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-14 00:00:00.000000000 Z
11
+ date: 2016-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor