mirror of
https://github.com/frosch95/K8sFileBrowser.git
synced 2026-04-11 12:58:22 +02:00
Compare commits
3 Commits
v0.0.5-alp
...
v0.0.6-alp
| Author | SHA1 | Date | |
|---|---|---|---|
| ba39661926 | |||
| 59e9131fed | |||
| d544f75c99 |
23
K8sFileBrowser/Models/Container.cs
Normal file
23
K8sFileBrowser/Models/Container.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace K8sFileBrowser.Models;
|
||||
|
||||
public class Container
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is Container container)
|
||||
{
|
||||
return Name == container.Name;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => Name.GetHashCode();
|
||||
}
|
||||
@@ -15,9 +15,9 @@ public interface IKubernetesService
|
||||
Task<IEnumerable<Namespace>> GetNamespacesAsync();
|
||||
Task<IEnumerable<Pod>> GetPodsAsync(string namespaceName, CancellationToken cancellationToken = default);
|
||||
IList<FileInformation> GetFiles(string namespaceName, string podName, string containerName, string path);
|
||||
Task DownloadFile(Namespace? selectedNamespace, Pod? selectedPod, FileInformation selectedFile,
|
||||
Task DownloadFile(Namespace? selectedNamespace, Pod? selectedPod, Container? selectedContainer, FileInformation selectedFile,
|
||||
string? saveFileName, CancellationToken cancellationToken = default);
|
||||
Task DownloadLog(Namespace? selectedNamespace, Pod? selectedPod,
|
||||
Task DownloadLog(Namespace? selectedNamespace, Pod? selectedPod, Container? selectedContainer,
|
||||
string? saveFileName, CancellationToken cancellationToken = default);
|
||||
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class KubernetesService : IKubernetesService
|
||||
_kubernetesClient = kubernetesClient;
|
||||
}
|
||||
|
||||
public async Task DownloadFile(Namespace? selectedNamespace, Pod? selectedPod, FileInformation selectedFile,
|
||||
public async Task DownloadFile(Namespace? selectedNamespace, Pod? selectedPod, Container? selectedContainer, FileInformation selectedFile,
|
||||
string? saveFileName, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Log.Information("{SelectedNamespace} - {SelectedPod} - {@SelectedFile} - {SaveFileName}",
|
||||
@@ -139,14 +139,14 @@ public class KubernetesService : IKubernetesService
|
||||
await _kubernetesClient.NamespacedPodExecAsync(
|
||||
selectedPod?.Name,
|
||||
selectedNamespace?.Name,
|
||||
selectedPod?.Containers.First(),
|
||||
selectedContainer?.Name,
|
||||
new[] { "sh", "-c", $"tar cf - {selectedFile.Name}" },
|
||||
false,
|
||||
handler,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public async Task DownloadLog(Namespace? selectedNamespace, Pod? selectedPod,
|
||||
public async Task DownloadLog(Namespace? selectedNamespace, Pod? selectedPod, Container? selectedContainer,
|
||||
string? saveFileName, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Log.Information("{SelectedNamespace} - {SelectedPod} - {SaveFileName}",
|
||||
@@ -155,7 +155,7 @@ public class KubernetesService : IKubernetesService
|
||||
var response = await _kubernetesClient.CoreV1.ReadNamespacedPodLogWithHttpMessagesAsync(
|
||||
selectedPod?.Name,
|
||||
selectedNamespace?.Name,
|
||||
container: selectedPod?.Containers.First(),
|
||||
container: selectedContainer?.Name,
|
||||
follow: false , cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace K8sFileBrowser.ViewModels;
|
||||
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
private ObservableAsPropertyHelper<IEnumerable<ClusterContext>> _clusterContexts;
|
||||
private ObservableAsPropertyHelper<IEnumerable<ClusterContext>> _clusterContexts = null!;
|
||||
public IEnumerable<ClusterContext> ClusterContexts => _clusterContexts.Value;
|
||||
|
||||
private ClusterContext? _selectedClusterContext;
|
||||
@@ -24,7 +24,7 @@ public class MainWindowViewModel : ViewModelBase
|
||||
set => this.RaiseAndSetIfChanged(ref _selectedClusterContext, value);
|
||||
}
|
||||
|
||||
private IEnumerable<Namespace> _namespaces;
|
||||
private IEnumerable<Namespace> _namespaces = null!;
|
||||
public IEnumerable<Namespace> Namespaces
|
||||
{
|
||||
get => _namespaces;
|
||||
@@ -39,7 +39,7 @@ public class MainWindowViewModel : ViewModelBase
|
||||
set => this.RaiseAndSetIfChanged(ref _selectedNamespace, value);
|
||||
}
|
||||
|
||||
private ObservableAsPropertyHelper<IEnumerable<Pod>> _pods;
|
||||
private ObservableAsPropertyHelper<IEnumerable<Pod>> _pods = null!;
|
||||
public IEnumerable<Pod> Pods => _pods.Value;
|
||||
|
||||
private Pod? _selectedPod;
|
||||
@@ -50,7 +50,22 @@ public class MainWindowViewModel : ViewModelBase
|
||||
set => this.RaiseAndSetIfChanged(ref _selectedPod, value);
|
||||
}
|
||||
|
||||
private ObservableAsPropertyHelper<IEnumerable<FileInformation>> _fileInformation;
|
||||
private IEnumerable<Container>? _containers;
|
||||
public IEnumerable<Container>? Containers
|
||||
{
|
||||
get => _containers;
|
||||
set => this.RaiseAndSetIfChanged(ref _containers, value);
|
||||
}
|
||||
|
||||
private Container? _selectedContainer;
|
||||
|
||||
public Container? SelectedContainer
|
||||
{
|
||||
get => _selectedContainer;
|
||||
set => this.RaiseAndSetIfChanged(ref _selectedContainer, value);
|
||||
}
|
||||
|
||||
private ObservableAsPropertyHelper<IEnumerable<FileInformation>> _fileInformation = null!;
|
||||
public IEnumerable<FileInformation> FileInformation => _fileInformation.Value;
|
||||
|
||||
private FileInformation? _selectedFile;
|
||||
@@ -69,19 +84,19 @@ public class MainWindowViewModel : ViewModelBase
|
||||
set => this.RaiseAndSetIfChanged(ref _selectedPath, value);
|
||||
}
|
||||
|
||||
private Message _message;
|
||||
private Message _message = null!;
|
||||
public Message Message
|
||||
{
|
||||
get => _message;
|
||||
set => this.RaiseAndSetIfChanged(ref _message, value);
|
||||
}
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DownloadCommand { get; private set; }
|
||||
public ReactiveCommand<Unit, Unit> DownloadLogCommand { get; private set; }
|
||||
public ReactiveCommand<Unit, Unit> ParentCommand { get; private set; }
|
||||
public ReactiveCommand<Unit, Unit> OpenCommand { get; private set; }
|
||||
public ReactiveCommand<Unit, Unit> DownloadCommand { get; private set; } = null!;
|
||||
public ReactiveCommand<Unit, Unit> DownloadLogCommand { get; private set; } = null!;
|
||||
public ReactiveCommand<Unit, Unit> ParentCommand { get; private set; } = null!;
|
||||
public ReactiveCommand<Unit, Unit> OpenCommand { get; private set; } = null!;
|
||||
|
||||
private ReactiveCommand<Namespace, IEnumerable<Pod>> GetPodsForNamespace { get; set; }
|
||||
private ReactiveCommand<Namespace, IEnumerable<Pod>> GetPodsForNamespace { get; set; } = null!;
|
||||
|
||||
|
||||
public MainWindowViewModel()
|
||||
@@ -99,6 +114,7 @@ public class MainWindowViewModel : ViewModelBase
|
||||
// register the listeners
|
||||
RegisterReadNamespaces(kubernetesService);
|
||||
RegisterReadPods();
|
||||
RegisterReadContainers();
|
||||
RegisterReadFiles(kubernetesService);
|
||||
RegisterResetPath();
|
||||
|
||||
@@ -124,18 +140,37 @@ public class MainWindowViewModel : ViewModelBase
|
||||
// reset the path when the pod or namespace changes
|
||||
this.WhenAnyValue(c => c.SelectedPod, c => c.SelectedNamespace)
|
||||
.Throttle(new TimeSpan(10))
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.Subscribe(x => SelectedPath = "/");
|
||||
}
|
||||
|
||||
private void RegisterReadContainers()
|
||||
{
|
||||
// read the file information when the path changes
|
||||
this
|
||||
.WhenAnyValue(c => c.SelectedPod, c => c.SelectedNamespace)
|
||||
.Throttle(new TimeSpan(10))
|
||||
.Select(x => x.Item2 == null || x.Item1 == null
|
||||
? new List<Container>()
|
||||
: x.Item1.Containers.Select(c => new Container {Name = c}))
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Subscribe( x => Containers = x);
|
||||
|
||||
this.WhenAnyValue(x => x.Containers)
|
||||
.Throttle(new TimeSpan(10))
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Subscribe(x => SelectedContainer = x?.FirstOrDefault());
|
||||
}
|
||||
|
||||
private void RegisterReadFiles(IKubernetesService kubernetesService)
|
||||
{
|
||||
// read the file information when the path changes
|
||||
_fileInformation = this
|
||||
.WhenAnyValue(c => c.SelectedPath, c => c.SelectedPod, c => c.SelectedNamespace)
|
||||
.WhenAnyValue(c => c.SelectedPath, c => c.SelectedPod, c => c.SelectedNamespace, c => c.SelectedContainer)
|
||||
.Throttle(new TimeSpan(10))
|
||||
.Select(x => x.Item3 == null || x.Item2 == null
|
||||
.Select(x => x.Item3 == null || x.Item2 == null || x.Item1 == null || x.Item4 == null
|
||||
? new List<FileInformation>()
|
||||
: kubernetesService.GetFiles(x.Item3!.Name, x.Item2!.Name, x.Item2!.Containers.First(),
|
||||
: kubernetesService.GetFiles(x.Item3!.Name, x.Item2!.Name, x.Item4!.Name,
|
||||
x.Item1))
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.ToProperty(this, x => x.FileInformation);
|
||||
@@ -206,7 +241,7 @@ public class MainWindowViewModel : ViewModelBase
|
||||
if (saveFileName != null)
|
||||
{
|
||||
ShowWorkingMessage("Downloading Log...");
|
||||
await kubernetesService.DownloadLog(SelectedNamespace, SelectedPod, saveFileName);
|
||||
await kubernetesService.DownloadLog(SelectedNamespace, SelectedPod, SelectedContainer, saveFileName);
|
||||
HideWorkingMessage();
|
||||
}
|
||||
}, RxApp.TaskpoolScheduler);
|
||||
@@ -232,7 +267,7 @@ public class MainWindowViewModel : ViewModelBase
|
||||
if (saveFileName != null)
|
||||
{
|
||||
ShowWorkingMessage("Downloading File...");
|
||||
await kubernetesService.DownloadFile(SelectedNamespace, SelectedPod, SelectedFile, saveFileName);
|
||||
await kubernetesService.DownloadFile(SelectedNamespace, SelectedPod, SelectedContainer, SelectedFile, saveFileName);
|
||||
HideWorkingMessage();
|
||||
}
|
||||
}, RxApp.TaskpoolScheduler);
|
||||
|
||||
@@ -72,12 +72,24 @@
|
||||
</ListBox>
|
||||
<GridSplitter Grid.Column="1" ResizeDirection="Columns" />
|
||||
<Grid Grid.Column="2" RowDefinitions="Auto, *">
|
||||
<Grid ColumnDefinitions="*, Auto">
|
||||
<Grid ColumnDefinitions="*, Auto, Auto">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||
<TextBlock Text="Current Directory" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
|
||||
<TextBlock Text="{Binding SelectedPath}" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="4" Margin="10" HorizontalAlignment="Right">
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<Label VerticalAlignment="Center"
|
||||
Margin="0 0 10 0">
|
||||
Container:
|
||||
</Label>
|
||||
<ComboBox ItemsSource="{Binding Containers}"
|
||||
SelectedItem="{Binding SelectedContainer}"
|
||||
VerticalAlignment="Center"
|
||||
MinWidth="200"
|
||||
Margin="0 0 10 0">
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4" Margin="10" HorizontalAlignment="Right">
|
||||
|
||||
<Button Command="{Binding ParentCommand}" VerticalAlignment="Center" ToolTip.Tip="Go To Parent Directory">
|
||||
<PathIcon Data="{StaticResource arrow_curve_up_left_regular}"></PathIcon>
|
||||
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Andreas Billmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Reference in New Issue
Block a user