Azure Web App staging monitoring - azure

everyone.
Right now I'm using nice nuGet package to monitor my azure web app. The code could look something like this
var certificate = BuildCertificate(StoreName.My, StoreLocation.LocalMachine, " certificate thumbprint");
string subscriptionId = "subscriptionId";
string webspace = "westuswebspace";
string website = "websitename";
using (var client = new MetricsClient(new CertificateCloudCredentials(subscriptionId, certificate)))
{
var metricDefs = client.MetricDefinitions.List(ResourceIdBuilder.BuildWebSiteResourceId(webspace, website), null, null);
var end = DateTime.UtcNow;
var start = end.AddHours(-12);
var timeGrain = TimeSpan.FromHours(1);
var metricVals = client.MetricValues.List(ResourceIdBuilder.BuildWebSiteResourceId(webspace, website),
metricDefs.MetricDefinitionCollection.Value.Select(md => md.DisplayName).ToList(), "",
timeGrain, start, end);
foreach (var metric in metricVals.MetricValueSetCollection.Value)
{
Console.WriteLine("Metric Name: {0}", metric.DisplayName);
Console.WriteLine("Metric Namespace: {0}", metric.Namespace);
foreach (var val in metric.MetricValues)
{
Console.WriteLine("Value: {0}", val.Average.HasValue ? val.Average.Value : 0);
}
Console.WriteLine("//////////////////////");
}
}
certificate retrieval logic
private static X509Certificate2 BuildCertificate(StoreName storeName, StoreLocation storeLocation, string thumbprint)
{
var store = new X509Store(storeName, storeLocation);
store.Open(OpenFlags.ReadOnly);
try
{
var builder = new StringBuilder(thumbprint.Length);
foreach (char c in thumbprint.Where(char.IsLetterOrDigit))
{
builder.Append(c);
}
string cleanThumbprint = builder.ToString();
X509Certificate2Collection list = store.Certificates.Find(X509FindType.FindByThumbprint, cleanThumbprint, false);
X509Certificate2 cert;
if (list == null || list.Count != 1)
{
cert = null;
}
else
{
cert = list[0];
}
return cert;
}
finally
{
store.Close();
}
}
so, everything works perfectly fine, when I'm working with prod, but I can't figure out, how I can monitor my staging environment.
Please, help me with that. I would highly appreciate any help.

Related

CSOM CreateSPAsyncReadJob stays in Queue state

I am referring to the Migration Asynchronous Read API that allows creating a read job on SharePoint using CSOM. I am able to create the read job successfully but unfortunately, the job stays in a queue state since long.
The function returns the Object that includes UniqueJobID, AzureContainerManifestUri, AzureQueueReportUri and EncryptionKey
By using clientContext.Site.GetMigrationJobStatus method I am able to check the read job status that always returns Queued
Here is the sample code for reference:
using (var clientContext = new ClientContext(siteUrl))
{
clientContext.Credentials = new SharePointOnlineCredentials(userName, password);
var result = clientContext.Site.CreateSPAsyncReadJob($"{siteUrl}/List/MyList", new AsyncReadOptions { });
clientContext.ExecuteQuery();
MigrationJobState state;
do
{
var status = clientContext.Site.GetMigrationJobStatus(result[0].JobId);
clientContext.ExecuteQuery();
state = status.Value;
} while (state == MigrationJobState.Queued);
}
I have also tried to connect to the AzureQueueReportUri queue that contains the message with encrypted content. I am not sure how we can decrypt the content to make it human readable. Here is the sample message:
{
"Label": "Encrypted",
"JobId": "079ece4a-cfd2-4676-a27d-2662beb5bb0a",
"IV": "RYc+ZA2feX1hnAcVWR1R+w==",
"Content": "qbjTBbb2N+DkNumLoCJSAAfwj8etDLgjxp+b2T9k03L9WfRJKlFBIZO457q+CbHA+8DHJS7VbPzVMoW6ybo2GxgteTYVP+yVUOPPvz57VGQJyzg2gss+Bsjn73GTWWUfwC/W+oWnEpt8PawZysCjSNf6A4HKZKewkskCshN/pND8ZpevrGt2qq0dTt0NkTIkuYv5AvIP7DSWjdl7nN/W5x4c2nR0sPFqKYom41a4tIqrruzwCDEEjWLFtuXAQ+UN2TMV9PWabRFe9n/P1RHrAJaNU+JjJiJm+lE1dQChz+7OuQoJsYnbjYTbqEE8CnIB0/E0zTrc3zLc6th8MBsKpZJjd31ovqr/Xez6zCnvMKotSdScFtTgQqHxmVDBMfMgi2mm8cKQpdKwRufP/YhaDQlvFkmj2FQN0KAMNxwFBh/MWCVhz5uCJ50CGhChcn4h"
}
I am also not able to connect the AzureContainerManifestUri blob container. It fails with an error Authentication Error. Signature did not match.
Can anyone please guide me how can I proceed ahead?
The method parameters have been changed. Here is the latest updated documentation: https://learn.microsoft.com/en-us/sharepoint/dev/apis/export-amr-api
Sample Code: https://gist.github.com/techmadness/484e7de0a7c51e5faf952a79f1eacb85
using System;
using System.Linq;
using System.Security;
using System.Threading;
using Microsoft.SharePoint.Client;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.Queue;
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
var userName = "admin#tenant.onmicrosoft.com";
var password = GetSecurePassword("password");
var siteUrl = "https://tenant.sharepoint.com/sites/testsite";
var listUrl = $"{siteUrl}/testlist";
var azStorageConnectionStrong = "DefaultEndpointsProtocol=https;AccountName=abcd;AccountKey=xyz";
using (var clientContext = new ClientContext(siteUrl))
{
clientContext.Credentials = new SharePointOnlineCredentials(userName, password);
var azManifestContainer = CreateContainerIfNotExists(azStorageConnectionStrong, "spread-manifest-container");
var azReportQueue = CreateQueueIfNotExists(azStorageConnectionStrong, "spread-report-queue");
var azManifestContainerUrl = GetSASUrl(azManifestContainer);
var azReportQueueUrl = GetSASUrl(azReportQueue);
var output = clientContext.Site.CreateSPAsyncReadJob(
listUrl,
new AsyncReadOptions
{
IncludeDirectDescendantsOnly = true,
IncludeSecurity = true,
},
null,
azManifestContainerUrl,
azReportQueueUrl);
clientContext.ExecuteQuery();
CloudQueueMessage message;
do
{
Thread.Sleep(TimeSpan.FromSeconds(10));
message = azReportQueue.GetMessage();
if (message != null)
{
Console.WriteLine(message.AsString);
azReportQueue.DeleteMessage(message);
}
} while (message != null);
Console.ReadLine();
}
}
private static SecureString GetSecurePassword(string pwd)
{
SecureString securePassword = new SecureString();
foreach (var ch in pwd.ToArray())
{
securePassword.AppendChar(ch);
}
return securePassword;
}
private static CloudBlobContainer CreateContainerIfNotExists(string storageConnectionString, string containerName)
{
var storageAccount = CloudStorageAccount.Parse(storageConnectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(containerName);
container.CreateIfNotExistsAsync().GetAwaiter().GetResult();
return container;
}
private static CloudQueue CreateQueueIfNotExists(string storageConnectionString, string queueName)
{
var cloudStorageAccount = CloudStorageAccount.Parse(storageConnectionString);
var queueClient = cloudStorageAccount.CreateCloudQueueClient();
var queue = queueClient.GetQueueReference(queueName);
queue.CreateIfNotExistsAsync().GetAwaiter().GetResult();
return queue;
}
public static string GetSASUrl(CloudBlobContainer container)
{
var sharedAccessSignature = container.GetSharedAccessSignature(new SharedAccessBlobPolicy
{
Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write,
SharedAccessStartTime = DateTime.UtcNow.AddDays(-1),
SharedAccessExpiryTime = DateTime.UtcNow.AddDays(7),
});
return container.StorageUri.PrimaryUri + sharedAccessSignature;
}
public static string GetSASUrl(CloudQueue queue)
{
var sharedAccessSignature = queue.GetSharedAccessSignature(new SharedAccessQueuePolicy
{
Permissions = SharedAccessQueuePermissions.Add | SharedAccessQueuePermissions.Read,
SharedAccessStartTime = DateTime.UtcNow.AddDays(-1),
SharedAccessExpiryTime = DateTime.UtcNow.AddDays(7)
});
return queue.StorageUri.PrimaryUri + sharedAccessSignature;
}
}
}

How to get Logic App Metrics?

I'm trying to get Logic Apps metrics like BillableExecutions, Latency etc in my console application.
Currently I'm able to list the logic apps runs, triggers, versions using the .Net Client Microsoft.Azure.Management. But it doesn't seem to have the API to access the monitoring API's.
Code excerpt
private static void Main(string[] args)
{
var token = GetTokenCredentials();
var client = new LogicManagementClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var dataQuery = new ODataQuery<WorkflowFilter>
{
Top = 50
};
using (client)
{
var logicAppsWorkFlows = client.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
var runs = GetWorkflowRuns(client, logicAppsWorkFlow.Id.Split('/')[4], logicAppsWorkFlow.Name);
Console.WriteLine(runs.Count);
}
Console.WriteLine(logicAppsWorkFlows.Count());
}
}
Can someone tell me how to access Logic Apps Metrics? Is there a client similar to Microsoft.Azure.Management for access metrics data?
Update 2
I have found a client dll which was in pre release mode which is used to get metrics. Below is my current code
var token = GetTokenCredentials();
var insightsClient = new InsightsClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var logicManagementClient = new LogicManagementClient(token, new HttpClientHandler())
{
SubscriptionId = new AzureSubscription().SubscriptionId
};
var dataQuery = new ODataQuery<WorkflowFilter>
{
Top = 50
};
using (logicManagementClient)
{
var logicAppsWorkFlows = logicManagementClient.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
using (insightsClient)
{
var metricsDataQuery = new ODataQuery<Metric>
{
Filter = "name.value eq 'ActionLatency' and startTime ge '2014-07-16'"
};
IEnumerable<Metric> metricsList = null;
try
{
metricsList = insightsClient.Metrics.List(logicAppsWorkFlow.Id, metricsDataQuery);
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (metricsList == null) continue;
foreach (var metric in metricsList)
{
foreach (var metricValue in metric.Data)
{
Console.WriteLine(metric.Name.Value + " = " + metricValue.Total);
}
}
}
}
}
I'm getting an exception saying the filter string is not valid. Im referring the filter string structure provided here
https://learn.microsoft.com/en-us/rest/api/monitor/filter-syntax
Can someone tell what im doing wrong here?
Thanks
It looks like ge is not allowed for Logic Apps StartTime field for some reason. I had to change the code to below to make it work
using (logicManagementClient)
{
var logicAppsWorkFlows = logicManagementClient.Workflows.ListBySubscription(dataQuery);
foreach (var logicAppsWorkFlow in logicAppsWorkFlows)
{
using (insightsClient)
{
var metricsDataQuery = new ODataQuery<Metric>
{
Filter = "startTime eq " + DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd") + " and name.value eq 'BillableTriggerExecutions' and endTime eq " + DateTime.Now.ToString("yyyy-MM-dd")
};
var query = metricsDataQuery.GetQueryString();
Console.WriteLine(query);
IEnumerable<Metric> metricsList = null;
try
{
//throws exception if there is no metrics data
//TODO: Check whether the logic app ran atleast one time
metricsList = insightsClient.Metrics.List(logicAppsWorkFlow.Id, metricsDataQuery);
}
catch (Exception e)
{
Console.WriteLine(e);
}
if (metricsList == null) continue;
foreach (var metric in metricsList)
{
foreach (var metricValue in metric.Data)
{
Console.WriteLine(metric.Name.Value + " = " + metricValue.Total);
}
}
}
}
}

PCLCrypto exception 'CryptographicException: Bad PKCS7 padding. Invalid length'

I'm struggling with the PCLCryptho libraby, I can't get it working without retrieving the exception 'CryptographicException: Bad PKCS7 padding. Invalid length'. Running the code once is working, but running it multiple times after each other fails (with different input strings). The decryption takes place after a new instance of the program. I'm running this code on iOS with Xamarin Forms. Here's my code (I'm using the same VI each time and save the salt in the Settinsg for now):
public static string EncryptAnswer(string answer, string passWord)
{
try
{
var keyMaterial = CreateKey(passWord);
var cipherTextBuffer = GetBytes(answer);
var symmetricAlgorithm = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var symmetricKey = symmetricAlgorithm.CreateSymmetricKey(keyMaterial);
using (var encryptor = WinRTCrypto.CryptographicEngine.CreateEncryptor(symmetricKey, GetBytes("vivivivivivivivi")))
{
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (var bWriter = new BinaryWriter(cs))
{
bWriter.Write(cipherTextBuffer, 0, cipherTextBuffer.Length);
cs.FlushFinalBlock();
}
}
return GetString(ms.ToArray());
}
}
}
catch (Exception e)
{
return string.Empty;
}
}
public static string DecryptAnswer(string encryptedAnswer, string passWord)
{
try
{
var cipherTextBuffer = GetBytes(encryptedAnswer);
var keyMaterial = CreateKey(passWord);
var symmetricAlgorithm = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var symmetricKey = symmetricAlgorithm.CreateSymmetricKey(keyMaterial);
using (var decryptor = WinRTCrypto.CryptographicEngine.CreateDecryptor(symmetricKey, GetBytes("vivivivivivivivi")))
{
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
using (var binWriter = new BinaryWriter(cs))
{
binWriter.Write(cipherTextBuffer, 0, cipherTextBuffer.Length);
}
return GetString(ms.ToArray());
}
}
}
catch (Exception e)
{
}
return string.Empty;
}
public static byte[] CreateSalt()
{
var salt = WinRTCrypto.CryptographicBuffer.GenerateRandom(8);
CrossSettings.Current.AddOrUpdateValue("Salt", GetString(salt));
return salt;
}
private static byte[] GetSalt()
{
var saltString = CrossSettings.Current.GetValueOrDefault<string>("Salt");
var salt = GetBytes(saltString);
return salt;
}
private static byte[] CreateKey(string passWord)
{
var key = NetFxCrypto.DeriveBytes.GetBytes(passWord, GetSalt(), 1000, 32);
return key;
}
private static byte[] GetBytes(string str)
{
return Encoding.Unicode.GetBytes(str);
}
private static string GetString(byte[] bytes)
{
return Encoding.Unicode.GetString(bytes, 0, bytes.Length);
}
This seems to be equal to the answers and examples I found. Can someone tell me what's wrong?

How to create azure VM with Rest Api

Here is the code, but it prompts error:
The image o3lceiy3.ioa201305211013360129.vhd does not exist.
the subscriptionId and X509Certificate2 are valid
internal class Program
{
public static X509Certificate2 Certificate { get; set; }
private static void Main(string[] args)
{
const string subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
//#"https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments";
var url = string.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments",
subscriptionId, "edoc2cloudtest");
var myReq = (HttpWebRequest)WebRequest.Create(url);
myReq.Method = "POST";
myReq.Headers.Add("x-ms-version", "2012-03-01");
myReq.Proxy = null;
myReq.Timeout = 30000;
myReq.ContentType = "application/xml";
var postData = ReadConfig();
using (var reqStream = myReq.GetRequestStream())
{
var data = Encoding.UTF8.GetBytes(postData);
reqStream.Write(data, 0, data.Length);
reqStream.Flush();
}
Certificate = GetX509Certificate();
myReq.ClientCertificates.Add(Certificate);
try
{
var myRes = (HttpWebResponse) myReq.GetResponse();
}
catch (WebException exWeb)
{
// Parse the web response.
Stream responseStream = exWeb.Response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
XmlDocument xDocResp = new XmlDocument();
xDocResp.Load(reader);
HttpWebResponse responseStatus = (HttpWebResponse)exWeb.Response;
responseStream.Close();
reader.Close();
var result = NiceFormatXml(xDocResp);
Console.WriteLine(result);
}
}
private static string NiceFormatXml(XmlDocument xDoc)
{
StringBuilder niceString = new StringBuilder();
StringWriter strWriter = new StringWriter(niceString);
XmlTextWriter xmlWriter = new XmlTextWriter(strWriter);
xmlWriter.Formatting = Formatting.Indented;
xDoc.WriteTo(xmlWriter);
xmlWriter.Close();
strWriter.Close();
return niceString.ToString();
}
private static X509Certificate2 GetX509Certificate()
{
X509Certificate2 certificate2 = null;
var store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var collection = store.Certificates;
var fcollection = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
const string certificateThumbprint = "‎‎‎‎7dfbc7369306ed096b7e5c7b4ba6e99f190240e9";
store.Close();
if (fcollection.Count > 0)
{
foreach (var variable in fcollection)
{
if (variable.Thumbprint != null &&
variable.Thumbprint.Equals(certificateThumbprint, StringComparison.InvariantCultureIgnoreCase))
{
certificate2 = variable;
}
}
}
return certificate2;
}
private static string ReadConfig()
{
string path = System.AppDomain.CurrentDomain.BaseDirectory + "Edoc2Cloud.xml";
//string path = System.AppDomain.CurrentDomain.BaseDirectory + "VM-CreateVM.xml";
string s;
using (var sr = new StreamReader(path, Encoding.GetEncoding("GB2312")))
{
s = sr.ReadToEnd();
}
return s;
}
}
Here is the XML:
<Deployment xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>EDoc2Test</Name>
<DeploymentSlot>Staging</DeploymentSlot>
<Label>EDoc2Testlabe</Label>
<RoleList>
<Role>
<RoleName>EDoc2TestRoleName</RoleName>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet>
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
<ComputerName>computer-name</ComputerName>
<AdminPassword>APasswor_324d</AdminPassword>
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
</ConfigurationSet>
</ConfigurationSets>
<AvailabilitySetName>EDoc2TestSetName</AvailabilitySetName>
<OSVirtualHardDisk>
<HostCaching>ReadWrite</HostCaching>
<DiskName>SomeName-0-20121007173943</DiskName>
<MediaLink>http://portalvhdsx4flx9dhmjyt1.blob.core.windows.net/vhds/o3lceiy3.ioa201305211013360129.vhd</MediaLink>
<SourceImageName>o3lceiy3.ioa201305211013360129.vhd</SourceImageName>
</OSVirtualHardDisk>
<RoleSize>Medium</RoleSize>
</Role>
Based on the error you're receiving and the XML you've specified, can you please check if there is an image by the name o3lceiy3.ioa201305211013360129.vhd in your custom images? You could find that information by logging into the portal and going to Virtual Machines --> Images.
Documentation regarding <SourceImageName> parameter states that it is needed when you want to create a virtual machine either by using system or custom images.
You can read the complete documentation here: http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx#OSVirtualHardDisk.

How can I use start script change IIS Application pool pipeline mode

I used a web role.
I just wonder if I can use Start script for my project to change the pipeline mode to classic.
I can use C# code achieve that, but I prefer to use cmd, The problem I meet here is how can I get the applicationPool name by cmd?
Here is my C# code:
{
using (ServerManager serverManager = new ServerManager())
{
Site site = serverManager.Sites[RoleEnvironment.CurrentRoleInstance.Id + "_Web"];
Configuration config = serverManager.GetApplicationHostConfiguration();
string AppPoolName = site.Applications[0].ApplicationPoolName;
ConfigurationSection applicationPoolsSection = config.GetSection("system.applicationHost/applicationPools");
ConfigurationElementCollection applicationPoolsCollection = applicationPoolsSection.GetCollection();
ConfigurationElement addElement = FindElement(applicationPoolsCollection, "add", "name", AppPoolName);
if (addElement == null) throw new InvalidOperationException("Element not found!");
addElement["managedPipelineMode"] = #"Classic";
serverManager.CommitChanges();
return base.OnStart();
}
}
private static ConfigurationElement FindElement(ConfigurationElementCollection collection, string elementTagName, params string[] keyValues)
{
foreach (ConfigurationElement element in collection)
{
if (String.Equals(element.ElementTagName, elementTagName, StringComparison.OrdinalIgnoreCase))
{
bool matches = true;
for (int i = 0; i < keyValues.Length; i += 2)
{
object o = element.GetAttributeValue(keyValues[i]);
string value = null;
if (o != null)
{
value = o.ToString();
}
if (!String.Equals(value, keyValues[i + 1], StringComparison.OrdinalIgnoreCase))
{
matches = false;
break;
}
}
if (matches)
{
return element;
}
}
}
return null;
}
}
So How can I do that ?
If the pool name is the only problem you are facing, try using appcmd for listing all available pools:
appcmd.exe list apppool /text:*
This should give you all apppools available on IIS with the app names (provided you have enough rights).

Resources