Skip to content

Commit

Permalink
feat: Reports warnings on failed kube deploy, fixes error out (contai…
Browse files Browse the repository at this point in the history
…ners#3050)

* feat: Reports warnings on failed kube deploy, fixes error out

### What does this PR do?

* Reports warnings when encountering container errors when using Play
  Kubernetes
* Fixes the error / warning output that was not appearing correctly.

### Screenshot/screencast of this PR

<!-- Please include a screenshot or a screencast explaining what is doing this PR -->

### What issues does this PR fix or reference?

<!-- Please include any related issue from Podman Desktop repository (or from another issue tracker).
-->

Closes containers#2621
Closes containers#3033

### How to test this PR?

<!-- Please explain steps to reproduce -->

Signed-off-by: Charlie Drage <charlie@charliedrage.com>

* add tests

Signed-off-by: Charlie Drage <charlie@charliedrage.com>

* make sure we check to see if containererrors is undefined first

Signed-off-by: Charlie Drage <charlie@charliedrage.com>

---------

Signed-off-by: Charlie Drage <charlie@charliedrage.com>
  • Loading branch information
cdrage authored and mairin committed Jul 7, 2023
1 parent af3b8db commit 23408d2
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 8 deletions.
142 changes: 142 additions & 0 deletions packages/renderer/src/lib/kube/KubePlayYAML.spec.ts
@@ -0,0 +1,142 @@
/**********************************************************************
* Copyright (C) 2023 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
***********************************************************************/

import '@testing-library/jest-dom';
import { test, expect, vi } from 'vitest';
import { providerInfos } from '../../stores/providers';
import { render, screen } from '@testing-library/svelte';
import KubePlayYAML from './KubePlayYAML.svelte';
import type { ProviderStatus } from '@podman-desktop/api';
import type { ProviderContainerConnectionInfo } from '../../../../main/src/plugin/api/provider-info';
import userEvent from '@testing-library/user-event';
import type { PlayKubeInfo } from '../../../../main/src/plugin/dockerode/libpod-dockerode';

const mockedErroredPlayKubeInfo: PlayKubeInfo = {
Pods: [
{
ContainerErrors: ['error 1', 'error 2'],
Containers: ['container 1', 'container 2'],
Id: 'pod-id',
InitContainers: ['init-container 1', 'init-container 2'],
Logs: ['log 1', 'log 2'],
},
],
RmReport: [
{
Err: 'rm error',
Id: 'rm-id',
},
],
Secrets: [
{
CreateReport: {
ID: 'secret-id',
},
},
],
StopReport: [
{
Err: 'stop error',
Id: 'stop-id',
},
],
Volumes: [
{
Name: 'volume 1',
},
{
Name: 'volume 2',
},
],
};

// fake the window.events object
beforeAll(() => {
(window.events as unknown) = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
receive: (_channel: string, func: any) => {
func();
},
};
(window as any).getConfigurationValue = vi.fn();
(window as any).matchMedia = vi.fn().mockReturnValue({
addListener: vi.fn(),
});
(window as any).openFileDialog = vi.fn().mockResolvedValue({ canceled: false, filePaths: ['Containerfile'] });
(window as any).telemetryPage = vi.fn();
(window as any).kubernetesGetCurrentContextName = vi.fn();
(window as any).kubernetesGetCurrentNamespace = vi.fn();
(window as any).kubernetesListNamespaces = vi.fn();
});

function setup() {
const pStatus: ProviderStatus = 'started';
const pInfo: ProviderContainerConnectionInfo = {
name: 'test',
status: 'started',
endpoint: {
socketPath: '',
},
type: 'podman',
};
const providerInfo = {
id: 'test',
internalId: 'id',
name: '',
containerConnections: [pInfo],
kubernetesConnections: undefined,
status: pStatus,
containerProviderConnectionCreation: false,
containerProviderConnectionInitialization: false,
kubernetesProviderConnectionCreation: false,
kubernetesProviderConnectionInitialization: false,
links: undefined,
detectionChecks: undefined,
warnings: undefined,
images: undefined,
installationSupport: undefined,
};
providerInfos.set([providerInfo]);
}

test('error: When pressing the Play button, expect us to show the errors to the user', async () => {
(window as any).playKube = vi.fn().mockResolvedValue(mockedErroredPlayKubeInfo);

// Render the component
setup();
render(KubePlayYAML, {});

// Simulate selecting a file
const fileInput = screen.getByRole('textbox', { name: 'Kubernetes YAML file' });
expect(fileInput).toBeInTheDocument();
await userEvent.click(fileInput);

// Simulate selecting a runtime
const runtimeOption = screen.getByText('Using a Podman container engine');
expect(runtimeOption).toBeInTheDocument();

// Simulate clicking the "Play" button
const playButton = screen.getByRole('button', { name: 'Play' });
expect(playButton).toBeInTheDocument();
await userEvent.click(playButton);

// Since we error out with the mocked kubePlay function (see very top of tests)
// Expect the following error to be in in the document.
const error = screen.getByText('The following pods were created but failed to start: error 1, error 2');
expect(error).toBeInTheDocument();
});
64 changes: 56 additions & 8 deletions packages/renderer/src/lib/kube/KubePlayYAML.svelte
Expand Up @@ -10,13 +10,15 @@ import NoContainerEngineEmptyScreen from '../image/NoContainerEngineEmptyScreen.
import NavPage from '../ui/NavPage.svelte';
import KubePlayIcon from '../kube/KubePlayIcon.svelte';
import ErrorMessage from '../ui/ErrorMessage.svelte';
import WarningMessage from '../ui/WarningMessage.svelte';
import type { V1NamespaceList } from '@kubernetes/client-node/dist/api';
import { faCircleCheck } from '@fortawesome/free-solid-svg-icons';
import Fa from 'svelte-fa/src/fa.svelte';
let runStarted = false;
let runFinished = false;
let runError = '';
let runWarning = '';
let kubernetesYamlFilePath = undefined;
let hasInvalidFields = true;
Expand All @@ -25,6 +27,7 @@ let currentNamespace: string;
let allNamespaces: V1NamespaceList;
let playKubeResultRaw;
let playKubeResultJSON;
let userChoice: 'podman' | 'kubernetes' = 'podman';
Expand Down Expand Up @@ -57,8 +60,28 @@ async function playKubeFile(): Promise<void> {
if (userChoice === 'podman') {
try {
const result = await window.playKube(kubernetesYamlFilePath, selectedProvider);
// remove the null values from the result
playKubeResultRaw = JSON.stringify(removeEmptyOrNull(result), null, 2);
playKubeResultJSON = JSON.parse(playKubeResultRaw);
// If there are container errors, that means that it was *able* to create the container
// but if failed to start. We will add this to the "warning" section as we were able to create the
// We add this with comma deliminated errors
if (playKubeResultJSON.Pods.length > 0) {
// Filter out the pods that have container errors, but check to see that container errors exists first
const containerErrors = playKubeResultJSON.Pods.filter(
pod => pod.ContainerErrors && pod.ContainerErrors.length > 0,
);
// For each Pod that has container errors, we will add the container errors to the warning message
if (containerErrors.length > 0) {
runWarning = `The following pods were created but failed to start: ${containerErrors
.map(pod => pod.ContainerErrors.join(', '))
.join(', ')}`;
}
}
runFinished = true;
} catch (error) {
runError = error;
Expand Down Expand Up @@ -107,6 +130,10 @@ onDestroy(() => {
}
});
function goBackToHistory(): void {
window.history.go(-1);
}
async function getKubernetesfileLocation() {
const result = await window.openFileDialog('Select a .yaml file to play', {
name: 'YAML files',
Expand Down Expand Up @@ -274,17 +301,38 @@ async function getKubernetesfileLocation() {
complete...
</div>
{/if}
<div class="text-sm"><ErrorMessage error="{runError}" /></div>

{#if runWarning}
<WarningMessage class="text-sm" error="{runWarning}" />
{/if}

{#if runError}
<ErrorMessage class="text-sm" error="{runError}" />
{/if}

{#if playKubeResultJSON}
<!-- Output area similar to DeployPodToKube.svelte -->
<div class="bg-charcoal-800 p-5 my-4">
<div class="flex flex-row items-center">
<div>
{#if playKubeResultJSON?.Pods.length > 1}
Created pods:
{:else}
Created pod:
{/if}
</div>
</div>

<div class="h-[100px] pt-2">
<MonacoEditor content="{playKubeResultRaw}" language="json" />
</div>
</div>
{/if}

{#if runFinished}
<!-- On click, go BACK to the previous page (if clicked on Pods page, go back to pods, same for Containers)-->
<button on:click="{() => history.back()}" class="w-full pf-c-button pf-m-primary">Done</button>
<button on:click="{() => goBackToHistory()}" class="pt-4 w-full pf-c-button pf-m-primary">Done</button>
{/if}
</div>
{#if playKubeResultRaw}
<div class=" h-full w-full px-6 pb-4 space-y-6 lg:px-8 sm:pb-6 xl:pb-8">
<MonacoEditor content="{playKubeResultRaw}" language="json" />
</div>
{/if}
</div>
</NavPage>
{/if}

0 comments on commit 23408d2

Please sign in to comment.