foreman_orchestration 0.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.
- data/LICENSE +619 -0
- data/README.md +38 -0
- data/Rakefile +47 -0
- data/app/assets/javascripts/foreman_orchestration/stacks.js +129 -0
- data/app/assets/stylesheets/foreman_orchestration/stacks.css.scss +3 -0
- data/app/assets/stylesheets/foreman_orchestration/templates.css.scss +4 -0
- data/app/controllers/concerns/foreman_orchestration/compute_resources_controller_extensions.rb +17 -0
- data/app/controllers/foreman_orchestration/stack_templates_controller.rb +57 -0
- data/app/controllers/foreman_orchestration/stacks_controller.rb +75 -0
- data/app/controllers/foreman_orchestration/tenants_controller.rb +26 -0
- data/app/helpers/concerns/foreman_orchestration/layout_helper_extensions.rb +22 -0
- data/app/models/concerns/foreman_orchestration/openstack_extensions.rb +51 -0
- data/app/models/foreman_orchestration/orchestration_client.rb +51 -0
- data/app/models/foreman_orchestration/stack.rb +91 -0
- data/app/models/foreman_orchestration/stack_template.rb +31 -0
- data/app/views/dashboard/_foreman_orchestration_widget.html.erb +2 -0
- data/app/views/foreman_orchestration/stack_templates/_form.html.erb +8 -0
- data/app/views/foreman_orchestration/stack_templates/_with_params.html.erb +31 -0
- data/app/views/foreman_orchestration/stack_templates/edit.html.erb +3 -0
- data/app/views/foreman_orchestration/stack_templates/index.html.erb +27 -0
- data/app/views/foreman_orchestration/stack_templates/new.html.erb +3 -0
- data/app/views/foreman_orchestration/stacks/_form.html.erb +40 -0
- data/app/views/foreman_orchestration/stacks/all.html.erb +40 -0
- data/app/views/foreman_orchestration/stacks/index.html.erb +49 -0
- data/app/views/foreman_orchestration/stacks/new.html.erb +6 -0
- data/app/views/foreman_orchestration/tenants/_for_select.html.erb +21 -0
- data/config/routes.rb +30 -0
- data/db/migrate/20151112145323_create_stack_templates.rb +10 -0
- data/lib/foreman_orchestration.rb +4 -0
- data/lib/foreman_orchestration/engine.rb +71 -0
- data/lib/foreman_orchestration/version.rb +3 -0
- data/lib/tasks/foreman_orchestration_tasks.rake +39 -0
- data/locale/Makefile +62 -0
- data/locale/en/foreman_orchestration.po +19 -0
- data/locale/foreman_orchestration.pot +19 -0
- data/locale/gemspec.rb +2 -0
- data/test/factories/foreman_orchestration_factories.rb +5 -0
- data/test/test_plugin_helper.rb +6 -0
- data/test/unit/foreman_orchestration_test.rb +11 -0
- metadata +137 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module ForemanOrchestration
|
2
|
+
class OrchestrationClient
|
3
|
+
extend Forwardable
|
4
|
+
def_delegators :@tenant, :id, :name, :description, :enabled
|
5
|
+
|
6
|
+
def initialize(tenant, credentials)
|
7
|
+
@tenant = tenant
|
8
|
+
@credentials = credentials
|
9
|
+
end
|
10
|
+
|
11
|
+
def stacks
|
12
|
+
client.stacks
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_stack(stack)
|
16
|
+
params = {
|
17
|
+
files: {},
|
18
|
+
disable_rollback: true,
|
19
|
+
parameters: stack.parameters,
|
20
|
+
stack_name: stack.name,
|
21
|
+
environment: {},
|
22
|
+
template: stack.template_body
|
23
|
+
}
|
24
|
+
client.create_stack(params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete_stack(stack)
|
28
|
+
fog_model = fog_model_for_stack(stack.id)
|
29
|
+
client.delete_stack(fog_model)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def credentials
|
35
|
+
@credentials.merge(openstack_tenant: name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def client
|
39
|
+
@client ||= Fog::Orchestration.new(credentials)
|
40
|
+
end
|
41
|
+
|
42
|
+
def fog_model_for_stack(id)
|
43
|
+
model = stacks.find { |s| s.id == id }
|
44
|
+
if model
|
45
|
+
model
|
46
|
+
else
|
47
|
+
raise "Cannot find a stack with the specified id: #{id}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module ForemanOrchestration
|
2
|
+
class Stack
|
3
|
+
include ActiveModel::Validations
|
4
|
+
include ActiveModel::Conversion
|
5
|
+
|
6
|
+
attr_accessor :id, :compute_resource_id, :tenant_id, :name, :template_id
|
7
|
+
attr_accessor :parameters
|
8
|
+
|
9
|
+
validates :compute_resource_id, presence: true
|
10
|
+
validates :tenant_id, presence: true
|
11
|
+
validates :name, presence: true, format: {with: /^[a-zA-Z][a-zA-Z0-9_.-]*$/}
|
12
|
+
validates :template_id, presence: true
|
13
|
+
|
14
|
+
def initialize(params = {})
|
15
|
+
@id = params[:id]
|
16
|
+
@name = params[:name]
|
17
|
+
@template_id = params[:template_id]
|
18
|
+
@parameters = params[:parameters] || {}
|
19
|
+
compute_resource_params(params)
|
20
|
+
tenant_params(params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def persisted?
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
def save
|
28
|
+
if valid?
|
29
|
+
tenant.create_stack(self)
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy
|
36
|
+
tenant.delete_stack(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def template
|
40
|
+
if template_id
|
41
|
+
@template ||= StackTemplate.find(template_id)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def template_body
|
46
|
+
if template
|
47
|
+
YAML.load(template.template)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def tenant
|
52
|
+
if tenant_id && compute_resource
|
53
|
+
@tenant ||= compute_resource.orchestration_client_for(tenant_id)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def compute_resource
|
58
|
+
if compute_resource_id
|
59
|
+
@compute_resource ||= Foreman::Model::Openstack.find(compute_resource_id)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def tenants
|
64
|
+
# TODO: find a better place for this method
|
65
|
+
if compute_resource
|
66
|
+
@tenants ||= compute_resource.orchestration_clients
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def tenant_params(params)
|
73
|
+
if params[:tenant]
|
74
|
+
@tenant = params[:tenant]
|
75
|
+
@tenant_id = @tenant.id
|
76
|
+
else
|
77
|
+
@tenant_id = params[:tenant_id]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def compute_resource_params(params)
|
82
|
+
if params[:compute_resource]
|
83
|
+
@compute_resource = params[:compute_resource]
|
84
|
+
@compute_resource_id = @compute_resource.id
|
85
|
+
else
|
86
|
+
@compute_resource_id = params[:compute_resource_id]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ForemanOrchestration
|
2
|
+
class StackTemplate < ActiveRecord::Base
|
3
|
+
attr_accessible :name, :template
|
4
|
+
|
5
|
+
validates :name, presence: true
|
6
|
+
validates :template, presence: true
|
7
|
+
|
8
|
+
validate do
|
9
|
+
begin
|
10
|
+
YAML.load(template)
|
11
|
+
rescue Psych::SyntaxError
|
12
|
+
errors.add(:template, 'Provided template is not a valid YAML file')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.for_select_tag
|
17
|
+
select([:id, :name]).order(:name).all
|
18
|
+
end
|
19
|
+
|
20
|
+
def parameters
|
21
|
+
@template_parameters ||= parse_parameters
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def parse_parameters
|
27
|
+
yaml = YAML.load(template)
|
28
|
+
yaml['parameters']
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= form_for @template, url: (@template.new_record? ? stack_templates_path : stack_template_path(@template)) do |f| %>
|
2
|
+
<%= base_errors_for @template %>
|
3
|
+
|
4
|
+
<%= text_f f, :name %>
|
5
|
+
<%= textarea_f f, :template, size: 'col-md-8', rows: 20 %>
|
6
|
+
|
7
|
+
<%= submit_or_cancel f %>
|
8
|
+
<% end %>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<%= hidden_field_tag 'foreman_orchestration_stack[template_id]', template.id %>
|
2
|
+
<h4>Review template body:</h4>
|
3
|
+
<div class="clearfix">
|
4
|
+
<div class="form-group">
|
5
|
+
<div class="row">
|
6
|
+
<div class="col-md-8">
|
7
|
+
<pre class="stack-template-body"><%= h template.template %></pre>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
<% unless template.parameters.empty? %>
|
13
|
+
<h4>Specify parameters for the chosen template:</h4>
|
14
|
+
<% template.parameters.each do |key, value| %>
|
15
|
+
<div class="clearfix">
|
16
|
+
<div class="form-group">
|
17
|
+
<div class="row">
|
18
|
+
<div class="col-md-2 control-label">
|
19
|
+
<%= label_tag key, key %>
|
20
|
+
</div>
|
21
|
+
<div class="col-md-6">
|
22
|
+
<%= text_field_tag "foreman_orchestration_stack[parameters[#{key}]]",
|
23
|
+
parameters[key] || value['default'],
|
24
|
+
class: 'form-control' %>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
<% end %>
|
30
|
+
<% end %>
|
31
|
+
<%= submit_tag 'Submit', class: 'btn btn-primary' %>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<% title _("Templates") %>
|
2
|
+
<% title_actions display_link_if_authorized(_("New Template"), hash_for_new_stack_template_path), help_path %>
|
3
|
+
|
4
|
+
<table class="table table-bordered table-striped table-two-pane">
|
5
|
+
<thead>
|
6
|
+
<tr>
|
7
|
+
<th>Name</th>
|
8
|
+
<th>Created at</th>
|
9
|
+
<th>Updated at</th>
|
10
|
+
<th>Action</th>
|
11
|
+
</tr>
|
12
|
+
</thead>
|
13
|
+
<tbody>
|
14
|
+
<% for template in @templates %>
|
15
|
+
<tr>
|
16
|
+
<td><%= h template.name %></td>
|
17
|
+
<td><%= template.created_at %></td>
|
18
|
+
<td><%= template.updated_at %></td>
|
19
|
+
<td>
|
20
|
+
<%= action_buttons(
|
21
|
+
display_link_if_authorized(_("Edit"), hash_for_edit_stack_template_path(:id => template).merge(:auth_object => template, :authorizer => authorizer)),
|
22
|
+
display_delete_if_authorized(hash_for_stack_template_path(:id => template).merge(:auth_object => template, :authorizer => authorizer), :data => { :confirm => 'Are you sure?'}, :action => :destroy)) %>
|
23
|
+
</td>
|
24
|
+
</tr>
|
25
|
+
<% end %>
|
26
|
+
</tbody>
|
27
|
+
</table>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<%= form_for @stack, url: stacks_path do |f| %>
|
2
|
+
<%= base_errors_for @stack %>
|
3
|
+
|
4
|
+
<%= selectable_f f, :compute_resource_id,
|
5
|
+
options_from_collection_for_select(@compute_resources, 'id', 'name', @stack.compute_resource_id),
|
6
|
+
{:include_blank => _('Choose a compute resource')},
|
7
|
+
{:label => _('Compute resource'),
|
8
|
+
:onchange => 'stacksNewComputeResourceSelected(this);',
|
9
|
+
:'data-url' => new_stack_path,
|
10
|
+
:help_inline => :indicator, :required => true} %>
|
11
|
+
|
12
|
+
<div id="tenants-list-container">
|
13
|
+
<div id="tenants-list">
|
14
|
+
<% if @stack.tenants %>
|
15
|
+
<%= selectable_f f, :tenant_id,
|
16
|
+
options_from_collection_for_select(@stack.tenants, 'id', 'name', @stack.tenant_id),
|
17
|
+
{:include_blank => _('Choose a tenant')},
|
18
|
+
{:label => _('Tenant'), :required => true} %>
|
19
|
+
|
20
|
+
<% end %>
|
21
|
+
</div>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<div id="main-stack-parameters" class="<%= 'hidden' unless @stack.compute_resource_id %>">
|
25
|
+
<%= text_f f, :name, required: true, label: _('Stack name'),
|
26
|
+
help_inline: _('This value must match the following pattern: ^[a-zA-Z][a-zA-Z0-9_.-]*$') %>
|
27
|
+
<%= selectable_f f, :template_id,
|
28
|
+
options_from_collection_for_select(ForemanOrchestration::StackTemplate.for_select_tag, 'id', 'name', @stack.template_id),
|
29
|
+
{include_blank: _('Choose a template')},
|
30
|
+
{:label => _('Template'), :'data-url' => with_params_stack_template_path(':template_id'),
|
31
|
+
:onchange => 'stacksLoadTemplateWithParams(this)', required: true,
|
32
|
+
:help_inline => :indicator} %>
|
33
|
+
<div id="template-with-params">
|
34
|
+
<% if @stack.template %>
|
35
|
+
<%= render partial: 'foreman_orchestration/stack_templates/with_params',
|
36
|
+
locals: {template: @stack.template, parameters: @stack.parameters} %>
|
37
|
+
<% end %>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
<% end %>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<% javascript 'foreman_orchestration/stacks' %>
|
2
|
+
<% stylesheet 'foreman_orchestration/stacks' %>
|
3
|
+
|
4
|
+
<%= form_for :stack do %>
|
5
|
+
<% title _("All Stacks") %>
|
6
|
+
|
7
|
+
<% if @compute_resources.empty? %>
|
8
|
+
<div class="alert alert-info">
|
9
|
+
There are no compute resources. But you can create a new one
|
10
|
+
<%= link_to 'here', new_compute_resource_path %>
|
11
|
+
</div>
|
12
|
+
<% else %>
|
13
|
+
<%= selectable_tag :compute_resource,
|
14
|
+
options_from_collection_for_select(@compute_resources, 'id', 'name', @compute_resource.try(:id)),
|
15
|
+
{:label => _('Compute resource'),
|
16
|
+
:onchange => 'stacksComputeResourceSelected(this);',
|
17
|
+
:help_inline => :indicator, :include_blank => true,
|
18
|
+
:'data-url' => for_select_compute_resource_tenants_path(':id'),
|
19
|
+
:'data-default-value' => @compute_resource.try(:id) } do %>
|
20
|
+
<%= content_tag :button, :id => 'set-default-compute-resource',
|
21
|
+
:type => 'button', :class => 'btn btn-primary',
|
22
|
+
:disabled => 'disabled', :onclick => 'setDefaultComputeResource(this);',
|
23
|
+
:'data-url' => default_compute_resource_path(':id'),
|
24
|
+
:'data-disable-with' => 'Processing...' do -%>
|
25
|
+
Set as default
|
26
|
+
<% end -%>
|
27
|
+
<% end %>
|
28
|
+
<% end %>
|
29
|
+
|
30
|
+
<div id="tenants-list">
|
31
|
+
<% if @tenants %>
|
32
|
+
<%= render partial: 'foreman_orchestration/tenants/for_select' %>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
35
|
+
<div id="stacks-list">
|
36
|
+
<% if @stacks %>
|
37
|
+
<%= render template: 'foreman_orchestration/stacks/index', layout: nil %>
|
38
|
+
<% end %>
|
39
|
+
</div>
|
40
|
+
<% end %>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<div class="row">
|
2
|
+
<div id="title_action" class="col-sm-12">
|
3
|
+
<%= link_to(
|
4
|
+
'New Stack',
|
5
|
+
new_stack_path(
|
6
|
+
:compute_resource_id => @compute_resource.id,
|
7
|
+
:tenant_id => @tenant.id
|
8
|
+
),
|
9
|
+
:class => 'btn btn-success'
|
10
|
+
) %>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<%# add: sorting, filters, checkboxes %>
|
15
|
+
<table class="table table-bordered table-striped table-two-pane">
|
16
|
+
<thead>
|
17
|
+
<tr>
|
18
|
+
<th>Name</th>
|
19
|
+
<th>Description</th>
|
20
|
+
<th>Status</th>
|
21
|
+
<th>Creation time</th>
|
22
|
+
<th>Updated time</th>
|
23
|
+
<th>Action</th>
|
24
|
+
</tr>
|
25
|
+
</thead>
|
26
|
+
<tbody>
|
27
|
+
<% for stack in @stacks %>
|
28
|
+
<tr>
|
29
|
+
<td><%= h stack.stack_name %></td>
|
30
|
+
<td><%= h stack.description %></td>
|
31
|
+
<td><%= h stack.stack_status %></td>
|
32
|
+
<td><%= stack.creation_time %></td>
|
33
|
+
<td><%= stack.updated_time %></td>
|
34
|
+
<td>
|
35
|
+
<%= link_to(
|
36
|
+
'Delete',
|
37
|
+
compute_resource_tenant_stack_path(
|
38
|
+
:compute_resource_id => @compute_resource.id,
|
39
|
+
:tenant_id => @tenant.id,
|
40
|
+
:id => stack.id
|
41
|
+
),
|
42
|
+
:method => :delete, :confirm => 'Are you sure?',
|
43
|
+
:class => 'delete'
|
44
|
+
)%>
|
45
|
+
</td>
|
46
|
+
</tr>
|
47
|
+
<% end %>
|
48
|
+
</tbody>
|
49
|
+
</table>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<% if @tenants.empty? %>
|
2
|
+
<div class="alert alert-info">
|
3
|
+
Selected compute resource doesn't have any tenant
|
4
|
+
</div>
|
5
|
+
<% else %>
|
6
|
+
<%= selectable_tag :tenant,
|
7
|
+
options_from_collection_for_select(@tenants, 'id', 'name', @tenant.try(:id)),
|
8
|
+
{:label => _('Tenant'),
|
9
|
+
:onchange => 'stacksTenantSelected(this);',
|
10
|
+
:'data-url' => compute_resource_tenant_stacks_path(@compute_resource, ':id'),
|
11
|
+
:'data-default-value' => @compute_resource.default_tenant_id,
|
12
|
+
:help_inline => :indicator, :include_blank => true} do %>
|
13
|
+
<%= content_tag :button, :id => 'set-default-tenant',
|
14
|
+
:type => 'button', :class => 'btn btn-primary',
|
15
|
+
:disabled => 'disabled', :onclick => 'setDefaultTenant(this);',
|
16
|
+
:'data-url' => default_compute_resource_tenant_path(@compute_resource, ':id'),
|
17
|
+
:'data-disable-with' => 'Processing...' do -%>
|
18
|
+
Set as default
|
19
|
+
<% end -%>
|
20
|
+
<% end %>
|
21
|
+
<% end %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
resources :compute_resources, :only => [] do
|
3
|
+
member do
|
4
|
+
post :default
|
5
|
+
end
|
6
|
+
scope :module => :foreman_orchestration do
|
7
|
+
resources :tenants, :only => [:index] do
|
8
|
+
collection do
|
9
|
+
get :for_select
|
10
|
+
end
|
11
|
+
member do
|
12
|
+
post :default
|
13
|
+
end
|
14
|
+
resources :stacks, :only => [:index, :destroy]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
scope :module => :foreman_orchestration do
|
19
|
+
resources :stacks, :only => [:new, :create] do
|
20
|
+
collection do
|
21
|
+
get :all
|
22
|
+
end
|
23
|
+
end
|
24
|
+
resources :stack_templates do
|
25
|
+
member do
|
26
|
+
get :with_params
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|