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    tftpAvailable: false,
13  },
14  getters: {
15    isTftpUploadAvailable: (state) => state.tftpAvailable,
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    setTftpUploadAvailable: (state, tftpAvailable) =>
45      (state.tftpAvailable = tftpAvailable),
46  },
47  actions: {
48    async getFirmwareInformation({ dispatch }) {
49      dispatch('getActiveHostFirmware');
50      dispatch('getActiveBmcFirmware');
51      return await dispatch('getFirmwareInventory');
52    },
53    getActiveBmcFirmware({ commit }) {
54      return api
55        .get('/redfish/v1/Managers/bmc')
56        .then(({ data: { Links } }) => {
57          const id = Links?.ActiveSoftwareImage['@odata.id'].split('/').pop();
58          commit('setActiveBmcFirmwareId', id);
59        })
60        .catch((error) => console.log(error));
61    },
62    getActiveHostFirmware({ commit }) {
63      return api
64        .get('/redfish/v1/Systems/system/Bios')
65        .then(({ data: { Links } }) => {
66          const id = Links?.ActiveSoftwareImage['@odata.id'].split('/').pop();
67          commit('setActiveHostFirmwareId', id);
68        })
69        .catch((error) => console.log(error));
70    },
71    async getFirmwareInventory({ commit }) {
72      const inventoryList = await api
73        .get('/redfish/v1/UpdateService/FirmwareInventory')
74        .then(({ data: { Members = [] } = {} }) =>
75          Members.map((item) => api.get(item['@odata.id']))
76        )
77        .catch((error) => console.log(error));
78      await api
79        .all(inventoryList)
80        .then((response) => {
81          const bmcFirmware = [];
82          const hostFirmware = [];
83          response.forEach(({ data }) => {
84            const firmwareType = data?.RelatedItem?.[0]?.['@odata.id']
85              .split('/')
86              .pop();
87            const item = {
88              version: data?.Version,
89              id: data?.Id,
90              location: data?.['@odata.id'],
91              status: data?.Status?.Health,
92            };
93            if (firmwareType === 'bmc') {
94              bmcFirmware.push(item);
95            } else if (firmwareType === 'Bios') {
96              hostFirmware.push(item);
97            }
98          });
99          commit('setBmcFirmware', bmcFirmware);
100          commit('setHostFirmware', hostFirmware);
101        })
102        .catch((error) => {
103          console.log(error);
104        });
105    },
106    getUpdateServiceSettings({ commit }) {
107      api
108        .get('/redfish/v1/UpdateService')
109        .then(({ data }) => {
110          const applyTime =
111            data.HttpPushUriOptions.HttpPushUriApplyTime.ApplyTime;
112          const allowableActions =
113            data?.Actions?.['#UpdateService.SimpleUpdate']?.[
114              'TransferProtocol@Redfish.AllowableValues'
115            ];
116
117          commit('setApplyTime', applyTime);
118          if (allowableActions?.includes('TFTP')) {
119            commit('setTftpUploadAvailable', true);
120          }
121        })
122        .catch((error) => console.log(error));
123    },
124    setApplyTimeImmediate({ commit }) {
125      const data = {
126        HttpPushUriOptions: {
127          HttpPushUriApplyTime: {
128            ApplyTime: 'Immediate',
129          },
130        },
131      };
132      return api
133        .patch('/redfish/v1/UpdateService', data)
134        .then(() => commit('setApplyTime', 'Immediate'))
135        .catch((error) => console.log(error));
136    },
137    async uploadFirmware({ state, dispatch }, image) {
138      if (state.applyTime !== 'Immediate') {
139        // ApplyTime must be set to Immediate before making
140        // request to update firmware
141        await dispatch('setApplyTimeImmediate');
142      }
143      return await api
144        .post('/redfish/v1/UpdateService', image, {
145          headers: { 'Content-Type': 'application/octet-stream' },
146        })
147        .catch((error) => {
148          console.log(error);
149          throw new Error(i18n.t('pageFirmware.toast.errorUpdateFirmware'));
150        });
151    },
152    async uploadFirmwareTFTP({ state, dispatch }, fileAddress) {
153      const data = {
154        TransferProtocol: 'TFTP',
155        ImageURI: fileAddress,
156      };
157      if (state.applyTime !== 'Immediate') {
158        // ApplyTime must be set to Immediate before making
159        // request to update firmware
160        await dispatch('setApplyTimeImmediate');
161      }
162      return await api
163        .post(
164          '/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate',
165          data
166        )
167        .catch((error) => {
168          console.log(error);
169          throw new Error(i18n.t('pageFirmware.toast.errorUpdateFirmware'));
170        });
171    },
172    async switchBmcFirmwareAndReboot({ getters }) {
173      const backupLocation = getters.backupBmcFirmware.location;
174      const data = {
175        Links: {
176          ActiveSoftwareImage: {
177            '@odata.id': backupLocation,
178          },
179        },
180      };
181      return await api
182        .patch('/redfish/v1/Managers/bmc', data)
183        .catch((error) => {
184          console.log(error);
185          throw new Error(i18n.t('pageFirmware.toast.errorSwitchImages'));
186        });
187    },
188  },
189};
190
191export default FirmwareStore;
192