radfish 0.1.0
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/LICENSE +21 -0
- data/README.md +531 -0
- data/Rakefile +14 -0
- data/exe/radfish +7 -0
- data/lib/radfish/cli/base.rb +39 -0
- data/lib/radfish/cli.rb +759 -0
- data/lib/radfish/client.rb +142 -0
- data/lib/radfish/core/base_client.rb +126 -0
- data/lib/radfish/core/boot.rb +47 -0
- data/lib/radfish/core/jobs.rb +31 -0
- data/lib/radfish/core/power.rb +31 -0
- data/lib/radfish/core/session.rb +119 -0
- data/lib/radfish/core/storage.rb +23 -0
- data/lib/radfish/core/system.rb +39 -0
- data/lib/radfish/core/utility.rb +47 -0
- data/lib/radfish/core/virtual_media.rb +31 -0
- data/lib/radfish/vendor_detector.rb +199 -0
- data/lib/radfish/version.rb +5 -0
- data/lib/radfish.rb +89 -0
- data/radfish.gemspec +46 -0
- metadata +238 -0
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
class Client
|
5
|
+
include Debuggable
|
6
|
+
|
7
|
+
attr_reader :adapter, :vendor
|
8
|
+
attr_accessor :verbosity
|
9
|
+
|
10
|
+
def initialize(host:, username:, password:, vendor: nil, **options)
|
11
|
+
@verbosity = options[:verbosity] || 0
|
12
|
+
|
13
|
+
# Auto-detect vendor if not specified
|
14
|
+
if vendor.nil?
|
15
|
+
detector = VendorDetector.new(
|
16
|
+
host: host,
|
17
|
+
username: username,
|
18
|
+
password: password,
|
19
|
+
port: options[:port] || 443,
|
20
|
+
use_ssl: options.fetch(:use_ssl, true),
|
21
|
+
verify_ssl: options.fetch(:verify_ssl, false)
|
22
|
+
)
|
23
|
+
detector.verbosity = @verbosity
|
24
|
+
@vendor = detector.detect
|
25
|
+
|
26
|
+
if @vendor.nil?
|
27
|
+
raise UnsupportedVendorError, "Could not detect vendor for #{host}"
|
28
|
+
end
|
29
|
+
|
30
|
+
debug "Auto-detected vendor: #{@vendor}", 1, :green
|
31
|
+
else
|
32
|
+
@vendor = vendor.to_s.downcase
|
33
|
+
debug "Using specified vendor: #{@vendor}", 1, :cyan
|
34
|
+
end
|
35
|
+
|
36
|
+
# Get the adapter class for this vendor
|
37
|
+
adapter_class = Radfish.get_adapter(@vendor)
|
38
|
+
|
39
|
+
if adapter_class.nil?
|
40
|
+
# Try to load the adapter gem dynamically
|
41
|
+
begin
|
42
|
+
require "radfish/#{@vendor}_adapter"
|
43
|
+
adapter_class = Radfish.get_adapter(@vendor)
|
44
|
+
rescue LoadError
|
45
|
+
# Adapter gem not installed
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if adapter_class.nil?
|
50
|
+
raise UnsupportedVendorError, "No adapter available for vendor: #{@vendor}. " \
|
51
|
+
"Please install the radfish-#{@vendor} gem or use a supported vendor."
|
52
|
+
end
|
53
|
+
|
54
|
+
# Create the adapter instance
|
55
|
+
@adapter = adapter_class.new(
|
56
|
+
host: host,
|
57
|
+
username: username,
|
58
|
+
password: password,
|
59
|
+
**options
|
60
|
+
)
|
61
|
+
|
62
|
+
# Pass verbosity to adapter
|
63
|
+
@adapter.verbosity = @verbosity if @adapter.respond_to?(:verbosity=)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.connect(host:, username:, password:, vendor: nil, **options)
|
67
|
+
client = new(host: host, username: username, password: password, vendor: vendor, **options)
|
68
|
+
|
69
|
+
if block_given?
|
70
|
+
begin
|
71
|
+
client.login
|
72
|
+
yield client
|
73
|
+
ensure
|
74
|
+
client.logout
|
75
|
+
end
|
76
|
+
else
|
77
|
+
client
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Delegate all method calls to the adapter
|
82
|
+
def method_missing(method, *args, **kwargs, &block)
|
83
|
+
if @adapter.respond_to?(method)
|
84
|
+
if kwargs.empty?
|
85
|
+
@adapter.send(method, *args, &block)
|
86
|
+
else
|
87
|
+
@adapter.send(method, *args, **kwargs, &block)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
super
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def respond_to_missing?(method, include_private = false)
|
95
|
+
@adapter.respond_to?(method, include_private) || super
|
96
|
+
end
|
97
|
+
|
98
|
+
# Core methods that should always be available
|
99
|
+
|
100
|
+
def login
|
101
|
+
@adapter.login
|
102
|
+
end
|
103
|
+
|
104
|
+
def logout
|
105
|
+
@adapter.logout
|
106
|
+
end
|
107
|
+
|
108
|
+
def vendor_name
|
109
|
+
@vendor
|
110
|
+
end
|
111
|
+
|
112
|
+
def adapter_class
|
113
|
+
@adapter.class
|
114
|
+
end
|
115
|
+
|
116
|
+
def supported_features
|
117
|
+
# Return a list of features this adapter supports
|
118
|
+
features = []
|
119
|
+
|
120
|
+
# Check which modules are included
|
121
|
+
features << :power if @adapter.respond_to?(:power_status)
|
122
|
+
features << :system if @adapter.respond_to?(:system_info)
|
123
|
+
features << :storage if @adapter.respond_to?(:storage_controllers)
|
124
|
+
features << :virtual_media if @adapter.respond_to?(:virtual_media)
|
125
|
+
features << :boot if @adapter.respond_to?(:boot_options)
|
126
|
+
features << :jobs if @adapter.respond_to?(:jobs)
|
127
|
+
features << :utility if @adapter.respond_to?(:sel_log)
|
128
|
+
|
129
|
+
features
|
130
|
+
end
|
131
|
+
|
132
|
+
def info
|
133
|
+
{
|
134
|
+
vendor: @vendor,
|
135
|
+
adapter: adapter_class.name,
|
136
|
+
features: supported_features,
|
137
|
+
host: @adapter.host,
|
138
|
+
base_url: @adapter.base_url
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
module Core
|
5
|
+
class BaseClient
|
6
|
+
include Debuggable
|
7
|
+
|
8
|
+
attr_reader :host, :username, :password, :port, :use_ssl, :verify_ssl, :host_header
|
9
|
+
attr_accessor :verbosity, :retry_count, :retry_delay
|
10
|
+
|
11
|
+
def initialize(host:, username:, password:, port: 443, use_ssl: true, verify_ssl: false,
|
12
|
+
retry_count: 3, retry_delay: 1, host_header: nil, **options)
|
13
|
+
@host = host
|
14
|
+
@username = username
|
15
|
+
@password = password
|
16
|
+
@port = port
|
17
|
+
@use_ssl = use_ssl
|
18
|
+
@verify_ssl = verify_ssl
|
19
|
+
@host_header = host_header
|
20
|
+
@verbosity = 0
|
21
|
+
@retry_count = retry_count
|
22
|
+
@retry_delay = retry_delay
|
23
|
+
|
24
|
+
# Store any vendor-specific options
|
25
|
+
@options = options
|
26
|
+
end
|
27
|
+
|
28
|
+
def base_url
|
29
|
+
protocol = use_ssl ? 'https' : 'http'
|
30
|
+
"#{protocol}://#{host}:#{port}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def connection
|
34
|
+
@connection ||= Faraday.new(url: base_url, ssl: { verify: verify_ssl }) do |faraday|
|
35
|
+
faraday.request :multipart
|
36
|
+
faraday.request :url_encoded
|
37
|
+
faraday.adapter Faraday.default_adapter
|
38
|
+
|
39
|
+
if @verbosity > 0
|
40
|
+
faraday.response :logger, Logger.new(STDOUT), bodies: @verbosity >= 2 do |logger|
|
41
|
+
logger.filter(/(Authorization: Basic )([^,\n]+)/, '\1[FILTERED]')
|
42
|
+
logger.filter(/(Password"=>"?)([^,"]+)/, '\1[FILTERED]')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def with_retries(max_retries = nil, initial_delay = nil, error_classes = nil)
|
49
|
+
max_retries ||= @retry_count
|
50
|
+
initial_delay ||= @retry_delay
|
51
|
+
error_classes ||= [StandardError]
|
52
|
+
|
53
|
+
retries = 0
|
54
|
+
begin
|
55
|
+
yield
|
56
|
+
rescue *error_classes => e
|
57
|
+
retries += 1
|
58
|
+
if retries <= max_retries
|
59
|
+
delay = initial_delay * (retries ** 1.5).to_i
|
60
|
+
debug "RETRY: #{e.message} - Attempt #{retries}/#{max_retries}, waiting #{delay}s", 1, :yellow
|
61
|
+
sleep delay
|
62
|
+
retry
|
63
|
+
else
|
64
|
+
debug "MAX RETRIES REACHED: #{e.message} after #{max_retries} attempts", 1, :red
|
65
|
+
raise e
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Vendor-specific methods to be overridden
|
71
|
+
|
72
|
+
def vendor
|
73
|
+
raise NotImplementedError, "Subclass must implement #vendor"
|
74
|
+
end
|
75
|
+
|
76
|
+
def login
|
77
|
+
raise NotImplementedError, "Subclass must implement #login"
|
78
|
+
end
|
79
|
+
|
80
|
+
def logout
|
81
|
+
raise NotImplementedError, "Subclass must implement #logout"
|
82
|
+
end
|
83
|
+
|
84
|
+
def authenticated_request(method, path, **options)
|
85
|
+
raise NotImplementedError, "Subclass must implement #authenticated_request"
|
86
|
+
end
|
87
|
+
|
88
|
+
def redfish_version
|
89
|
+
response = authenticated_request(:get, "/redfish/v1")
|
90
|
+
if response.status == 200
|
91
|
+
data = JSON.parse(response.body)
|
92
|
+
data["RedfishVersion"]
|
93
|
+
else
|
94
|
+
raise Error, "Failed to get Redfish version: #{response.status}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def service_root
|
99
|
+
response = authenticated_request(:get, "/redfish/v1")
|
100
|
+
if response.status == 200
|
101
|
+
JSON.parse(response.body)
|
102
|
+
else
|
103
|
+
raise Error, "Failed to get service root: #{response.status}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Helper for handling responses
|
108
|
+
def handle_response(response)
|
109
|
+
if response.headers["location"]
|
110
|
+
return handle_location(response.headers["location"])
|
111
|
+
end
|
112
|
+
|
113
|
+
if response.status.between?(200, 299)
|
114
|
+
return response.body
|
115
|
+
else
|
116
|
+
raise Error, "Request failed: #{response.status} - #{response.body}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def handle_location(location)
|
121
|
+
# Subclasses can override for vendor-specific handling
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
module Core
|
5
|
+
module Boot
|
6
|
+
def boot_options
|
7
|
+
raise NotImplementedError, "Adapter must implement #boot_options"
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_boot_override(target, persistent: false)
|
11
|
+
raise NotImplementedError, "Adapter must implement #set_boot_override"
|
12
|
+
end
|
13
|
+
|
14
|
+
def clear_boot_override
|
15
|
+
raise NotImplementedError, "Adapter must implement #clear_boot_override"
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_boot_order(devices)
|
19
|
+
raise NotImplementedError, "Adapter must implement #set_boot_order"
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_boot_devices
|
23
|
+
raise NotImplementedError, "Adapter must implement #get_boot_devices"
|
24
|
+
end
|
25
|
+
|
26
|
+
def boot_to_pxe
|
27
|
+
raise NotImplementedError, "Adapter must implement #boot_to_pxe"
|
28
|
+
end
|
29
|
+
|
30
|
+
def boot_to_disk
|
31
|
+
raise NotImplementedError, "Adapter must implement #boot_to_disk"
|
32
|
+
end
|
33
|
+
|
34
|
+
def boot_to_cd
|
35
|
+
raise NotImplementedError, "Adapter must implement #boot_to_cd"
|
36
|
+
end
|
37
|
+
|
38
|
+
def boot_to_usb
|
39
|
+
raise NotImplementedError, "Adapter must implement #boot_to_usb"
|
40
|
+
end
|
41
|
+
|
42
|
+
def boot_to_bios_setup
|
43
|
+
raise NotImplementedError, "Adapter must implement #boot_to_bios_setup"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
module Core
|
5
|
+
module Jobs
|
6
|
+
def jobs
|
7
|
+
raise NotImplementedError, "Adapter must implement #jobs"
|
8
|
+
end
|
9
|
+
|
10
|
+
def job_status(job_id)
|
11
|
+
raise NotImplementedError, "Adapter must implement #job_status"
|
12
|
+
end
|
13
|
+
|
14
|
+
def wait_for_job(job_id, timeout: 600)
|
15
|
+
raise NotImplementedError, "Adapter must implement #wait_for_job"
|
16
|
+
end
|
17
|
+
|
18
|
+
def cancel_job(job_id)
|
19
|
+
raise NotImplementedError, "Adapter must implement #cancel_job"
|
20
|
+
end
|
21
|
+
|
22
|
+
def clear_completed_jobs
|
23
|
+
raise NotImplementedError, "Adapter must implement #clear_completed_jobs"
|
24
|
+
end
|
25
|
+
|
26
|
+
def jobs_summary
|
27
|
+
raise NotImplementedError, "Adapter must implement #jobs_summary"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
module Core
|
5
|
+
module Power
|
6
|
+
def power_status
|
7
|
+
raise NotImplementedError, "Adapter must implement #power_status"
|
8
|
+
end
|
9
|
+
|
10
|
+
def power_on
|
11
|
+
raise NotImplementedError, "Adapter must implement #power_on"
|
12
|
+
end
|
13
|
+
|
14
|
+
def power_off
|
15
|
+
raise NotImplementedError, "Adapter must implement #power_off"
|
16
|
+
end
|
17
|
+
|
18
|
+
def power_restart
|
19
|
+
raise NotImplementedError, "Adapter must implement #power_restart"
|
20
|
+
end
|
21
|
+
|
22
|
+
def power_cycle
|
23
|
+
raise NotImplementedError, "Adapter must implement #power_cycle"
|
24
|
+
end
|
25
|
+
|
26
|
+
def reset_type_allowed
|
27
|
+
raise NotImplementedError, "Adapter must implement #reset_type_allowed"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
module Core
|
5
|
+
class Session
|
6
|
+
include Debuggable
|
7
|
+
|
8
|
+
attr_reader :client, :x_auth_token, :session_id
|
9
|
+
|
10
|
+
def initialize(client)
|
11
|
+
@client = client
|
12
|
+
@x_auth_token = nil
|
13
|
+
@session_id = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def connection
|
17
|
+
@connection ||= Faraday.new(url: client.base_url, ssl: { verify: client.verify_ssl }) do |faraday|
|
18
|
+
faraday.request :url_encoded
|
19
|
+
faraday.adapter Faraday.default_adapter
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def create
|
24
|
+
debug "Creating Redfish session for #{client.host}", 1
|
25
|
+
|
26
|
+
payload = {
|
27
|
+
UserName: client.username,
|
28
|
+
Password: client.password
|
29
|
+
}.to_json
|
30
|
+
|
31
|
+
headers = {
|
32
|
+
'Content-Type' => 'application/json',
|
33
|
+
'Accept' => 'application/json'
|
34
|
+
}
|
35
|
+
headers['Host'] = client.host_header if client.host_header
|
36
|
+
|
37
|
+
begin
|
38
|
+
response = connection.post('/redfish/v1/SessionService/Sessions', payload, headers)
|
39
|
+
|
40
|
+
if response.status == 201
|
41
|
+
@x_auth_token = response.headers['x-auth-token']
|
42
|
+
|
43
|
+
if response.headers['location']
|
44
|
+
@session_id = response.headers['location'].split('/').last
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
body = JSON.parse(response.body)
|
49
|
+
@session_id ||= body["Id"] if body.is_a?(Hash)
|
50
|
+
rescue JSON::ParserError
|
51
|
+
end
|
52
|
+
|
53
|
+
debug "Session created successfully. Token: #{@x_auth_token ? @x_auth_token[0..10] + '...' : 'nil'}", 1, :green
|
54
|
+
return true
|
55
|
+
else
|
56
|
+
debug "Failed to create session. Status: #{response.status}", 1, :red
|
57
|
+
debug "Response: #{response.body}", 2
|
58
|
+
return false
|
59
|
+
end
|
60
|
+
rescue Faraday::Error => e
|
61
|
+
debug "Connection error creating session: #{e.message}", 1, :red
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def delete
|
67
|
+
return unless @x_auth_token && @session_id
|
68
|
+
|
69
|
+
debug "Deleting session #{@session_id}", 1
|
70
|
+
|
71
|
+
headers = {
|
72
|
+
'X-Auth-Token' => @x_auth_token,
|
73
|
+
'Accept' => 'application/json'
|
74
|
+
}
|
75
|
+
headers['Host'] = client.host_header if client.host_header
|
76
|
+
|
77
|
+
begin
|
78
|
+
response = connection.delete("/redfish/v1/SessionService/Sessions/#{@session_id}", nil, headers)
|
79
|
+
|
80
|
+
if response.status == 204 || response.status == 200
|
81
|
+
debug "Session deleted successfully", 1, :green
|
82
|
+
@x_auth_token = nil
|
83
|
+
@session_id = nil
|
84
|
+
return true
|
85
|
+
else
|
86
|
+
debug "Failed to delete session. Status: #{response.status}", 1, :yellow
|
87
|
+
return false
|
88
|
+
end
|
89
|
+
rescue Faraday::Error => e
|
90
|
+
debug "Error deleting session: #{e.message}", 1, :yellow
|
91
|
+
return false
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def valid?
|
96
|
+
return false unless @x_auth_token
|
97
|
+
|
98
|
+
headers = {
|
99
|
+
'X-Auth-Token' => @x_auth_token,
|
100
|
+
'Accept' => 'application/json'
|
101
|
+
}
|
102
|
+
headers['Host'] = client.host_header if client.host_header
|
103
|
+
|
104
|
+
begin
|
105
|
+
response = connection.get("/redfish/v1/SessionService/Sessions/#{@session_id}", nil, headers)
|
106
|
+
response.status == 200
|
107
|
+
rescue
|
108
|
+
false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def verbosity
|
115
|
+
client.verbosity
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
module Core
|
5
|
+
module Storage
|
6
|
+
def storage_controllers
|
7
|
+
raise NotImplementedError, "Adapter must implement #storage_controllers"
|
8
|
+
end
|
9
|
+
|
10
|
+
def drives
|
11
|
+
raise NotImplementedError, "Adapter must implement #drives"
|
12
|
+
end
|
13
|
+
|
14
|
+
def volumes
|
15
|
+
raise NotImplementedError, "Adapter must implement #volumes"
|
16
|
+
end
|
17
|
+
|
18
|
+
def storage_summary
|
19
|
+
raise NotImplementedError, "Adapter must implement #storage_summary"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
module Core
|
5
|
+
module System
|
6
|
+
def system_info
|
7
|
+
raise NotImplementedError, "Adapter must implement #system_info"
|
8
|
+
end
|
9
|
+
|
10
|
+
def cpus
|
11
|
+
raise NotImplementedError, "Adapter must implement #cpus"
|
12
|
+
end
|
13
|
+
|
14
|
+
def memory
|
15
|
+
raise NotImplementedError, "Adapter must implement #memory"
|
16
|
+
end
|
17
|
+
|
18
|
+
def nics
|
19
|
+
raise NotImplementedError, "Adapter must implement #nics"
|
20
|
+
end
|
21
|
+
|
22
|
+
def fans
|
23
|
+
raise NotImplementedError, "Adapter must implement #fans"
|
24
|
+
end
|
25
|
+
|
26
|
+
def temperatures
|
27
|
+
raise NotImplementedError, "Adapter must implement #temperatures"
|
28
|
+
end
|
29
|
+
|
30
|
+
def psus
|
31
|
+
raise NotImplementedError, "Adapter must implement #psus"
|
32
|
+
end
|
33
|
+
|
34
|
+
def power_consumption
|
35
|
+
raise NotImplementedError, "Adapter must implement #power_consumption"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
module Core
|
5
|
+
module Utility
|
6
|
+
def sel_log
|
7
|
+
raise NotImplementedError, "Adapter must implement #sel_log"
|
8
|
+
end
|
9
|
+
|
10
|
+
def clear_sel_log
|
11
|
+
raise NotImplementedError, "Adapter must implement #clear_sel_log"
|
12
|
+
end
|
13
|
+
|
14
|
+
def sel_summary(limit: 10)
|
15
|
+
raise NotImplementedError, "Adapter must implement #sel_summary"
|
16
|
+
end
|
17
|
+
|
18
|
+
def accounts
|
19
|
+
raise NotImplementedError, "Adapter must implement #accounts"
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_account(username:, password:, role: "Administrator")
|
23
|
+
raise NotImplementedError, "Adapter must implement #create_account"
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete_account(username)
|
27
|
+
raise NotImplementedError, "Adapter must implement #delete_account"
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_account_password(username:, new_password:)
|
31
|
+
raise NotImplementedError, "Adapter must implement #update_account_password"
|
32
|
+
end
|
33
|
+
|
34
|
+
def sessions
|
35
|
+
raise NotImplementedError, "Adapter must implement #sessions"
|
36
|
+
end
|
37
|
+
|
38
|
+
def service_info
|
39
|
+
raise NotImplementedError, "Adapter must implement #service_info"
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_firmware_version
|
43
|
+
raise NotImplementedError, "Adapter must implement #get_firmware_version"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Radfish
|
4
|
+
module Core
|
5
|
+
module VirtualMedia
|
6
|
+
def virtual_media
|
7
|
+
raise NotImplementedError, "Adapter must implement #virtual_media"
|
8
|
+
end
|
9
|
+
|
10
|
+
def insert_virtual_media(iso_url, device: nil)
|
11
|
+
raise NotImplementedError, "Adapter must implement #insert_virtual_media"
|
12
|
+
end
|
13
|
+
|
14
|
+
def eject_virtual_media(device: nil)
|
15
|
+
raise NotImplementedError, "Adapter must implement #eject_virtual_media"
|
16
|
+
end
|
17
|
+
|
18
|
+
def virtual_media_status
|
19
|
+
raise NotImplementedError, "Adapter must implement #virtual_media_status"
|
20
|
+
end
|
21
|
+
|
22
|
+
def mount_iso_and_boot(iso_url, device: nil)
|
23
|
+
raise NotImplementedError, "Adapter must implement #mount_iso_and_boot"
|
24
|
+
end
|
25
|
+
|
26
|
+
def unmount_all_media
|
27
|
+
raise NotImplementedError, "Adapter must implement #unmount_all_media"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|