foreman_ovirt 0.2.0 → 2.0.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 +619 -0
- data/README.md +140 -0
- data/Rakefile +37 -43
- data/app/assets/javascripts/foreman_ovirt/display.js +10 -0
- data/app/assets/javascripts/foreman_ovirt/host_edit.js +61 -0
- data/app/assets/javascripts/foreman_ovirt/nic_info.js +3 -0
- data/app/assets/javascripts/foreman_ovirt/ovirt.js +261 -0
- data/app/controllers/concerns/foreman_ovirt/compute_resources_vms_controller.rb +29 -0
- data/app/controllers/concerns/foreman_ovirt/parameters_extension.rb +35 -0
- data/app/controllers/foreman_ovirt/concerns/compute_resources_controller_extensions.rb +60 -0
- data/app/helpers/ovirt_compute_resource_helper.rb +26 -0
- data/app/models/concerns/fog_extensions/ovirt/server.rb +42 -0
- data/app/models/concerns/fog_extensions/ovirt/template.rb +14 -0
- data/app/models/concerns/fog_extensions/ovirt/volume.rb +11 -0
- data/app/models/foreman_ovirt/ovirt.rb +752 -0
- data/app/views/api/v2/compute_resources/ovirt.json.rabl +1 -0
- data/app/views/compute_resources/form/_ovirt.html.erb +14 -0
- data/app/views/compute_resources/show/_ovirt.html.erb +16 -0
- data/app/views/compute_resources_vms/form/ovirt/_base.html.erb +83 -0
- data/app/views/compute_resources_vms/form/ovirt/_network.html.erb +32 -0
- data/app/views/compute_resources_vms/form/ovirt/_volume.html.erb +16 -0
- data/app/views/compute_resources_vms/index/_ovirt.html.erb +12 -0
- data/app/views/compute_resources_vms/index/_ovirt_json.erb +6 -0
- data/app/views/compute_resources_vms/show/_ovirt.html.erb +55 -0
- data/app/views/images/form/_ovirt.html.erb +4 -0
- data/config/routes.rb +8 -13
- data/db/migrate/20250810212811_update_legacy_ovirt_compute_resource_type.rb +21 -0
- data/lib/foreman_ovirt/engine.rb +70 -0
- data/lib/foreman_ovirt/version.rb +3 -0
- data/lib/foreman_ovirt.rb +2 -1
- data/lib/tasks/foreman_ovirt_tasks.rake +30 -0
- data/locale/Makefile +73 -0
- data/locale/en/foreman_ovirt.po +19 -0
- data/locale/foreman_ovirt.pot +19 -0
- data/locale/gemspec.rb +2 -0
- data/package.json +39 -0
- data/test/factories/foreman_ovirt_factories.rb +5 -0
- data/test/test_plugin_helper.rb +6 -0
- data/test/unit/foreman_ovirt_test.rb +11 -0
- data/webpack/components/extensions/HostDetails/DetailsTabCards/OvirtCard.js +132 -0
- data/webpack/components/ovirt.js +20 -0
- data/webpack/global_index.js +14 -0
- data/webpack/global_test_setup.js +11 -0
- data/webpack/index.js +1 -0
- data/webpack/test_setup.js +17 -0
- metadata +157 -128
- data/.document +0 -5
- data/Gemfile +0 -14
- data/Gemfile.lock +0 -33
- data/LICENSE.txt +0 -20
- data/README.rdoc +0 -20
- data/VERSION +0 -1
- data/app/controllers/foreman_ovirt/auth_source_ovirts_controller.rb +0 -57
- data/app/controllers/foreman_ovirt/dashboard_controller.rb +0 -10
- data/app/controllers/foreman_ovirt/hosts_controller.rb +0 -17
- data/app/models/foreman_ovirt/auth_source_ovirt.rb +0 -78
- data/app/models/foreman_ovirt/user_extensions.rb +0 -26
- data/app/views/foreman_ovirt/auth_source_ovirts/_form.html.erb +0 -17
- data/app/views/foreman_ovirt/auth_source_ovirts/edit.html.erb +0 -3
- data/app/views/foreman_ovirt/auth_source_ovirts/index.html.erb +0 -22
- data/app/views/foreman_ovirt/auth_source_ovirts/new.html.erb +0 -3
- data/app/views/foreman_ovirt/auth_source_ovirts/welcome.html.erb +0 -8
- data/app/views/foreman_ovirt/hosts/_overview.html.erb +0 -27
- data/app/views/foreman_ovirt/hosts/show.html.erb +0 -48
- data/app/views/foreman_ovirt/hosts/show_graphs.html.erb +0 -13
- data/app/views/layouts/application_ovirt.html.erb +0 -36
- data/config/initializers/ovirt_setup.rb +0 -30
- data/foreman_ovirt.gemspec +0 -74
- data/lib/engine.rb +0 -9
data/README.md
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
# ForemanOvirt
|
2
|
+
|
3
|
+
#### Table of Contents
|
4
|
+
|
5
|
+
1. [Overview](#overview)
|
6
|
+
1. [Installation](#installation)
|
7
|
+
1. [Usage](#usage)
|
8
|
+
1. [Development](#development)
|
9
|
+
- [Dev prerequisites](#dev-prerequisites)
|
10
|
+
- [Dev server](#dev-server)
|
11
|
+
1. [Contributing](#contributing)
|
12
|
+
1. [Copyright](#copyright)
|
13
|
+
- [Plugin](#plugin)
|
14
|
+
- [The Foreman](#the-forman)
|
15
|
+
|
16
|
+
## Overview
|
17
|
+
|
18
|
+
[Foreman](http://theforeman.org/) plugin that adds [oVirt](https://www.ovirt.org) compute resource: managing virtual machines using the [fog-ovirt](https://github.com/fog/fog-ovirt) module.
|
19
|
+
|
20
|
+
This plugin continues the oVirt support that was part of Foreman up to version 3.15 and is now maintained as a standalone plugin. It requires Foreman 3.16+.
|
21
|
+
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
### From OS packages
|
25
|
+
|
26
|
+
On Rocky/Alma/RedHat:
|
27
|
+
|
28
|
+
```shell
|
29
|
+
sudo dnf install rubygem-foreman_ovirt
|
30
|
+
```
|
31
|
+
|
32
|
+
On Debian/Ubuntu:
|
33
|
+
|
34
|
+
```shell
|
35
|
+
sudo apt-get install ruby-foreman-ovirt
|
36
|
+
```
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
Create a oVirt compute resource and set:
|
41
|
+
|
42
|
+
* Provider: `oVirt`
|
43
|
+
* URL: `https://ovirt.example.com/ovirt-engine/api`
|
44
|
+
* Username: `admin@internal`
|
45
|
+
|
46
|
+
Then click on "Load Datacenters" and add all necessary information to the form.
|
47
|
+
|
48
|
+
## Development
|
49
|
+
|
50
|
+
### Dev prerequisites
|
51
|
+
|
52
|
+
See [Foreman dev setup](https://github.com/theforeman/foreman/blob/develop/developer_docs/foreman_dev_setup.asciidoc) and [foreman plugin development](https://github.com/theforeman/foreman/blob/develop/developer_docs/how_to_create_a_plugin.asciidoc) for details and a full explanation.
|
53
|
+
|
54
|
+
* oVirt 4.5+ is required
|
55
|
+
* NodeJS on the dev machine to run webpack-dev-server
|
56
|
+
|
57
|
+
### Dev server
|
58
|
+
|
59
|
+
NOTE: The following ignores all OS-dependant tasks and commands. Please see the official Foreman developer guide for an in-depth walkthrough.
|
60
|
+
|
61
|
+
Fork and clone this plugin repository:
|
62
|
+
|
63
|
+
```shell
|
64
|
+
git clone https://github.com/YOUR_FORK/foreman_ovirt.git
|
65
|
+
```
|
66
|
+
|
67
|
+
Minimal steps to setup a Foreman dev instance:
|
68
|
+
|
69
|
+
```shell
|
70
|
+
git clone https://github.com/theforeman/foreman.git -b develop
|
71
|
+
cd foreman
|
72
|
+
cp config/settings.yaml.example config/settings.yaml
|
73
|
+
cp config/database.yml.example config/database.yml
|
74
|
+
```
|
75
|
+
|
76
|
+
Edit `bundler.d/ovirt.rb` and add this content:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
gem 'fog-ovirt'
|
80
|
+
gem 'foreman_ovirt', :path => '/path/to/foreman_ovirt'
|
81
|
+
gem 'irb' # dev
|
82
|
+
```
|
83
|
+
|
84
|
+
In foreman directory, install dependencies:
|
85
|
+
|
86
|
+
```shell
|
87
|
+
bundle install --path vendor
|
88
|
+
npm install
|
89
|
+
```
|
90
|
+
|
91
|
+
Run Foreman dev server:
|
92
|
+
|
93
|
+
```shell
|
94
|
+
BIND=0.0.0.0 bundle exec foreman start
|
95
|
+
```
|
96
|
+
|
97
|
+
Note that the bundled webpack server may consume HUGE amounts of RAM on startup.
|
98
|
+
|
99
|
+
## Contributing
|
100
|
+
|
101
|
+
Fork and send a Pull Request. Thanks!
|
102
|
+
|
103
|
+
## Copyright
|
104
|
+
|
105
|
+
### Plugin
|
106
|
+
|
107
|
+
Copyright (c) 2025 markt.de GmbH & Co. KG
|
108
|
+
|
109
|
+
This program is free software: you can redistribute it and/or modify
|
110
|
+
it under the terms of the GNU General Public License as published by
|
111
|
+
the Free Software Foundation, either version 3 of the License, or
|
112
|
+
(at your option) any later version.
|
113
|
+
|
114
|
+
This program is distributed in the hope that it will be useful,
|
115
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
116
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
117
|
+
GNU General Public License for more details.
|
118
|
+
|
119
|
+
You should have received a copy of the GNU General Public License
|
120
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
121
|
+
|
122
|
+
The [LICENSE](LICENSE) file contains the full text of the GNU GPL v3 license, along with the text for all additional licenses referenced above.
|
123
|
+
|
124
|
+
### The Foreman
|
125
|
+
|
126
|
+
This plugin is based on code from Foreman 3.15.0.
|
127
|
+
|
128
|
+
The Foreman repository/package is licensed under the GNU GPL v3 or newer, with some exceptions.
|
129
|
+
|
130
|
+
Copyright (c) 2009-2020 to Ohad Levy, Paul Kelly and their respective owners.
|
131
|
+
|
132
|
+
All copyright holders for the Foreman project are in the separate file called Contributors.
|
133
|
+
|
134
|
+
Except where specified below, this program and entire repository is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
|
135
|
+
|
136
|
+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
137
|
+
|
138
|
+
You should have received a copy of the GNU General Public License along with this program. If not, see [GNU licenses](http://www.gnu.org/licenses/).
|
139
|
+
|
140
|
+
All rights reserved.
|
data/Rakefile
CHANGED
@@ -1,53 +1,47 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'bundler'
|
1
|
+
#!/usr/bin/env rake
|
5
2
|
begin
|
6
|
-
|
7
|
-
rescue
|
8
|
-
|
9
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
-
exit e.status_code
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
11
6
|
end
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
gem.homepage = "http://github.com/oourfali/foreman_ovirt"
|
19
|
-
gem.license = "MIT"
|
20
|
-
gem.summary = %Q{Plugin engine for Foreman-Ovirt integration}
|
21
|
-
gem.description = %Q{Foreman oVirt plugin}
|
22
|
-
gem.email = "ovedo@redhat.com"
|
23
|
-
gem.authors = ["Oved Ourfali"]
|
24
|
-
# dependencies defined in Gemfile
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
25
13
|
end
|
26
|
-
#Jeweler::RubygemsDotOrgTasks.new
|
27
14
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'ForemanOvirt'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
33
21
|
end
|
34
22
|
|
35
|
-
|
36
|
-
# Rcov::RcovTask.new do |test|
|
37
|
-
# test.libs << 'test'
|
38
|
-
# test.pattern = 'test/**/test_*.rb'
|
39
|
-
# test.verbose = true
|
40
|
-
# test.rcov_opts << '--exclude "gems/*"'
|
41
|
-
# end
|
23
|
+
APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
|
42
24
|
|
43
|
-
|
25
|
+
Bundler::GemHelper.install_tasks
|
44
26
|
|
45
|
-
require '
|
46
|
-
Rake::RDocTask.new do |rdoc|
|
47
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
27
|
+
require 'rake/testtask'
|
48
28
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
task default: :test
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'rubocop/rake_task'
|
40
|
+
RuboCop::RakeTask.new
|
41
|
+
rescue LoadError
|
42
|
+
puts 'Rubocop not loaded.'
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default do
|
46
|
+
Rake::Task['rubocop'].execute
|
53
47
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
function toggle_keyboard_options() {
|
2
|
+
if ($('select.display_type').val().toLowerCase() === 'vnc') {
|
3
|
+
$('.keyboard_layout').parents('.form-group').css('display', '');
|
4
|
+
} else {
|
5
|
+
$('.keyboard_layout').parents('.form-group').css('display', 'none');
|
6
|
+
}
|
7
|
+
}
|
8
|
+
|
9
|
+
$(document).on('change', '.display_type', toggle_keyboard_options);
|
10
|
+
$(document).ready(toggle_keyboard_options);
|
@@ -0,0 +1,61 @@
|
|
1
|
+
$(document).ready(function() {
|
2
|
+
var ovirt = {
|
3
|
+
update_cluster_tab: function (compute_resource_id) {
|
4
|
+
if (compute_resource_id) {
|
5
|
+
$('#cluster-indicator').show();
|
6
|
+
$.get('/compute_resources/' + compute_resource_id + '/available_clusters', { 'format': 'json' }, function (data) {
|
7
|
+
var cluster_id = $('#host_compute_attributes_cluster_id');
|
8
|
+
helpers.update_select_options(cluster_id, data);
|
9
|
+
cluster_id.change();
|
10
|
+
$('#cluster-indicator').hide();
|
11
|
+
});
|
12
|
+
} else {
|
13
|
+
$('#cluster-indicator').hide();
|
14
|
+
}
|
15
|
+
},
|
16
|
+
|
17
|
+
update_template_tab: function (compute_resource_id, cluster_id) {
|
18
|
+
if (compute_resource_id && cluster_id) {
|
19
|
+
$('#template-indicator').show();
|
20
|
+
$.get('/compute_resources/' + compute_resource_id + '/available_images', { 'cluster_id': cluster_id, 'format': 'json' }, function (data) {
|
21
|
+
var template_id = $('#host_compute_attributes_template_id');
|
22
|
+
helpers.update_select_options(template_id, data);
|
23
|
+
$('#template-indicator').hide();
|
24
|
+
});
|
25
|
+
} else {
|
26
|
+
$('#template-indicator').hide();
|
27
|
+
}
|
28
|
+
}
|
29
|
+
};
|
30
|
+
|
31
|
+
$('#host_compute_resource_id').on('change', function () {
|
32
|
+
var selected = $(this).find('option:selected');
|
33
|
+
if (selected.data('provider') === 'Ovirt') {
|
34
|
+
ovirt.update_cluster_tab($(this).val());
|
35
|
+
}
|
36
|
+
});
|
37
|
+
|
38
|
+
$('#host_compute_attributes_cluster_id').on('change', function () {
|
39
|
+
var compute_resource_id = $('#host_compute_resource_id').val();
|
40
|
+
var selected = $('#host_compute_resource_id').find('option:selected');
|
41
|
+
if (selected.data('provider') === 'Ovirt') {
|
42
|
+
ovirt.update_template_tab(compute_resource_id, $(this).val());
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
if ($('#host_compute_resource_id').find('option:selected').data('provider') === 'Ovirt') {
|
47
|
+
ovirt.update_cluster_tab($('#host_compute_resource_id').val());
|
48
|
+
}
|
49
|
+
|
50
|
+
$('#host_interfaces_attributes').on('change', '.type', function() {
|
51
|
+
var root = $(this).parents('.fields');
|
52
|
+
// show the relevant network
|
53
|
+
var network = $(this).val();
|
54
|
+
if (network) {
|
55
|
+
// hide all other networks
|
56
|
+
root.find('.ovirt_network').hide();
|
57
|
+
// show the relevant network
|
58
|
+
root.find('.' + network.toLowerCase() + '_network').show();
|
59
|
+
}
|
60
|
+
});
|
61
|
+
});
|
@@ -0,0 +1,261 @@
|
|
1
|
+
/* eslint-disable jquery/no-each */
|
2
|
+
/* eslint-disable jquery/no-text */
|
3
|
+
/* eslint-disable jquery/no-data */
|
4
|
+
/* eslint-disable jquery/no-sizzle */
|
5
|
+
/* eslint-disable jquery/no-hide */
|
6
|
+
/* eslint-disable jquery/no-attr */
|
7
|
+
/* eslint-disable jquery/no-ajax */
|
8
|
+
/* eslint-disable jquery/no-trigger */
|
9
|
+
/* eslint-disable jquery/no-val */
|
10
|
+
/* eslint-disable jquery/no-prop */
|
11
|
+
/* eslint-disable func-names */
|
12
|
+
|
13
|
+
function templateSelected(item) {
|
14
|
+
const template = $(item).val();
|
15
|
+
|
16
|
+
if (template === null) {
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
|
20
|
+
const url = $(item).attr('data-url');
|
21
|
+
|
22
|
+
tfm.tools.showSpinner();
|
23
|
+
$.ajax({
|
24
|
+
type: 'post',
|
25
|
+
url,
|
26
|
+
data: `template_id=${template}`,
|
27
|
+
success(result) {
|
28
|
+
// As Instance Type values will take precence over templates values,
|
29
|
+
// we don't update memory/cores values if instance type is already selected
|
30
|
+
if (!$('#host_compute_attributes_instance_type').val()) {
|
31
|
+
updateCoresAndSockets(result);
|
32
|
+
setMemoryInputProps({ value: result.memory });
|
33
|
+
$('[id$=_ha]').prop('checked', result.ha);
|
34
|
+
}
|
35
|
+
$('#network_interfaces')
|
36
|
+
.children('.fields')
|
37
|
+
.remove();
|
38
|
+
$.each(result.interfaces, function() {
|
39
|
+
addNetworkInterface(this);
|
40
|
+
});
|
41
|
+
$('#storage_volumes .children_fields >.fields').remove();
|
42
|
+
$.each(result.volumes, function() {
|
43
|
+
// Change variable name because 'interface' is a reserved keyword.
|
44
|
+
// eslint-disable-next-line dot-notation
|
45
|
+
this.disk_interface = this['interface'];
|
46
|
+
addVolume(this);
|
47
|
+
});
|
48
|
+
const templateSelector = $('#host_compute_attributes_template');
|
49
|
+
|
50
|
+
if (templateSelector.siblings('.select2-container-disabled').length > 0) {
|
51
|
+
templateSelector.val(result.id);
|
52
|
+
}
|
53
|
+
},
|
54
|
+
complete() {
|
55
|
+
// eslint-disable-next-line no-undef
|
56
|
+
reloadOnAjaxComplete(item);
|
57
|
+
},
|
58
|
+
});
|
59
|
+
}
|
60
|
+
|
61
|
+
function instanceTypeSelected(item) {
|
62
|
+
const instanceType = $(item).val();
|
63
|
+
|
64
|
+
if (!item.disabled) {
|
65
|
+
const url = $(item).attr('data-url');
|
66
|
+
|
67
|
+
tfm.tools.showSpinner();
|
68
|
+
$.ajax({
|
69
|
+
type: 'post',
|
70
|
+
url,
|
71
|
+
data: `instance_type_id=${instanceType}`,
|
72
|
+
success(result) {
|
73
|
+
if (result.name != null) {
|
74
|
+
setMemoryInputProps({ value: result.memory });
|
75
|
+
updateCoresAndSockets(result);
|
76
|
+
$('[id$=_ha]').prop('checked', result.ha);
|
77
|
+
}
|
78
|
+
setMemoryInputProps({ disabled: result.name != null });
|
79
|
+
disableCoresAndSockets(result);
|
80
|
+
['_ha'].forEach(name =>
|
81
|
+
$(`[id$=${name}]`).prop('readOnly', result.name != null)
|
82
|
+
);
|
83
|
+
const instanceTypeSelector = $(
|
84
|
+
'#host_compute_attributes_instance_type'
|
85
|
+
);
|
86
|
+
|
87
|
+
if (instanceTypeSelector.is(':disabled')) {
|
88
|
+
instanceTypeSelector.val(result.id).trigger('change');
|
89
|
+
}
|
90
|
+
},
|
91
|
+
complete() {
|
92
|
+
// eslint-disable-next-line no-undef
|
93
|
+
reloadOnAjaxComplete(item);
|
94
|
+
},
|
95
|
+
});
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
// fill in the template interfaces.
|
100
|
+
function addNetworkInterface({ name, network }) {
|
101
|
+
const nestedFields = $('#network_interfaces .add_nested_fields');
|
102
|
+
// no network interfaces update when the network editing is not allowed by the compute resource
|
103
|
+
|
104
|
+
if (nestedFields.length > 0) {
|
105
|
+
// eslint-disable-next-line no-undef
|
106
|
+
const newId = add_child_node(nestedFields);
|
107
|
+
|
108
|
+
$(`[id$=${newId}_name]`).val(name);
|
109
|
+
$(`[id$=${newId}_network]`).val(network);
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
// fill in the template volumes.
|
114
|
+
function addVolume({
|
115
|
+
size_gb: sizeGb,
|
116
|
+
storage_domain: storageDomain,
|
117
|
+
sparse,
|
118
|
+
bootable,
|
119
|
+
id,
|
120
|
+
disk_interface: diskInterface,
|
121
|
+
wipe_after_delete: wipeAfterDelete,
|
122
|
+
}) {
|
123
|
+
// eslint-disable-next-line no-undef
|
124
|
+
const newId = add_child_node($('#storage_volumes .add_nested_fields'));
|
125
|
+
|
126
|
+
disableElement($(`[id$=${newId}_size_gb]`).val(sizeGb));
|
127
|
+
$(`[id$=${newId}_storage_domain]`).val(storageDomain);
|
128
|
+
disableElement($(`[id$=${newId}_interface]`).val(diskInterface));
|
129
|
+
disableElement($(`[id$=${newId}_bootable_true]`).attr('checked', bootable));
|
130
|
+
disableElement(
|
131
|
+
$(`[id$=${newId}_wipe_after_delete]`).prop('checked', wipeAfterDelete)
|
132
|
+
);
|
133
|
+
if (id) {
|
134
|
+
$(`[id$=${newId}_id]`).val(id);
|
135
|
+
}
|
136
|
+
$(`[id$=${newId}_storage_domain]`)
|
137
|
+
.next()
|
138
|
+
.hide();
|
139
|
+
}
|
140
|
+
|
141
|
+
function setMemoryInputProps(props) {
|
142
|
+
const newProps = { ...props };
|
143
|
+
|
144
|
+
if (newProps.value !== undefined && newProps.value !== null) {
|
145
|
+
newProps.value = parseInt(newProps.value, 10);
|
146
|
+
}
|
147
|
+
|
148
|
+
const memoryInputElement = getComponentByWrapperId('memory-input');
|
149
|
+
memoryInputElement.reactProps = {
|
150
|
+
...memoryInputElement.reactProps,
|
151
|
+
...newProps,
|
152
|
+
};
|
153
|
+
}
|
154
|
+
|
155
|
+
function updateCoresAndSockets(result) {
|
156
|
+
const coresInputElement = getComponentByWrapperId('cores-input');
|
157
|
+
coresInputElement.reactProps = {
|
158
|
+
...coresInputElement.reactProps,
|
159
|
+
value: parseInt(result.cores, 10),
|
160
|
+
};
|
161
|
+
const socketInputElement = getComponentByWrapperId('sockets-input');
|
162
|
+
socketInputElement.reactProps = {
|
163
|
+
...socketInputElement.reactProps,
|
164
|
+
value: parseInt(result.sockets, 10),
|
165
|
+
};
|
166
|
+
}
|
167
|
+
|
168
|
+
function disableCoresAndSockets(result) {
|
169
|
+
const coresInputElement = getComponentByWrapperId('cores-input');
|
170
|
+
coresInputElement.reactProps = {
|
171
|
+
...coresInputElement.reactProps,
|
172
|
+
disabled: result.name != null,
|
173
|
+
};
|
174
|
+
const socketInputElement = getComponentByWrapperId('sockets-input');
|
175
|
+
socketInputElement.reactProps = {
|
176
|
+
...socketInputElement.reactProps,
|
177
|
+
disabled: result.name != null,
|
178
|
+
};
|
179
|
+
}
|
180
|
+
|
181
|
+
function getComponentByWrapperId(wrapperId) {
|
182
|
+
return document
|
183
|
+
.getElementById(wrapperId)
|
184
|
+
.getElementsByTagName('foreman-react-component')[0];
|
185
|
+
}
|
186
|
+
|
187
|
+
function disableElement(element) {
|
188
|
+
element
|
189
|
+
.clone()
|
190
|
+
.attr('type', 'hidden')
|
191
|
+
.appendTo(element);
|
192
|
+
element.attr('disabled', 'disabled');
|
193
|
+
}
|
194
|
+
|
195
|
+
function bootableRadio(item) {
|
196
|
+
const disabled = $('[id$=_bootable_true]:disabled:checked:visible');
|
197
|
+
|
198
|
+
$('[id$=_bootable_true]').prop('checked', false);
|
199
|
+
if (disabled.length > 0) {
|
200
|
+
disabled.prop('checked', true);
|
201
|
+
} else {
|
202
|
+
$(item).prop('checked', true);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
function clusterSelected(item) {
|
206
|
+
const cluster = $(item).val();
|
207
|
+
const url = $(item).data('url');
|
208
|
+
|
209
|
+
tfm.tools.showSpinner();
|
210
|
+
$.ajax({
|
211
|
+
type: 'post',
|
212
|
+
url,
|
213
|
+
data: `cluster_id=${cluster}`,
|
214
|
+
success(result) {
|
215
|
+
const networkOptions = $('select[id$=_network]').empty();
|
216
|
+
|
217
|
+
$.each(result, function() {
|
218
|
+
networkOptions.append(
|
219
|
+
$('<option />')
|
220
|
+
.val(this.id)
|
221
|
+
.text(this.name)
|
222
|
+
);
|
223
|
+
});
|
224
|
+
},
|
225
|
+
complete() {
|
226
|
+
// eslint-disable-next-line no-undef
|
227
|
+
reloadOnAjaxComplete(item);
|
228
|
+
},
|
229
|
+
});
|
230
|
+
}
|
231
|
+
|
232
|
+
function vnicSelected(item) {
|
233
|
+
const selectedVnicProfile = $(item).val();
|
234
|
+
if (selectedVnicProfile) {
|
235
|
+
const itemId = $(item).attr('id');
|
236
|
+
const nicId = itemId.match(/[a-z_]*_([0-9]+)[a-z_]*_vnic_profile/)[1];
|
237
|
+
const idNetwork = `id$=_${nicId}_network`;
|
238
|
+
|
239
|
+
const vnicOptions = JSON.parse(
|
240
|
+
$('select[id$=_vnic_profile]')[1].getAttribute('data-profiles')
|
241
|
+
);
|
242
|
+
const networkOptions = JSON.parse(
|
243
|
+
$('select[id$=_vnic_profile]')[1].getAttribute('data-networks')
|
244
|
+
);
|
245
|
+
|
246
|
+
const vnicNetwork = vnicOptions.filter(
|
247
|
+
vnicOption => vnicOption.id === selectedVnicProfile
|
248
|
+
)[0].network;
|
249
|
+
const networkObj = networkOptions.filter(
|
250
|
+
network => network.id === vnicNetwork.id
|
251
|
+
)[0];
|
252
|
+
const networkSelect = $(`select[${idNetwork}]`);
|
253
|
+
networkSelect.empty();
|
254
|
+
networkSelect.append(
|
255
|
+
$('<option />')
|
256
|
+
.val(networkObj.id)
|
257
|
+
.text(networkObj.name)
|
258
|
+
);
|
259
|
+
networkSelect.val(networkObj.id).trigger('change');
|
260
|
+
}
|
261
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ForemanOvirt
|
2
|
+
module ComputeResourcesVmsController
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
prepend Overrides
|
7
|
+
end
|
8
|
+
|
9
|
+
module Overrides
|
10
|
+
def index
|
11
|
+
load_vms
|
12
|
+
@authorizer = Authorizer.new(User.current, collection: [@compute_resource])
|
13
|
+
|
14
|
+
respond_to do |format|
|
15
|
+
format.html
|
16
|
+
format.json do
|
17
|
+
if @compute_resource.supports_vms_pagination?
|
18
|
+
# XXX: Foreman Core uses ".json", but this results in a "partial missing" error.
|
19
|
+
render partial: "compute_resources_vms/index/#{@compute_resource.provider.downcase}_json"
|
20
|
+
else
|
21
|
+
render json: _('JSON VM listing is not supported for this compute resource.'),
|
22
|
+
status: :not_implemented
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanOvirt
|
4
|
+
module ParametersExtension
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# This block is executed when the module is included in the base class.
|
8
|
+
# It's responsible for setting up the method alias chain.
|
9
|
+
included do
|
10
|
+
# We need to modify class methods, so we operate on the singleton class.
|
11
|
+
class << self
|
12
|
+
# Create an alias for the original method.
|
13
|
+
alias_method :compute_resource_params_filter_without_ovirt, :compute_resource_params_filter
|
14
|
+
# Make the original method name point to our new implementation.
|
15
|
+
alias_method :compute_resource_params_filter, :compute_resource_params_filter_with_ovirt
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
# Our new implementation that extends the original functionality.
|
21
|
+
def compute_resource_params_filter_with_ovirt
|
22
|
+
# Call the original method via its new alias to get the base filter object.
|
23
|
+
compute_resource_params_filter_without_ovirt.tap do |filter|
|
24
|
+
# Now, add the oVirt specific parameters to the existing filter.
|
25
|
+
filter.permit :datacenter,
|
26
|
+
:ovirt_quota,
|
27
|
+
:keyboard_layout,
|
28
|
+
:use_v4,
|
29
|
+
:public_key,
|
30
|
+
:uuid
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module ForemanOvirt
|
2
|
+
module Concerns
|
3
|
+
module ComputeResourcesControllerExtensions
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
prepended do
|
7
|
+
before_action :change_datacenter_to_uuid, only: [:create, :update]
|
8
|
+
rescue_from ::ProxyAPI::Ovirt::Unauthorized, with: :render_ovirt_unauthorized_error
|
9
|
+
end
|
10
|
+
|
11
|
+
def available_clusters
|
12
|
+
organization = find_organization_by_id_or_name(params[:organization_id], params[:organization_name])
|
13
|
+
location = find_location_by_id_or_name(params[:location_id], params[:location_name])
|
14
|
+
proxy = find_resource(params[:id], [organization, location].compact, ::ProxyAPI::Ovirt)
|
15
|
+
render json: proxy.clusters
|
16
|
+
rescue Foreman::Exception => e
|
17
|
+
render_error e.message, status: :not_found
|
18
|
+
end
|
19
|
+
|
20
|
+
def available_vnic_profiles
|
21
|
+
organization = find_organization_by_id_or_name(params[:organization_id], params[:organization_name])
|
22
|
+
location = find_location_by_id_or_name(params[:location_id], params[:location_name])
|
23
|
+
proxy = find_resource(params[:id], [organization, location].compact, ::ProxyAPI::Ovirt)
|
24
|
+
render json: proxy.vnic_profiles(params[:network_id])
|
25
|
+
rescue Foreman::Exception => e
|
26
|
+
render_error e.message, status: :not_found
|
27
|
+
end
|
28
|
+
|
29
|
+
def action_permission
|
30
|
+
case params[:action]
|
31
|
+
when 'available_clusters', 'available_vnic_profiles'
|
32
|
+
:view
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def change_datacenter_to_uuid
|
41
|
+
return unless params[:compute_resource] && params[:compute_resource][:provider] == 'Ovirt' && params[:compute_resource][:datacenter]
|
42
|
+
proxy = find_resource(params[:id]) if params[:id].present?
|
43
|
+
proxy ||= ::ProxyAPI::Ovirt.new(
|
44
|
+
url: params[:compute_resource][:url],
|
45
|
+
user: params[:compute_resource][:user],
|
46
|
+
password: params[:compute_resource][:password]
|
47
|
+
)
|
48
|
+
uuid = proxy.datacenter_uuid_by_name(params[:compute_resource][:datacenter])
|
49
|
+
params[:compute_resource][:datacenter] = uuid
|
50
|
+
rescue ::ProxyAPI::Ovirt::Unauthorized
|
51
|
+
rescue Foreman::Exception => e
|
52
|
+
render_error e.message, status: :not_found
|
53
|
+
end
|
54
|
+
|
55
|
+
def render_ovirt_unauthorized_error
|
56
|
+
render_error "401 Unauthorized", status: :unauthorized
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|