foreman_orchestration 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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