dtk-common-core 0.5.6

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.
@@ -0,0 +1,6 @@
1
+ dtk-common-repo
2
+ ===============
3
+
4
+ License
5
+ ----------------------
6
+ DTK Common Core is released under the GPLv3 license. Please see LICENSE for more details.
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/dtk-common-core/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Rich PELAVIN"]
6
+ gem.email = ["rich@reactor8.com"]
7
+ gem.description = %q{Dtk common repo is core common librabry of dtk, and mostly hold libraries used for http communication.}
8
+ gem.summary = %q{Common libraries used for DTK CLI client.}
9
+ gem.homepage = "https://github.com/rich-reactor8/dtk-common-repo"
10
+ gem.licenses = ["GPL-3.0"]
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "dtk-common-core"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = "#{DtkCommonCore::VERSION}.#{ARGV[3]}".chomp(".")
17
+
18
+ gem.add_dependency 'rest-client','~> 1.6.7'
19
+ end
@@ -0,0 +1,131 @@
1
+ #TODO: will start moving over to using DtkCommon namespace; versions in DtkCommon namespace also in DTK::Common are teh upgraded versions
2
+ require 'etc'
3
+
4
+ module DtkCommon
5
+ module Aux
6
+ def self.dtk_instance_repo_username(tenant_id=nil)
7
+ instance_unique_id = get_ec2_instance_id() || get_macaddress().gsub(/:/,'-')
8
+ tenant_id ||= ::DTK::Common::Aux.running_process_user()
9
+ "dtk-#{instance_unique_id}--#{tenant_id}"
10
+ end
11
+ end
12
+ end
13
+
14
+ module DTK
15
+ module Common
16
+ module AuxMixin
17
+ def get_ssh_rsa_pub_key()
18
+ path = "#{running_process_home_dir()}/.ssh/id_rsa.pub"
19
+ begin
20
+ File.open(path){|f|f.read}.chomp
21
+ rescue Errno::ENOENT
22
+ raise Error.new("user (#{ENV['USER']}) does not have a public key under #{path}")
23
+ rescue => e
24
+ raise e
25
+ end
26
+ end
27
+
28
+ def hash_subset(hash,keys_subset,opts={})
29
+ keys_subset.inject(Hash.new) do |h,k|
30
+ index = k.kind_of?(Hash) ? k.keys.first : k
31
+ if opts[:no_non_nil] and hash[index].nil? then h
32
+ elsif not hash.has_key?(index) then h
33
+ else
34
+ key = k.kind_of?(Hash) ? k.values.first : k
35
+ val = hash[index]
36
+ h.merge(key => val)
37
+ end
38
+ end
39
+ end
40
+
41
+ def convert_keys_to_symbols(hash)
42
+ hash.keys.inject(Hash.new){|h,k|h.merge(k.to_sym => hash[k])}
43
+ end
44
+
45
+ def dtk_instance_repo_username()
46
+ #on ec2 changing mac addresses; so selectively pick instance id on ec2
47
+ unique_id = get_ec2_instance_id() || get_macaddress().gsub(/:/,'-')
48
+ "dtk-#{unique_id}"
49
+ end
50
+
51
+ def update_ssh_known_hosts(remote_host)
52
+ fingerprint = `ssh-keyscan -H -t rsa #{remote_host}`
53
+ ssh_known_hosts = "#{running_process_home_dir()}/.ssh/known_hosts"
54
+ if File.file?(ssh_known_hosts)
55
+ `ssh-keygen -f "#{ssh_known_hosts}" -R #{remote_host}`
56
+ end
57
+ File.open(ssh_known_hosts,"a"){|f| f << "#{fingerprint}\n"}
58
+ end
59
+
60
+ def get_macaddress()
61
+ return @macaddress if @macaddress
62
+ #TODO: may just use underlying routines for facter - macaddress
63
+ require 'facter'
64
+ collection = ::Facter.collection
65
+ @macaddress = collection.fact('macaddress').value
66
+ end
67
+
68
+ def get_ec2_public_dns()
69
+ get_ec2_meta_data('public-hostname')
70
+ end
71
+
72
+ def get_ec2_instance_id()
73
+ # @ec2_instance_id_cached used because it could have tried to get this info and result was null
74
+ return @ec2_instance_id if @ec2_instance_id_cached
75
+ @ec2_instance_id_cached = true
76
+ @ec2_instance_id = get_ec2_meta_data('instance-id')
77
+ end
78
+
79
+ def snake_to_camel_case(snake_case)
80
+ snake_case.gsub(/(^|_)(.)/) { $2.upcase }
81
+ end
82
+
83
+ def platform_is_linux?()
84
+ RUBY_PLATFORM.downcase.include?("linux")
85
+ end
86
+
87
+ def platform_is_windows?()
88
+ RUBY_PLATFORM.downcase.include?("mswin") or RUBY_PLATFORM.downcase.include?("mingw")
89
+ end
90
+
91
+ def running_process_user()
92
+ if platform_is_windows?()
93
+ Etc.getlogin
94
+ else
95
+ Etc.getpwuid(Process.uid).name
96
+ end
97
+ end
98
+
99
+ def running_process_home_dir()
100
+ if platform_is_windows?()
101
+ File.expand_path('~')
102
+ else
103
+ Etc.getpwuid(Process.uid).dir
104
+ end
105
+ end
106
+
107
+ private
108
+ def get_ec2_meta_data(var)
109
+ #Fragments taken from Puppetlabs facter ec2
110
+ require 'open-uri'
111
+ require 'timeout'
112
+ ret = nil
113
+ begin
114
+ url = "http://169.254.169.254:80/"
115
+ Timeout::timeout(WaitSec) {open(url)}
116
+ ret = OpenURI.open_uri("http://169.254.169.254/2008-02-01/meta-data/#{var}").read
117
+ rescue Timeout::Error
118
+ rescue
119
+ #TODO: unexpected; write t log what error is
120
+ end
121
+ ret
122
+ end
123
+ WaitSec = 2
124
+ end
125
+ module Aux
126
+ class << self
127
+ include AuxMixin
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,3 @@
1
+ module DtkCommonCore
2
+ VERSION = "0.5.6"
3
+ end
@@ -0,0 +1,5 @@
1
+ require File.expand_path('auxiliary.rb', File.dirname(__FILE__))
2
+ require File.expand_path('errors.rb', File.dirname(__FILE__))
3
+ require File.expand_path('hash_object.rb', File.dirname(__FILE__))
4
+ require File.expand_path('log.rb', File.dirname(__FILE__))
5
+ require File.expand_path('response.rb', File.dirname(__FILE__))
@@ -0,0 +1,2 @@
1
+ require File.expand_path('errors/errors', File.dirname(__FILE__))
2
+ require File.expand_path('errors/rest_error', File.dirname(__FILE__))
@@ -0,0 +1,127 @@
1
+ #TODO: should have a Common namespace put in after DTK
2
+ module DTK
3
+ class Error < NameError
4
+ def self.top_error_in_hash()
5
+ {:error => :Error}
6
+ end
7
+ def initialize(msg="",name_or_opts=nil)
8
+ name = nil
9
+ opts = Hash.new
10
+ if name_or_opts.kind_of?(Hash)
11
+ opts = name_or_opts
12
+ else
13
+ name = name_or_opts
14
+ end
15
+ super(msg,name)
16
+ #TODO: might make default to be :log_error => false
17
+ unless opts.has_key?(:log_error) and not opts[:log_error]
18
+ Log.info(to_s)
19
+ if caller_info = opts[:caller_info]
20
+ caller_depth = (caller_info.kind_of?(Hash) ? caller_info[:depth] : nil)||DefaultCallerDepth
21
+ Log.info_pp(caller[CallerOffset,caller_depth])
22
+ end
23
+ end
24
+ end
25
+ CallerOffset = 3
26
+ DefaultCallerDepth = 3
27
+
28
+ def to_hash()
29
+ if to_s == ""
30
+ Error.top_error_in_hash()
31
+ elsif name.nil?
32
+ {:error => {:Error => {:msg => to_s}}}
33
+ else
34
+ {:error => {name.to_sym => {:msg => to_s}}}
35
+ end
36
+ end
37
+ end
38
+
39
+ class R8ParseError < Error
40
+ def initialize(msg,calling_obj=nil)
41
+ msg = (calling_obj ? "#{msg} in class #{calling_obj.class.to_s}" : msg)
42
+ super(msg)
43
+ end
44
+ end
45
+ class ErrorUsage < Error
46
+ end
47
+
48
+ class ErrorConstraintViolations < ErrorUsage
49
+ def initialize(violations)
50
+ super(msg(violations),:ConstraintViolations)
51
+ end
52
+ private
53
+ def msg(violations)
54
+ return ("constraint violation: " + violations) if violations.kind_of?(String)
55
+ v_with_text = violations.compact
56
+ if v_with_text.size < 2
57
+ return "constraint violations"
58
+ elsif v_with_text.size == 2
59
+ return "constraint violations: #{v_with_text[1]}"
60
+ end
61
+ ret = "constraint violations: "
62
+ ret << (v_with_text.first == :or ? "(atleast) one of " : "")
63
+ ret << "(#{v_with_text[1..v_with_text.size-1].join(", ")})"
64
+ end
65
+ end
66
+
67
+ class ErrorUserInputNeeded < ErrorUsage
68
+ def initialize(needed_inputs)
69
+ super()
70
+ @needed_inputs = needed_inputs
71
+ end
72
+ def to_s()
73
+ ret = "following inputs are needed:\n"
74
+ @needed_inputs.each do |k,v|
75
+ ret << " #{k}: type=#{v[:type]}; description=#{v[:description]}\n"
76
+ end
77
+ ret
78
+ end
79
+ end
80
+
81
+ class ErrorNotImplemented < Error
82
+ def initialize(msg="NotImplemented error")
83
+ super("in #{this_parent_parent_method}: #{msg}",:NotImplemented)
84
+ end
85
+ end
86
+
87
+ class ErrorNotFound < Error
88
+ attr_reader :obj_type,:obj_value
89
+ def initialize(obj_type=nil,obj_value=nil)
90
+ @obj_type = obj_type
91
+ @obj_value = obj_value
92
+ end
93
+ def to_s()
94
+ if obj_type.nil?
95
+ "NotFound error:"
96
+ elsif obj_value.nil?
97
+ "NotFound error: type = #{@obj_type.to_s}"
98
+ else
99
+ "NotFound error: #{@obj_type.to_s} = #{@obj_value.to_s}"
100
+ end
101
+ end
102
+ def to_hash()
103
+ if obj_type.nil?
104
+ {:error => :NotFound}
105
+ elsif obj_value.nil?
106
+ {:error => {:NotFound => {:type => @obj_type}}}
107
+ else
108
+ {:error => {:NotFound => {:type => @obj_type, :value => @obj_value}}}
109
+ end
110
+ end
111
+ end
112
+
113
+ class ErrorAMQP < Error
114
+ def to_s()
115
+ "AMQP error"
116
+ end
117
+ end
118
+ class ErrorAMQPQueueDoesNotExist < ErrorAMQP
119
+ attr_reader :queue_name
120
+ def initialize(queue_name)
121
+ @queue_name = queue_name
122
+ end
123
+ def to_s()
124
+ "queue #{queue_name} does not exist"
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,59 @@
1
+ #TODO: should have a Common namespace put in after DTK
2
+ #When creating these objects, an internal errro class is passed to the creation functions
3
+ module DTK
4
+ class RestError
5
+ def self.create(err)
6
+ if RestUsageError.match?(err)
7
+ RestUsageError.new(err)
8
+ elsif NotFound.match?(err)
9
+ NotFound.new(err)
10
+ else
11
+ Internal.new(err)
12
+ end
13
+ end
14
+ def initialize(err)
15
+ @code = nil
16
+ @message = nil
17
+ end
18
+ def hash_form()
19
+ {:code => code||:error, :message => message||''}
20
+ end
21
+ private
22
+ attr_reader :code, :message
23
+ public
24
+ #its either its a usage or and internal (application error) bug
25
+ class Internal < RestError
26
+ def hash_form()
27
+ super.merge(:internal => true)
28
+ end
29
+ private
30
+ def initialize(err)
31
+ super
32
+ @message = "#{err.to_s} (#{err.backtrace.first})"
33
+ end
34
+ end
35
+ class RestUsageError < RestError
36
+ def initialize(err)
37
+ super
38
+ @message = err.to_s
39
+ end
40
+ def self.match?(err)
41
+ err.kind_of?(ErrorUsage)
42
+ end
43
+ end
44
+ class NotFound < RestUsageError
45
+ def self.match?(err)
46
+ err.kind_of?(::NoMethodError) and is_controller_method(err)
47
+ end
48
+ def initialize(err)
49
+ super
50
+ @code = :not_found
51
+ @message = "'#{err.name}' was not found"
52
+ end
53
+ private
54
+ def self.is_controller_method(err)
55
+ err.to_s =~ /#<XYZ::.+Controller:/
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,49 @@
1
+ module DTK
2
+ module Common
3
+ class SimpleHashObject < Hash
4
+ def initialize(initial_val=nil,&block)
5
+ block ? super(&block) : super()
6
+ if initial_val
7
+ replace(initial_val)
8
+ end
9
+ end
10
+ end
11
+
12
+ # require 'active_support/ordered_hash'
13
+ # class SimpleOrderedHash < ::ActiveSupport::OrderedHash
14
+ class SimpleOrderedHash < Hash
15
+ def initialize(elements=[])
16
+ super()
17
+ elements = [elements] unless elements.kind_of?(Array)
18
+ elements.each{|el|self[el.keys.first] = el.values.first}
19
+ end
20
+
21
+ #set unless value is nill
22
+ def set_unless_nil(k,v)
23
+ self[k] = v unless v.nil?
24
+ end
25
+ end
26
+
27
+ class PrettyPrintHash < SimpleOrderedHash
28
+ #field with '?' suffix means optioanlly add depending on whether name present and non-null in source
29
+ #if block is given then apply to source[name] rather than returning just source[name]
30
+ def add(model_object,*keys,&block)
31
+ keys.each do |key|
32
+ #if marked as optional skip if not present
33
+ if key.to_s =~ /(^.+)\?$/
34
+ key = $1.to_sym
35
+ next unless model_object[key]
36
+ end
37
+ #special treatment of :id
38
+ val = (key == :id ? model_object.id : model_object[key])
39
+ self[key] = (block ? block.call(val) : val)
40
+ end
41
+ self
42
+ end
43
+
44
+ def slice(*keys)
45
+ keys.inject(self.class.new){|h,k|h.merge(k => self[k])}
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,37 @@
1
+ #TODO: bring in a production quality ruby logging capability that gets wrapped here
2
+ #TODO: would put this in config
3
+ module DTK
4
+ module Log
5
+ Config = Hash.new
6
+ Config[:print_time] = false
7
+ Config[:print_method] = false
8
+
9
+ def self.info(msg, out = $stdout)
10
+ out << "info: "
11
+ out << format(msg)
12
+ end
13
+ def self.debug(msg, out = $stdout)
14
+ out << "debug: "
15
+ out << format(msg)
16
+ end
17
+ def self.error(msg, out = $stdout)
18
+ out << "error: "
19
+ out << format(msg)
20
+ end
21
+ def self.info_pp(obj, out = $stdout)
22
+ out << Aux::pp_form(obj)
23
+ end
24
+ def self.debug_pp(obj, out = $stdout)
25
+ out << Aux::pp_form(obj)
26
+ obj
27
+ end
28
+ private
29
+ def self.format(msg)
30
+ ret = String.new
31
+ ret << "#{Time.now}: " if Config[:print_time]
32
+ ret << "in fn: #{this_parent_method}: " if Config[:print_method]
33
+ ret << msg
34
+ ret << "\n"
35
+ end
36
+ end
37
+ end