Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to feature/egressExtension Part 1 #2748

Conversation

kkeirstead
Copy link
Member

Summary

Part 1 of my updates to the feature/egressExtension branch - I pulled out some things to keep this PR smaller, as well as areas that I'm still working through. I'll leave comments throughout the code to explain different things that I think are worth pointing out or that I've cut out (for now). Builds on top of #1953.

Release Notes Entry

kkeirstead and others added 30 commits October 18, 2022 11:50
… addition to supporting writing configuration in the main location
… - this did require (for now) some duplication of files
…d wiring up the fourth location (.dotnet\tools) to check for extensions
…ol install to be the landing site for third party extensions - needs refinement (currently uses some hard-coded values)
@kkeirstead kkeirstead requested a review from a team as a code owner October 20, 2022 19:16
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Copy link
Member Author

Choose a reason for hiding this comment

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

We aren't doing it yet, but in the future we'll be moving this to the new extensions repo

/// <summary>
/// Custom metadata of the blob to be created.
/// </summary>
public Dictionary<string, string> CustomMetadata { get; }
Copy link
Member Author

Choose a reason for hiding this comment

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

Not currently being populated (I'll mention more about this in another comment)


namespace Microsoft.Diagnostics.Tools.Monitor.Egress
{
/// <summary>
/// Egress provider options for external egress providers.
/// </summary>
internal sealed partial class ExtensionEgressProviderOptions :
Dictionary<string, string>,
Dictionary<string, object>,
Copy link
Member Author

Choose a reason for hiding this comment

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

This isn't implemented in this PR, but in the initial iteration of this design we were assuming that we could treat all of our extension's configuration as a Dictionary<string, string>. The addition of the Azure provider's Metadata (used for custom metadata) breaks this assumption, and will require changes to how we pass the configuration to the extension. To simplify this PR, I am not currently passing the Metadata section of configuration, but this will be fixed in a future PR.

@@ -12,7 +12,7 @@
using Microsoft.Diagnostics.Monitoring.TestCommon.Fixtures;
using Microsoft.Diagnostics.Monitoring.WebApi;
using Microsoft.Diagnostics.Tools.Monitor.Egress;
using Microsoft.Diagnostics.Tools.Monitor.Egress.AzureBlob;
//using Microsoft.Diagnostics.Tools.Monitor.Egress.AzureBlob;
Copy link
Member Author

Choose a reason for hiding this comment

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

(Relevant to the whole file) For the sake of simplicity, the tests for Azure egress aren't enabled in this PR. These will be re-integrated in a future PR, as well as hopefully more testing specifically around the end-to-end extension experience.

@@ -34,7 +34,23 @@ public void Configure(string name, TOptions options)
IConfigurationSection providerOptionsSection = providerTypeSection.GetSection(name);
if (providerOptionsSection.Exists())
{
providerOptionsSection.Bind(options);
if (options is ExtensionEgressProviderOptions extensionOptions)
Copy link
Member Author

Choose a reason for hiding this comment

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

This is where we'll need to handle Metadata (and anything else that doesn't have a value for a child).


bool isDotnetToolsLocation = _targetFolder == HostBuilderSettings.ExtensionDirectoryPath;

// Special case -> need to look in particular path for dotnet tool installation
Copy link
Member Author

Choose a reason for hiding this comment

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

This logic is for the dotnet tool install scenario, so that users don't need to manually place an extension downloaded from Nuget into the right directory. This works in my limited testing (building a nuget package locally, and then calling dotnet tool install --add-source... on it), but I think this area may need some more refinement going forward.

QueueDoesNotExist = 57,
QueueOptionsPartiallySet = 58,
WritingMessageToQueueFailed = 59,
MonitorApiKeyNotConfigured = 56, // Note the gap - from removing things related to Azure egress
Copy link
Member Author

Choose a reason for hiding this comment

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

Will we want to update all of these numbers to be in-order again? I haven't for now, but we have several gaps left behind by the logging specific to the Azure extension.

Copy link
Member

Choose a reason for hiding this comment

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

Do not remove or reorder anything here. Just add a comment after then that they've moved to the extension.

IDirectoryContents extensionDir = _fileSystem.GetDirectoryContents(extensionName);
string extensionPath = string.Empty;

bool isDotnetToolsLocation = _targetFolder == HostBuilderSettings.ExtensionDirectoryPath;
Copy link
Member

Choose a reason for hiding this comment

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

  • If you aren't guaranteed that _targetFolder is an absolute path, you'll want to resolve it.
  • If on Windows, paths are case insensitive.
Suggested change
bool isDotnetToolsLocation = _targetFolder == HostBuilderSettings.ExtensionDirectoryPath;
bool isDotnetToolsLocations = string.Equals(
Path.GetFullPath(_targetFolder),
Path.GetFullPath(HostBuilderSettings.ExtensionDirectoryPath),
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal);

Consider adding a helper method such as ArePathsEqual to help simplify this suggested code.

Comment on lines +13 to +17
<!--
Workaround for https://github.com/dotnet/aspnetcore/issues/42200
Required as of 7.0 Preview 5 SDK
-->
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
<!--
Workaround for https://github.com/dotnet/aspnetcore/issues/42200
Required as of 7.0 Preview 5 SDK
-->
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>

I think this should be reverted, see #2700

Comment on lines 148 to 152
if (configDict.ContainsKey(propKey))
{
return configDict[propKey];
return configDict[propKey].ToString();
}
return null;
Copy link
Member

@schmittjoseph schmittjoseph Oct 20, 2022

Choose a reason for hiding this comment

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

Suggested change
if (configDict.ContainsKey(propKey))
{
return configDict[propKey];
return configDict[propKey].ToString();
}
return null;
if (configDict.TryGetValue(propKey, out object propValue))
{
return propValue.ToString();
}
return null;

suggestion: can update this to only access the dictionary once

@@ -0,0 +1,25 @@

Copy link
Member

Choose a reason for hiding this comment

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

Remove this and add the AzureBlobStorage project to the dotnet-monitor.sln file if it already doesn't exist.

{
private int BlobStorageBufferSize = 4 * 1024 * 1024;
private readonly string AzureBlobStorage = "AzureBlobStorage";
Copy link
Member

Choose a reason for hiding this comment

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

This should be moved to some kind of shared constant because it is used in the same way both here and in the Program class.

{
private int BlobStorageBufferSize = 4 * 1024 * 1024;
private readonly string AzureBlobStorage = "AzureBlobStorage";
protected ILogger Logger { get; }
Copy link
Member

Choose a reason for hiding this comment

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

This should be a private field.

static async Task<int> Main(string[] args)
{
// Expected command line format is: AzureBlobStorage.exe Egress --Provider-Name MyProviderEndpointName
RootCommand rootCommand = new RootCommand("Egresses an artifact to Azure Storage.");
using var loggerFactory = LoggerFactory.Create(builder =>
Copy link
Member

Choose a reason for hiding this comment

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

This should be done in the Egress method and not stored as static state on the Program class.

@@ -0,0 +1,6 @@
# Code of Conduct
Copy link
Member

Choose a reason for hiding this comment

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

Do not create a separate file here. This is still part of the dotnet-monitor repo so it should be using the files at the root.

@@ -0,0 +1,23 @@
The MIT License (MIT)
Copy link
Member

Choose a reason for hiding this comment

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

Do not create a separate license file here. This is still part of the dotnet-monitor repo so it should be using the files at the root.

@kkeirstead
Copy link
Member Author

Closing this PR in favor of breaking things down even further for ease of review. I will incorporate the feedback already left on this PR into my changes.

@kkeirstead kkeirstead closed this Oct 21, 2022
providerOptionsSection.Bind(options);
if (options is ExtensionEgressProviderOptions extensionOptions)
{
var children = providerOptionsSection.GetChildren();
Copy link
Member

Choose a reason for hiding this comment

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

Why is this needed? Are you working around this issue? dotnet/runtime#77246

@@ -43,8 +42,7 @@ public ExtensionEgressProvider(IEgressPropertiesProvider propertyProvider, Exten
{
Settings = artifactSettings,
Configuration = options,
Properties = _propertyProvider.GetAllProperties(),
ProviderName = providerName,
Copy link
Member

Choose a reason for hiding this comment

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

Why is the provider name being removed?

@@ -42,6 +44,16 @@ internal sealed class HostBuilderSettings
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "." + ProductFolderName) :
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ProductFolderName));

// Location where extensions are stored by default.
// Windows: "%USERPROFILE%\.dotnet\Tools"
// Other: "%XDG_CONFIG_HOME%/dotnet/tools" OR "%HOME%/.config/dotnet/tools" -> IS THIS RIGHT?
Copy link
Member

Choose a reason for hiding this comment

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

It appears to be the same as on Windows:

jander@DESKTOP-N8NH8I6:~/.dotnet/tools$ ls
dotnet-dump  dotnet-monitor  dotnet-sos  dotnet-trace

IDirectoryContents extensionDir = _fileSystem.GetDirectoryContents(extensionName);
string extensionPath = string.Empty;

bool isDotnetToolsLocation = _targetFolder == HostBuilderSettings.ExtensionDirectoryPath;
Copy link
Member

Choose a reason for hiding this comment

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

I think you should have a separate ExtensionRepository implementation for the dotnet tools folder since its algorithm is very much different than the FolderExtensionRepository implementation.

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.

3 participants