dtk-common-core 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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