Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/pci kubernetes show etcd 3 tapc 23 #14143

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,9 @@
"kube_service_cluster_admission_plugins_always_pull_image_explanation": "Erzwingt, dass jeder neue Pod jedes Mal die benötigten Images herunterlädt.",
"kube_service_cluster_admission_plugins_node_restriction_explanation": "Die Verwendung des Plug-Ins für den NodeRestriction-Zugangscontroller schränkt die Node- und POD-Objekte ein, die ein Kubelet ändern kann. Wenn sie durch diesen Zugangscontroller eingeschränkt sind, dürfen Kubelets nur ihr eigenes API-Node-Objekt und nur die API-Pod-Objekte ändern, die an ihren Node gebunden sind.",
"kube_service_cluster_admission_plugins_error": "Beim Zurücksetzen Ihres Clusters ist ein Fehler aufgetreten: {{ message }}",
"kube_service_cluster_admission_plugins_success": "Die Änderung der Plugins wurde registriert."
"kube_service_cluster_admission_plugins_success": "Die Änderung der Plugins wurde registriert.",
"kube_service_cluster_etcd_quota": "Verwendung des ETCD-Quotas",
"kube_service_cluster_etcd_quota_info": "Das ETCD-Quota stellt den der ETCD-Datenbank Ihres verwalteten Clusters zugewiesenen Speicherplatz dar.",
"kube_service_etcd_quota_error": "Dieser Cluster verwendet mehr als 80% des zugewiesenen ETCD-Speicherplatzes.",
"kube_service_etcd_quota_error_link": "Wie verwalte ich meine ETCD-Ressourcen?"
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,9 @@
"kube_service_cluster_admission_plugins_always_pull_image_explanation": "Forces each new pod to download the required images each time.",
"kube_service_cluster_admission_plugins_node_restriction_explanation": "Using the NodeRestriction admission controller plug-in limits the Node and Pod objects that a Kubelet can modify. When throttled by this admission controller, Kubelets are only allowed to modify their own API Node object and only those API Pod objects that are bound to their node.",
"kube_service_cluster_admission_plugins_error": "An error has occurred resetting your cluster: {{ message }}",
"kube_service_cluster_admission_plugins_success": "The Admission Plugins modification has been processed."
"kube_service_cluster_admission_plugins_success": "The Admission Plugins modification has been processed.",
"kube_service_cluster_etcd_quota": "Use of ETCD quota",
"kube_service_cluster_etcd_quota_info": "The ETCD quota represents the space allocated to the ETCD database in your managed cluster.",
"kube_service_etcd_quota_error": "This cluster uses more than 80% of the allocated ETCD space.",
"kube_service_etcd_quota_error_link": "How do I manage my ETCD resources?"
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,9 @@
"kube_service_cluster_admission_plugins_always_pull_image_explanation": "Fuerza cada nuevo pod a descargar las imágenes necesarias cada vez.",
"kube_service_cluster_admission_plugins_node_restriction_explanation": "El uso del plugin del controlador de admisión NodeRestriction limita los objetos Node y Pod que un kubelet puede modificar. Cuando están limitados por este controlador de admisión, los kubelets solo están autorizados a modificar su propio objeto API Node y únicamente los objetos API Pod asociados a sus nodos.",
"kube_service_cluster_admission_plugins_error": "Se ha producido un error al restaurar el cluster: {{ message }}.",
"kube_service_cluster_admission_plugins_success": "La modificación de los Admission Plugins se ha registrado."
"kube_service_cluster_admission_plugins_success": "La modificación de los Admission Plugins se ha registrado.",
"kube_service_cluster_etcd_quota": "Uso de la cuota ETCD",
"kube_service_cluster_etcd_quota_info": "La cuota ETCD representa el espacio asignado a la base de datos ETCD del clúster administrado.",
"kube_service_etcd_quota_error": "Este clúster usa más del 80% del espacio ETCD asignado.",
"kube_service_etcd_quota_error_link": "¿Cómo gestionar mis recursos ETCD?"
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@
"kube_service_cluster_network_vrack_default_gateway": "Passerelle par défaut du vRACK (DHCP)",
"kube_service_cluster_network_vrack_customer_gateway": "Passerelle : {{ vRackGatewayIp }}",
"kubernetes_add_private_network": "Configurer un réseau",

"kube_service_network_edit": "Modifier les paramètres du réseau"
"kube_service_network_edit": "Modifier les paramètres du réseau",
"kube_service_cluster_etcd_quota": "Utilisation du quota ETCD",
"kube_service_cluster_etcd_quota_info": "Le quota ETCD représente l'espace alloué à la base de donnée ETCD de votre cluster managé.",
"kube_service_etcd_quota_error": "Ce cluster utilise plus de 80% de l'espace ETCD attribué.",
"kube_service_etcd_quota_error_link": "Comment gérer mes ressources ETCD ?"
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@
"kube_service_cluster_network_vrack_default_gateway": "Passerelle par défaut du vRACK (DHCP)",
"kube_service_cluster_network_vrack_customer_gateway": "Passerelle : {{ vRackGatewayIp }}",
"kubernetes_add_private_network": "Configurer un réseau",

"kube_service_network_edit": "Modifier les paramètres du réseau"
"kube_service_network_edit": "Modifier les paramètres du réseau",
"kube_service_cluster_etcd_quota": "Utilisation du quota ETCD",
"kube_service_cluster_etcd_quota_info": "Le quota ETCD représente l'espace alloué à la base de donnée ETCD de votre cluster managé.",
"kube_service_etcd_quota_error": "Ce cluster utilise plus de 80% de l'espace ETCD attribué.",
"kube_service_etcd_quota_error_link": "Comment gérer mes ressources ETCD ?"
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"kube_service_cluster_network_subnet": "Sottorete",
"kube_service_cluster_network_lb_subnet": "Sottorete Load Balancer",
"kube_service_cluster_network_error": "Si è verificato un errore durante il caricamento delle informazioni di rete: {{ error }}",
"kube_service_network_edit": "Modificare i parametri della rete",
"kube_service_network_edit": "Modificare le impostazioni di rete",
"kubernetes_add_private_network": "Configurare una rete",
"kube_service_cluster_admission_plugins": "Admission Plugins",
"kube_service_cluster_admission_plugins_mutation": "Attivare/disattivare i plugin",
Expand All @@ -93,5 +93,9 @@
"kube_service_cluster_admission_plugins_always_pull_image_explanation": "Forza ogni nuovo pod a scaricare le immagini necessarie ogni volta.",
"kube_service_cluster_admission_plugins_node_restriction_explanation": "L'utilizzo del plugin del controller di ammissione NodeRestriction limita gli oggetti Node e Pod che un kubelet può modificare. Quando sono limitati da questo controller di ammissione, i kubelet sono autorizzati a modificare solo il proprio oggetto API Node ed esclusivamente gli oggetti API Pod associati al loro nodo.",
"kube_service_cluster_admission_plugins_error": "Si è verificato un errore durante il ripristino del cluster: {{ message }}",
"kube_service_cluster_admission_plugins_success": "La modifica degli Admission Plugins è stata presa in carico."
"kube_service_cluster_admission_plugins_success": "La modifica degli Admission Plugins è stata presa in carico.",
"kube_service_cluster_etcd_quota": "Utilizzo della quota ETCD",
"kube_service_cluster_etcd_quota_info": "La quota ETCD rappresenta lo spazio assegnato al database ETCD del cluster gestito.",
"kube_service_etcd_quota_error": "Questo cluster utilizza oltre l'80% dello spazio ETCD assegnato.",
"kube_service_etcd_quota_error_link": "Come si gestiscono le risorse ETCD?"
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,9 @@
"kube_service_cluster_admission_plugins_always_pull_image_explanation": "Wprowadź regułę, zgodnie z którą każdy nowy pod zawsze pobiera wymagane obrazy.",
"kube_service_cluster_admission_plugins_node_restriction_explanation": "Użycie wtyczki kontrolera dostępu NodeRestriction ogranicza obiekty Node i Pod, które kubelet może modyfikować. Gdy obiekty te są ograniczone przez kontroler dostępu, kublety mogą modyfikować tylko własny obiekt API Node i tylko obiekty API Pod powiązane z ich węzłem.",
"kube_service_cluster_admission_plugins_error": "Wystąpił błąd podczas resetu klastra: {{ message }}.",
"kube_service_cluster_admission_plugins_success": "Dyspozycja modyfikacji Admission Plugins została przyjęta."
"kube_service_cluster_admission_plugins_success": "Dyspozycja modyfikacji Admission Plugins została przyjęta.",
"kube_service_cluster_etcd_quota": "Wykorzystanie limitu ETCD",
"kube_service_cluster_etcd_quota_info": "Rozmiar ETCD to przestrzeń przydzielona do bazy danych ETCD zarządzanego klastra.",
"kube_service_etcd_quota_error": "Ten klaster zużywa ponad 80% przydzielonego miejsca ETCD.",
"kube_service_etcd_quota_error_link": "Jak zarządzać zasobami ETCD?"
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"kube_service_cluster_network_subnet": "Sub-rede",
"kube_service_cluster_network_lb_subnet": "Sub-rede Load Balancer",
"kube_service_cluster_network_error": "Ocorreu um erro ao carregar as informações de rede: {{ error }}",
"kube_service_network_edit": "Modificar os parâmetros da rede",
"kube_service_network_edit": "Modificar as definições da rede",
"kubernetes_add_private_network": "Configurar uma rede",
"kube_service_cluster_admission_plugins": "Admissão Plugins",
"kube_service_cluster_admission_plugins_mutation": "Ativar/desativar os plugins",
Expand All @@ -93,5 +93,9 @@
"kube_service_cluster_admission_plugins_always_pull_image_explanation": "Força cada novo pod a carregar as imagens necessárias a cada vez.",
"kube_service_cluster_admission_plugins_node_restriction_explanation": "A utilização do plug-in do controlador de admissão NodeRestriction limita os objetos Node e Pod que um kubelet pode modificar. Quando restritas por este controlador de admissão, os kubelets só podem modificar o seu próprio objeto API Node e apenas os objetos API Pod que estão ligados ao nó.",
"kube_service_cluster_admission_plugins_error": "Ocorreu um erro ao reiniciar o seu cluster: {{ message }}",
"kube_service_cluster_admission_plugins_success": "A modificação das Admission Plugins foi tomada em conta."
"kube_service_cluster_admission_plugins_success": "A modificação das Admission Plugins foi tomada em conta.",
"kube_service_cluster_etcd_quota": "Utilização da quota ETCD",
"kube_service_cluster_etcd_quota_info": "A quota ETCD representa o espaço atribuído à base de dados ETCD do seu cluster gerido.",
"kube_service_etcd_quota_error": "Este cluster utiliza mais de 80% do espaço ETCD atribuído.",
"kube_service_etcd_quota_error_link": "Como gerir os meus recursos ETCD?"
}
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,10 @@ export async function editNetwork(
}
return Promise.all(todo);
}

export const getKubeEtcdUsage = async (projectId: string, kubeId: string) => {
const { data } = await v6.get(
`/cloud/project/${projectId}/kube/${kubeId}/metrics/etcdUsage`,
);
return data;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { describe, it, vi } from 'vitest';
import * as ApiKubernetesModule from '@/api/data/kubernetes';
import {
useAllKube,
useGetClusterEtcdUsage,
useKubernetesCluster,
useKubes,
useRenameKubernetesCluster,
Expand Down Expand Up @@ -176,3 +177,36 @@ describe('useUpdateKubePolicy', () => {
expect(mockError).not.toHaveBeenCalled();
});
});

describe('useGetClusterEtcdUsage', () => {
afterEach(() => {
vi.clearAllMocks();
vi.restoreAllMocks();
});
it('fetches etcd usage successfully', async () => {
const mockData = { usage: 500, quota: 1024 };
vi.spyOn(ApiKubernetesModule, 'getKubeEtcdUsage').mockResolvedValueOnce(
mockData,
);

const { result } = renderHook(
() => useGetClusterEtcdUsage('project-valid', 'kube1'),
{ wrapper },
);

await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toEqual(mockData);
});

it('handles error when fetching etcd usage', async () => {
vi.spyOn(ApiKubernetesModule, 'getKubeEtcdUsage').mockRejectedValueOnce(
new Error('Network Error'),
);

const { result } = renderHook(
() => useGetClusterEtcdUsage('project-error', 'kube1'),
{ wrapper },
);
await waitFor(() => expect(result.current.isError).toBe(true));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
updateKubernetesCluster,
updateKubeVersion,
updateOidcProvider,
getKubeEtcdUsage,
} from '../data/kubernetes';
import { getPrivateNetworkName } from '../data/network';
import { useAllPrivateNetworks } from './useNetwork';
Expand Down Expand Up @@ -627,3 +628,14 @@ export const useCreateKubernetesCluster = ({
...mutation,
};
};

export const useGetClusterEtcdUsage = (projectId, kubeId) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const useGetClusterEtcdUsage = (projectId, kubeId) => {
export const useClusterEtcdUsage = (projectId, kubeId) => {

const queryKey = ['project', projectId, 'kube', kubeId, 'etcd', 'usage'];
return useQuery({
queryKey,
queryFn: async () => {
const data = await getKubeEtcdUsage(projectId, kubeId);
return data;
},
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
ODS_ICON_NAME,
ODS_ICON_SIZE,
ODS_TEXT_COLOR_INTENT,
ODS_TEXT_LEVEL,
ODS_TEXT_SIZE,
} from '@ovhcloud/ods-components';
import { OsdsText, OsdsIcon } from '@ovhcloud/ods-components/react';

const PopoverTrigger = ({ title }: { title: string }) => (
<span slot="popover-trigger">
<OsdsText
className="mb-4"
size={ODS_TEXT_SIZE._200}
level={ODS_TEXT_LEVEL.heading}
color={ODS_TEXT_COLOR_INTENT.text}
onClick={(event) => event.stopPropagation()}
>
{title}
</OsdsText>
<OsdsIcon
name={ODS_ICON_NAME.HELP}
size={ODS_ICON_SIZE.xs}
className="ml-4 cursor-help"
color={ODS_TEXT_COLOR_INTENT.primary}
/>
</span>
);

export default PopoverTrigger;
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { render, waitFor } from '@testing-library/react';
import * as manager from '@ovh-ux/manager-react-components';
import { vi } from 'vitest';
import { UseQueryResult } from '@tanstack/react-query';
import ClusterEtcd from './ClusterETCD.component';
import { wrapper } from '@/wrapperRenders';
import * as useKubernetesModule from '@/api/hooks/useKubernetes';
import { getColorByPercentage } from '@/helpers';

describe('ClusterEtcd', () => {
it('renders progress bar and usage text correctly', async () => {
const mockUsage = 500;
const mockQuota = 1000;
const mockPercentage = (mockUsage / mockQuota) * 100;

vi.spyOn(useKubernetesModule, 'useGetClusterEtcdUsage').mockReturnValue(({
data: { usage: mockUsage, quota: mockQuota },
isPending: false,
} as unknown) as UseQueryResult<{ usage: number; quota: number }>);

const { getByText, container } = render(<ClusterEtcd />, { wrapper });

await waitFor(() => {
const progressBar = container.querySelector('osds-progress-bar');
const progressBarColor = getColorByPercentage(mockPercentage);

expect(progressBar).toBeInTheDocument();
expect(progressBar?.getAttribute('color')).toBe(progressBarColor);
expect(progressBar?.getAttribute('value')).toBe(
mockPercentage.toString(),
);
expect(
getByText('500 unit_size_B / 1000 unit_size_B'),
).toBeInTheDocument();
});
});

it('applies correct styles based on progress percentage', async () => {
const mockUsage = 700;
const mockQuota = 1000;
const mockPercentage = (mockUsage / mockQuota) * 100;

vi.spyOn(useKubernetesModule, 'useGetClusterEtcdUsage').mockReturnValue(({
data: { usage: mockUsage, quota: mockQuota },
isPending: false,
} as unknown) as UseQueryResult<{ usage: number; quota: number }>);

const { container } = render(<ClusterEtcd />, { wrapper });

await waitFor(() => {
const progressBar = container.querySelector('osds-progress-bar');
const progressBarStyle = getColorByPercentage(mockPercentage);

expect(progressBar).toBeInTheDocument();
expect(progressBar).toHaveProperty('color', progressBarStyle);
});
});

it('renders correct usage and quota information', async () => {
const mockUsage = 300;
const mockQuota = 600;

vi.spyOn(useKubernetesModule, 'useGetClusterEtcdUsage').mockReturnValue(({
data: { usage: mockUsage, quota: mockQuota },
isPending: false,
} as unknown) as UseQueryResult<{ usage: number; quota: number }>);

const { getByText } = render(<ClusterEtcd />, { wrapper });

await waitFor(() => {
expect(
getByText('300 unit_size_B / 600 unit_size_B'),
).toBeInTheDocument();
});
});
it('should call addError only once when percentage is over 80%', async () => {
const mockUsage = 550;
const mockQuota = 600;
const addWarning = vi.fn();
vi.spyOn(manager, 'useNotifications').mockReturnValue({
addWarning,
});

// Mock useGetClusterEtcdUsage to return usage leading to percentage > 80%
vi.spyOn(useKubernetesModule, 'useGetClusterEtcdUsage').mockReturnValue(({
data: { usage: mockUsage, quota: mockQuota },
isPending: false,
} as unknown) as UseQueryResult<{ usage: number; quota: number }>);

// Render the component
render(<ClusterEtcd />);
await waitFor(() => expect(addWarning).toHaveBeenCalledTimes(1));
// Check that addWarning is called only once
});
});
Loading
Loading