您开始深入学习,编写您的第一个程序。但是,一旦您创建客户端对象并获得您的第一个对象,问题就开始接踵而来,您意识到您需要更多的信息。所以您找到了您信赖的朋友 Google,在 SLDN 论坛中找到了您所需要的信息,还找到了和一些散落在互联网上的简短示例,但您很快意识到:除了 python 之外,SoftLayer API 还绑定了许多不同的语言/格式(ruby、perl、c#、SOAP、RESTful,等等),而且目前我们还不清楚如何将其他语言的代码片段翻译成您所熟悉的语言,因为每个绑定与 SoftLayer API 交互的方式似乎都是不同的。您打算怎么做?
继续阅读。撰写本文就是为了填补一些空白。
您想要知道的第一件事可能是:当创建 SoftLayer Client 对象时,您可以连接到私有网络上的 API 端点,就像上面显示的链接中的示例那样(这意味着您必须在 SoftLayer 机器上运行您的代码),或者,您可以使用公共端点,这样您就可以从您的笔记本电脑运行/测试代码:
client = SoftLayer.Client(username=myuser, api_key=mykey, endpoint_url=SoftLayer.API_PUBLIC_ENDPOINT)
有两种不同的方法来访问 SoftLayer 数据和运行 SoftLayer 方法: 服务 和 管理器 。使用管理器更容易掌握一些,但这并不适用于所有的数据和功能。所以,如果您正在执行比基础操作更复杂的操作,那么您需要学习如何使用这些服务。就我个人而言,我发现只使用服务更适合我一些,所以我将重点介绍这个方面。但您可能发现您更喜欢使用管理器,那么您可以使用管理器。我在下面介绍的许多技巧对于两种方法都适用。
回页首
您会在这里花很多时间,所以让我们来熟悉一下这个网站。您要注意的第一件事是,如果您滚动左边的服务列表,就会发现有许多的服务。SoftLayer API 的使用超级广泛,如果您学会了如何使用它,那么这是一条好消息。每个服务实质上就是一个包含方法和数据的类,尽管从 Python 角度讲,您不会像访问真正的 Python 类一样访问它们(也就是说,您不会使用构造函数来获得一个单独的类,从而处理某个实例)。相反,主要 Client 对象是一个服务对象字典。当服务数据类型由此服务或另一个服务中的任何方法返回时,服务网站中的每个页面都显示了可以从该服务运行的方法(在您单击蓝色的 Service 选项卡时就会显示该服务),以及该服务的数据结构(在您单击绿色 Data Type 选项卡时就会显示)。别担心,当您开始使用它时就会更加清楚这一切。
单击任何的 get 方法,您会看到该方法返回的数据类型。如果回到 Account service 页面并单击绿色 Data Type 选项卡,就会看到 Local Properties(本地属性)和 Relational & Count Properties(关系和统计属性)列表。本地属性是此服务数据类型的直属部分。关系属性是指向其他服务数据类型的指针。如果按照这个指导方针,您可能会完全失去您需要的所有数据。我发现在新的选项卡中打开每个链接是最简单的方式,这样您就有了一个如何到达那里的历史记录(因为您需要使用该历史记录来实现正确编码)。
一个示例有助于澄清这一点。假设您想用您的 SoftLayer 帐户获得一个 VLAN(及其子网)的列表。通过查看 Account 页面的 Services 选项卡下的方法,您会发现一个 getNetworkVlans 方法,该方法将返回 Network_Vlan 服务数据类型。在该页面上,您会看到一个本地属性 vlanNumber,您想了解该属性,但是如何告诉 SoftLayer 具体返回哪些属性呢?这时就是对象掩码发挥其作用的时候了。掩码是您想要返回的一个逗号分隔的属性名称字符串。
在这里,您感兴趣的其他属性是什么?我已经吸取了教训,VLAN 数字在 SoftLayer 并不是独一无二的,在帐户、数据中心、甚至是在一个p中也不是惟一的。惟一指定一个 VLAN 的最好方法是提供它所在的主路由器。查看关系属性列表,您会看到一个称为 primaryRouter 的属性,该属性显然比称为 secondaryRouter 的属性更好一些。单击 primaryRouter 部分中的链接,系统会将您带到一个 Hardware_Router 数据类型页面。原来的主机名是最好的路由器属性(稍后我会解释如何理解这一点),所以 primaryRouter.hostname 将是您的掩码中列出的第二个属性。您还想知道组成此 VLAN 的子网,所以您应该回到 Network_Vlan 页面,您会发现另一个称为 primarySubnets 的关系属性。追随该链接来到 Network_Subnet 数据类型页面,您会看到名为 networkIdentifier 和 cidr 的两个本地属性。将这些属性添加到您的掩码,它将变成:
mask = 'vlanNumber, primaryRouter.hostname, subnets.networkIdentifier, subnets.cidr'
将所有这些汇总在一起,就形成了您的第一个 SoftLayer API Python 程序:
import SoftLayer import pprint client = SoftLayer.Client(username=myuser, api_key=mykey, endpoint_url=SoftLayer.API_PUBLIC_ENDPOINT) mask = 'vlanNumber, primaryRouter.hostname, subnets.networkIdentifier, subnets.cidr' allVlans = client['Account'].getNetworkVlans(mask=mask) pprint.pprint(allVlans)
在实际程序中,您将访问所返回的数据结构的成员,并使用它们执行一些操作。但 pprint 在查看结构时真的很有用,这样您就可以知道如何编写代码来访问它,尤其在它是字典内的列表中的字典的时候。
请注意,我指的是没有以 “SoftLayer_” 开头的所有 SoftLayer 服务/数据类型。因为 SoftLayer 通常在其文档中采用这种方式,这也是您在代码中引用它们的方式。
回页首
在上面的掩码中,我们指定了希望在每一层的数据结构中出现一些特定本地属性:
这些属性不是偶然出现,而是特意安排的。如果在任何级别的数据类型层次结构上,您没有至少指定一个本地属性,那么 SoftLayer API 将会返回该数据类型的所有本地属性。这一点在探索哪些属性拥有您想要的值的时候可能非常有用(与 pprint 结合使用)。这是因为用于每个属性的文档通常不是特定的。但 API 调用也需要花费很长的时间,在返回大量属性时,需要花费大量的时间。在上面的示例中,如果我们只是将掩码更改为:
mask = 'primaryRouter, subnets'
我们仍将获得我们感兴趣的属性(和其他数据),但编码时间增加了 70%(在我的有 90 个 VLAN 的帐户中,原编码需要 1 秒钟,现在需要 1.7 秒),因为它返回了每个 VLAN 的 Network_Vlan、Hardware_Router 和 Network_Subnet 的所有本地属性。这在您试图弄明白您到底想要什么属性时非常有用(结合使用 pprint),这也正是我发现 hostname 是 Hardware_Router 的最有用属性的方式。一旦完成了探索,就应该限制返回的数据,将它限定为您所需要的数据。在我使用的一个案例中,在采用这种方式限定掩码之前,一个 API 调用花费了我 5 倍的时间。
所以,这里的经验法则是:
在您的掩码中,对于您所涉及的每个数据类型,至少指定 1 个本地属性(远程属性不计入此中)。如果您不需要任何本地属性(您只是遵循其他数据类型的远程属性),至少应该指定 “id” 属性。
掩码可以传递到在其 Web 页面的 Optional Headers 部分中列出了 ObjectMask 的任何方法中。
id 是 SoftLayer 用作其数据对象的主键的惟一整数标识符。它们在一个帐户和数据类型中是惟一的,但它们可以在帐户或数据类型中重复。最常见的 id 用法是在任何服务的 getObject 方法中使用它。例如:
client['Network_Gateway'].getObject(id=gatewayid, mask=mask)
还可以在通常返回一个对象列表的某些方法中指定一个 id,以便只得到某个特定对象:
client['Network_Gateway'].getInsideVlans(id=gatewayid, mask=mask) client['User_Customer'].getChildUsers(id=id, mask='username, email, displayName, firstName, lastName')
或者对某个特殊对象运行一个操作:
client['Network_Gateway'].bypassVlans(objs, id=gatewayid) client['Ticket'].getStatus(id=12497530)
似乎在 Optional 或 Required Headers 部分中列出了 InitParameters 的任何方法都会接受 id 作为一个参数。您通常可以从先前的 API 查询中获得 id 值。
我们已经了解到,可以限制您要求返回的数据量加快 SoftLayer API 的速度。掩码使您能够准确地指定您想要返回的每个对象的属性(服务实例)。但是如何指定哪些对象应该返回,而不是获得给定类型的所有对象呢?这就是过滤器大显身手的地方。很少有文档介绍过滤器的使用,所以在这里我将解释一下过滤器。与 “掩码” 类似,“过滤器” 是另一个可以用在大多数方法上的可选参数。它的价值在于:您可以指定嵌套词典,该字典始于运行方法所使用的服务中的某个属性,遵从属性的用法,直到您通过过滤器选择获得某个您想要的数据。在该操作中,您使用一个叫 “operation” 的键、一个运算符和值指定了一个字典。用一个示例解释会让您更清楚地了解这一切。如果我想获得我的帐户中的所有虚拟 Guest (虚拟服务器),我的帐户中有一个包含字符串 “feat” 的域名,那么我的编码将如下所示:
guests = client['Account'].getVirtualGuests(mask=mask, filter={'virtualGuests': {'domain': {'operation': '*= feat'}}})
请注意,即使 getVirtualGuests() 返回了 Virtual_Guest() 数据类型,我开始并没有指定这些属性。该方法位于 Account 服务中,所以我从这个数据类型开始介绍。Account 数据类型有一个名为 “virtualGuests” 的远程属性,该属性随后会将我带到 Virtual_Guest 数据类型,这个数据类型有一个名为 “domain” 的本地属性,这是我感兴趣的一个属性。还要注意的是,运算符和值在相同的字符串中是匹配的。我的示例中使用的运算符 “* =” 意味着 “包含”,以下是完整的运算符列表:
如果您想匹配多个属性,那么可以向字典添加额外的键,所有操作实质上都用 AND 组合在了一起。例如,以下命令将选择域中包含 “feat”、主机名为 “myvm” 的
虚拟 Guest:
guests = client['Account'].getVirtualGuests(mask=mask, filter={'virtualGuests': {'hostname': {'operation': 'myvm'}, 'domain': {'operation': '*= feat'}}})
还有一个名为 “betweenDate” 的 “扩展” 运算符,运算符的值是字典的后续键中给出的。您可以查看一个这样的示例。可能还有其他扩展的运算符;我从未见过这些运算符的列表。
在我的下一篇博客中,我将介绍从哪儿开始导航,使用 SoftLayer API 调用修改资源,并处理 SoftLayer 异常。