Skip to content

Commit 110fd11

Browse files
authored
[Az.Ssh] June Release: Update Docs and Improve error handling (#21823)
* Make small improvements to Relay Info error messages * Update documentation to mention the requirement to install Az.Ssh.ArcProxy * Improve error handling for Proxy search and AAD cert generation failure * Move Account Type error message to Resources file * Bug: Relau Info not being converted to base64 string
1 parent 9a5b1ca commit 110fd11

File tree

7 files changed

+132
-88
lines changed

7 files changed

+132
-88
lines changed

src/Ssh/Ssh/Common/SshBaseCmdlet.cs

Lines changed: 76 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
using Microsoft.Azure.PowerShell.Ssh.Helpers.HybridConnectivity;
4343
using System.Management.Automation.Host;
4444
using System.Management.Automation.Runspaces;
45-
45+
using System.Collections.ObjectModel;
4646

4747
namespace Microsoft.Azure.Commands.Ssh
4848

@@ -311,12 +311,6 @@ private ResourceManagementClient ResourceManagementClient
311311

312312
protected internal void ValidateParameters()
313313
{
314-
var context = DefaultProfile.DefaultContext;
315-
if (LocalUser == null && context.Account.Type == AzureAccount.AccountType.ServicePrincipal)
316-
{
317-
throw new AzPSArgumentException(Resources.AADLoginForServicePrincipal, nameof(LocalUser));
318-
}
319-
320314
if (Rdp && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
321315
{
322316
throw new AzPSArgumentException(Resources.RDPOnNonWindowsClient, nameof(Rdp));
@@ -454,7 +448,7 @@ protected internal EndpointAccessResource GetRelayInformation()
454448
{
455449
throw new AzPSCloudException(Resources.FailedToCreateDefaultEndpointUnauthorized);
456450
}
457-
throw new AzPSCloudException(String.Format(Resources.FailedToCreateDefaultEndpoint, createEndpointException));
451+
throw new AzPSCloudException(String.Format(Resources.FailedToCreateDefaultEndpoint, createEndpointException.Message));
458452
}
459453

460454
try
@@ -463,13 +457,13 @@ protected internal EndpointAccessResource GetRelayInformation()
463457
}
464458
catch (Exception listCredException)
465459
{
466-
throw new AzPSCloudException(String.Format(Resources.FailedToListCredentials, listCredException));
460+
throw new AzPSCloudException(String.Format(Resources.FailedToListCredentials, listCredException.Message));
467461
}
468462

469463
}
470464
else
471465
{
472-
throw new AzPSCloudException(String.Format(Resources.FailedToListCredentials, exception));
466+
throw new AzPSCloudException(String.Format(Resources.FailedToListCredentials, exception.Message));
473467
}
474468
}
475469
return cred;
@@ -499,16 +493,20 @@ protected internal string GetProxyPath()
499493

500494
if (String.IsNullOrEmpty(proxyPath))
501495
{
502-
System.Collections.ObjectModel.Collection<ChoiceDescription> choices = new System.Collections.ObjectModel.Collection<ChoiceDescription> { new ChoiceDescription("N", "No"), new ChoiceDescription("Y", "Yes") };
496+
Collection<ChoiceDescription> choices = new Collection<ChoiceDescription> {
497+
new ChoiceDescription("N", "No"),
498+
new ChoiceDescription("Y", "Yes")
499+
};
500+
503501
int userChoice = this.Host.UI.PromptForChoice(
504-
caption: $"You currently don't have the required Az.Ssh.ArcProxy module installed in this machine. Would you like us to attempt to install this module for the current user?",
505-
message: "You must have the Az.Ssh.Proxy PowerShell module installed in the client machine in order to connect to Azure Arc resources. You can find the module in the PowerShell Gallery <Link>.",
502+
caption: Resources.InstallProxyModuleCaption,
503+
message: Resources.InstallProxyModuleMessage,
506504
choices: choices,
507505
defaultChoice: 0);
508506
if (userChoice == 1)
509507
{
510508
var installationResults = InvokeCommand.InvokeScript(
511-
script: "Install-module Az.Ssh.ArcProxy -Repository PsGallery -Scope CurrentUser",
509+
script: "Install-module Az.Ssh.ArcProxy -Repository PsGallery -Scope CurrentUser -MaximumVersion 1.9.9 -AllowClobber",
512510
useNewScope: true,
513511
writeToPipeline: PipelineResultTypes.Error,
514512
input: null,
@@ -521,48 +519,9 @@ protected internal string GetProxyPath()
521519

522520
if (!String.IsNullOrEmpty(proxyPath)) { return proxyPath; }
523521

524-
throw new AzPSApplicationException("Failed to find the module Az.Ssh.ArcProxy installed in this machine. You must have the Az.Ssh.Proxy PowerShell module installed in the client machine in order to connect to Azure Arc resources. You can find the module in the PowerShell Gallery <Link>.");
525-
}
526-
527-
private string SearchForInstalledProxyPath()
528-
{
529-
var results = InvokeCommand.InvokeScript(
530-
script: "Get-module -ListAvailable -Name Az.Ssh.ArcProxy");
531-
532-
foreach (var result in results)
533-
{
534-
if (result?.BaseObject is PSModuleInfo moduleInfo)
535-
{
536-
var proxyPath = GetProxyPathInModuleDirectory(moduleInfo.Path);
537-
538-
if (moduleInfo.Version >= new Version("2.0.0"))
539-
{
540-
WriteWarning("This version of the Az.Ssh extension only supports version 1.x.x of the Az.Ssh.ArcProxy PowerShell Module. Check that this extension is the latest version available");
541-
continue;
542-
}
543-
544-
if (!File.Exists(proxyPath))
545-
{
546-
continue;
547-
}
548-
549-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
550-
{
551-
if (!SetExecutePermissionForProxyOnLinux(proxyPath))
552-
{
553-
WriteWarning($"Unable to add Execute permission to SSH Proxy {proxyPath}. The SSH connection will fail if the current user doesn't have permission to execute the SSH proxy file.");
554-
}
555-
}
556-
557-
return proxyPath;
558-
}
559-
560-
}
561-
return null;
522+
throw new AzPSApplicationException(Resources.FailedToFindProxyModule);
562523
}
563524

564-
565-
566525

567526
protected internal void GetVmIpAddress()
568527
{
@@ -691,13 +650,51 @@ protected internal bool IsArc()
691650

692651
#region Private Methods
693652

694-
protected internal bool SetExecutePermissionForProxyOnLinux(string path)
653+
private string SearchForInstalledProxyPath()
654+
{
655+
var results = InvokeCommand.InvokeScript(
656+
script: "Get-module -ListAvailable -Name Az.Ssh.ArcProxy");
657+
658+
foreach (var result in results)
659+
{
660+
if (result?.BaseObject is PSModuleInfo moduleInfo)
661+
{
662+
var proxyPath = GetProxyPathInModuleDirectory(moduleInfo.Path);
663+
664+
if (moduleInfo.Version >= new Version("2.0.0"))
665+
{
666+
WriteWarning(String.Format(Resources.UnsuportedVersionProxyModule, moduleInfo.Path, moduleInfo.Version));
667+
continue;
668+
}
669+
670+
if (!File.Exists(proxyPath))
671+
{
672+
continue;
673+
}
674+
675+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
676+
{
677+
// does this check even work?
678+
if (!SetExecutePermissionForProxyOnLinux(proxyPath))
679+
{
680+
WriteWarning($"Unable to add Execute permission to SSH Proxy {proxyPath}. The SSH connection will fail if the current user doesn't have permission to execute the SSH proxy file.");
681+
}
682+
}
683+
684+
return proxyPath;
685+
}
686+
687+
}
688+
return null;
689+
}
690+
691+
private bool SetExecutePermissionForProxyOnLinux(string path)
695692
{
696693
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
697694
{
698695
try
699696
{
700-
var script = $"chmod +x {path}"; // should we just add permission for the owner? Or all users?
697+
var script = $"chmod +x {path}";
701698
var results = InvokeCommand.InvokeScript(
702699
script: script,
703700
useNewScope: true,
@@ -708,18 +705,16 @@ protected internal bool SetExecutePermissionForProxyOnLinux(string path)
708705
}
709706
catch
710707
{
711-
// If this operation fails we want to warn the user
712708
return false;
713709
}
714710
return true;
715-
//check results somehow?
716711
}
717712
return true;
718713
}
719714

720715
private void SetResourceId()
721716
{
722-
if (ResourceId == null)
717+
if (String.IsNullOrEmpty(ResourceId) && ParameterSetName.Equals(InteractiveParameterSet))
723718
{
724719
ResourceIdentifier id = new ResourceIdentifier();
725720
id.ResourceGroupName = ResourceGroupName;
@@ -787,7 +782,23 @@ private SshCredential GetAccessToken(string publicKeyFile)
787782
{
788783
throw new AzPSApplicationException("Cannot load SshCredentialFactory instance from context.");
789784
}
790-
var token = factory.GetSshCredential(context, parameters);
785+
786+
SshCredential token = null;
787+
788+
try
789+
{
790+
token = factory.GetSshCredential(context, parameters);
791+
}
792+
catch (KeyNotFoundException exception)
793+
{
794+
if (context.Account.Type != AzureAccount.AccountType.User)
795+
{
796+
throw new AzPSApplicationException(String.Format(Resources.FailedToAADUnsupportedAccountType, context.Account.Type));
797+
}
798+
799+
throw new AzPSApplicationException($"Failed to generate AAD certificate with exception: {exception.Message}.");
800+
}
801+
791802
return token;
792803
}
793804

@@ -813,6 +824,11 @@ private List<string> GetSSHCertPrincipals(string certFile)
813824
principals.Add(line.Trim());
814825
}
815826
}
827+
828+
if (!principals.Any())
829+
{
830+
throw new AzPSInvalidOperationException("Unable to find Principals in generated AAD Certificate.");
831+
}
816832
return principals;
817833
}
818834

src/Ssh/Ssh/Properties/Resources.Designer.cs

Lines changed: 36 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)