kaigara 0.0.3 → 0.0.4

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