ztk 0.3.1 → 1.0.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,41 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ module ZTK::DSL::Core
22
+ module IO
23
+
24
+ def self.included(base)
25
+ base.class_eval do
26
+ base.send(:extend, ZTK::DSL::Core::IO::ClassMethods)
27
+ end
28
+ end
29
+
30
+ module ClassMethods
31
+
32
+ def load(rb_file)
33
+ new do
34
+ instance_eval(::IO.read(rb_file))
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,135 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ module ZTK::DSL::Core::Relations
22
+ module BelongsTo
23
+
24
+ def self.included(base)
25
+ base.class_eval do
26
+ base.add_relation(:belongs_to)
27
+ base.send(:extend, ZTK::DSL::Core::Relations::BelongsTo::ClassMethods)
28
+ end
29
+ end
30
+
31
+ def belongs_to_references
32
+ @belongs_to_references ||= {}
33
+ end
34
+
35
+ def get_belongs_to_reference(key)
36
+ logger.debug { "key(#{key})" }
37
+
38
+ if belongs_to_references.key?(key)
39
+ logger.debug { "found key -> (#{key})" }
40
+
41
+ belongs_to_references[key]
42
+ else
43
+ logger.debug { "looking up key -> (#{key})" }
44
+
45
+ key_id = send("#{key}_id")
46
+ item = key.to_s.classify.constantize.find(key_id).first
47
+ belongs_to_references[key] = item
48
+ end
49
+ end
50
+
51
+ def set_belongs_to_reference(key, value)
52
+ logger.debug { "key(#{key}), value(#{value})" }
53
+
54
+ belongs_to_references[key] = value
55
+ attributes.merge!("#{key}_id".to_sym => value.id)
56
+
57
+ klass = self.class.to_s.demodulize.downcase.pluralize
58
+ logger.debug { "send(#{klass})" }
59
+ many = value.send(klass)
60
+ many << self
61
+ many.uniq!
62
+ end
63
+
64
+ def save_belongs_to_references
65
+ belongs_to_references.each do |key, dataset|
66
+ dataset.each do |data|
67
+ # do something to store the data somewhere
68
+ end
69
+ end
70
+ end
71
+
72
+ module ClassMethods
73
+
74
+ def belongs_to(key, options={})
75
+ belongs_to_relations[key] = {
76
+ :class_name => key.to_s.classify,
77
+ :key => key
78
+ }.merge(options)
79
+ logger.debug { "key(#{key.inspect}), options(#{belongs_to_relations[key].inspect})" }
80
+
81
+ define_method(key) do |*args|
82
+ logger.debug { "*args(#{args.inspect})" }
83
+
84
+ if args.count == 0
85
+ get_belongs_to_reference(key)
86
+ else
87
+ send("#{key}=", *args)
88
+ end
89
+ end
90
+
91
+ define_method("#{key}=") do |value|
92
+ logger.debug { "#{key}= value(#{value.inspect})" }
93
+
94
+ set_belongs_to_reference(key, value)
95
+ end
96
+
97
+ define_method("#{key}_id") do |*args|
98
+ logger.debug { "#{key}_id *args(#{args.inspect})" }
99
+
100
+ if args.count == 0
101
+ attributes["#{key}_id".to_sym]
102
+ else
103
+ send("#{key}_id=".to_sym, args.first)
104
+ end
105
+
106
+ end
107
+
108
+ define_method("#{key}_id=") do |value|
109
+ options = self.class.belongs_to_relations[key]
110
+ logger.debug { "#{key}_id= value(#{value.inspect}), options(#{options.inspect})" }
111
+
112
+ if value != attributes["#{key}_id".to_sym]
113
+ item = options[:class_name].constantize.find(value).first
114
+ set_belongs_to_reference(key, item)
115
+ else
116
+ value
117
+ end
118
+ end
119
+
120
+ # define_method(singularize(key)) do |value|
121
+ # set_belongs_to_reference(key, value)
122
+ # end
123
+
124
+ # define_method(singularize(key)) do |&block|
125
+ # puts get_belongs_to_reference(key).inspect
126
+ # data = constantize(classify(key.to_s)).new(&block)
127
+ # get_belongs_to_reference(key) << data
128
+ # data
129
+ # end
130
+ end
131
+
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,105 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ module ZTK::DSL::Core::Relations
22
+ module HasMany
23
+
24
+ def self.included(base)
25
+ base.class_eval do
26
+ base.add_relation(:has_many)
27
+ base.send(:extend, ZTK::DSL::Core::Relations::HasMany::ClassMethods)
28
+ end
29
+ end
30
+
31
+ def has_many_references
32
+ @has_many_references ||= {}
33
+ end
34
+
35
+ def get_has_many_reference(key)
36
+ logger.debug { "key(#{key})" }
37
+
38
+ if has_many_references.key?(key)
39
+ logger.debug { "found key -> (#{key})" }
40
+
41
+ has_many_references[key]
42
+ else
43
+ logger.debug { "looking up key -> (#{key})" }
44
+
45
+ has_many_references[key] ||= []
46
+ end
47
+ end
48
+
49
+ def set_has_many_reference(key, value)
50
+ logger.debug { "key(#{key}), value(#{value})" }
51
+
52
+ dataset = get_has_many_reference(key)
53
+ dataset.clear
54
+ dataset.concat(value)
55
+ end
56
+
57
+ def save_has_many_references
58
+ has_many_references.each do |key, dataset|
59
+ dataset.each do |data|
60
+ # do something to store the data somewhere
61
+ end
62
+ end
63
+ end
64
+
65
+ module ClassMethods
66
+
67
+ def has_many(key, options={})
68
+ has_many_relations[key] = {
69
+ :class_name => key.to_s.classify,
70
+ :key => key
71
+ }.merge(options)
72
+ logger.debug { "key(#{key.inspect}), options(#{has_many_relations[key].inspect})" }
73
+
74
+ define_method(key) do |*args|
75
+ logger.debug { "#{key} *args(#{args.inspect})" }
76
+
77
+ if args.count == 0
78
+ get_has_many_reference(key)
79
+ else
80
+ send("#{key}=", *args)
81
+ end
82
+ end
83
+
84
+ define_method("#{key}=") do |value|
85
+ logger.debug { "#{key}= value(#{value.inspect})" }
86
+
87
+ set_has_many_reference(key, value)
88
+ end
89
+
90
+ define_method(key.to_s.singularize) do |&block|
91
+ options = self.class.has_many_relations[key]
92
+ logger.debug { "#{key.to_s.singularize} block(#{block.inspect}), options(#{options.inspect})" }
93
+ data = options[:class_name].constantize.new(&block)
94
+ get_has_many_reference(key) << data
95
+ klass = self.class.to_s.demodulize.singularize.downcase
96
+ logger.debug { "send(#{klass})" }
97
+ data.send("#{klass}=", self)
98
+ data
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,45 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ module ZTK::DSL::Core
22
+ module Relations
23
+ autoload :BelongsTo, "ztk/dsl/core/relations/belongs_to"
24
+ autoload :HasMany, "ztk/dsl/core/relations/has_many"
25
+
26
+ def self.included(base)
27
+ base.class_eval do
28
+ base.send(:extend, ZTK::DSL::Core::Relations::ClassMethods)
29
+ base.send(:include, ZTK::DSL::Core::Relations::BelongsTo)
30
+ base.send(:include, ZTK::DSL::Core::Relations::HasMany)
31
+ end
32
+ end
33
+
34
+ module ClassMethods
35
+
36
+ def add_relation(key)
37
+ relation_key = "#{key}_relations"
38
+ cattr_accessor relation_key
39
+ send(relation_key) || send("#{relation_key}=", {})
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,77 @@
1
+ module ZTK::DSL
2
+ module Core
3
+ autoload :Attributes, "ztk/dsl/core/attributes"
4
+ autoload :Actions, "ztk/dsl/core/actions"
5
+ autoload :Dataset, "ztk/dsl/core/dataset"
6
+ autoload :IO, "ztk/dsl/core/io"
7
+ autoload :Relations, "ztk/dsl/core/relations"
8
+
9
+ def self.included(base)
10
+ base.class_eval do
11
+ base.send(:extend, ZTK::DSL::Core::ClassMethods)
12
+
13
+ base.send(:extend, ZTK::DSL::Core::DualMethods)
14
+ base.send(:include, ZTK::DSL::Core::DualMethods)
15
+
16
+ base.send(:include, ZTK::DSL::Core::Attributes)
17
+ base.send(:include, ZTK::DSL::Core::Actions)
18
+ base.send(:include, ZTK::DSL::Core::Dataset)
19
+ base.send(:include, ZTK::DSL::Core::IO)
20
+ base.send(:include, ZTK::DSL::Core::Relations)
21
+ end
22
+ end
23
+
24
+ module DualMethods
25
+
26
+ def logger
27
+ unless defined?($logger)
28
+ $logger = ::ZTK::Logger.new("dsl.log")
29
+ $logger.info {"=" * 80}
30
+ $logger.info {"=" * 80}
31
+ $logger.info {"=" * 80}
32
+ end
33
+ $logger
34
+ end
35
+
36
+ end
37
+
38
+ module ClassMethods
39
+
40
+ def cattr_accessor(*args)
41
+ cattr_reader(*args)
42
+ cattr_writer(*args)
43
+ end
44
+
45
+ def cattr_reader(*args)
46
+ args.flatten.each do |arg|
47
+ next if arg.is_a?(Hash)
48
+ instance_eval %Q{
49
+ unless defined?(@@#{arg})
50
+ @@#{arg} = nil
51
+ end
52
+
53
+ def #{arg}
54
+ @@#{arg}
55
+ end
56
+ }
57
+ end
58
+ end
59
+
60
+ def cattr_writer(*args)
61
+ args.flatten.each do |arg|
62
+ next if arg.is_a?(Hash)
63
+ instance_eval %Q{
64
+ unless defined?(@@#{arg})
65
+ @@#{arg} = nil
66
+ end
67
+
68
+ def #{arg}=(value)
69
+ @@#{arg} = value
70
+ end
71
+ }
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+ end
data/lib/ztk/dsl.rb ADDED
@@ -0,0 +1,34 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ require "active_support/inflector"
22
+
23
+ # @author Zachary Patten <zachary@jovelabs.net>
24
+ module ZTK
25
+ module DSL
26
+
27
+ # @author Zachary Patten <zachary@jovelabs.net>
28
+ class DSLError < Error; end
29
+
30
+ autoload :Base, "ztk/dsl/base"
31
+ autoload :Core, "ztk/dsl/core"
32
+
33
+ end
34
+ end
data/lib/ztk/logger.rb CHANGED
@@ -17,7 +17,6 @@
17
17
  # limitations under the License.
18
18
  #
19
19
  ################################################################################
20
-
21
20
  require "logger"
22
21
 
23
22
  module ZTK
@@ -45,6 +44,7 @@ module ZTK
45
44
  # @author Zachary Patten <zachary@jovelabs.net>
46
45
  class Logger < ::Logger
47
46
 
47
+ # Log Levels
48
48
  SEVERITIES = Severity.constants.inject([]) {|arr,c| arr[Severity.const_get(c)] = c; arr}
49
49
 
50
50
  def initialize(*args)
@@ -52,15 +52,28 @@ module ZTK
52
52
  set_log_level
53
53
  end
54
54
 
55
+ # Provides access to the raw log device.
55
56
  def logdev
56
57
  self.instance_variable_get(:@logdev).instance_variable_get(:@dev)
57
58
  end
58
59
 
60
+ # Specialized logging. Logs messages in the same format, except has the
61
+ # option to shift the caller_at position to exposed the proper calling
62
+ # method.
63
+ #
64
+ # Very useful in situations of class inheritence, for example, where you
65
+ # might have logging statements in a base class, which are inherited by
66
+ # another class. When calling the base class method via the inherited class
67
+ # the log messages will indicate the base class as the caller. While this
68
+ # is technically true it is not always what we want to see in the logs
69
+ # because it is ambigious and does not show us where the call truly
70
+ # originated from.
59
71
  def shift(severity, shift=0, &block)
60
72
  severity = ZTK::Logger.const_get(severity.to_s.upcase)
61
73
  add(severity, nil, nil, shift, &block)
62
74
  end
63
75
 
76
+ # Generates a human-readable string about the logger.
64
77
  def inspect
65
78
  "#<#{self.class} filename=#{@logdev.filename.inspect}>"
66
79
  end
data/lib/ztk/parallel.rb CHANGED
@@ -17,7 +17,6 @@
17
17
  # limitatIOns under the License.
18
18
  #
19
19
  ################################################################################
20
-
21
20
  require "base64"
22
21
 
23
22
  module ZTK
@@ -62,6 +61,7 @@ module ZTK
62
61
  # @author Zachary Patten <zachary@jovelabs.net>
63
62
  class Parallel < ZTK::Base
64
63
 
64
+ # Default Maximum Number of Forks
65
65
  MAX_FORKS = case RUBY_PLATFORM
66
66
  when /darwin/ then
67
67
  %x( sysctl hw.ncpu ).chomp.split(':').last.strip.to_i
@@ -72,7 +72,7 @@ module ZTK
72
72
  # Result Set
73
73
  attr_accessor :results
74
74
 
75
- # @param [Hash] config Configuration options hash.
75
+ # @param [Hash] configuration Configuration options hash.
76
76
  # @option config [Integer] :max_forks Maximum number of forks to use.
77
77
  # @option config [Proc] :before_fork (nil) Proc to call before forking.
78
78
  # @option config [Proc] :after_fork (nil) Proc to call after forking.
data/lib/ztk/report.rb CHANGED
@@ -17,7 +17,6 @@
17
17
  # limitations under the License.
18
18
  #
19
19
  ################################################################################
20
-
21
20
  require 'socket'
22
21
  require 'timeout'
23
22
 
@@ -28,6 +27,15 @@ module ZTK
28
27
  # @author Zachary Patten <zachary@jovelabs.net>
29
28
  class ReportError < Error; end
30
29
 
30
+ # ZTK Report Class
31
+ #
32
+ # This class contains tools for generating spreadsheet or key-value list
33
+ # styled output. Report methods are currently meant to be interchangeable;
34
+ # that is one should be able to just switch which method they are calling
35
+ # to change the output type.
36
+ #
37
+ # The idea here is that everything is auto-sized and simply displayed.
38
+ #
31
39
  # @author Zachary Patten <zachary@jovelabs.net>
32
40
  class Report < ZTK::Base
33
41
 
@@ -38,6 +46,21 @@ module ZTK
38
46
  config.logger.debug { "config=#{config.send(:table).inspect}" }
39
47
  end
40
48
 
49
+ # Displays data in a spreadsheet style.
50
+ #
51
+ # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+
52
+ # | NAME | ALIVE | ARCH | DISTRO | IP | MAC | CHEF VERSION | PERSIST |
53
+ # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+
54
+ # | sudo | false | amd64 | ubuntu | 192.168.99.110 | 00:00:5e:34:d6:aa | N/A | true |
55
+ # | timezone | false | amd64 | ubuntu | 192.168.122.47 | 00:00:5e:92:d7:f6 | N/A | true |
56
+ # | chef-client | false | amd64 | ubuntu | 192.168.159.98 | 00:00:5e:c7:ce:26 | N/A | true |
57
+ # | users | false | amd64 | ubuntu | 192.168.7.78 | 00:00:5e:89:f9:50 | N/A | true |
58
+ # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+
59
+ #
60
+ # @param [Array] dataset An array of items for which we want to generate a
61
+ # report
62
+ # @param [Array] headers An array of headers used for ordering the output.
63
+ # @return [OpenStruct]
41
64
  def spreadsheet(dataset, headers, &block)
42
65
  !block_given? and log_and_raise(ReportError, "You must supply a block!")
43
66
  headers.nil? and log_and_raise(ReportError, "Headers can not be nil!")
@@ -80,6 +103,25 @@ module ZTK
80
103
  OpenStruct.new(:rows => rows, :max_lengths => max_lengths, :width => width)
81
104
  end
82
105
 
106
+ # Displays data in a key-value list style.
107
+ #
108
+ # +-------------------------------------------------------------------+
109
+ # | PROVIDER: Cucumber::Chef::Provider::Vagrant |
110
+ # | ID: default |
111
+ # | STATE: aborted |
112
+ # | USERNAME: vagrant |
113
+ # | IP ADDRESS: 127.0.0.1 |
114
+ # | PORT: 2222 |
115
+ # | CHEF-SERVER API: http://127.0.0.1:4000 |
116
+ # | CHEF-SERVER WEBUI: http://127.0.0.1:4040 |
117
+ # | CHEF-SERVER DEFAULT USER: admin |
118
+ # | CHEF-SERVER DEFAULT PASSWORD: p@ssw0rd1 |
119
+ # +-------------------------------------------------------------------+
120
+ #
121
+ # @param [Array] dataset An array of items for which we want to generate a
122
+ # report
123
+ # @param [Array] headers An array of headers used for ordering the output.
124
+ # @return [OpenStruct]
83
125
  def list(dataset, headers, &block)
84
126
  !block_given? and log_and_raise(ReportError, "You must supply a block!")
85
127
  headers.nil? and log_and_raise(ReportError, "Headers can not be nil!")
@@ -17,6 +17,7 @@
17
17
  # limitations under the License.
18
18
  #
19
19
  ################################################################################
20
+
20
21
  module ZTK
21
22
 
22
23
  # ZTK::RescueRetry Error Class
@@ -24,13 +25,50 @@ module ZTK
24
25
  # @author Zachary Patten <zachary@jovelabs.net>
25
26
  class RescueRetryError < Error; end
26
27
 
27
- # RescueRetry Class
28
+ # ZTK RescueRetry Class
29
+ #
30
+ # This class contains an exception handling tool, which will allowing retry
31
+ # of all or specific *Exceptions* based on a set number of attempts to make.
32
+ #
33
+ # The block is yielded and if a valid exception occurs the block will be
34
+ # re-executed for the set number of attempts.
35
+ #
36
+ # For example, from the ZTK SSH class:
37
+ #
38
+ # ZTK::RescueRetry.try(:tries => 3, :on => EOFError) do
39
+ # @ssh = Net::SSH.start(config.host_name, config.user, ssh_options)
40
+ # ...
41
+ # end
42
+ #
43
+ # If an SSH connection drops on the other side and we go to write to it, we
44
+ # will get this error. Wrapping the SSH code in *RescueRetry* allows us to
45
+ # retry the connection in the event this happens. If we have no luck after
46
+ # 3 attempts at executing the block, *RescueRetry* surfaces the exception.
28
47
  #
29
48
  # @author Zachary Patten <zachary@jovelabs.net>
30
49
  class RescueRetry
31
50
 
32
51
  class << self
33
52
 
53
+ # Rescue and Retry the supplied block.
54
+ #
55
+ # When no options are supplied, if an *Exception* is encounter it is
56
+ # surfaced immediately and no retry is performed.
57
+ #
58
+ # It is advisable to at least leave the *delay* option at 1. You could
59
+ # optionally set this to 0, but this is generally a bad idea.
60
+ #
61
+ # @param [Hash] options Configuration options hash.
62
+ # @option options [String] :tries (1) How many attempts at executing the
63
+ # block before we give up and surface the *Exception*.
64
+ # @option options [String] :on (Exception) Watch for a specific exception
65
+ # instead of performing retry on all exceptions.
66
+ # @option options [Float,Integer] :delay (1) How long to sleep for between
67
+ # each retry.
68
+ #
69
+ # @yield Block should execute the tasks to be rescued and retried if
70
+ # needed.
71
+ # @return [Object] The return value of the block.
34
72
  def try(options={}, &block)
35
73
  options = Base.build_config({
36
74
  :tries => 1,