blob: 13b1f9dbd58c591adb94c9fc74eb2104d5ebdd93 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using Google.Protobuf;
using Grpc.Core;
using Org.Apache.REEF.Bridge.Core.Common.Client;
using Org.Apache.REEF.Bridge.Core.Common.Client.Config.Runtime.Proto;
using Org.Apache.REEF.Bridge.Core.Common.Driver;
using Org.Apache.REEF.Bridge.Core.Grpc.Driver;
using Org.Apache.REEF.Bridge.Core.Proto;
using Org.Apache.REEF.Common.Client;
using Org.Apache.REEF.Common.Files;
using Org.Apache.REEF.Tang.Annotations;
using Org.Apache.REEF.Tang.Formats;
using Org.Apache.REEF.Tang.Implementations.Configuration;
using Org.Apache.REEF.Tang.Interface;
using Org.Apache.REEF.Tang.Util;
using Org.Apache.REEF.Utilities;
using Org.Apache.REEF.Utilities.Logging;
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Org.Apache.REEF.Bridge.Core.Grpc.Client
{
internal sealed class ClientLauncher : IClientLauncher
{
private const string SoFileNameExtension = ".so";
private const string DylibFileNameExtension = ".dylib";
private const string DllFileNameExtension = ".dll";
private const string ExeFileNameExtension = ".exe";
private const string JarFileNameExtension = ".jar";
private const string ConfigFileNameExtension = ".config";
private const string JavaClientLauncherClass = "org.apache.reef.bridge.client.grpc.ClientLauncher";
private const string DriverExe = "Org.Apache.REEF.Bridge.Core.Driver.exe";
private const string DriverDll = "Org.Apache.REEF.Bridge.Core.Driver.dll";
private static readonly string jsonSDK = @"
{
""runtimeOptions"": {
""tfm"": ""netcoreapp2.0"",
""framework"": {
""name"": ""Microsoft.NETCore.App"",
""version"": ""2.0.0""
}
}
}
";
private static readonly Logger Log = Logger.GetLogger(typeof(ClientLauncher));
private readonly ClientService _clientService;
private readonly DriverClientConfiguration _driverClientConfiguration;
private readonly REEFFileNames _reefFileNames;
private readonly IConfigurationSerializer _configurationSerializer;
private readonly JavaClientLauncher _javaClientLauncher;
private readonly Server _grpcServer;
private readonly int _grpcServerPort;
[Inject]
private ClientLauncher(
ClientService clientService,
JavaClientLauncher javaClientLauncher,
REEFFileNames reefFileNames,
IConfigurationSerializer configurationSerializer,
DriverClientParameters driverRuntimeProto,
IRuntimeProtoProvider runtimeProtoProvider)
{
_clientService = clientService;
_javaClientLauncher = javaClientLauncher;
_reefFileNames = reefFileNames;
_configurationSerializer = configurationSerializer;
_driverClientConfiguration = driverRuntimeProto.Proto;
runtimeProtoProvider.SetParameters(_driverClientConfiguration);
_grpcServer = new Server
{
Services = { BridgeClient.BindService(clientService) },
Ports = { new ServerPort("localhost", 0, ServerCredentials.Insecure) }
};
_grpcServer.Start();
Log.Log(Level.Info, "Server port any {0}", _grpcServer.Ports.Any());
foreach (var serverPort in _grpcServer.Ports)
{
Log.Log(Level.Info, "Server port {0}", serverPort.BoundPort);
_grpcServerPort = serverPort.BoundPort;
}
}
public void Dispose()
{
_grpcServer.ShutdownAsync();
}
public async Task<LauncherStatus> SubmitAsync(
IConfiguration driverAppConfiguration,
CancellationToken cancellationToken)
{
var driverClientConfiguration =
Configurations.Merge(driverAppConfiguration,
DriverBridgeConfiguration.ConfigurationModule
.Set(DriverBridgeConfiguration.DriverServiceClient, GenericType<DriverServiceClient>.Class)
.Set(DriverBridgeConfiguration.DriverClientService, GenericType<DriverClientService>.Class)
.Build());
var jobFolder = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
Log.Log(Level.Info, "Job folder {0}", jobFolder);
Directory.CreateDirectory(jobFolder.FullName);
AddDependencies(jobFolder, driverClientConfiguration);
// Launch command
if (File.Exists(DriverExe))
{
_driverClientConfiguration.DriverClientLaunchCommand = string.Format(
@"cmd.exe /c {0} {1}",
Path.Combine(_reefFileNames.GetGlobalFolderPath(), DriverExe),
_reefFileNames.GetClrDriverConfigurationPath());
}
else
{
_driverClientConfiguration.DriverClientLaunchCommand = string.Format(
@"dotnet {0} {1}",
Path.Combine(_reefFileNames.GetGlobalFolderPath(), DriverDll),
_reefFileNames.GetClrDriverConfigurationPath());
}
var driverClientConfigFile = Path.Combine(jobFolder.FullName, "driverclient.json");
using (var outputFile = new StreamWriter(driverClientConfigFile))
{
outputFile.Write(JsonFormatter.Default.Format(_driverClientConfiguration));
}
// Submit a new job
_clientService.Reset();
var task = _javaClientLauncher.LaunchAsync(JavaLoggingSetting.Info,
JavaClientLauncherClass,
new[] { driverClientConfigFile, _grpcServerPort.ToString() },
cancellationToken);
lock (_clientService)
{
while (!_clientService.IsDone && !cancellationToken.IsCancellationRequested)
{
Monitor.Wait(_clientService, TimeSpan.FromMinutes(1));
}
}
await task;
return _clientService.LauncherStatus;
}
private void AddDependencies(FileSystemInfo jobFolder, IConfiguration driverClientConfiguration)
{
// driver client configuration
var driverClientConfigurationFile = Path.GetFullPath(Path.Combine(
jobFolder.FullName,
_reefFileNames.GetClrDriverConfigurationName()));
_configurationSerializer.ToFile(driverClientConfiguration, driverClientConfigurationFile);
_driverClientConfiguration.LocalFiles.Add(driverClientConfigurationFile);
/*
var jsonSDKFile = Path.Combine(jobFolder.FullName, "Org.Apache.REEF.Bridge.Core.Driver.runtimeconfig.json");
File.WriteAllText(jsonSDKFile, jsonSDK);
_driverClientConfiguration.GlobalFiles.Add(jsonSDKFile);
*/
// resource files
var a = typeof(ClientLauncher).Assembly;
foreach (var name in a.GetManifestResourceNames())
{
Log.Log(Level.Info, "Extracting resource {0}", name);
var resource = a.GetManifestResourceStream(name);
using (var file = new FileStream(name, FileMode.Create, FileAccess.Write))
{
resource.CopyTo(file);
}
}
var directory = ClientUtilities.GetPathToExecutingAssembly();
{
if (Directory.Exists(directory))
{
// For input paths that are directories, extract only files of a predetermined type
_driverClientConfiguration.GlobalFiles.Add(
Directory.GetFiles(directory).Where(IsAssemblyToCopy));
}
else
{
// Throw if a path input was not a file or a directory
throw new FileNotFoundException($"Global Assembly Directory not Found: {directory}");
}
}
}
/// <summary>
/// Returns true, if the given file path references a DLL or EXE or JAR.
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
private static bool IsAssemblyToCopy(string filePath)
{
var fileName = Path.GetFileName(filePath);
if (string.IsNullOrWhiteSpace(fileName))
{
return false;
}
var lowerCasePath = fileName.ToLower();
return lowerCasePath.EndsWith(DllFileNameExtension) ||
lowerCasePath.EndsWith(ExeFileNameExtension) ||
lowerCasePath.EndsWith(DylibFileNameExtension) ||
lowerCasePath.EndsWith(SoFileNameExtension) ||
lowerCasePath.EndsWith(ConfigFileNameExtension) ||
lowerCasePath.EndsWith(JarFileNameExtension);
}
}
}