foreman_ansible 7.0.4 → 7.1.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.
- checksums.yaml +4 -4
 - data/app/controllers/api/v2/ansible_playbooks_controller.rb +66 -0
 - data/app/jobs/sync_playbooks.rb +25 -0
 - data/app/lib/proxy_api/ansible.rb +13 -0
 - data/app/services/foreman_ansible/import_playbooks_error_notification.rb +38 -0
 - data/app/services/foreman_ansible/import_playbooks_success_notification.rb +33 -0
 - data/app/services/foreman_ansible/playbooks_importer.rb +73 -0
 - data/app/services/foreman_ansible/proxy_api.rb +3 -4
 - data/app/views/ansible_roles/index.html.erb +2 -0
 - data/app/views/api/v2/ansible_playbooks/sync.json.rabl +5 -0
 - data/app/views/foreman_ansible/job_templates/ansible_windows_updates.erb +160 -0
 - data/app/views/foreman_ansible/job_templates/configure_cloud_connector_-_ansible_default.erb +37 -0
 - data/config/routes.rb +7 -0
 - data/db/seeds.d/90_notification_blueprints.rb +14 -0
 - data/lib/foreman_ansible/register.rb +3 -1
 - data/lib/foreman_ansible/remote_execution.rb +6 -0
 - data/lib/foreman_ansible/version.rb +1 -1
 - data/test/fixtures/playbooks_example_output.json +1 -0
 - data/test/fixtures/sample_playbooks.json +10 -0
 - data/test/functional/api/v2/ansible_playbooks_controller_test.rb +65 -0
 - data/test/functional/hosts_controller_test.rb +2 -2
 - data/test/unit/import_playbooks_test.rb +51 -0
 - data/test/unit/lib/proxy_api/ansible_test.rb +6 -0
 - data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTable.js +58 -75
 - data/webpack/components/AnsibleHostDetail/components/JobsTab/PreviousJobsTable.js +44 -58
 - data/webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/AllRolesTable.js +32 -55
 - data/webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/index.js +1 -1
 - data/webpack/components/AnsibleHostDetail/components/RolesTab/RolesTable.js +29 -42
 - data/webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariables.js +27 -38
 - data/webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariablesActions.js +2 -1
 - data/webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariablesConstants.js +1 -0
 - data/webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariablesSelectors.js +6 -0
 - data/webpack/components/AnsibleRolesAndVariables/index.js +7 -1
 - data/webpack/components/AnsibleRolesSwitcher/components/AvailableRolesList.js +2 -2
 - data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AvailableRolesList.test.js.snap +9 -6
 - data/webpack/helpers/pageParamsHelper.js +3 -3
 - metadata +46 -31
 - data/webpack/components/withPagination.js +0 -0
 - data/webpack/helpers/paginationHelper.js +0 -9
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: dc6d250a74d7e811600edfd0f78551286d8800644512d4346fd6d5794fe451f3
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: f7057a56a7e5fda90510ab9aa13b70b59efa90f07a8e7fb3460140102e36d390
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 99dbfada521e9075ae164312cdf3eecb85e663beca47e558b5d3fd61cde68bb2a632e29f80ca9dcbf5519be3122a15b6c2777f4400b6bd685c84f2488a02baf4
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: b8a5fde3a9bb62aaf578b5d08ef24afe6bd9ddc2ac7af33b732a6c8eadfeb077dc92f0db86496975f44d3b9ad0c59acdb176f1722e964de5a4afb7a7c826182c
         
     | 
| 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Api
         
     | 
| 
      
 4 
     | 
    
         
            +
              module V2
         
     | 
| 
      
 5 
     | 
    
         
            +
                # API controller for Ansible Roles
         
     | 
| 
      
 6 
     | 
    
         
            +
                class AnsiblePlaybooksController < ::Api::V2::BaseController
         
     | 
| 
      
 7 
     | 
    
         
            +
                  include ::Api::Version2
         
     | 
| 
      
 8 
     | 
    
         
            +
                  include ::ForemanAnsible::ProxyAPI
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  before_action :find_proxy, only: [:fetch, :sync]
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  resource_description do
         
     | 
| 
      
 13 
     | 
    
         
            +
                    api_version 'v2'
         
     | 
| 
      
 14 
     | 
    
         
            +
                    api_base_url '/ansible/api'
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  api :PUT, '/ansible_playbooks/sync', N_('Sync Ansible playbooks')
         
     | 
| 
      
 18 
     | 
    
         
            +
                  param :proxy_id, :identifier, :required => true, :desc => N_('Smart Proxy to sync from')
         
     | 
| 
      
 19 
     | 
    
         
            +
                  param :playbooks_names, Array, N_('Ansible  playbooks names to be synced')
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def sync
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @task = plan_ansible_sync(@proxy.id, playbooks_names)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  api :GET, '/ansible_playbooks/fetch', N_('Fetch Ansible playbooks available to be synced')
         
     | 
| 
      
 25 
     | 
    
         
            +
                  param :proxy_id, :identifier, N_('Smart Proxy to fetch from'),
         
     | 
| 
      
 26 
     | 
    
         
            +
                        :required => true
         
     | 
| 
      
 27 
     | 
    
         
            +
                  def fetch
         
     | 
| 
      
 28 
     | 
    
         
            +
                    fetched = fetch_playbooks_names
         
     | 
| 
      
 29 
     | 
    
         
            +
                    render :json => { :results => { :playbooks_names => fetched } }
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def action_permission
         
     | 
| 
      
 33 
     | 
    
         
            +
                    case params[:action]
         
     | 
| 
      
 34 
     | 
    
         
            +
                    when 'sync', 'fetch'
         
     | 
| 
      
 35 
     | 
    
         
            +
                      :import
         
     | 
| 
      
 36 
     | 
    
         
            +
                    else
         
     | 
| 
      
 37 
     | 
    
         
            +
                      super
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def plan_ansible_sync(proxy_id, playbooks_names)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    ForemanTasks.async_task(ImportPlaybooksJob::Async::SyncPlaybooks, proxy_id, playbooks_names)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  private
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def find_proxy
         
     | 
| 
      
 48 
     | 
    
         
            +
                    unless params[:proxy_id]
         
     | 
| 
      
 49 
     | 
    
         
            +
                      msg = _('Smart proxy id is required')
         
     | 
| 
      
 50 
     | 
    
         
            +
                      render_error('custom_error', :status => :unprocessable_entity, :locals => { :message => msg })
         
     | 
| 
      
 51 
     | 
    
         
            +
                      return false
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
                    @proxy = SmartProxy.find(params[:proxy_id])
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  def fetch_playbooks_names
         
     | 
| 
      
 57 
     | 
    
         
            +
                    proxy_api = find_proxy_api(@proxy)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    proxy_api.playbooks_names if @proxy
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  def playbooks_names
         
     | 
| 
      
 62 
     | 
    
         
            +
                    params.fetch(:playbooks_names, [])
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ImportPlaybooksJob
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Async
         
     | 
| 
      
 3 
     | 
    
         
            +
                class SyncPlaybooks < ::Actions::EntryAction
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def plan(proxy_id, playbooks_names)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    plan_self(proxy_id: proxy_id, playbooks_names: playbooks_names)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def run
         
     | 
| 
      
 9 
     | 
    
         
            +
                    playbooks_importer = ForemanAnsible::PlaybooksImporter.new(proxy)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    output[:result] = playbooks_importer.import_playbooks(playbooks_names)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    ForemanAnsible::ImportPlaybooksSuccessNotification.deliver!(task)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  rescue StandardError => e
         
     | 
| 
      
 13 
     | 
    
         
            +
                    ForemanAnsible::ImportPlaybooksErrorNotification.new(e, task).deliver!
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def proxy
         
     | 
| 
      
 17 
     | 
    
         
            +
                    SmartProxy.find(input[:proxy_id])
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def playbooks_names
         
     | 
| 
      
 21 
     | 
    
         
            +
                    input[:playbooks_names]
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -40,5 +40,18 @@ module ProxyAPI 
     | 
|
| 
       40 
40 
     | 
    
         
             
                  raise ProxyException.new(url, e,
         
     | 
| 
       41 
41 
     | 
    
         
             
                                           N_('Unable to get roles/variables from Ansible'))
         
     | 
| 
       42 
42 
     | 
    
         
             
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def playbooks_names
         
     | 
| 
      
 45 
     | 
    
         
            +
                  parse(get('playbooks_names'))
         
     | 
| 
      
 46 
     | 
    
         
            +
                rescue *PROXY_ERRORS => e
         
     | 
| 
      
 47 
     | 
    
         
            +
                  raise ProxyException.new(url, e, N_('Unable to get playbook\'s names from Ansible'))
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def playbooks(playbooks_names = [])
         
     | 
| 
      
 51 
     | 
    
         
            +
                  playbooks_names = playbooks_names.join(',')
         
     | 
| 
      
 52 
     | 
    
         
            +
                  parse(get("playbooks/#{playbooks_names}"))
         
     | 
| 
      
 53 
     | 
    
         
            +
                rescue *PROXY_ERRORS => e
         
     | 
| 
      
 54 
     | 
    
         
            +
                  raise ProxyException.new(url, e, N_('Unable to get playbooks from Ansible'))
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
       43 
56 
     | 
    
         
             
              end
         
     | 
| 
       44 
57 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ForemanAnsible
         
     | 
| 
      
 4 
     | 
    
         
            +
              class ImportPlaybooksErrorNotification < ::UINotifications::Base
         
     | 
| 
      
 5 
     | 
    
         
            +
                private
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(error, task)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @job_error = error
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @subject = task
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def create
         
     | 
| 
      
 13 
     | 
    
         
            +
                  ::Notification.create!(
         
     | 
| 
      
 14 
     | 
    
         
            +
                    :audience => Notification::AUDIENCE_USER,
         
     | 
| 
      
 15 
     | 
    
         
            +
                    :notification_blueprint => blueprint,
         
     | 
| 
      
 16 
     | 
    
         
            +
                    :initiator => initiator,
         
     | 
| 
      
 17 
     | 
    
         
            +
                    :message => message,
         
     | 
| 
      
 18 
     | 
    
         
            +
                    :subject => subject,
         
     | 
| 
      
 19 
     | 
    
         
            +
                    :actions => {
         
     | 
| 
      
 20 
     | 
    
         
            +
                      :links => links
         
     | 
| 
      
 21 
     | 
    
         
            +
                    }
         
     | 
| 
      
 22 
     | 
    
         
            +
                  )
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def blueprint
         
     | 
| 
      
 26 
     | 
    
         
            +
                  name = 'Sync_playbooks_failed'
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @blueprint ||= NotificationBlueprint.unscoped.find_by(:name => name)
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def message
         
     | 
| 
      
 31 
     | 
    
         
            +
                  _("Failed to import playbooks Due to: #{@job_error}")
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def links
         
     | 
| 
      
 35 
     | 
    
         
            +
                  [{ :href => Rails.application.routes.url_helpers.foreman_tasks_task_path(:id => subject.id), :title => N_('Task Details') }]
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ForemanAnsible
         
     | 
| 
      
 4 
     | 
    
         
            +
              class ImportPlaybooksSuccessNotification < ::UINotifications::Base
         
     | 
| 
      
 5 
     | 
    
         
            +
                private
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def create
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ::Notification.create!(
         
     | 
| 
      
 9 
     | 
    
         
            +
                    :audience => Notification::AUDIENCE_USER,
         
     | 
| 
      
 10 
     | 
    
         
            +
                    :notification_blueprint => blueprint,
         
     | 
| 
      
 11 
     | 
    
         
            +
                    :initiator => initiator,
         
     | 
| 
      
 12 
     | 
    
         
            +
                    :message => message,
         
     | 
| 
      
 13 
     | 
    
         
            +
                    :subject => subject,
         
     | 
| 
      
 14 
     | 
    
         
            +
                    :actions => {
         
     | 
| 
      
 15 
     | 
    
         
            +
                      :links => links
         
     | 
| 
      
 16 
     | 
    
         
            +
                    }
         
     | 
| 
      
 17 
     | 
    
         
            +
                  )
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def blueprint
         
     | 
| 
      
 21 
     | 
    
         
            +
                  name = 'Sync_playbooks_successfully'
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @blueprint ||= NotificationBlueprint.unscoped.find_by(:name => name)
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def message
         
     | 
| 
      
 26 
     | 
    
         
            +
                  blueprint.message
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def links
         
     | 
| 
      
 30 
     | 
    
         
            +
                  [{ :href => Rails.application.routes.url_helpers.foreman_tasks_task_path(:id => subject.id), :title => N_('Task Details') }]
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ForemanAnsible
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Imports playbooks from smart proxy
         
     | 
| 
      
 5 
     | 
    
         
            +
              class PlaybooksImporter
         
     | 
| 
      
 6 
     | 
    
         
            +
                include ::ForemanAnsible::ProxyAPI
         
     | 
| 
      
 7 
     | 
    
         
            +
                delegate :playbooks, :playbooks_names, :to => :proxy_api
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(proxy = nil)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @ansible_proxy = proxy
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def import_playbooks(playbooks_names)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  playbooks = playbooks(playbooks_names)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  result = { created: {}, updated: {} }
         
     | 
| 
      
 16 
     | 
    
         
            +
                  playbooks.each do |playbook|
         
     | 
| 
      
 17 
     | 
    
         
            +
                    parsed_playbook = parse_playbook playbook
         
     | 
| 
      
 18 
     | 
    
         
            +
                    job_template_id = JobTemplate.where(name: parsed_playbook[:name]).pick(:id)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    if job_template_id.present?
         
     | 
| 
      
 20 
     | 
    
         
            +
                      updated = update_job_template(job_template_id, parsed_playbook)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      result[:updated].merge!(updated) unless updated.nil?
         
     | 
| 
      
 22 
     | 
    
         
            +
                    else
         
     | 
| 
      
 23 
     | 
    
         
            +
                      result[:created].merge!(create_job_template(parsed_playbook))
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  result
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def parse_playbook(playbook)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  content = playbook['playbooks_content']
         
     | 
| 
      
 31 
     | 
    
         
            +
                  {
         
     | 
| 
      
 32 
     | 
    
         
            +
                    name: playbook['name'],
         
     | 
| 
      
 33 
     | 
    
         
            +
                    playbook_content: metadata(playbook['name']) + content,
         
     | 
| 
      
 34 
     | 
    
         
            +
                    vars: get_vars(content)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  }
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def metadata(playbook_name)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  <<~END_HEREDOC
         
     | 
| 
      
 40 
     | 
    
         
            +
                    <%#
         
     | 
| 
      
 41 
     | 
    
         
            +
                      name: #{playbook_name}
         
     | 
| 
      
 42 
     | 
    
         
            +
                      snippet: false
         
     | 
| 
      
 43 
     | 
    
         
            +
                      job_category: Ansible Playbook - Imported
         
     | 
| 
      
 44 
     | 
    
         
            +
                      provider_type: Ansible
         
     | 
| 
      
 45 
     | 
    
         
            +
                      kind: job_template
         
     | 
| 
      
 46 
     | 
    
         
            +
                      model: JobTemplate
         
     | 
| 
      
 47 
     | 
    
         
            +
                    %>
         
     | 
| 
      
 48 
     | 
    
         
            +
                  END_HEREDOC
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def get_vars(playbook_content)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  YAML.safe_load(playbook_content).map { |play| play['vars'] }
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def create_job_template(playbook)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  job_template = JobTemplate.create(name: playbook[:name], template: playbook[:playbook_content], job_category: 'Ansible Playbook - Imported', provider_type: 'Ansible')
         
     | 
| 
      
 57 
     | 
    
         
            +
                  # TODO: Add support for creating template inputs
         
     | 
| 
      
 58 
     | 
    
         
            +
                  job_template.organizations = Organization.unscoped.all
         
     | 
| 
      
 59 
     | 
    
         
            +
                  job_template.locations = Location.unscoped.all
         
     | 
| 
      
 60 
     | 
    
         
            +
                  job_template.save
         
     | 
| 
      
 61 
     | 
    
         
            +
                  { job_template.id => job_template.name }
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                def update_job_template(job_template_id, playbook)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # TODO: Add support for updating template inputs
         
     | 
| 
      
 66 
     | 
    
         
            +
                  inputs = []
         
     | 
| 
      
 67 
     | 
    
         
            +
                  job_template = JobTemplate.find(job_template_id)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  should_update = !playbook[:playbook_content].eql?(job_template.template)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  job_template.template = playbook[:playbook_content] if should_update
         
     | 
| 
      
 70 
     | 
    
         
            +
                  { job_template.id => job_template.name } unless inputs.empty? && !should_update
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -8,16 +8,15 @@ module ForemanAnsible 
     | 
|
| 
       8 
8 
     | 
    
         
             
                included do
         
     | 
| 
       9 
9 
     | 
    
         
             
                  attr_reader :ansible_proxy
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
                  def find_proxy_api
         
     | 
| 
      
 11 
     | 
    
         
            +
                  def find_proxy_api(ansible_proxy)
         
     | 
| 
       12 
12 
     | 
    
         
             
                    if ansible_proxy.blank?
         
     | 
| 
       13 
13 
     | 
    
         
             
                      raise ::Foreman::Exception.new(N_('Proxy not found'))
         
     | 
| 
       14 
14 
     | 
    
         
             
                    end
         
     | 
| 
       15 
     | 
    
         
            -
                     
     | 
| 
      
 15 
     | 
    
         
            +
                    ::ProxyAPI::Ansible.new(:url => ansible_proxy.url)
         
     | 
| 
       16 
16 
     | 
    
         
             
                  end
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                  def proxy_api
         
     | 
| 
       19 
     | 
    
         
            -
                     
     | 
| 
       20 
     | 
    
         
            -
                    find_proxy_api
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @proxy_api ||= find_proxy_api(ansible_proxy)
         
     | 
| 
       21 
20 
     | 
    
         
             
                  end
         
     | 
| 
       22 
21 
     | 
    
         
             
                end
         
     | 
| 
       23 
22 
     | 
    
         
             
              end
         
     | 
| 
         @@ -9,6 +9,7 @@ 
     | 
|
| 
       9 
9 
     | 
    
         
             
                  <th class="col-md-6"><%= sort :name, :as => s_("Role|Name") %></th>
         
     | 
| 
       10 
10 
     | 
    
         
             
                  <th class="col-md-2"><%= _("Hostgroups") %></th>
         
     | 
| 
       11 
11 
     | 
    
         
             
                  <th class="col-md-2"><%= _("Hosts") %></th>
         
     | 
| 
      
 12 
     | 
    
         
            +
                  <th class="col-md-2"><%= _("Variables") %></th>
         
     | 
| 
       12 
13 
     | 
    
         
             
                  <th class="col-md-2"><%= sort :updated_at, :as => _("Imported at") %></th>
         
     | 
| 
       13 
14 
     | 
    
         
             
                  <th class="col-md-2"><%= _("Actions") %></th>
         
     | 
| 
       14 
15 
     | 
    
         
             
                </tr>
         
     | 
| 
         @@ -19,6 +20,7 @@ 
     | 
|
| 
       19 
20 
     | 
    
         
             
                    <td class="ellipsis"><%= role.name %></td>
         
     | 
| 
       20 
21 
     | 
    
         
             
                    <td class="ellipsis"><%= role.hostgroups.count %></td>
         
     | 
| 
       21 
22 
     | 
    
         
             
                    <td class="ellipsis"><%= link_to role.hosts.count, hosts_path(:search => "ansible_role = #{role.name}")%></td>
         
     | 
| 
      
 23 
     | 
    
         
            +
                    <td class="ellipsis"><%= link_to(role.ansible_variables.count, ansible_variables_path(:search => "ansible_role = #{role}")) %></td>
         
     | 
| 
       22 
24 
     | 
    
         
             
                    <td class="ellipsis"><%= import_time role %></td>
         
     | 
| 
       23 
25 
     | 
    
         
             
                    <td>
         
     | 
| 
       24 
26 
     | 
    
         
             
                      <%
         
     | 
| 
         @@ -0,0 +1,160 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%#
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: Manage Windows Updates - Ansible Default
         
     | 
| 
      
 3 
     | 
    
         
            +
            snippet: false
         
     | 
| 
      
 4 
     | 
    
         
            +
            template_inputs:
         
     | 
| 
      
 5 
     | 
    
         
            +
            - name: reject_list
         
     | 
| 
      
 6 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 7 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 8 
     | 
    
         
            +
              description: "A list of update titles or KB numbers that can be used to specify
         
     | 
| 
      
 9 
     | 
    
         
            +
                which updates are to be excluded from installation.\r\nIf an available update
         
     | 
| 
      
 10 
     | 
    
         
            +
                does match one of the entries, then it is skipped and not installed.\r\nEach entry
         
     | 
| 
      
 11 
     | 
    
         
            +
                can either be the KB article or Update title as a regex according to the PowerShell
         
     | 
| 
      
 12 
     | 
    
         
            +
                regex rules."
         
     | 
| 
      
 13 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 14 
     | 
    
         
            +
            - name: category_names
         
     | 
| 
      
 15 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 16 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 17 
     | 
    
         
            +
              description: "A scalar or list of categories to install updates from. To get the
         
     | 
| 
      
 18 
     | 
    
         
            +
                list of categories, run the module with state=searched. The category must be the
         
     | 
| 
      
 19 
     | 
    
         
            +
                full category string, but is case insensitive.\r\nSome possible categories are
         
     | 
| 
      
 20 
     | 
    
         
            +
                Application, Connectors, Critical Updates, Definition Updates, Developer Kits,
         
     | 
| 
      
 21 
     | 
    
         
            +
                Feature Packs, Guidance, Security Updates, Service Packs, Tools, Update Rollups
         
     | 
| 
      
 22 
     | 
    
         
            +
                and Updates.\r\n\r\nDefault is '[\"CriticalUpdates\", \"SecurityUpdates\", \"UpdateRollups\"]'"
         
     | 
| 
      
 23 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 24 
     | 
    
         
            +
            - name: log_path
         
     | 
| 
      
 25 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 26 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 27 
     | 
    
         
            +
              description: If set, win_updates will append update progress to the specified file.
         
     | 
| 
      
 28 
     | 
    
         
            +
                The directory must already exist.
         
     | 
| 
      
 29 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 30 
     | 
    
         
            +
            - name: reboot
         
     | 
| 
      
 31 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 32 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 33 
     | 
    
         
            +
              description: "Ansible will automatically reboot the remote host if it is required
         
     | 
| 
      
 34 
     | 
    
         
            +
                and continue to install updates after the reboot.\r\nThis can be used instead
         
     | 
| 
      
 35 
     | 
    
         
            +
                of using a win_reboot task after this one and ensures all updates for that category
         
     | 
| 
      
 36 
     | 
    
         
            +
                is installed in one go.\r\nAsync does not work when reboot=true.\r\n\r\nDefault
         
     | 
| 
      
 37 
     | 
    
         
            +
                is 'false'"
         
     | 
| 
      
 38 
     | 
    
         
            +
              options: "false\r\ntrue"
         
     | 
| 
      
 39 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 40 
     | 
    
         
            +
            - name: reboot_timeout
         
     | 
| 
      
 41 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 42 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 43 
     | 
    
         
            +
              description: "The time in seconds to wait until the host is back online from a reboot.\r\nThis
         
     | 
| 
      
 44 
     | 
    
         
            +
                is only used if reboot=true and a reboot is required.\r\n\r\nDefault is '1200'"
         
     | 
| 
      
 45 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 46 
     | 
    
         
            +
            - name: server_selection
         
     | 
| 
      
 47 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 48 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 49 
     | 
    
         
            +
              description: "Defines the Windows Update source catalog.\r\ndefault Use the default
         
     | 
| 
      
 50 
     | 
    
         
            +
                search source. For many systems default is set to the Microsoft Windows Update
         
     | 
| 
      
 51 
     | 
    
         
            +
                catalog. Systems participating in Windows Server Update Services (WSUS), Systems
         
     | 
| 
      
 52 
     | 
    
         
            +
                Center Configuration Manager (SCCM), or similar corporate update server environments
         
     | 
| 
      
 53 
     | 
    
         
            +
                may default to those managed update sources instead of the Windows Update catalog.\r\nmanaged_server
         
     | 
| 
      
 54 
     | 
    
         
            +
                Use a managed server catalog. For environments utilizing Windows Server Update
         
     | 
| 
      
 55 
     | 
    
         
            +
                Services (WSUS), Systems Center Configuration Manager (SCCM), or similar corporate
         
     | 
| 
      
 56 
     | 
    
         
            +
                update servers, this option selects the defined corporate update source.\r\nwindows_update
         
     | 
| 
      
 57 
     | 
    
         
            +
                Use the Microsoft Windows Update catalog.\r\n\r\nDefault is 'default'"
         
     | 
| 
      
 58 
     | 
    
         
            +
              options: "default\r\nmanaged_server\r\nwindows_update"
         
     | 
| 
      
 59 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 60 
     | 
    
         
            +
            - name: state
         
     | 
| 
      
 61 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 62 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 63 
     | 
    
         
            +
              description: "Controls whether found updates are downloaded or installed or listed\r\nThis
         
     | 
| 
      
 64 
     | 
    
         
            +
                module also supports Ansible check mode, which has the same effect as setting
         
     | 
| 
      
 65 
     | 
    
         
            +
                state=searched\r\n\r\nDefault is 'searched'"
         
     | 
| 
      
 66 
     | 
    
         
            +
              options: "installed\r\nsearched\r\ndownloaded"
         
     | 
| 
      
 67 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 68 
     | 
    
         
            +
            - name: use_scheduled_task
         
     | 
| 
      
 69 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 70 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 71 
     | 
    
         
            +
              description: "Will not auto elevate the remote process with become and use a scheduled
         
     | 
| 
      
 72 
     | 
    
         
            +
                task instead.\r\nSet this to true when using this module with async on Server
         
     | 
| 
      
 73 
     | 
    
         
            +
                2008, 2008 R2, or Windows 7, or on Server 2008 that is not authenticated with
         
     | 
| 
      
 74 
     | 
    
         
            +
                basic or credssp.\r\nCan also be set to true on newer hosts where become does
         
     | 
| 
      
 75 
     | 
    
         
            +
                not work due to further privilege restrictions from the OS defaults."
         
     | 
| 
      
 76 
     | 
    
         
            +
              options: "false\r\ntrue"
         
     | 
| 
      
 77 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 78 
     | 
    
         
            +
            - name: whitelist
         
     | 
| 
      
 79 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 80 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 81 
     | 
    
         
            +
              description: "A list of update titles or KB numbers that can be used to specify
         
     | 
| 
      
 82 
     | 
    
         
            +
                which updates are to be searched or installed.\r\nIf an available update does
         
     | 
| 
      
 83 
     | 
    
         
            +
                not match one of the entries, then it is skipped and not installed.\r\nEach entry
         
     | 
| 
      
 84 
     | 
    
         
            +
                can either be the KB article or Update title as a regex according to the PowerShell
         
     | 
| 
      
 85 
     | 
    
         
            +
                regex rules.\r\nThe whitelist is only validated on updates that were found based
         
     | 
| 
      
 86 
     | 
    
         
            +
                on category_names. It will not force the module to install an update if it was
         
     | 
| 
      
 87 
     | 
    
         
            +
                not in the category specified."
         
     | 
| 
      
 88 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 89 
     | 
    
         
            +
            model: JobTemplate
         
     | 
| 
      
 90 
     | 
    
         
            +
            job_category: Ansible Playbook
         
     | 
| 
      
 91 
     | 
    
         
            +
            provider_type: Ansible
         
     | 
| 
      
 92 
     | 
    
         
            +
            kind: job_template
         
     | 
| 
      
 93 
     | 
    
         
            +
            organizations:
         
     | 
| 
      
 94 
     | 
    
         
            +
            - My_Organization
         
     | 
| 
      
 95 
     | 
    
         
            +
            locations:
         
     | 
| 
      
 96 
     | 
    
         
            +
            - My_Location
         
     | 
| 
      
 97 
     | 
    
         
            +
            %>
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
            - hosts: all
         
     | 
| 
      
 100 
     | 
    
         
            +
              vars:
         
     | 
| 
      
 101 
     | 
    
         
            +
                updates: []
         
     | 
| 
      
 102 
     | 
    
         
            +
                <% if input('state').blank? %>
         
     | 
| 
      
 103 
     | 
    
         
            +
                state: searched
         
     | 
| 
      
 104 
     | 
    
         
            +
                <% else %>
         
     | 
| 
      
 105 
     | 
    
         
            +
                state: <%= input('state') %>
         
     | 
| 
      
 106 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
              tasks:
         
     | 
| 
      
 109 
     | 
    
         
            +
                - name: "{{ state | replace('ed','') | capitalize }} Windows Updates"
         
     | 
| 
      
 110 
     | 
    
         
            +
                  win_updates:
         
     | 
| 
      
 111 
     | 
    
         
            +
                    <% unless input('reject_list').blank? %>
         
     | 
| 
      
 112 
     | 
    
         
            +
                    blacklist: <%= input('reject_list') %>
         
     | 
| 
      
 113 
     | 
    
         
            +
                    <% end -%>
         
     | 
| 
      
 114 
     | 
    
         
            +
                    <% if input('category_names').blank? %>
         
     | 
| 
      
 115 
     | 
    
         
            +
                    category_names: ["CriticalUpdates", "SecurityUpdates", "UpdateRollups"]
         
     | 
| 
      
 116 
     | 
    
         
            +
                    <% else %>
         
     | 
| 
      
 117 
     | 
    
         
            +
                    category_names: <%= input('category_names') %>
         
     | 
| 
      
 118 
     | 
    
         
            +
                    <% end %>
         
     | 
| 
      
 119 
     | 
    
         
            +
                    <% unless input('log_path').blank? %>
         
     | 
| 
      
 120 
     | 
    
         
            +
                    log_path: <%= input('log_path') %>
         
     | 
| 
      
 121 
     | 
    
         
            +
                    <% end -%>
         
     | 
| 
      
 122 
     | 
    
         
            +
                    <% if input('reboot').blank? %>
         
     | 
| 
      
 123 
     | 
    
         
            +
                    reboot: false
         
     | 
| 
      
 124 
     | 
    
         
            +
                    <% else %>
         
     | 
| 
      
 125 
     | 
    
         
            +
                    reboot: <%= input('reboot') %>
         
     | 
| 
      
 126 
     | 
    
         
            +
                    <% end %>
         
     | 
| 
      
 127 
     | 
    
         
            +
                    <% if input('reboot_timeout').blank? %>
         
     | 
| 
      
 128 
     | 
    
         
            +
                    reboot_timeout: 1200
         
     | 
| 
      
 129 
     | 
    
         
            +
                    <% else %>
         
     | 
| 
      
 130 
     | 
    
         
            +
                    reboot_timeout: <%= input('reboot_timeout') %>
         
     | 
| 
      
 131 
     | 
    
         
            +
                    <% end -%>
         
     | 
| 
      
 132 
     | 
    
         
            +
                    <% if input('server_selection').blank? %>
         
     | 
| 
      
 133 
     | 
    
         
            +
                    server_selection: default
         
     | 
| 
      
 134 
     | 
    
         
            +
                    <% else %>
         
     | 
| 
      
 135 
     | 
    
         
            +
                    server_selection: <%= input('server_selection') %>
         
     | 
| 
      
 136 
     | 
    
         
            +
                    <% end %>
         
     | 
| 
      
 137 
     | 
    
         
            +
                    state: "{{ state }}"
         
     | 
| 
      
 138 
     | 
    
         
            +
                    <% if input('use_scheduled_task').blank? %>
         
     | 
| 
      
 139 
     | 
    
         
            +
                    use_scheduled_task: false
         
     | 
| 
      
 140 
     | 
    
         
            +
                    <% else %>
         
     | 
| 
      
 141 
     | 
    
         
            +
                    use_scheduled_task: <%= input('use_scheduled_task') %>
         
     | 
| 
      
 142 
     | 
    
         
            +
                    <% end %>
         
     | 
| 
      
 143 
     | 
    
         
            +
                    <% if !input('whitelist').blank? %>
         
     | 
| 
      
 144 
     | 
    
         
            +
                    whitelist: <%= input('whitelist') %>
         
     | 
| 
      
 145 
     | 
    
         
            +
                    <% end -%>
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                  register: found_updates
         
     | 
| 
      
 148 
     | 
    
         
            +
                  
         
     | 
| 
      
 149 
     | 
    
         
            +
                - name: "Get all {{ state }} updates"
         
     | 
| 
      
 150 
     | 
    
         
            +
                  set_fact:
         
     | 
| 
      
 151 
     | 
    
         
            +
                    updates: "{{ updates + [ current_update ] }}"
         
     | 
| 
      
 152 
     | 
    
         
            +
                  vars:
         
     | 
| 
      
 153 
     | 
    
         
            +
                    current_update: "{{ item.value.title  }}"
         
     | 
| 
      
 154 
     | 
    
         
            +
                  loop: "{{ found_updates.updates | dict2items }}"
         
     | 
| 
      
 155 
     | 
    
         
            +
                  no_log: true
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                - name: "List {{ state }} Windows Updates"
         
     | 
| 
      
 158 
     | 
    
         
            +
                  debug: 
         
     | 
| 
      
 159 
     | 
    
         
            +
                    msg: "{{ item }}"
         
     | 
| 
      
 160 
     | 
    
         
            +
                  loop: "{{ updates }}"
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%#
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: Configure Cloud Connector
         
     | 
| 
      
 3 
     | 
    
         
            +
            snippet: false
         
     | 
| 
      
 4 
     | 
    
         
            +
            template_inputs:
         
     | 
| 
      
 5 
     | 
    
         
            +
            - name: satellite_user
         
     | 
| 
      
 6 
     | 
    
         
            +
              required: true
         
     | 
| 
      
 7 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 8 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 9 
     | 
    
         
            +
              value_type: plain
         
     | 
| 
      
 10 
     | 
    
         
            +
              hidden_value: false
         
     | 
| 
      
 11 
     | 
    
         
            +
            - name: satellite_password
         
     | 
| 
      
 12 
     | 
    
         
            +
              required: true
         
     | 
| 
      
 13 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 14 
     | 
    
         
            +
              advanced: false
         
     | 
| 
      
 15 
     | 
    
         
            +
              value_type: plain
         
     | 
| 
      
 16 
     | 
    
         
            +
              hidden_value: true
         
     | 
| 
      
 17 
     | 
    
         
            +
            - name: http_proxy
         
     | 
| 
      
 18 
     | 
    
         
            +
              required: false
         
     | 
| 
      
 19 
     | 
    
         
            +
              input_type: user
         
     | 
| 
      
 20 
     | 
    
         
            +
              advanced: true
         
     | 
| 
      
 21 
     | 
    
         
            +
              value_type: plain
         
     | 
| 
      
 22 
     | 
    
         
            +
              hidden_value: false
         
     | 
| 
      
 23 
     | 
    
         
            +
              description: You can specify a HTTP proxy address that should be used for Cloud Connector connection to the cloud.redhat.com. Note that it must be HTTP proxy, not HTTPS. The tunelling of SSL (secured web socket connection) in SSL (HTTPS proxy) is currently unsupported.
         
     | 
| 
      
 24 
     | 
    
         
            +
            model: JobTemplate
         
     | 
| 
      
 25 
     | 
    
         
            +
            job_category: Maintenance Operations
         
     | 
| 
      
 26 
     | 
    
         
            +
            description_format: "%{template_name}"
         
     | 
| 
      
 27 
     | 
    
         
            +
            provider_type: Ansible
         
     | 
| 
      
 28 
     | 
    
         
            +
            kind: job_template
         
     | 
| 
      
 29 
     | 
    
         
            +
            feature: ansible_configure_cloud_connector
         
     | 
| 
      
 30 
     | 
    
         
            +
            %>
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            ---
         
     | 
| 
      
 33 
     | 
    
         
            +
            - hosts: all
         
     | 
| 
      
 34 
     | 
    
         
            +
              vars:
         
     | 
| 
      
 35 
     | 
    
         
            +
                satellite_url: "<%= foreman_server_url %>"
         
     | 
| 
      
 36 
     | 
    
         
            +
              roles:
         
     | 
| 
      
 37 
     | 
    
         
            +
                - project-receptor.satellite_receptor_installer
         
     | 
    
        data/config/routes.rb
    CHANGED
    
    | 
         @@ -85,6 +85,13 @@ Rails.application.routes.draw do 
     | 
|
| 
       85 
85 
     | 
    
         
             
                      end
         
     | 
| 
       86 
86 
     | 
    
         
             
                    end
         
     | 
| 
       87 
87 
     | 
    
         | 
| 
      
 88 
     | 
    
         
            +
                    resources :ansible_playbooks, :only => [] do
         
     | 
| 
      
 89 
     | 
    
         
            +
                      collection do
         
     | 
| 
      
 90 
     | 
    
         
            +
                        get :fetch
         
     | 
| 
      
 91 
     | 
    
         
            +
                        put :sync
         
     | 
| 
      
 92 
     | 
    
         
            +
                      end
         
     | 
| 
      
 93 
     | 
    
         
            +
                    end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
       88 
95 
     | 
    
         
             
                    resources :ansible_variables, :only => [:show, :index, :destroy, :update, :create] do
         
     | 
| 
       89 
96 
     | 
    
         
             
                      collection do
         
     | 
| 
       90 
97 
     | 
    
         
             
                        put :import
         
     | 
| 
         @@ -31,7 +31,21 @@ blueprints = [ 
     | 
|
| 
       31 
31 
     | 
    
         
             
                :name => 'Sync_roles_and_variables_failed',
         
     | 
| 
       32 
32 
     | 
    
         
             
                :message => 'DYNAMIC',
         
     | 
| 
       33 
33 
     | 
    
         
             
                :level => 'error'
         
     | 
| 
      
 34 
     | 
    
         
            +
              },
         
     | 
| 
      
 35 
     | 
    
         
            +
              {
         
     | 
| 
      
 36 
     | 
    
         
            +
                :group => N_('Playbooks'),
         
     | 
| 
      
 37 
     | 
    
         
            +
                :name => 'Sync_playbooks_successfully',
         
     | 
| 
      
 38 
     | 
    
         
            +
                :message => N_('Import playbooks has finished successfully'),
         
     | 
| 
      
 39 
     | 
    
         
            +
                :level => 'success'
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              },
         
     | 
| 
      
 42 
     | 
    
         
            +
              {
         
     | 
| 
      
 43 
     | 
    
         
            +
                :group => N_('Playbooks'),
         
     | 
| 
      
 44 
     | 
    
         
            +
                :name => 'Sync_playbooks_failed',
         
     | 
| 
      
 45 
     | 
    
         
            +
                :message => 'DYNAMIC',
         
     | 
| 
      
 46 
     | 
    
         
            +
                :level => 'error'
         
     | 
| 
       34 
47 
     | 
    
         
             
              }
         
     | 
| 
       35 
48 
     | 
    
         | 
| 
       36 
49 
     | 
    
         
             
            ]
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
       37 
51 
     | 
    
         
             
            blueprints.each { |blueprint| UINotifications::Seed.new(blueprint).configure }
         
     | 
| 
         @@ -158,6 +158,8 @@ Foreman::Plugin.register :foreman_ansible do 
     | 
|
| 
       158 
158 
     | 
    
         
             
                           :resource_type => 'Hostgroup'
         
     | 
| 
       159 
159 
     | 
    
         
             
                permission :generate_ansible_inventory,
         
     | 
| 
       160 
160 
     | 
    
         
             
                           { :'api/v2/ansible_inventories' => [:schedule] }
         
     | 
| 
      
 161 
     | 
    
         
            +
                permission :import_ansible_playbooks,
         
     | 
| 
      
 162 
     | 
    
         
            +
                           { :'api/v2/ansible_playbooks' => [:sync, :fetch] }
         
     | 
| 
       161 
163 
     | 
    
         
             
              end
         
     | 
| 
       162 
164 
     | 
    
         | 
| 
       163 
165 
     | 
    
         
             
              role 'Ansible Roles Manager',
         
     | 
| 
         @@ -167,7 +169,7 @@ Foreman::Plugin.register :foreman_ansible do 
     | 
|
| 
       167 
169 
     | 
    
         
             
                    :view_ansible_roles, :destroy_ansible_roles,
         
     | 
| 
       168 
170 
     | 
    
         
             
                    :import_ansible_roles, :view_ansible_variables,
         
     | 
| 
       169 
171 
     | 
    
         
             
                    :create_ansible_variables, :import_ansible_variables,
         
     | 
| 
       170 
     | 
    
         
            -
                    :edit_ansible_variables, :destroy_ansible_variables]
         
     | 
| 
      
 172 
     | 
    
         
            +
                    :edit_ansible_variables, :destroy_ansible_variables, :import_ansible_playbooks]
         
     | 
| 
       171 
173 
     | 
    
         | 
| 
       172 
174 
     | 
    
         
             
              role 'Ansible Tower Inventory Reader',
         
     | 
| 
       173 
175 
     | 
    
         
             
                   [:view_hosts, :view_hostgroups, :view_facts, :generate_report_templates, :generate_ansible_inventory,
         
     | 
| 
         @@ -48,6 +48,12 @@ module ForemanAnsible 
     | 
|
| 
       48 
48 
     | 
    
         
             
                    :description => N_('Upgrade Capsules on given Capsule server hosts'),
         
     | 
| 
       49 
49 
     | 
    
         
             
                    :proxy_selector_override => ::RemoteExecutionProxySelector::INTERNAL_PROXY
         
     | 
| 
       50 
50 
     | 
    
         
             
                  )
         
     | 
| 
      
 51 
     | 
    
         
            +
                  RemoteExecutionFeature.register(
         
     | 
| 
      
 52 
     | 
    
         
            +
                    :ansible_configure_cloud_connector,
         
     | 
| 
      
 53 
     | 
    
         
            +
                    N_('Configure Cloud Connector on given hosts'),
         
     | 
| 
      
 54 
     | 
    
         
            +
                    :description => N_('Configure Cloud Connector on given hosts'),
         
     | 
| 
      
 55 
     | 
    
         
            +
                    :proxy_selector_override => ::RemoteExecutionProxySelector::INTERNAL_PROXY
         
     | 
| 
      
 56 
     | 
    
         
            +
                  )
         
     | 
| 
       51 
57 
     | 
    
         
             
                end
         
     | 
| 
       52 
58 
     | 
    
         
             
              end
         
     | 
| 
       53 
59 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            { "template": "<%#\n  name: xprazak2.forklift_collection.foreman_provisioning.yml\n  snippet: false\n  job_category: Ansible Playbook - Imported\n  provider_type: Ansible\n  kind: job_template\n  model: JobTemplate\n%>\n- hosts: all\n  become: true\n  vars:\n    libvirt_tftp: true\n  roles:\n    - foreman\n    - libvirt\n    - foreman_provisioning\n"}
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            [
         
     | 
| 
      
 2 
     | 
    
         
            +
              {
         
     | 
| 
      
 3 
     | 
    
         
            +
                "name": "xprazak2.forklift_collection.foreman_provisioning.yml",
         
     | 
| 
      
 4 
     | 
    
         
            +
                "playbooks_content": "- hosts: all\n  become: true\n  vars:\n    libvirt_tftp: true\n  roles:\n    - foreman\n    - libvirt\n    - foreman_provisioning\n"
         
     | 
| 
      
 5 
     | 
    
         
            +
              },
         
     | 
| 
      
 6 
     | 
    
         
            +
              {
         
     | 
| 
      
 7 
     | 
    
         
            +
                "name": "xprazak2.forklift_collection.collect_debug_draft.yml",
         
     | 
| 
      
 8 
     | 
    
         
            +
                "playbooks_content": "---\n- hosts: all\n  become: true\n  vars:\n    bats_output_dir: '/root/bats_results'\n    remote_dir: \"/tmp/debug-{{ pipeline_type | default('foreman') }}-{{ pipeline_version | default('nightly') }}-{{ pipeline_os | default('el7') }}\"\n  roles:\n    - sos_report\n  tasks:\n    - name: \"Find bats files\"\n      find:\n        paths: \"{{ bats_output_dir }}\"\n        patterns: \"*.tap\"\n      register: bats_results\n\n    - name: \"Copy bats results\"\n      fetch:\n        src: \"{{ item.path }}\"\n        dest: \"{{ remote_dir }}\"\n      with_items: \"{{ bats_results.files }}\"\n\n    - name: \"Find smoker files\"\n      find:\n        paths: \"{{ smoker_output_dir }}\"\n        patterns: \"*.xml\"\n      register: smoker_results\n\n    - name: \"Copy smoker results\"\n      fetch:\n        src: \"{{ item.path }}\"\n        dest: \"{{ remote_dir }}\"\n      with_items: \"{{ smoker_results.files }}\"\n"
         
     | 
| 
      
 9 
     | 
    
         
            +
              }
         
     | 
| 
      
 10 
     | 
    
         
            +
            ]
         
     | 
| 
         @@ -0,0 +1,65 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'test_plugin_helper'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Api
         
     | 
| 
      
 6 
     | 
    
         
            +
              module V2
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Tests for the ansible playbooks controller
         
     | 
| 
      
 8 
     | 
    
         
            +
                class AnsiblePlaybooksControllerTest < ActionController::TestCase
         
     | 
| 
      
 9 
     | 
    
         
            +
                  let(:ansible_proxy) { FactoryBot.create(:smart_proxy, :with_ansible) }
         
     | 
| 
      
 10 
     | 
    
         
            +
                  let(:proxy_api) { ::ProxyAPI::Ansible.new(url: ansible_proxy.url) }
         
     | 
| 
      
 11 
     | 
    
         
            +
                  let(:playbooks_names) { %w[xprazak2.forklift_collection.foreman_provisioning.yml xprazak2.forklift_collection.collect_debug_draft.yml] }
         
     | 
| 
      
 12 
     | 
    
         
            +
                  let(:importer_test) { mock('PlaybooksImporter') }
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  test 'should fetch with nil' do
         
     | 
| 
      
 15 
     | 
    
         
            +
                    AnsiblePlaybooksController.any_instance.stubs(:fetch_playbooks_names).returns(nil)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    get :fetch, :params => {
         
     | 
| 
      
 18 
     | 
    
         
            +
                      :proxy_id => ansible_proxy.id
         
     | 
| 
      
 19 
     | 
    
         
            +
                    }, :session => set_session_user
         
     | 
| 
      
 20 
     | 
    
         
            +
                    response = JSON.parse(@response.body)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    assert_empty response['results']['playbooks_names']
         
     | 
| 
      
 22 
     | 
    
         
            +
                    assert_response :success
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  test 'should fetch playbooks names' do
         
     | 
| 
      
 26 
     | 
    
         
            +
                    AnsiblePlaybooksController.any_instance.stubs(:fetch_playbooks_names).returns(playbooks_names)
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                    get :fetch, :params => {
         
     | 
| 
      
 29 
     | 
    
         
            +
                      :proxy_id => ansible_proxy.id
         
     | 
| 
      
 30 
     | 
    
         
            +
                    }, :session => set_session_user
         
     | 
| 
      
 31 
     | 
    
         
            +
                    response = JSON.parse(@response.body)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    assert_not_empty response['results']
         
     | 
| 
      
 33 
     | 
    
         
            +
                    assert_equal response['results']['playbooks_names'], playbooks_names
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  test 'should use correct proxy' do
         
     | 
| 
      
 37 
     | 
    
         
            +
                    AnsiblePlaybooksController.any_instance.expects(:find_proxy_api).with(ansible_proxy).returns(proxy_api)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    proxy_api.expects(:playbooks_names).returns(playbooks_names)
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    get :fetch, :params => {
         
     | 
| 
      
 41 
     | 
    
         
            +
                      :proxy_id => ansible_proxy.id
         
     | 
| 
      
 42 
     | 
    
         
            +
                    }, :session => set_session_user
         
     | 
| 
      
 43 
     | 
    
         
            +
                    response = JSON.parse(@response.body)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    assert_not_empty response['results']
         
     | 
| 
      
 45 
     | 
    
         
            +
                    assert_not_empty playbooks_names = response['results']['playbooks_names']
         
     | 
| 
      
 46 
     | 
    
         
            +
                    assert_equal 2, playbooks_names.count
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  test 'check plan and sync' do
         
     | 
| 
      
 50 
     | 
    
         
            +
                    task = mock('Foreman Task')
         
     | 
| 
      
 51 
     | 
    
         
            +
                    AnsiblePlaybooksController.any_instance.expects(:plan_ansible_sync).with(ansible_proxy.id, playbooks_names).returns(task)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    task.stubs(:id).returns('123')
         
     | 
| 
      
 53 
     | 
    
         
            +
                    task.stubs(:action).returns('Import Playbooks')
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    put :sync, :params => {
         
     | 
| 
      
 56 
     | 
    
         
            +
                      :proxy_id => ansible_proxy.id,
         
     | 
| 
      
 57 
     | 
    
         
            +
                      :playbooks_names => playbooks_names
         
     | 
| 
      
 58 
     | 
    
         
            +
                    }, :session => set_session_user
         
     | 
| 
      
 59 
     | 
    
         
            +
                    response = JSON.parse(@response.body)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    assert_equal '123', response['id']
         
     | 
| 
      
 61 
     | 
    
         
            +
                    assert_equal 'Import Playbooks', response['action']
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
            end
         
     |