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:
126
examples/cp/Cp.cs
Normal file
126
examples/cp/Cp.cs
Normal 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
11
examples/cp/cp.csproj
Normal 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>
|
||||||
Reference in New Issue
Block a user