How do i filter using a partial VM name (string) in vmware vSphere client REST API? - vsphere

Good day!
i am trying to automate some actions to be done to VM's in my organisation.
The action to be done depends on the a substring in the VM name.
for eg, i would need to delete all VM's whose name starts with 'delete', etc.
I can use the below API to fetch the list of VM's:
GET https://{{vc}}/rest/vcenter/vm
However, this API can only fetch a maximum of 1000 VM's.
Is there any way i can filter and get only the list of VM's with the expected substring from this API?
from what i understand, appending filter.names.1 to the above API works but for that i need to input the exact and entire VM name.
is there a way where i can search for a list of VM's with partial text?
Apologies, i am a newbie to this.
thank you for your time!

Since vSphere API does not provide such capability to search by partial VM name there is a tricky way to do this.
I am using the search functionality in vSphere Client 6.7.0.
Prerequisite is to get the following cookies first:
VSPHERE-USERNAME
VSPHERE-CLIENT-SESSION-INDEX
VSPHERE-UI-JSESSIONID
You have to do three calls in order to get them:
1. GET "https://[URL]/ui/login" you will be forwarded to a new URL from where you can take "SAMLRequest token"
2. POST "https://[URL]/websso/SAML2/SSO/vsphere.local?SAMLRequest=[SAMLRequest token]", set as header "CastleAuthorization=Basic%20[credentials]" where credentials is the Base64 encoding of "User:Password". Get the value of "SAMLResponse" hidden field from the response.
3. POST "https://[URL]/ui/saml/websso/sso", set "SAMLResponse=[SAMLResponse value]", where "SAMLResponse value" you have it from the previous response. From this response you will get the cookies.
Once you have those three cookies, make a new call as you set the cookies
4. GET "https://[URL]/ui/search/quicksearch/?opId=0&query=[partial VM name]"
For example for this call "https://[URL]/ui/search/quicksearch/?opId=0&query=test"
you will get response like this:
[{
"icon": "vsphere-icon-vm",
"labelPlural": "Virtual Machines",
"label": "Virtual Machine",
"results": [{
"id": "urn:vmomi:VirtualMachine:vm-2153:103ac083-e314-47ea-942a-c685d9a4e6c9",
"type": "VirtualMachine",
"name": "TestVM1"
}, {
"id": "urn:vmomi:VirtualMachine:vm-3391:103ac083-e314-47ea-942a-c685d9a4e6c9",
"type": "VirtualMachine",
"name": "TestVM2"
}, {
"id": "urn:vmomi:VirtualMachine:vm-3438:103ac083-e314-47ea-942a-c685d9a4e6c9",
"type": "VirtualMachine",
"name": "TestVM3"
}
]
}
]
Below is my own vSphere Search Proxy Client written in C#:
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
namespace VsphereSearchProxy
{
static class Program
{
const string VSPHERE_URL = "VSPHERE_URL";
static string VSPHERE_CRED_BASE64
{
get
{
var plainTextCred = Encoding.UTF8.GetBytes("USER:PASS");
return Convert.ToBase64String(plainTextCred);
}
}
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Expected one argument: Virtual Machine name");
return;
}
var vmName = args[0];
var vsphereUri = VSPHERE_URL.TrimEnd('/');
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.Expect100Continue = true;
//=================================================================
Console.WriteLine("\nStep 1\n");
var url1 = vsphereUri + "/ui/login";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url1);
request.Method = "GET";
request.KeepAlive = true;
request.AllowAutoRedirect = true;
var response = (HttpWebResponse)request.GetResponse();
var url2 = response.ResponseUri.AbsoluteUri;
Console.WriteLine("url2: " + url2);
WebHeaderCollection headerCollection = response.Headers;
Console.WriteLine("\nResponse headers\n");
for (int i = 0; i < headerCollection.Count; i++)
{
Console.WriteLine("\t" + headerCollection.GetKey(i) + " = " + headerCollection.Get(i));
}
//=================================================================
Console.WriteLine("\nStep 2\n");
request = (HttpWebRequest)WebRequest.Create(url2);
request.Method = "POST";
request.Headers.Add("Authorization: Basic " + VSPHERE_CRED_BASE64);
request.ContentType = "application/x-www-form-urlencoded";
request.KeepAlive = true;
request.AllowAutoRedirect = false;
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write("CastleAuthorization=Basic%20" + VSPHERE_CRED_BASE64);
streamWriter.Flush();
streamWriter.Close();
}
response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Expected 200 OK, but got " + response.StatusCode);
}
headerCollection = response.Headers;
Console.WriteLine("\nResponse headers\n");
for (int i = 0; i < headerCollection.Count; i++)
{
Console.WriteLine("\t" + headerCollection.GetKey(i) + " = " + headerCollection.Get(i));
}
var responseString = "";
using (Stream stream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
responseString = reader.ReadToEnd();
}
var SAMLResponse = "";
Match match = Regex.Match(responseString, "<input[^>]*type=\"hidden\"\\s+name=\"SAMLResponse\"[^>]*value=\"([^\"]*)\"");
if (match.Success)
{
SAMLResponse = match.Groups[1].Value;
SAMLResponse = SAMLResponse.Replace("\n", "");
//Console.WriteLine("SAMLResponse: " + SAMLResponse);
}
if (string.IsNullOrWhiteSpace(SAMLResponse))
{
throw new Exception("SAMLResponse is missing or blank");
}
//=================================================================
Console.WriteLine("\nStep 3\n");
var url3 = vsphereUri + "/ui/saml/websso/sso";
request = (HttpWebRequest)WebRequest.Create(url3);
request.Method = "POST";
request.Headers.Add("Authorization: Basic " + VSPHERE_CRED_BASE64);
request.ContentType = "application/x-www-form-urlencoded";
request.KeepAlive = true;
request.AllowAutoRedirect = false;
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write("SAMLResponse=" + HttpUtility.UrlEncode(SAMLResponse));
streamWriter.Flush();
streamWriter.Close();
}
response = (HttpWebResponse)request.GetResponse();
var cookies = response.Headers["Set-Cookie"];
Console.WriteLine("cookies: " + cookies);
headerCollection = response.Headers;
Console.WriteLine("\nResponse headers\n");
for (int i = 0; i < headerCollection.Count; i++)
{
Console.WriteLine("\t" + headerCollection.GetKey(i) + " = " + headerCollection.Get(i));
}
//=================================================================
Console.WriteLine("\nStep 4\n");
var url4 = vsphereUri + "/ui/search/quicksearch/?opId=:1&query=" + vmName;
request = (HttpWebRequest)WebRequest.Create(url4);
request.Method = "GET";
request.Headers.Add("Cookie: " + cookies);
request.KeepAlive = true;
request.AllowAutoRedirect = false;
response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Expected 200 OK, but got " + response.StatusCode);
}
var jsonResp = "";
using (Stream stream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
jsonResp = reader.ReadToEnd();
}
Console.WriteLine(jsonResp);
}
}
}

Unfortunately the vSphere Automation API isn't setup to filter on partial names or even when using a wildcard. Some of the available filters may help you limit the output to be under the 1000 object limit (example: filter on specific clusters and/or folders).
Hopefully this is something that's added in a future release.

Related

Mule - Salesforce connector - Retrieve job failed results bulk v2 - not returning failed data

I am querying Salesforce Bulk api failed results in Mule. But it doesn't fetch the data. It jus shows the record id and error message. But if i check in workbench, it shows the id, error, datacolumns(a,b,c)
How to get those details..Is there any other way to get the bulk api v2 failed results in Mule
doing simple Transformation before logging
%dw 2.0
output application/json
---
payload
Debug Log :
On workbench, I get the actual data.
please share your thoughts why i don't see those data
#RestResource(urlMapping='/bulkapi/failures')
global without sharing class RestGetBulkAPIResults
{
#HttpGet
global static void getFailedRecords()
{
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;
res.addHeader('Content-Type', 'application/json');
Http http = new Http();
HttpRequest httpReq = new HttpRequest();
HttpResponse httpRes = new HttpResponse();
httpReq.setMethod('GET');
httpReq.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
string path = '/services/data/v48.0/jobs/ingest/7502i000001fJG9AAM/failedResults/';
httpReq.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm()+ path);
httpRes = http.send(httpReq);
string op = httpRes.getBody();
string[] rowList = op.split('\n');
string[] headers = rowList[0].split(',');
integer columnsCount = headers.size();
integer dataRowsCount = rowList.size();
string fullFormattedData = '[';
for(integer rowIndex =1; rowIndex < dataRowsCount; rowIndex++)
{
string[] rowData = rowList[rowIndex].split(',');
string rowJsonData ='{';
for(integer columnIndex=0; columnIndex < columnsCount; columnIndex++)
{
rowJsonData += headers[columnIndex] + ':' + rowData[columnIndex] + ',';
}
rowJsonData = rowJsonData.removeEnd(',');
rowJsonData += '}';
fullFormattedData += rowJsonData;
}
fullFormattedData += ']';
system.debug('resp' + httpRes.getBody());
res.responseBody = Blob.valueOf(fullFormattedData);
res.statusCode = 200;
}
}

Get appointments from all Outlook calendars

I'm trying to read appointments from Outlook calendar using ExchangeServiceBinding but my solution takes appointments only from "default" outlook calendar and don't read from "sub calendars/custom calendars". Do you know how to define rest of the calendars or do you know better solution which contains all calendars?
Critical part is that solution shouldn't contain MAPI because of next use in web service.
My current code:
private static List<List<string>> ReadCalendarEvents(string email)
{
List<List<string>> calendarEvents = new List<List<string>>();
// Specify the request version.
esb.RequestServerVersionValue = new RequestServerVersion();
esb.RequestServerVersionValue.Version = ExchangeVersionType.Exchange2007;
// Form the FindItem request.
FindItemType findItemRequest = new FindItemType();
CalendarViewType calendarView = new CalendarViewType();
calendarView.StartDate = DateTime.Now.AddDays(-7);
calendarView.EndDate = DateTime.Now.AddDays(200);
calendarView.MaxEntriesReturned = 1000;
calendarView.MaxEntriesReturnedSpecified = true;
findItemRequest.Item = calendarView;
// Define which item properties are returned in the response.
ItemResponseShapeType itemProperties = new ItemResponseShapeType();
// Use the Default shape for the response.
//itemProperties.BaseShape = DefaultShapeNamesType.IdOnly;
itemProperties.BaseShape = DefaultShapeNamesType.AllProperties;
findItemRequest.ItemShape = itemProperties;
DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[1];
folderIDArray[0] = new DistinguishedFolderIdType();
folderIDArray[0].Id = DistinguishedFolderIdNameType.calendar;
//
folderIDArray[0].Mailbox = new EmailAddressType();
folderIDArray[0].Mailbox.EmailAddress = email;
findItemRequest.ParentFolderIds = folderIDArray;
// Define the traversal type.
findItemRequest.Traversal = ItemQueryTraversalType.Shallow;
try
{
// Send the FindItem request and get the response.
FindItemResponseType findItemResponse = esb.FindItem(findItemRequest);
// Access the response message.
ArrayOfResponseMessagesType responseMessages = findItemResponse.ResponseMessages;
ResponseMessageType[] rmta = responseMessages.Items;
int folderNumber = 0;
foreach (ResponseMessageType rmt in rmta)
{
// One FindItemResponseMessageType per folder searched.
FindItemResponseMessageType firmt = rmt as FindItemResponseMessageType;
if (firmt.RootFolder == null)
continue;
FindItemParentType fipt = firmt.RootFolder;
object obj = fipt.Item;
// FindItem contains an array of items.
if (obj is ArrayOfRealItemsType)
{
ArrayOfRealItemsType items =
(obj as ArrayOfRealItemsType);
if (items.Items == null)
{
folderNumber++;
}
else
{
foreach (ItemType it in items.Items)
{
if (it is CalendarItemType)
{
CalendarItemType cal = (CalendarItemType)it;
List<string> ce = new List<string>();
ce.Add(cal.Location);
ce.Add(cal.Start.ToShortDateString() + " " + cal.Start.ToShortTimeString());
ce.Add(cal.End.ToShortDateString() + " " + cal.End.ToShortTimeString());
ce.Add(cal.Subject);
if (cal.Organizer != null)
{
ce.Add(cal.Organizer.Item.Name);
}
calendarEvents.Add(ce);
Console.WriteLine(cal.Subject + " " + cal.Start.ToShortDateString() + " " + cal.Start.ToShortTimeString() + " " + cal.Location);
}
}
folderNumber++;
}
}
}
}
catch (Exception e)
{
throw;
}
finally
{
}
return calendarEvents;
}
In EWS you need to query one folder at a time, for non default folders you will first need to find the FolderId before you can then query the appointments (or items) within a Folder. To find all the Calendar folders in a Mailbox you need to use the FindFolder operation and create a restriction to limit the result to folder with a FolderClass of IPF.Appointment eg
// Create the request and specify the travesal type.
FindFolderType findFolderRequest = new FindFolderType();
findFolderRequest.Traversal = FolderQueryTraversalType.Deep;
// Define the properties that are returned in the response.
FolderResponseShapeType responseShape = new FolderResponseShapeType();
responseShape.BaseShape = DefaultShapeNamesType.Default;
findFolderRequest.FolderShape = responseShape;
// Identify which folders to search.
DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[1];
folderIDArray[0] = new DistinguishedFolderIdType();
folderIDArray[0].Id = DistinguishedFolderIdNameType.msgfolderroot;
IsEqualToType iet = new IsEqualToType();
PathToUnindexedFieldType FolderClass = new PathToUnindexedFieldType();
FolderClass.FieldURI = UnindexedFieldURIType.folderFolderClass;
iet.Item = FolderClass;
FieldURIOrConstantType constantType = new FieldURIOrConstantType();
ConstantValueType constantValueType = new ConstantValueType();
constantValueType.Value = "IPF.Appointment";
constantType.Item = constantValueType;
iet.FieldURIOrConstant = constantType;
// Add the folders to search to the request.
RestrictionType restriction = new RestrictionType();
restriction.Item = iet;
findFolderRequest.Restriction = restriction;
findFolderRequest.ParentFolderIds = folderIDArray;
try
{
// Send the request and get the response.
FindFolderResponseType findFolderResponse = esb.FindFolder(findFolderRequest);
// Get the response messages.
ResponseMessageType[] rmta = findFolderResponse.ResponseMessages.Items;
foreach (ResponseMessageType rmt in rmta)
{
// Cast to the correct response message type.
if (((FindFolderResponseMessageType)rmt).ResponseClass == ResponseClassType.Success) {
foreach (FolderType folder in ((FindFolderResponseMessageType)rmt).RootFolder.Folders) {
Console.WriteLine(folder.DisplayName);
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
You also might want to look at using the EWS Managed API which will save you greatly time and the amount of code you need to write
Cheers
Glen

Cannot send a content-body with this verb-type. error while getting response when trying to Upload file in Box Storage

When i am trying to upload files in Box Storage using api provided by Box but at response time i am getting this error
public static void UploadFileRequest(string FolderID, string accesstoken)
{
string boundary = string.Format("----------------------------{0}", DateTime.Now.Ticks.ToString("x"));
string filename="C:\\Users\\Administrator\\Desktop\\Text.txt";
HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create("https://upload.box.com/api/2.0/files/content");
ASCIIEncoding encoding = new ASCIIEncoding();
string hh = "\"filename=#\"" + filename + "\" "+";"+"";
hh += "parent_id=\"" + FolderID + "\"";
string kj = string.Format(("filename=#" + filename));
byte[] data = encoding.GetBytes(hh);
httpWReq.Headers.Add("Authorization", "Bearer " + accesstoken);
httpWReq.ContentType = "application/json";
httpWReq.ContentLength = data.Length;
using (Stream stream = httpWReq.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse();
string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
}
Without knowing the Box API, I will assume that the upload should be a POST operation, so you will need to specify the correct HTTP method on your request, before sending it:
httpWReq.Method = "POST";
The Method property defaults to "GET", and GET operations does not normally have a body..
Here is the solution , as C# accepts bytes format and then any Upload is done , i was missing that .. hope it helps
private void UploadBoxFile(string Filename)
{
HttpWebRequest req = HttpWebRequest.Create("https://upload.box.com/api/2.0/files/content") as HttpWebRequest;
req.Method = "POST";
req.Headers.Add("Authorization", "Bearer < Access Token >");
req.ContentType = "multipart/form-data; boundary=\"d174f29b-6def-47db-8519-3da38b21b398\"";
string Content = GetFormatedData(Filename);
req.ContentLength = Content.Length;
using (Stream Writer = req.GetRequestStream())
{
Writer.Write(Encoding.UTF8.GetBytes(Content), 0, Content.Length);
}
req.GetResponse();
}
private string GetFormatedData(string Filename)
{
StringBuilder build = new StringBuilder();
string Id = "d174f29b-6def-47db-8519-3da38b21b398";
build.AppendLine("--" + Id);
build.AppendLine("Content-Disposition: form-data; filename=\"hello1.txt\"; name=\"filename\"");
build.AppendLine("Content-Type: application/octet-stream");
build.AppendLine();
string FileContent = "This is a sample text";
build.AppendLine(FileContent);
build.AppendLine("--" + Id);
build.AppendLine("Content-Disposition: form-data; name=\"folder_id\"");
build.AppendLine();
build.AppendLine("0");
build.AppendLine("--" + Id + "--");
return build.ToString();
}
Thanks..

Post data to web API

I've been trying to send data to a web API VIA post. But it doesn't seem to be sending it.
Here's how I do it.
var baseAddress = "http://192.168.0.103/vchatapi/api/Images?gsmNumber=" + profileNumberLbl.Content + "&content=" + base64 + "&contentType=image/" + contentType;
var http = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(new System.Uri(baseAddress));
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
This code works with get:
var baseAddress = "http://192.168.0.103/vchatapi/api/SendSMSVerificationCode?gsmNumber=" + areCode + mobile + "&udid=123456";
var http = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(new System.Uri(baseAddress));
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "GET";
try
{
var response = http.GetResponse();
var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
var content = sr.ReadToEnd();
verificationCode = verificationCode.FromJson(content);
if (!verificationCode.Equals(""))
{
MessageBox.Show(this, "Verification Code: " + verificationCode);
verificationTextBox.IsEnabled = true;
areaCodeCB.IsEnabled = false;
mobileNumberTB.IsEnabled = false;
}
else
{
MessageBox.Show(this, "Invalid Number");
}
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message);
}
Any ideas? Thanks!
Since you are doing a POST, you would be sending the content in the body of the request. You would need to get hold of the request's stream and write data to it. The following answer post has a very concise example:
https://stackoverflow.com/a/2551006/1184056

Missing credential from request in OOB application

I'm writing a simple Silverlight application in which I have the following code, which I think is pretty standard:
WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
var request = new WebClient();
var cred = new NetworkCredential(Server.UserName, Server.Password);
request.Credentials = cred;
request.UseDefaultCredentials = false;
request.DownloadStringCompleted += TestServerCompleted;
var uri = new Uri(Server.GetRequestUrl(Methods.ping));
request.DownloadStringAsync(uri);
Yet when I view the request in Fiddler, no credentials are added to the headers. What am I missing? Shouldn't there be an "Authorization: Basic ..." header in there?
Try with something like this.
HttpWebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
req.UseDefaultCredentials = false;
req.Credentials = ew NetworkCredential(Server.UserName, Server.Passwor
req.ContentType = "text/xml;charset=\"utf-8\"";
req.Accept = "text/xml";
req.Method = "POST";
return req;
req.BeginGetResponse((IAsyncResult asynchronousResultResponse) =>
{
try
{
HttpWebRequest requestResponse = (HttpWebRequest)asynchronousResultResponse.AsyncState;
HttpWebResponse response = (HttpWebResponse)requestResponse.EndGetResponse(asynchronousResultResponse);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
//Your response is here in responseString
streamResponse.Close();
streamRead.Close();
response.Close();
}
catch (Exception e)
{
Callback(null, e);
}
}, webRequest);
I Hope it can help, even 2 months later...

Resources