right_agent 0.9.11 → 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +3 -2
- data/lib/right_agent/actors/agent_manager.rb +2 -2
- data/lib/right_agent/agent.rb +26 -14
- data/lib/right_agent/packets.rb +3 -1
- data/lib/right_agent/platform/windows.rb +47 -12
- data/lib/right_agent/serialize/message_pack.rb +6 -1
- data/lib/right_agent/serialize/serializer.rb +1 -1
- data/right_agent.gemspec +8 -3
- data/spec/dispatcher_spec.rb +4 -0
- data/spec/log_spec.rb +1 -1
- data/spec/platform/windows_volume_manager_spec.rb +253 -0
- data/spec/serialize/serializer_spec.rb +6 -2
- data/spec/spec.win32.opts +1 -0
- metadata +10 -8
data/Rakefile
CHANGED
@@ -46,8 +46,9 @@ directory gemtask.package_dir
|
|
46
46
|
CLEAN.include(gemtask.package_dir)
|
47
47
|
|
48
48
|
# == Unit tests == #
|
49
|
-
|
50
|
-
|
49
|
+
spec_opts_file = "\"#{File.dirname(__FILE__)}/spec/spec.opts\""
|
50
|
+
spec_opts_file = "\"#{File.dirname(__FILE__)}/spec/spec.win32.opts\"" if RUBY_PLATFORM =~ /mingw|mswin32/
|
51
|
+
RSPEC_OPTS = ['--options', spec_opts_file]
|
51
52
|
|
52
53
|
desc 'Run unit tests'
|
53
54
|
RSpec::Core::RakeTask.new do |t|
|
@@ -65,7 +65,7 @@ class AgentManager
|
|
65
65
|
#
|
66
66
|
# === Return
|
67
67
|
# (RightScale::OperationResult):: Always returns success
|
68
|
-
def stats(options)
|
68
|
+
def stats(options = {})
|
69
69
|
@agent.stats(RightScale::SerializationHelper.symbolize_keys(options))
|
70
70
|
end
|
71
71
|
|
@@ -80,7 +80,7 @@ class AgentManager
|
|
80
80
|
#
|
81
81
|
# === Return
|
82
82
|
# (OperationResult):: Empty success result or error result with message
|
83
|
-
def profile(options)
|
83
|
+
def profile(options = {})
|
84
84
|
require 'memprof'
|
85
85
|
|
86
86
|
options = RightScale::SerializationHelper.symbolize_keys(options)
|
data/lib/right_agent/agent.rb
CHANGED
@@ -177,7 +177,7 @@ module RightScale
|
|
177
177
|
now = Time.now
|
178
178
|
Log.info("[start] Agent #{@identity} starting; time: #{now.utc}; utc_offset: #{now.utc_offset}")
|
179
179
|
Log.debug("Start options:")
|
180
|
-
log_opts = @options.inject([]){ |t, (k, v)| t << "- #{k}: #{v}" }
|
180
|
+
log_opts = @options.inject([]){ |t, (k, v)| t << "- #{k}: #{v.respond_to?(:each) ? v.inspect : v}" }
|
181
181
|
log_opts.each { |l| Log.debug(l) }
|
182
182
|
|
183
183
|
begin
|
@@ -532,19 +532,23 @@ module RightScale
|
|
532
532
|
def stats(options = {})
|
533
533
|
now = Time.now
|
534
534
|
reset = options[:reset]
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
535
|
+
stats = {
|
536
|
+
"name" => @agent_name,
|
537
|
+
"identity" => @identity,
|
538
|
+
"hostname" => Socket.gethostname,
|
539
|
+
"memory" => Platform.process.resident_set_size,
|
540
|
+
"version" => AgentConfig.protocol_version,
|
541
|
+
"brokers" => @broker.stats(reset),
|
542
|
+
"agent stats" => agent_stats(reset),
|
543
|
+
"receive stats" => @dispatcher.stats(reset),
|
544
|
+
"send stats" => @sender.stats(reset),
|
545
|
+
"last reset time" => @last_stat_reset_time.to_i,
|
546
|
+
"stat time" => now.to_i,
|
547
|
+
"service uptime" => (now - @service_start_time).to_i,
|
548
|
+
"machine uptime" => Platform.shell.uptime
|
549
|
+
}
|
550
|
+
stats["revision"] = @revision if @revision
|
551
|
+
result = OperationResult.success(stats)
|
548
552
|
@last_stat_reset_time = now if reset
|
549
553
|
result
|
550
554
|
end
|
@@ -612,6 +616,7 @@ module RightScale
|
|
612
616
|
@agent_type = parsed_identity.agent_type
|
613
617
|
@agent_name = @options[:agent_name]
|
614
618
|
@stats_routing_key = "stats.#{@agent_type}.#{parsed_identity.base_id}"
|
619
|
+
@revision = revision
|
615
620
|
|
616
621
|
@remaining_setup = {}
|
617
622
|
@all_setup = [:setup_identity_queue]
|
@@ -814,6 +819,13 @@ module RightScale
|
|
814
819
|
yield
|
815
820
|
end
|
816
821
|
|
822
|
+
# Determine current revision of software
|
823
|
+
#
|
824
|
+
# === Return
|
825
|
+
# (String):: Revision of software in displayable format
|
826
|
+
def revision
|
827
|
+
end
|
828
|
+
|
817
829
|
end # Agent
|
818
830
|
|
819
831
|
end # RightScale
|
data/lib/right_agent/packets.rb
CHANGED
@@ -102,7 +102,9 @@ module RightScale
|
|
102
102
|
'size' => nil
|
103
103
|
}.to_msgpack(*a)
|
104
104
|
@size = msg.size
|
105
|
-
|
105
|
+
# For ruby 1.9 size attribute moves from front to back of packet
|
106
|
+
re = RUBY_VERSION < "1.9.0" ? /size\xC0/ : /size\xC0$/
|
107
|
+
msg.sub!(re) { |m| "size" + @size.to_msgpack }
|
106
108
|
msg
|
107
109
|
end
|
108
110
|
|
@@ -327,6 +327,9 @@ module RightScale
|
|
327
327
|
|
328
328
|
def initialize
|
329
329
|
@os_info = OSInformation.new
|
330
|
+
|
331
|
+
@assignable_disk_regex = /^[D-Zd-z]:[\/\\]?$/
|
332
|
+
@assignable_path_regex = /^[A-Za-z]:[\/\\][\/\\\w\s\d\-_\.~]+$/
|
330
333
|
end
|
331
334
|
|
332
335
|
# Determines if the given path is valid for a Windows volume attachemnt
|
@@ -335,7 +338,7 @@ module RightScale
|
|
335
338
|
# === Return
|
336
339
|
# result(Boolean):: true if path is a valid volume root
|
337
340
|
def is_attachable_volume_path?(path)
|
338
|
-
return nil != (path =~
|
341
|
+
return (nil != (path =~ @assignable_disk_regex) || nil != (path =~ @assignable_path_regex))
|
339
342
|
end
|
340
343
|
|
341
344
|
# Gets a list of physical or virtual disks in the form:
|
@@ -448,7 +451,7 @@ EOF
|
|
448
451
|
#
|
449
452
|
# === Parameters
|
450
453
|
# disk_index(int): zero-based disk index (from disks list, etc.)
|
451
|
-
# device(String)::
|
454
|
+
# device(String):: disk letter or mount path specified for the volume to create
|
452
455
|
#
|
453
456
|
# === Return
|
454
457
|
# always true
|
@@ -457,12 +460,14 @@ EOF
|
|
457
460
|
# ArgumentError:: on invalid parameters
|
458
461
|
# VolumeError:: on failure to format
|
459
462
|
def format_disk(disk_index, device)
|
463
|
+
if device.match(@assignable_path_regex) && @os_info.major < 6
|
464
|
+
raise ArgumentError.new("Mount path assignment is not supported in this version of windows")
|
465
|
+
end
|
460
466
|
# note that creating the primary partition automatically creates and
|
461
467
|
# selects a new volume, which can be assigned a letter before the
|
462
468
|
# partition has actually been formatted.
|
463
469
|
raise ArgumentError.new("Invalid index = #{disk_index}") unless disk_index >= 0
|
464
470
|
raise ArgumentError.new("Invalid device = #{device}") unless is_attachable_volume_path?(device)
|
465
|
-
letter = device[0,1]
|
466
471
|
online_command = if @os_info.major < 6; "online noerr"; else; "online disk noerr"; end
|
467
472
|
clear_readonly_command = if @os_info.major < 6; ""; else; "attribute disk clear readonly noerr"; end
|
468
473
|
|
@@ -477,7 +482,7 @@ select disk #{disk_index}
|
|
477
482
|
#{online_command}
|
478
483
|
clean
|
479
484
|
create partition primary
|
480
|
-
|
485
|
+
#{get_assign_command_for_device(device)}
|
481
486
|
#{format_command}
|
482
487
|
EOF
|
483
488
|
exit_code, output_text = run_script(script)
|
@@ -485,7 +490,7 @@ EOF
|
|
485
490
|
|
486
491
|
# must format using command shell's FORMAT command before 2008 server.
|
487
492
|
if @os_info.major < 6
|
488
|
-
command = "echo Y | format #{
|
493
|
+
command = "echo Y | format #{device[0,1]}: /Q /V: /FS:NTFS"
|
489
494
|
output_text = `#{command}`
|
490
495
|
exit_code = $?.exitstatus
|
491
496
|
raise VolumeError.new("Failed to format disk #{disk_index} for device #{device}: exit code = #{exit_code}\n#{output_text}") if exit_code != 0
|
@@ -531,7 +536,7 @@ EOF
|
|
531
536
|
#
|
532
537
|
# === Parameters
|
533
538
|
# volume_device_or_index(int):: old device or zero-based volume index (from volumes list, etc.) to select for assignment.
|
534
|
-
# device(String)::
|
539
|
+
# device(String):: disk letter or mount path specified for the volume to create
|
535
540
|
#
|
536
541
|
# === Return
|
537
542
|
# always true
|
@@ -541,18 +546,24 @@ EOF
|
|
541
546
|
# VolumeError:: on failure to assign device name
|
542
547
|
# ParserError:: on failure to parse volume list
|
543
548
|
def assign_device(volume_device_or_index, device)
|
549
|
+
if device.match(@assignable_path_regex) && @os_info.major < 6
|
550
|
+
raise ArgumentError.new("Mount path assignment is not supported in this version of windows")
|
551
|
+
end
|
552
|
+
# Volume selector for drive letter assignments
|
544
553
|
volume_selector_match = volume_device_or_index.to_s.match(/^([D-Zd-z]|\d+):?$/)
|
554
|
+
# Volume selector for mount path assignments
|
555
|
+
volume_selector_match = volume_device_or_index.to_s.match(@assignable_path_regex) unless volume_selector_match
|
545
556
|
raise ArgumentError.new("Invalid volume_device_or_index = #{volume_device_or_index}") unless volume_selector_match
|
546
557
|
volume_selector = volume_selector_match[1]
|
547
558
|
raise ArgumentError.new("Invalid device = #{device}") unless is_attachable_volume_path?(device)
|
548
|
-
new_letter = device[0,1]
|
549
559
|
script = <<EOF
|
550
560
|
rescan
|
551
561
|
list volume
|
552
|
-
select volume #{volume_selector}
|
562
|
+
select volume "#{volume_selector}"
|
553
563
|
attribute volume clear readonly noerr
|
554
|
-
|
564
|
+
#{get_assign_command_for_device(device)}
|
555
565
|
EOF
|
566
|
+
|
556
567
|
exit_code, output_text = run_script(script)
|
557
568
|
raise VolumeError.new("Failed to assign device \"#{device}\" for volume \"#{volume_device_or_index}\": exit code = #{exit_code}\n#{script}\n#{output_text}") if exit_code != 0
|
558
569
|
true
|
@@ -641,7 +652,8 @@ EOF
|
|
641
652
|
# conditions{Hash):: hash of conditions to match or nil (default)
|
642
653
|
#
|
643
654
|
# === Return
|
644
|
-
# result(Array):: volumes or empty
|
655
|
+
# result(Array):: volumes or empty. Drive letters are appended with ':' even though they aren't
|
656
|
+
# returned that way from diskpart
|
645
657
|
#
|
646
658
|
# === Raise
|
647
659
|
# ParserError:: on failure to parse volume list
|
@@ -657,6 +669,14 @@ EOF
|
|
657
669
|
break
|
658
670
|
end
|
659
671
|
match_data = line.match(line_regex)
|
672
|
+
unless match_data
|
673
|
+
path_match_regex = /([A-Za-z]:[\/\\][\/\\\w\s\d]+)/
|
674
|
+
match_data = line.match(path_match_regex)
|
675
|
+
if match_data
|
676
|
+
result.last[:device] = match_data[1]
|
677
|
+
next
|
678
|
+
end
|
679
|
+
end
|
660
680
|
raise ParserError.new("Failed to parse volume info from #{line.inspect} using #{line_regex.inspect}") unless match_data
|
661
681
|
letter = nil_if_empty(match_data[2])
|
662
682
|
device = "#{letter.upcase}:" if letter
|
@@ -689,8 +709,8 @@ EOF
|
|
689
709
|
info_width = header_match[5].length
|
690
710
|
line_regex_text = "^[\\* ] Volume (\\d[\\d ]\{2\}) ([A-Za-z ]) "\
|
691
711
|
"(.\{#{label_width}\}) (.\{#{filesystem_width}\}) "\
|
692
|
-
"(.\{#{type_width}\}) [ ]?([\\d ]\{3\}\\d) (.?B)
|
693
|
-
"(.\{#{status_width}\})
|
712
|
+
"(.\{#{type_width}\}) [ ]?([\\d ]\{3\}\\d) (.?B)\\s{0,2}"\
|
713
|
+
"(.\{#{status_width}\})\\s{0,2}(.\{0,#{info_width}\})"
|
694
714
|
line_regex = Regexp.compile(line_regex_text)
|
695
715
|
else
|
696
716
|
# one or more lines of ignored headers
|
@@ -823,6 +843,21 @@ EOF
|
|
823
843
|
end
|
824
844
|
end
|
825
845
|
|
846
|
+
# Returns the correct diskpart assignment command for the specified device (either drive letter, or path)
|
847
|
+
#
|
848
|
+
# === Parameters
|
849
|
+
# device(String):: Either a drive letter or mount path
|
850
|
+
#
|
851
|
+
# === Return
|
852
|
+
# result(String):: The correct diskpart assignment command
|
853
|
+
def get_assign_command_for_device(device)
|
854
|
+
if device.match(@assignable_disk_regex)
|
855
|
+
"assign letter=#{device[0,1]}"
|
856
|
+
elsif device.match(@assignable_path_regex)
|
857
|
+
"assign mount=\"#{device}\""
|
858
|
+
end
|
859
|
+
end
|
860
|
+
|
826
861
|
end # VolumeManager
|
827
862
|
|
828
863
|
# Provides utilities for formatting executable shell commands, etc.
|
@@ -35,7 +35,12 @@ module MessagePack
|
|
35
35
|
# === Return
|
36
36
|
# obj(Object):: Unserialized object
|
37
37
|
def self.load(data)
|
38
|
-
|
38
|
+
if data.respond_to?(:force_encoding)
|
39
|
+
# For Ruby 1.9 need to ensure that MessagePack receives ASCII-8BIT data
|
40
|
+
create(unpack(data.force_encoding("ASCII-8BIT")))
|
41
|
+
else
|
42
|
+
create(unpack(data))
|
43
|
+
end
|
39
44
|
end
|
40
45
|
|
41
46
|
# Create any msgpack_class objects nested within the unserialized data by calling
|
@@ -141,7 +141,7 @@ module RightScale
|
|
141
141
|
# === Return
|
142
142
|
# (Array):: Ordered serializers
|
143
143
|
def order_serializers(packet)
|
144
|
-
packet
|
144
|
+
packet.getbyte(0) > 127 ? MSGPACK_FIRST_SERIALIZERS : JSON_FIRST_SERIALIZERS
|
145
145
|
end
|
146
146
|
|
147
147
|
end # Serializer
|
data/right_agent.gemspec
CHANGED
@@ -24,8 +24,8 @@ require 'rubygems'
|
|
24
24
|
|
25
25
|
Gem::Specification.new do |spec|
|
26
26
|
spec.name = 'right_agent'
|
27
|
-
spec.version = '0.
|
28
|
-
spec.date = '2012-
|
27
|
+
spec.version = '0.10.2'
|
28
|
+
spec.date = '2012-05-01'
|
29
29
|
spec.authors = ['Lee Kirchhoff', 'Raphael Simon', 'Tony Spataro']
|
30
30
|
spec.email = 'lee@rightscale.com'
|
31
31
|
spec.homepage = 'https://github.com/rightscale/right_agent'
|
@@ -38,13 +38,18 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.require_path = 'lib'
|
39
39
|
|
40
40
|
spec.add_dependency('right_support', '~> 1.3')
|
41
|
-
spec.add_dependency('right_amqp', '~> 0.
|
41
|
+
spec.add_dependency('right_amqp', '~> 0.3')
|
42
42
|
spec.add_dependency('json', ['~> 1.4'])
|
43
43
|
spec.add_dependency('eventmachine', '~> 0.12.10')
|
44
44
|
spec.add_dependency('right_popen', '~> 1.0.11')
|
45
45
|
spec.add_dependency('msgpack', '0.4.4')
|
46
46
|
spec.add_dependency('net-ssh', '~> 2.0')
|
47
47
|
|
48
|
+
if spec.platform.to_s =~ /mswin|mingw/
|
49
|
+
spec.add_dependency('win32-dir', '~> 0.3.5')
|
50
|
+
spec.add_dependency('win32-process', '~> 0.6.1')
|
51
|
+
end
|
52
|
+
|
48
53
|
spec.description = <<-EOF
|
49
54
|
RightAgent provides a foundation for running an agent on a server to interface
|
50
55
|
in a secure fashion with other agents in the RightScale system. A RightAgent
|
data/spec/dispatcher_spec.rb
CHANGED
@@ -337,6 +337,7 @@ describe "RightScale::Dispatcher" do
|
|
337
337
|
EM.run do
|
338
338
|
@agent.should_receive(:options).and_return(:dup_check => true)
|
339
339
|
@dispatcher = RightScale::Dispatcher.new(@agent)
|
340
|
+
@dispatcher.em = EMMock
|
340
341
|
req = RightScale::Request.new('/foo/bar', 'you', :token => "try")
|
341
342
|
@dispatcher.instance_variable_get(:@dispatched).store(req.token)
|
342
343
|
@dispatcher.dispatch(req).should be_nil
|
@@ -349,6 +350,7 @@ describe "RightScale::Dispatcher" do
|
|
349
350
|
EM.run do
|
350
351
|
@agent.should_receive(:options).and_return(:dup_check => true)
|
351
352
|
@dispatcher = RightScale::Dispatcher.new(@agent)
|
353
|
+
@dispatcher.em = EMMock
|
352
354
|
req = RightScale::Request.new('/foo/bar', 'you', :token => "try")
|
353
355
|
req.tries.concat(["try1", "try2"])
|
354
356
|
@dispatcher.instance_variable_get(:@dispatched).store("try2")
|
@@ -361,6 +363,7 @@ describe "RightScale::Dispatcher" do
|
|
361
363
|
EM.run do
|
362
364
|
@agent.should_receive(:options).and_return(:dup_check => true)
|
363
365
|
@dispatcher = RightScale::Dispatcher.new(@agent)
|
366
|
+
@dispatcher.em = EMMock
|
364
367
|
req = RightScale::Request.new('/foo/bar', 'you', :token => "try")
|
365
368
|
req.tries.concat(["try1", "try2"])
|
366
369
|
@dispatcher.instance_variable_get(:@dispatched).store("try3")
|
@@ -372,6 +375,7 @@ describe "RightScale::Dispatcher" do
|
|
372
375
|
it "should not check for duplicates if dup_check disabled" do
|
373
376
|
EM.run do
|
374
377
|
@dispatcher = RightScale::Dispatcher.new(@agent)
|
378
|
+
@dispatcher.em = EMMock
|
375
379
|
req = RightScale::Request.new('/foo/bar', 'you', :token => "try")
|
376
380
|
req.tries.concat(["try1", "try2"])
|
377
381
|
@dispatcher.instance_variable_get(:@dispatched).should be_nil
|
data/spec/log_spec.rb
CHANGED
@@ -35,7 +35,7 @@ describe RightScale::Log do
|
|
35
35
|
def log_count(text)
|
36
36
|
# no such animal as egrep in windows, so hacked up an equivalent here.
|
37
37
|
pattern = Regexp.compile(text)
|
38
|
-
File.read(@log_file).
|
38
|
+
File.read(@log_file).each_line.select { |x| x =~ pattern }.count
|
39
39
|
end
|
40
40
|
|
41
41
|
before(:all) do
|
@@ -0,0 +1,253 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 RightScale Inc
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
24
|
+
|
25
|
+
if RightScale::Platform.windows?
|
26
|
+
module OsInfoExtensions
|
27
|
+
def set_osinfo(osinfo)
|
28
|
+
@os_info = osinfo
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_osinfo
|
32
|
+
@os_info
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe RightScale::Platform do
|
37
|
+
before(:all) do
|
38
|
+
@platform = RightScale::Platform
|
39
|
+
end
|
40
|
+
|
41
|
+
context :volume_manager do
|
42
|
+
context :is_attachable_volume_path do
|
43
|
+
it 'allows paths with hyphens and underscores' do
|
44
|
+
@platform.volume_manager.is_attachable_volume_path?('C:\\Some_crazy-path').should == true
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'allows paths with periods' do
|
48
|
+
@platform.volume_manager.is_attachable_volume_path?('C:\\Some.crazy.path').should == true
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'allows paths with tildes' do
|
52
|
+
@platform.volume_manager.is_attachable_volume_path?('C:\\~Some~crazy~path').should == true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context :parse_volumes do
|
57
|
+
it 'can parse volumes from diskpart output' do
|
58
|
+
list_vol_resp = <<EOF
|
59
|
+
Volume ### Ltr Label Fs Type Size Status Info
|
60
|
+
---------- --- ----------- ----- ---------- ------- --------- --------
|
61
|
+
Volume 0 C 2008Boot NTFS Partition 80 GB Healthy System
|
62
|
+
* Volume 1 D NTFS Partition 4094 MB Healthy
|
63
|
+
Volume 2 NTFS Partition 4094 MB Healthy
|
64
|
+
EOF
|
65
|
+
|
66
|
+
volume_hash_ary = [
|
67
|
+
{:index => 0, :device => "C:", :label => "2008Boot", :filesystem => "NTFS", :type => "Partition", :total_size => 85899345920, :status => "Healthy", :info => "System"},
|
68
|
+
{:index => 1, :device => "D:", :label => nil, :filesystem => "NTFS", :type => "Partition", :total_size => 4292870144, :status => "Healthy", :info => nil},
|
69
|
+
{:index => 2, :device => nil, :label => nil, :filesystem => "NTFS", :type => "Partition", :total_size => 4292870144, :status => "Healthy", :info => nil}
|
70
|
+
]
|
71
|
+
|
72
|
+
@platform.volume_manager.send(:parse_volumes, list_vol_resp).should == volume_hash_ary
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'can parse volumes from diskpart output with mounted paths' do
|
76
|
+
list_vol_resp = <<EOF
|
77
|
+
Volume ### Ltr Label Fs Type Size Status Info
|
78
|
+
---------- --- ----------- ----- ---------- ------- --------- --------
|
79
|
+
Volume 0 C NTFS Partition 80 GB Healthy System
|
80
|
+
* Volume 1 FAT32 Partition 1023 MB Healthy
|
81
|
+
C:\\Program Files\\RightScale\\Mount\\Softlayer\\
|
82
|
+
EOF
|
83
|
+
|
84
|
+
volume_hash_ary = [
|
85
|
+
{:index => 0, :device => "C:", :label => nil, :filesystem => "NTFS", :type => "Partition", :total_size => 85899345920, :status => "Healthy", :info => "System"},
|
86
|
+
{:index => 1, :device => "C:\\Program Files\\RightScale\\Mount\\Softlayer\\", :label => nil, :filesystem => "FAT32", :type => "Partition", :total_size => 1072693248, :status => "Healthy", :info => nil}
|
87
|
+
]
|
88
|
+
|
89
|
+
@platform.volume_manager.send(:parse_volumes, list_vol_resp).should == volume_hash_ary
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'raises a parser error when diskpart output is malformed' do
|
93
|
+
list_vol_resp = "foobarbaz"
|
94
|
+
|
95
|
+
lambda { @platform.volume_manager.send(:parse_volumes, list_vol_resp) }.should raise_error(RightScale::Platform::VolumeManager::ParserError)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'can filter results with only one condition' do
|
99
|
+
list_vol_resp = <<EOF
|
100
|
+
Volume ### Ltr Label Fs Type Size Status Info
|
101
|
+
---------- --- ----------- ----- ---------- ------- --------- --------
|
102
|
+
Volume 0 C 2008Boot NTFS Partition 80 GB Healthy System
|
103
|
+
* Volume 1 D NTFS Partition 4094 MB Healthy
|
104
|
+
Volume 2 NTFS Partition 4094 MB Healthy
|
105
|
+
EOF
|
106
|
+
|
107
|
+
volume_hash_ary = [
|
108
|
+
{:index => 1, :device => "D:", :label => nil, :filesystem => "NTFS", :type => "Partition", :total_size => 4292870144, :status => "Healthy", :info => nil}
|
109
|
+
]
|
110
|
+
|
111
|
+
condition = {:device => "D:"}
|
112
|
+
|
113
|
+
@platform.volume_manager.send(:parse_volumes, list_vol_resp, condition).should == volume_hash_ary
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'can filter results with many conditions' do
|
117
|
+
list_vol_resp = <<EOF
|
118
|
+
Volume ### Ltr Label Fs Type Size Status Info
|
119
|
+
---------- --- ----------- ----- ---------- ------- --------- --------
|
120
|
+
Volume 0 C 2008Boot NTFS Partition 80 GB Healthy System
|
121
|
+
* Volume 1 D NTFS Partition 4094 MB Healthy
|
122
|
+
Volume 2 NTFS Partition 4094 MB Healthy
|
123
|
+
EOF
|
124
|
+
|
125
|
+
volume_hash_ary = [
|
126
|
+
{:index => 1, :device => "D:", :label => nil, :filesystem => "NTFS", :type => "Partition", :total_size => 4292870144, :status => "Healthy", :info => nil}
|
127
|
+
]
|
128
|
+
|
129
|
+
condition = {:device => "D:", :filesystem => "NTFS", :type => "Partition"}
|
130
|
+
|
131
|
+
@platform.volume_manager.send(:parse_volumes, list_vol_resp, condition).should == volume_hash_ary
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context :assign_device do
|
136
|
+
it 'assigns a device to a drive letter when a drive letter is specified' do
|
137
|
+
script = <<EOF
|
138
|
+
rescan
|
139
|
+
list volume
|
140
|
+
select volume "0"
|
141
|
+
attribute volume clear readonly noerr
|
142
|
+
assign letter=S
|
143
|
+
EOF
|
144
|
+
|
145
|
+
mount_resp = ''
|
146
|
+
flexmock(@platform.volume_manager).should_receive(:run_script).with(script).once.and_return([0, mount_resp])
|
147
|
+
|
148
|
+
@platform.volume_manager.assign_device('0', 'S:')
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'assigns a device to a path when a mount point is specified' do
|
152
|
+
osinfo = flexmock(:major => 6)
|
153
|
+
|
154
|
+
@platform.volume_manager.extend(OsInfoExtensions)
|
155
|
+
old_osinfo = @platform.volume_manager.get_osinfo
|
156
|
+
@platform.volume_manager.set_osinfo(osinfo)
|
157
|
+
|
158
|
+
script = <<EOF
|
159
|
+
rescan
|
160
|
+
list volume
|
161
|
+
select volume "0"
|
162
|
+
attribute volume clear readonly noerr
|
163
|
+
assign mount="C:\\Program Files\\RightScale\\Mount\\Softlayer"
|
164
|
+
EOF
|
165
|
+
|
166
|
+
flexmock(@platform.volume_manager).should_receive(:run_script).with(script).once.and_return([0, ''])
|
167
|
+
|
168
|
+
@platform.volume_manager.assign_device('0', "C:\\Program Files\\RightScale\\Mount\\Softlayer")
|
169
|
+
@platform.volume_manager.set_osinfo(old_osinfo)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'raises an exception when an invalid drive letter is specified' do
|
173
|
+
lambda{@platform.volume_manager.assign_device('0', 'C:')}.should raise_error(RightScale::Platform::VolumeManager::ArgumentError)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'raises an exception when an invalid path is specified' do
|
177
|
+
lambda{@platform.volume_manager.assign_device('0', 'This is not a path')}.should raise_error(RightScale::Platform::VolumeManager::ArgumentError)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'raises an exception when a mount path is specified and OS is pre 2008' do
|
181
|
+
osinfo = flexmock(:major => 5)
|
182
|
+
|
183
|
+
@platform.volume_manager.extend(OsInfoExtensions)
|
184
|
+
old_osinfo = @platform.volume_manager.get_osinfo
|
185
|
+
@platform.volume_manager.set_osinfo(osinfo)
|
186
|
+
|
187
|
+
lambda{@platform.volume_manager.assign_device(0, "C:\\Somepath")}.should raise_error(RightScale::Platform::VolumeManager::ArgumentError)
|
188
|
+
@platform.volume_manager.set_osinfo(old_osinfo)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context :format_disk do
|
193
|
+
it 'formats and assigns a drive to a drive letter when a drive letter is specified' do
|
194
|
+
osinfo = flexmock(:major => 6)
|
195
|
+
@platform.volume_manager.extend(OsInfoExtensions)
|
196
|
+
old_osinfo = @platform.volume_manager.get_osinfo
|
197
|
+
@platform.volume_manager.set_osinfo(osinfo)
|
198
|
+
|
199
|
+
script = <<EOF
|
200
|
+
rescan
|
201
|
+
list disk
|
202
|
+
select disk 0
|
203
|
+
attribute disk clear readonly noerr
|
204
|
+
online disk noerr
|
205
|
+
clean
|
206
|
+
create partition primary
|
207
|
+
assign letter=S
|
208
|
+
format FS=NTFS quick
|
209
|
+
EOF
|
210
|
+
|
211
|
+
flexmock(@platform.volume_manager).should_receive(:run_script).with(script).once.and_return([0,''])
|
212
|
+
@platform.volume_manager.format_disk(0, 'S:')
|
213
|
+
@platform.volume_manager.set_osinfo(old_osinfo)
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'formats and assigns a drive to a path when a mount point is specified' do
|
217
|
+
osinfo = flexmock(:major => 6)
|
218
|
+
@platform.volume_manager.extend(OsInfoExtensions)
|
219
|
+
old_osinfo = @platform.volume_manager.get_osinfo
|
220
|
+
@platform.volume_manager.set_osinfo(osinfo)
|
221
|
+
|
222
|
+
script = <<EOF
|
223
|
+
rescan
|
224
|
+
list disk
|
225
|
+
select disk 0
|
226
|
+
attribute disk clear readonly noerr
|
227
|
+
online disk noerr
|
228
|
+
clean
|
229
|
+
create partition primary
|
230
|
+
assign mount="C:\\Somepath"
|
231
|
+
format FS=NTFS quick
|
232
|
+
EOF
|
233
|
+
|
234
|
+
flexmock(@platform.volume_manager).should_receive(:run_script).with(script).once.and_return([0,''])
|
235
|
+
@platform.volume_manager.format_disk(0, 'C:\\Somepath')
|
236
|
+
@platform.volume_manager.set_osinfo(old_osinfo)
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'raises an exception when a mount path is specified and OS is pre 2008' do
|
240
|
+
osinfo = flexmock(:major => 5)
|
241
|
+
|
242
|
+
@platform.volume_manager.extend(OsInfoExtensions)
|
243
|
+
old_osinfo = @platform.volume_manager.get_osinfo
|
244
|
+
@platform.volume_manager.set_osinfo(osinfo)
|
245
|
+
|
246
|
+
lambda{@platform.volume_manager.format_disk(0, "C:\\Somepath")}.should raise_error(RightScale::Platform::VolumeManager::ArgumentError)
|
247
|
+
@platform.volume_manager.set_osinfo(old_osinfo)
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
@@ -104,14 +104,18 @@ describe RightScale::Serializer do
|
|
104
104
|
serializer = RightScale::Serializer.new(:msgpack)
|
105
105
|
date = Date.today
|
106
106
|
data = serializer.dump(date)
|
107
|
-
Date.
|
107
|
+
Date.strptime(serializer.load(data), "%Y-%m-%d").should == date
|
108
108
|
end
|
109
109
|
|
110
110
|
it "should serialize Time object" do
|
111
111
|
serializer = RightScale::Serializer.new(:msgpack)
|
112
112
|
time = Time.now
|
113
113
|
data = serializer.dump(time)
|
114
|
-
|
114
|
+
if RUBY_VERSION < "1.9.0"
|
115
|
+
Time.parse(serializer.load(data)).to_i.should == time.to_i
|
116
|
+
else
|
117
|
+
DateTime.parse(serializer.load(data)).to_time.to_i.should == time.to_i
|
118
|
+
end
|
115
119
|
end
|
116
120
|
|
117
121
|
it "should serialize DateTime object" do
|
@@ -0,0 +1 @@
|
|
1
|
+
--format=nested
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 51
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 10
|
9
|
+
- 2
|
10
|
+
version: 0.10.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Lee Kirchhoff
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2012-
|
20
|
+
date: 2012-05-01 00:00:00 -07:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
@@ -41,11 +41,11 @@ dependencies:
|
|
41
41
|
requirements:
|
42
42
|
- - ~>
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
hash:
|
44
|
+
hash: 13
|
45
45
|
segments:
|
46
46
|
- 0
|
47
|
-
-
|
48
|
-
version: "0.
|
47
|
+
- 3
|
48
|
+
version: "0.3"
|
49
49
|
requirement: *id002
|
50
50
|
name: right_amqp
|
51
51
|
prerelease: false
|
@@ -271,6 +271,7 @@ files:
|
|
271
271
|
- spec/platform/linux_volume_manager_spec.rb
|
272
272
|
- spec/platform/platform_spec.rb
|
273
273
|
- spec/platform/windows.rb
|
274
|
+
- spec/platform/windows_volume_manager_spec.rb
|
274
275
|
- spec/results_mock.rb
|
275
276
|
- spec/secure_identity_spec.rb
|
276
277
|
- spec/security/cached_certificate_store_proxy_spec.rb
|
@@ -287,6 +288,7 @@ files:
|
|
287
288
|
- spec/serialize/serializable_spec.rb
|
288
289
|
- spec/serialize/serializer_spec.rb
|
289
290
|
- spec/spec.opts
|
291
|
+
- spec/spec.win32.opts
|
290
292
|
- spec/spec_helper.rb
|
291
293
|
- spec/tracer_spec.rb
|
292
294
|
has_rdoc: true
|