SaltStack的多雲管理解決方案——怎樣爲Salt-cloud開發一個雲平臺驅動程序

Salt Cloud在類似於主Salt項目的模塊系統上運行。 saltcloud內部的模塊位於salt源碼的salt/cloud/clouds目錄中。

有兩種基本類型的雲模塊。 如果雲平臺主機支持libcloud,則使用它是編寫模塊的最快方法。 Apache Libcloud項目位於:

http://libcloud.apache.org/

不是所有的雲平臺主機都受libcloud支持。 此外,libcloud不一定支持受支持的雲平臺主機中的所有功能。 在這兩種情況下,都可以選擇創建不依賴libcloud的模塊。

您也可以參考在Github上維護的這一份技術資料:Extending Salt Cloud - Adding Cloud Providers

All Driver Modules - 所有驅動程序都需要實現的函數

所有驅動程序模塊都需要以下功能,無論它們是否基於libcloud實現的。

The virtual() Function

此功能確定在執行時使該雲模塊是否可用。 通常,它使用get_configured_provider()來確定是否已設置必要的配置。 它還可以檢查必要的導入,以決定是否加載模塊。 在大多數情況下,它將返回True或False值。 如果使用的驅動程序名稱與文件名不匹配,則應返回該名稱而不是True。 在Azure模塊中可以看到一個示例:

https://github.com/saltstack/salt/tree/develop/salt/cloud/clouds/msazure.py

The get_configured_provider() Function

此函數使用config.is_provider_configured()確定是否已爲此驅動程序配置了所有必需的信息。 所需設置列表中的最後一個值應跟逗號。

Libcloud Based Modules - 基於Libcloud實現的函數

基於libcloud編寫雲模塊有兩個主要優點。 首先,libcloud項目已經完成了許多基礎工作。 其次,Salt所需的大多數功能已經添加到Salt Cloud項目中。

The create() Function

需要手動編寫的最重要的函數是create()函數。 這是用於請求由雲主機創建虛擬機並等待其可用,然後(可選)登錄並在其上安裝Salt的方法。

下面爲Linode提供的模塊是編寫基於libcloud的雲驅動程序模塊的一個很好的例子:

https://github.com/saltstack/salt/tree/develop/salt/cloud/clouds/linode.py

create()函數的基本流程如下:

  • 向雲主機發送請求以創建虛擬機。
  • 等待虛擬機可用。
  • 生成用於部署Salt的kwarg。
  • 登錄到虛擬機並部署Salt。
  • 返回描述新創建的虛擬機的數據結構。

在此功能函數的各個階段,事件可能會在Salt事件總線上觸發。這些事件中有四個是必需的,如下所述。用戶可以在適當的地方添加其他事件。

調用create()函數時,將傳遞一個名爲vm_的數據結構。該字典變量中包含描述要創建的虛擬機的信息的組合。 Salt還提供了一個稱爲__opts__的字典,其中包含用於運行Salt Cloud的選項以及一組配置和環境變量。

create()函數必須做的第一件事是觸發一個事件,指出它已開始創建過程。該事件被標記爲salt/cloud/<vm name>/creating。有效負載包含VM、配置文件和驅動程序的名稱。

然後通常會創建一組kwargs,以描述雲主機請求虛擬機所需的參數。

然後觸發一個事件,指出將要請求虛擬機。它被標記爲salt/cloud/<vm name>/requesting。有效負載包含將發送到雲主機的大多數或所有參數。任何私人信息(例如密碼)都不應在事件中發送。

發出請求後,將生成一組部署Kwargs。這些將用於在目標計算機上安裝Salt。此時支持Windows選項,即使雲主機當前不支持Windows,也應生成Windows選項。如果主機最終決定支持Windows,則這將節省將來的時間。

然後觸發一個事件,指出部署過程即將開始。該事件被標記爲salt/cloud/<vm name>/deploying。事件的有效負載將包含一組部署Kwargs,可用於有目的的調試。在觸發事件之前,應從部署參數刪除所有私人數據,包括密碼和密鑰(包括公共密鑰)。

如果傳遞了任何Windows選項,則將調用salt.utils.cloud.deploy_windows()函數。否則,將假定目標是Linux或Unix計算機,並調用salt.utils.cloud.deploy_script()

這兩個功能都將等待目標計算機可用,然後等待登錄所需的端口,然後成功登錄即可用於安裝Salt。Minion配置和密鑰隨後將通過適當的功能上傳到目標上的臨時目錄。在Windows目標主機上,Windows Minion Installer將以靜默模式運行。在Linux/Unix目標上,將運行部署腳本(默認情況下爲bootstrap-salt.sh),該腳本將自動檢測操作系統,並使用其本機軟件包管理器安裝Salt。這些不需要由雲模塊中的開發人員處理。

擴展了salt.utils.cloud.validate_windows_cred()函數,以獲取重試和retry_delay參數的數量,以防特定的雲主機在提供Windows憑據和可用憑據之間存在延遲。在其create()函數中,或作爲在創建過程中調用的子函數,開發人員應使用驅動程序配置中的win_deploy_auth_retrieswin_deploy_auth_retry_delay參數,以使最終用戶能夠爲了他們的特定主機自定義嘗試次數和嘗試之間的延遲。

當部署功能完成後,將觸發一個最終事件,該事件描述了剛剛創建的虛擬機。該事件被標記爲salt/cloud/<vm name>/created。有效負載包含VM、profile配置文件和provider驅動程序的名稱。

最後,將描述新虛擬機的字典信息(從provider處查詢)返回給用戶。由於此數據未在事件總線上觸發,因此它可以並且應該返回雲主機返回的所有密碼。在某些情況下(例如,Rackspace),這是用戶唯一一次可以查詢密碼的時間。創建後的查詢可能不會包含密碼信息(這取決於主機)。

The libcloudfuncs Functions

所有云主機都需要許多其他功能。 但是,對於基於libcloud的模塊,這些全部由libcloudfuncs庫免費提供。 以下兩行設置了導入:

from salt.cloud.libcloudfuncs import *   # pylint: disable=W0614,W0401
import salt.utils.functools

然後,一系列調用聲明將使必要的功能函數在雲模塊中可用。

get_size = salt.utils.functools.namespaced_function(get_size, globals())
get_image = salt.utils.functools.namespaced_function(get_image, globals())
avail_locations = salt.utils.functools.namespaced_function(avail_locations, globals())
avail_images = salt.utils.functools.namespaced_function(avail_images, globals())
avail_sizes = salt.utils.functools.namespaced_function(avail_sizes, globals())
script = salt.utils.functools.namespaced_function(script, globals())
destroy = salt.utils.functools.namespaced_function(destroy, globals())
list_nodes = salt.utils.functools.namespaced_function(list_nodes, globals())
list_nodes_full = salt.utils.functools.namespaced_function(list_nodes_full, globals())
list_nodes_select = salt.utils.functools.namespaced_function(list_nodes_select, globals())
show_instance = salt.utils.functools.namespaced_function(show_instance, globals())

如有必要,可以通過刪除相應的聲明行,然後正常添加函數來替換這些函數的實現。

所有云模塊都需要這些功能函數,下一節將對其進行詳細描述。

Non-Libcloud Based Modules - 非基於Libcloud庫實現的功能函數

在某些情況下,不能選擇使用libcloud。 這可能是因爲libcloud尚未包含必需的驅動程序本身,或者可能是libcloud隨附的驅動程序未包含開發人員所需的所有必需功能。 在這種情況下,可以替換libcloudfuncs中的部分或全部功能。 如果已全部替換,則應從Salt Cloud模塊中缺少libcloud導入。

非libcloud驅動程序的一個很好的例子是DigitalOcean驅動程序:

https://github.com/saltstack/salt/tree/develop/salt/cloud/clouds/digitalocean.py

The create() Function

必須按照基於libcloud的模塊文檔中的說明創建create()函數。

The get_size() Function

此功能僅對於基於libcloud的模塊是必需的,否則不需要存在。

The get_image() Function

此功能僅對於基於libcloud的模塊是必需的,否則不需要存在。

The avail_locations() Function

如果雲主機使用多個數據中心,則此函數返回可用位置的列表。 如果雲主機僅使用一個數據中心,則沒有必要。 通常使用–list-locations選項調用它。

salt-cloud --list-locations my-cloud-provider

The avail_images() Function

此函數返回可用於該雲服務商的鏡像列表。 當前尚沒有任何不提供此功能的已知雲提供商,儘管它們可能引用了不同名稱的鏡像(例如,“模板”)。 通常使用–list-images選項調用它。

salt-cloud --list-images my-cloud-provider

The avail_sizes() Function

此函數返回可用於該雲服務商的配置規格大小的列表。 通常,這是指RAM、CPU和/或磁盤空間的組合。 某些雲服務商可能沒有此功能。 例如,Parallels模塊將RAM、CPU和磁盤空間分解爲單獨的選項,而在其他驅動程序中,這些選項被嵌入到映像中。 通常使用–list-sizes選項調用它。

salt-cloud --list-sizes my-cloud-provider

The script() Function

此功能可構建需要在遠程計算機上使用的部署腳本。 它很通用,很可能會在不久的將來移入salt.utils.cloud庫,通常這可以從另一個模塊中批量複製使用。 一個很好的例子是Azure驅動程序。

The destroy() Function

此功能不可逆地銷燬雲平臺上的虛擬機。 在這樣做之前,它會在Salt事件總線上觸發一個事件。 該事件的標籤爲salt/cloud/<vm name>/destroying。 虛擬機銷燬後,將觸發另一個事件。 該事件的標籤爲salt/cloud/<vm name>/destroyed

通常使用-d選項調用此函數:

salt-cloud -d myinstance

The list_nodes() Function

此函數使用以下字段返回此雲驅動程序上可用的節點列表:

  • id (str)
  • image (str)
  • size (str)
  • state (str)
  • private_ips (list)
  • public_ips (list)

此函數中不應返回任何其他字段,並且即使所有字段爲空,也應返回所有這些字段。 即使爲空,private_ips和public_ips字段也應始終爲列表類型,其他字段應始終爲str類型。 通常使用-Q選項調用此函數:

salt-cloud -Q

The list_nodes_full() Function

有關所有節點的所有可用信息都應在此函數中返回。 即使通常不由雲提供商提供,也應返回list_nodes()函數中的字段。 這是因爲如果沒有期望的字段,Salt和3rd Party中的某些功能都會中斷。 通常使用-F選項調用此函數:

salt-cloud -F

The list_nodes_select() Function

此函數僅返回/etc/salt/cloudquery.selection選項中指定的字段。 由於此功能是如此通用,因此所有繁重的工作都已移至salt.utils.cloud庫中。

仍然需要存在一個調用list_nodes_select()的函數。 通常,以下代碼可以按原樣使用:

def list_nodes_select(call=None):
    '''
    Return a list of the VMs that are on the provider, with select fields
    '''
    return salt.utils.cloud.list_nodes_select(
        list_nodes_full('function'), __opts__['query.selection'], call,
    )

但是,這取決於雲提供商,可能會需要其他變量。 例如,某些模塊使用conn對象,或者可能需要將其他選項傳遞到list_nodes_full()中。 在這種情況下,請確保適當地更新功能:

def list_nodes_select(conn=None, call=None):
    '''
    Return a list of the VMs that are on the provider, with select fields
    '''
    if not conn:
        conn = get_conn()   # pylint: disable=E0602

    return salt.utils.cloud.list_nodes_select(
        list_nodes_full(conn, 'function'),
        __opts__['query.selection'],
        call,
    )

通常使用-S選項調用此函數:

salt-cloud -S

The show_instance() Function

此功能用於顯示可從雲提供商處獲得的有關單個節點的所有信息。 提供此功能的最簡單方法通常是調用list_nodes_full(),並僅返回所請求節點的數據。 通常稱爲action:

salt-cloud -a show_instance myinstance

Actions and Functions

可以以--action--function的形式將額外的功能添加到雲提供商。 針對雲實例/虛擬機執行actions,針對雲提供商執行functions。

Actions

Actions是針對特定實例或虛擬機執行的調用。 show_instance操作應在所有云模塊中可用。 通常使用-a選項調用actions:

salt-cloud -a show_instance myinstance

Actions必須接受name作爲第一個參數,可以視情況選擇支持任意數量的kwargs,並且必須接受call參數,默認值爲None

在執行任何其他工作之前,通常應先執行一項操作以驗證它已被正確調用。 然後,它可以執行所需的功能,並將有用的信息返回給用戶。 基本動作如下:

def show_instance(name, call=None):
'''
Show the details from EC2 concerning an AMI
'''
if call != 'action':
    raise SaltCloudSystemExit(
        'The show_instance action must be called with -a or --action.'
    )

return _get_node(name)

請注意,一般的kwargs(如果使用)會以kwargs而不是**kwargs的形式傳遞給動作。 在Functions部分中可以看到一個示例。

Functions

調用針對特定雲提供商執行的管理功能。 通常有用的可選功能是show_image,它詳細描述了鏡像。 通常使用-f選項調用函數:

salt-cloud -f show_image my-cloud-provider image='Ubuntu 13.10 64-bit'

函數可以接受任意數量的kwargs,並且必須接受默認值爲Nonecall參數。

在執行任何其他工作之前,函數通常應驗證是否已正確調用它。 然後,它可以執行所需的功能,並將有用的信息返回給用戶。 基本功能如下:

def show_image(kwargs, call=None):
    '''
    Show the details from EC2 concerning an AMI
    '''
    if call != 'function':
        raise SaltCloudSystemExit(
            'The show_image action must be called with -f or --function.'
        )

    params = {'ImageId.1': kwargs['image'],
              'Action': 'DescribeImages'}
    result = query(params)
    log.info(result)

    return result

請注意,通用kwargs通過kwargs傳遞給函數,而不是**kwargs

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章