| 
1 |  | -using ICSharpCode.SharpZipLib.Tar;  | 
 | 1 | +using ICSharpCode.SharpZipLib.Tar;  | 
2 | 2 | using k8s;  | 
3 | 3 | using System;  | 
4 | 4 | using System.IO;  | 
 | 
7 | 7 | using System.Threading;  | 
8 | 8 | using System.Threading.Tasks;  | 
9 | 9 | 
 
  | 
10 |  | -namespace cp  | 
11 |  | -{  | 
12 |  | -    internal class Cp  | 
13 |  | -    {  | 
14 |  | -        private static IKubernetes client;  | 
 | 10 | +namespace cp;  | 
15 | 11 | 
 
  | 
16 |  | -        private static async Task Main(string[] args)  | 
17 |  | -        {  | 
18 |  | -            var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();  | 
19 |  | -            client = new Kubernetes(config);  | 
 | 12 | +internal class Cp  | 
 | 13 | +{  | 
 | 14 | +    private static IKubernetes client;  | 
20 | 15 | 
 
  | 
 | 16 | +    private static async Task Main(string[] args)  | 
 | 17 | +    {  | 
 | 18 | +        var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();  | 
 | 19 | +        client = new Kubernetes(config);  | 
21 | 20 | 
 
  | 
22 |  | -            var pods = client.CoreV1.ListNamespacedPod("default", null, null, null, $"job-name=upload-demo");  | 
23 |  | -            var pod = pods.Items.First();  | 
24 | 21 | 
 
  | 
25 |  | -            await CopyFileToPodAsync(pod.Metadata.Name, "default", "upload-demo", args[0], $"home/{args[1]}");  | 
 | 22 | +        var pods = client.CoreV1.ListNamespacedPod("default", null, null, null, $"job-name=upload-demo");  | 
 | 23 | +        var pod = pods.Items.First();  | 
26 | 24 | 
 
  | 
27 |  | -        }  | 
 | 25 | +        await CopyFileToPodAsync(pod.Metadata.Name, "default", "upload-demo", args[0], $"home/{args[1]}").ConfigureAwait(false);  | 
 | 26 | +    }  | 
28 | 27 | 
 
  | 
29 | 28 | 
 
  | 
30 | 29 | 
 
  | 
31 | 30 | 
 
  | 
32 |  | -        private static void ValidatePathParameters(string sourcePath, string destinationPath)  | 
 | 31 | +    private static void ValidatePathParameters(string sourcePath, string destinationPath)  | 
 | 32 | +    {  | 
 | 33 | +        if (string.IsNullOrWhiteSpace(sourcePath))  | 
33 | 34 |         {  | 
34 |  | -            if (string.IsNullOrWhiteSpace(sourcePath))  | 
35 |  | -            {  | 
36 |  | -                throw new ArgumentException($"{nameof(sourcePath)} cannot be null or whitespace");  | 
37 |  | -            }  | 
38 |  | - | 
39 |  | -            if (string.IsNullOrWhiteSpace(destinationPath))  | 
40 |  | -            {  | 
41 |  | -                throw new ArgumentException($"{nameof(destinationPath)} cannot be null or whitespace");  | 
42 |  | -            }  | 
43 |  | - | 
 | 35 | +            throw new ArgumentException($"{nameof(sourcePath)} cannot be null or whitespace");  | 
44 | 36 |         }  | 
45 | 37 | 
 
  | 
46 |  | -        public static async Task<int> CopyFileToPodAsync(string name, string @namespace, string container, string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken = default(CancellationToken))  | 
 | 38 | +        if (string.IsNullOrWhiteSpace(destinationPath))  | 
47 | 39 |         {  | 
48 |  | -            // All other parameters are being validated by MuxedStreamNamespacedPodExecAsync called by NamespacedPodExecAsync  | 
49 |  | -            ValidatePathParameters(sourceFilePath, destinationFilePath);  | 
 | 40 | +            throw new ArgumentException($"{nameof(destinationPath)} cannot be null or whitespace");  | 
 | 41 | +        }  | 
 | 42 | +    }  | 
 | 43 | + | 
 | 44 | +    public static async Task<int> CopyFileToPodAsync(string name, string @namespace, string container, string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken = default(CancellationToken))  | 
 | 45 | +    {  | 
 | 46 | +        // All other parameters are being validated by MuxedStreamNamespacedPodExecAsync called by NamespacedPodExecAsync  | 
 | 47 | +        ValidatePathParameters(sourceFilePath, destinationFilePath);  | 
50 | 48 | 
 
  | 
51 |  | -            // The callback which processes the standard input, standard output and standard error of exec method  | 
52 |  | -            var handler = new ExecAsyncCallback(async (stdIn, stdOut, stdError) =>  | 
 | 49 | +        // The callback which processes the standard input, standard output and standard error of exec method  | 
 | 50 | +        var handler = new ExecAsyncCallback(async (stdIn, stdOut, stdError) =>  | 
 | 51 | +        {  | 
 | 52 | +            var fileInfo = new FileInfo(destinationFilePath);  | 
 | 53 | +            try  | 
53 | 54 |             {  | 
54 |  | -                var fileInfo = new FileInfo(destinationFilePath);  | 
55 |  | -                try  | 
 | 55 | +                using (var memoryStream = new MemoryStream())  | 
56 | 56 |                 {  | 
57 |  | -                    using (var memoryStream = new MemoryStream())  | 
 | 57 | +                    using (var inputFileStream = File.OpenRead(sourceFilePath))  | 
 | 58 | +                    using (var tarOutputStream = new TarOutputStream(memoryStream, Encoding.Default))  | 
58 | 59 |                     {  | 
59 |  | -                        using (var inputFileStream = File.OpenRead(sourceFilePath))  | 
60 |  | -                        using (var tarOutputStream = new TarOutputStream(memoryStream, Encoding.Default))  | 
61 |  | -                        {  | 
62 |  | -                            tarOutputStream.IsStreamOwner = false;  | 
63 |  | - | 
64 |  | -                            var fileSize = inputFileStream.Length;  | 
65 |  | -                            var entry = TarEntry.CreateTarEntry(fileInfo.Name);  | 
66 |  | - | 
67 |  | -                            entry.Size = fileSize;  | 
 | 60 | +                        tarOutputStream.IsStreamOwner = false;  | 
68 | 61 | 
 
  | 
69 |  | -                            tarOutputStream.PutNextEntry(entry);  | 
70 |  | -                            await inputFileStream.CopyToAsync(tarOutputStream);  | 
71 |  | -                            tarOutputStream.CloseEntry();  | 
72 |  | -                        }  | 
 | 62 | +                        var fileSize = inputFileStream.Length;  | 
 | 63 | +                        var entry = TarEntry.CreateTarEntry(fileInfo.Name);  | 
73 | 64 | 
 
  | 
74 |  | -                        memoryStream.Position = 0;  | 
 | 65 | +                        entry.Size = fileSize;  | 
75 | 66 | 
 
  | 
76 |  | -                        await memoryStream.CopyToAsync(stdIn);  | 
77 |  | -                        await stdIn.FlushAsync();  | 
 | 67 | +                        tarOutputStream.PutNextEntry(entry);  | 
 | 68 | +                        await inputFileStream.CopyToAsync(tarOutputStream).ConfigureAwait(false);  | 
 | 69 | +                        tarOutputStream.CloseEntry();  | 
78 | 70 |                     }  | 
79 | 71 | 
 
  | 
80 |  | -                }  | 
81 |  | -                catch (Exception ex)  | 
82 |  | -                {  | 
83 |  | -                    throw new IOException($"Copy command failed: {ex.Message}");  | 
84 |  | -                }  | 
 | 72 | +                    memoryStream.Position = 0;  | 
85 | 73 | 
 
  | 
86 |  | -                using StreamReader streamReader = new StreamReader(stdError);  | 
87 |  | -                while (streamReader.EndOfStream == false)  | 
88 |  | -                {  | 
89 |  | -                    string error = await streamReader.ReadToEndAsync();  | 
90 |  | -                    throw new IOException($"Copy command failed: {error}");  | 
 | 74 | +                    await memoryStream.CopyToAsync(stdIn).ConfigureAwait(false);  | 
 | 75 | +                    await stdIn.FlushAsync().ConfigureAwait(false);  | 
91 | 76 |                 }  | 
92 |  | -            });  | 
93 |  | - | 
94 |  | -            string destinationFolder = GetFolderName(destinationFilePath);  | 
95 |  | - | 
96 |  | -            return await client.NamespacedPodExecAsync(  | 
97 |  | -                name,  | 
98 |  | -                @namespace,  | 
99 |  | -                container,  | 
100 |  | -                new string[] { "sh", "-c", $"tar xmf - -C {destinationFolder}" },  | 
101 |  | -                false,  | 
102 |  | -                handler,  | 
103 |  | -                cancellationToken);  | 
104 |  | -        }  | 
105 |  | - | 
 | 77 | +            }  | 
 | 78 | +            catch (Exception ex)  | 
 | 79 | +            {  | 
 | 80 | +                throw new IOException($"Copy command failed: {ex.Message}");  | 
 | 81 | +            }  | 
106 | 82 | 
 
  | 
107 |  | -        private static string GetFolderName(string filePath)  | 
108 |  | -        {  | 
109 |  | -            var folderName = Path.GetDirectoryName(filePath);  | 
 | 83 | +            using StreamReader streamReader = new StreamReader(stdError);  | 
 | 84 | +            while (streamReader.EndOfStream == false)  | 
 | 85 | +            {  | 
 | 86 | +                string error = await streamReader.ReadToEndAsync().ConfigureAwait(false);  | 
 | 87 | +                throw new IOException($"Copy command failed: {error}");  | 
 | 88 | +            }  | 
 | 89 | +        });  | 
 | 90 | + | 
 | 91 | +        string destinationFolder = GetFolderName(destinationFilePath);  | 
 | 92 | + | 
 | 93 | +        return await client.NamespacedPodExecAsync(  | 
 | 94 | +            name,  | 
 | 95 | +            @namespace,  | 
 | 96 | +            container,  | 
 | 97 | +            new string[] { "sh", "-c", $"tar xmf - -C {destinationFolder}" },  | 
 | 98 | +            false,  | 
 | 99 | +            handler,  | 
 | 100 | +            cancellationToken).ConfigureAwait(false);  | 
 | 101 | +    }  | 
110 | 102 | 
 
  | 
111 |  | -            return string.IsNullOrEmpty(folderName) ? "." : folderName;  | 
112 |  | -        }  | 
113 | 103 | 
 
  | 
 | 104 | +    private static string GetFolderName(string filePath)  | 
 | 105 | +    {  | 
 | 106 | +        var folderName = Path.GetDirectoryName(filePath);  | 
114 | 107 | 
 
  | 
 | 108 | +        return string.IsNullOrEmpty(folderName) ? "." : folderName;  | 
115 | 109 |     }  | 
116 | 110 | }  | 
0 commit comments