slotz 0.1
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.
- checksums.yaml +7 -0
- data/Gemfile +19 -0
- data/LICENSE.md +29 -0
- data/README.md +3 -0
- data/lib/slotz/options.rb +13 -0
- data/lib/slotz/reservation.rb +43 -0
- data/lib/slotz/system/application.rb +40 -0
- data/lib/slotz/system/platforms/base.rb +74 -0
- data/lib/slotz/system/platforms/linux.rb +26 -0
- data/lib/slotz/system/platforms/mixins/unix.rb +46 -0
- data/lib/slotz/system/platforms/osx.rb +25 -0
- data/lib/slotz/system/platforms/windows.rb +81 -0
- data/lib/slotz/system/platforms.rb +12 -0
- data/lib/slotz/system.rb +241 -0
- data/lib/slotz/version.rb +3 -0
- data/lib/slotz.rb +35 -0
- data/slotz.gemspec +41 -0
- data/spec/slotz/system/platforms/linux_spec.rb +31 -0
- data/spec/slotz/system/platforms/osx_spec.rb +32 -0
- data/spec/slotz/system/platforms/windows_spec.rb +41 -0
- data/spec/slotz/system/slotz_spec.rb +155 -0
- data/spec/slotz/system_spec.rb +88 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/helpers/paths.rb +15 -0
- data/spec/support/shared/system/platforms/base.rb +19 -0
- data/spec/support/shared/system/platforms/mixins/unix.rb +37 -0
- metadata +149 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 1829fa39dcca433a7c74867bde89d53f70447c4c72c7abd54fb7ef4e68a73c87
|
|
4
|
+
data.tar.gz: acc87fb694a334b2fbaabf99bb4c608ee6fd9fa168f4f143c2087fd4e86e4f2d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: cae56d7e4293d7b3152dd353127ef550b089fefb49aea0e3b83cb48e41a67fee0f9a3e7d2f2166872791ceebcabe5066039ecb5969f64063e4a8358fd0ef2a68
|
|
7
|
+
data.tar.gz: 05e01352f292781b59cd23cc4fc0ae665ff718d4c1451c8afefdbcd1c9c3c9149e1bc9ccc6cab42ee97d3a89fbd9a3b62d9f61b67c9de671760a2a9438c62ea1
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# License
|
|
2
|
+
|
|
3
|
+
Copyright (C) 2025, Anastasios Laskos <mailto:anastasios.laskos@gmail.com>
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
7
|
+
are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright notice,
|
|
10
|
+
this list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name of the copyright holder nor the names of its contributors
|
|
17
|
+
may be used to endorse or promote products derived from this software
|
|
18
|
+
without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
21
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
22
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
24
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
25
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
26
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
27
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
28
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
29
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Slotz
|
|
2
|
+
|
|
3
|
+
class Reservation < Module
|
|
4
|
+
|
|
5
|
+
attr_reader :disk
|
|
6
|
+
attr_reader :memory
|
|
7
|
+
attr_reader :cores
|
|
8
|
+
|
|
9
|
+
def initialize( provision )
|
|
10
|
+
@provision = provision
|
|
11
|
+
|
|
12
|
+
ObjectSpace.define_finalizer(self, proc {
|
|
13
|
+
Slotz::RESERVED[:disk] -= self.class.disk
|
|
14
|
+
Slotz::RESERVED[:memory] -= self.class.memory
|
|
15
|
+
Slotz::RESERVED[:cores] -= self.class.cores
|
|
16
|
+
})
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def included( base )
|
|
20
|
+
provisions = @provision
|
|
21
|
+
base.class_eval do
|
|
22
|
+
@disk = provisions[:disk]
|
|
23
|
+
def self.disk
|
|
24
|
+
@disk
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
@memory = provisions[:memory]
|
|
28
|
+
def self.memory
|
|
29
|
+
@memory
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
@cores = provisions[:cores]
|
|
33
|
+
def self.cores
|
|
34
|
+
@cores
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Slotz.filter base
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Slotz
|
|
2
|
+
|
|
3
|
+
class Application
|
|
4
|
+
|
|
5
|
+
attr_reader :klass
|
|
6
|
+
attr_reader :requirements
|
|
7
|
+
|
|
8
|
+
def initialize( klass, requirements = {} )
|
|
9
|
+
@klass = klass
|
|
10
|
+
@requirements = requirements
|
|
11
|
+
|
|
12
|
+
Slotz.occupy self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def disk
|
|
16
|
+
@requirements[:disk]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def remaining_disk
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def cores
|
|
24
|
+
@requirements[:cores]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def remaining_cores
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def memory
|
|
32
|
+
@requirements[:memory]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def remaining_memory
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'concurrent'
|
|
2
|
+
require 'tmpdir'
|
|
3
|
+
|
|
4
|
+
module Slotz
|
|
5
|
+
|
|
6
|
+
class System
|
|
7
|
+
module Platforms
|
|
8
|
+
|
|
9
|
+
class Base
|
|
10
|
+
class <<self
|
|
11
|
+
|
|
12
|
+
# @private
|
|
13
|
+
def inherited( platform )
|
|
14
|
+
System.register_platform platform
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [Bool]
|
|
18
|
+
# `true` if it's the current platform, `false` otherwise.
|
|
19
|
+
#
|
|
20
|
+
# @abstract
|
|
21
|
+
def current?
|
|
22
|
+
raise 'Missing implementation'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [Integer]
|
|
27
|
+
# Amount of free RAM in bytes.
|
|
28
|
+
#
|
|
29
|
+
# @abstract
|
|
30
|
+
def memory_free
|
|
31
|
+
raise 'Missing implementation'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @param [Integer] pgid
|
|
35
|
+
# Process group ID.
|
|
36
|
+
#
|
|
37
|
+
# @return [Integer]
|
|
38
|
+
# Amount of RAM in bytes used by the given GPID.
|
|
39
|
+
#
|
|
40
|
+
# @abstract
|
|
41
|
+
def memory_for_process_group( pgid )
|
|
42
|
+
raise 'Missing implementation'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [Integer]
|
|
46
|
+
# Amount of free disk in bytes.
|
|
47
|
+
#
|
|
48
|
+
# @abstract
|
|
49
|
+
def disk_space_free
|
|
50
|
+
raise 'Missing implementation'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @return [String
|
|
54
|
+
# Location for temporary file storage.
|
|
55
|
+
def disk_directory
|
|
56
|
+
Dir.tmpdir
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [Integer]
|
|
60
|
+
# Amount of CPU cores.
|
|
61
|
+
def cpu_count
|
|
62
|
+
Concurrent.processor_count
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @private
|
|
66
|
+
def _exec( cmd )
|
|
67
|
+
%x(#{cmd})
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_relative 'mixins/unix'
|
|
2
|
+
|
|
3
|
+
module Slotz
|
|
4
|
+
|
|
5
|
+
class System
|
|
6
|
+
module Platforms
|
|
7
|
+
class Linux < Base
|
|
8
|
+
include Mixins::Unix
|
|
9
|
+
|
|
10
|
+
# @return [Integer]
|
|
11
|
+
# Amount of free RAM in bytes.
|
|
12
|
+
def memory_free
|
|
13
|
+
memory.available_bytes
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class <<self
|
|
17
|
+
def current?
|
|
18
|
+
Slotz::System.linux?
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'vmstat'
|
|
2
|
+
|
|
3
|
+
module Slotz
|
|
4
|
+
class System
|
|
5
|
+
module Platforms
|
|
6
|
+
module Mixins
|
|
7
|
+
|
|
8
|
+
module Unix
|
|
9
|
+
|
|
10
|
+
# @param [Integer] pgid
|
|
11
|
+
# Process group ID.
|
|
12
|
+
#
|
|
13
|
+
# @return [Integer]
|
|
14
|
+
# Amount of RAM in bytes used by the given GPID.
|
|
15
|
+
def memory_for_process_group( pgid )
|
|
16
|
+
rss = 0
|
|
17
|
+
|
|
18
|
+
_exec( "ps -o rss -g #{pgid}" ).split("\n")[1..-1].each do |rss_string|
|
|
19
|
+
rss += rss_string.to_i
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
rss * pagesize
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Integer]
|
|
26
|
+
# Amount of free disk in bytes.
|
|
27
|
+
def disk_space_free
|
|
28
|
+
Vmstat.disk( disk_directory ).available_bytes
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def pagesize
|
|
34
|
+
@pagesize ||= memory.pagesize
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def memory
|
|
38
|
+
Vmstat.memory
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require_relative 'mixins/unix'
|
|
2
|
+
|
|
3
|
+
module Slotz
|
|
4
|
+
|
|
5
|
+
class System
|
|
6
|
+
module Platforms
|
|
7
|
+
class OSX < Base
|
|
8
|
+
include Mixins::Unix
|
|
9
|
+
|
|
10
|
+
# @return [Integer]
|
|
11
|
+
# Amount of free RAM in bytes.
|
|
12
|
+
def memory_free
|
|
13
|
+
pagesize * memory.free
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class <<self
|
|
17
|
+
def current?
|
|
18
|
+
Slotz::System.mac?
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module Slotz
|
|
2
|
+
|
|
3
|
+
class System
|
|
4
|
+
module Platforms
|
|
5
|
+
|
|
6
|
+
class Windows < Base
|
|
7
|
+
|
|
8
|
+
class <<self
|
|
9
|
+
def current?
|
|
10
|
+
Slotz::System.windows?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @return [Integer]
|
|
15
|
+
# Amount of free RAM in bytes.
|
|
16
|
+
def memory_free
|
|
17
|
+
result = wmi.ExecQuery(
|
|
18
|
+
'select AvailableBytes from Win32_PerfFormattedData_PerfOS_Memory'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
memory = nil
|
|
22
|
+
result.each do |e|
|
|
23
|
+
memory = e.availableBytes.to_i
|
|
24
|
+
e.ole_free
|
|
25
|
+
end
|
|
26
|
+
result.ole_free
|
|
27
|
+
|
|
28
|
+
memory
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @param [Integer] pgid
|
|
32
|
+
# Process group ID.
|
|
33
|
+
#
|
|
34
|
+
# @return [Integer]
|
|
35
|
+
# Amount of RAM in bytes used by the given GPID.
|
|
36
|
+
def memory_for_process_group( pgid )
|
|
37
|
+
processes = wmi.ExecQuery(
|
|
38
|
+
"select PrivatePageCount from win32_process where ProcessID='#{pgid}' or ParentProcessID='#{pgid}'"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
memory = 0
|
|
42
|
+
processes.each do |process|
|
|
43
|
+
# Not actually pages but bytes, no idea why.
|
|
44
|
+
memory += process.privatePageCount.to_i
|
|
45
|
+
process.ole_free
|
|
46
|
+
end
|
|
47
|
+
processes.ole_free
|
|
48
|
+
|
|
49
|
+
memory
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @return [Integer]
|
|
53
|
+
# Amount of free disk in bytes.
|
|
54
|
+
def disk_space_free
|
|
55
|
+
device_id = disk_directory.split( '/' ).first
|
|
56
|
+
|
|
57
|
+
drives = wmi.ExecQuery(
|
|
58
|
+
"select FreeSpace from win32_LogicalDisk where DeviceID='#{device_id}'"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
space = nil
|
|
62
|
+
drives.each do |drive|
|
|
63
|
+
space = drive.freeSpace.to_i
|
|
64
|
+
drive.ole_free
|
|
65
|
+
end
|
|
66
|
+
drives.ole_free
|
|
67
|
+
|
|
68
|
+
space
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def wmi
|
|
74
|
+
@wmi ||= WIN32OLE.connect( 'winmgmts://' )
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
data/lib/slotz/system.rb
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
require_relative 'system/platforms/base'
|
|
2
|
+
require 'singleton'
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
5
|
+
module Slotz
|
|
6
|
+
|
|
7
|
+
class System
|
|
8
|
+
include Singleton
|
|
9
|
+
|
|
10
|
+
# @return [Bool]
|
|
11
|
+
def self.windows?
|
|
12
|
+
@is_windows ||= Gem.win_platform?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [Bool]
|
|
16
|
+
def self.linux?
|
|
17
|
+
@is_linux ||= RbConfig::CONFIG['host_os'] =~ /linux/
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @return [Bool]
|
|
21
|
+
def self.mac?
|
|
22
|
+
@is_mac ||= RbConfig::CONFIG['host_os'] =~ /darwin|mac os/i
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Array<Platforms::Base>]
|
|
26
|
+
attr_reader :platforms
|
|
27
|
+
|
|
28
|
+
# @return [Slots]
|
|
29
|
+
attr_reader :slots
|
|
30
|
+
|
|
31
|
+
attr_accessor :max_slots
|
|
32
|
+
|
|
33
|
+
def initialize
|
|
34
|
+
@platforms = []
|
|
35
|
+
@pids = Set.new
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def use( pid )
|
|
39
|
+
@pids << pid
|
|
40
|
+
pid
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [Integer]
|
|
44
|
+
# Amount of new applications that can be safely run in parallel, currently.
|
|
45
|
+
# User option will override decision based on system resources.
|
|
46
|
+
def available
|
|
47
|
+
# Manual mode, user gave us a value.
|
|
48
|
+
if (max_slots = System.max_slots)
|
|
49
|
+
max_slots - used
|
|
50
|
+
|
|
51
|
+
# Auto-mode, pick the safest restriction, RAM vs CPU.
|
|
52
|
+
else
|
|
53
|
+
available_auto
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @return [Integer]
|
|
58
|
+
# Amount of new applications that can be safely run in parallel, currently.
|
|
59
|
+
# The decision is based on the available resources alone.
|
|
60
|
+
def available_auto( requirements )
|
|
61
|
+
[ available_in_memory( requirements[:memory] ),
|
|
62
|
+
available_in_cpu( requirements[:cores] ),
|
|
63
|
+
available_in_disk( requirements[:disk] ) ].min
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [Integer]
|
|
67
|
+
# Amount of instances that are currently alive.
|
|
68
|
+
def used
|
|
69
|
+
Slotz.applications.size
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [Integer]
|
|
73
|
+
# Amount of scans that can be safely run in parallel, in total.
|
|
74
|
+
def total
|
|
75
|
+
used + available
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def fits?( requirements )
|
|
79
|
+
available_auto( requirements )
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @return [Integer]
|
|
83
|
+
# Amount of processes we can fit into the available memory.
|
|
84
|
+
#
|
|
85
|
+
# Works based on slots, available memory isn't currently available OS
|
|
86
|
+
# memory but memory that is unallocated.
|
|
87
|
+
def available_in_memory( memory )
|
|
88
|
+
return Float::INFINITY if memory.to_i == 0
|
|
89
|
+
(unallocated_memory / memory).to_i
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @return [Integer]
|
|
93
|
+
# Amount of CPU cores that are available.
|
|
94
|
+
#
|
|
95
|
+
# Well, they may not be really available, other stuff on the machine could
|
|
96
|
+
# be using them to a considerable extent, but we can only do so much.
|
|
97
|
+
def available_in_cpu( cores )
|
|
98
|
+
@system.cpu_count - used
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @param [Integer] pid
|
|
102
|
+
#
|
|
103
|
+
# @return [Integer]
|
|
104
|
+
# Remaining memory for the scan, in bytes.
|
|
105
|
+
def remaining_memory_for( pid )
|
|
106
|
+
[memory_size - @system.memory_for_process_group( pid ), 0].max
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @return [Integer]
|
|
110
|
+
# Amount of memory (in bytes) available for future scans.
|
|
111
|
+
def unallocated_memory
|
|
112
|
+
# Available memory right now.
|
|
113
|
+
available_mem = @system.memory_free
|
|
114
|
+
|
|
115
|
+
# Remove allocated memory to figure out how much we can really spare.
|
|
116
|
+
@pids.each do |pid|
|
|
117
|
+
# Mark the remaining allocated memory as unavailable.
|
|
118
|
+
available_mem -= remaining_memory_for( pid )
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
available_mem
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @param [Integer] pid
|
|
125
|
+
#
|
|
126
|
+
# @return [Integer]
|
|
127
|
+
# Remaining disk space for the scan, in bytes.
|
|
128
|
+
def remaining_disk_space_for( pid )
|
|
129
|
+
[disk_space - @system.disk_space_for_process( pid ), 0].max
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# @return [Integer]
|
|
133
|
+
# Amount of disk space (in bytes) available for future scans.
|
|
134
|
+
def unallocated_disk_space
|
|
135
|
+
# Available space right now.
|
|
136
|
+
available_space = @system.disk_space_free
|
|
137
|
+
|
|
138
|
+
# # Remove allocated space to figure out how much we can really spare.
|
|
139
|
+
# @pids.each do |pid|
|
|
140
|
+
# # Mark the remaining allocated space as unavailable.
|
|
141
|
+
# available_space -= remaining_disk_space_for( pid )
|
|
142
|
+
# end
|
|
143
|
+
|
|
144
|
+
available_space
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def disk_space_requirement( application )
|
|
148
|
+
application.disk.to_i
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @return [Fixnum]
|
|
152
|
+
# Amount of memory (in bytes) to allocate.
|
|
153
|
+
def memory_requirement( application )
|
|
154
|
+
application.memory.to_i
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# @return [Integer]
|
|
158
|
+
# Amount of free RAM in bytes.
|
|
159
|
+
def memory_free
|
|
160
|
+
platform.memory_free
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# @param [Integer] pgid
|
|
164
|
+
# Process group ID.
|
|
165
|
+
#
|
|
166
|
+
# @return [Integer]
|
|
167
|
+
# Amount of RAM in bytes used by the given GPID.
|
|
168
|
+
def memory_for_process_group( pgid )
|
|
169
|
+
platform.memory_for_process_group( pgid )
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# @return [Integer]
|
|
173
|
+
# Amount of free disk space in bytes.
|
|
174
|
+
def disk_space_free
|
|
175
|
+
platform.disk_space_free
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# @return [String
|
|
179
|
+
# Location for temporary file storage.
|
|
180
|
+
def disk_directory
|
|
181
|
+
platform.disk_directory
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# @param [Integer] pid
|
|
185
|
+
# Process ID.
|
|
186
|
+
#
|
|
187
|
+
# @return [Integer]
|
|
188
|
+
# Amount of disk space in bytes used by the given PID.
|
|
189
|
+
def disk_space_for_process( pid )
|
|
190
|
+
platform.disk_space_for_process( pid )
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# @return [Integer]
|
|
194
|
+
# Amount of CPU cores.
|
|
195
|
+
def cpu_count
|
|
196
|
+
@cpu_count ||= platform.cpu_count
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# @return [Platforms::Base]
|
|
200
|
+
def platform
|
|
201
|
+
return @platform if @platform
|
|
202
|
+
|
|
203
|
+
platforms.each do |klass|
|
|
204
|
+
next if !klass.current?
|
|
205
|
+
|
|
206
|
+
return @platform = klass.new
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
raise "Unsupported platform: #{RUBY_PLATFORM}"
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# @private
|
|
213
|
+
def register_platform( platform )
|
|
214
|
+
platforms << platform
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# @private
|
|
218
|
+
def reset
|
|
219
|
+
@pids.clear
|
|
220
|
+
@cpu_count = nil
|
|
221
|
+
@platform = nil
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
class <<self
|
|
225
|
+
def method_missing( sym, *args, &block )
|
|
226
|
+
if instance.respond_to?( sym )
|
|
227
|
+
instance.send( sym, *args, &block )
|
|
228
|
+
else
|
|
229
|
+
super( sym, *args, &block )
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def respond_to?( *args )
|
|
234
|
+
super || instance.respond_to?( *args )
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
require_relative 'system/platforms'
|
data/lib/slotz.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Slotz
|
|
2
|
+
require_relative 'slotz/version'
|
|
3
|
+
require_relative 'slotz/options'
|
|
4
|
+
require_relative 'slotz/system'
|
|
5
|
+
require_relative 'slotz/reservation'
|
|
6
|
+
|
|
7
|
+
RESERVED = {
|
|
8
|
+
disk: 0,
|
|
9
|
+
memory: 0,
|
|
10
|
+
cores: 0
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
def self.filter( reservation )
|
|
14
|
+
# fail 'Max utilization.' if Slotz::System.max_utilization?
|
|
15
|
+
|
|
16
|
+
if RESERVED[:disk] + reservation.disk <= System.disk_space_free
|
|
17
|
+
RESERVED[:disk] += reservation.disk
|
|
18
|
+
else
|
|
19
|
+
fail 'Not enough disk resources.'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if RESERVED[:memory] + reservation.memory <= System.memory_free
|
|
23
|
+
RESERVED[:memory] += reservation.memory
|
|
24
|
+
else
|
|
25
|
+
fail 'Not enough memory resources.'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# if RESERVED[:cores] + requirements[:cores] <= System.cores
|
|
29
|
+
# RESERVED[:cores] += requirements[:cores]
|
|
30
|
+
# else
|
|
31
|
+
# fail 'Not enough CPU resources.'
|
|
32
|
+
# end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
data/slotz.gemspec
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
require_relative File.expand_path( File.dirname( __FILE__ ) ) + '/lib/slotz/version'
|
|
5
|
+
|
|
6
|
+
s.name = 'slotz'
|
|
7
|
+
s.version = Slotz::VERSION
|
|
8
|
+
s.date = Time.now.strftime( '%Y-%m-%d' )
|
|
9
|
+
s.summary = 'An application-centric, decentralised and distributed computing solution. '
|
|
10
|
+
|
|
11
|
+
s.homepage = 'https://github.com/qadron/cuboid'
|
|
12
|
+
s.email = 'tasos.laskos@gmail.com'
|
|
13
|
+
s.authors = [ 'Tasos Laskos' ]
|
|
14
|
+
s.licenses = ['MIT']
|
|
15
|
+
|
|
16
|
+
s.files += Dir.glob( 'config/**/**' )
|
|
17
|
+
s.files += Dir.glob( 'lib/**/**' )
|
|
18
|
+
s.files += Dir.glob( 'logs/**/**' )
|
|
19
|
+
s.files += Dir.glob( 'components/**/**' )
|
|
20
|
+
s.files += Dir.glob( 'spec/**/**' )
|
|
21
|
+
s.files += %w(Gemfile slotz.gemspec)
|
|
22
|
+
s.test_files = Dir.glob( 'spec/**/**' )
|
|
23
|
+
|
|
24
|
+
s.extra_rdoc_files = %w(README.md LICENSE.md)
|
|
25
|
+
|
|
26
|
+
s.rdoc_options = [ '--charset=UTF-8' ]
|
|
27
|
+
|
|
28
|
+
s.add_dependency 'awesome_print', '1.9.2'
|
|
29
|
+
|
|
30
|
+
# Don't specify version, messes with the packages since they always grab the
|
|
31
|
+
# latest one.
|
|
32
|
+
s.add_dependency 'bundler'
|
|
33
|
+
|
|
34
|
+
s.add_dependency 'concurrent-ruby'
|
|
35
|
+
s.add_dependency 'vmstat', '~> 2.3.1'
|
|
36
|
+
s.add_dependency 'sys-proctable', '~> 1.3.0'
|
|
37
|
+
|
|
38
|
+
s.description = <<DESCRIPTION
|
|
39
|
+
DESCRIPTION
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Slotz::System::Platforms::Linux do
|
|
4
|
+
it_should_behave_like 'Slotz::System::Platforms::Mixins::Unix'
|
|
5
|
+
|
|
6
|
+
describe '#memory_free' do
|
|
7
|
+
it 'returns the amount of free memory' do
|
|
8
|
+
o = Object.new
|
|
9
|
+
expect(o).to receive(:available_bytes).and_return(1000)
|
|
10
|
+
expect(subject).to receive(:memory).at_least(:once).and_return(o)
|
|
11
|
+
|
|
12
|
+
expect(subject.memory_free).to eq 1000
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '.current?' do
|
|
17
|
+
context 'when running on Linux' do
|
|
18
|
+
it 'returns true' do
|
|
19
|
+
expect(Slotz::System).to receive(:linux?).and_return( true )
|
|
20
|
+
expect(described_class).to be_current
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'when not running on Linux' do
|
|
25
|
+
it 'returns false' do
|
|
26
|
+
expect(Slotz::System).to receive(:linux?).and_return( false )
|
|
27
|
+
expect(described_class).to_not be_current
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Slotz::System::Platforms::OSX do
|
|
4
|
+
it_should_behave_like 'Slotz::System::Platforms::Mixins::Unix'
|
|
5
|
+
|
|
6
|
+
describe '#memory_free' do
|
|
7
|
+
it 'returns the amount of free memory' do
|
|
8
|
+
o = Object.new
|
|
9
|
+
expect(o).to receive(:free).and_return(1000)
|
|
10
|
+
expect(o).to receive(:pagesize).and_return(4096)
|
|
11
|
+
expect(subject).to receive(:memory).at_least(:once).and_return(o)
|
|
12
|
+
|
|
13
|
+
expect(subject.memory_free).to eq 4096000
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '.current?' do
|
|
18
|
+
context 'when running on OSX' do
|
|
19
|
+
it 'returns true' do
|
|
20
|
+
expect(Slotz::System).to receive(:mac?).and_return( true )
|
|
21
|
+
expect(described_class).to be_current
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'when not running on OSX' do
|
|
26
|
+
it 'returns false' do
|
|
27
|
+
expect(Slotz::System).to receive(:mac?).and_return( false )
|
|
28
|
+
expect(described_class).to_not be_current
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Slotz::System::Platforms::Windows, if: Slotz::System.windows? do
|
|
4
|
+
it_should_behave_like 'Slotz::System::Platforms::Base'
|
|
5
|
+
|
|
6
|
+
subject { described_class.new }
|
|
7
|
+
|
|
8
|
+
describe '#memory_free' do
|
|
9
|
+
it 'returns the amount of free memory' do
|
|
10
|
+
expect(subject.memory_free).to be > 0
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '#disk_space_free' do
|
|
15
|
+
it 'returns the amount of free disk space' do
|
|
16
|
+
expect(subject.disk_space_free).to be > 0
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#memory_for_process_group' do
|
|
21
|
+
it 'returns bytes of memory used by the group' do
|
|
22
|
+
expect(subject.memory_for_process_group( Process.pid )).to be > 0
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '.current?' do
|
|
27
|
+
context 'when running on Windows' do
|
|
28
|
+
it 'returns true'do
|
|
29
|
+
expect(Slotz).to receive(:windows?).and_return( true )
|
|
30
|
+
expect(described_class).to be_current
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'when not running on Windows' do
|
|
35
|
+
it 'returns false' do
|
|
36
|
+
expect(Slotz).to receive(:windows?).and_return( false )
|
|
37
|
+
expect(described_class).to_not be_current
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Slotz do
|
|
4
|
+
subject { system }
|
|
5
|
+
let(:system) { Slotz::System.instance }
|
|
6
|
+
|
|
7
|
+
before :each do
|
|
8
|
+
subject.reset
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#available' do
|
|
12
|
+
context 'when OptionGroups::system#max_slots is set' do
|
|
13
|
+
before do
|
|
14
|
+
Slotz::System.max_slots = 5
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'uses it to calculate available slots' do
|
|
18
|
+
expect(subject.available).to eq 5
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'when some slots have been used' do
|
|
22
|
+
it 'subtracts them' do
|
|
23
|
+
allow(subject).to receive(:used).and_return( 2 )
|
|
24
|
+
expect(subject.available).to eq 3
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'when OptionGroups::system#max_slots is not set' do
|
|
30
|
+
before do
|
|
31
|
+
Slotz::System.max_slots = nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'uses #available_auto' do
|
|
35
|
+
pending
|
|
36
|
+
expect(subject).to receive(:available_auto).and_return( 25 )
|
|
37
|
+
expect(subject.available).to eq 25
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe '#available_auto' do
|
|
43
|
+
before do
|
|
44
|
+
Slotz::System.max_slots = nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'calculates slots based on previously reserved resources' do
|
|
48
|
+
pending
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'when restricted by memory' do
|
|
52
|
+
it 'bases the calculation on memory slots' do
|
|
53
|
+
pending
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'when restricted by CPUs' do
|
|
58
|
+
it 'bases the calculation on CPU slots' do
|
|
59
|
+
pending
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context 'when restricted by disk space' do
|
|
64
|
+
it 'bases the calculation on disk space' do
|
|
65
|
+
pending
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe '#used' do
|
|
71
|
+
it 'returns the amount of active instances' do
|
|
72
|
+
pending
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context 'when a process dies' do
|
|
76
|
+
it 'gets removed from the count'
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe '#total' do
|
|
81
|
+
it 'sums up free and used slots' do
|
|
82
|
+
expect(subject).to receive(:available).and_return( 3 )
|
|
83
|
+
expect(subject).to receive(:used).and_return( 5 )
|
|
84
|
+
|
|
85
|
+
expect(subject.total).to eq 8
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe '#available_in_memory' do
|
|
90
|
+
it 'returns amount of free memory slots' do
|
|
91
|
+
pending
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
describe '#available_in_cpu' do
|
|
96
|
+
it 'returns amount of free CPUs splots' do
|
|
97
|
+
pending
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe '#unallocated_memory' do
|
|
102
|
+
context 'when there are no scans running' do
|
|
103
|
+
it 'returns the amount of free memory' do
|
|
104
|
+
pending
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context 'when there are scans running' do
|
|
109
|
+
context 'using part of their allocation' do
|
|
110
|
+
it 'removes their allocated slots' do
|
|
111
|
+
pending
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe '#remaining_memory_for' do
|
|
118
|
+
it 'returns the amount of allocated memory available to the scan' do
|
|
119
|
+
pending
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
describe '#unallocated_disk_space' do
|
|
124
|
+
context 'when there are no scans running' do
|
|
125
|
+
it 'returns the amount of free disk space' do
|
|
126
|
+
pending
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context 'when there are scans running' do
|
|
131
|
+
context 'using part of their allocation' do
|
|
132
|
+
it 'removes their allocated slots' do
|
|
133
|
+
pending
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
describe '#remaining_disk_space_for' do
|
|
140
|
+
it 'returns the amount of allocated disk space available to the scan' do
|
|
141
|
+
pending
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe '#memory_size' do
|
|
146
|
+
before do
|
|
147
|
+
# Slotz::Options.reset
|
|
148
|
+
end
|
|
149
|
+
let(:memory_size) { subject.memory_size }
|
|
150
|
+
|
|
151
|
+
it 'is approx 0.2GB with default options' do
|
|
152
|
+
pending
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Slotz::System do
|
|
4
|
+
subject { described_class.instance }
|
|
5
|
+
|
|
6
|
+
describe '#memory_free' do
|
|
7
|
+
it 'delegates to #platform' do
|
|
8
|
+
expect(subject.platform).to receive(:memory_free).and_return(10)
|
|
9
|
+
expect(subject.memory_free).to eq 10
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#memory_for_process_group' do
|
|
14
|
+
it 'delegates to #platform' do
|
|
15
|
+
expect(subject.platform).to receive(:memory_for_process_group).with(123).and_return(10)
|
|
16
|
+
expect(subject.memory_for_process_group(123)).to eq 10
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#disk_space_free' do
|
|
21
|
+
it 'delegates to #platform' do
|
|
22
|
+
expect(subject.platform).to receive(:disk_space_free).and_return(10)
|
|
23
|
+
expect(subject.disk_space_free).to eq 10
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe '#disk_space_for_process' do
|
|
28
|
+
it 'delegates to #platform' do
|
|
29
|
+
expect(subject.platform).to receive(:disk_space_for_process).with(123).and_return(10)
|
|
30
|
+
expect(subject.disk_space_for_process(123)).to eq 10
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '#disk_directory' do
|
|
35
|
+
it "delegates to #platform" do
|
|
36
|
+
expect(subject.platform).to receive(:disk_directory).and_return('10')
|
|
37
|
+
expect(subject.disk_directory).to eq '10'
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe '#cpu_count' do
|
|
42
|
+
it 'delegates to #platform' do
|
|
43
|
+
expect(subject.platform).to receive(:cpu_count).and_return(10)
|
|
44
|
+
expect(subject.cpu_count).to eq 10
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe '#platform' do
|
|
49
|
+
it 'returns the current platform' do
|
|
50
|
+
pending
|
|
51
|
+
platform_stub = Class.new do
|
|
52
|
+
def self.current?
|
|
53
|
+
true
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
subject.platforms.unshift platform_stub
|
|
58
|
+
|
|
59
|
+
expect(subject.platform).to be_instance_of platform_stub
|
|
60
|
+
|
|
61
|
+
subject.platforms.delete platform_stub
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context 'when the platform could not be identified' do
|
|
65
|
+
it 'raises error' do
|
|
66
|
+
pending
|
|
67
|
+
subject.platforms.each do |platform|
|
|
68
|
+
expect(platform).to receive(:current?).and_return(false)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
expect do
|
|
72
|
+
subject.platform
|
|
73
|
+
end.to raise_error "Unsupported platform: #{RUBY_PLATFORM}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe '#platforms' do
|
|
79
|
+
it 'returns all supported platforms' do
|
|
80
|
+
pending
|
|
81
|
+
expect(subject.platforms.map(&:to_s).sort).to eq [
|
|
82
|
+
described_class::Platforms::Linux,
|
|
83
|
+
described_class::Platforms::OSX,
|
|
84
|
+
described_class::Platforms::Windows
|
|
85
|
+
].map(&:to_s).sort
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require_relative 'support/helpers/paths'
|
|
2
|
+
|
|
3
|
+
Dir.glob( "#{support_path}/{lib,helpers,shared,factories}/**/*.rb" ).each { |f| require f }
|
|
4
|
+
|
|
5
|
+
RSpec::Core::MemoizedHelpers.module_eval do
|
|
6
|
+
alias to should
|
|
7
|
+
alias to_not should_not
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
RSpec.configure do |config|
|
|
11
|
+
config.run_all_when_everything_filtered = true
|
|
12
|
+
config.color = true
|
|
13
|
+
config.add_formatter :documentation
|
|
14
|
+
config.alias_example_to :expect_it
|
|
15
|
+
config.filter_run_when_matching focus: true
|
|
16
|
+
|
|
17
|
+
config.mock_with :rspec do |mocks|
|
|
18
|
+
mocks.yield_receiver_to_any_instance_implementation_blocks = true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
config.before( :each ) do
|
|
22
|
+
# reset_all
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
config.after( :each ) do
|
|
26
|
+
# cleanup_instances
|
|
27
|
+
# processes_killall
|
|
28
|
+
end
|
|
29
|
+
config.after( :all ) do
|
|
30
|
+
# killall
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
def name_from_filename
|
|
2
|
+
File.basename( caller.first.split( ':' ).first, '_spec.rb' )
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
def spec_path
|
|
6
|
+
File.expand_path( File.dirname( File.absolute_path( __FILE__ ) ) + '/../../' ) + '/'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def support_path
|
|
10
|
+
"#{spec_path}support/"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def fixtures_path
|
|
14
|
+
"#{support_path}fixtures/"
|
|
15
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'tmpdir'
|
|
2
|
+
|
|
3
|
+
shared_examples_for 'Slotz::System::Platforms::Base' do
|
|
4
|
+
subject { described_class.new }
|
|
5
|
+
|
|
6
|
+
describe '#disk_directory' do
|
|
7
|
+
it "delegates to #{Dir.tmpdir}" do
|
|
8
|
+
expect(subject.disk_directory).to eq Dir.tmpdir
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe '#cpu_count' do
|
|
13
|
+
it 'returns the amount of CPUs' do
|
|
14
|
+
expect(Concurrent).to receive(:processor_count).and_return(99)
|
|
15
|
+
expect(subject.cpu_count).to eq 99
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
shared_examples_for 'Slotz::System::Platforms::Mixins::Unix' do
|
|
2
|
+
it_should_behave_like 'Slotz::System::Platforms::Base'
|
|
3
|
+
|
|
4
|
+
subject { described_class.new }
|
|
5
|
+
|
|
6
|
+
describe '#memory_for_process_group' do
|
|
7
|
+
let(:ps) do
|
|
8
|
+
<<EOTXT
|
|
9
|
+
RSS
|
|
10
|
+
109744
|
|
11
|
+
63732
|
|
12
|
+
62236
|
|
13
|
+
63876
|
|
14
|
+
62772
|
|
15
|
+
62856
|
|
16
|
+
64504
|
|
17
|
+
EOTXT
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'returns bytes of memory used by the group' do
|
|
21
|
+
expect(subject).to receive(:pagesize).and_return(4096)
|
|
22
|
+
expect(subject).to receive(:_exec).with('ps -o rss -g 123').and_return(ps)
|
|
23
|
+
expect(subject.memory_for_process_group( 123 )).to eq 2005893120
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe '#disk_space_free' do
|
|
28
|
+
it 'returns the amount of free disk space' do
|
|
29
|
+
o = Object.new
|
|
30
|
+
expect(o).to receive(:available_bytes).and_return(1000)
|
|
31
|
+
expect(Vmstat).to receive(:disk).with(Slotz::System.disk_directory).and_return(o)
|
|
32
|
+
|
|
33
|
+
expect(subject.disk_space_free).to eq 1000
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: slotz
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: '0.1'
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Tasos Laskos
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-10-19 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: awesome_print
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - '='
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 1.9.2
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - '='
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 1.9.2
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: concurrent-ruby
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: vmstat
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 2.3.1
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 2.3.1
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: sys-proctable
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 1.3.0
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 1.3.0
|
|
83
|
+
description: ''
|
|
84
|
+
email: tasos.laskos@gmail.com
|
|
85
|
+
executables: []
|
|
86
|
+
extensions: []
|
|
87
|
+
extra_rdoc_files:
|
|
88
|
+
- README.md
|
|
89
|
+
- LICENSE.md
|
|
90
|
+
files:
|
|
91
|
+
- Gemfile
|
|
92
|
+
- LICENSE.md
|
|
93
|
+
- README.md
|
|
94
|
+
- lib/slotz.rb
|
|
95
|
+
- lib/slotz/options.rb
|
|
96
|
+
- lib/slotz/reservation.rb
|
|
97
|
+
- lib/slotz/system.rb
|
|
98
|
+
- lib/slotz/system/application.rb
|
|
99
|
+
- lib/slotz/system/platforms.rb
|
|
100
|
+
- lib/slotz/system/platforms/base.rb
|
|
101
|
+
- lib/slotz/system/platforms/linux.rb
|
|
102
|
+
- lib/slotz/system/platforms/mixins/unix.rb
|
|
103
|
+
- lib/slotz/system/platforms/osx.rb
|
|
104
|
+
- lib/slotz/system/platforms/windows.rb
|
|
105
|
+
- lib/slotz/version.rb
|
|
106
|
+
- slotz.gemspec
|
|
107
|
+
- spec/slotz/system/platforms/linux_spec.rb
|
|
108
|
+
- spec/slotz/system/platforms/osx_spec.rb
|
|
109
|
+
- spec/slotz/system/platforms/windows_spec.rb
|
|
110
|
+
- spec/slotz/system/slotz_spec.rb
|
|
111
|
+
- spec/slotz/system_spec.rb
|
|
112
|
+
- spec/spec_helper.rb
|
|
113
|
+
- spec/support/helpers/paths.rb
|
|
114
|
+
- spec/support/shared/system/platforms/base.rb
|
|
115
|
+
- spec/support/shared/system/platforms/mixins/unix.rb
|
|
116
|
+
homepage: https://github.com/qadron/cuboid
|
|
117
|
+
licenses:
|
|
118
|
+
- MIT
|
|
119
|
+
metadata: {}
|
|
120
|
+
post_install_message:
|
|
121
|
+
rdoc_options:
|
|
122
|
+
- "--charset=UTF-8"
|
|
123
|
+
require_paths:
|
|
124
|
+
- lib
|
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - ">="
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: '0'
|
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
|
+
requirements:
|
|
132
|
+
- - ">="
|
|
133
|
+
- !ruby/object:Gem::Version
|
|
134
|
+
version: '0'
|
|
135
|
+
requirements: []
|
|
136
|
+
rubygems_version: 3.4.22
|
|
137
|
+
signing_key:
|
|
138
|
+
specification_version: 4
|
|
139
|
+
summary: An application-centric, decentralised and distributed computing solution.
|
|
140
|
+
test_files:
|
|
141
|
+
- spec/slotz/system/slotz_spec.rb
|
|
142
|
+
- spec/slotz/system/platforms/osx_spec.rb
|
|
143
|
+
- spec/slotz/system/platforms/linux_spec.rb
|
|
144
|
+
- spec/slotz/system/platforms/windows_spec.rb
|
|
145
|
+
- spec/slotz/system_spec.rb
|
|
146
|
+
- spec/support/shared/system/platforms/base.rb
|
|
147
|
+
- spec/support/shared/system/platforms/mixins/unix.rb
|
|
148
|
+
- spec/support/helpers/paths.rb
|
|
149
|
+
- spec/spec_helper.rb
|