summaryrefslogtreecommitdiff
path: root/src/components/Composables/useRebootBmc.ts
blob: 7f283bbc17b709bbb7238acea30d74a14c0f6ebf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import { useQuery, useMutation, useQueryClient } from '@tanstack/vue-query';
import { computed } from 'vue';
import type { ComputedRef } from 'vue';
import api from '@/store/api';
import { useRedfishRoot } from '@/api/composables/useRedfishRoot';
import { shouldRetry } from '@/api/composables/useAllSubResources';
import type { Manager } from '@/api/types/redfish';

export const rebootBmcQueryKey = ['redfish', 'bmcManager'] as const;

export interface UseRebootBmcReturn {
  lastBmcRebootTime: ComputedRef<Date | null>;
  rebootBmc: () => Promise<void>;
  isBusy: ComputedRef<boolean>;
  isError: ComputedRef<boolean>;
  isLoading: ComputedRef<boolean>;
  isRebootEnabled: ComputedRef<boolean>;
}

export function useRebootBmc(): UseRebootBmcReturn {
  const queryClient = useQueryClient();
  const { data: serviceRoot, isLoading: rootLoading } = useRedfishRoot();

  const managerProvidingServiceUri = computed<string | null>(
    () => serviceRoot.value?.ManagerProvidingService?.['@odata.id'] ?? null,
  );
  const managersCollectionUri = computed<string | null>(
    () => serviceRoot.value?.Managers?.['@odata.id'] ?? null,
  );

  const bmcQuery = useQuery<Manager | null, unknown>({
    queryKey: computed(() => [
      ...rebootBmcQueryKey,
      managerProvidingServiceUri.value ?? managersCollectionUri.value,
    ]),
    queryFn: async ({ signal }) => {
      let managerUri = managerProvidingServiceUri.value;
      if (!managerUri) {
        const collectionUri = managersCollectionUri.value;
        if (!collectionUri) return null;
        const { data: collection } = await api.get<{
          Members?: { '@odata.id': string }[];
        }>(collectionUri, { signal });
        managerUri = collection.Members?.[0]?.['@odata.id'] ?? null;
      }
      if (!managerUri) return null;
      const { data } = await api.get<Manager>(managerUri, { signal });
      return data;
    },
    enabled: computed(
      () => !!managerProvidingServiceUri.value || !!managersCollectionUri.value,
    ),
    staleTime: Infinity,
    gcTime: Infinity,
    refetchOnMount: true,
    refetchOnWindowFocus: false,
    refetchOnReconnect: true,
    retry: shouldRetry,
    retryDelay: (attemptIndex: number) => Math.min(1000 * 2 ** attemptIndex, 30000),
  });

  const mutation = useMutation<void, unknown, void, unknown>({
    mutationFn: async () => {
      const manager = bmcQuery.data.value;
      if (!manager) throw new Error('Manager resource not available');
      const resetTarget =
        manager.Actions?.['#Manager.Reset']?.target ??
        `${manager['@odata.id']}/Actions/Manager.Reset`;
      await api.post(resetTarget, { ResetType: 'GracefulRestart' });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: rebootBmcQueryKey });
    },
  });

  const lastBmcRebootTime = computed<Date | null>(() => {
    const lastReset = bmcQuery.data.value?.LastResetTime;
    return lastReset ? new Date(lastReset) : null;
  });

  const isBusy = computed<boolean>(() => mutation.isPending.value);
  const isError = computed<boolean>(() => bmcQuery.isError.value);
  const isLoading = computed<boolean>(
    () => rootLoading.value || bmcQuery.isLoading.value,
  );
  const isRebootEnabled = computed<boolean>(
    () => !isBusy.value && !isError.value && !!bmcQuery.data.value,
  );

  async function rebootBmc(): Promise<void> {
    await mutation.mutateAsync();
  }

  return {
    lastBmcRebootTime,
    rebootBmc,
    isBusy,
    isError,
    isLoading,
    isRebootEnabled,
  };
}