foreman_opennebula 2.3.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 +26 -0
- data/Rakefile +47 -0
- data/app/assets/javascripts/foreman_opennebula/scheduler_hint_filter_selected.js +30 -0
- data/app/assets/javascripts/foreman_opennebula/vmgroup_selected.js +30 -0
- data/app/controllers/foreman_opennebula/hosts_controller.rb +21 -0
- data/app/helpers/concerns/foreman_opennebula/form_helper_extensions.rb +9 -0
- data/app/helpers/concerns/foreman_opennebula/hosts_helper_extensions.rb +20 -0
- data/app/models/concerns/fog_extensions/opennebula/flavor.rb +109 -0
- data/app/models/concerns/fog_extensions/opennebula/interface.rb +11 -0
- data/app/models/concerns/fog_extensions/opennebula/server.rb +135 -0
- data/app/models/concerns/foreman_opennebula/key_pair_compute_resource.rb +80 -0
- data/app/models/foreman_opennebula/opennebula.rb +221 -0
- data/app/views/api/v2/compute_resources/opennebula.json.rabl +1 -0
- data/app/views/compute_resources/form/_opennebula.html.erb +6 -0
- data/app/views/compute_resources/show/_opennebula.html.erb +4 -0
- data/app/views/compute_resources_vms/form/opennebula/_base.html.erb +85 -0
- data/app/views/compute_resources_vms/form/opennebula/_network.html.erb +2 -0
- data/app/views/compute_resources_vms/form/opennebula/_scheduler_hint_data.html.erb +13 -0
- data/app/views/compute_resources_vms/form/opennebula/_vmgroup_role.html.erb +6 -0
- data/app/views/compute_resources_vms/index/_opennebula.html.erb +26 -0
- data/app/views/compute_resources_vms/show/_opennebula.html.erb +47 -0
- data/app/views/images/form/_opennebula.html.erb +4 -0
- data/config/routes.rb +6 -0
- data/lib/foreman_opennebula/engine.rb +59 -0
- data/lib/foreman_opennebula/version.rb +3 -0
- data/lib/foreman_opennebula.rb +4 -0
- data/lib/tasks/foreman_opennebula_tasks.rake +48 -0
- data/locale/Makefile +60 -0
- data/locale/en/foreman_opennebula.po +19 -0
- data/locale/foreman_opennebula.pot +19 -0
- data/locale/gemspec.rb +2 -0
- data/package.json +22 -0
- data/test/factories/foreman_opennebula_factories.rb +5 -0
- data/test/test_plugin_helper.rb +6 -0
- data/test/unit/foreman_opennebula_test.rb +11 -0
- data/webpack/components/MemorySizeInput/MemorySizeInput.css +4 -0
- data/webpack/components/MemorySizeInput/MemorySizeInput.js +83 -0
- data/webpack/components/MemorySizeInput/index.js +3 -0
- data/webpack/global_index.js +4 -0
- data/webpack/index.js +6 -0
- metadata +145 -0
@@ -0,0 +1,221 @@
|
|
1
|
+
module ForemanOpennebula
|
2
|
+
class Opennebula < ComputeResource
|
3
|
+
include ForemanOpennebula::KeyPairComputeResource
|
4
|
+
|
5
|
+
validates :url, :format => { :with => URI::DEFAULT_PARSER.make_regexp }, :presence => true
|
6
|
+
validates :user, :password, :presence => true
|
7
|
+
|
8
|
+
delegate :flavors, :networks, :to => :client
|
9
|
+
|
10
|
+
def self.provider_friendly_name
|
11
|
+
'OpenNebula'
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.model_name
|
15
|
+
ComputeResource.model_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def capabilities
|
19
|
+
[:build, :image, :key_pair]
|
20
|
+
end
|
21
|
+
|
22
|
+
def provided_attributes
|
23
|
+
super.merge({ :mac => :mac })
|
24
|
+
end
|
25
|
+
|
26
|
+
def possible_scheduler_hints
|
27
|
+
%w[Cluster Host Raw]
|
28
|
+
end
|
29
|
+
|
30
|
+
def available_flavors
|
31
|
+
# TODO: Sort by name.
|
32
|
+
flavors.sort_by { |flavor| flavor.id.to_i }
|
33
|
+
end
|
34
|
+
|
35
|
+
def available_networks
|
36
|
+
networks.sort_by(&:name)
|
37
|
+
end
|
38
|
+
|
39
|
+
def available_images
|
40
|
+
image_pool = ::OpenNebula::ImagePool.new(client.client)
|
41
|
+
rc = image_pool.info
|
42
|
+
raise ::Foreman::Exception.new N_(rc.message) if ::OpenNebula.is_error?(rc)
|
43
|
+
image_pool.sort_by(&:name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def available_clusters
|
47
|
+
cluster_pool = ::OpenNebula::ClusterPool.new(client.client)
|
48
|
+
rc = cluster_pool.info
|
49
|
+
raise ::Foreman::Exception.new N_(rc.message) if ::OpenNebula.is_error?(rc)
|
50
|
+
cluster_pool.sort_by(&:name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def available_hosts
|
54
|
+
host_pool = ::OpenNebula::HostPool.new(client.client)
|
55
|
+
rc = host_pool.info
|
56
|
+
raise ::Foreman::Exception.new N_(rc.message) if ::OpenNebula.is_error?(rc)
|
57
|
+
host_pool.sort_by(&:name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def available_vmgroups
|
61
|
+
vmgroup_pool = ::OpenNebula::VMGroupPool.new(client.client)
|
62
|
+
rc = vmgroup_pool.info
|
63
|
+
raise ::Foreman::Exception.new N_(rc.message) if ::OpenNebula.is_error?(rc)
|
64
|
+
vmgroup_pool.sort_by(&:name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def available_roles(vmgroup_id)
|
68
|
+
available_vmgroups.detect { |vmgroup| vmgroup.id == vmgroup_id.to_i }.role_names.sort
|
69
|
+
end
|
70
|
+
|
71
|
+
def available_users
|
72
|
+
user_pool = ::OpenNebula::UserPool.new(client.client)
|
73
|
+
rc = user_pool.info
|
74
|
+
raise ::Foreman::Exception.new N_(rc.message) if ::OpenNebula.is_error?(rc)
|
75
|
+
user_pool
|
76
|
+
end
|
77
|
+
|
78
|
+
def create_vm(args = {})
|
79
|
+
vm_attrs = {:name => args[:name]}
|
80
|
+
vm_attrs[:flavor] = flavors.get(args[:template_id])
|
81
|
+
vm_attrs[:flavor].template_id = args[:template_id]
|
82
|
+
vm_attrs[:flavor].cpu = args[:cpu] if args[:cpu].present?
|
83
|
+
vm_attrs[:flavor].vcpu = args[:vcpu] if args[:vcpu].present?
|
84
|
+
vm_attrs[:flavor].memory = args[:memory] if args[:memory].present?
|
85
|
+
|
86
|
+
if args[:disk_size].present?
|
87
|
+
[vm_attrs[:flavor].disk].flatten.compact.first[:SIZE] = args[:disk_size]
|
88
|
+
end
|
89
|
+
|
90
|
+
vm_attrs[:flavor].nic = args[:interfaces_attributes].map do |_, attrs|
|
91
|
+
nic = {
|
92
|
+
:vnet => networks.get(attrs[:vnet])
|
93
|
+
}
|
94
|
+
nic[:ip] = attrs['ip'] if args['provision_method'] == 'image' && attrs['ip'].present?
|
95
|
+
if vm_attrs[:flavor].nic_default.present?
|
96
|
+
vm_attrs[:flavor].nic_default.each do |param, value|
|
97
|
+
nic[param.downcase.to_sym] = value
|
98
|
+
end
|
99
|
+
end
|
100
|
+
new_interface(nic)
|
101
|
+
end
|
102
|
+
|
103
|
+
if args[:scheduler_hint_filter].present? && args[:scheduler_hint_data].present?
|
104
|
+
if args[:scheduler_hint_filter] == 'Cluster'
|
105
|
+
cluster = available_clusters.detect { |c| c.id == args[:scheduler_hint_data].to_i }
|
106
|
+
vm_attrs[:flavor].sched_requirements = "CLUSTER_ID = #{cluster.id}"
|
107
|
+
elsif args[:scheduler_hint_filter] == 'Host'
|
108
|
+
host = available_hosts.detect { |h| h.id == args[:scheduler_hint_data].to_i }
|
109
|
+
vm_attrs[:flavor].sched_requirements = "ID = #{host.id}"
|
110
|
+
else
|
111
|
+
vm_attrs[:flavor].sched_requirements = args[:scheduler_hint_data]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if args[:vmgroup_id].present? && args[:vmgroup_role].present?
|
116
|
+
vm_attrs[:flavor].vmgroup = { 'VMGROUP_ID' => args[:vmgroup_id], 'ROLE' => args[:vmgroup_role] }
|
117
|
+
end
|
118
|
+
|
119
|
+
if args['provision_method'] == 'image' && args['image_id'].present?
|
120
|
+
[vm_attrs[:flavor].disk].flatten.compact.first.delete('IMAGE')
|
121
|
+
[vm_attrs[:flavor].disk].flatten.compact.first['IMAGE_ID'] = args[:image_id]
|
122
|
+
|
123
|
+
vm_attrs[:flavor].context['SET_HOSTNAME'] = args[:name]
|
124
|
+
vm_attrs[:flavor].context['USER_DATA'] = args[:user_data] if args[:user_data].present?
|
125
|
+
|
126
|
+
vm_attrs[:flavor].os['BOOT'] = 'disk0'
|
127
|
+
else
|
128
|
+
vm_attrs[:flavor].os['BOOT'] = 'nic0,disk0'
|
129
|
+
end
|
130
|
+
|
131
|
+
vm = super(vm_attrs)
|
132
|
+
vm.wait_for { vm.status == 1 }
|
133
|
+
find_vm_by_uuid(vm.id)
|
134
|
+
end
|
135
|
+
|
136
|
+
def vm_ready(vm)
|
137
|
+
vm.wait_for { ready? || poweroff? }
|
138
|
+
raise Foreman::Exception.new(N_('Failed to run VM %{name}'), { :name => vm.name }) if vm.poweroff?
|
139
|
+
end
|
140
|
+
|
141
|
+
def supports_update?
|
142
|
+
true
|
143
|
+
end
|
144
|
+
|
145
|
+
def update_required?(old_attrs, new_attrs)
|
146
|
+
vm = find_vm_by_uuid(old_attrs[:uuid])
|
147
|
+
old_attrs[:disk_size] = vm.disk_size
|
148
|
+
super(old_attrs, new_attrs)
|
149
|
+
end
|
150
|
+
|
151
|
+
def save_vm(uuid, attr)
|
152
|
+
vm = find_vm_by_uuid(uuid)
|
153
|
+
changed_attrs = %i[cpu vcpu memory].reject { |k| vm.send(k).to_s == attr[k].to_s }
|
154
|
+
|
155
|
+
if !vm.ready? && !vm.poweroff?
|
156
|
+
raise ::Foreman::Exception.new N_("The VM status: #{vm.status}. It should be ACTIVE (3) or POWEROFF (8)")
|
157
|
+
end
|
158
|
+
|
159
|
+
last_state = vm.state
|
160
|
+
if vm.ready?
|
161
|
+
vm.onevm_object.poweroff(true)
|
162
|
+
vm.wait_for { poweroff? }
|
163
|
+
end
|
164
|
+
|
165
|
+
if changed_attrs.any?
|
166
|
+
flavor = client.flavors.new
|
167
|
+
%i[cpu vcpu memory].each { |k| flavor.send("#{k}=", attr[k].to_s) }
|
168
|
+
vm.onevm_object.resize(flavor.to_s, true)
|
169
|
+
|
170
|
+
renewed_vm = find_vm_by_uuid(uuid)
|
171
|
+
unchanged_attrs = changed_attrs.reject { |k| renewed_vm.send(k).to_s == attr[k].to_s }
|
172
|
+
if unchanged_attrs.any?
|
173
|
+
raise ::Foreman::Exception.new N_("Parameter #{unchanged_attrs.join(', ')} was not changed. "\
|
174
|
+
'Check if the host has enough resources for this VM')
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
if vm.disk_size.to_i != attr[:disk_size].to_i
|
179
|
+
disk_id = vm.disks.first.disk_id.to_i
|
180
|
+
rc = vm.onevm_object.disk_resize(disk_id, attr[:disk_size].to_i)
|
181
|
+
raise ::Foreman::Exception.new N_(rc.message) if ::OpenNebula.is_error?(rc)
|
182
|
+
sleep(1) # wait before resume vm
|
183
|
+
end
|
184
|
+
|
185
|
+
if last_state == 'RUNNING'
|
186
|
+
vm.onevm_object.resume
|
187
|
+
sleep(2)
|
188
|
+
vm_ready(vm)
|
189
|
+
end
|
190
|
+
vm
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_connection(options = {})
|
194
|
+
super
|
195
|
+
%i[url user password].all? { |i| errors[i].empty? } && !client.client.get_version.is_a?(OpenNebula::Error)
|
196
|
+
rescue => e
|
197
|
+
errors[:base] << e.message
|
198
|
+
end
|
199
|
+
|
200
|
+
def console(uuid)
|
201
|
+
vm = find_vm_by_uuid(uuid)
|
202
|
+
WsProxy.start(:host => vm.host, :host_port => vm.display[:port],
|
203
|
+
:password => vm.display[:password]).merge(:type => vm.display[:type], :name => vm.name)
|
204
|
+
end
|
205
|
+
|
206
|
+
def associated_host(vm)
|
207
|
+
associate_by('mac', vm.interfaces.map(&:mac))
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
def client
|
213
|
+
@client ||= Fog::Compute.new(
|
214
|
+
provider: 'OpenNebula',
|
215
|
+
opennebula_username: user,
|
216
|
+
opennebula_password: password,
|
217
|
+
opennebula_endpoint: url
|
218
|
+
)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
attributes :url
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<%= text_f f, :url, :label => _("URL"), :size => "col-md-8", :help_block => _("e.g. http://host.example.com:2633/RPC2") %>
|
2
|
+
<%= text_f f, :user, :label => _("User") %>
|
3
|
+
<%= password_f f, :password, :label => _("Password"), :unset => unset_password? %>
|
4
|
+
<div class="col-md-offset-2">
|
5
|
+
<%= test_connection_button_f(f, (f.object.flavors rescue false)) %>
|
6
|
+
</div>
|
@@ -0,0 +1,85 @@
|
|
1
|
+
<% unless new_vm %>
|
2
|
+
<% if host.compute_object.ready? %>
|
3
|
+
<%= alert(:header => _('Warning'),
|
4
|
+
:class => 'alert-warning',
|
5
|
+
:text => _('Editing VM parameters causes it to reboot.')) %>
|
6
|
+
<% end %>
|
7
|
+
<%= alert(:header => _('Notice'),
|
8
|
+
:class => 'alert-info',
|
9
|
+
:text => _('Disk size can only be increased.')) %>
|
10
|
+
<% disabled = true %>
|
11
|
+
<% else %>
|
12
|
+
<% disabled = false %>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<%= select_f f, :template_id, compute_resource.available_flavors, :id, :name, {},
|
16
|
+
:label => _('Template'),
|
17
|
+
:disabled => disabled %>
|
18
|
+
|
19
|
+
<%= counter_f f, :cpu,
|
20
|
+
:label => _('CPU'),
|
21
|
+
:min => 0.01,
|
22
|
+
:help_inline => _('Default from template') %>
|
23
|
+
|
24
|
+
<%= counter_f f, :vcpu,
|
25
|
+
:label => _('VCPU'),
|
26
|
+
:min => 1,
|
27
|
+
:help_inline => _('Default from template') %>
|
28
|
+
|
29
|
+
<%= megabyte_size_f f, :memory,
|
30
|
+
:label => _('Memory'),
|
31
|
+
:help_inline => _('Default from template') %>
|
32
|
+
|
33
|
+
<%= megabyte_size_f f, :disk_size,
|
34
|
+
:label => _('Disk'),
|
35
|
+
:help_inline => _('Default from template') %>
|
36
|
+
|
37
|
+
<% unless controller_name == 'compute_attributes' %>
|
38
|
+
<%= select_f f, :vmgroup_id, compute_resource.available_vmgroups, :id, :name, { :include_blank => true },
|
39
|
+
:label => _('VM Group'),
|
40
|
+
:help_inline => _('Optional'),
|
41
|
+
:'data-url' => url_for(controller: 'foreman_opennebula/hosts', action: 'vmgroup_selected'),
|
42
|
+
:onchange => 'vmgroupSelected(this);',
|
43
|
+
:disabled => disabled %>
|
44
|
+
|
45
|
+
<div id='vmgroup_role_wrapper'>
|
46
|
+
<% if host.compute_object.vmgroup_id.present? %>
|
47
|
+
<%= render :partial => 'compute_resources_vms/form/opennebula/vmgroup_role', :locals => {
|
48
|
+
:vmgroup_id => host.compute_object.vmgroup_id,
|
49
|
+
:disabled => disabled
|
50
|
+
} %>
|
51
|
+
<% end %>
|
52
|
+
</div>
|
53
|
+
|
54
|
+
<%= selectable_f f, :scheduler_hint_filter, compute_resource.possible_scheduler_hints, { :include_blank => true },
|
55
|
+
:label => _('Scheduler hint filter'),
|
56
|
+
:'data-url' => url_for(controller: 'foreman_opennebula/hosts',
|
57
|
+
action: 'scheduler_hint_filter_selected'),
|
58
|
+
:'data-minimum-results-for-search' => 'Infinity',
|
59
|
+
:onchange => 'schedulerHintFilterSelected(this);',
|
60
|
+
:help_inline => _('Optional'),
|
61
|
+
:disabled => disabled %>
|
62
|
+
|
63
|
+
<div id='scheduler_hint_data_wrapper'>
|
64
|
+
<% if host.compute_object.scheduler_hint_filter.present? %>
|
65
|
+
<%= render :partial => 'compute_resources_vms/form/opennebula/scheduler_hint_data', :locals => {
|
66
|
+
:scheduler_hint_filter => host.compute_object.scheduler_hint_filter,
|
67
|
+
:disabled => disabled
|
68
|
+
} %>
|
69
|
+
<% end %>
|
70
|
+
</div>
|
71
|
+
|
72
|
+
<%-
|
73
|
+
arch ||= nil ; os ||= nil
|
74
|
+
images = possible_images(compute_resource, arch, os)
|
75
|
+
-%>
|
76
|
+
<div id='image_selection'>
|
77
|
+
<%= select_f f, :image_id, images, :uuid, :name, {
|
78
|
+
:include_blank => (images.empty? || images.size == 1) ? false : _('Please select an image') },
|
79
|
+
:disabled => images.empty? || (params[:host] && params[:host][:provision_method] == 'build'),
|
80
|
+
:label => _('Image') %>
|
81
|
+
</div>
|
82
|
+
|
83
|
+
<%= javascript_include_tag 'foreman_opennebula/vmgroup_selected' %>
|
84
|
+
<%= javascript_include_tag 'foreman_opennebula/scheduler_hint_filter_selected' %>
|
85
|
+
<% end %>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<%- scheduler_hint_filter ||= @host.compute_attributes[:scheduler_hint_filter] %>
|
2
|
+
<%- disabled ||= false %>
|
3
|
+
<%= fields_for "#{type}[compute_attributes]", @host.compute_object do |f| %>
|
4
|
+
<%- if scheduler_hint_filter == 'Cluster' %>
|
5
|
+
<%= select_f f, :scheduler_hint_data, @host.compute_resource.available_clusters, :id, :name,
|
6
|
+
{ :include_blank => true }, :label => _("Deploy to cluster"), :disabled => disabled %>
|
7
|
+
<%- elsif scheduler_hint_filter == 'Host' %>
|
8
|
+
<%= select_f f, :scheduler_hint_data, @host.compute_resource.available_hosts, :id, :name,
|
9
|
+
{ :include_blank => true }, :label => _("Deploy to host"), :disabled => disabled %>
|
10
|
+
<%- else %>
|
11
|
+
<%= text_f f, :scheduler_hint_data, :label => _("Scheduler hint data"), :disabled => disabled %>
|
12
|
+
<%- end %>
|
13
|
+
<%- end %>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<%- vmgroup_id ||= @host.compute_attributes[:vmgroup_id] %>
|
2
|
+
<%- disabled ||= false %>
|
3
|
+
<%= fields_for "#{type}[compute_attributes]", @host.compute_object do |f| %>
|
4
|
+
<%= selectable_f f, :vmgroup_role, @host.compute_resource.available_roles(vmgroup_id),
|
5
|
+
{ :include_blank => true }, :label => _("Role"), :disabled => disabled %>
|
6
|
+
<%- end %>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<thead>
|
2
|
+
<tr>
|
3
|
+
<th><%= _('Name') %></th>
|
4
|
+
<th><%= _('CPU') %></th>
|
5
|
+
<th><%= _('VCPU') %></th>
|
6
|
+
<th><%= _('Memory') %></th>
|
7
|
+
<th><%= _('Storage') %></th>
|
8
|
+
<th><%= _('Host') %></th>
|
9
|
+
<th><%= _('State') %></th>
|
10
|
+
<th><%= _('Actions') %></th>
|
11
|
+
</tr>
|
12
|
+
</thead>
|
13
|
+
<tbody>
|
14
|
+
<% @vms.each do |vm| %>
|
15
|
+
<tr>
|
16
|
+
<td><%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.uuid).merge(:auth_object => @compute_resource, :auth_action => 'view', :authorizer => authorizer) %></td>
|
17
|
+
<td><%= vm.cpu %></td>
|
18
|
+
<td><%= vm.vcpu %></td>
|
19
|
+
<td><%= number_to_human_size(vm.memory.to_i.megabytes) %></td>
|
20
|
+
<td><%= number_to_human_size(vm.disks.map { |disk| disk.size.to_i.megabytes }.sum) %></td>
|
21
|
+
<td><%= vm.host %></td>
|
22
|
+
<td><span <%= vm_power_class(vm.ready?) %>><%= vm_state(vm) %></span></td>
|
23
|
+
<td><%= action_buttons(*available_actions(vm)) %></td>
|
24
|
+
</tr>
|
25
|
+
<% end %>
|
26
|
+
</tbody>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<% title @vm.name %>
|
2
|
+
<div class='col-md-12'>
|
3
|
+
<table class="<%= table_css_classes %>">
|
4
|
+
<thead>
|
5
|
+
<tr><th colspan="2"><%= _('Properties') %></th></tr>
|
6
|
+
</thead>
|
7
|
+
<tbody>
|
8
|
+
<%= prop :cpu, 'CPU' %>
|
9
|
+
<%= prop :vcpu, 'VCPU' %>
|
10
|
+
<tr>
|
11
|
+
<td><%= _('Memory') %></td>
|
12
|
+
<td><%= number_to_human_size(@vm.memory.to_i.megabytes) %></td>
|
13
|
+
</tr>
|
14
|
+
<% @vm.disks.each do |disk| %>
|
15
|
+
<tr>
|
16
|
+
<td><%= _("Disk %s") % disk.target %></td>
|
17
|
+
<td><%= "#{disk.image} / #{number_to_human_size(disk.size.to_i.megabytes)}" %></td>
|
18
|
+
</tr>
|
19
|
+
<% end %>
|
20
|
+
<% @vm.interfaces.each do |iface| %>
|
21
|
+
<tr>
|
22
|
+
<td><%= _("Nic %s") % iface.nic_id %></td>
|
23
|
+
<td><%= "#{iface.network} / #{iface.mac}" %></td>
|
24
|
+
</tr>
|
25
|
+
<% end %>
|
26
|
+
<% if @vm.vmgroup_id.present? %>
|
27
|
+
<tr>
|
28
|
+
<td><%= _("VM Group") %></td>
|
29
|
+
<td><%= @compute_resource.available_vmgroups.detect { |vmgroup| vmgroup.id == @vm.vmgroup_id.to_i }.name %></td>
|
30
|
+
</tr>
|
31
|
+
<tr>
|
32
|
+
<td><%= _("Role") %></td>
|
33
|
+
<td><%= @vm.vmgroup_role %></td>
|
34
|
+
</tr>
|
35
|
+
<% end %>
|
36
|
+
<% if @vm.host.present? %>
|
37
|
+
<tr>
|
38
|
+
<td><%= _("Cluster") %></td>
|
39
|
+
<td><%= @compute_resource.available_hosts.detect { |host| host.name == @vm.host }.to_hash['HOST']['CLUSTER'] %></td>
|
40
|
+
</tr>
|
41
|
+
<%= prop :host %>
|
42
|
+
<% end %>
|
43
|
+
<%= prop :state, 'LCM State' %>
|
44
|
+
<%= prop :sched_message if @vm.sched_message %>
|
45
|
+
</tbody>
|
46
|
+
</table>
|
47
|
+
</div>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<%= image_field f, :label => _("Image"), :help_inline => _("Image used to create new vm.") %>
|
2
|
+
<%= text_f f, :username, :value => @image.username || "root", :help_inline => _("The user that is used to ssh into the instance, normally cloud-user, ec2-user, ubuntu, root etc") %>
|
3
|
+
<%= password_f f, :password, :help_inline => _("Password to authenticate with - used for SSH finish step.") %>
|
4
|
+
<%= checkbox_f f, :user_data, :help_inline => _("Does this image support user data input (e.g. via cloud-init)?") %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
namespace :foreman_opennebula do
|
3
|
+
match 'hosts/vmgroup_selected', :to => 'hosts#vmgroup_selected', :via => 'post'
|
4
|
+
match 'hosts/scheduler_hint_filter_selected', :to => 'hosts#scheduler_hint_filter_selected', :via => 'post'
|
5
|
+
end
|
6
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'fast_gettext'
|
2
|
+
require 'gettext_i18n_rails'
|
3
|
+
require 'fog/opennebula'
|
4
|
+
|
5
|
+
module ForemanOpennebula
|
6
|
+
class Engine < ::Rails::Engine
|
7
|
+
isolate_namespace ForemanOpennebula
|
8
|
+
engine_name 'foreman_opennebula'
|
9
|
+
|
10
|
+
initializer 'foreman_opennebula.register_gettext', after: :load_config_initializers do |_app|
|
11
|
+
locale_dir = File.join(File.expand_path('../..', __dir__), 'locale')
|
12
|
+
locale_domain = 'foreman_opennebula'
|
13
|
+
Foreman::Gettext::Support.add_text_domain locale_domain, locale_dir
|
14
|
+
end
|
15
|
+
|
16
|
+
initializer 'foreman_opennebula.register_plugin', :before => :finisher_hook do |_app|
|
17
|
+
Foreman::Plugin.register :foreman_opennebula do
|
18
|
+
requires_foreman '>= 3.7'
|
19
|
+
compute_resource ForemanOpennebula::Opennebula
|
20
|
+
register_global_js_file 'global'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
config.to_prepare do
|
25
|
+
require 'fog/opennebula/models/compute/server'
|
26
|
+
require 'fog/opennebula/models/compute/flavor'
|
27
|
+
require 'fog/opennebula/models/compute/interface'
|
28
|
+
require File.expand_path('../../app/models/concerns/fog_extensions/opennebula/server', __dir__)
|
29
|
+
require File.expand_path('../../app/models/concerns/fog_extensions/opennebula/flavor', __dir__)
|
30
|
+
require File.expand_path('../../app/models/concerns/fog_extensions/opennebula/interface', __dir__)
|
31
|
+
require File.expand_path('../../app/helpers/concerns/foreman_opennebula/hosts_helper_extensions', __dir__)
|
32
|
+
require File.expand_path('../../app/helpers/concerns/foreman_opennebula/form_helper_extensions', __dir__)
|
33
|
+
|
34
|
+
::Fog::Compute::OpenNebula::Server.include(FogExtensions::OpenNebula::Server)
|
35
|
+
::Fog::Compute::OpenNebula::Flavor.include(FogExtensions::OpenNebula::Flavor)
|
36
|
+
::Fog::Compute::OpenNebula::Interface.include(FogExtensions::OpenNebula::Interface)
|
37
|
+
::HostsHelper.include(ForemanOpennebula::HostsHelperExtensions)
|
38
|
+
# ::FormHelper.include(ForemanOpennebula::FormHelperExtensions)
|
39
|
+
::ActionView::Base.include(ForemanOpennebula::FormHelperExtensions)
|
40
|
+
rescue => e
|
41
|
+
Rails.logger.warn "ForemanOpennebula: skipping engine hook (#{e})"
|
42
|
+
end
|
43
|
+
|
44
|
+
assets_to_precompile =
|
45
|
+
Dir.chdir(root) do
|
46
|
+
Dir['app/assets/javascripts/**/*', 'app/assets/stylesheets/**/*'].map do |f|
|
47
|
+
f.split(File::SEPARATOR, 4).last
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
initializer 'foreman_opennebula.assets.precompile' do |app|
|
52
|
+
app.config.assets.precompile += assets_to_precompile
|
53
|
+
end
|
54
|
+
|
55
|
+
initializer 'foreman_opennebula.configure_assets', group: :assets do
|
56
|
+
SETTINGS[:foreman_opennebula] = { assets: { precompile: assets_to_precompile } }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
# Tasks
|
4
|
+
namespace :foreman_opennebula do
|
5
|
+
namespace :example do
|
6
|
+
desc 'Example Task'
|
7
|
+
task task: :environment do
|
8
|
+
# Task goes here
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Tests
|
14
|
+
namespace :test do
|
15
|
+
desc 'Test ForemanOpennebula'
|
16
|
+
Rake::TestTask.new(:foreman_opennebula) do |t|
|
17
|
+
test_dir = File.expand_path('../../test', __dir__)
|
18
|
+
t.libs << 'test'
|
19
|
+
t.libs << test_dir
|
20
|
+
t.pattern = "#{test_dir}/**/*_test.rb"
|
21
|
+
t.verbose = true
|
22
|
+
t.warning = false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
namespace :foreman_opennebula do
|
27
|
+
task :rubocop do
|
28
|
+
begin
|
29
|
+
require 'rubocop/rake_task'
|
30
|
+
RuboCop::RakeTask.new(:rubocop_foreman_opennebula) do |task|
|
31
|
+
task.patterns = ["#{ForemanOpennebula::Engine.root}/app/**/*.rb",
|
32
|
+
"#{ForemanOpennebula::Engine.root}/lib/**/*.rb",
|
33
|
+
"#{ForemanOpennebula::Engine.root}/test/**/*.rb"]
|
34
|
+
end
|
35
|
+
rescue
|
36
|
+
puts 'Rubocop not loaded.'
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::Task['rubocop_foreman_opennebula'].invoke
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Rake::Task[:test].enhance ['test:foreman_opennebula']
|
44
|
+
|
45
|
+
load 'tasks/jenkins.rake'
|
46
|
+
if Rake::Task.task_defined?(:'jenkins:unit')
|
47
|
+
Rake::Task['jenkins:unit'].enhance ['test:foreman_opennebula', 'foreman_opennebula:rubocop']
|
48
|
+
end
|
data/locale/Makefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# Makefile for PO merging and MO generation. More info in the README.
|
3
|
+
#
|
4
|
+
# make all-mo (default) - generate MO files
|
5
|
+
# make check - check translations using translate-tool
|
6
|
+
# make tx-update - download and merge translations from Transifex
|
7
|
+
# make clean - clean everything
|
8
|
+
#
|
9
|
+
DOMAIN = foreman_opennebula
|
10
|
+
VERSION = $(shell ruby -e 'require "rubygems";spec = Gem::Specification::load(Dir.glob("../*.gemspec")[0]);puts spec.version')
|
11
|
+
POTFILE = $(DOMAIN).pot
|
12
|
+
MOFILE = $(DOMAIN).mo
|
13
|
+
POFILES = $(shell find . -name '$(DOMAIN).po')
|
14
|
+
MOFILES = $(patsubst %.po,%.mo,$(POFILES))
|
15
|
+
POXFILES = $(patsubst %.po,%.pox,$(POFILES))
|
16
|
+
EDITFILES = $(patsubst %.po,%.edit.po,$(POFILES))
|
17
|
+
|
18
|
+
%.mo: %.po
|
19
|
+
mkdir -p $(shell dirname $@)/LC_MESSAGES
|
20
|
+
msgfmt -o $(shell dirname $@)/LC_MESSAGES/$(MOFILE) $<
|
21
|
+
|
22
|
+
# Generate MO files from PO files
|
23
|
+
all-mo: $(MOFILES)
|
24
|
+
|
25
|
+
# Check for malformed strings
|
26
|
+
%.pox: %.po
|
27
|
+
msgfmt -c $<
|
28
|
+
pofilter --nofuzzy -t variables -t blank -t urls -t emails -t long -t newlines \
|
29
|
+
-t endwhitespace -t endpunc -t puncspacing -t options -t printf -t validchars --gnome $< > $@
|
30
|
+
cat $@
|
31
|
+
! grep -q msgid $@
|
32
|
+
|
33
|
+
%.edit.po:
|
34
|
+
touch $@
|
35
|
+
|
36
|
+
check: $(POXFILES)
|
37
|
+
|
38
|
+
# Unify duplicate translations
|
39
|
+
uniq-po:
|
40
|
+
for f in $(shell find ./ -name "*.po") ; do \
|
41
|
+
msguniq $$f -o $$f ; \
|
42
|
+
done
|
43
|
+
|
44
|
+
tx-pull: $(EDITFILES)
|
45
|
+
tx pull -f
|
46
|
+
for f in $(EDITFILES) ; do \
|
47
|
+
sed -i 's/^\("Project-Id-Version: \).*$$/\1$(DOMAIN) $(VERSION)\\n"/' $$f; \
|
48
|
+
done
|
49
|
+
|
50
|
+
tx-update: tx-pull
|
51
|
+
@echo
|
52
|
+
@echo Run rake plugin:gettext[$(DOMAIN)] from the Foreman installation, then make -C locale mo-files to finish
|
53
|
+
@echo
|
54
|
+
|
55
|
+
mo-files: $(MOFILES)
|
56
|
+
git add $(POFILES) $(POTFILE) ../locale/*/LC_MESSAGES
|
57
|
+
git commit -m "i18n - pulling from tx"
|
58
|
+
@echo
|
59
|
+
@echo Changes commited!
|
60
|
+
@echo
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# foreman_opennebula
|
2
|
+
#
|
3
|
+
# This file is distributed under the same license as foreman_opennebula.
|
4
|
+
#
|
5
|
+
#, fuzzy
|
6
|
+
msgid ""
|
7
|
+
msgstr ""
|
8
|
+
"Project-Id-Version: version 0.0.1\n"
|
9
|
+
"Report-Msgid-Bugs-To: \n"
|
10
|
+
"POT-Creation-Date: 2014-08-20 08:46+0100\n"
|
11
|
+
"PO-Revision-Date: 2014-08-20 08:54+0100\n"
|
12
|
+
"Last-Translator: Foreman Team <foreman-dev@googlegroups.com>\n"
|
13
|
+
"Language-Team: Foreman Team <foreman-dev@googlegroups.com>\n"
|
14
|
+
"Language: \n"
|
15
|
+
"MIME-Version: 1.0\n"
|
16
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
17
|
+
"Content-Transfer-Encoding: 8bit\n"
|
18
|
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
19
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# foreman_opennebula
|
2
|
+
#
|
3
|
+
# This file is distributed under the same license as foreman_opennebula.
|
4
|
+
#
|
5
|
+
#, fuzzy
|
6
|
+
msgid ""
|
7
|
+
msgstr ""
|
8
|
+
"Project-Id-Version: version 0.0.1\n"
|
9
|
+
"Report-Msgid-Bugs-To: \n"
|
10
|
+
"POT-Creation-Date: 2014-08-20 08:46+0100\n"
|
11
|
+
"PO-Revision-Date: 2014-08-20 08:46+0100\n"
|
12
|
+
"Last-Translator: Foreman Team <foreman-dev@googlegroups.com>\n"
|
13
|
+
"Language-Team: Foreman Team <foreman-dev@googlegroups.com>\n"
|
14
|
+
"Language: \n"
|
15
|
+
"MIME-Version: 1.0\n"
|
16
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
17
|
+
"Content-Transfer-Encoding: 8bit\n"
|
18
|
+
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
19
|
+
|
data/locale/gemspec.rb
ADDED