foreman_snapshot_management 1.5.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +200 -2
  3. data/Rakefile +9 -2
  4. data/app/controllers/api/v2/snapshots_controller.rb +39 -7
  5. data/app/controllers/concerns/foreman/controller/parameters/snapshot.rb +2 -0
  6. data/app/controllers/foreman_snapshot_management/snapshots_controller.rb +10 -7
  7. data/app/helpers/concerns/foreman_snapshot_management/hosts_helper_extension.rb +2 -0
  8. data/app/helpers/foreman_snapshot_management/snapshot_helper.rb +2 -0
  9. data/app/models/concerns/fog_extensions/proxmox/snapshots/mock.rb +24 -0
  10. data/app/models/concerns/fog_extensions/vsphere/snapshots/mock.rb +2 -0
  11. data/app/models/concerns/fog_extensions/vsphere/snapshots/real.rb +4 -2
  12. data/app/models/foreman_snapshot_management/proxmox_extensions.rb +101 -0
  13. data/app/models/foreman_snapshot_management/snapshot.rb +36 -30
  14. data/app/models/foreman_snapshot_management/vmware_extensions.rb +42 -13
  15. data/app/views/api/v2/snapshots/base.json.rabl +4 -0
  16. data/app/views/api/v2/snapshots/create.json.rabl +2 -0
  17. data/app/views/api/v2/snapshots/destroy.json.rabl +2 -0
  18. data/app/views/api/v2/snapshots/index.json.rabl +2 -0
  19. data/app/views/api/v2/snapshots/main.json.rabl +4 -2
  20. data/app/views/api/v2/snapshots/revert.json.rabl +2 -0
  21. data/app/views/api/v2/snapshots/show.json.rabl +2 -0
  22. data/app/views/api/v2/snapshots/update.json.rabl +2 -0
  23. data/app/views/foreman_snapshot_management/snapshots/_index.html.erb +12 -74
  24. data/app/views/{foreman_snapshot_management/hosts/_snapshots_tab_content.html.erb → hosts/_snapshots_tab.html.erb} +8 -0
  25. data/config/routes.rb +2 -0
  26. data/lib/foreman_snapshot_management.rb +2 -0
  27. data/lib/foreman_snapshot_management/engine.rb +56 -17
  28. data/lib/foreman_snapshot_management/version.rb +3 -1
  29. data/lib/tasks/foreman_snapshot_management_tasks.rake +31 -10
  30. data/locale/de/LC_MESSAGES/foreman_snapshot_management.mo +0 -0
  31. data/locale/de/foreman_snapshot_management.po +195 -0
  32. data/locale/en/LC_MESSAGES/foreman_snapshot_management.mo +0 -0
  33. data/locale/en/foreman_snapshot_management.edit.po +0 -0
  34. data/locale/en/foreman_snapshot_management.po +179 -11
  35. data/locale/foreman_snapshot_management.pot +259 -8
  36. data/locale/gemspec.rb +3 -1
  37. data/package.json +46 -0
  38. data/test/controllers/api/v2/snapshots_test.rb +252 -39
  39. data/test/controllers/foreman_snapshot_management/snapshots_controller_test.rb +63 -9
  40. data/test/factories/proxmox_factory.rb +18 -0
  41. data/test/test_plugin_helper.rb +5 -0
  42. data/webpack/components/SnapshotManagement/SnapshotManagement.js +84 -0
  43. data/webpack/components/SnapshotManagement/SnapshotManagementActions.js +212 -0
  44. data/webpack/components/SnapshotManagement/SnapshotManagementConstants.js +9 -0
  45. data/webpack/components/SnapshotManagement/SnapshotManagementReducer.js +100 -0
  46. data/webpack/components/SnapshotManagement/SnapshotManagementSelectors.js +8 -0
  47. data/webpack/components/SnapshotManagement/__tests__/SnapshotManagementActions.test.js +123 -0
  48. data/webpack/components/SnapshotManagement/__tests__/SnapshotManagementReducer.test.js +157 -0
  49. data/webpack/components/SnapshotManagement/__tests__/__snapshots__/SnapshotManagementActions.test.js.snap +314 -0
  50. data/webpack/components/SnapshotManagement/__tests__/__snapshots__/SnapshotManagementReducer.test.js.snap +214 -0
  51. data/webpack/components/SnapshotManagement/components/SnapshotForm/SnapshotForm.js +118 -0
  52. data/webpack/components/SnapshotManagement/components/SnapshotForm/SnapshotFormConstants.js +5 -0
  53. data/webpack/components/SnapshotManagement/components/SnapshotForm/__tests__/SnapshotForm.test.js +26 -0
  54. data/webpack/components/SnapshotManagement/components/SnapshotForm/__tests__/__snapshots__/SnapshotForm.test.js.snap +476 -0
  55. data/webpack/components/SnapshotManagement/components/SnapshotForm/index.js +19 -0
  56. data/webpack/components/SnapshotManagement/components/SnapshotForm/snapshotForm.scss +3 -0
  57. data/webpack/components/SnapshotManagement/components/SnapshotFormModal/SnapshotFormModal.js +37 -0
  58. data/webpack/components/SnapshotManagement/components/SnapshotFormModal/SnapshotFormModalConstants.js +1 -0
  59. data/webpack/components/SnapshotManagement/components/SnapshotFormModal/__tests__/SnapshotFormModal.test.js +19 -0
  60. data/webpack/components/SnapshotManagement/components/SnapshotFormModal/__tests__/__snapshots__/SnapshotFormModal.test.js.snap +19 -0
  61. data/webpack/components/SnapshotManagement/components/SnapshotFormModal/index.js +12 -0
  62. data/webpack/components/SnapshotManagement/components/SnapshotFormModal/useSnapshotFormModal.js +7 -0
  63. data/webpack/components/SnapshotManagement/components/SnapshotList/SnapshotList.js +314 -0
  64. data/webpack/components/SnapshotManagement/components/SnapshotList/SnapshotListHelper.js +70 -0
  65. data/webpack/components/SnapshotManagement/components/SnapshotList/__tests__/SnapshotList.test.js +88 -0
  66. data/webpack/components/SnapshotManagement/components/SnapshotList/__tests__/__snapshots__/SnapshotList.test.js.snap +1081 -0
  67. data/webpack/components/SnapshotManagement/components/SnapshotList/snapshotList.scss +13 -0
  68. data/webpack/components/SnapshotManagement/index.js +33 -0
  69. data/webpack/components/SnapshotManagement/snapshotManagement.scss +5 -0
  70. data/webpack/global_index.js +7 -0
  71. data/webpack/global_test_setup.js +11 -0
  72. data/webpack/index.js +8 -0
  73. data/webpack/reducers.js +7 -0
  74. data/webpack/test_setup.js +17 -0
  75. metadata +52 -54
  76. data/app/overrides/hosts/add_tab_to_host_overview.rb +0 -11
  77. data/app/views/foreman_snapshot_management/hosts/_snapshots_tab.html.erb +0 -3
@@ -1,37 +1,61 @@
1
- require 'test_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
2
4
 
3
5
  module ForemanSnapshotManagement
4
6
  class SnapshotsControllerTest < ActionController::TestCase
5
- let(:tax_location) { Location.find_by_name('Location 1') }
6
- let(:tax_organization) { Organization.find_by_name('Organization 1') }
7
+ let(:tax_location) { Location.find_by(name: 'Location 1') }
8
+ let(:tax_organization) { Organization.find_by(name: 'Organization 1') }
7
9
  let(:compute_resource) do
8
10
  cr = FactoryBot.create(:compute_resource, :vmware, :uuid => 'Solutions', :locations => [tax_location], organizations: [tax_organization])
9
- ComputeResource.find_by_id(cr.id)
11
+ ComputeResource.find_by(id: cr.id)
10
12
  end
11
13
  let(:uuid) { '5032c8a5-9c5e-ba7a-3804-832a03e16381' }
12
14
  let(:uuid2) { 'a7169e20-74d3-4367-afc2-d355716e7555' }
13
15
  let(:host) { FactoryBot.create(:host, :managed, :compute_resource => compute_resource, :uuid => uuid) }
14
16
  let(:host2) { FactoryBot.create(:host, :managed, :compute_resource => compute_resource, :uuid => uuid2) }
15
17
  let(:snapshot_id) { 'snapshot-0101' }
18
+ let(:proxmox_compute_resource) do
19
+ FactoryBot.create(:proxmox_cr)
20
+ ComputeResource.find_by(type: 'ForemanFogProxmox::Proxmox')
21
+ end
22
+ let(:vmid) { '1_100' }
23
+ let(:proxmox_host) { FactoryBot.create(:host, :managed, :compute_resource => proxmox_compute_resource, :uuid => vmid) }
24
+ let(:proxmox_snapshot) { 'snapshot1' }
16
25
  setup { ::Fog.mock! }
17
26
  teardown { ::Fog.unmock! }
18
27
 
19
28
  context 'GET #index' do
20
- test 'should get index' do
29
+ test 'should get VMware snapshot index' do
21
30
  get :index, params: { :host_id => host.to_param }, session: set_session_user
22
31
  assert_response :success
23
32
  assert_not_nil assigns(:snapshots)
24
33
  assert_template 'foreman_snapshot_management/snapshots/_index'
25
34
  end
35
+
36
+ test 'should get Proxmox index' do
37
+ Host::Managed.any_instance.stubs(:vm_exists?).returns(false)
38
+ get :index, params: { :host_id => proxmox_host.to_param }, session: set_session_user
39
+ assert_response :success
40
+ assert_not_nil assigns(:snapshots)
41
+ assert_template 'foreman_snapshot_management/snapshots/_index'
42
+ end
26
43
  end
27
44
 
28
45
  context 'POST #create' do
29
- test 'create valid' do
46
+ test 'create valid VMware snapshot' do
30
47
  post :create, params: { :host_id => host.to_param, :snapshot => { :name => 'test' } }, session: set_session_user
31
48
  assert_redirected_to host_url(host, :anchor => 'snapshots')
32
49
  assert_includes flash[:notice] || flash[:success], 'Successfully created Snapshot.'
33
50
  end
34
51
 
52
+ test 'create valid proxmox snapshot' do
53
+ Host::Managed.any_instance.stubs(:vm_exists?).returns(false)
54
+ post :create, params: { :host_id => proxmox_host.to_param, :snapshot => { :name => 'test' } }, session: set_session_user
55
+ assert_redirected_to host_url(proxmox_host, :anchor => 'snapshots')
56
+ assert_includes flash[:notice] || flash[:success], 'Successfully created Snapshot.'
57
+ end
58
+
35
59
  test 'create valid multiple' do
36
60
  post :create_multiple_host, params: { :host_ids => [host.id, host2.id], :snapshot => { :name => 'test' } }, session: set_session_user
37
61
  assert_redirected_to hosts_url
@@ -60,6 +84,13 @@ module ForemanSnapshotManagement
60
84
  assert_includes flash[:notice] || flash[:success], 'Successfully deleted Snapshot.'
61
85
  end
62
86
 
87
+ test 'destroy successful' do
88
+ Host::Managed.any_instance.stubs(:vm_exists?).returns(false)
89
+ delete :destroy, params: { :host_id => proxmox_host.to_param, :id => proxmox_snapshot }, session: set_session_user
90
+ assert_redirected_to host_url(proxmox_host, :anchor => 'snapshots')
91
+ assert_includes flash[:notice] || flash[:success], 'Successfully deleted Snapshot.'
92
+ end
93
+
63
94
  test 'destroy with error' do
64
95
  ForemanSnapshotManagement::Snapshot.any_instance.stubs(:destroy).returns(false)
65
96
  delete :destroy, params: { :host_id => host.to_param, :id => snapshot_id }, session: set_session_user
@@ -69,12 +100,19 @@ module ForemanSnapshotManagement
69
100
  end
70
101
 
71
102
  context 'PUT #revert' do
72
- test 'revert successful' do
103
+ test 'revert successful VMware' do
73
104
  put :revert, params: { :host_id => host.to_param, :id => snapshot_id }, session: set_session_user
74
105
  assert_redirected_to host_url(host, :anchor => 'snapshots')
75
106
  assert_includes flash[:notice] || flash[:success], 'VM successfully rolled back.'
76
107
  end
77
108
 
109
+ test 'revert successful proxmox snapshot' do
110
+ Host::Managed.any_instance.stubs(:vm_exists?).returns(false)
111
+ put :revert, params: { :host_id => proxmox_host.to_param, :id => proxmox_snapshot }, session: set_session_user
112
+ assert_redirected_to host_url(proxmox_host, :anchor => 'snapshots')
113
+ assert_includes flash[:notice] || flash[:success], 'VM successfully rolled back.'
114
+ end
115
+
78
116
  test 'revert with error' do
79
117
  ForemanSnapshotManagement::Snapshot.any_instance.stubs(:revert).returns(false)
80
118
  put :revert, params: { :host_id => host.to_param, :id => snapshot_id }, session: set_session_user
@@ -84,7 +122,7 @@ module ForemanSnapshotManagement
84
122
  end
85
123
 
86
124
  context 'PUT #update' do
87
- test 'update successful' do
125
+ test 'update successful VMware snapsoht' do
88
126
  data = { 'name' => 'test 2', 'description' => '' }
89
127
  put :update, params: { :host_id => host.to_param, :id => snapshot_id, :snapshot => data }, session: set_session_user
90
128
  assert_response :success
@@ -92,11 +130,27 @@ module ForemanSnapshotManagement
92
130
  assert_equal(data, body)
93
131
  end
94
132
 
95
- test 'update with error' do
133
+ test 'update successful proxmox' do
134
+ Host::Managed.any_instance.stubs(:vm_exists?).returns(false)
135
+ data = { 'name' => 'snapshot1', 'description' => 'updated snapshot1' }
136
+ put :update, params: { :host_id => proxmox_host.to_param, :id => proxmox_snapshot, :snapshot => data }, session: set_session_user
137
+ assert_response :success
138
+ body = ActiveSupport::JSON.decode(@response.body)
139
+ assert_equal(data, body)
140
+ end
141
+
142
+ test 'update with error VMware snapshot' do
96
143
  ForemanSnapshotManagement::Snapshot.any_instance.stubs(:save).returns(false)
97
144
  put :update, params: { :host_id => host.to_param, :id => snapshot_id, :snapshot => { :name => 'test 2' } }, session: set_session_user
98
145
  assert_response :unprocessable_entity
99
146
  end
147
+
148
+ test 'update with error proxmox snapshot' do
149
+ Host::Managed.any_instance.stubs(:vm_exists?).returns(false)
150
+ ForemanSnapshotManagement::Snapshot.any_instance.stubs(:save).returns(false)
151
+ put :update, params: { :host_id => proxmox_host.to_param, :id => proxmox_snapshot, :snapshot => { :name => 'snapshot1', :description => 'fail' } }, session: set_session_user
152
+ assert_response :unprocessable_entity
153
+ end
100
154
  end
101
155
  end
102
156
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :proxmox_resource, :class => ComputeResource do
5
+ sequence(:name) { |n| "compute_resource_proxmox#{n}" }
6
+ organizations { [Organization.find_by(name: 'Organization 1')] }
7
+ locations { [Location.find_by(name: 'Location 1')] }
8
+
9
+ trait :proxmox do
10
+ provider { 'Proxmox' }
11
+ user { 'root@pam' }
12
+ password { 'proxmox01' }
13
+ url { 'https://192.168.56.101:8006/api2/json' }
14
+ end
15
+
16
+ factory :proxmox_cr, :class => ForemanFogProxmox::Proxmox, :traits => [:proxmox]
17
+ end
18
+ end
@@ -1,2 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This calls the main test_helper in Foreman-core
2
4
  require 'test_helper'
5
+
6
+ FactoryBot.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')
7
+ FactoryBot.reload
@@ -0,0 +1,84 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Button } from 'patternfly-react';
4
+
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+
7
+ import SnapshotFormModal from './components/SnapshotFormModal';
8
+ import useSnapshotFormModal from './components/SnapshotFormModal/useSnapshotFormModal';
9
+ import SnapshotList from './components/SnapshotList/SnapshotList';
10
+ import './snapshotManagement.scss';
11
+
12
+ const SnapshotManagement = ({ canCreate, host, ...props }) => {
13
+ const children = [];
14
+ const { setModalOpen, setModalClosed } = useSnapshotFormModal();
15
+
16
+ const onCreateClick = () => {
17
+ setModalOpen();
18
+ };
19
+ const allowedHostAttr = ['id', 'name'];
20
+ const filteredHost = Object.keys(host)
21
+ .filter(key => allowedHostAttr.includes(key))
22
+ .reduce(
23
+ (obj, key) => ({
24
+ ...obj,
25
+ [key]: host[key],
26
+ }),
27
+ {}
28
+ );
29
+
30
+ if (canCreate) {
31
+ children.push(
32
+ <SnapshotFormModal
33
+ key="snapshot-form-modal"
34
+ setModalClosed={setModalClosed}
35
+ host={filteredHost}
36
+ hostId={host.id}
37
+ {...props}
38
+ />
39
+ );
40
+ children.push(
41
+ <Button
42
+ key="snapshot-create-button"
43
+ onClick={onCreateClick}
44
+ className="snapshot-create"
45
+ >
46
+ {__('Create Snapshot')}
47
+ </Button>
48
+ );
49
+ }
50
+
51
+ children.push(
52
+ <SnapshotList key="snapshot-list" host={filteredHost} {...props} />
53
+ );
54
+
55
+ return <div>{children}</div>;
56
+ };
57
+
58
+ SnapshotManagement.propTypes = {
59
+ host: PropTypes.shape({
60
+ id: PropTypes.number.isRequired,
61
+ name: PropTypes.string.isRequired,
62
+ }).isRequired,
63
+ canCreate: PropTypes.bool,
64
+ canUpdate: PropTypes.bool,
65
+ canRevert: PropTypes.bool,
66
+ canDelete: PropTypes.bool,
67
+ capabilities: PropTypes.shape({
68
+ editSnapshotName: PropTypes.bool,
69
+ limitSnapshotNameFormat: PropTypes.bool,
70
+ }),
71
+ };
72
+
73
+ SnapshotManagement.defaultProps = {
74
+ canCreate: false,
75
+ canUpdate: false,
76
+ canRevert: false,
77
+ canDelete: false,
78
+ capabilities: {
79
+ editSnapshotName: true,
80
+ limitSnapshotNameFormat: false,
81
+ },
82
+ };
83
+
84
+ export default SnapshotManagement;
@@ -0,0 +1,212 @@
1
+ import { API, actionTypeGenerator } from 'foremanReact/redux/API';
2
+ import { sprintf, translate as __ } from 'foremanReact/common/I18n';
3
+ import { addToast } from 'foremanReact/redux/actions/toasts';
4
+
5
+ import {
6
+ SNAPSHOT_LIST,
7
+ SNAPSHOT_LIST_URL,
8
+ SNAPSHOT_DELETE,
9
+ SNAPSHOT_DELETE_URL,
10
+ SNAPSHOT_UPDATE,
11
+ SNAPSHOT_UPDATE_URL,
12
+ SNAPSHOT_ROLLBACK,
13
+ SNAPSHOT_ROLLBACK_URL,
14
+ } from './SnapshotManagementConstants';
15
+
16
+ export const loadSnapshotList = hostId => async dispatch => {
17
+ const { REQUEST, SUCCESS, FAILURE } = actionTypeGenerator(SNAPSHOT_LIST);
18
+
19
+ dispatch({
20
+ type: REQUEST,
21
+ payload: { hostId },
22
+ });
23
+ try {
24
+ const { data } = await API.get(
25
+ SNAPSHOT_LIST_URL.replace(':host_id', hostId)
26
+ );
27
+ return dispatch({
28
+ type: SUCCESS,
29
+ payload: { hostId },
30
+ response: data,
31
+ });
32
+ } catch (error) {
33
+ return dispatch({
34
+ type: FAILURE,
35
+ payload: { hostId },
36
+ response: error,
37
+ });
38
+ }
39
+ };
40
+
41
+ export const snapshotDeleteAction = (host, rowData) => async dispatch => {
42
+ const { REQUEST, SUCCESS, FAILURE } = actionTypeGenerator(SNAPSHOT_DELETE);
43
+
44
+ dispatch({
45
+ type: REQUEST,
46
+ payload: {
47
+ host,
48
+ id: rowData.id,
49
+ },
50
+ });
51
+ try {
52
+ const { data } = await API.delete(
53
+ sprintf(SNAPSHOT_DELETE_URL, host.id, rowData.id)
54
+ );
55
+
56
+ dispatch(
57
+ addToast({
58
+ type: 'success',
59
+ message: sprintf(
60
+ __('Successfully removed Snapshot "%s" from host %s'),
61
+ rowData.name,
62
+ host.name
63
+ ),
64
+ key: SUCCESS,
65
+ })
66
+ );
67
+ dispatch(loadSnapshotList(host.id));
68
+ return dispatch({
69
+ type: SUCCESS,
70
+ payload: {
71
+ host,
72
+ id: rowData.id,
73
+ },
74
+ response: data,
75
+ });
76
+ } catch (error) {
77
+ dispatch(
78
+ addToast({
79
+ type: 'error',
80
+ message: sprintf(
81
+ __('Error occurred while removing Snapshot: %s'),
82
+ error
83
+ ),
84
+ key: FAILURE,
85
+ })
86
+ );
87
+ return dispatch({
88
+ type: FAILURE,
89
+ payload: {
90
+ host,
91
+ id: rowData.id,
92
+ },
93
+ response: error,
94
+ });
95
+ }
96
+ };
97
+
98
+ export const snapshotUpdateAction = (host, rowData) => async dispatch => {
99
+ const { REQUEST, SUCCESS, FAILURE } = actionTypeGenerator(SNAPSHOT_UPDATE);
100
+
101
+ dispatch({
102
+ type: REQUEST,
103
+ payload: {
104
+ host,
105
+ id: rowData.id,
106
+ snapshot: {
107
+ name: rowData.name,
108
+ description: rowData.description,
109
+ },
110
+ },
111
+ });
112
+ try {
113
+ const { data } = await API.put(
114
+ sprintf(SNAPSHOT_UPDATE_URL, host.id, rowData.id),
115
+ {
116
+ snapshot: {
117
+ name: rowData.name,
118
+ description: rowData.description,
119
+ },
120
+ }
121
+ );
122
+ dispatch(
123
+ addToast({
124
+ type: 'success',
125
+ message: sprintf(
126
+ __('Successfully updated Snapshot "%s"'),
127
+ rowData.name
128
+ ),
129
+ key: SUCCESS,
130
+ })
131
+ );
132
+ return dispatch({
133
+ type: SUCCESS,
134
+ payload: {
135
+ host,
136
+ id: rowData.id,
137
+ },
138
+ response: data,
139
+ });
140
+ } catch (error) {
141
+ dispatch(
142
+ addToast({
143
+ type: 'error',
144
+ message: sprintf(
145
+ __('Error occurred while updating Snapshot: %s'),
146
+ error
147
+ ),
148
+ key: FAILURE,
149
+ })
150
+ );
151
+ return dispatch({
152
+ type: FAILURE,
153
+ payload: {
154
+ host,
155
+ id: rowData.id,
156
+ },
157
+ response: error,
158
+ });
159
+ }
160
+ };
161
+
162
+ export const snapshotRollbackAction = (host, rowData) => async dispatch => {
163
+ const { REQUEST, SUCCESS, FAILURE } = actionTypeGenerator(SNAPSHOT_ROLLBACK);
164
+
165
+ dispatch({
166
+ type: REQUEST,
167
+ payload: {
168
+ host,
169
+ id: rowData.id,
170
+ },
171
+ });
172
+ try {
173
+ const { data } = await API.put(
174
+ sprintf(SNAPSHOT_ROLLBACK_URL, host.id, rowData.id)
175
+ );
176
+ dispatch(
177
+ addToast({
178
+ type: 'success',
179
+ message: sprintf(
180
+ __('Successfully rolled back Snapshot "%s" on host %s'),
181
+ rowData.name,
182
+ host.name
183
+ ),
184
+ key: SUCCESS,
185
+ })
186
+ );
187
+ return dispatch({
188
+ type: SUCCESS,
189
+ payload: {
190
+ host,
191
+ id: rowData.id,
192
+ },
193
+ response: data,
194
+ });
195
+ } catch (error) {
196
+ dispatch(
197
+ addToast({
198
+ type: 'error',
199
+ message: sprintf(__('Error occurred while rolling back VM: %s'), error),
200
+ key: FAILURE,
201
+ })
202
+ );
203
+ return dispatch({
204
+ type: FAILURE,
205
+ payload: {
206
+ host,
207
+ id: rowData.id,
208
+ },
209
+ response: error,
210
+ });
211
+ }
212
+ };