Skip to content

Commit 2fe1f7f

Browse files
author
Jianghao Lu
committed
Merge branch 'master' of github.com:Azure/azure-powershell into dev
Conflicts: src/AzurePowershell.sln src/Common/AzurePSCmdlet.cs src/Common/Commands.Common/Commands.Common.csproj src/ResourceManager/AzureBatch/Commands.Batch/Accounts/GetBatchAccountCommand.cs src/ResourceManager/AzureBatch/Commands.Batch/Accounts/GetBatchAccountKeysCommand.cs src/ResourceManager/AzureBatch/Commands.Batch/Accounts/NewBatchAccountCommand.cs src/ResourceManager/AzureBatch/Commands.Batch/Accounts/NewBatchAccountKeyCommand.cs src/ResourceManager/AzureBatch/Commands.Batch/Accounts/RemoveBatchAccountCommand.cs src/ResourceManager/AzureBatch/Commands.Batch/Accounts/SetBatchAccountCommand.cs src/ResourceManager/AzureBatch/Commands.Batch/Utils/Constants.cs src/ResourceManager/Compute/Commands.Compute/Common/ConstantStringTypes.cs src/ResourceManager/Compute/Commands.Compute/Properties/Resources.resx src/ResourceManager/Compute/Commands.Compute/VirtualMachine/Config/NewAzureVMConfigCommand.cs src/ResourceManager/Resources/Commands.Resources.Test/ResourceGroups/GetAzureResourceGroupLogCommandTests.cs src/ResourceManager/Resources/Commands.Resources/ResourceGroups/GetAzureResourceGroupLogCommand.cs
2 parents d725792 + 6b43f46 commit 2fe1f7f

File tree

213 files changed

+54085
-37728
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

213 files changed

+54085
-37728
lines changed

ChangeLog.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
* Changed the output format of Get image cmdlets as a table
88
* Fixed Set-AzureVMAccessExtension cmdlet
99
* Azure Compute (Service Management) cmdlets
10-
* Changed the warning message to a non-terminating error message for ResourceNotFound in VM cmdlets
1110
* Exposed ComputeImageConfig in Get-AzurePlatformVMImage cmdlet
1211
* Fixed Publish-AzurePlatformExtension and Set-AzurePlatformExtension cmdlets
1312
* Azure Backup - added the following cmdlets
@@ -44,6 +43,12 @@
4443
* Get-AzureSqlServerActiveDirectoryAdministrator
4544
* Set-AzureSqlServerActiveDirectoryAdministrator
4645
* Remove-AzureSqlServerActiveDirectoryAdministrator
46+
* SQL Server VM cmdlets (ARM)
47+
* New-AzureVMSqlServerAutoPatchingConfig
48+
* New-AzureVMSqlServerAutoBackupConfig
49+
* Set-AzureVMSqlServerExtension
50+
* Get-AzureVMSqlServerExtension
51+
* Remove-AzureVMSqlServerExtension
4752

4853
## 2015.08.17 version 0.9.7
4954
* Azure Profile cmdlets

setup/azurecmdfiles.wxi

Lines changed: 156 additions & 0 deletions
Large diffs are not rendered by default.

src/Common/AzurePSCmdlet.cs

Lines changed: 264 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// ----------------------------------------------------------------------------------
1+
// ----------------------------------------------------------------------------------
22
//
33
// Copyright Microsoft Corporation
44
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,6 +21,15 @@
2121
using Microsoft.Azure.Common.Authentication;
2222
using Microsoft.Azure.Common.Authentication.Models;
2323
using Microsoft.WindowsAzure.Commands.Common;
24+
using Microsoft.WindowsAzure.Commands.Common.Properties;
25+
using Newtonsoft.Json;
26+
using System;
27+
using System.Collections.Concurrent;
28+
using System.Diagnostics;
29+
using System.IO;
30+
using System.Management.Automation;
31+
using System.Management.Automation.Host;
32+
using System.Threading;
2433

2534
namespace Microsoft.WindowsAzure.Commands.Utilities.Common
2635
{
@@ -34,6 +43,21 @@ public abstract class AzurePSCmdlet : PSCmdlet, IDisposable
3443
private RecordingTracingInterceptor _httpTracingInterceptor;
3544

3645
private DebugStreamTraceListener _adalListener;
46+
protected static AzurePSDataCollectionProfile _dataCollectionProfile = null;
47+
48+
protected AzurePSQoSEvent QosEvent;
49+
50+
protected virtual bool IsUsageMetricEnabled {
51+
get { return false; }
52+
}
53+
54+
protected virtual bool IsErrorMetricEnabled
55+
{
56+
get { return true; }
57+
}
58+
59+
[Parameter(Mandatory = false, HelpMessage = "In-memory profile.")]
60+
public AzureProfile Profile { get; set; }
3761

3862
/// <summary>
3963
/// Gets the PowerShell module name used for user agent header.
@@ -60,10 +84,174 @@ public AzurePSCmdlet()
6084
}
6185

6286
/// <summary>
63-
/// Cmdlet begin process. Write to logs, setup Http Tracing and initialize profile and adds user agent.
87+
/// Initialize the data collection profile
88+
/// </summary>
89+
protected static void InitializeDataCollectionProfile()
90+
{
91+
if (_dataCollectionProfile != null && _dataCollectionProfile.EnableAzureDataCollection.HasValue)
92+
{
93+
return;
94+
}
95+
96+
// Get the value of the environment variable for Azure PS data collection setting.
97+
string value = Environment.GetEnvironmentVariable(AzurePSDataCollectionProfile.EnvironmentVariableName);
98+
if (!string.IsNullOrWhiteSpace(value))
99+
{
100+
if (string.Equals(value, bool.FalseString, StringComparison.OrdinalIgnoreCase))
101+
{
102+
// Disable data collection only if it is explictly set to 'false'.
103+
_dataCollectionProfile = new AzurePSDataCollectionProfile(true);
104+
}
105+
else if (string.Equals(value, bool.TrueString, StringComparison.OrdinalIgnoreCase))
106+
{
107+
// Enable data collection only if it is explictly set to 'true'.
108+
_dataCollectionProfile = new AzurePSDataCollectionProfile(false);
109+
}
110+
}
111+
112+
// If the environment value is null or empty, or not correctly set, try to read the setting from default file location.
113+
if (_dataCollectionProfile == null)
114+
{
115+
string fileFullPath = Path.Combine(AzureSession.ProfileDirectory, AzurePSDataCollectionProfile.DefaultFileName);
116+
if (File.Exists(fileFullPath))
117+
{
118+
string contents = File.ReadAllText(fileFullPath);
119+
_dataCollectionProfile = JsonConvert.DeserializeObject<AzurePSDataCollectionProfile>(contents);
120+
}
121+
}
122+
123+
// If the environment variable or file content is not set, create a new profile object.
124+
if (_dataCollectionProfile == null)
125+
{
126+
_dataCollectionProfile = new AzurePSDataCollectionProfile();
127+
}
128+
}
129+
130+
/// <summary>
131+
/// Get the data collection profile
132+
/// </summary>
133+
protected static AzurePSDataCollectionProfile GetDataCollectionProfile()
134+
{
135+
if (_dataCollectionProfile == null)
136+
{
137+
InitializeDataCollectionProfile();
138+
}
139+
140+
return _dataCollectionProfile;
141+
}
142+
143+
/// <summary>
144+
/// Check whether the data collection is opted in from user
145+
/// </summary>
146+
/// <returns>true if allowed</returns>
147+
public static bool IsDataCollectionAllowed()
148+
{
149+
if (_dataCollectionProfile != null &&
150+
_dataCollectionProfile.EnableAzureDataCollection.HasValue &&
151+
_dataCollectionProfile.EnableAzureDataCollection.Value)
152+
{
153+
return true;
154+
}
155+
156+
return false;
157+
}
158+
159+
/// <summary>
160+
/// Save the current data collection profile Json data into the default file path
161+
/// </summary>
162+
/// <param name="profile"></param>
163+
protected void SaveDataCollectionProfile()
164+
{
165+
if (_dataCollectionProfile == null)
166+
{
167+
InitializeDataCollectionProfile();
168+
}
169+
170+
string fileFullPath = Path.Combine(AzureSession.ProfileDirectory, AzurePSDataCollectionProfile.DefaultFileName);
171+
var contents = JsonConvert.SerializeObject(_dataCollectionProfile);
172+
AzureSession.DataStore.WriteFile(fileFullPath, contents);
173+
WriteWarning(string.Format(Resources.DataCollectionSaveFileInformation, fileFullPath));
174+
}
175+
176+
protected bool CheckIfInteractive()
177+
{
178+
bool interactive = true;
179+
if (this.Host == null || this.Host.UI == null || this.Host.UI.RawUI == null)
180+
{
181+
interactive = false;
182+
}
183+
else
184+
{
185+
try
186+
{
187+
var test = this.Host.UI.RawUI.KeyAvailable;
188+
}
189+
catch
190+
{
191+
interactive = false;
192+
}
193+
}
194+
195+
if (!interactive && !_dataCollectionProfile.EnableAzureDataCollection.HasValue)
196+
{
197+
_dataCollectionProfile.EnableAzureDataCollection = false;
198+
}
199+
return interactive;
200+
}
201+
202+
/// <summary>
203+
/// Prompt for the current data collection profile
204+
/// </summary>
205+
/// <param name="profile"></param>
206+
protected void PromptForDataCollectionProfileIfNotExists()
207+
{
208+
// Initialize it from the environment variable or profile file.
209+
InitializeDataCollectionProfile();
210+
211+
if (!_dataCollectionProfile.EnableAzureDataCollection.HasValue && CheckIfInteractive())
212+
{
213+
WriteWarning(Resources.DataCollectionPrompt);
214+
215+
const double timeToWaitInSeconds = 60;
216+
var status = string.Format(Resources.DataCollectionConfirmTime, timeToWaitInSeconds);
217+
ProgressRecord record = new ProgressRecord(0, Resources.DataCollectionActivity, status);
218+
219+
var startTime = DateTime.Now;
220+
var endTime = DateTime.Now;
221+
double elapsedSeconds = 0;
222+
223+
while (!this.Host.UI.RawUI.KeyAvailable && elapsedSeconds < timeToWaitInSeconds)
224+
{
225+
Thread.Sleep(TimeSpan.FromMilliseconds(10));
226+
endTime = DateTime.Now;
227+
228+
elapsedSeconds = (endTime - startTime).TotalSeconds;
229+
record.PercentComplete = ((int)elapsedSeconds * 100 / (int)timeToWaitInSeconds);
230+
WriteProgress(record);
231+
}
232+
233+
bool enabled = false;
234+
if (this.Host.UI.RawUI.KeyAvailable)
235+
{
236+
KeyInfo keyInfo = this.Host.UI.RawUI.ReadKey(ReadKeyOptions.NoEcho | ReadKeyOptions.AllowCtrlC | ReadKeyOptions.IncludeKeyDown);
237+
enabled = (keyInfo.Character == 'Y' || keyInfo.Character == 'y');
238+
}
239+
240+
_dataCollectionProfile.EnableAzureDataCollection = enabled;
241+
242+
WriteWarning(enabled ? Resources.DataCollectionConfirmYes : Resources.DataCollectionConfirmNo);
243+
244+
SaveDataCollectionProfile();
245+
}
246+
}
247+
248+
/// <summary>
249+
/// Cmdlet begin process. Write to logs, setup Http Tracing and initialize profile
64250
/// </summary>
65251
protected override void BeginProcessing()
66252
{
253+
PromptForDataCollectionProfileIfNotExists();
254+
InitializeQosEvent();
67255
if (string.IsNullOrEmpty(ParameterSetName))
68256
{
69257
WriteDebugWithTimestamp(string.Format("{0} begin processing without ParameterSet.", this.GetType().Name));
@@ -95,6 +283,7 @@ protected override void BeginProcessing()
95283
/// </summary>
96284
protected override void EndProcessing()
97285
{
286+
LogQosEvent();
98287
string message = string.Format("{0} end processing.", this.GetType().Name);
99288
WriteDebugWithTimestamp(message);
100289

@@ -125,6 +314,13 @@ protected bool IsVerbose()
125314
protected new void WriteError(ErrorRecord errorRecord)
126315
{
127316
FlushDebugMessages();
317+
if (QosEvent != null && errorRecord != null)
318+
{
319+
QosEvent.Exception = errorRecord.Exception;
320+
QosEvent.IsSuccess = false;
321+
LogQosEvent(true);
322+
}
323+
128324
base.WriteError(errorRecord);
129325
}
130326

@@ -234,6 +430,62 @@ private void FlushDebugMessages()
234430
}
235431
}
236432

433+
protected void InitializeQosEvent()
434+
{
435+
QosEvent = new AzurePSQoSEvent()
436+
{
437+
CmdletType = this.GetType().Name,
438+
IsSuccess = true,
439+
};
440+
441+
if (this.Profile != null && this.Profile.DefaultSubscription != null)
442+
{
443+
QosEvent.Uid = MetricHelper.GenerateSha256HashString(
444+
this.Profile.DefaultSubscription.Id.ToString());
445+
}
446+
else
447+
{
448+
QosEvent.Uid = "defaultid";
449+
}
450+
}
451+
452+
/// <summary>
453+
/// Invoke this method when the cmdlet is completed or terminated.
454+
/// </summary>
455+
protected void LogQosEvent(bool waitForMetricSending = false)
456+
{
457+
if (QosEvent == null)
458+
{
459+
return;
460+
}
461+
462+
QosEvent.FinishQosEvent();
463+
464+
if (!IsUsageMetricEnabled && (!IsErrorMetricEnabled || QosEvent.IsSuccess))
465+
{
466+
return;
467+
}
468+
469+
if (!IsDataCollectionAllowed())
470+
{
471+
return;
472+
}
473+
474+
WriteDebug(QosEvent.ToString());
475+
476+
try
477+
{
478+
MetricHelper.LogQoSEvent(QosEvent, IsUsageMetricEnabled, IsErrorMetricEnabled);
479+
MetricHelper.FlushMetric(waitForMetricSending);
480+
WriteDebug("Finish sending metric.");
481+
}
482+
catch (Exception e)
483+
{
484+
//Swallow error from Application Insights event collection.
485+
WriteWarning(e.ToString());
486+
}
487+
}
488+
237489
/// <summary>
238490
/// Asks for confirmation before executing the action.
239491
/// </summary>
@@ -244,10 +496,19 @@ private void FlushDebugMessages()
244496
/// <param name="action">The action code</param>
245497
protected void ConfirmAction(bool force, string actionMessage, string processMessage, string target, Action action)
246498
{
499+
if (QosEvent != null)
500+
{
501+
QosEvent.PauseQoSTimer();
502+
}
503+
247504
if (force || ShouldContinue(actionMessage, ""))
248505
{
249506
if (ShouldProcess(target, processMessage))
250-
{
507+
{
508+
if (QosEvent != null)
509+
{
510+
QosEvent.ResumeQosTimer();
511+
}
251512
action();
252513
}
253514
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using System;
16+
using System.IO;
17+
using Newtonsoft.Json;
18+
using Microsoft.Azure.Common.Authentication;
19+
20+
namespace Microsoft.WindowsAzure.Commands.Common
21+
{
22+
public class AzurePSDataCollectionProfile
23+
{
24+
public const string EnvironmentVariableName = "Azure_PS_Data_Collection";
25+
public static string DefaultFileName = "AzureDataCollectionProfile.json";
26+
27+
public AzurePSDataCollectionProfile()
28+
{
29+
}
30+
31+
public AzurePSDataCollectionProfile(bool enable)
32+
{
33+
EnableAzureDataCollection = enable;
34+
}
35+
36+
[JsonProperty(PropertyName = "enableAzureDataCollection")]
37+
public bool? EnableAzureDataCollection { get; set; }
38+
}
39+
}

0 commit comments

Comments
 (0)