foreman_acd 0.3.0 → 0.4.0

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