in src/dsc/Commands/Connect/ConnectCommand.cs [394:486]
private async Task<(ExitCode, string)> ExecuteInnerAsync(IConnectManagementClient connectManagementClient, Action workloadStartedHandler, CancellationToken cancellationToken, IRoutingManagementClient routingManagementClient = null)
{
try
{
if (!string.IsNullOrEmpty(_routingHeaderValue))
{
await routingManagementClient.DeployRoutingManagerAsync(cancellationToken);
}
var remoteAgentInfo = await connectManagementClient.StartRemoteAgentAsync(cancellationToken);
var remoteAgentLocalPort = await connectManagementClient.ConnectToRemoteAgentAsync(remoteAgentInfo, cancellationToken);
if (!string.IsNullOrEmpty(_routingHeaderValue))
{
// If routing is enabled, wait until the routing manager is connected to say the connection has been established successfully.
var routingStatus = await routingManagementClient.GetStatusAsync(remoteAgentInfo.PodName, cancellationToken);
if (routingStatus.Value.IsConnected == null)
{
_log.Error(routingStatus.Value.ErrorMessage);
throw new UserVisibleException(_operationContext, Resources.FailedToGetRoutingManagerDeploymentStatusFormat, string.Format(CommonResources.CorrelationIdErrorMessageFormat, _operationContext.CorrelationId));
}
else if (routingStatus.Value.IsConnected == false)
{
throw new UserVisibleException(_operationContext, Resources.FailedToGetRoutingManagerDeploymentStatusRanOutOfTimeFormat, routingStatus.Value.ErrorMessage + string.Format(CommonResources.CorrelationIdErrorMessageFormat, _operationContext.CorrelationId));
}
}
this.ReportProgress(EventLevel.Informational, Resources.Progress_ConnectionEstablished);
// Map ports for reverse port forwarding, and ports and IPs for service port forwardings
await connectManagementClient.AddLocalMappingsAsync(_localPorts, _elevationRequests, cancellationToken);
var workloadInfo = await connectManagementClient.GetWorkloadInfo();
await connectManagementClient.StartServicePortForwardingsAsync(remoteAgentLocalPort, workloadInfo.ReachableEndpoints, workloadInfo.ReversePortForwardInfo, cancellationToken);
var envVars = await connectManagementClient.GetLocalEnvironment(_localPorts, cancellationToken);
if (!string.IsNullOrEmpty(_envJsonPath))
{
_fileSystem.Value.WriteAllTextToFile(_envJsonPath, JsonHelpers.SerializeObjectIndented(envVars));
}
this.ReportProgress(EventLevel.LogAlways, $"##################### {Resources.Progress_EnvironmentStarted} #############################################################");
if (string.IsNullOrEmpty(_updateScript))
{
var consoleProcess = _consoleLauncher.Value.LaunchTerminalWithEnv(envVars, _envScriptPath, launchCommand: _commandLineArgumentsManager.CommandExecuteArguments);
_waitProcesses.Add(consoleProcess);
}
else
{
_consoleLauncher.Value.LaunchTerminalWithEnv(envVars, _envScriptPath, performLaunch: false);
}
this.ReportProgress(EventLevel.LogAlways, string.Format(Resources.Progress_RunScriptToConnect, _envScriptPath));
workloadStartedHandler();
while (!cancellationToken.IsCancellationRequested)
{
if (_waitProcesses.Any() && !_waitProcesses.Where(p => !p.HasExited).Any())
{
// all waitProcesses are terminated.
break;
}
cancellationToken.WaitHandle.WaitOne(1000);
}
return (ExitCode.Success, string.Empty);
}
catch (OperationCanceledException)
{
// Expected for StopConnect scenario. Message has been logged. Continue.
return (ExitCode.Success, string.Empty);
}
catch (Exception e) when (base._sdkErrorHandling.TryHandleKnownException(e, CliConstants.Dependency.ServiceRunPortForward, out string failureReason))
{
// Message has been logged. Continue.
return (ExitCode.Fail, failureReason);
}
catch (Exception ex)
{
if (!(ex is TaskCanceledException) && !(ex is OperationCanceledException))
{
_log.Error($"ServiceConnectCommand.ExecuteInnerAsync caught exception {ex.ToString()}");
_out.Error(Resources.Error_ConnectOperationFailed);
}
throw;
}
finally
{
// We attempt to restore remote workload and stop all port forward connections regardless of success/failure of the operation.
// In case of a failure we attempt to restore as much as possible and some of the restore/stop workflows might be essentially no-op,
// example if remote agent connection fails, there is no local workload connection to close because the port forwarding connections
// have not been made and no local IPs have been allocated for remote services.
this.ReportProgress(EventLevel.LogAlways, Resources.Progress_StoppingWorkload);
await Task.WhenAll(connectManagementClient.RestoreOriginalRemoteContainerAsync(CancellationToken.None),
connectManagementClient.StopLocalConnectionAsync(CancellationToken.None));
_cleanupPerformed = true;
}
}