foreman_chef 0.2.2 → 0.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.
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