foreman_acd 0.6.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -5
  3. data/app/controllers/foreman_acd/ansible_playbooks_controller.rb +90 -0
  4. data/app/controllers/foreman_acd/app_definitions_controller.rb +104 -7
  5. data/app/controllers/foreman_acd/app_instances_controller.rb +34 -32
  6. data/app/controllers/foreman_acd/concerns/ansible_playbook_parameters.rb +1 -1
  7. data/app/controllers/foreman_acd/concerns/app_instance_mixins.rb +36 -0
  8. data/app/controllers/foreman_acd/remote_execution_controller.rb +37 -21
  9. data/app/controllers/ui_acd_controller.rb +42 -3
  10. data/app/lib/actions/foreman_acd/deploy_all_hosts.rb +12 -7
  11. data/app/lib/actions/foreman_acd/run_configurator.rb +11 -7
  12. data/app/models/concerns/foreman_acd/host_managed_extensions.rb +41 -28
  13. data/app/models/foreman_acd/acd_provider.rb +7 -1
  14. data/app/models/foreman_acd/ansible_playbook.rb +2 -1
  15. data/app/models/foreman_acd/app_instance.rb +48 -3
  16. data/app/models/foreman_acd/foreman_host.rb +8 -0
  17. data/app/services/foreman_acd/acd_proxy_proxy_selector.rb +17 -0
  18. data/app/services/foreman_acd/app_configurator.rb +59 -15
  19. data/app/services/foreman_acd/app_deployer.rb +27 -4
  20. data/app/services/foreman_acd/inventory_creator.rb +25 -1
  21. data/app/views/foreman_acd/ansible_playbooks/_form.html.erb +41 -7
  22. data/app/views/foreman_acd/app_definitions/_form.html.erb +5 -1
  23. data/app/views/foreman_acd/app_definitions/import.html.erb +20 -1
  24. data/app/views/foreman_acd/app_definitions/index.html.erb +3 -6
  25. data/app/views/foreman_acd/app_instances/_form.html.erb +5 -1
  26. data/app/views/foreman_acd/app_instances/index.html.erb +18 -12
  27. data/app/views/foreman_acd/app_instances/report.html.erb +8 -3
  28. data/app/views/templates/job/run_acd_ansible_playbook.erb +1 -1
  29. data/app/views/ui_acd/host_report.json.rabl +4 -0
  30. data/app/views/ui_acd/report_data.json.rabl +10 -0
  31. data/app/views/ui_acd/validate_hostname.json.rabl +6 -0
  32. data/config/routes.rb +6 -0
  33. data/db/migrate/20210316151145_add_git_commit_to_ansible_playbooks.rb +8 -0
  34. data/db/migrate/20210503122809_add_git_url_to_ansible_playbooks.rb +8 -0
  35. data/db/migrate/20210818125913_add_is_existing_host_to_foreman_host.rb +8 -0
  36. data/db/migrate/20210902110645_add_initial_configure_task.rb +8 -0
  37. data/db/seeds.d/75-job_templates.rb +1 -1
  38. data/lib/foreman_acd/engine.rb +26 -4
  39. data/lib/foreman_acd/plugin.rb +9 -18
  40. data/lib/foreman_acd/version.rb +1 -1
  41. data/lib/foreman_acd.rb +30 -0
  42. data/lib/tasks/foreman_acd_tasks.rake +0 -12
  43. data/package.json +8 -22
  44. data/test/controllers/ansible_playbooks_controller_test.rb +1 -1
  45. data/test/controllers/app_instances_controller_test.rb +8 -3
  46. data/test/controllers/ui_acd_controller_test.rb +25 -6
  47. data/test/factories/foreman_acd_factories.rb +18 -4
  48. data/test/models/acd_provider_test.rb +37 -0
  49. data/test/models/ansible_playbook_test.rb +11 -0
  50. data/test/models/app_definition_test.rb +1 -1
  51. data/test/models/app_instance_test.rb +2 -0
  52. data/test/models/concerns/host_extensions_test.rb +26 -0
  53. data/test/models/foreman_host_test.rb +12 -0
  54. data/webpack/__mocks__/foremanReact/API.js +2 -0
  55. data/webpack/__mocks__/foremanReact/common/I18n.js +3 -0
  56. data/webpack/__mocks__/foremanReact/common/helpers.js +2 -0
  57. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +2 -0
  58. data/webpack/__mocks__/foremanReact/components/ForemanModal.js +7 -0
  59. data/webpack/__mocks__/foremanReact/components/common/forms/CommonForm.js +2 -0
  60. data/webpack/__mocks__/foremanReact/components/common/forms/TextInput.js +2 -0
  61. data/webpack/__mocks__/foremanReact/components/hosts/powerStatus.js +1 -0
  62. data/webpack/__snapshots__/helper.test.js.snap +14 -0
  63. data/webpack/components/ApplicationDefinition/ApplicationDefinition.js +35 -11
  64. data/webpack/components/ApplicationDefinition/ApplicationDefinitionActions.js +12 -0
  65. data/webpack/components/ApplicationDefinition/ApplicationDefinitionConstants.js +1 -0
  66. data/webpack/components/ApplicationDefinition/ApplicationDefinitionReducer.js +30 -9
  67. data/webpack/components/ApplicationDefinition/ApplicationDefinitionSelectors.js +4 -0
  68. data/webpack/components/ApplicationDefinition/__fixtures__/applicationDefinitionConfData_1.fixtures.js +288 -0
  69. data/webpack/components/ApplicationDefinition/__fixtures__/applicationDefinitionReducer.fixtures.js +79 -0
  70. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinition.test.js +26 -0
  71. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinitionReducer.test.js +119 -0
  72. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinitionSelectors.test.js +53 -0
  73. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinition.test.js.snap +226 -0
  74. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinitionReducer.test.js.snap +3033 -0
  75. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinitionSelectors.test.js.snap +307 -0
  76. data/webpack/components/ApplicationDefinition/components/AnsiblePlaybookSelector.js +2 -1
  77. data/webpack/components/ApplicationDefinition/components/__tests__/AnsiblePlaybookSelector.test.js +41 -0
  78. data/webpack/components/ApplicationDefinition/components/__tests__/__snapshots__/AnsiblePlaybookSelector.test.js.snap +121 -0
  79. data/webpack/components/ApplicationDefinition/index.js +8 -0
  80. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImport.js +214 -0
  81. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImport.scss +1 -0
  82. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportActions.js +161 -0
  83. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportConstants.js +6 -0
  84. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportReducer.js +79 -0
  85. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportSelectors.js +8 -0
  86. data/webpack/components/ApplicationDefinitionImport/__fixtures__/applicationDefinitionImportConfData_1.fixtures.js +129 -0
  87. data/webpack/components/ApplicationDefinitionImport/__fixtures__/applicationDefinitionImportReducer.fixtures.js +29 -0
  88. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImport.test.js +20 -0
  89. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImportReducer.test.js +43 -0
  90. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImportSelectors.test.js +29 -0
  91. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImport.test.js.snap +62 -0
  92. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImportReducer.test.js.snap +362 -0
  93. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImportSelectors.test.js.snap +130 -0
  94. data/webpack/components/ApplicationDefinitionImport/index.js +32 -0
  95. data/webpack/components/ApplicationInstance/ApplicationInstance.js +105 -31
  96. data/webpack/components/ApplicationInstance/ApplicationInstanceActions.js +118 -6
  97. data/webpack/components/ApplicationInstance/ApplicationInstanceConstants.js +4 -0
  98. data/webpack/components/ApplicationInstance/ApplicationInstanceHelper.js +15 -0
  99. data/webpack/components/ApplicationInstance/ApplicationInstanceReducer.js +71 -30
  100. data/webpack/components/ApplicationInstance/ApplicationInstanceSelectors.js +4 -0
  101. data/webpack/components/ApplicationInstance/__fixtures__/applicationInstanceConfData_1.fixtures.js +263 -0
  102. data/webpack/components/ApplicationInstance/__fixtures__/applicationInstanceReducer.fixtures.js +80 -0
  103. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstance.test.js +24 -0
  104. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceReducer.test.js +131 -0
  105. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceSelectors.test.js +56 -0
  106. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstance.test.js.snap +300 -0
  107. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceReducer.test.js.snap +2990 -0
  108. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceSelectors.test.js.snap +284 -0
  109. data/webpack/components/ApplicationInstance/components/AppDefinitionSelector.js +1 -0
  110. data/webpack/components/ApplicationInstance/components/ServiceCounter.js +1 -1
  111. data/webpack/components/ApplicationInstance/helper.js +0 -0
  112. data/webpack/components/ApplicationInstance/index.js +8 -0
  113. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.js +81 -6
  114. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportActions.js +35 -1
  115. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportConstants.js +3 -0
  116. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportReducer.js +19 -0
  117. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportSelectors.js +4 -0
  118. data/webpack/components/ApplicationInstanceReport/__fixtures__/applicationInstanceReportData_1.fixtures.js +349 -0
  119. data/webpack/components/ApplicationInstanceReport/__fixtures__/applicationInstanceReportReducer.fixtures.js +20 -0
  120. data/webpack/components/ApplicationInstanceReport/__tests__/ApplicationInstanceReport.test.js +47 -0
  121. data/webpack/components/ApplicationInstanceReport/__tests__/ApplicationInstanceReportReducer.test.js +41 -0
  122. data/webpack/components/ApplicationInstanceReport/__tests__/ApplicationInstanceReportSelectors.test.js +26 -0
  123. data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReport.test.js.snap +7 -0
  124. data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReportReducer.test.js.snap +718 -0
  125. data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReportSelectors.test.js.snap +347 -0
  126. data/webpack/components/ApplicationInstanceReport/components/__tests__/ReportViewer.test.js +24 -0
  127. data/webpack/components/ApplicationInstanceReport/components/__tests__/__snapshots__/ReportViewer.test.js.snap +24 -0
  128. data/webpack/components/ApplicationInstanceReport/index.js +8 -1
  129. data/webpack/components/ExistingHostSelection/ExistingHostSelection.js +104 -0
  130. data/webpack/components/ExistingHostSelection/ExistingHostSelection.scss +15 -0
  131. data/webpack/components/ExistingHostSelection/ExistingHostSelectionActions.js +71 -0
  132. data/webpack/components/ExistingHostSelection/ExistingHostSelectionConstants.js +4 -0
  133. data/webpack/components/ExistingHostSelection/ExistingHostSelectionHelper.js +0 -0
  134. data/webpack/components/ExistingHostSelection/ExistingHostSelectionReducer.js +90 -0
  135. data/webpack/components/ExistingHostSelection/ExistingHostSelectionSelectors.js +8 -0
  136. data/webpack/components/ExistingHostSelection/__fixtures__/existingHostSelectionConfData_1.fixtures.js +191 -0
  137. data/webpack/components/ExistingHostSelection/__fixtures__/existingHostSelectionReducer.fixtures.js +203 -0
  138. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelection.test.js +19 -0
  139. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelectionReducer.test.js +59 -0
  140. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelectionSelectors.test.js +36 -0
  141. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelection.test.js.snap +35 -0
  142. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelectionReducer.test.js.snap +614 -0
  143. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelectionSelectors.test.js.snap +27 -0
  144. data/webpack/components/ExistingHostSelection/components/ServiceSelector.js +48 -0
  145. data/webpack/components/ExistingHostSelection/components/__tests__/ServiceSelector.test.js +35 -0
  146. data/webpack/components/ExistingHostSelection/components/__tests__/__snapshots__/ServiceSelector.test.js.snap +77 -0
  147. data/webpack/components/ExistingHostSelection/index.js +26 -0
  148. data/webpack/components/ParameterSelection/ParameterSelection.js +103 -1
  149. data/webpack/components/ParameterSelection/ParameterSelection.scss +7 -0
  150. data/webpack/components/ParameterSelection/ParameterSelectionActions.js +46 -4
  151. data/webpack/components/ParameterSelection/ParameterSelectionConstants.js +2 -0
  152. data/webpack/components/ParameterSelection/ParameterSelectionHelper.js +5 -1
  153. data/webpack/components/ParameterSelection/ParameterSelectionReducer.js +51 -29
  154. data/webpack/components/ParameterSelection/ParameterSelectionSelectors.js +2 -0
  155. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionData_1.fixtures.js +124 -84
  156. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionReducer.fixtures.js +10 -4
  157. data/webpack/components/ParameterSelection/__tests__/ParameterSelection.test.js +36 -46
  158. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionReducer.test.js +33 -25
  159. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionSelectors.test.js +12 -6
  160. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelection.test.js.snap +84 -112
  161. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionReducer.test.js.snap +1589 -878
  162. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionSelectors.test.js.snap +130 -79
  163. data/webpack/components/ParameterSelection/index.js +4 -1
  164. data/webpack/components/SyncGitRepo/SyncGitRepo.js +202 -0
  165. data/webpack/components/SyncGitRepo/SyncGitRepo.scss +1 -0
  166. data/webpack/components/SyncGitRepo/SyncGitRepoActions.js +123 -0
  167. data/webpack/components/SyncGitRepo/SyncGitRepoConstants.js +8 -0
  168. data/webpack/components/SyncGitRepo/SyncGitRepoReducer.js +80 -0
  169. data/webpack/components/SyncGitRepo/SyncGitRepoSelectors.js +6 -0
  170. data/webpack/components/SyncGitRepo/__fixtures__/syncGitRepoConfData_1.fixtures.js +7 -0
  171. data/webpack/components/SyncGitRepo/__fixtures__/syncGitRepoReducer.fixtures.js +44 -0
  172. data/webpack/components/SyncGitRepo/__tests__/SyncGitRepo.test.js +27 -0
  173. data/webpack/components/SyncGitRepo/__tests__/SyncGitRepoReducer.test.js +95 -0
  174. data/webpack/components/SyncGitRepo/__tests__/SyncGitRepoSelectors.test.js +32 -0
  175. data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepo.test.js.snap +31 -0
  176. data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepoReducer.test.js.snap +137 -0
  177. data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepoSelectors.test.js.snap +13 -0
  178. data/webpack/components/SyncGitRepo/components/FormTextInput.js +42 -0
  179. data/webpack/components/SyncGitRepo/components/ScmTypeSelector.js +47 -0
  180. data/webpack/components/SyncGitRepo/index.js +28 -0
  181. data/webpack/components/common/DeleteTableEntry.js +16 -2
  182. data/webpack/components/common/ExtTextInput.js +43 -0
  183. data/webpack/components/common/__tests__/EditTableEntry.test.js +53 -0
  184. data/webpack/components/common/__tests__/LockTableEntry.test.js +35 -0
  185. data/webpack/components/common/__tests__/__snapshots__/DeleteTableEntry.test.js.snap +40 -2
  186. data/webpack/components/common/__tests__/__snapshots__/EditTableEntry.test.js.snap +81 -0
  187. data/webpack/components/common/__tests__/__snapshots__/LockTableEntry.test.js.snap +60 -0
  188. data/webpack/helper.js +35 -1
  189. data/webpack/helper.test.js +56 -0
  190. data/webpack/index.js +7 -0
  191. data/webpack/js-yaml.js +3874 -0
  192. data/webpack/reducer.js +16 -1
  193. data/webpack/test_setup.js +0 -2
  194. metadata +136 -11
  195. data/webpack/components/common/EasyHeaderFormatter.js +0 -18
  196. data/webpack/components/common/__tests__/__snapshots__/AddParameter.test.js.snap +0 -35
  197. data/webpack/components/common/__tests__/__snapshots__/DeleteParameter.test.js.snap +0 -41
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import {
4
4
  Icon,
5
5
  Button,
6
+ MessageDialog,
6
7
  } from 'patternfly-react';
7
8
  import * as resolve from 'table-resolver';
8
9
  import ForemanModal from 'foremanReact/components/ForemanModal';
@@ -12,13 +13,14 @@ import {
12
13
  } from 'foremanReact/common/I18n';
13
14
  import Select from 'foremanReact/components/common/forms/Select';
14
15
  import ParameterSelection from '../ParameterSelection';
16
+ import ExistingHostSelection from '../ExistingHostSelection';
15
17
  import AddTableEntry from '../common/AddTableEntry';
16
18
  import DeleteTableEntry from '../common/DeleteTableEntry';
17
19
  import RailsData from '../common/RailsData';
18
- import EasyHeaderFormatter from '../common/EasyHeaderFormatter';
19
20
  import AppDefinitionSelector from './components/AppDefinitionSelector';
20
21
  import ServiceCounter from './components/ServiceCounter';
21
22
  import { arrayToObject } from '../../helper';
23
+ import { EasyHeaderFormatter } from '../../helper';
22
24
 
23
25
  import {
24
26
  Table,
@@ -41,7 +43,7 @@ class ApplicationInstance extends React.Component {
41
43
  return (rowData.backup !== undefined);
42
44
  }
43
45
 
44
- addTableEntryAllowed() {
46
+ changeDataAllowed() {
45
47
  return this.props.editMode || this.props.appDefinition.id == ''
46
48
  }
47
49
 
@@ -63,8 +65,6 @@ class ApplicationInstance extends React.Component {
63
65
  const invalidMinServices = this.props.services.filter(s => (Number(s.minCount) != 0) && (s.currentCount < s.minCount));
64
66
  const invalidMaxServices = this.props.services.filter(s => (Number(s.maxCount) != 0) && (s.currentCount > s.maxCount));
65
67
 
66
- console.log(invalidMinServices);
67
-
68
68
  if (invalidMinServices.length > 0 || invalidMaxServices.length > 0) {
69
69
  result = false;
70
70
 
@@ -92,7 +92,7 @@ class ApplicationInstance extends React.Component {
92
92
 
93
93
  componentDidMount() {
94
94
  const {
95
- data: { mode, appDefinition, hosts, ansibleVarsAll, appDefinitionUrl },
95
+ data: { mode, appDefinition, hosts, ansibleVarsAll, appDefinitionUrl, supportedPlugins },
96
96
  initApplicationInstance,
97
97
  addApplicationInstanceHost,
98
98
  deleteApplicationInstanceHost,
@@ -107,29 +107,36 @@ class ApplicationInstance extends React.Component {
107
107
  loadApplicationDefinition(appDefinition.id, { url: appDefinitionUrl });
108
108
  }
109
109
 
110
+ const already_deployed_msg = __("This is an already deployed host. Changing the parameters is not possible!");
111
+
110
112
  const inlineEditButtonsFormatter = inlineEditFormatterFactory({
111
113
  isEditing: additionalData => this.props.editMode,
112
114
  renderValue: (value, additionalData) => (
113
115
  <td style={{ padding: '2px' }}>
116
+ { additionalData.rowData.isExistingHost == true ? (
117
+ <Icon style={{marginRight: 8, marginLeft: 2}} type="pf" name="info" title={already_deployed_msg} />
118
+ ) : (<span></span>)}
114
119
  <Button
115
120
  bsStyle="default"
116
121
  onClick={() => activateEditApplicationInstanceHost(additionalData)}
117
122
  >
118
- <Icon type="pf" name="edit" title={__("edit entry")} />
123
+ <Icon type="pf" name="edit" title={__("Edit entry")} />
119
124
  </Button>
120
125
  &nbsp;
121
- <Button
122
- bsStyle="default"
123
- onClick={() => openForemanParameterSelectionModal(additionalData)}
124
- >
125
- <Icon type="pf" name="settings" title={__("change parameters")} />
126
- </Button>
126
+ { additionalData.rowData.isExistingHost == false ? (
127
+ <Button
128
+ bsStyle="default"
129
+ onClick={() => openForemanParameterSelectionModal(additionalData)}
130
+ >
131
+ <Icon type="pf" name="settings" title={__("Change parameters")} />
132
+ </Button>
133
+ ) : (<span></span>)}
127
134
  &nbsp;
128
135
  <Button
129
136
  bsStyle="default"
130
137
  onClick={() => openAnsibleParameterSelectionModal(additionalData)}
131
138
  >
132
- <span title={__("change ansible variables")}>A</span>
139
+ <span title={__("Change ansible variables")}>A</span>
133
140
  </Button>
134
141
  &nbsp;
135
142
  <DeleteTableEntry
@@ -142,13 +149,18 @@ class ApplicationInstance extends React.Component {
142
149
  ),
143
150
  renderEdit: (value, additionalData) => (
144
151
  <td style={{ padding: '2px' }}>
152
+ { additionalData.rowData.isExistingHost == true ? (
153
+ <Icon style={{marginRight: 8, marginLeft: 2}} type="pf" name="info" title={already_deployed_msg} />
154
+ ) : (<span></span>)}
145
155
  <Button bsStyle="default" disabled>
146
156
  <Icon type="pf" name={__("edit")} />
147
157
  </Button>
148
158
  &nbsp;
149
- <Button bsStyle="default" disabled>
150
- <Icon type="pf" name={__("settings")} />
151
- </Button>
159
+ { additionalData.rowData.isExistingHost == false ? (
160
+ <Button bsStyle="default" disabled>
161
+ <Icon type="pf" name={__("settings")} />
162
+ </Button>
163
+ ) : (<span></span>)}
152
164
  &nbsp;
153
165
  <Button bsStyle="default" disabled>
154
166
  <span>A</span>
@@ -217,8 +229,8 @@ class ApplicationInstance extends React.Component {
217
229
  prettyValue = serviceList[value];
218
230
  return inlineEditFormatterImpl.renderValue(prettyValue, additionalData)
219
231
  }
220
- if (additionalData.property == 'hostname') {
221
- if (additionalData.rowData.newEntry === true) {
232
+ if (additionalData.property == 'hostname') {
233
+ if (additionalData.rowData.newEntry === true) {
222
234
  return inlineEditFormatterImpl.renderEditText(value, additionalData);
223
235
  }
224
236
  return inlineEditFormatterImpl.renderValue(prettyValue, additionalData)
@@ -232,6 +244,7 @@ class ApplicationInstance extends React.Component {
232
244
  appDefinition,
233
245
  hosts,
234
246
  ansibleVarsAll,
247
+ supportedPlugins,
235
248
  this.headerFormatter,
236
249
  this.inlineEditFormatter,
237
250
  this.inlineEditButtonsFormatter,
@@ -241,16 +254,20 @@ class ApplicationInstance extends React.Component {
241
254
  render() {
242
255
  const {
243
256
  data: { mode, applications, organization, location, foremanDataUrl, appDefinitionUrl },
257
+ showAlertModal, alertModalText, alertModalTitle, closeAlertModal,
244
258
  appDefinition,
245
259
  services,
246
260
  hosts,
247
261
  columns,
262
+ hiddenForemanParameterTypes,
248
263
  addApplicationInstanceHost,
249
264
  confirmEditApplicationInstanceHost,
250
265
  cancelEditApplicationInstanceHost,
251
266
  closeForemanParameterSelectionModal,
252
267
  openAnsibleParameterSelectionModal,
253
268
  closeAnsibleParameterSelectionModal,
269
+ openAddExistingHostsModal,
270
+ closeAddExistingHostsModal,
254
271
  changeParameterSelectionMode,
255
272
  loadApplicationDefinition,
256
273
  } = this.props;
@@ -265,7 +282,17 @@ class ApplicationInstance extends React.Component {
265
282
 
266
283
  return (
267
284
  <span>
268
- <div class="service-counter">
285
+ <MessageDialog
286
+ show={showAlertModal}
287
+ onHide={closeAlertModal}
288
+ primaryAction={closeAlertModal}
289
+ primaryActionButtonContent={__('OK')}
290
+ primaryActionButtonBsStyle={"danger"}
291
+ icon={<Icon type="pf" name="error-circle-o" />}
292
+ title={alertModalTitle}
293
+ primaryContent={alertModalText}
294
+ />
295
+ <div className="service-counter">
269
296
  <ServiceCounter
270
297
  title="Service counts"
271
298
  serviceList={ services }
@@ -275,6 +302,7 @@ class ApplicationInstance extends React.Component {
275
302
  <div>
276
303
  <AppDefinitionSelector
277
304
  label="Application Definition"
305
+ hidden={ false }
278
306
  editable={ mode == 'newInstance' }
279
307
  viewText={ appDefinition.name }
280
308
  options={ applications }
@@ -283,9 +311,9 @@ class ApplicationInstance extends React.Component {
283
311
  additionalData={{url: appDefinitionUrl}}
284
312
  />
285
313
  {appDefinition.id == '' ? (
286
- <p style={{ paddingTop: 25 }}>
314
+ <div style={{ paddingTop: 25 }}>
287
315
  <pre>{ "App Definition can't be blank" }</pre>
288
- </p>
316
+ </div>
289
317
  ) : (<div></div>)}
290
318
  </div>
291
319
  <div className="form-group">
@@ -311,27 +339,38 @@ class ApplicationInstance extends React.Component {
311
339
  role: 'row',
312
340
  isEditing: () => this.isEditing({ rowData }),
313
341
  onCancel: () => cancelEditApplicationInstanceHost({ rowData, rowIndex }),
314
- onConfirm: () => confirmEditApplicationInstanceHost({ rowData, rowIndex }),
342
+ onConfirm: () => confirmEditApplicationInstanceHost({ rowData, rowIndex, appDefinition }),
315
343
  last: rowIndex === services.length - 1
316
344
  })}
317
345
  />
318
346
  </Table.PfProvider>
319
347
  <AddTableEntry
320
348
  hidden={ false }
321
- disabled={ this.addTableEntryAllowed() }
349
+ disabled={ this.changeDataAllowed() }
322
350
  onAddTableEntry={ addApplicationInstanceHost }
323
351
  />
352
+ <span style={{ marginLeft: 10 }}>
353
+ <Button
354
+ bsStyle="default"
355
+ disabled={ this.changeDataAllowed() }
356
+ onClick={() => openAddExistingHostsModal({
357
+ isAllGroup: true
358
+ })}
359
+ >
360
+ <Icon title={__("Add existing hosts")} type="pf" name="server" />
361
+ </Button>
362
+ </span>
324
363
  <span style={{ marginLeft: 30 }}>
325
364
  Ansible group vars 'all':
326
365
  <Button
327
366
  style={{ marginLeft: 10 }}
328
367
  bsStyle="default"
329
- disabled={ this.props.editMode }
368
+ disabled={ this.changeDataAllowed() }
330
369
  onClick={() => openAnsibleParameterSelectionModal({
331
370
  isAllGroup: true
332
371
  })}
333
372
  >
334
- <span title={__("change ansible variables for 'all'")}>A</span>
373
+ <span title={__("Change ansible variables for 'all'")}>A</span>
335
374
  </Button>
336
375
  </span>
337
376
  </div>
@@ -342,12 +381,13 @@ class ApplicationInstance extends React.Component {
342
381
  title={__("Foreman Parameter specification for Application Instance")}
343
382
  >
344
383
  <ForemanModal.Header closeButton={false}>
345
- Parameter specification
384
+ {__("Parameter specification")}
346
385
  </ForemanModal.Header>
347
386
  {this.props.parametersData ? (
348
387
  <ParameterSelection
349
388
  editModeCallback={ (hide) => changeParameterSelectionMode({ mode: hide })}
350
389
  paramType={ PARAMETER_SELECTION_PARAM_TYPE_FOREMAN }
390
+ hiddenParameterTypes={ hiddenForemanParameterTypes }
351
391
  location={ location }
352
392
  organization={ organization }
353
393
  paramDataUrl= { foremanDataUrl }
@@ -370,7 +410,7 @@ class ApplicationInstance extends React.Component {
370
410
  title={__("Ansible group variables for Application Instance")}
371
411
  >
372
412
  <ForemanModal.Header closeButton={false}>
373
- Parameter specification
413
+ {__("Parameter specification")}
374
414
  </ForemanModal.Header>
375
415
  {this.props.parametersData ? (
376
416
  <ParameterSelection
@@ -390,19 +430,42 @@ class ApplicationInstance extends React.Component {
390
430
  </ForemanModal.Footer>
391
431
  </ForemanModal>
392
432
  </div>
433
+ <div>
434
+ <ForemanModal
435
+ id="AppInstanceAddExistingHosts"
436
+ dialogClassName="add_existing_hosts_modal"
437
+ title={__("Add existing hosts to an Application Instance")}
438
+ >
439
+ <ForemanModal.Header closeButton={false}>
440
+ {__("Existing hosts selection")}
441
+ </ForemanModal.Header>
442
+ <ExistingHostSelection
443
+ location={ location }
444
+ organization={ organization }
445
+ services={ services }
446
+ allHosts={ this.props.hosts }
447
+ />
448
+ <ForemanModal.Footer>
449
+ <div>
450
+ <Button bsStyle="primary" disabled={this.props.paramEditMode} onClick={() => closeAddExistingHostsModal({ mode: 'save' })}>{__("Save")}</Button>
451
+ <Button bsStyle="default" disabled={this.props.paramEditMode} onClick={() => closeAddExistingHostsModal({ mode: 'cancel' })}>{__("Cancel")}</Button>
452
+ </div>
453
+ </ForemanModal.Footer>
454
+ </ForemanModal>
455
+ </div>
393
456
  {validateResult == false ? (
394
- <p style={{ paddingTop: 25 }}>
457
+ <div style={{ paddingTop: 25 }}>
395
458
  <pre>{ validateMsg }</pre>
396
- </p>
459
+ </div>
397
460
  ) : (<div></div>)}
398
461
  <RailsData
399
- key='applications_instance'
462
+ key='application_instance_hosts_data'
400
463
  view='app_instance'
401
464
  parameter='hosts'
402
465
  value={JSON.stringify(this.props.hosts)}
403
466
  />
404
467
  <RailsData
405
- key='applications_instance'
468
+ key='application_instance_ansible_data'
406
469
  view='app_instance'
407
470
  parameter='ansible_vars_all'
408
471
  value={JSON.stringify(this.props.ansibleVarsAll)}
@@ -413,6 +476,9 @@ class ApplicationInstance extends React.Component {
413
476
 
414
477
  ApplicationInstance.defaultProps = {
415
478
  error: {},
479
+ showAlertModal: false,
480
+ alertModalText: '',
481
+ alertModalTitle: '',
416
482
  appDefinition: { "id": '', "name": '' },
417
483
  editMode: false,
418
484
  services: [],
@@ -420,18 +486,24 @@ ApplicationInstance.defaultProps = {
420
486
  ansibleVarsAll: [],
421
487
  parametersData: {},
422
488
  columns: [],
489
+ hiddenForemanParameterTypes: [],
423
490
  editParamsOfRowId: null,
424
491
  paramEditMode: false,
425
492
  }
426
493
 
427
494
  ApplicationInstance.propTypes = {
428
495
  initApplicationInstance: PropTypes.func,
496
+ showAlertModal: PropTypes.bool,
497
+ alertModalText: PropTypes.string,
498
+ alertModalTitle: PropTypes.string,
429
499
  editMode: PropTypes.bool.isRequired,
430
500
  services: PropTypes.array,
431
501
  appDefinition: PropTypes.object,
432
502
  columns: PropTypes.array,
503
+ hiddenForemanParameterTypes: PropTypes.array,
433
504
  hosts: PropTypes.array,
434
505
  ansibleVarsAll: PropTypes.array,
506
+ closeAlertModal: PropTypes.func,
435
507
  loadApplicationDefinition: PropTypes.func,
436
508
  addApplicationInstanceHost: PropTypes.func,
437
509
  deleteApplicationInstanceHost: PropTypes.func,
@@ -443,6 +515,8 @@ ApplicationInstance.propTypes = {
443
515
  closeForemanParameterSelectionModal: PropTypes.func,
444
516
  openAnsibleParameterSelectionModal: PropTypes.func,
445
517
  closeAnsibleParameterSelectionModal: PropTypes.func,
518
+ openAddExistingHostsModal: PropTypes.func,
519
+ closeAddExistingHostsModal: PropTypes.func,
446
520
  changeParameterSelectionMode: PropTypes.func,
447
521
  parametersData: PropTypes.object,
448
522
  paramEditMode: PropTypes.bool,
@@ -16,26 +16,35 @@ import {
16
16
 
17
17
  import {
18
18
  APPLICATION_INSTANCE_INIT,
19
+ APPLICATION_INSTANCE_CLOSE_ALERT_MODAL,
19
20
  APPLICATION_INSTANCE_HOST_DELETE,
20
21
  APPLICATION_INSTANCE_HOST_ADD,
21
22
  APPLICATION_INSTANCE_HOST_EDIT_ACTIVATE,
22
23
  APPLICATION_INSTANCE_HOST_EDIT_CONFIRM,
23
24
  APPLICATION_INSTANCE_HOST_EDIT_CHANGE,
24
25
  APPLICATION_INSTANCE_HOST_EDIT_CANCEL,
26
+ APPLICATION_INSTANCE_HOST_EDIT_ERROR,
25
27
  APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_OPEN,
26
28
  APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_CLOSE,
27
29
  APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_OPEN,
28
30
  APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_CLOSE,
31
+ APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_OPEN,
32
+ APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_CLOSE,
29
33
  APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_REQUEST,
30
34
  APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_SUCCESS,
31
35
  APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_FAILURE,
32
36
  APPLICATION_INSTANCE_CHANGE_PARAMETER_SELECTION_MODE,
33
37
  } from './ApplicationInstanceConstants';
34
38
 
39
+ import {
40
+ supportedPluginsToHiddenParameterTypes,
41
+ } from '../../helper';
42
+
35
43
  export const initApplicationInstance = (
36
44
  appDefinition,
37
45
  hosts,
38
46
  ansibleVarsAll,
47
+ supportedPlugins,
39
48
  headerFormatter,
40
49
  inlineEditFormatter,
41
50
  inlineEditButtonsFormatter,
@@ -112,6 +121,7 @@ export const initApplicationInstance = (
112
121
  initialState.appDefinition = appDefinition;
113
122
  initialState.hosts = hosts;
114
123
  initialState.ansibleVarsAll = ansibleVarsAll;
124
+ initialState.hiddenForemanParameterTypes = supportedPluginsToHiddenParameterTypes(supportedPlugins);
115
125
 
116
126
  dispatch({
117
127
  type: APPLICATION_INSTANCE_INIT,
@@ -127,6 +137,11 @@ const errorHandler = (msg, err) => {
127
137
  return { type: msg, payload: { error } };
128
138
  };
129
139
 
140
+ export const closeAlertModal = () => ({
141
+ type: APPLICATION_INSTANCE_CLOSE_ALERT_MODAL,
142
+ payload: {}
143
+ });
144
+
130
145
  export const loadApplicationDefinition = (
131
146
  applicationDefinitionId,
132
147
  additionalData,
@@ -167,12 +182,84 @@ export const activateEditApplicationInstanceHost = (additionalData) => ({
167
182
  },
168
183
  });
169
184
 
170
- export const confirmEditApplicationInstanceHost = (rowData) => ({
171
- type: APPLICATION_INSTANCE_HOST_EDIT_CONFIRM,
172
- payload: {
173
- ...rowData,
174
- },
175
- });
185
+ export const confirmEditApplicationInstanceHost = (
186
+ allData
187
+ ) => async(dispatch) => {
188
+
189
+ // Host name can not be empty
190
+
191
+ if (allData.rowData.hostname == '') {
192
+ dispatch({
193
+ type: APPLICATION_INSTANCE_HOST_EDIT_ERROR,
194
+ payload: __("Every host needs to have a valid name"),
195
+ });
196
+ return;
197
+ }
198
+
199
+ // Host name can only have specific characters
200
+
201
+ const hostname = allData.rowData.hostname.toLowerCase();
202
+ const hostnameRegex = /^[0-9a-z]([0-9a-z\-]{0,61}[0-9a-z])$/;
203
+
204
+ if (hostname.match(hostnameRegex) == undefined) {
205
+ dispatch({
206
+ type: APPLICATION_INSTANCE_HOST_EDIT_ERROR,
207
+ payload: __("The hostname uses not allowed characters. See https://en.wikipedia.org/wiki/Hostname#Syntax for more details."),
208
+ });
209
+ return;
210
+ }
211
+
212
+ // Service can not be empty
213
+
214
+ if (allData.rowData.service == '') {
215
+ dispatch({
216
+ type: APPLICATION_INSTANCE_HOST_EDIT_ERROR,
217
+ payload: __("Every host needs to be assigned to a service."),
218
+ });
219
+ return;
220
+ }
221
+
222
+ // Validation if host name is already used (only for new host entrys)
223
+
224
+ const url = '/acd/ui_acd_validate_hostname'
225
+ const validationData = {};
226
+
227
+ validationData['appDefId'] = allData.appDefinition.id;
228
+ validationData['serviceId'] = allData.rowData.service;
229
+ validationData['hostname'] = allData.rowData.hostname;
230
+
231
+ if (allData.rowData.newEntry === true) {
232
+ try {
233
+ const response = await api.get(url, {}, validationData);
234
+
235
+ if (response.data.result === true) {
236
+ dispatch({
237
+ type: APPLICATION_INSTANCE_HOST_EDIT_CONFIRM,
238
+ payload: {
239
+ ...allData,
240
+ }
241
+ });
242
+ } else {
243
+ dispatch({
244
+ type: APPLICATION_INSTANCE_HOST_EDIT_ERROR,
245
+ payload: __('Hostname \''+ allData.rowData.hostname +'\' is already used. This check also includes hosts outside this application instance.'),
246
+ });
247
+ }
248
+ } catch (error) {
249
+ dispatch({
250
+ type: APPLICATION_INSTANCE_HOST_EDIT_ERROR,
251
+ payload: __('Error during validation if hostname is already used.'),
252
+ });
253
+ }
254
+ } else {
255
+ dispatch({
256
+ type: APPLICATION_INSTANCE_HOST_EDIT_CONFIRM,
257
+ payload: {
258
+ ...allData,
259
+ }
260
+ });
261
+ }
262
+ };
176
263
 
177
264
  export const cancelEditApplicationInstanceHost = (rowData) => ({
178
265
  type: APPLICATION_INSTANCE_HOST_EDIT_CANCEL,
@@ -239,6 +326,31 @@ export const closeAnsibleParameterSelectionModal = (additionalData) => dispatch
239
326
  );
240
327
  }
241
328
 
329
+ export const openAddExistingHostsModal = (additionalData) => dispatch => {
330
+ dispatch({
331
+ type: APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_OPEN,
332
+ payload: {
333
+ ...additionalData,
334
+ }
335
+ });
336
+ dispatch(
337
+ setModalOpen({ id: 'AppInstanceAddExistingHosts' })
338
+ );
339
+ }
340
+
341
+ export const closeAddExistingHostsModal = (additionalData) => dispatch => {
342
+ dispatch({
343
+ type: APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_CLOSE,
344
+ payload: {
345
+ ...additionalData,
346
+ }
347
+ });
348
+
349
+ dispatch(
350
+ setModalClosed({ id: 'AppInstanceAddExistingHosts' })
351
+ );
352
+ }
353
+
242
354
  export const changeParameterSelectionMode = (additionalData) => ({
243
355
  type: APPLICATION_INSTANCE_CHANGE_PARAMETER_SELECTION_MODE,
244
356
  payload: {
@@ -1,4 +1,5 @@
1
1
  export const APPLICATION_INSTANCE_INIT = 'APPLICATION_INSTANCE_INIT';
2
+ export const APPLICATION_INSTANCE_CLOSE_ALERT_MODAL = 'APPLICATION_INSTANCE_CLOSE_ALERT_MODAL';
2
3
  export const APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_REQUEST = 'APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_REQUEST';
3
4
  export const APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_SUCCESS = 'APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_SUCCESS';
4
5
  export const APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_FAILURE = 'APPLICATION_INSTANCE_LOAD_APPLICATION_DEFINITION_FAILURE';
@@ -8,8 +9,11 @@ export const APPLICATION_INSTANCE_HOST_EDIT_ACTIVATE = 'APPLICATION_INSTANCE_HOS
8
9
  export const APPLICATION_INSTANCE_HOST_EDIT_CONFIRM = 'APPLICATION_INSTANCE_HOST_EDIT_CONFIRM';
9
10
  export const APPLICATION_INSTANCE_HOST_EDIT_CHANGE = 'APPLICATION_INSTANCE_HOST_EDIT_CHANGE';
10
11
  export const APPLICATION_INSTANCE_HOST_EDIT_CANCEL = 'APPLICATION_INSTANCE_HOST_EDIT_CANCEL';
12
+ export const APPLICATION_INSTANCE_HOST_EDIT_ERROR = 'APPLICATION_INSTANCE_HOST_EDIT_ERROR';
11
13
  export const APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_OPEN = 'APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_OPEN';
12
14
  export const APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_CLOSE = 'APPLICATION_INSTANCE_FOREMAN_PARAMETER_SELECTION_MODAL_CLOSE';
13
15
  export const APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_OPEN = 'APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_OPEN';
14
16
  export const APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_CLOSE = 'APPLICATION_INSTANCE_ANSIBLE_PARAMETER_SELECTION_MODAL_CLOSE';
17
+ export const APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_OPEN = 'APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_OPEN';
18
+ export const APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_CLOSE = 'APPLICATION_INSTANCE_ADD_EXISTING_HOSTS_MODAL_CLOSE';
15
19
  export const APPLICATION_INSTANCE_CHANGE_PARAMETER_SELECTION_MODE = 'APPLICATION_INSTANCE_CHANGE_PARAMETER_SELECTION_MODE';
@@ -0,0 +1,15 @@
1
+
2
+ function calculateServiceUsage(hostServiceId, services) {
3
+ const service = services.find(serv => serv['id'] == hostServiceId);
4
+ if ('currentCount' in service) {
5
+ service['currentCount'] += 1;
6
+ } else {
7
+ service['currentCount'] = 1;
8
+ }
9
+
10
+ return services;
11
+ }
12
+
13
+ export {
14
+ calculateServiceUsage,
15
+ };