1import api from '@/store/api';
2import i18n from '@/i18n';
3
4const FirmwareStore = {
5  namespaced: true,
6  state: {
7    bmcFirmware: [],
8    hostFirmware: [],
9    bmcActiveFirmwareId: null,
10    hostActiveFirmwareId: null,
11    applyTime: null,
12    multipartHttpPushUri: null,
13    httpPushUri: null,
14  },
15  getters: {
16    isSingleFileUploadEnabled: (state) => state.hostFirmware.length === 0,
17    activeBmcFirmware: (state) => {
18      return state.bmcFirmware.find(
19        (firmware) => firmware.id === state.bmcActiveFirmwareId,
20      );
21    },
22    activeHostFirmware: (state) => {
23      return state.hostFirmware.find(
24        (firmware) => firmware.id === state.hostActiveFirmwareId,
25      );
26    },
27    backupBmcFirmware: (state) => {
28      return state.bmcFirmware.find(
29        (firmware) => firmware.id !== state.bmcActiveFirmwareId,
30      );
31    },
32    backupHostFirmware: (state) => {
33      return state.hostFirmware.find(
34        (firmware) => firmware.id !== state.hostActiveFirmwareId,
35      );
36    },
37  },
38  mutations: {
39    setActiveBmcFirmwareId: (state, id) => (state.bmcActiveFirmwareId = id),
40    setActiveHostFirmwareId: (state, id) => (state.hostActiveFirmwareId = id),
41    setBmcFirmware: (state, firmware) => (state.bmcFirmware = firmware),
42    setHostFirmware: (state, firmware) => (state.hostFirmware = firmware),
43    setApplyTime: (state, applyTime) => (state.applyTime = applyTime),
44    setHttpPushUri: (state, httpPushUri) => (state.httpPushUri = httpPushUri),
45    setMultipartHttpPushUri: (state, multipartHttpPushUri) =>
46      (state.multipartHttpPushUri = multipartHttpPushUri),
47  },
48  actions: {
49    async getFirmwareInformation({ dispatch }) {
50      dispatch('getActiveHostFirmware');
51      dispatch('getActiveBmcFirmware');
52      return await dispatch('getFirmwareInventory');
53    },
54    async getActiveBmcFirmware({ commit }) {
55      return api
56        .get(`${await this.dispatch('global/getBmcPath')}`)
57        .then(({ data: { Links } }) => {
58          const id = Links?.ActiveSoftwareImage['@odata.id'].split('/').pop();
59          commit('setActiveBmcFirmwareId', id);
60        })
61        .catch((error) => console.log(error));
62    },
63    async getActiveHostFirmware({ commit }) {
64      return api
65        .get(`${await this.dispatch('global/getSystemPath')}/Bios`)
66        .then(({ data: { Links } }) => {
67          const id = Links?.ActiveSoftwareImage['@odata.id'].split('/').pop();
68          commit('setActiveHostFirmwareId', id);
69        })
70        .catch((error) => console.log(error));
71    },
72    async getFirmwareInventory({ commit }) {
73      const inventoryList = await api
74        .get('/redfish/v1/UpdateService/FirmwareInventory')
75        .then(({ data: { Members = [] } = {} }) =>
76          Members.map((item) => api.get(item['@odata.id'])),
77        )
78        .catch((error) => console.log(error));
79      await api
80        .all(inventoryList)
81        .then((response) => {
82          const bmcFirmware = [];
83          const hostFirmware = [];
84          response.forEach(({ data }) => {
85            const firmwareType = data?.RelatedItem?.[0]?.['@odata.id']
86              .split('/')
87              .pop();
88            const item = {
89              version: data?.Version,
90              id: data?.Id,
91              location: data?.['@odata.id'],
92              status: data?.Status?.Health,
93            };
94            if (firmwareType === 'bmc') {
95              bmcFirmware.push(item);
96            } else if (firmwareType === 'Bios') {
97              hostFirmware.push(item);
98            }
99          });
100          commit('setBmcFirmware', bmcFirmware);
101          commit('setHostFirmware', hostFirmware);
102        })
103        .catch((error) => {
104          console.log(error);
105        });
106    },
107    getUpdateServiceSettings({ commit }) {
108      api
109        .get('/redfish/v1/UpdateService')
110        .then(({ data }) => {
111          const applyTime =
112            data.HttpPushUriOptions.HttpPushUriApplyTime.ApplyTime;
113          commit('setApplyTime', applyTime);
114          const httpPushUri = data.HttpPushUri;
115          commit('setHttpPushUri', httpPushUri);
116          const multipartHttpPushUri = data.MultipartHttpPushUri;
117          commit('setMultipartHttpPushUri', multipartHttpPushUri);
118        })
119        .catch((error) => console.log(error));
120    },
121    async uploadFirmware({ state, dispatch }, params) {
122      if (state.multipartHttpPushUri != null) {
123        return dispatch('uploadFirmwareMultipartHttpPush', params);
124      } else if (state.httpPushUri != null) {
125        return dispatch('uploadFirmwareHttpPush', params);
126      } else {
127        console.log('Do not support firmware push update');
128      }
129    },
130    async uploadFirmwareHttpPush({ state }, { image }) {
131      return await api
132        .post(state.httpPushUri, image, {
133          headers: { 'Content-Type': 'application/octet-stream' },
134        })
135        .catch((error) => {
136          console.log(error);
137          throw new Error(
138            i18n.global.t('pageFirmware.toast.errorUpdateFirmware'),
139          );
140        });
141    },
142    async uploadFirmwareMultipartHttpPush({ state }, { image, targets }) {
143      const formData = new FormData();
144      formData.append('UpdateFile', image);
145      let params = {};
146      if (targets != null && targets.length > 0) {
147        params.Targets = targets;
148      } else {
149        // TODO: Should be OK to leave Targets out, remove this clause
150        // when bmcweb is updated
151        params.Targets = [`${await this.dispatch('global/getBmcPath')}`];
152      }
153      formData.append('UpdateParameters', JSON.stringify(params));
154      return await api
155        .post(state.multipartHttpPushUri, formData, {
156          headers: { 'Content-Type': 'multipart/form-data' },
157        })
158        .catch((error) => {
159          console.log(error);
160          throw new Error(
161            i18n.global.t('pageFirmware.toast.errorUpdateFirmware'),
162          );
163        });
164    },
165    async switchBmcFirmwareAndReboot({ getters }) {
166      const backupLocation = getters.backupBmcFirmware.location;
167      const data = {
168        Links: {
169          ActiveSoftwareImage: {
170            '@odata.id': backupLocation,
171          },
172        },
173      };
174      return await api
175        .patch(`${await this.dispatch('global/getBmcPath')}`, data)
176        .catch((error) => {
177          console.log(error);
178          throw new Error(
179            i18n.global.t('pageFirmware.toast.errorSwitchImages'),
180          );
181        });
182    },
183  },
184};
185
186export default FirmwareStore;
187