Browse Source

Check for kubectl connectedness and give better error

- Checking for kubectl
- Checking for a cluster
- More in depth docker validation
davidfowl/dependencies
Ryan Nowak 7 years ago
parent
commit
5edd3f9904
  1. 10
      src/Tye.Core/BuildDockerImageStep.cs
  2. 10
      src/Tye.Core/DeployServiceYamlStep.cs
  3. 10
      src/Tye.Core/Tye.Core.csproj
  4. 11
      src/Tye.Hosting/DockerRunner.cs
  5. 5
      src/Tye.Hosting/Tye.Hosting.csproj
  6. 52
      src/shared/DockerDetector.cs
  7. 54
      src/shared/KubectlDetector.cs
  8. 0
      src/shared/NameSanitizer.cs
  9. 2
      src/shared/ProcessResult.cs
  10. 2
      src/shared/ProcessUtil.cs
  11. 0
      src/shared/TempDirectory.cs
  12. 0
      src/shared/TempFile.cs
  13. 10
      src/tye/Program.DeployCommand.cs
  14. 11
      src/tye/tye.csproj
  15. 2
      test/E2ETest/E2ETest.csproj

10
src/Tye.Core/BuildDockerImageStep.cs

@ -29,6 +29,16 @@ namespace Tye
return;
}
if (!await DockerDetector.Instance.IsDockerInstalled.Value)
{
throw new CommandException($"Cannot generate a docker image for '{service.Service.Name}' because docker is not installed.");
}
if (!await DockerDetector.Instance.IsDockerConnectedToDaemon.Value)
{
throw new CommandException($"Cannot generate a docker image for '{service.Service.Name}' because docker is not running.");
}
await DockerContainerBuilder.BuildContainerImageAsync(output, application, service, project, container);
}
}

10
src/Tye.Core/DeployServiceYamlStep.cs

@ -26,6 +26,16 @@ namespace Tye
return;
}
if (!await KubectlDetector.Instance.IsKubectlInstalled.Value)
{
throw new CommandException($"Cannot apply manifests for '{service.Service.Name}' because kubectl is not installed.");
}
if (!await KubectlDetector.Instance.IsKubectlConnectedToCluster.Value)
{
throw new CommandException($"Cannot apply manifests for '{service.Service.Name}' because kubectl is not connected to a cluster.");
}
using var tempFile = TempFile.Create();
output.WriteDebugLine($"Writing output to '{tempFile.FilePath}'.");

10
src/Tye.Core/Tye.Core.csproj

@ -10,6 +10,7 @@
<ItemGroup>
<PackageReference Include="KubernetesClient" Version="1.6.11" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="semver" Version="2.0.6" />
<PackageReference Include="Sln" Version="0.3.0" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20071.2" />
@ -24,8 +25,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="..\tye\TempDirectory.cs" Link="TempDirectory.cs" />
<Compile Include="..\tye\TempFile.cs" Link="TempFile.cs" />
<Compile Include="..\shared\DockerDetector.cs" Link="DockerDetector.cs" />
<Compile Include="..\shared\KubectlDetector.cs" Link="KubectlDetector.cs" />
<Compile Include="..\shared\NameSanitizer.cs" Link="NameSanitizer.cs" />
<Compile Include="..\shared\ProcessUtil.cs" Link="ProcessUtil.cs" />
<Compile Include="..\shared\ProcessResult.cs" Link="ProcessResult.cs" />
<Compile Include="..\shared\TempDirectory.cs" Link="TempDirectory.cs" />
<Compile Include="..\shared\TempFile.cs" Link="TempFile.cs" />
</ItemGroup>
<ItemGroup>

11
src/Tye.Hosting/DockerRunner.cs

@ -15,7 +15,6 @@ namespace Tye.Hosting
public class DockerRunner : IApplicationProcessor
{
private readonly ILogger _logger;
private readonly Lazy<Task<bool>> _dockerInstalled = new Lazy<Task<bool>>(DetectDockerInstalled);
public DockerRunner(ILogger logger)
{
@ -51,7 +50,7 @@ namespace Tye.Hosting
private async Task StartContainerAsync(Application application, Service service, DockerRunInfo docker)
{
if (!await _dockerInstalled.Value)
if (!await DockerDetector.Instance.IsDockerInstalled.Value)
{
_logger.LogError("Unable to start docker container for service {ServiceName}, Docker is not installed.", service.Description.Name);
@ -59,6 +58,14 @@ namespace Tye.Hosting
return;
}
if (!await DockerDetector.Instance.IsDockerConnectedToDaemon.Value)
{
_logger.LogError("Unable to start docker container for service {ServiceName}, Docker is not running.", service.Description.Name);
service.Logs.OnNext($"Unable to start docker container for service {service.Description.Name}, Docker is not running.");
return;
}
var serviceDescription = service.Description;
var environmentArguments = "";

5
src/Tye.Hosting/Tye.Hosting.csproj

@ -15,7 +15,10 @@
</ItemGroup>
<ItemGroup>
<Compile Include="..\tye\NameSanitizer.cs" Link="NameSanitizer.cs" />
<Compile Include="..\shared\DockerDetector.cs" Link="DockerDetector.cs" />
<Compile Include="..\shared\NameSanitizer.cs" Link="NameSanitizer.cs" />
<Compile Include="..\shared\ProcessUtil.cs" Link="ProcessUtil.cs" />
<Compile Include="..\shared\ProcessResult.cs" Link="ProcessResult.cs" />
</ItemGroup>
<ItemGroup>

52
src/shared/DockerDetector.cs

@ -0,0 +1,52 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading.Tasks;
namespace Tye
{
internal class DockerDetector
{
public static DockerDetector Instance { get; } = new DockerDetector();
private DockerDetector()
{
IsDockerInstalled = new Lazy<Task<bool>>(DetectDockerInstalled);
IsDockerConnectedToDaemon = new Lazy<Task<bool>>(DetectDockerConnectedToDaemon);
}
public Lazy<Task<bool>> IsDockerInstalled { get; }
public Lazy<Task<bool>> IsDockerConnectedToDaemon { get; }
private async Task<bool> DetectDockerInstalled()
{
try
{
await ProcessUtil.RunAsync("docker", "version", throwOnError: false);
return true;
}
catch (Exception)
{
// Unfortunately, process throws
return false;
}
}
private async Task<bool> DetectDockerConnectedToDaemon()
{
try
{
var result = await ProcessUtil.RunAsync("docker", "version", throwOnError: false);
return result.ExitCode == 0;
}
catch (Exception)
{
// Unfortunately, process throws
return false;
}
}
}
}

54
src/shared/KubectlDetector.cs

@ -0,0 +1,54 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading.Tasks;
namespace Tye
{
internal class KubectlDetector
{
public static KubectlDetector Instance { get; } = new KubectlDetector();
private KubectlDetector()
{
IsKubectlInstalled = new Lazy<Task<bool>>(DetectKubectlInstalled);
IsKubectlConnectedToCluster = new Lazy<Task<bool>>(DetectKubectlConnectedToCluster);
}
public Lazy<Task<bool>> IsKubectlInstalled { get; }
public Lazy<Task<bool>> IsKubectlConnectedToCluster { get; }
private static async Task<bool> DetectKubectlInstalled()
{
try
{
// Ignoring the exit code and relying on Process to throw if kubectl is not found
// kubectl version will return non-zero if you're not connected to a cluster.
await ProcessUtil.RunAsync("kubectl", "version", throwOnError: false);
return true;
}
catch (Exception)
{
// Unfortunately, process throws
return false;
}
}
private static async Task<bool> DetectKubectlConnectedToCluster()
{
try
{
var result = await ProcessUtil.RunAsync("kubectl", "cluster-info", throwOnError: false);
return result.ExitCode == 0;
}
catch (Exception)
{
// Unfortunately, process throws
return false;
}
}
}
}

0
src/tye/NameSanitizer.cs → src/shared/NameSanitizer.cs

2
src/Tye.Hosting/Infrastructure/ProcessResult.cs → src/shared/ProcessResult.cs

@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Tye.Hosting
namespace Tye
{
internal class ProcessResult
{

2
src/Tye.Hosting/Infrastructure/ProcessUtil.cs → src/shared/ProcessUtil.cs

@ -11,7 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using Mono.Unix.Native;
namespace Tye.Hosting
namespace Tye
{
internal static class ProcessUtil
{

0
src/tye/TempDirectory.cs → src/shared/TempDirectory.cs

0
src/tye/TempFile.cs → src/shared/TempFile.cs

10
src/tye/Program.DeployCommand.cs

@ -161,6 +161,16 @@ namespace Tye
await ApplicationYamlWriter.WriteAsync(output, writer, application);
}
if (!await KubectlDetector.Instance.IsKubectlInstalled.Value)
{
throw new CommandException($"Cannot apply manifests because kubectl is not installed.");
}
if (!await KubectlDetector.Instance.IsKubectlConnectedToCluster.Value)
{
throw new CommandException($"Cannot apply manifests because kubectl is not connected to a cluster.");
}
output.WriteDebugLine("Running 'kubectl apply'.");
output.WriteCommandLine("kubectl", $"apply -f \"{tempFile.FilePath}\"");
var capture = output.Capture();

11
src/tye/tye.csproj

@ -10,12 +10,23 @@
<IsPackable>true</IsPackable>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\shared\DockerDetector.cs" Link="DockerDetector.cs" />
<Compile Include="..\shared\KubectlDetector.cs" Link="KubectlDetector.cs" />
<Compile Include="..\shared\NameSanitizer.cs" Link="NameSanitizer.cs" />
<Compile Include="..\shared\ProcessUtil.cs" Link="ProcessUtil.cs" />
<Compile Include="..\shared\ProcessResult.cs" Link="ProcessResult.cs" />
<Compile Include="..\shared\TempDirectory.cs" Link="TempDirectory.cs" />
<Compile Include="..\shared\TempFile.cs" Link="TempFile.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Tye.Hosting\Tye.Hosting.csproj" />
<ProjectReference Include="..\Tye.Core\Tye.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20104.2" />
<PackageReference Include="YamlDotNet" Version="8.0.0" />
</ItemGroup>

2
test/E2ETest/E2ETest.csproj

@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\src\tye\TempDirectory.cs" Link="TempDirectory.cs" />
<Compile Include="..\..\src\shared\TempDirectory.cs" Link="TempDirectory.cs" />
</ItemGroup>
<ItemGroup>

Loading…
Cancel
Save