foreman_chef 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/chef_proxy_environment_refresh.js +26 -0
  3. data/app/controllers/foreman_chef/application_controller.rb +7 -0
  4. data/app/controllers/foreman_chef/environments_controller.rb +90 -0
  5. data/app/helpers/foreman_chef/chef_proxy_form.rb +22 -8
  6. data/app/lib/proxy_api/foreman_chef/chef_proxy.rb +13 -0
  7. data/app/models/foreman_chef/concerns/host_action_subject.rb +1 -2
  8. data/app/models/foreman_chef/concerns/host_and_hostgroup_extensions.rb +18 -0
  9. data/app/models/foreman_chef/concerns/host_extensions.rb +17 -0
  10. data/app/models/foreman_chef/concerns/hostgroup_extensions.rb +32 -0
  11. data/app/models/foreman_chef/concerns/smart_proxy_extensions.rb +44 -0
  12. data/app/models/foreman_chef/environment.rb +33 -0
  13. data/app/models/foreman_chef/fact_importer.rb +1 -1
  14. data/app/models/foreman_chef/fact_name.rb +1 -0
  15. data/app/overrides/add_chef_proxy.rb +1 -0
  16. data/app/services/foreman_chef/chef_server_importer.rb +100 -0
  17. data/app/views/foreman/unattended/snippets/_chef_client_bootstrap.erb +2 -1
  18. data/app/views/foreman_chef/environments/_form.html.erb +11 -0
  19. data/app/views/foreman_chef/environments/edit.html.erb +3 -0
  20. data/app/views/foreman_chef/environments/environments_for_chef_proxy.html.erb +3 -0
  21. data/app/views/foreman_chef/environments/import.html.erb +58 -0
  22. data/app/views/foreman_chef/environments/index.html.erb +35 -0
  23. data/app/views/foreman_chef/environments/new.html.erb +3 -0
  24. data/config/routes.rb +14 -0
  25. data/db/migrate/20150916141657_create_chef_environment.rb +20 -0
  26. data/lib/foreman_chef/engine.rb +46 -6
  27. data/lib/foreman_chef/version.rb +1 -1
  28. metadata +19 -6
  29. data/app/models/foreman_chef/chef_proxy_association.rb +0 -10
  30. data/app/models/foreman_chef/host_extensions.rb +0 -16
  31. data/app/models/foreman_chef/hostgroup_extensions.rb +0 -18
  32. data/app/models/foreman_chef/smart_proxy_extensions.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5548655ef04945387de4f731e48299605e51112f
4
- data.tar.gz: 4580383d50804a8a876eb1d71193c5fcbacd6b52
3
+ metadata.gz: 7da1a055be91131a483a56eb8769bf6fafe304b9
4
+ data.tar.gz: 2375b6891121651e6824fff3e73e8ec38261a437
5
5
  SHA512:
6
- metadata.gz: 69faf9ce712b4f2e51d81221f8e99f2b02d835d67d297e459876af7e7d7d10d2a6e0a38e4378062fc2337a03126169c5d65254206d7ce4b851b6c8d02058371d
7
- data.tar.gz: 1d5e194fa1e2033f1e325b46eb19eccf89f66bdef3826841e6f8f17d5b5285580a5400832ec17fa0d880cb8b180ef81f5fe67f9dbc29eb0d216bd292a88e2def
6
+ metadata.gz: f6e44141df5a607f79c380b3ca81ded67314e4eb6553e6e7b262b666915b0bee84442003e44cdaf8a20f34a230eba1230dc0948dab4157012ba1660e69e26dc4
7
+ data.tar.gz: efd17ea55ffb24fb2ae0067f023d9fa4f029aca65a85008ddd57e427710b57f78c3481f3d72cf8ec18608864a26f5b2961af3041cbe7d0bf0e8e98020638928a
@@ -0,0 +1,26 @@
1
+ $(function () {
2
+ $("#host_chef_proxy_id, #hostgroup_chef_proxy_id").change(function () {
3
+ var element = $(this);
4
+ var attrs = attribute_hash(['chef_proxy_id']);
5
+ var url = element.attr('data-url');
6
+ if (element.attr('id') == 'host_chef_proxy_id') {
7
+ attrs['type'] = 'host'
8
+ } else {
9
+ attrs['type'] = 'hostgroup'
10
+ }
11
+
12
+ foreman.tools.showSpinner();
13
+ $.ajax({
14
+ data: attrs,
15
+ type: 'get',
16
+ url: url,
17
+ complete: function () {
18
+ reloadOnAjaxComplete(element);
19
+ },
20
+ success: function (request) {
21
+ $('#host_chef_environment_id, #hostgroup_chef_environment_id').parent().parent().replaceWith(request);
22
+ }
23
+ });
24
+ });
25
+ });
26
+
@@ -0,0 +1,7 @@
1
+ module ForemanChef
2
+ class ApplicationController < ::ApplicationController
3
+ def resource_class
4
+ "::ForemanChef::#{controller_name.singularize.classify}".constantize
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,90 @@
1
+ module ForemanChef
2
+ class EnvironmentsController < ::ForemanChef::ApplicationController
3
+ include Foreman::Controller::AutoCompleteSearch
4
+ before_filter :find_resource, :only => [:edit, :update, :destroy]
5
+
6
+ def import
7
+ proxy = SmartProxy.authorized(:view_smart_proxies).find(params[:proxy])
8
+ opts = params[:proxy].blank? ? {} : { :url => proxy.url, :chef_proxy => proxy }
9
+ opts[:env] = params[:env] unless params[:env].blank?
10
+ @importer = ChefServerImporter.new(opts)
11
+ @changed = @importer.changes
12
+ if @changed.values.all?(&:empty?)
13
+ notice _("Nothing to synchronize")
14
+ redirect_to foreman_chef_environments_path
15
+ end
16
+ end
17
+
18
+ def synchronize
19
+ proxy = SmartProxy.authorized(:view_smart_proxies).find(params[:proxy])
20
+ if (errors = ChefServerImporter.new(:chef_proxy => proxy).obsolete_and_new(params[:changed])).empty?
21
+ notice _("Successfully updated environments")
22
+ else
23
+ error _("Failed to update environments: %s") % errors.to_sentence
24
+ end
25
+ redirect_to foreman_chef_environments_path
26
+ end
27
+
28
+ def index
29
+ @environments = resource_base.includes(:chef_proxy).search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
30
+ end
31
+
32
+ def new
33
+ @environment = ForemanChef::Environment.new
34
+ end
35
+
36
+ def create
37
+ @environment = ForemanChef::Environment.new(params[:foreman_chef_environment])
38
+ if @environment.save
39
+ process_success
40
+ else
41
+ process_error
42
+ end
43
+ end
44
+
45
+ def edit
46
+ end
47
+
48
+ def update
49
+ if @environment.update_attributes(params[:foreman_chef_environment])
50
+ process_success
51
+ else
52
+ process_error
53
+ end
54
+ end
55
+
56
+ def destroy
57
+ if @environment.destroy
58
+ process_success
59
+ else
60
+ process_error
61
+ end
62
+ end
63
+
64
+ def auto_complete_controller_name
65
+ 'foreman_chef_environments'
66
+ end
67
+
68
+ def environments_for_chef_proxy
69
+ @chef_proxy = SmartProxy.authorized(:view_smart_proxies).with_features('Chef').find_by_id(params[:chef_proxy_id])
70
+ @environments = @chef_proxy.present? ? @chef_proxy.chef_environments : []
71
+ @type = params[:type]
72
+ render :layout => false
73
+ end
74
+
75
+ protected
76
+
77
+ def controller_permission
78
+ 'chef_environments'
79
+ end
80
+
81
+ def action_permission
82
+ case params[:action]
83
+ when 'import', 'synchronize'
84
+ 'import'
85
+ else
86
+ super
87
+ end
88
+ end
89
+ end
90
+ end
@@ -1,14 +1,28 @@
1
1
  module ForemanChef
2
2
  module ChefProxyForm
3
3
  def chef_proxy_form(f)
4
- # Don't show this if we have no Chef proxies, otherwise always include blank
5
- # so the user can choose not to use puppet on this host
6
- proxies = SmartProxy.with_taxonomy_scope_override(@location,@organization).with_features('Chef')
7
- return if proxies.count == 0
8
- select_f f, :chef_proxy_id, proxies, :id, :name,
9
- { :include_blank => blank_or_inherit_f(f, :chef_proxy) },
10
- { :label => _("Chef proxy"),
11
- :help_inline => _("Use this foreman proxy as an entry point to your Chef, node will be managed via this proxy") }
4
+ # Don't show this if we have no Chef proxies, otherwise always include blank
5
+ # so the user can choose not to use puppet on this host
6
+ proxies = SmartProxy.with_taxonomy_scope_override(@location,@organization).with_features('Chef')
7
+ return if proxies.count == 0
8
+ javascript('chef_proxy_environment_refresh')
9
+
10
+ chef_proxy_form_chef_proxy_select(f, proxies) +
11
+ chef_proxy_form_chef_environment_select(f, f.object.available_chef_environments)
12
+ end
13
+
14
+ def chef_proxy_form_chef_environment_select(f, environments)
15
+ select_f(f, :chef_environment_id, environments, :id, :name,
16
+ {:include_blank => blank_or_inherit_f(f, :chef_environment_id)},
17
+ {:label => _("Chef environment")})
18
+ end
19
+
20
+ def chef_proxy_form_chef_proxy_select(f, proxies)
21
+ select_f(f, :chef_proxy_id, proxies, :id, :name,
22
+ { :include_blank => blank_or_inherit_f(f, :chef_proxy) },
23
+ { :label => _("Chef proxy"),
24
+ :help_inline => _("Use this foreman proxy as an entry point to your Chef, node will be managed via this proxy"),
25
+ :data => { :url => environments_for_chef_proxy_foreman_chef_environments_path } })
12
26
  end
13
27
  end
14
28
  end
@@ -17,6 +17,13 @@ module ProxyAPI
17
17
  end
18
18
  end
19
19
 
20
+ class Environment < ProxyAPI::Resource
21
+ def initialize(args)
22
+ @url = "#{args[:url]}/#{PREFIX}/environments"
23
+ super args
24
+ end
25
+ end
26
+
20
27
  def initialize(args)
21
28
  @args = args
22
29
  end
@@ -48,6 +55,12 @@ module ProxyAPI
48
55
  def delete_client(key)
49
56
  Client.new(@args).send(:delete, key)
50
57
  end
58
+
59
+ # List all Chef environments
60
+ # Returns : Hash representation of environments on chef server
61
+ def list_environments
62
+ Environment.new(@args).send(:get)
63
+ end
51
64
  end
52
65
  end
53
66
  end
@@ -13,11 +13,10 @@ module ForemanChef
13
13
  def action_input_key
14
14
  "host"
15
15
  end
16
-
17
16
  end
18
17
  end
19
18
  end
20
19
 
21
20
  class ::Host::Managed::Jail < Safemode::Jail
22
- allow :chef_proxy
21
+ allow :chef_proxy, :chef_environment
23
22
  end
@@ -0,0 +1,18 @@
1
+ module ForemanChef
2
+ module Concerns
3
+ module HostAndHostgroupExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ belongs_to :chef_proxy, :class_name => "SmartProxy"
8
+ belongs_to :chef_environment, :class_name => "ForemanChef::Environment"
9
+
10
+ attr_accessible :chef_proxy_id, :chef_environment_id
11
+ end
12
+
13
+ def available_chef_environments
14
+ self.chef_proxy.present? ? self.chef_proxy.chef_environments : []
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ module ForemanChef
2
+ module Concerns
3
+ module HostExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ alias_method_chain :set_hostgroup_defaults, :chef_attributes
8
+ end
9
+
10
+ def set_hostgroup_defaults_with_chef_attributes
11
+ set_hostgroup_defaults_without_chef_attributes
12
+ return unless hostgroup
13
+ assign_hostgroup_attributes(['chef_proxy_id', 'chef_environment_id'])
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ module ForemanChef
2
+ module Concerns
3
+ module HostgroupExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ def inherited_chef_proxy_id
7
+ read_attribute(:chef_proxy_id) || nested(:chef_proxy_id)
8
+ end
9
+
10
+ def inherited_chef_environment_id
11
+ read_attribute(:chef_environment_id) || nested(:chef_environment_id)
12
+ end
13
+
14
+ def chef_proxy
15
+ if ancestry.present?
16
+ SmartProxy.with_features('Chef').find_by_id(inherited_chef_proxy_id)
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def chef_environment
23
+ if ancestry.present?
24
+ ::ForemanChef::Environment.find_by_id(inherited_chef_environment_id)
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,44 @@
1
+ module ForemanChef
2
+ module Concerns
3
+ module SmartProxyExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ has_many :chef_environments, :class_name => "::ForemanChef::Environment", :foreign_key => 'chef_proxy_id'
8
+ end
9
+
10
+ # create or overwrite instance methods...
11
+ def show_node(fqdn)
12
+ reply = ProxyAPI::ForemanChef::ChefProxy.new(:url => url).show_node(fqdn)
13
+ JSON.parse(reply)
14
+ rescue RestClient::ResourceNotFound
15
+ Foreman::Logging.logger('foreman_chef').debug "Node '#{fqdn}' not found"
16
+ return false
17
+ end
18
+
19
+ def delete_node(fqdn)
20
+ begin
21
+ reply = ProxyAPI::ForemanChef::ChefProxy.new(:url => url).delete_node(fqdn)
22
+ JSON.parse(reply)
23
+ #rescue RestClient::
24
+ end
25
+ end
26
+
27
+ def show_client(fqdn)
28
+ reply = ProxyAPI::ForemanChef::ChefProxy.new(:url => url).show_client(fqdn)
29
+ JSON.parse(reply)
30
+ rescue RestClient::ResourceNotFound
31
+ Foreman::Logging.logger('foreman_chef').debug "Client '#{fqdn}' not found"
32
+ return false
33
+ end
34
+
35
+ def delete_client(fqdn)
36
+ begin
37
+ reply = ProxyAPI::ForemanChef::ChefProxy.new(:url => url).delete_client(fqdn)
38
+ JSON.parse(reply)
39
+ #rescue RestClient::
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,33 @@
1
+ module ForemanChef
2
+ class Environment < ActiveRecord::Base
3
+ include Authorizable
4
+ extend FriendlyId
5
+ friendly_id :name
6
+ include Parameterizable::ByName
7
+
8
+ has_many :hosts, :class_name => '::Host::Managed'
9
+ has_many :hostgroups, :class_name => '::Hostgroup'
10
+ belongs_to :chef_proxy, :class_name => '::SmartProxy'
11
+
12
+ attr_accessible :name, :description, :chef_proxy_id
13
+
14
+ validates :name, :uniqueness => true, :presence => true, :format => { :with => /\A[\w\d\.]+\z/, :message => N_('is alphanumeric and cannot contain spaces') }
15
+
16
+ scoped_search :on => :name, :complete_value => true
17
+ scoped_search :in => :hostgroups, :on => :name, :complete_value => true, :rename => :hostgroup
18
+ scoped_search :in => :hosts, :on => :name, :complete_value => true, :rename => :host
19
+ scoped_search :in => :chef_proxy, :on => :name, :complete_value => true, :rename => 'chef_proxy.name'
20
+
21
+ class Jail < Safemode::Jail
22
+ allow :name
23
+ end
24
+
25
+ def self.humanize_class_name(_name = nil)
26
+ _('Chef environment')
27
+ end
28
+
29
+ def self.permission_name(action)
30
+ "#{action}_chef_environments"
31
+ end
32
+ end
33
+ end
@@ -75,7 +75,7 @@ module ForemanChef
75
75
  end
76
76
 
77
77
  def fact_names
78
- @fact_names ||= fact_name_class.maximum(:id, :group => 'name')
78
+ @fact_names ||= fact_name_class.group(:name).maximum(:id)
79
79
  end
80
80
 
81
81
  # if the host does not exists yet, we don't have an host_id to use the fact_values table.
@@ -1,4 +1,5 @@
1
1
  module ForemanChef
2
2
  class FactName < ::FactName
3
+ attr_accessible :compose
3
4
  end
4
5
  end
@@ -14,3 +14,4 @@ Deface::Override.new(:virtual_path => "hostgroups/_form",
14
14
  # detected within the full override template string above
15
15
  N_('Chef proxy')
16
16
  N_('Use this foreman proxy as an entry point to your Chef, node will be managed via this proxy')
17
+ N_('Chef environment')
@@ -0,0 +1,100 @@
1
+ module ForemanChef
2
+ class ChefServerImporter
3
+ def initialize(args = {})
4
+ @chef_proxy = args[:chef_proxy]
5
+ @environment = args[:env]
6
+ @proxy = args[:proxy]
7
+ @url_arg = args[:url]
8
+ end
9
+
10
+ def proxy
11
+ if @proxy
12
+ @proxy
13
+ elsif @url_arg
14
+ @proxy = ProxyAPI::ForemanChef::ChefProxy.new(:url => @url_arg)
15
+ else
16
+ url = SmartProxy.with_features('Chef').first.try(:url)
17
+ raise "Can't find a valid Proxy with a Chef feature" if url.blank?
18
+ @proxy = ProxyAPI::ForemanChef::ChefProxy.new(:url => url)
19
+ end
20
+ end
21
+ attr_writer :proxy
22
+
23
+ # return changes hash, currently exists to keep compatibility with importer html
24
+ def changes
25
+ changes = {'new' => {}, 'obsolete' => {}, 'updated' => {}}
26
+
27
+ if @environment.nil?
28
+ new_environments.each do |env|
29
+ changes['new'][env] = {}
30
+ end
31
+
32
+ old_environments.each do |env|
33
+ changes['obsolete'][env] = {}
34
+ end
35
+ else
36
+ env = @environment
37
+ changes['new'][env] = {} if new_environments.include?(@environment)
38
+ changes['obsolete'][env] = {} if old_environments.include?(@environment)
39
+ end
40
+ changes
41
+ end
42
+
43
+ # Update the environments based upon the user's selection
44
+ # +changes+ : Hash with two keys: :new and :obsolete.
45
+ # changed[:/new|obsolete/] is and Array of Strings
46
+ # Returns : Array of Strings containing all record errors
47
+ def obsolete_and_new(changes = { })
48
+ return if changes.empty?
49
+ if changes['new'].present?
50
+ changes['new'].each { |name, _| ForemanChef::Environment.create(:name => name, :chef_proxy_id => @chef_proxy.id) }
51
+ end
52
+ if changes['obsolete'].present?
53
+ changes['obsolete'].each { |name, _| ForemanChef::Environment.where(:chef_proxy_id => @chef_proxy.id).find_by_name(name).destroy }
54
+ end
55
+ []
56
+ end
57
+
58
+ def db_environments
59
+ @db_environments ||= (ForemanChef::Environment.where(:chef_proxy_id => @chef_proxy.id).pluck('name') - ignored_environments)
60
+ end
61
+
62
+ def actual_environments
63
+ @actual_environments ||= (fetch_environments_from_proxy.map { |e| e['name'] } - ignored_environments)
64
+ end
65
+
66
+ def new_environments
67
+ actual_environments - db_environments
68
+ end
69
+
70
+ def old_environments
71
+ db_environments - actual_environments
72
+ end
73
+
74
+ private
75
+
76
+ def fetch_environments_from_proxy
77
+ JSON.parse(proxy.list_environments)
78
+ rescue => e
79
+ Foreman::Logging.exception 'Failed to get environments from proxy', e
80
+ return []
81
+ end
82
+
83
+ def ignored_environments
84
+ ignored_file[:ignored] || []
85
+ end
86
+
87
+ def ignored_file
88
+ return @ignored_file if @ignored_file
89
+ file = File.join(Rails.root.to_s, "config", "ignored_environments.yml")
90
+ @ignored_file = File.exist?(file) ? YAML.load_file(file) : {}
91
+ rescue => e
92
+ logger.warn "Failed to parse environment ignore file: #{e}"
93
+ @ignored_file = {}
94
+ end
95
+
96
+ def logger
97
+ @logger ||= Foreman::Logging.logger('foreman_chef')
98
+ end
99
+ end
100
+ end
@@ -43,7 +43,8 @@ EOF
43
43
 
44
44
  #first run of chef-client
45
45
  echo "First run of chef-client"
46
- /usr/local/bin/chef-client -j /tmp/base.json || /usr/bin/chef-client -j /tmp/base.json
46
+ <% chef_args = "-j /tmp/base.json -E #{@host.chef_environment.nil? ? '_default' : @host.chef_environment.name }" -%>
47
+ /usr/local/bin/chef-client <%= chef_args %> || /usr/bin/chef-client <%= chef_args %>
47
48
 
48
49
  echo "Finished, cleaning"
49
50
  rm -f /tmp/base.json
@@ -0,0 +1,11 @@
1
+ <%= form_for @environment, :url => (@environment.new_record? ? foreman_chef_environments_path : foreman_chef_environment_path(:id => @environment)) do |f| %>
2
+ <%= base_errors_for @environment %>
3
+
4
+ <%= text_f f, :name %>
5
+ <%= select_f f, :chef_proxy_id, SmartProxy.with_features('Chef'), :id, :name,
6
+ {},
7
+ { :label => _('Chef proxy'), :help_inline => popover('Chef proxy association', _('When you select this proxy in host or host group form,<br>all associated environments will be loaded into environment select box')) } %>
8
+ <%= textarea_f f, :description, :rows => 3 %>
9
+
10
+ <%= submit_or_cancel f, false, :cancel_path => foreman_chef_environments_path %>
11
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% title _("Edit Environment") %>
2
+
3
+ <%= render :partial => 'form' %>
@@ -0,0 +1,3 @@
1
+ <%= fields_for @type do |f| %>
2
+ <%= chef_proxy_form_chef_environment_select f, @environments %>
3
+ <% end %>
@@ -0,0 +1,58 @@
1
+ <% title _("Changed environments") %>
2
+ <%= form_tag synchronize_foreman_chef_environments_path do %>
3
+ <%= hidden_field_tag :proxy, params[:proxy] %>
4
+ <h4><%= _("Select the changes you want to realize in Foreman") %></h4>
5
+ <h6>
6
+ <%= _("Toggle") %>:
7
+ <%= link_to_function(icon_text("check", _("New")),
8
+ "toggleCheckboxesBySelector('.env_select_boxes_new')",
9
+ :title => _("Check/Uncheck new")) %> |
10
+ <%= link_to_function(icon_text("check", _("Updated")),
11
+ "toggleCheckboxesBySelector('.env_select_boxes_updated')",
12
+ :title => _("Check/Uncheck updated")) %> |
13
+ <%= link_to_function(icon_text("check", _("Obsolete")),
14
+ "toggleCheckboxesBySelector('.env_select_boxes_obsolete')",
15
+ :title => _("Check/Uncheck obsolete")) %>
16
+ </h6>
17
+ <table class="table table-striped table-bordered">
18
+ <thead>
19
+ <tr>
20
+ <th class="ca">
21
+ <%= link_to_function(icon_text("check"),
22
+ "toggleCheckboxesBySelector('.env_select_boxes')",
23
+ :title => _("Check/Uncheck all")) %>
24
+ </th>
25
+ <th><%= _("Environment") %></th>
26
+ <th><%= _("Operation") %></th>
27
+ <th><%= _("Additional data") %></th>
28
+ </tr>
29
+ </thead>
30
+ <tbody>
31
+ <% for kind in ["new", "obsolete", "updated"] %>
32
+ <% unless (envs = @changed[kind]).empty? %>
33
+ <% for env in envs.keys.sort %>
34
+ <tr>
35
+ <td>
36
+ <%= check_box_tag "changed[#{kind}][#{env}]", @changed[kind][env].to_json, false, :class => "env_select_boxes env_select_boxes_#{kind} env_select_boxes_env_#{env}" %>
37
+ </td>
38
+ <td>
39
+ <%= link_to_function("#{env}", "toggleCheckboxesBySelector('.env_select_boxes_env_#{env}')", :title => _("Check/Uncheck all %s changes") % env) %>
40
+ </td>
41
+ <td>
42
+ <%= {"new" => _("Add:"), "obsolete" => _("Remove:"), "updated" => _("Update:")}[kind] %>
43
+ </td>
44
+ <td>
45
+ <% pcs = @changed[kind][env] %>
46
+ <%= class_update_text pcs, env %>
47
+ </td>
48
+ </tr>
49
+ <% end %>
50
+ <% end %>
51
+ <% end %>
52
+ </tbody>
53
+ </table>
54
+ <div>
55
+ <%= link_to _("Cancel"), send("foreman_chef_environments_path"), :class => "btn btn-default" %>
56
+ <%= submit_tag _("Update"), :class => "btn btn-primary" %>
57
+ </div>
58
+ <% end %>
@@ -0,0 +1,35 @@
1
+ <% title _('Chef Environments') %>
2
+
3
+ <% title_actions(
4
+ select_action_button(_('Import'), {}, SmartProxy.with_features('Chef').map do |proxy|
5
+ display_link_if_authorized(_("Import from %s chef server") % proxy.name,
6
+ hash_for_import_foreman_chef_environments_path(:proxy => proxy),
7
+ {:class => 'btn btn-default', :"data-no-turbolink" => true})
8
+ end.flatten)
9
+ ) %>
10
+ <% title_actions button_group(display_link_if_authorized(_('New Chef Environment'), hash_for_new_foreman_chef_environment_path)) %>
11
+
12
+ <table class="table table-bordered table-striped">
13
+ <tr>
14
+ <th><%= sort :name, :as => s_('Environment|Name') %></th>
15
+ <th><%= sort :host, :as => _('Hosts'), :default => 'DESC' %></th>
16
+ <th><%= sort :hostgroup, :as => _('Host groups'), :default => 'DESC' %></th>
17
+ <th><%= sort 'chef_proxy.name', :as => _('Chef proxy'), :default => 'DESC' %></th>
18
+ <th></th>
19
+ </tr>
20
+ <% for chef_environment in @environments %>
21
+ <tr>
22
+ <td><%= link_to_if_authorized h(chef_environment.name), hash_for_edit_foreman_chef_environment_path(:id => chef_environment).merge(:auth_object => chef_environment, :authorizer => authorizer) %></td>
23
+ <td><%= link_to_if_authorized(chef_environment.hosts.count, hash_for_hosts_path(:search => "chef_environment = #{chef_environment}")) %></td>
24
+ <td><%= link_to_if_authorized(chef_environment.hostgroups.count, hash_for_hostgroups_path(:search => "chef_environment = #{chef_environment}")) %></td>
25
+ <td><%= link_to_if_authorized(chef_environment.chef_proxy.name, hash_for_smart_proxy_path(chef_environment.chef_proxy)) %></td>
26
+ <td>
27
+ <%= action_buttons(display_delete_if_authorized(hash_for_foreman_chef_environment_path(:id => chef_environment).merge(:auth_object => chef_environment, :authorizer => authorizer),
28
+ :confirm => _('Delete %s?') % chef_environment.name)) %>
29
+ </td>
30
+ </tr>
31
+ <% end %>
32
+ </table>
33
+
34
+ <%= page_entries_info @environments %>
35
+ <%= will_paginate @environments %>
@@ -0,0 +1,3 @@
1
+ <% title _("New Environment") %>
2
+
3
+ <%= render :partial => 'form' %>
data/config/routes.rb ADDED
@@ -0,0 +1,14 @@
1
+ Rails.application.routes.draw do
2
+
3
+ namespace :foreman_chef do
4
+ resources :environments do
5
+ collection do
6
+ get :auto_complete_search
7
+ get :import
8
+ post :synchronize
9
+ get :environments_for_chef_proxy
10
+ end
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,20 @@
1
+ class CreateChefEnvironment < ActiveRecord::Migration
2
+ def up
3
+ create_table :foreman_chef_environments do |t|
4
+ t.string :name, :default => '', :null => false
5
+ t.text :description, :default => ''
6
+ t.integer :chef_proxy_id, :null => false
7
+ t.timestamps
8
+ end
9
+
10
+ add_column :hosts, :chef_environment_id, :integer
11
+ add_column :hostgroups, :chef_environment_id, :integer
12
+ end
13
+
14
+ def down
15
+ remove_column :hostgroups, :chef_environment_id
16
+ remove_column :hosts, :chef_environment_id
17
+
18
+ drop_table :foreman_chef_environments
19
+ end
20
+ end
@@ -12,6 +12,24 @@ module ForemanChef
12
12
  end
13
13
  end
14
14
 
15
+ config.autoload_paths += Dir["#{config.root}/app/helpers/concerns"]
16
+
17
+ # Precompile any JS or CSS files under app/assets/
18
+ # If requiring files from each other, list them explicitly here to avoid precompiling the same
19
+ # content twice.
20
+ assets_to_precompile =
21
+ Dir.chdir(root) do
22
+ Dir['app/assets/javascripts/**/*', 'app/assets/stylesheets/**/*'].map do |f|
23
+ f.split(File::SEPARATOR, 4).last.gsub(/\.scss\Z/, '')
24
+ end
25
+ end
26
+ initializer 'foreman_chef.assets.precompile' do |app|
27
+ app.config.assets.precompile += assets_to_precompile
28
+ end
29
+ initializer 'foreman_chef.configure_assets', group: :assets do
30
+ SETTINGS[:foreman_chef] = { assets: { precompile: assets_to_precompile } }
31
+ end
32
+
15
33
  initializer 'foreman_chef.load_default_settings', :before => :load_config_initializers do
16
34
  require_dependency File.expand_path('../../../app/models/setting/foreman_chef.rb', __FILE__) if (Setting.table_exists? rescue(false))
17
35
  end
@@ -28,8 +46,20 @@ module ForemanChef
28
46
 
29
47
  initializer 'foreman_chef.register_plugin', :after => :finisher_hook do |app|
30
48
  Foreman::Plugin.register :foreman_chef do
31
- requires_foreman '>= 1.9'
49
+ requires_foreman '>= 1.11'
32
50
  allowed_template_helpers :chef_bootstrap
51
+
52
+ permission :import_chef_environments, { :environments => [:import, :synchronize] }, :resource_type => 'ForemanChef::Environment'
53
+ permission :view_chef_environments, { :environments => [:index, :environments_for_chef_proxy] }, :resource_type => 'ForemanChef::Environment'
54
+ permission :edit_chef_environments, { :environments => [:edit, :update] }, :resource_type => 'ForemanChef::Environment'
55
+ permission :destroy_chef_environments, { :environments => [:destroy] }, :resource_type => 'ForemanChef::Environment'
56
+
57
+ divider :top_menu, :caption => N_('Chef'), :last => true, :parent => :configure_menu
58
+ menu :top_menu, :chef_environments,
59
+ url_hash: { controller: 'foreman_chef/environments', action: :index },
60
+ caption: N_('Environments'),
61
+ parent: :configure_menu,
62
+ last: true
33
63
  end
34
64
  end
35
65
 
@@ -44,13 +74,15 @@ module ForemanChef
44
74
 
45
75
  #Include extensions to models in this config.to_prepare block
46
76
  config.to_prepare do
47
- ::Host::Managed.send :include, ForemanChef::HostExtensions
48
- ::Hostgroup.send :include, ForemanChef::HostgroupExtensions
49
- ::Host::Managed.send :include, ChefProxyAssociation
50
- ::Hostgroup.send :include, ChefProxyAssociation
51
- ::SmartProxy.send :include, SmartProxyExtensions
52
77
  ::FactImporter.register_fact_importer(:foreman_chef, ForemanChef::FactImporter)
53
78
  ::FactParser.register_fact_parser(:foreman_chef, ForemanChef::FactParser)
79
+ ::ConfigReportImporter.register_smart_proxy_feature('Chef')
80
+
81
+ ::Host::Managed.send :include, ForemanChef::Concerns::HostAndHostgroupExtensions
82
+ ::Hostgroup.send :include, ForemanChef::Concerns::HostAndHostgroupExtensions
83
+ ::Host::Managed.send :include, ForemanChef::Concerns::HostExtensions
84
+ ::Hostgroup.send :include, ForemanChef::Concerns::HostgroupExtensions
85
+ ::SmartProxy.send :include, ForemanChef::Concerns::SmartProxyExtensions
54
86
  ::Host::Base.send :include, ForemanChef::Concerns::HostActionSubject
55
87
  ::HostsController.send :include, ForemanChef::Concerns::HostsControllerRescuer
56
88
  # Renderer Concern needs to be injected to controllers, ForemanRenderer was already included
@@ -63,4 +95,12 @@ module ForemanChef
63
95
  ::Foreman::Renderer.send :include, ForemanChef::Concerns::Renderer
64
96
  end
65
97
  end
98
+
99
+ def self.table_name_prefix
100
+ "foreman_chef_"
101
+ end
102
+
103
+ def use_relative_model_naming
104
+ true
105
+ end
66
106
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanChef
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_chef
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marek Hulan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-24 00:00:00.000000000 Z
11
+ date: 2016-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deface
@@ -68,28 +68,41 @@ files:
68
68
  - LICENSE
69
69
  - README.md
70
70
  - Rakefile
71
+ - app/assets/javascripts/chef_proxy_environment_refresh.js
72
+ - app/controllers/foreman_chef/application_controller.rb
71
73
  - app/controllers/foreman_chef/concerns/hosts_controller_rescuer.rb
74
+ - app/controllers/foreman_chef/environments_controller.rb
72
75
  - app/helpers/foreman_chef/chef_proxy_form.rb
73
76
  - app/lib/actions/foreman_chef/client/destroy.rb
74
77
  - app/lib/actions/foreman_chef/host/destroy.rb
75
78
  - app/lib/proxy_api/foreman_chef/chef_proxy.rb
76
- - app/models/foreman_chef/chef_proxy_association.rb
77
79
  - app/models/foreman_chef/concerns/host_action_subject.rb
80
+ - app/models/foreman_chef/concerns/host_and_hostgroup_extensions.rb
81
+ - app/models/foreman_chef/concerns/host_extensions.rb
82
+ - app/models/foreman_chef/concerns/hostgroup_extensions.rb
78
83
  - app/models/foreman_chef/concerns/renderer.rb
84
+ - app/models/foreman_chef/concerns/smart_proxy_extensions.rb
85
+ - app/models/foreman_chef/environment.rb
79
86
  - app/models/foreman_chef/fact_importer.rb
80
87
  - app/models/foreman_chef/fact_name.rb
81
88
  - app/models/foreman_chef/fact_parser.rb
82
- - app/models/foreman_chef/host_extensions.rb
83
- - app/models/foreman_chef/hostgroup_extensions.rb
84
- - app/models/foreman_chef/smart_proxy_extensions.rb
85
89
  - app/models/setting/foreman_chef.rb
86
90
  - app/overrides/add_chef_proxy.rb
91
+ - app/services/foreman_chef/chef_server_importer.rb
87
92
  - app/services/foreman_chef/proxy_exception.rb
88
93
  - app/views/foreman/unattended/snippets/_chef_client_bootstrap.erb
89
94
  - app/views/foreman/unattended/snippets/_chef_client_gem_bootstrap.erb
90
95
  - app/views/foreman/unattended/snippets/_chef_client_omnibus_bootstrap.erb
96
+ - app/views/foreman_chef/environments/_form.html.erb
97
+ - app/views/foreman_chef/environments/edit.html.erb
98
+ - app/views/foreman_chef/environments/environments_for_chef_proxy.html.erb
99
+ - app/views/foreman_chef/environments/import.html.erb
100
+ - app/views/foreman_chef/environments/index.html.erb
101
+ - app/views/foreman_chef/environments/new.html.erb
102
+ - config/routes.rb
91
103
  - db/migrate/20140220145827_add_chef_proxy_id_to_host.rb
92
104
  - db/migrate/20140513144804_add_chef_proxy_id_to_hostgroup.rb
105
+ - db/migrate/20150916141657_create_chef_environment.rb
93
106
  - db/seeds.rb
94
107
  - lib/foreman_chef.rb
95
108
  - lib/foreman_chef/engine.rb
@@ -1,10 +0,0 @@
1
- module ForemanChef
2
- module ChefProxyAssociation
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- belongs_to :chef_proxy, :class_name => "SmartProxy"
7
- end
8
-
9
- end
10
- end
@@ -1,16 +0,0 @@
1
- module ForemanChef
2
- module HostExtensions
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- alias_method_chain :set_hostgroup_defaults, :chef_proxy
7
- end
8
-
9
- def set_hostgroup_defaults_with_chef_proxy
10
- set_hostgroup_defaults_without_chef_proxy
11
- return unless hostgroup
12
- assign_hostgroup_attributes(['chef_proxy_id'])
13
- end
14
-
15
- end
16
- end
@@ -1,18 +0,0 @@
1
- module ForemanChef
2
- module HostgroupExtensions
3
- extend ActiveSupport::Concern
4
-
5
- def inherited_chef_proxy_id
6
- read_attribute(:chef_proxy_id) || nested(:chef_proxy_id)
7
- end
8
-
9
- def chef_proxy
10
- if ancestry.present?
11
- SmartProxy.with_features('Chef').find_by_id(inherited_chef_proxy_id)
12
- else
13
- super
14
- end
15
- end
16
-
17
- end
18
- end
@@ -1,38 +0,0 @@
1
- module ForemanChef
2
- module SmartProxyExtensions
3
- extend ActiveSupport::Concern
4
-
5
- # create or overwrite instance methods...
6
- def show_node(fqdn)
7
- reply = ProxyAPI::ForemanChef::ChefProxy.new(:url => url).show_node(fqdn)
8
- JSON.parse(reply)
9
- rescue RestClient::ResourceNotFound
10
- Foreman::Logging.logger('foreman_chef').debug "Node '#{fqdn}' not found"
11
- return false
12
- end
13
-
14
- def delete_node(fqdn)
15
- begin
16
- reply = ProxyAPI::ForemanChef::ChefProxy.new(:url => url).delete_node(fqdn)
17
- JSON.parse(reply)
18
- #rescue RestClient::
19
- end
20
- end
21
-
22
- def show_client(fqdn)
23
- reply = ProxyAPI::ForemanChef::ChefProxy.new(:url => url).show_client(fqdn)
24
- JSON.parse(reply)
25
- rescue RestClient::ResourceNotFound
26
- Foreman::Logging.logger('foreman_chef').debug "Client '#{fqdn}' not found"
27
- return false
28
- end
29
-
30
- def delete_client(fqdn)
31
- begin
32
- reply = ProxyAPI::ForemanChef::ChefProxy.new(:url => url).delete_client(fqdn)
33
- JSON.parse(reply)
34
- #rescue RestClient::
35
- end
36
- end
37
- end
38
- end