foreman_acd 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63b0fc4a685be137bfd8d72d166d0c157081dc4c2ad34cbde4ac7e75faed4e1a
4
- data.tar.gz: 9484df12c6738faa15f1b6d76721992b74a5ae0a795bbe6fc1f20cb08d3e7edd
3
+ metadata.gz: 433f2c68da81192db3c98fc013ed2149490f2471e84d372db8241522a33b6630
4
+ data.tar.gz: aa46c833de3feb1cce0802de82dec78f1610331984e6df8df649fdadfffa2b2a
5
5
  SHA512:
6
- metadata.gz: 18caaab55b04561db5addf6d8376d37a4d7b043ccf7bba5cc98bb3d4fbc4b163b1a72416a5cffae556fa08626377dfa94608a0946d7009fd34a89989e96e9679
7
- data.tar.gz: 7f00242c823cf86a6a315885009d19ed05b8215fbfd3b2d973a819aad716dfe576fdc719b8d3b1ea3f5c869fed1eb4b3647aa264aedcca8c6a0dc24fc237085f
6
+ metadata.gz: 0accbf314dd5776a5b012507d97619be98beff2c11e523da4d27f69e9fdb1bf1d284c134dba6549719312a66ede8cb80c8a06e3851f01a14951b1752ef2e29e8
7
+ data.tar.gz: d003bc7a5de1c180b2e33ade4e85b2912776db564d59ff9d8eca4f9ccc00c38591fd061649df07bb89e76ad0b0ac5efe1c64dd506132148aaf087b758a18c078
data/README.md CHANGED
@@ -4,67 +4,121 @@
4
4
 
5
5
  A plugin to bring an user self service portal and application centric deployment to Foreman.
6
6
 
7
+
7
8
  # Description
8
9
 
9
- The target of this plugin is, to deploy whole applications which include multiple hosts
10
- and an Ansible Playbook / saltstack state to configure the application.
10
+ The target of this plugin is, to deploy whole applications which include multiple hosts and
11
+ configure them using an Ansible Playbook / saltstack state.
11
12
 
12
13
  This plugin follows the idea of different user types working together.
13
- The administrative user creates application definitions including multiple servers and
14
+ The administrative user creates Application Definition including multiple servers and
14
15
  configuration management items (Ansible Playbook, saltstack state).
15
- The user can create and deploy new application instances with an easy to use self service portal.
16
+ The user can create and deploy new Application Instaces with an easy to use self service portal.
16
17
 
17
- *Example Application Definition:*
18
- To run a complex web application, a loadbalancer is required.
18
+ *Example Application Definition:* To run a complex web application, a loadbalancer is required.
19
19
  The loadbalancer routes the requests to 3 different web servers.
20
20
  The web servers are using a database which is in high availability mode on 2 hosts.
21
21
  => 6 hosts are required.
22
22
 
23
23
  This plugin aims to setup all 6 hosts and to deploy the application.
24
24
 
25
+
25
26
  # Current State
26
- In the current state the plugin can be used to provide an easy to use self service user portal
27
- to deploy new servers.
27
+
28
+ ## Application Definition
29
+
30
+ - Configure a ansible playbook
31
+ - Use the configured ansible playbook in a Application Definition
32
+ - Overwrite ansible playbook's group variables for the Application Definition
33
+ - Set foreman parameters in the Application Definition
34
+ - Setup various services like webservers, database-servers, etc.
35
+
36
+ ## Application Instance
37
+
38
+ - Use an Application Definition for your Application Instance
39
+ - Configure specific hosts which uses the Application Definitions services
40
+ - Deploy these hosts
41
+ - Configure the hosts using the configured ansible playbook
42
+
28
43
 
29
44
  # Road Map
30
- - Self service portal for single host deployments (current version)
31
- - Add application deployment with single host requirements
32
- - Add application deployment with multi host requirements
45
+ -
46
+ - Add Application deployment with single host requirements
47
+ - Add Application deployment with multi host requirements
33
48
 
34
49
  ## WARNING
35
50
 
36
51
  This plugin is in development.
37
- In the current state, a self service portal to deploy single servers can be created.
38
52
 
39
53
  ## Installation
40
54
 
41
- See [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
42
- for how to install Foreman plugins
55
+ See [How_to_Install_a_Plugin](https://theforeman.org/plugins/#2.Installation)
56
+ for how to install Foreman plugins.
57
+
58
+ ### TL;DR:
59
+
60
+ yum install tfm-rubygem-foreman_acd
61
+ foreman-maintain service restart --only foreman
62
+
63
+ In some cases you need to do manally
64
+
65
+ foreman-rake db:migrate
66
+ foreman-rake db:seed
67
+
68
+ ### Hints
43
69
 
44
- ATM, Katello plugin need to exist, too.
70
+ Katello plugin need to exist, too.
71
+
72
+ ### Configuration
73
+
74
+ To get ansible playbooks running, you need to:
75
+
76
+ cat /var/lib/foreman-proxy/ssh/id_rsa_foreman_proxy.pub >> /root/.ssh/authorized_keys
77
+
78
+ Make sure, that the job template 'Run ACD Ansible Playbook - SSH Default' is part of your organization / location.
45
79
 
46
80
  ## Usage
47
81
 
48
- Application Definition (Admin)
82
+ ### Ansible Playbook
83
+
84
+ * Copy (or checkout a git repository) to e.g. /opt/ansible-playbook
85
+ * Add a new Ansible Playbook via Configure -> Ansible Playbook
86
+ * Set the path to /opt/ansible-playbook and name the playbook file. (e.g. site.yml)
87
+ * Save it and press "Import group variables" for this newly created ansible playbook.
88
+
89
+ ### Application Definition (Admin)
90
+
49
91
  * Create an Application Definition (Configure -> Application Definition) first
50
- * Select the Hostgroup you want to use.
92
+ * Select the Ansible Playbook you want to use.
93
+ * Add new services and specifiy the host group you want to use.
51
94
  * Specifiy the values, a user could overwrite.
52
95
  (you can set a default value, if you want)
53
96
 
54
- Application Instance (User)
55
- * Create an Application Instance (Configure -> Application Instrane)
97
+ ### Application Instance (User)
98
+
99
+ * Create an Application Instance (Configure -> Application Instance)
56
100
  * Select the Application Definition which should be used
57
101
  * Set the values.
58
102
  Remember, all parameters need to have a value.
59
103
  * Save the Application Instance
60
- * To Deploy the host, select "Deploy" in the Action selection dropdown field
61
- on the Application Instance index site
104
+
105
+ ### Deploy & Configure the Application Instance (User)
106
+
107
+ * To Deploy the host, select "Deploy" in the action selection dropdown field
108
+ on the Application Instance index site.
109
+ * See if the hosts are deployed via action selection dropdown -> report.
110
+ * After all hosts are deployed, run the ansible playbook via
111
+ action selection dropdown -> Run ansible playbook
112
+
62
113
 
63
114
  ## TODO
64
115
 
65
- - Add ansible playbook / saltstack support to configure the application
66
- - Multi-host support
67
- - Add validation to the different parameter types
116
+ - Add saltstack support to configure the application
117
+ - "git" support for the ansible playbooks
118
+ - Automatically run the ansible playbook after all hosts are deployed
119
+ - More parameter / value validation
120
+ - Deliver ansible playbooks to the connected foreman smart proxies
121
+
68
122
 
69
123
  ## Contributing
70
124
 
@@ -72,7 +126,7 @@ Fork and send a Pull Request. Thanks!
72
126
 
73
127
  ## Copyright
74
128
 
75
- Copyright (c) 2019 ATIX AG
129
+ Copyright (c) 2020 ATIX AG
76
130
 
77
131
  This program is free software: you can redistribute it and/or modify
78
132
  it under the terms of the GNU General Public License as published by
@@ -86,4 +140,3 @@ GNU General Public License for more details.
86
140
 
87
141
  You should have received a copy of the GNU General Public License
88
142
  along with this program. If not, see <http://www.gnu.org/licenses/>.
89
-
@@ -86,11 +86,11 @@ module ForemanAcd
86
86
 
87
87
  # We need to support: group_vars/group_file and group_vars/group_dir/yaml_files
88
88
  dir_and_file = File.split(vars_file)
89
- basename = File.basename(dir_and_file[0], '.*')
90
- if basename == 'group_vars'
91
- group_name = dir_and_file[1]
92
- else
93
- group_name = basename
89
+
90
+ if File.basename(dir_and_file[0]) == 'group_vars' # in case of group_vars/group_file
91
+ group_name = File.basename(dir_and_file[1], '.*')
92
+ else # in case of group_vars/group_dir/yaml_files
93
+ group_name = File.basename(dir_and_file[0])
94
94
  end
95
95
 
96
96
  logger.debug("Add ansible vars from file #{vars_file} to group #{group_name}")
@@ -16,7 +16,8 @@ module ForemanAcd
16
16
  end
17
17
 
18
18
  def read_ansible_playbooks
19
- @ansible_playbooks = AnsiblePlaybook.all.map { |elem| { elem.id => elem.name } }.reduce({}) { |h, v| h.merge v }
19
+ # Only use ansible playbooks for which the user pressed import group vars once.
20
+ @ansible_playbooks = AnsiblePlaybook.where.not(vars: nil).map { |elem| { elem.id => elem.name } }.reduce({}) { |h, v| h.merge v }
20
21
  end
21
22
 
22
23
  def read_hostgroups
@@ -6,17 +6,13 @@ module ForemanAcd
6
6
  include Foreman::Controller::AutoCompleteSearch
7
7
  include ::ForemanAcd::Concerns::AppInstanceParameters
8
8
 
9
- before_action :find_resource, :only => [:edit, :update, :destroy, :deploy, :report, :configure]
9
+ before_action :find_resource, :only => [:edit, :update, :destroy, :deploy, :report]
10
10
  before_action :read_applications, :only => [:new, :edit]
11
11
 
12
12
  def index
13
13
  @app_instances = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
14
14
  end
15
15
 
16
- def read_applications
17
- @applications = AppDefinition.all.map { |elem| { elem.id => elem.name } }.reduce({}) { |h, v| h.merge v }
18
- end
19
-
20
16
  def new
21
17
  @app_instance = AppInstance.new
22
18
  end
@@ -55,8 +51,6 @@ module ForemanAcd
55
51
  :deploy
56
52
  when 'report'
57
53
  :report
58
- when 'configure'
59
- :configure
60
54
  else
61
55
  super
62
56
  end
@@ -64,51 +58,35 @@ module ForemanAcd
64
58
 
65
59
  def deploy
66
60
  app_deployer = ForemanAcd::AppDeployer.new(@app_instance)
61
+ app_hosts = app_deployer.deploy
67
62
 
68
63
  # save any change to the app_hosts json
69
- @app_instance.hosts = app_deployer.deploy.to_json
64
+ @app_instance.hosts = app_hosts.to_json
70
65
  @app_instance.save
71
66
 
72
- @deploy_hosts = app_deployer.deploy_hosts
67
+ @deploy_hosts = collect_host_report_data(app_hosts)
73
68
  end
74
69
 
75
70
  def report
76
- @report_hosts = []
77
71
  app_hosts = JSON.parse(@app_instance.hosts)
78
- app_hosts.each do |host_data|
79
- h = Host.find(host_data['foreman_host_id'])
80
- @report_hosts.push({id: h.id, name: host_data['hostname'], hostname: h.hostname, hostUrl: host_path(h), powerStatusUrl: power_api_host_path(h) })
81
- end
72
+ @report_hosts = collect_host_report_data(app_hosts)
82
73
 
83
74
  logger.debug("deploy report hosts are: #{@report_hosts.inspect}")
84
75
  end
85
76
 
86
- def configure
87
- app_configurator = ForemanAcd::AppConfigurator.new(@app_instance)
88
- jobs = app_configurator.configure
89
- job_count = jobs.count
90
-
91
- customize_first = if params[:customize] == 'true'
92
- true
93
- else
94
- false
95
- end
96
-
97
- logger.debug("Created #{job_count} to configure #{@app_instance} - customize: #{customize_first}")
98
-
99
- if job_count == 1 && customize_first == false
100
- jobs.first.trigger!
101
- redirect_to job_invocation_path(jobs.first.job_invocation)
102
- elsif customize_first == false
103
- jobs.each do |composer|
104
- composer.save
105
- end
106
- # redirect to the job itself if we want to customize the job
107
- redirect_to job_invocations_path
108
- else
109
- # redirect to the job itself if we only have one job, otherwise to the index page
110
- redirect_to job_invocations_path
77
+ private
78
+
79
+ def read_applications
80
+ @applications = AppDefinition.all.map { |elem| { elem.id => elem.name } }.reduce({}) { |h, v| h.merge v }
81
+ end
82
+
83
+ def collect_host_report_data(app_hosts)
84
+ report_data = []
85
+ app_hosts.each do |host_data|
86
+ host = Host.find(host_data['foreman_host_id'])
87
+ report_data << { id: host.id, name: host_data['hostname'], hostname: host.hostname, hostUrl: host_path(host), progress_report_id: host.progress_report_id}
111
88
  end
89
+ report_data
112
90
  end
113
91
  end
114
92
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanAcd
4
+ # Class to run remote execution jobs
5
+ class RemoteExecutionController < JobInvocationsController
6
+
7
+ def new
8
+ jobs = init_configuration
9
+ @composer = jobs.first
10
+ end
11
+
12
+ def create
13
+ customize_first = params[:customize] || false
14
+ jobs = init_configuration
15
+
16
+ if jobs.count == 1 && customize_first == false
17
+ @composer = jobs.first
18
+ @composer.trigger!
19
+ redirect_to job_invocation_path(@composer.job_invocation)
20
+ elsif customize_first == false
21
+ jobs.each do |composer|
22
+ composer.trigger
23
+ end
24
+ # redirect to the job itself if we want to customize the job
25
+ redirect_to job_invocations_path
26
+ else
27
+ @composer = jobs.first
28
+ render :action => 'new'
29
+ end
30
+ end
31
+
32
+ # to overcome the isolated namespace engine difficulties with paths
33
+ helper Rails.application.routes.url_helpers
34
+ def _routes
35
+ Rails.application.routes
36
+ end
37
+
38
+ private
39
+
40
+ def init_configuration
41
+ app_instance = ForemanAcd::AppInstance.find_by(:name => params[:id])
42
+ app_configurator = ForemanAcd::AppConfigurator.new(app_instance)
43
+
44
+ jobs = app_configurator.configure
45
+ logger.debug("Creating #{jobs.count} job(s) to configure the app #{app_instance}. Customize first: #{params[:customize]}")
46
+ return jobs
47
+ end
48
+ end
49
+ end
@@ -8,7 +8,7 @@ module ForemanAcd
8
8
  friendly_id :name
9
9
 
10
10
  self.table_name = 'acd_ansible_playbooks'
11
- has_many :app_definitions, :inverse_of => :ansible_playbook, :dependent => :destroy
11
+ has_many :app_definitions, :inverse_of => :ansible_playbook, :foreign_key => 'acd_ansible_playbook_id', dependent: :restrict_with_error
12
12
  validates :name, :presence => true, :uniqueness => true
13
13
  scoped_search :on => :name
14
14
  default_scope -> { order("acd_ansible_playbooks.name") }
@@ -5,11 +5,9 @@ module ForemanAcd
5
5
  class AppDeployer
6
6
 
7
7
  delegate :logger, :to => :Rails
8
- attr_reader :deploy_hosts
9
8
 
10
9
  def initialize(app_instance)
11
10
  @app_instance = app_instance
12
- @deploy_hosts = []
13
11
  end
14
12
 
15
13
  def deploy
@@ -44,7 +42,7 @@ module ForemanAcd
44
42
  end
45
43
 
46
44
  # REMOVE ME (but very nice for testing)
47
- #host.mac = "00:11:22:33:44:55"
45
+ # host.mac = "00:11:22:33:44:55"
48
46
 
49
47
  apply_compute_profile(host)
50
48
  host.suggest_default_pxe_loader
@@ -52,8 +50,6 @@ module ForemanAcd
52
50
 
53
51
  # save the foreman host id
54
52
  host_data['foreman_host_id'] = host.id
55
-
56
- @deploy_hosts.push({ id: host.id, name: host_data['hostname'], hostname: host.hostname, hostUrl: host_path(h), progress_report_id: host.progress_report_id})
57
53
  rescue StandardError => e
58
54
  logger.error("Failed to initiate host creation: #{e.class}: #{e.message}\n#{e.backtrace.join($INPUT_RECORD_SEPARATOR)}")
59
55
  end
@@ -16,9 +16,9 @@
16
16
  <td><%= ansible_playbook.description %></td>
17
17
  <td>
18
18
  <%= action_buttons(
19
+ display_link_if_authorized(_("Import group variables"), hash_for_import_vars_ansible_playbook_path(:id => ansible_playbook).merge(:auth_object => ansible_playbook, :authorizer => authorizer)),
19
20
  display_delete_if_authorized(hash_for_ansible_playbook_path(:id => ansible_playbook).merge(:auth_object => ansible_playbook, :authorizer => authorizer),
20
- :data => { 'confirm': _('Delete %s?') % ansible_playbook.name }),
21
- display_link_if_authorized(_("Import group variables"), hash_for_import_vars_ansible_playbook_path(:id => ansible_playbook).merge(:auth_object => ansible_playbook, :authorizer => authorizer))
21
+ :data => { 'confirm': _('Delete %s?') % ansible_playbook.name })
22
22
  ) %>
23
23
  </td>
24
24
  </tr>
@@ -17,9 +17,9 @@
17
17
  <td>
18
18
  <%= action_buttons(display_link_if_authorized(_("Deploy"), hash_for_deploy_app_instance_path(:id => app_instance), :method => :post,
19
19
  :title => _("Deploy application #{app_instance}")),
20
- display_link_if_authorized(_("Run Playbook"), hash_for_configure_app_instance_path(:id => app_instance), :method => :post,
20
+ display_link_if_authorized(_("Run Playbook"), hash_for_remote_execution_path(:id => app_instance), :method => :post,
21
21
  :title => _("Run ansible playbook for application #{app_instance}")),
22
- display_link_if_authorized(_("Run Playbook - customize first"), hash_for_configure_app_instance_path(:id => app_instance, :customize => true), :method => :post,
22
+ display_link_if_authorized(_("Run Playbook - customize first"), hash_for_remote_execution_path(:id => app_instance, :customize => true), :method => :post,
23
23
  :title => _("Prepare job to run ansible playbook for application #{app_instance}")),
24
24
  display_link_if_authorized(_("Report"), hash_for_report_app_instance_path(:id => app_instance), :method => :get,
25
25
  :title => _("Show last deployment report for application #{app_instance}")),
@@ -31,11 +31,12 @@ Rails.application.routes.draw do
31
31
 
32
32
  member do
33
33
  post 'deploy'
34
- post 'configure'
35
34
  get 'report'
36
35
  end
37
36
  end
38
37
 
38
+ match '/remote_execution', :controller => 'foreman_acd/remote_execution', :action => 'create', :via => [:post]
39
+
39
40
  get 'ui_acd_app/:id', :to => 'ui_acd#app', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_app
40
41
  get 'ui_acd_foreman_data/:id', :to => 'ui_acd#foreman_data', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_foreman_data
41
42
  get 'ui_acd_ansible_data/:id', :to => 'ui_acd#ansible_data', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_ansible_data
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ForemanAcd
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -11,7 +11,8 @@ import Select from 'foremanReact/components/common/forms/Select';
11
11
  import ParameterSelection from '../ParameterSelection';
12
12
  import AddTableEntry from '../common/AddTableEntry';
13
13
  import DeleteTableEntry from '../common/DeleteTableEntry';
14
- import RailsData from '../common/RailsData'
14
+ import RailsData from '../common/RailsData';
15
+ import EasyHeaderFormatter from '../common/EasyHeaderFormatter';
15
16
  import AnsiblePlaybookSelector from './components/AnsiblePlaybookSelector';
16
17
 
17
18
  import {
@@ -118,8 +119,7 @@ class ApplicationDefinition extends React.Component {
118
119
  });
119
120
  this.inlineEditButtonsFormatter = inlineEditButtonsFormatter;
120
121
 
121
- const headerFormatter = value => <Table.Heading>{value}</Table.Heading>;
122
- this.headerFormatter = headerFormatter;
122
+ this.headerFormatter = EasyHeaderFormatter;
123
123
 
124
124
  const inlineEditFormatterImpl = {
125
125
  renderValue: (value, additionalData) => (
@@ -55,7 +55,7 @@ export const initApplicationDefinition = (
55
55
  props: {
56
56
  index: 0,
57
57
  style: {
58
- width: '20%'
58
+ width: '15%'
59
59
  }
60
60
  },
61
61
  },
@@ -71,7 +71,7 @@ export const initApplicationDefinition = (
71
71
  props: {
72
72
  index: 1,
73
73
  style: {
74
- width: '20%'
74
+ width: '10%'
75
75
  }
76
76
  },
77
77
  },
@@ -151,7 +151,7 @@ export const initApplicationDefinition = (
151
151
  props: {
152
152
  index: 6,
153
153
  style: {
154
- width: '20%'
154
+ width: '15%'
155
155
  }
156
156
  },
157
157
  },
@@ -10,7 +10,8 @@ import Select from 'foremanReact/components/common/forms/Select';
10
10
  import ParameterSelection from '../ParameterSelection';
11
11
  import AddTableEntry from '../common/AddTableEntry';
12
12
  import DeleteTableEntry from '../common/DeleteTableEntry';
13
- import RailsData from '../common/RailsData'
13
+ import RailsData from '../common/RailsData';
14
+ import EasyHeaderFormatter from '../common/EasyHeaderFormatter';
14
15
  import AppDefinitionSelector from './components/AppDefinitionSelector';
15
16
  import ServiceCounter from './components/ServiceCounter';
16
17
  import { arrayToObject } from '../../helper';
@@ -145,8 +146,7 @@ class ApplicationInstance extends React.Component {
145
146
  });
146
147
  this.inlineEditButtonsFormatter = inlineEditButtonsFormatter;
147
148
 
148
- const headerFormatter = value => <Table.Heading>{value}</Table.Heading>;
149
- this.headerFormatter = headerFormatter;
149
+ this.headerFormatter = EasyHeaderFormatter;
150
150
 
151
151
  const inlineEditFormatterImpl = {
152
152
  renderValue: (value, additionalData) => (
@@ -50,7 +50,7 @@ export const initApplicationInstance = (
50
50
  props: {
51
51
  index: 0,
52
52
  style: {
53
- width: '20%'
53
+ width: '30%'
54
54
  }
55
55
  },
56
56
  },
@@ -66,7 +66,7 @@ export const initApplicationInstance = (
66
66
  props: {
67
67
  index: 1,
68
68
  style: {
69
- width: '20%'
69
+ width: '30%'
70
70
  }
71
71
  },
72
72
  },
@@ -77,7 +77,7 @@ export const initParameterSelection = (
77
77
  props: {
78
78
  sort: true,
79
79
  style: {
80
- width: '20%'
80
+ width: '25%'
81
81
  }
82
82
  },
83
83
  transforms: [sortableTransform],
@@ -96,7 +96,7 @@ export const initParameterSelection = (
96
96
  props: {
97
97
  sort: true,
98
98
  style: {
99
- width: '20%'
99
+ width: '25%'
100
100
  }
101
101
  },
102
102
  transforms: [sortableTransform],
@@ -159,7 +159,7 @@ export const initParameterSelection = (
159
159
  label: 'Actions',
160
160
  props: {
161
161
  style: {
162
- width: '20%'
162
+ width: '10%'
163
163
  }
164
164
  },
165
165
  formatters: [actionHeaderCellFormatter]
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import {
4
+ Table,
5
+ } from 'patternfly-react';
6
+
7
+ const EasyHeaderFormatter = (value, { column }) => (
8
+ <Table.Heading aria-label={column.header.label} {...column.header.props}>
9
+ {value}
10
+ </Table.Heading>
11
+ );
12
+
13
+ EasyHeaderFormatter.propTypes = {
14
+ value: PropTypes.string.isRequired,
15
+ column: PropTypes.object.isRequired,
16
+ };
17
+
18
+ export default EasyHeaderFormatter;
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_acd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ATIX AG
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-26 00:00:00.000000000 Z
11
+ date: 2020-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -62,6 +62,7 @@ files:
62
62
  - app/controllers/foreman_acd/concerns/ansible_playbook_parameters.rb
63
63
  - app/controllers/foreman_acd/concerns/app_definition_parameters.rb
64
64
  - app/controllers/foreman_acd/concerns/app_instance_parameters.rb
65
+ - app/controllers/foreman_acd/remote_execution_controller.rb
65
66
  - app/controllers/ui_acd_controller.rb
66
67
  - app/models/foreman_acd/ansible_playbook.rb
67
68
  - app/models/foreman_acd/app_definition.rb
@@ -175,6 +176,7 @@ files:
175
176
  - webpack/components/ParameterSelection/index.js
176
177
  - webpack/components/common/AddTableEntry.js
177
178
  - webpack/components/common/DeleteTableEntry.js
179
+ - webpack/components/common/EasyHeaderFormatter.js
178
180
  - webpack/components/common/ExtSelect.js
179
181
  - webpack/components/common/RailsData.js
180
182
  - webpack/components/common/__tests__/AddTableEntry.test.js