VyattaのREST APIで、作成したconfigをリモートから一括で設定&commitできるクラスを作成してみました。REST APIのrequestを作るのには Requests というPythonのHTTPライブラリを使っています。
sshでログインしてconfigをコピペしても一括でconfigを適用することはできますが、手作業が発生してしまいます。この方法であれば、リモートからコマンドだけで設定が変更できるので作業がかなり楽になりますし、provisioning時のスクリプトから実行するなど処理の自動化もできるようになるでしょう。
前提となるシステム要件
- VyattaはSubscription Editionであること
- Vyatta Community EditionではREST APIがサポートされません
- SoftLayerの場合はVyatta Gateway Applianceを選択してください
-
Requests のインストール
-
$ pip install requests
でインストール
-
注意点
使用にあたってはいくつか注意点があります。
- configを変更前の状態に元に戻す機能は実装していません。その場合はsshでVyattaにログインして、deleteコマンドで設定を削除してください。
- commitされるので、変更するconfigの内容によってはVyattaにアクセスできなくなってしまう場合もあるかもしれません。実行の際は注意してください。
- もしアクセスできなくなった場合は、SoftLayerのチケットで修復をお願いしてみてください。きっと優しいSoftLayerのサポートエンジニアが助けてくれると思います。
- IPMIを使ってローカルコンソールからログインして修正することもできるでしょう。
- または、変更したconfigはcommitしていますがsaveはしていないので、最悪自分でVyattaを再起動すれば元の設定に戻ります。
モジュール
VyattaControlクラス
Vyatta.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
import urllib
import requests
requests.packages.urllib3.disable_warnings() # Surpress "InsecureRequestWarning" warning
import Vyatta
import vyuser
class VyattaControl(object):
"""
Provides methods to show and modify Vyatta status and configurations.
"""
def __init__(self, urlBase, user, passwd):
self.urlBase = urlBase
self.urlConfBase = urlBase + 'rest/conf'
self.urlOpBase = urlBase + 'rest/op'
self.user = user
self.passwd = passwd
def getOpId(self, urlOpId):
"""
Get the operation id, which is substring of the Location header in HTTP response.
:param urlOpPost:
:return:
"""
rop = requests.post(urlOpId, auth=(self.user, self.passwd), verify=False) # Request to get operation id
return rop.headers['Location'].split('/')[2] # Get Location header
def getConfId(self):
"""
Get the configuration id, which is substring of the Location header in HTTP response.
:return:
"""
rconf = requests.post(self.urlConfBase, auth=(self.user, self.passwd), verify=False)
return rconf.headers['Location'].split('/')[2]
def deleteConfId(self, confId):
"""
Delete existing Vyatta configuration session
:param confId: Configuration ID to be deleted
:return: HTTP status code for DELETE request
"""
urlConfDelete = self.urlConfBase + '/' + confId
rdel = requests.delete(urlConfDelete, auth=(self.user, self.passwd), verify=False)
return rdel.status_code
def commandOperational(self, opCommandFileName):
"""
Call Vyatta operational mode commands from opCommandFileName file.
:param opCommandFileName: Input file for Vyatta operational mode commands
:return:
"""
with open(opCommandFileName, encoding='utf-8') as opCommandFile:
for line in opCommandFile:
urlOpCommand = self.urlOpBase + '/' + '/'.join(line.split(None))
ropResult = requests.get(self.urlOpBase + '/' + self.getOpId(urlOpCommand),
auth=(self.user, self.passwd),
verify=False) # Request to get the results
print('$ ' + line)
print(ropResult.text)
def createEncodedUrl(self, confId, string):
"""
URLencode every configuration words and form proper URL for REST API requests.
:param confId: Configuration session ID
:param string: One line Vyatta configuration commands and parameters
:return: Encoded URL for Vyatta REST API
TODO: Fix wrong encoding when spaces in description "" in Vyatta configuration is used.
ex. description "IPSEC to HQ". In the meantime, avoid using "" in Vyatta configuration.
"""
encodedWord = []
for word in string.split():
encodedWord.append(urllib.parse.quote(word, safe="")) # Encode each words, then make a list of words
encodedUrl = self.urlConfBase + '/' + confId + '/' \
+ '/'.join(' '.join(encodedWord).split(None))
return encodedUrl
def editConfig(self, confFileName):
"""
Read configurations from a file and send requests to Vyatta via REST API,
then actually modify Vyatta configuration and commit configuration changes.
:param confFileName: A file which has the configurations to apply
:return: HTTP status code for deleteConfId()
"""
# Set configurations
with open(confFileName, encoding='utf-8') as confFile:
confId = self.getConfId() # Get configuration ID
for line in confFile:
if not (re.compile("^#").match(line)
or re.compile("^$").match(line)): # Skip line matches with "^#" or "^$"
urlConfPut = self.createEncodedUrl(confId, line)
rconf = requests.put(urlConfPut,
auth=(self.user, self.passwd),
verify=False) # Request for configuration commands
print("%s : %s" % (urlConfPut, rconf.status_code))
# Commit configurations
self.commitConfig(confId)
# Delete conf-id and return HTTP status code
return self.deleteConfId(confId)
def commitConfig(self, confId):
"""
Commit configuration changes
:param confId: Configuration session ID
:return: HTTP status code
"""
urlConfCommit = self.urlConfBase + '/' + confId + '/commit'
rconf = requests.post(urlConfCommit, auth=(self.user, self.passwd), verify=False) # Request for commit
print("%s : %s" % (urlConfCommit, rconf.status_code))
return rconf.status_code
def saveConfig(self, confId):
"""
To be implemented
:param confId:
:return:
"""
pass
def revertConfig(self, confId):
"""
To be implemented
:param confId:
:return:
"""
pass
if __name__ == "__main__":
# Test code
pass
実行スクリプトの例
実行スクリプト
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Vyatta
import vyuser
user = vyuser.VYUSER
passwd = vyuser.VYPASSWD
urlBase = vyuser.URLBASE
vy = Vyatta.VyattaControl(urlBase, user, passwd)
vy.editConfig('vy_configuration.conf')
vy.commandOperational('vy_op_command.conf')
Vyattaユーザー情報ファイル
vyuser.conf
VYUSER = "vyatta"
VYPASSWD = "<vyatta password>"
URLBASE = "https://10.x.x.x/"
configの定義ファイル
変更するVyattaのconfigが記載されたファイル。
設定ファイルをテンプレート化して、アドレス等のパラメーターを与えると、構成パターンに応じたconfigを自動生成するような仕組みがほしいところですが、今のところは変更するconfigを全て手で個別に作成します。
以下は、BYOIPのためにGRE over IPsecを確立する設定のconfigの例です。
vy_configuration.conf
# Comments start with #
# BYOIP subnet
set interfaces bonding bond0 address 192.168.2.1/24
# GRE settings
set interfaces tunnel tun0 address 192.168.10.1/30
set interfaces tunnel tun0 encapsulation gre
set interfaces tunnel tun0 multicast enable
set interfaces tunnel tun0 local-ip 111.111.111.111
set interfaces tunnel tun0 remote-ip 222.222.222.222
# IPsec ESP policy settings
set vpn ipsec esp-group ESP1 lifetime 3600
set vpn ipsec esp-group ESP1 mode tunnel
set vpn ipsec esp-group ESP1 pfs enable
set vpn ipsec esp-group ESP1 proposal 1 encryption aes128
set vpn ipsec esp-group ESP1 proposal 1 hash sha1
# IPsec IKE policy settings
set vpn ipsec ike-group IKE1 lifetime 86400
set vpn ipsec ike-group IKE1 proposal 1 dh-group 5
set vpn ipsec ike-group IKE1 proposal 1 encryption aes128
set vpn ipsec ike-group IKE1 proposal 1 hash sha1
# IPsec interface settings
set vpn ipsec ipsec-interfaces interface bond1
# IPsec VPN settings
set vpn ipsec site-to-site peer 222.222.222.222 authentication mode pre-shared-secret
set vpn ipsec site-to-site peer 222.222.222.222 authentication pre-shared-secret test_key_1
set vpn ipsec site-to-site peer 222.222.222.222 default-esp-group ESP1
set vpn ipsec site-to-site peer 222.222.222.222 ike-group IKE1
set vpn ipsec site-to-site peer 222.222.222.222 local-address 111.111.111.111
set vpn ipsec site-to-site peer 222.222.222.222 tunnel 1 protocol gre
# Static Route
set protocols static route 192.168.1.0/24 next-hop 192.168.10.2
実行するOperational Modeコマンドの定義ファイル
configを確認したりステータスを確認するために、Operational Modeのコマンドもファイルから入力して実行できます。
vy_op_command.conf
show configuration
show interfaces
show vpn ipsec sa