Skip to content

Commit b8ffaf1

Browse files
committed
Merge pull request Azure#1252 from vadimp-msft/dev
MSFT 4811945: [LIVESITE BLOCKING][HOTFIX] VMProvisioning: Collection creation often fails because service-account limit on domain-join too low, and we don't clean-up AD accounts
2 parents 1588e5b + 839ff7b commit b8ffaf1

14 files changed

+587
-1
lines changed

src/ServiceManagement/RemoteApp/Commands.RemoteApp.Test/Commands.RemoteApp.Test.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
</ItemGroup>
4141
<ItemGroup>
4242
<Compile Include="Collection\RemoteAppCollection.cs" />
43+
<Compile Include="Common\MockAdHelper.cs" />
4344
<Compile Include="Common\VmObjects.cs" />
4445
<Compile Include="Common\CollectionObjects.cs" />
4546
<Compile Include="Common\MockObject.cs" />
@@ -154,6 +155,8 @@
154155
<HintPath>..\..\..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
155156
</Reference>
156157
<Reference Include="System" />
158+
<Reference Include="System.DirectoryServices" />
159+
<Reference Include="System.DirectoryServices.Protocols" />
157160
<Reference Include="System.Management.Automation" />
158161
<Reference Include="System.Net" />
159162
<Reference Include="System.Net.Http" />
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.DirectoryServices;
4+
using System.Linq;
5+
using System.Management.Automation;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using Microsoft.WindowsAzure.Management.RemoteApp.Cmdlets;
9+
using Microsoft.WindowsAzure.Management.RemoteApp.Models;
10+
11+
namespace Microsoft.WindowsAzure.Commands.RemoteApp.Test.Common
12+
{
13+
class MockAdHelper : IAdHelper
14+
{
15+
internal const string CN = "cn";
16+
17+
internal IList<DirectoryEntry> entries = new List<DirectoryEntry>();
18+
19+
public class MockDirectoryEntry : DirectoryEntry
20+
{
21+
private string cn;
22+
23+
public MockDirectoryEntry(string cn)
24+
{
25+
this.cn = cn;
26+
}
27+
28+
public string MockCN
29+
{
30+
get
31+
{
32+
return cn;
33+
}
34+
}
35+
}
36+
37+
public IList<DirectoryEntry> GetVmAdEntries(string domainName, string OU, string vmNamePrefix, PSCredential credential)
38+
{
39+
return entries;
40+
}
41+
42+
43+
public string GetCN(DirectoryEntry dirEntry)
44+
{
45+
string entryCN = null;
46+
if(dirEntry is MockDirectoryEntry)
47+
{
48+
entryCN = (dirEntry as MockDirectoryEntry).MockCN;
49+
}
50+
else
51+
{
52+
entryCN = dirEntry.Properties[MockAdHelper.CN][0].ToString();
53+
}
54+
55+
return entryCN;
56+
}
57+
58+
public void DeleteEntry(DirectoryEntry dirEntry)
59+
{
60+
// do nothing
61+
}
62+
63+
public void SetEntries(string[] ObjNames)
64+
{
65+
entries.Clear();
66+
foreach(string objName in ObjNames)
67+
{
68+
entries.Add(new MockDirectoryEntry(objName));
69+
}
70+
}
71+
}
72+
}

src/ServiceManagement/RemoteApp/Commands.RemoteApp.Test/Common/RemoteAppClient.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace Microsoft.WindowsAzure.Commands.RemoteApp.Test
2424
using System.Threading;
2525
using System.Threading.Tasks;
2626
using Microsoft.Azure;
27+
using Microsoft.WindowsAzure.Commands.RemoteApp.Test.Common;
2728

2829

2930
public class RemoteAppClientCredentials : SubscriptionCloudCredentials
@@ -96,6 +97,7 @@ protected RemoteAppClientTest()
9697
{
9798
CommandRuntime = mockCommandRuntime,
9899
Client = remoteAppManagementClientMock.Object,
100+
ActiveDirectoryHelper = new MockAdHelper(),
99101
MgmtClient = mgmtClient.Object
100102
};
101103

src/ServiceManagement/RemoteApp/Commands.RemoteApp.Test/Common/VmObjects.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,50 @@ public static int SetUpDefaultRemoteAppVm(Mock<IRemoteAppManagementClient> clien
7070

7171
return mockVmList.Count;
7272
}
73+
74+
public static int SetUpStaleVmObjectsTest(Mock<IRemoteAppManagementClient> clientMock, string collectionName, string[] vmNames)
75+
{
76+
CollectionVmsListResult response = new CollectionVmsListResult();
77+
ActiveDirectoryConfigResult getAdResponse = new ActiveDirectoryConfigResult()
78+
{
79+
ActiveDirectoryConfig = new ActiveDirectoryConfig()
80+
{
81+
DomainName = "contoso.com",
82+
OrganizationalUnit = null,
83+
UserName = "user",
84+
Password = "********"
85+
}
86+
};
87+
88+
response.Vms = new List<RemoteAppVm>();
89+
foreach(string vmName in vmNames)
90+
{
91+
response.Vms.Add(new RemoteAppVm()
92+
{
93+
VirtualMachineName = vmName,
94+
LoggedOnUserUpns = { }
95+
});
96+
};
97+
98+
mockVmList = new List<RemoteAppVm>();
99+
foreach (RemoteAppVm vm in response.Vms)
100+
{
101+
RemoteAppVm mockVm = new RemoteAppVm()
102+
{
103+
VirtualMachineName = vm.VirtualMachineName,
104+
LoggedOnUserUpns = vm.LoggedOnUserUpns
105+
};
106+
mockVmList.Add(mockVm);
107+
}
108+
109+
ISetup<IRemoteAppManagementClient, Task<CollectionVmsListResult>> setup = clientMock.Setup(c => c.Collections.ListVmsAsync(collectionName, It.IsAny<CancellationToken>()));
110+
setup.Returns(Task.Factory.StartNew(() => response));
111+
112+
ISetup<IRemoteAppManagementClient, Task<ActiveDirectoryConfigResult>> setupGetAd = clientMock.Setup(c => c.Collections.GetAdAsync(collectionName, It.IsAny<CancellationToken>()));
113+
setupGetAd.Returns(Task.Factory.StartNew(() => getAdResponse));
114+
115+
return mockVmList.Count;
116+
}
117+
73118
}
74119
}

src/ServiceManagement/RemoteApp/Commands.RemoteApp.Test/Vm/RemoteAppVm.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,58 @@ public void GetVm()
111111
Assert.Equal<string>(vmName, resultVms[0].VirtualMachineName);
112112
Assert.Equal<string>(loggedInUserUpn, resultVms[0].LoggedOnUserUpns[0]);
113113
}
114+
115+
[Fact]
116+
[Trait(Category.AcceptanceType, Category.CheckIn)]
117+
public void GetStaleAdVmObjects()
118+
{
119+
int countOfExpectedVms = 0;
120+
GetAzureRemoteAppVmStaleAdObject mockCmdlet = SetUpTestCommon<GetAzureRemoteAppVmStaleAdObject>();
121+
IEnumerable<string> result = null;
122+
IList<string> resulAdObjs = null;
123+
124+
string[] existingVms = new string[] {"abcdefgh0003", "abcdefgh0004", "abcdefgh0005"};
125+
string[] adObjects = new string[] { "abcdefgh0000", "abcdefgh0002", "abcdefgh0003", "abcdefgh0004", "abcdefgh0005", "abcdefgh0006" };
126+
string[] expectedResult = new string[] { "abcdefgh0000", "abcdefgh0002" };
127+
128+
// Required parameters for this test
129+
mockCmdlet.CollectionName = collectionName;
130+
131+
// Setup the environment for testing this cmdlet
132+
countOfExpectedVms = MockObject.SetUpStaleVmObjectsTest(
133+
remoteAppManagementClientMock,
134+
collectionName,
135+
existingVms
136+
);
137+
138+
if(mockCmdlet.ActiveDirectoryHelper is MockAdHelper)
139+
{
140+
(mockCmdlet.ActiveDirectoryHelper as MockAdHelper).SetEntries(adObjects);
141+
}
142+
143+
mockCmdlet.ResetPipelines();
144+
145+
Log("Calling Get-AzureRemoteAppVmStaleAdObjects which should return list of stale Vm objects.");
146+
147+
mockCmdlet.ExecuteCmdlet();
148+
if (mockCmdlet.runTime().ErrorStream.Count != 0)
149+
{
150+
Assert.True(false,
151+
String.Format("Get-AzureRemoteAppVmStaleAdObjects returned the following error {0}.",
152+
mockCmdlet.runTime().ErrorStream[0].Exception.Message
153+
)
154+
);
155+
}
156+
157+
result = LanguagePrimitives.GetEnumerable(mockCmdlet.runTime().OutputPipeline).Cast<string>();
158+
159+
Assert.NotNull(result);
160+
Assert.Equal(expectedResult.Length, result.Count());
161+
162+
foreach (string staleObj in result)
163+
{
164+
Assert.True(expectedResult.Contains(staleObj));
165+
}
166+
}
114167
}
115168
}

src/ServiceManagement/RemoteApp/Commands.RemoteApp/Commands.RemoteApp.Designer.cs

Lines changed: 37 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ServiceManagement/RemoteApp/Commands.RemoteApp/Commands.RemoteApp.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@
136136
</Reference>
137137
<Reference Include="System" />
138138
<Reference Include="System.Core" />
139+
<Reference Include="System.DirectoryServices" />
140+
<Reference Include="System.DirectoryServices.Protocols" />
139141
<Reference Include="System.Management.Automation" />
140142
<Reference Include="System.Net" />
141143
<Reference Include="System.Net.Http" />
@@ -186,10 +188,13 @@
186188
<DesignTime>True</DesignTime>
187189
<DependentUpon>Commands.RemoteApp.resx</DependentUpon>
188190
</Compile>
191+
<Compile Include="Common\AdHelper.cs" />
189192
<Compile Include="Common\CmdRuntime.cs" />
190193
<Compile Include="Common\Exception.cs" />
194+
<Compile Include="Common\IAdHelper.cs" />
191195
<Compile Include="Common\LongRunningTask.cs" />
192196
<Compile Include="Common\RdsCmdlet.cs" />
197+
<Compile Include="Common\RdsStaleAdObjectCmdlet.cs" />
193198
<Compile Include="Common\RemoteAppRegEx.cs" />
194199
<Compile Include="OperationalResult\GetAzureRemoteAppOperationResult.cs" />
195200
<Compile Include="RemoteProgram\GetAzureRemoteAppProgram.cs" />
@@ -210,7 +215,9 @@
210215
<Compile Include="TemplateImage\RemoveAzureRemoteAppTemplateImage.cs" />
211216
<Compile Include="TemplateImage\RenameAzureRemoteAppTemplateImage.cs" />
212217
<Compile Include="TemplateImage\TemplateImage.cs" />
218+
<Compile Include="Vm\ClearAzureRemoteAppVmStaleAdObject.cs" />
213219
<Compile Include="Vm\GetAzureRemoteAppVm.cs" />
220+
<Compile Include="Vm\GetAzureRemoteAppVmStaleAdObject.cs" />
214221
<Compile Include="Vm\RestartAzureRemoteAppVm.cs" />
215222
<Compile Include="Vnet\GetAzureRemoteAppVnet.cs" />
216223
<Compile Include="Vnet\GetAzureRemoteAppVpnDeviceConfigScript.cs" />

src/ServiceManagement/RemoteApp/Commands.RemoteApp/Commands.RemoteApp.resx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,4 +279,16 @@
279279
<data name="RestartVmWarningMessage" xml:space="preserve">
280280
<value>User {0} is on VM {1}. These users also have active sessions on this VM and will be logged off when the VM is rebooted: {2}</value>
281281
</data>
282+
<data name="GenericDeleteConfirmation" xml:space="preserve">
283+
<value>{0} will be deleted. Are you sure?</value>
284+
</data>
285+
<data name="GenericDeleteVerboseDescription" xml:space="preserve">
286+
<value>{0} will be deleted.</value>
287+
</data>
288+
<data name="GenericVerboseDelete" xml:space="preserve">
289+
<value>Deleting {0}</value>
290+
</data>
291+
<data name="GenericVerboseSkip" xml:space="preserve">
292+
<value>Skipping {0}</value>
293+
</data>
282294
</root>

0 commit comments

Comments
 (0)