Skip to content

Conversation

@MichalPavlik
Copy link
Member

@MichalPavlik MichalPavlik commented Mar 25, 2022

Fixes #7372

Context

MSBuild server is a new node that accepts build request from client. This approach avoids spawning a new MSBuild process for every build from CLI tools like .NET SDK.

Changes Made

This PR implements a new node capable to accept and validate pipe connection, receive and invoke build commands, send console messages to client and inform about build result.

Testing

Tests will be added.

Notes

This is only draft as some areas need more care:

  • Intelligent console messages flushing - based on buffer size AND elapsed time since last flush
  • Console messages colorization - we want to use ANSI escape codes for colorization. Right now it's possible to pass -consoleLoggerParameters:ForceConsoleColor parameter from client, but we have to find a better way.
  • Unit tests

Some aspects will be implemented in different PR:

  1. Configurable timeout (nice to have)
  2. Support for build cancellation
  3. Non-interactive console checking - we don't want to emit ASNI escape codes when the stream is redirected

@MichalPavlik MichalPavlik requested review from ladipro and rainersigwald and removed request for ladipro March 25, 2022 10:32
Copy link
Member

@ladipro ladipro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving a few comments inline.

byte? ExpectedVersionInFirstByte { get; }
}

internal readonly struct Handshake : IHandshake
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Better make it a class because the struct will be boxed on the way out of GetHandshake anyway.

}

internal readonly struct Handshake
internal interface IHandshake
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading the sources correctly, the only place where handshake needs to be accessed in a generic way is NodeEndpointOutOfProcBase.GetHandshake. This has exactly one caller in PacketPumpProc and only one method is called on the handshake: RetrieveHandshakeComponents.

So overall it looks like this interface may be an overkill and we could instead have something like RetrieveHandshakeComponents (suggestion: name it GetHandshakeData?) directly on NodeEndpointOutOfProcBase.

Comment on lines 22 to 33
// We currently use 6 bits of this 32-bit integer. Very old builds will instantly reject any handshake that does not start with F5 or 06; slightly old builds always lead with 00.
// This indicates in the first byte that we are a modern build.
_options = (int)nodeType | (CommunicationsUtilities.handshakeVersion << 24);
string? handshakeSalt = Environment.GetEnvironmentVariable("MSBUILDNODEHANDSHAKESALT");
var msBuildFile = new FileInfo(msBuildLocation);
var msBuildDirectory = msBuildFile.DirectoryName;
_salt = ComputeHandshakeHash(handshakeSalt + msBuildDirectory);
Version fileVersion = new Version(FileVersionInfo.GetVersionInfo(msBuildLocation).FileVersion ?? string.Empty);
_fileVersionMajor = fileVersion.Major;
_fileVersionMinor = fileVersion.Minor;
_fileVersionBuild = fileVersion.Build;
_fileVersionRevision = fileVersion.Revision;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Some of this code looks copied from the original Handshake. Do you think it would be worth deduping? By introducing a base class or a helper method maybe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why we need a new handshake at all? The point of the original handshake is that both sides need to come up with the same thing. I don't like the idea of adding a new thing here without good justification.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had same question. Handshake from prototype was a little bit different, but I had to align it with current codebase, so it looks almost same now. The main difference is that server doesn't need session ID. We can remove duplicates by (for example) inheritance - if it's OK to change the original handshake from value type to reference type.

cc: @rokonec

@danmoseley
Copy link
Member

I didn't review the code but it's of course critical that the CLI-MSBuild pipe is tested to ensure it's secured in the same way as the MSBuild-MSBUild pipes are: the user at both ends must be the same user and (on Windows) elevation level.

In .NET Core there's API to do this: while MSBuild builds against .NET Framework it has to continue to do it manually.

@MichalPavlik
Copy link
Member Author

Hello @danmoseley, client-server communication uses same IPC infrastructure with user and elevation checking as the current nodes. It's implemented in base class and we didn't change it.

string serverRunningMutexName = $@"Global\server-running-{pipeName}";
_serverBusyMutexName = $@"Global\server-busy-{pipeName}";

// TODO: shall we address possible race condition. It is harmless as it, with acceptable probability, just cause unnecessary process spawning
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This race condition will be most probably handled by client. Please change this command to describe our decision about how will client handle it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There would be mutex "Global\server-launch-{_pipeName}" for starting server process in a client. This does not guarantee that some other client, if anybody writes it, would not introduce a race condition, so the fast quit from server process in this case is still needed.

@rokonec rokonec changed the base branch from main to feature/msbuild-server April 21, 2022 09:00
@rokonec rokonec changed the title MSBuild server node [WIP-FEATURE] MSBuild server node Apr 21, 2022
@rokonec rokonec marked this pull request as ready for review April 21, 2022 09:19
@Forgind
Copy link
Contributor

Forgind commented Apr 21, 2022

If this is no longer a WIP, can you remove the [WIP-FEATURE] in the title?

Looks like the test failures are from an overload of GetHandshakeOptions not being found.

@MichalPavlik
Copy link
Member Author

@Forgind, we marked it as WIP as we will merge the code to the feature branch with the client implementation. It will make the work more efficient and we will continue with changes.

@MichalPavlik MichalPavlik merged commit b0a788d into dotnet:feature/msbuild-server Apr 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MSBuild Server] Implement communication protocol in server

6 participants