foreman_acd 0.0.6 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/foreman_acd/api/v2/app_definitions_controller.rb +1 -2
  3. data/app/controllers/foreman_acd/app_definitions_controller.rb +29 -1
  4. data/app/controllers/foreman_acd/app_instances_controller.rb +70 -21
  5. data/app/controllers/foreman_acd/concerns/app_definition_parameters.rb +1 -1
  6. data/app/controllers/foreman_acd/concerns/app_instance_parameters.rb +1 -1
  7. data/app/controllers/ui_acd_controller.rb +0 -1
  8. data/app/models/foreman_acd/app_definition.rb +0 -1
  9. data/app/views/foreman_acd/app_definitions/_form.html.erb +6 -14
  10. data/app/views/foreman_acd/app_definitions/import.html.erb +18 -0
  11. data/app/views/foreman_acd/app_definitions/index.html.erb +9 -5
  12. data/app/views/foreman_acd/app_instances/_form.html.erb +5 -5
  13. data/app/views/foreman_acd/app_instances/deploy.html.erb +19 -0
  14. data/app/views/foreman_acd/app_instances/index.html.erb +6 -5
  15. data/app/views/foreman_acd/app_instances/report.html.erb +19 -0
  16. data/app/views/ui_acd/app_definition.json.rabl +1 -1
  17. data/config/routes.rb +7 -0
  18. data/db/migrate/20190610202252_create_app_definitions.rb +1 -3
  19. data/db/migrate/20190625140305_create_app_instances.rb +1 -1
  20. data/lib/foreman_acd/plugin.rb +19 -2
  21. data/lib/foreman_acd/version.rb +1 -1
  22. data/webpack/components/ApplicationDefinition/ApplicationDefinition.js +261 -0
  23. data/webpack/components/ApplicationDefinition/ApplicationDefinition.scss +1 -0
  24. data/webpack/components/ApplicationDefinition/ApplicationDefinitionActions.js +211 -0
  25. data/webpack/components/ApplicationDefinition/ApplicationDefinitionConstants.js +9 -0
  26. data/webpack/components/ApplicationDefinition/ApplicationDefinitionReducer.js +147 -0
  27. data/webpack/components/ApplicationDefinition/ApplicationDefinitionSelectors.js +6 -0
  28. data/webpack/components/ApplicationDefinition/index.js +29 -0
  29. data/webpack/components/ApplicationInstance/ApplicationInstance.js +342 -0
  30. data/webpack/components/ApplicationInstance/ApplicationInstance.scss +11 -0
  31. data/webpack/components/ApplicationInstance/ApplicationInstanceActions.js +210 -0
  32. data/webpack/components/ApplicationInstance/ApplicationInstanceConstants.js +12 -0
  33. data/webpack/components/ApplicationInstance/ApplicationInstanceReducer.js +223 -0
  34. data/webpack/components/ApplicationInstance/ApplicationInstanceSelectors.js +8 -0
  35. data/webpack/components/ApplicationInstance/components/AppDefinitionSelector.js +49 -0
  36. data/webpack/components/ApplicationInstance/components/Service.js +30 -0
  37. data/webpack/components/ApplicationInstance/components/ServiceCounter.js +37 -0
  38. data/webpack/components/ApplicationInstance/index.js +33 -0
  39. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.js +155 -0
  40. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.scss +27 -0
  41. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportActions.js +86 -0
  42. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportConstants.js +4 -0
  43. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportReducer.js +52 -0
  44. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportSelectors.js +5 -0
  45. data/webpack/components/ApplicationInstanceReport/components/ReportViewer.js +26 -0
  46. data/webpack/components/ApplicationInstanceReport/index.js +27 -0
  47. data/webpack/components/ParameterSelection/ParameterSelection.js +65 -161
  48. data/webpack/components/ParameterSelection/ParameterSelection.scss +9 -0
  49. data/webpack/components/ParameterSelection/ParameterSelectionActions.js +42 -71
  50. data/webpack/components/ParameterSelection/ParameterSelectionConstants.js +12 -19
  51. data/webpack/components/ParameterSelection/ParameterSelectionHelper.js +3 -3
  52. data/webpack/components/ParameterSelection/ParameterSelectionReducer.js +76 -75
  53. data/webpack/components/ParameterSelection/ParameterSelectionSelectors.js +2 -6
  54. data/webpack/components/ParameterSelection/__fixtures__/parameterSelection.fixtures.js +12 -21
  55. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionData_1.fixtures.js +1 -1
  56. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionReducer.fixtures.js +3 -45
  57. data/webpack/components/ParameterSelection/__tests__/ParameterSelection.test.js +20 -0
  58. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionReducer.test.js +22 -46
  59. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionSelectors.test.js +6 -6
  60. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelection.test.js.snap +40 -265
  61. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionReducer.test.js.snap +11 -96
  62. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionSelectors.test.js.snap +3 -9
  63. data/webpack/components/ParameterSelection/index.js +4 -6
  64. data/webpack/components/common/AddTableEntry.js +30 -0
  65. data/webpack/components/common/DeleteTableEntry.js +39 -0
  66. data/webpack/components/common/ExtSelect.js +43 -0
  67. data/webpack/components/common/RailsData.js +27 -0
  68. data/webpack/components/common/__tests__/AddTableEntry.test.js +26 -0
  69. data/webpack/components/common/__tests__/DeleteTableEntry.test.js +29 -0
  70. data/webpack/components/common/__tests__/ExtSelect.test.js +38 -0
  71. data/webpack/components/common/__tests__/RailsData.test.js +16 -0
  72. data/webpack/components/common/__tests__/__snapshots__/AddParameter.test.js.snap +35 -0
  73. data/webpack/components/common/__tests__/__snapshots__/AddTableEntry.test.js.snap +35 -0
  74. data/webpack/components/common/__tests__/__snapshots__/DeleteParameter.test.js.snap +41 -0
  75. data/webpack/components/common/__tests__/__snapshots__/DeleteTableEntry.test.js.snap +41 -0
  76. data/webpack/components/common/__tests__/__snapshots__/ExtSelect.test.js.snap +18 -0
  77. data/webpack/components/common/__tests__/__snapshots__/RailsData.test.js.snap +10 -0
  78. data/webpack/helper.js +20 -0
  79. data/webpack/index.js +6 -0
  80. data/webpack/reducer.js +40 -3
  81. metadata +47 -46
@@ -0,0 +1,8 @@
1
+ const applicationInstanceConf = state => state.foremanAcd.applicationInstanceConf;
2
+
3
+ export const selectEditMode = state => applicationInstanceConf(state).editMode;
4
+ export const selectAppDefinition = state => applicationInstanceConf(state).appDefinition;
5
+ export const selectHosts = state => applicationInstanceConf(state).hosts;
6
+ export const selectColumns = state => applicationInstanceConf(state).columns;
7
+ export const selectParametersData = state => applicationInstanceConf(state).parametersData;
8
+ export const selectServices = state => applicationInstanceConf(state).services;
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import ExtSelect from '../../common/ExtSelect';
4
+ import RailsData from '../../common/RailsData'
5
+
6
+ const AppDefinitionSelector= ({
7
+ label,
8
+ hidden,
9
+ editable,
10
+ viewText,
11
+ selectValue,
12
+ onChange,
13
+ options,
14
+ additionalData,
15
+ }) =>{
16
+ return (
17
+ <div className="form-group">
18
+ <label className="col-md-2 control-label">{label}</label>
19
+ <div className="col-md-4">
20
+ <ExtSelect
21
+ editable={editable}
22
+ viewText={viewText}
23
+ selectValue={selectValue}
24
+ onChange={onChange}
25
+ options={options}
26
+ additionalData={additionalData}
27
+ />
28
+ <RailsData
29
+ key='app_instance_id'
30
+ view='app_instance'
31
+ parameter='app_definition_id'
32
+ value={selectValue}
33
+ />
34
+ </div>
35
+ </div>
36
+ );
37
+ };
38
+
39
+ AppDefinitionSelector.propTypes = {
40
+ label: PropTypes.string.isRequired,
41
+ editable: PropTypes.bool.isRequired,
42
+ viewText: PropTypes.string,
43
+ selectValue: PropTypes.string,
44
+ onChange: PropTypes.func.isRequired,
45
+ options: PropTypes.object,
46
+ additionalData: PropTypes.object,
47
+ };
48
+
49
+ export default AppDefinitionSelector;
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ const Service= ({
5
+ name,
6
+ currentCount,
7
+ minCount,
8
+ maxCount,
9
+ }) =>{
10
+ return (
11
+ <div>
12
+ <label>{name}:</label> {currentCount} (Min/Max: {minCount}/{maxCount})
13
+ </div>
14
+ );
15
+ };
16
+
17
+ Service.defaultProps = {
18
+ minCount: 0,
19
+ maxCount: 0,
20
+ currentCount: 0,
21
+ };
22
+
23
+ Service.propTypes = {
24
+ name: PropTypes.string.isRequired,
25
+ minCount: PropTypes.number.isRequired,
26
+ maxCount: PropTypes.number.isRequired,
27
+ currentCount: PropTypes.number.isRequired,
28
+ };
29
+
30
+ export default Service;
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Service from './Service';
4
+ import { arrayToObjectObj } from '../../../helper';
5
+ import { cloneDeep } from 'lodash';
6
+
7
+ const ServiceCounter= ({
8
+ title,
9
+ serviceList,
10
+ }) =>{
11
+ if (serviceList == undefined || serviceList.length == 0) {
12
+ return null;
13
+ }
14
+ const services = cloneDeep(arrayToObjectObj(serviceList, "id"));
15
+
16
+ return (
17
+ <div>
18
+ <label class="service-counter-title">{title}</label>
19
+ {Object.keys(services).map(key => (
20
+ <Service
21
+ key={services[key].id}
22
+ name={services[key].name}
23
+ currentCount={services[key].currentCount}
24
+ minCount={Number(services[key].minCount)}
25
+ maxCount={Number(services[key].maxCount)}
26
+ />)
27
+ )}
28
+ </div>
29
+ );
30
+ };
31
+
32
+ ServiceCounter.propTypes = {
33
+ title: PropTypes.string.isRequired,
34
+ serviceList: PropTypes.array,
35
+ };
36
+
37
+ export default ServiceCounter;
@@ -0,0 +1,33 @@
1
+ import { bindActionCreators } from 'redux';
2
+ import { connect } from 'react-redux';
3
+
4
+ import './ApplicationInstance.scss';
5
+ import ApplicationInstance from './ApplicationInstance';
6
+ import * as ApplicationInstanceActions from './ApplicationInstanceActions';
7
+
8
+ import {
9
+ selectEditMode,
10
+ selectAppDefinition,
11
+ selectHosts,
12
+ selectServices,
13
+ selectColumns,
14
+ selectParametersData,
15
+ } from './ApplicationInstanceSelectors';
16
+
17
+ const mapStateToProps = state => ({
18
+ editMode: selectEditMode(state),
19
+ appDefinition: selectAppDefinition(state),
20
+ hosts: selectHosts(state),
21
+ services: selectServices(state),
22
+ columns: selectColumns(state),
23
+ parametersData: selectParametersData(state),
24
+ });
25
+
26
+ const mapDispatchToProps = dispatch =>
27
+ bindActionCreators(ApplicationInstanceActions, dispatch);
28
+
29
+ export default connect(
30
+ mapStateToProps,
31
+ mapDispatchToProps
32
+ )(ApplicationInstance);
33
+
@@ -0,0 +1,155 @@
1
+ import React, { useState } from 'react'
2
+ import PropTypes from 'prop-types';
3
+
4
+ import {
5
+ VerticalTabs,
6
+ } from 'patternfly-react-extensions';
7
+
8
+ import PowerStatus from 'foremanReact/components/hosts/powerStatus';
9
+ import ReportViewer from './components/ReportViewer';
10
+
11
+ class ApplicationInstanceReport extends React.Component {
12
+
13
+ constructor(props) {
14
+ super(props);
15
+ }
16
+
17
+ componentDidMount() {
18
+ const {
19
+ data: { hosts, mode },
20
+ initApplicationInstanceReport,
21
+ setActiveAndLoadLiveReport,
22
+ } = this.props;
23
+
24
+ initApplicationInstanceReport(hosts);
25
+
26
+ if (mode == 'liveReport') {
27
+ if (hosts.length > 0) {
28
+ const index = 0;
29
+ const url = `/api/v2/orchestration/${hosts[index].progress_report_id}/tasks`;
30
+ setActiveAndLoadLiveReport(index, url);
31
+ }
32
+ }
33
+ };
34
+
35
+ isActive(id) {
36
+ return (this.props.activeHostId === id);
37
+ }
38
+
39
+ collectLiveData(hosts) {
40
+ const {
41
+ setActiveAndLoadLiveReport,
42
+ } = this.props;
43
+ const tabs = []
44
+
45
+ for (const [index, value] of hosts.entries()) {
46
+ const url = `/api/v2/orchestration/${hosts[index].progress_report_id}/tasks`
47
+
48
+ tabs.push(
49
+ <VerticalTabs.Tab
50
+ id={index}
51
+ key={"vt_tab_"+index}
52
+ title={ value.name }
53
+ wrapStyle='nowrap'
54
+ onActivate={() => setActiveAndLoadLiveReport(index, url)}
55
+ active={this.isActive(index)}
56
+ />
57
+ );
58
+ }
59
+
60
+ return tabs;
61
+ }
62
+
63
+ collectLastReportData(hosts) {
64
+ const {
65
+ setActiveAndLoadLastReport,
66
+ } = this.props;
67
+ // FIXME
68
+ const url = undefined;
69
+
70
+ const tabs = []
71
+ for (const [index, value] of hosts.entries()) {
72
+ tabs.push(
73
+ <VerticalTabs.Tab
74
+ id={index}
75
+ key={"vt_tab_"+index}
76
+ title={ value.name }
77
+ wrapStyle='nowrap'
78
+ onActivate={() => setActiveAndLoadLastReport(index, url)}
79
+ active={this.isActive(index)}
80
+ />
81
+ );
82
+ }
83
+
84
+ return tabs;
85
+ }
86
+
87
+ liveReportStatus(host) {
88
+ return (
89
+ <span>Host: <a href={ host['hostUrl'] }>{ host['hostname'] }</a></span>
90
+ );
91
+ }
92
+
93
+ lastReportStatus(host) {
94
+ return (
95
+ <div>
96
+ <span>Host: <a href={ host['hostUrl'] }>{ host['hostname'] }</a></span>
97
+ <span>&nbsp;|&nbsp;</span>
98
+ <span>Power Status: <PowerStatus data={{ id: host['id'], url: host['powerStatusUrl'] }} /></span>
99
+ </div>
100
+ )
101
+ }
102
+
103
+ render() {
104
+ const {
105
+ data: { hosts, mode },
106
+ report,
107
+ activeHostId,
108
+ } = this.props;
109
+
110
+ let tabs = [];
111
+ let reportStatus = undefined;
112
+
113
+ if (mode == 'liveReport') {
114
+ tabs = this.collectLiveData(hosts);
115
+ reportStatus = this.liveReportStatus(hosts[activeHostId])
116
+ } else if (mode == 'lastReport') {
117
+ tabs = this.collectLastReportData(hosts);
118
+ reportStatus = this.lastReportStatus(hosts[activeHostId])
119
+ }
120
+
121
+ return (
122
+ <span>
123
+ <div className="deploy_report_hosts">
124
+ <VerticalTabs id="vertical_tabs">
125
+ {tabs}
126
+ </VerticalTabs>
127
+ </div>
128
+ <div className="deploy_report_status">
129
+ {reportStatus}
130
+ </div>
131
+ <div className="deploy_report_tasks">
132
+ <ReportViewer report={report} />
133
+ </div>
134
+ </span>
135
+ )};
136
+ }
137
+
138
+ ApplicationInstanceReport.defaultProps = {
139
+ error: {},
140
+ hosts: [],
141
+ report: [],
142
+ activeHostId: 0,
143
+ }
144
+
145
+ ApplicationInstanceReport.propTypes = {
146
+ initApplicationInstanceReport: PropTypes.func,
147
+ hosts: PropTypes.array,
148
+ report: PropTypes.array,
149
+ setActiveAndLoadLiveReport: PropTypes.func,
150
+ setActiveAndLoadLastReport: PropTypes.func,
151
+ activeHostId: PropTypes.number,
152
+
153
+ };
154
+
155
+ export default ApplicationInstanceReport;
@@ -0,0 +1,27 @@
1
+ @import '~@theforeman/vendor/scss/variables';
2
+
3
+ .deploy_report_hosts {
4
+ float:left;
5
+ width:25%;
6
+ height:100%;
7
+ }
8
+
9
+ .deploy_report_tasks {
10
+ float:left;
11
+ width:75%;
12
+ min-height: 300px;
13
+ background-color: #ecf9fe;
14
+ border: 1px solid #3dbff3;
15
+ }
16
+
17
+ ul.vertical-tabs-pf {
18
+ list-style-type: none;
19
+ }
20
+
21
+ .vertical-tabs-pf-tab.active {
22
+ background-color: $dropdown-link-hover-bg;
23
+ }
24
+
25
+ .vertical-tabs-pf-tab {
26
+ background-color: white;
27
+ }
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import api from 'foremanReact/API';
3
+
4
+ import {
5
+ actionHeaderCellFormatter,
6
+ } from 'patternfly-react';
7
+
8
+ import {
9
+ propsToSnakeCase,
10
+ propsToCamelCase,
11
+ } from 'foremanReact/common/helpers';
12
+
13
+ import {
14
+ APPLICATION_INSTANCE_DEPLOY_INIT,
15
+ APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_REQUEST,
16
+ APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_SUCCESS,
17
+ APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_FAILURE,
18
+ } from './ApplicationInstanceReportConstants';
19
+
20
+ export const initApplicationInstanceReport = (
21
+ hosts,
22
+ ) => dispatch => {
23
+ const initialState = {};
24
+
25
+ initialState.hosts = hosts;
26
+
27
+ dispatch({
28
+ type: APPLICATION_INSTANCE_DEPLOY_INIT,
29
+ payload: initialState,
30
+ });
31
+ };
32
+
33
+ const errorHandler = (msg, err) => {
34
+ const error = {
35
+ errorMsg: 'Failed to fetch data from server.',
36
+ statusText: err,
37
+ };
38
+ return { type: msg, payload: { error } };
39
+ };
40
+
41
+ export const loadReport = (dispatch, getState, id, url, live, initial) => {
42
+
43
+ const reportState = getState().foremanAcd.applicationInstanceReport;
44
+
45
+ if (live) {
46
+ if ((reportState.activeHostId == id) || (initial == true)) {
47
+ setTimeout(() => {
48
+ loadReport(dispatch, getState, id, url, live, false);
49
+ }, 1600)
50
+ }
51
+ }
52
+
53
+ return api
54
+ .get(url, {}, {})
55
+ .then(({ data }) =>
56
+ dispatch({
57
+ type: APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_SUCCESS,
58
+ payload: data.results,
59
+ })
60
+ )
61
+ .catch(error => dispatch(errorHandler(APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_FAILURE, error)));
62
+ };
63
+
64
+ export const setActiveAndLoadLiveReport = (
65
+ id,
66
+ url,
67
+ ) => (dispatch, getState) => {
68
+ dispatch({
69
+ payload: { activeHostId: id },
70
+ type: APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_REQUEST
71
+ });
72
+
73
+ return loadReport(dispatch, getState, id, url, true, true);
74
+ }
75
+
76
+ export const setActiveAndLoadLastReport = (
77
+ id,
78
+ url,
79
+ ) => (dispatch, getState) => {
80
+ dispatch({
81
+ payload: { activeHostId: id },
82
+ type: APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_REQUEST
83
+ });
84
+
85
+ return loadReport(dispatch, getState, id, url, false, true);
86
+ };
@@ -0,0 +1,4 @@
1
+ export const APPLICATION_INSTANCE_DEPLOY_INIT = 'APPLICATION_INSTANCE_DEPLOY_INIT';
2
+ export const APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_REQUEST = 'APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_REQUEST';
3
+ export const APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_SUCCESS = 'APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_SUCCESS';
4
+ export const APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_FAILURE = 'APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_FAILURE';
@@ -0,0 +1,52 @@
1
+ import Immutable from 'seamless-immutable';
2
+
3
+ import {
4
+ cloneDeep,
5
+ findIndex,
6
+ findLastIndex,
7
+ } from 'lodash';
8
+
9
+ import {
10
+ APPLICATION_INSTANCE_DEPLOY_INIT,
11
+ APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_REQUEST,
12
+ APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_SUCCESS,
13
+ APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_FAILURE,
14
+ } from './ApplicationInstanceReportConstants';
15
+
16
+ export const initialState = Immutable({
17
+ name: false,
18
+ error: { errorMsg: '', status: '', statusText: '' },
19
+ });
20
+
21
+ const applicationInstanceReport = (state = initialState, action) => {
22
+ const { payload } = action;
23
+
24
+ switch (action.type) {
25
+ case APPLICATION_INSTANCE_DEPLOY_INIT: {
26
+ return state.merge(payload);
27
+ }
28
+ case APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_REQUEST: {
29
+ return state.merge({
30
+ loading: true,
31
+ activeHostId: payload.activeHostId,
32
+ })
33
+ }
34
+ case APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_SUCCESS: {
35
+ return state.merge({
36
+ report: payload,
37
+ loading: false,
38
+ });
39
+ }
40
+ case APPLICATION_INSTANCE_DEPLOY_LOAD_REPORT_FAILURE: {
41
+ return state.merge({
42
+ error: payload.error,
43
+ loading: false
44
+ });
45
+ }
46
+ default: {
47
+ return state;
48
+ }
49
+ }
50
+ };
51
+
52
+ export default applicationInstanceReport;