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.
Files changed (40) hide show
  1. data/LICENSE +619 -0
  2. data/README.md +38 -0
  3. data/Rakefile +47 -0
  4. data/app/assets/javascripts/foreman_orchestration/stacks.js +129 -0
  5. data/app/assets/stylesheets/foreman_orchestration/stacks.css.scss +3 -0
  6. data/app/assets/stylesheets/foreman_orchestration/templates.css.scss +4 -0
  7. data/app/controllers/concerns/foreman_orchestration/compute_resources_controller_extensions.rb +17 -0
  8. data/app/controllers/foreman_orchestration/stack_templates_controller.rb +57 -0
  9. data/app/controllers/foreman_orchestration/stacks_controller.rb +75 -0
  10. data/app/controllers/foreman_orchestration/tenants_controller.rb +26 -0
  11. data/app/helpers/concerns/foreman_orchestration/layout_helper_extensions.rb +22 -0
  12. data/app/models/concerns/foreman_orchestration/openstack_extensions.rb +51 -0
  13. data/app/models/foreman_orchestration/orchestration_client.rb +51 -0
  14. data/app/models/foreman_orchestration/stack.rb +91 -0
  15. data/app/models/foreman_orchestration/stack_template.rb +31 -0
  16. data/app/views/dashboard/_foreman_orchestration_widget.html.erb +2 -0
  17. data/app/views/foreman_orchestration/stack_templates/_form.html.erb +8 -0
  18. data/app/views/foreman_orchestration/stack_templates/_with_params.html.erb +31 -0
  19. data/app/views/foreman_orchestration/stack_templates/edit.html.erb +3 -0
  20. data/app/views/foreman_orchestration/stack_templates/index.html.erb +27 -0
  21. data/app/views/foreman_orchestration/stack_templates/new.html.erb +3 -0
  22. data/app/views/foreman_orchestration/stacks/_form.html.erb +40 -0
  23. data/app/views/foreman_orchestration/stacks/all.html.erb +40 -0
  24. data/app/views/foreman_orchestration/stacks/index.html.erb +49 -0
  25. data/app/views/foreman_orchestration/stacks/new.html.erb +6 -0
  26. data/app/views/foreman_orchestration/tenants/_for_select.html.erb +21 -0
  27. data/config/routes.rb +30 -0
  28. data/db/migrate/20151112145323_create_stack_templates.rb +10 -0
  29. data/lib/foreman_orchestration.rb +4 -0
  30. data/lib/foreman_orchestration/engine.rb +71 -0
  31. data/lib/foreman_orchestration/version.rb +3 -0
  32. data/lib/tasks/foreman_orchestration_tasks.rake +39 -0
  33. data/locale/Makefile +62 -0
  34. data/locale/en/foreman_orchestration.po +19 -0
  35. data/locale/foreman_orchestration.pot +19 -0
  36. data/locale/gemspec.rb +2 -0
  37. data/test/factories/foreman_orchestration_factories.rb +5 -0
  38. data/test/test_plugin_helper.rb +6 -0
  39. data/test/unit/foreman_orchestration_test.rb +11 -0
  40. metadata +137 -0
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # ForemanOrchestration
2
+
3
+ *Introdction here*
4
+
5
+ ## Installation
6
+
7
+ See [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
8
+ for how to install Foreman plugins
9
+
10
+ ## Usage
11
+
12
+ *Usage here*
13
+
14
+ ## TODO
15
+
16
+ *Todo list here*
17
+
18
+ ## Contributing
19
+
20
+ Fork and send a Pull Request. Thanks!
21
+
22
+ ## Copyright
23
+
24
+ Copyright (c) *year* *your name*
25
+
26
+ This program is free software: you can redistribute it and/or modify
27
+ it under the terms of the GNU General Public License as published by
28
+ the Free Software Foundation, either version 3 of the License, or
29
+ (at your option) any later version.
30
+
31
+ This program is distributed in the hope that it will be useful,
32
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
33
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34
+ GNU General Public License for more details.
35
+
36
+ You should have received a copy of the GNU General Public License
37
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
38
+
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'ForemanOrchestration'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
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 => _
42
+ puts 'Rubocop not loaded.'
43
+ end
44
+
45
+ task :default do
46
+ Rake::Task['rubocop'].execute
47
+ end
@@ -0,0 +1,129 @@
1
+ function updateDefaultEntityButton(selector, defaultValue, currentValue) {
2
+ var $button = $(selector);
3
+ if (currentValue == defaultValue || currentValue == '') {
4
+ $button.prop('disabled', true);
5
+ } else {
6
+ $button.prop('disabled', false);
7
+ }
8
+ }
9
+
10
+ function stacksComputeResourceSelected(item) {
11
+ var $item = $(item);
12
+ var computeResource = $item.val();
13
+ if (computeResource === '') {
14
+ return false;
15
+ } else {
16
+ $item.indicator_show();
17
+ var url = $item.data('url').replace(':id', computeResource);
18
+ var defaultValue = $item.data('default-value');
19
+ var $tenants = $('#tenants-list');
20
+ $('#stacks-list').empty();
21
+ $tenants.empty();
22
+ $tenants.load(url, function () {
23
+ $tenants.find('select').select2({allowClear: true});
24
+ $item.indicator_hide();
25
+ updateDefaultEntityButton('#set-default-compute-resource', defaultValue, computeResource);
26
+ });
27
+ }
28
+ }
29
+
30
+ function stacksNewComputeResourceSelected(item) {
31
+ var $item = $(item);
32
+ var computeResource = $item.val();
33
+ if (computeResource === '') {
34
+ return false;
35
+ } else {
36
+ $item.indicator_show();
37
+ var url = $item.data('url');
38
+ var params = $.param({compute_resource_id: computeResource});
39
+ var $main = $('#main-stack-parameters');
40
+ $main.hide();
41
+ var $container = $('#tenants-list-container');
42
+ $container.empty();
43
+ $container.load(url + ' #tenants-list', params, function () {
44
+ $container.find('select').select2({allowClear: true});
45
+ $main.show();
46
+ $item.indicator_hide();
47
+ });
48
+ }
49
+ }
50
+
51
+ function stacksTenantSelected(item) {
52
+ var $item = $(item);
53
+ var tenant = $item.val();
54
+ if (tenant === '') {
55
+ return false;
56
+ } else {
57
+ $item.indicator_show();
58
+ var url = $item.data('url').replace(':id', tenant);
59
+ var defaultValue = $item.data('default-value');
60
+ var $stacks = $('#stacks-list');
61
+ $stacks.empty();
62
+ $stacks.load(url, function () {
63
+ $item.indicator_hide();
64
+ updateDefaultEntityButton('#set-default-tenant', defaultValue, tenant);
65
+ });
66
+ }
67
+ }
68
+
69
+ function stacksLoadTemplateWithParams(item) {
70
+ var $item = $(item);
71
+ var templateId = $item.val();
72
+ if (templateId === '') {
73
+ return false;
74
+ } else {
75
+ $item.indicator_show();
76
+ var url = $item.data('url').replace(':template_id', templateId);
77
+ var params = $.param({template_id: templateId});
78
+ var $container = $('#template-with-params');
79
+ $container.hide();
80
+ $container.load(url, params, function () {
81
+ $container.show();
82
+ $item.indicator_hide();
83
+ });
84
+ }
85
+ }
86
+
87
+ function setDefaultComputeResource(button) {
88
+ var $button = $(button);
89
+ var $select = $('#compute_resource');
90
+ var computeResourceId = $select.val();
91
+ if (!$button.data('processing') && computeResourceId !== '') {
92
+ $button.data('processing', true);
93
+ var url = $button.data('url').replace(':id', computeResourceId);
94
+ var oldText = $button.text();
95
+ $button.text($button.data('disable-with'));
96
+ $.post(url).done(function () {
97
+ $button.prop('disabled', true);
98
+ $select.data('default-value', Number(computeResourceId));
99
+ }).fail(function () {
100
+ alert('Something went wrong');
101
+ }).always(function () {
102
+ $button.text(oldText);
103
+ $button.data('processing', false);
104
+ });
105
+ }
106
+ return false;
107
+ }
108
+
109
+ function setDefaultTenant(button) {
110
+ var $button = $(button);
111
+ var $select = $('#tenant');
112
+ var tenantId = $select.val();
113
+ if (!$button.data('processing') && tenantId !== '') {
114
+ $button.data('processing', true);
115
+ var url = $button.data('url').replace(':id', tenantId);
116
+ var oldText = $button.text();
117
+ $button.text($button.data('disable-with'));
118
+ $.post(url).done(function () {
119
+ $button.prop('disabled', true);
120
+ $select.data('default-value', tenantId);
121
+ }).fail(function () {
122
+ alert('Something went wrong');
123
+ }).always(function () {
124
+ $button.text(oldText);
125
+ $button.data('processing', false);
126
+ });
127
+ }
128
+ return false;
129
+ }
@@ -0,0 +1,3 @@
1
+ #stacks-list {
2
+ margin-top: 30px;
3
+ }
@@ -0,0 +1,4 @@
1
+ .stack-template-body {
2
+ max-height: 500px;
3
+ overflow: scroll;
4
+ }
@@ -0,0 +1,17 @@
1
+ module ForemanOrchestration
2
+ module ComputeResourcesControllerExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_filter :ajax_request, only: [:default]
7
+ end
8
+
9
+ def default
10
+ Foreman::Model::Openstack.find(params[:id])
11
+ .mark_as_default
12
+ respond_to do |format|
13
+ format.json { render :json => {}, :status => :ok }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ module ForemanOrchestration
2
+ class StackTemplatesController < ::ApplicationController
3
+ before_filter :find_resource, only: [:edit, :update, :destroy, :with_params]
4
+
5
+ def index
6
+ @templates = StackTemplate.order(:name).all
7
+ end
8
+
9
+ def new
10
+ @template = StackTemplate.new
11
+ end
12
+
13
+ # TODO: there is an API for template validation:
14
+ # http://developer.openstack.org/api-ref-orchestration-v1.html#template_validate
15
+ # Maybe we can use it here?
16
+ def create
17
+ @template = StackTemplate.new(template_params)
18
+ if @template.save
19
+ process_success object: @template
20
+ else
21
+ process_error object: @template
22
+ end
23
+ end
24
+
25
+ def update
26
+ if @template.update_attributes(template_params)
27
+ process_success object: @template
28
+ else
29
+ process_error object: @template
30
+ end
31
+ end
32
+
33
+ def destroy
34
+ if @template.destroy
35
+ process_success object: @template
36
+ else
37
+ process_error object: @template
38
+ end
39
+ end
40
+
41
+ # ajax methods
42
+ def with_params
43
+ render partial: 'with_params', locals: {template: @template, parameters: {}}
44
+ end
45
+
46
+ private
47
+
48
+ def template_params
49
+ params.fetch(:foreman_orchestration_stack_template)
50
+ .slice(:name, :template)
51
+ end
52
+
53
+ def find_resource
54
+ @template = StackTemplate.find(params[:id])
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,75 @@
1
+ module ForemanOrchestration
2
+ class StacksController < ::ApplicationController
3
+ before_filter :load_compute_resources, only: [:all, :new]
4
+
5
+ def all
6
+ @compute_resource = find_default_compute_resource
7
+ if @compute_resource
8
+ @tenants = @compute_resource.orchestration_clients
9
+ @tenant = @compute_resource.default_tenant
10
+ @stacks = @tenant.stacks if @tenant
11
+ end
12
+ end
13
+
14
+ def index
15
+ @compute_resource = find_compute_resource
16
+ @tenant = @compute_resource.orchestration_client_for(params[:tenant_id])
17
+ @stacks = @tenant.stacks
18
+ render layout: !ajax?
19
+ end
20
+
21
+ def new
22
+ @stack = Stack.new(new_stack_params)
23
+ end
24
+
25
+ def create
26
+ @stack = Stack.new(create_stack_params)
27
+ if @stack.save
28
+ flash[:notice] = "Stack '#{@stack.name}' is being created now"
29
+ redirect_to all_stacks_path
30
+ else
31
+ load_compute_resources
32
+ process_error object: @stack
33
+ end
34
+ end
35
+
36
+ def destroy
37
+ @stack = Stack.new(compute_resource_id: params[:compute_resource_id],
38
+ tenant_id: params[:tenant_id],
39
+ id: params[:id])
40
+ @stack.destroy
41
+ redirect_to all_stacks_path, notice: 'Stack is being deleted now'
42
+ end
43
+
44
+ private
45
+
46
+ def new_stack_params
47
+ if params[:compute_resource_id] && params[:tenant_id]
48
+ params.slice(:compute_resource_id, :tenant_id)
49
+ else
50
+ compute_resource = find_default_compute_resource
51
+ {
52
+ compute_resource: compute_resource,
53
+ tenant: compute_resource.default_tenant
54
+ }
55
+ end
56
+ end
57
+
58
+ def create_stack_params
59
+ params.fetch(:foreman_orchestration_stack)
60
+ .slice(:compute_resource_id, :tenant_id, :name, :template_id, :parameters)
61
+ end
62
+
63
+ def load_compute_resources
64
+ @compute_resources = ::Foreman::Model::Openstack.all
65
+ end
66
+
67
+ def find_default_compute_resource
68
+ @compute_resources.find(&:is_default) || @compute_resources.first
69
+ end
70
+
71
+ def find_compute_resource
72
+ Foreman::Model::Openstack.find(params[:compute_resource_id])
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,26 @@
1
+ module ForemanOrchestration
2
+ class TenantsController < ::ApplicationController
3
+ before_filter :ajax_request, only: [:default]
4
+ before_filter :find_compute_resource, only: [:for_select, :default]
5
+
6
+ def for_select
7
+ @tenants = @compute_resource.tenants
8
+ render partial: 'for_select'
9
+ end
10
+
11
+ def default
12
+ tenant = @compute_resource.orchestration_client_for(params[:id])
13
+ @compute_resource.default_tenant_id = tenant.id
14
+ @compute_resource.save!
15
+ respond_to do |format|
16
+ format.json { render :json => {}, :status => :ok }
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def find_compute_resource
23
+ @compute_resource = ::Foreman::Model::Openstack.find(params[:compute_resource_id])
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ module ForemanOrchestration
2
+ module LayoutHelperExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ def selectable_tag(name, options_tags = nil, options = {})
6
+ content_tag(:div, :class => 'clearfix') do
7
+ content_tag(:div, :class => 'form-group') do
8
+ label = label_tag(name, options.delete(:label), :class => 'col-md-3 control-label')
9
+ help = help_inline(:indicator, '')
10
+ add_help_to_label('col-md-4', label, help) do
11
+ addClass options, 'form-control'
12
+ select_tag name, options_tags, options
13
+ end + if block_given?
14
+ content_tag(:div, :class => 'col-md-2') do
15
+ yield
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,51 @@
1
+ module ForemanOrchestration
2
+ module OpenstackExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ def orchestration_clients
6
+ # TODO: select only enabled: true tenants?
7
+ @orchestration_clients ||= tenants.map do |t|
8
+ create_orchestration_client(t)
9
+ end
10
+ end
11
+
12
+ def orchestration_client_for(tenant_id)
13
+ orchestration_clients.find { |client| client.id == tenant_id }
14
+ end
15
+
16
+ def create_orchestration_client(tenant)
17
+ ForemanOrchestration::OrchestrationClient.new(tenant, fog_credentials)
18
+ end
19
+
20
+ def is_default
21
+ attrs[:is_default]
22
+ end
23
+
24
+ def mark_as_default
25
+ ActiveRecord::Base.transaction do
26
+ self.class.all.each do |record|
27
+ record.attrs[:is_default] = false
28
+ record.save!
29
+ end
30
+ attrs[:is_default] = true
31
+ save!
32
+ end
33
+ end
34
+
35
+ def default_tenant_id
36
+ attrs[:default_tenant_id]
37
+ end
38
+
39
+ def default_tenant_id=(tenant_id)
40
+ attrs[:default_tenant_id] = tenant_id
41
+ end
42
+
43
+ def default_tenant
44
+ if default_tenant_id
45
+ orchestration_client_for(default_tenant_id)
46
+ else
47
+ orchestration_clients.first
48
+ end
49
+ end
50
+ end
51
+ end