Copy local file to pod using tar (#962)

* Copy local file to pod using tar

* Update examples/cp/Cp.cs

Co-authored-by: Boshi Lian <farmer1992@gmail.com>

* File names as command line args, default encoding

* command line args

Co-authored-by: Boshi Lian <farmer1992@gmail.com>
This commit is contained in:
Lazar Krstić
2022-07-27 18:04:28 +02:00
committed by GitHub
parent a361f2d1f8
commit d59f4da2ae
2 changed files with 137 additions and 0 deletions

126
examples/cp/Cp.cs Normal file
View File

@@ -0,0 +1,126 @@
using System;
using System.IO;
using System.Threading.Tasks;
using k8s;
using ICSharpCode.SharpZipLib.Tar;
using System.Threading;
using System.Linq;
using System.Text;
namespace cp
{
internal class Cp
{
private static IKubernetes client;
private static async Task Main(string[] args)
{
var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
client = new Kubernetes(config);
var pods = client.CoreV1.ListNamespacedPod("default", null, null, null, $"job-name=upload-demo");
var pod = pods.Items.First();
await CopyFileToPodAsync(pod.Metadata.Name, "default", "upload-demo", args[0], $"home/{args[1]}");
}
private static void ValidatePathParameters(string sourcePath, string destinationPath)
{
if (string.IsNullOrWhiteSpace(sourcePath))
{
throw new ArgumentException($"{nameof(sourcePath)} cannot be null or whitespace");
}
if (string.IsNullOrWhiteSpace(destinationPath))
{
throw new ArgumentException($"{nameof(destinationPath)} cannot be null or whitespace");
}
}
public static async Task<int> CopyFileToPodAsync(string name, string @namespace, string container, string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken = default(CancellationToken))
{
// All other parameters are being validated by MuxedStreamNamespacedPodExecAsync called by NamespacedPodExecAsync
ValidatePathParameters(sourceFilePath, destinationFilePath);
// The callback which processes the standard input, standard output and standard error of exec method
var handler = new ExecAsyncCallback(async (stdIn, stdOut, stdError) =>
{
var fileInfo = new FileInfo(destinationFilePath);
try
{
using (var memoryStream = new MemoryStream())
{
using (var inputFileStream = File.OpenRead(sourceFilePath))
using (var tarOutputStream = new TarOutputStream(memoryStream, Encoding.Default))
{
tarOutputStream.IsStreamOwner = false;
var fileSize = inputFileStream.Length;
var entry = TarEntry.CreateTarEntry(fileInfo.Name);
entry.Size = fileSize;
tarOutputStream.PutNextEntry(entry);
await inputFileStream.CopyToAsync(tarOutputStream);
tarOutputStream.CloseEntry();
}
memoryStream.Position = 0;
const int bufferSize = 31 * 1024 * 1024; // must be lower than 32 * 1024 * 1024
byte[] localBuffer = new byte[bufferSize];
while (true)
{
int numRead = await memoryStream.ReadAsync(localBuffer, 0, localBuffer.Length);
if (numRead <= 0)
{
break;
}
await stdIn.WriteAsync(localBuffer, 0, numRead);
}
await stdIn.FlushAsync();
}
}
catch (Exception ex)
{
throw new IOException($"Copy command failed: {ex.Message}");
}
using StreamReader streamReader = new StreamReader(stdError);
while (streamReader.EndOfStream == false)
{
string error = await streamReader.ReadToEndAsync();
throw new IOException($"Copy command failed: {error}");
}
});
string destinationFolder = GetFolderName(destinationFilePath);
return await client.NamespacedPodExecAsync(
name,
@namespace,
container,
new string[] { "sh", "-c", $"tar xmf - -C {destinationFolder}" },
false,
handler,
cancellationToken);
}
private static string GetFolderName(string filePath)
{
var folderName = Path.GetDirectoryName(filePath);
return string.IsNullOrEmpty(folderName) ? "." : folderName;
}
}
}

11
examples/cp/cp.csproj Normal file
View File

@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SharpZipLib" Version="1.3.3" />
</ItemGroup>
</Project>