如何在 vmware vSphere 客户端 REST API 中使用部分 VM 名称(字符串)进行过滤?

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

美好的一天!

我正在尝试自动执行对我组织中的 VM 执行的某些操作。 要执行的操作取决于 VM 名称中的子字符串。

例如,我需要删除名称以 'delete' 开头的所有 VM,等等

我可以使用下面的 API 来获取 VM 的列表:

GET https://{{vc}}/rest/vcenter/vm

但是,此 API 最多只能获取 1000 个 VM。

有什么方法可以过滤并仅获取具有来自此 API 的预期子字符串的 VM 列表?

据我所知,将 filter.names.1 附加到上面的 API 是可行的,但为此我需要输入准确的完整 VM 名称。

有什么方法可以搜索带有部分文本的 VM 列表?

抱歉,我是新手。

感谢您的宝贵时间!

不幸的是,vSphere Automation API 未设置为过滤部分名称,甚至在使用通配符时也是如此。一些可用的过滤器可能会帮助您将输出限制在 1000 个对象限制以下(例如:过滤特定集群 and/or 文件夹)。

希望这是在未来版本中添加的内容。

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"
            }
        ]
    }
]

下面是我自己用 C# 编写的 vSphere Search Proxy Client:

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);
        }
    }
}