added app icon, introduce kubernetesservice interface and logging

This commit is contained in:
2023-08-01 20:39:25 +02:00
parent ee6544c641
commit 12ef9680d0
9 changed files with 189 additions and 154 deletions

View File

@@ -0,0 +1,6 @@
This favicon was generated using the following font:
- Font Title: Genos
- Font Author: Copyright 2011 The Genos Project Authors (https://github.com/googlefonts/genos)
- Font Source: http://fonts.gstatic.com/s/genos/v10/SlGNmQqPqpUOYTYjacb0Hc91fTwVA0_orUK6K7ZsAg.ttf
- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL))

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

View File

@@ -8,6 +8,7 @@
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault> <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms> <Platforms>AnyCPU</Platforms>
<ApplicationIcon>Assets/app.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
@@ -28,7 +29,9 @@
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.1" /> <PackageReference Include="Avalonia.ReactiveUI" Version="11.0.1" />
<PackageReference Include="KubernetesClient" Version="11.0.44" /> <PackageReference Include="KubernetesClient" Version="11.0.44" />
<PackageReference Include="Serilog" Version="3.0.1" /> <PackageReference Include="Serilog" Version="3.0.1" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SharpZipLib" Version="1.4.2" /> <PackageReference Include="SharpZipLib" Version="1.4.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -16,8 +16,8 @@ class Program
{ {
Log.Logger = new LoggerConfiguration() Log.Logger = new LoggerConfiguration()
//.Filter.ByIncludingOnly(Matching.WithProperty("Area", LogArea.Control)) //.Filter.ByIncludingOnly(Matching.WithProperty("Area", LogArea.Control))
.MinimumLevel.Verbose() .MinimumLevel.Information()
.WriteTo.Console() .WriteTo.Async(a => a.File("app.log"))
.CreateLogger(); .CreateLogger();
BuildAvaloniaApp() BuildAvaloniaApp()

View File

@@ -0,0 +1,20 @@
// // Copyright (c) Vector Informatik GmbH. All rights reserved.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using K8sFileBrowser.Models;
namespace K8sFileBrowser.Services;
public interface IKubernetesService
{
IEnumerable<ClusterContext> GetClusterContexts();
string GetCurrentContext();
void SwitchClusterContext(ClusterContext clusterContext);
IEnumerable<Namespace> GetNamespaces();
IEnumerable<Pod> GetPods(string namespaceName);
IList<FileInformation> GetFiles(string namespaceName, string podName, string containerName, string path);
Task DownloadFile(Namespace? selectedNamespace, Pod? selectedPod, FileInformation selectedFile,
string? saveFileName, CancellationToken cancellationToken = default);
}

View File

@@ -14,7 +14,7 @@ using static ICSharpCode.SharpZipLib.Core.StreamUtils;
namespace K8sFileBrowser.Services; namespace K8sFileBrowser.Services;
public class KubernetesService public class KubernetesService : IKubernetesService
{ {
private readonly K8SConfiguration _k8SConfiguration; private readonly K8SConfiguration _k8SConfiguration;
private IKubernetes _kubernetesClient = null!; private IKubernetes _kubernetesClient = null!;
@@ -98,9 +98,8 @@ public class KubernetesService
_kubernetesClient = kubernetesClient; _kubernetesClient = kubernetesClient;
} }
public async Task DownloadFile(Namespace? selectedNamespace, Pod? selectedPod, FileInformation selectedFile, public async Task DownloadFile(Namespace? selectedNamespace, Pod? selectedPod, FileInformation selectedFile,
string? saveFileName) string? saveFileName, CancellationToken cancellationToken = default)
{ {
Log.Information("{SelectedNamespace} - {SelectedPod} - {SelectedFile} - {SaveFileName}", Log.Information("{SelectedNamespace} - {SelectedPod} - {SelectedFile} - {SaveFileName}",
selectedNamespace, selectedPod, selectedFile, saveFileName); selectedNamespace, selectedPod, selectedFile, saveFileName);
@@ -111,7 +110,7 @@ public class KubernetesService
await using var outputFileStream = File.OpenWrite(saveFileName!); await using var outputFileStream = File.OpenWrite(saveFileName!);
await using var tarInputStream = new TarInputStream(stdOut, Encoding.Default); await using var tarInputStream = new TarInputStream(stdOut, Encoding.Default);
var entry = await tarInputStream.GetNextEntryAsync(default); var entry = await tarInputStream.GetNextEntryAsync(cancellationToken);
if (entry == null) if (entry == null)
{ {
throw new IOException("Copy command failed: no files found"); throw new IOException("Copy command failed: no files found");
@@ -119,7 +118,7 @@ public class KubernetesService
var bytes = new byte[entry.Size]; var bytes = new byte[entry.Size];
ReadFully( tarInputStream, bytes ); ReadFully( tarInputStream, bytes );
await outputFileStream.WriteAsync(bytes, default); await outputFileStream.WriteAsync(bytes, cancellationToken);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -129,7 +128,7 @@ public class KubernetesService
using var streamReader = new StreamReader(stdError); using var streamReader = new StreamReader(stdError);
while (streamReader.EndOfStream == false) while (streamReader.EndOfStream == false)
{ {
var error = await streamReader.ReadToEndAsync(default); var error = await streamReader.ReadToEndAsync(cancellationToken);
Log.Error(error); Log.Error(error);
} }
}); });

View File

@@ -15,6 +15,7 @@ public class MainWindowViewModel : ViewModelBase
public IEnumerable<ClusterContext> ClusterContexts => _clusterContexts.Value; public IEnumerable<ClusterContext> ClusterContexts => _clusterContexts.Value;
private ClusterContext? _selectedClusterContext; private ClusterContext? _selectedClusterContext;
public ClusterContext? SelectedClusterContext public ClusterContext? SelectedClusterContext
{ {
get => _selectedClusterContext; get => _selectedClusterContext;
@@ -25,6 +26,7 @@ public class MainWindowViewModel : ViewModelBase
public IEnumerable<Namespace> Namespaces => _namespaces.Value; public IEnumerable<Namespace> Namespaces => _namespaces.Value;
private Namespace? _selectedNamespace; private Namespace? _selectedNamespace;
public Namespace? SelectedNamespace public Namespace? SelectedNamespace
{ {
get => _selectedNamespace; get => _selectedNamespace;
@@ -35,6 +37,7 @@ public class MainWindowViewModel : ViewModelBase
public IEnumerable<Pod> Pods => _pods.Value; public IEnumerable<Pod> Pods => _pods.Value;
private Pod? _selectedPod; private Pod? _selectedPod;
public Pod? SelectedPod public Pod? SelectedPod
{ {
get => _selectedPod; get => _selectedPod;
@@ -45,6 +48,7 @@ public class MainWindowViewModel : ViewModelBase
public IEnumerable<FileInformation> FileInformation => _fileInformation.Value; public IEnumerable<FileInformation> FileInformation => _fileInformation.Value;
private FileInformation? _selectedFile; private FileInformation? _selectedFile;
public FileInformation? SelectedFile public FileInformation? SelectedFile
{ {
get => _selectedFile; get => _selectedFile;
@@ -52,6 +56,7 @@ public class MainWindowViewModel : ViewModelBase
} }
private string? _selectedPath; private string? _selectedPath;
public string? SelectedPath public string? SelectedPath
{ {
get => _selectedPath; get => _selectedPath;
@@ -59,6 +64,7 @@ public class MainWindowViewModel : ViewModelBase
} }
private bool _isDownloadActive; private bool _isDownloadActive;
public bool IsDownloadActive public bool IsDownloadActive
{ {
get => _isDownloadActive; get => _isDownloadActive;
@@ -72,7 +78,8 @@ public class MainWindowViewModel : ViewModelBase
public MainWindowViewModel() public MainWindowViewModel()
{ {
var kubernetesService = new KubernetesService(); //TODO: use dependency injection to get the kubernetes service
IKubernetesService kubernetesService = new KubernetesService();
var isFile = this var isFile = this
.WhenAnyValue(x => x.SelectedFile, x => x.IsDownloadActive) .WhenAnyValue(x => x.SelectedFile, x => x.IsDownloadActive)
@@ -86,15 +93,15 @@ public class MainWindowViewModel : ViewModelBase
.WhenAnyValue(x => x.SelectedPath, x => x.IsDownloadActive) .WhenAnyValue(x => x.SelectedPath, x => x.IsDownloadActive)
.Select(x => x.Item1 is not "/" && !x.Item2); .Select(x => x.Item1 is not "/" && !x.Item2);
OpenCommand = ReactiveCommand.Create(() => OpenCommand = ReactiveCommand.Create(() => { SelectedPath = SelectedFile != null ? SelectedFile!.Name : "/"; },
{ isDirectory, RxApp.MainThreadScheduler);
SelectedPath = SelectedFile != null ? SelectedFile!.Name : "/";
}, isDirectory, RxApp.MainThreadScheduler);
DownloadCommand = ReactiveCommand.CreateFromTask(async () => DownloadCommand = ReactiveCommand.CreateFromTask(async () =>
{ {
await Observable.StartAsync(async () => { await Observable.StartAsync(async () =>
var fileName = SelectedFile!.Name.Substring(SelectedFile!.Name.LastIndexOf('/') + 1, SelectedFile!.Name.Length - SelectedFile!.Name.LastIndexOf('/') - 1); {
var fileName = SelectedFile!.Name.Substring(SelectedFile!.Name.LastIndexOf('/') + 1,
SelectedFile!.Name.Length - SelectedFile!.Name.LastIndexOf('/') - 1);
var saveFileName = await ApplicationHelper.SaveFile(".", fileName); var saveFileName = await ApplicationHelper.SaveFile(".", fileName);
if (saveFileName != null) if (saveFileName != null)
{ {

View File

@@ -7,7 +7,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="K8sFileBrowser.Views.MainWindow" x:Class="K8sFileBrowser.Views.MainWindow"
x:DataType="vm:MainWindowViewModel" x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico" Icon="/Assets/app.ico"
Title="K8sFileBrowser"> Title="K8sFileBrowser">
<Design.DataContext> <Design.DataContext>